Android 10 包含了一些更新的系统行为变更,这些变更可能会影响您的应用。本页面列出的变更仅适用于以 API 29 或更高级别为目标的应用。如果您的应用将 targetSdkVersion 设置为“29”或更高,您应该适当地修改您的应用以支持这些行为。
请务必同时查看影响所有在 Android 10 上运行的应用的行为变更列表。
注意:除了本页面列出的变更外,Android 10 还引入了大量基于隐私的变更和限制,包括以下内容:
- 分区存储 (Scoped Storage)
- 对 USB 设备序列号的访问
- 启用、禁用和配置 Wi-Fi 的能力
- 连接 API 的位置权限
这些影响以 API 级别 29 或更高级别为目标的应用的变更,增强了用户隐私保护。要详细了解如何支持这些变更,请参阅隐私变更页面。
非 SDK 接口限制的更新
为了确保应用的稳定性和兼容性,Android 平台从 Android 9(API 级别 28)开始限制您的应用可以使用哪些非 SDK 接口。Android 10 基于与 Android 开发者的协作以及最新的内部测试,更新了受限非 SDK 接口的列表。我们的目标是确保在限制非 SDK 接口之前提供公开的替代方案。
如果您不以 Android 10(API 级别 29)为目标,其中一些变更可能不会立即影响您。但是,虽然您目前可以使用某些非 SDK 接口(取决于您的应用的目标 API 级别),但使用任何非 SDK 方法或字段始终存在导致应用崩溃的高风险。
如果您不确定您的应用是否使用了非 SDK 接口,可以测试您的应用以进行确认。如果您的应用依赖于非 SDK 接口,则应开始规划迁移到 SDK 替代方案。尽管如此,我们理解某些应用对于使用非 SDK 接口有正当理由。如果您无法为应用中的功能找到使用非 SDK 接口的替代方案,则应申请新的公共 API。
要了解更多信息,请参阅Android 10 中非 SDK 接口限制的更新以及非 SDK 接口的限制。
共享内存
Ashmem 已更改 /proc/<pid>/maps 中 dalvik 映射的格式,这会影响直接解析 maps 文件的应用。如果应用依赖于 dalvik 映射格式,应用开发者应在运行 Android 10 或更高版本的设备上测试 /proc/<pid>/maps 格式,并进行相应的解析。
以 Android 10 为目标的应用不能直接使用 ashmem (/dev/ashmem),必须通过 NDK 的 ASharedMemory 类访问共享内存。此外,应用不能对现有的 ashmem 文件描述符进行直接 IOCTL 调用,而必须使用 NDK 的 ASharedMemory 类或 Android Java API 来创建共享内存区域。此更改提高了使用共享内存时的安全性和稳健性,从而提升了 Android 的整体性能和安全性。
移除应用主目录的执行权限
从可写应用主目录执行文件属于 W^X 违规。应用应该只加载嵌入在应用 APK 文件中的二进制代码。
以 Android 10 为目标的不受信任应用不能直接对应用主目录内的文件调用 execve()。
此外,以 Android 10 为目标的应用不能在内存中修改已通过 dlopen() 打开的文件中的可执行代码,并期望这些更改被写入磁盘,因为该库无法通过可写文件描述符映射为 PROT_EXEC。这包括任何带有文本重定位的共享对象 (.so) 文件。
Android 运行时仅接受系统生成的 OAT 文件
Android 运行时 (ART) 不再从应用程序进程调用 dex2oat。此更改意味着 ART 将仅接受由系统生成的 OAT 文件。
在 ART 中强制执行 AOT 正确性
过去,如果编译时和运行时的类路径环境不一致,Android 运行时 (ART) 执行的预先编译 (AOT) 可能会导致运行时崩溃。Android 10 及更高版本始终要求这些环境上下文保持一致,从而导致以下行为变更:
- 自定义类加载器(即由应用编写的类加载器,而非
dalvik.system包中的类加载器)不会进行 AOT 编译。这是因为 ART 无法在运行时了解自定义的类查找实现。 - 二级 dex 文件(即应用手动加载的不在主 APK 中的 dex 文件)会在后台进行 AOT 编译。这是因为首次使用时进行编译可能开销过大,导致执行前出现不必要的延迟。注意,建议应用采用分块 (splits) 并放弃使用二级 dex 文件。
- Android 中的共享库(Android 清单中的 <library> 和 <uses-library> 条目)使用了与平台先前版本不同的类加载器层级结构来实现。
全屏 Intent 的权限变更
以 Android 10 或更高版本为目标并使用带有全屏 Intent 的通知的应用,必须在其应用的清单文件中请求 USE_FULL_SCREEN_INTENT 权限。这是一种普通权限,因此系统会自动授予请求该权限的应用。
如果以 Android 10 或更高版本为目标的应用在未请求必要权限的情况下尝试创建带有全屏 Intent 的通知,系统会忽略该全屏 Intent 并输出以下日志消息:
Package your-package-name: Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission
对可折叠设备的支持
Android 10 包含支持可折叠设备和大屏设备的变更。
当应用在 Android 10 上运行时,onResume() 和 onPause() 方法的工作方式会有所不同。当多个应用同时出现在多窗口或多显示模式下时,所有可见堆栈中可聚焦的顶部 Activity 都处于 resumed 状态,但只有一个(即“最顶层 resumed”的 Activity)实际上拥有焦点。在 Android 10 之前的版本上运行时,系统中一次只能有一个 Activity 处于 resumed 状态,所有其他可见 Activity 都会暂停。
请勿将“焦点”与“最顶层 resumed”的 Activity 混淆。系统根据 Z 轴顺序为 Activity 分配优先级,以便为用户最近交互过的 Activity 提供更高的优先级。一个 Activity 可以是 top-resumed,但不一定拥有焦点(例如,如果通知栏已展开)。
在 Android 10 (API 级别 29) 及更高版本中,您可以订阅 onTopResumedActivityChanged() 回调,以便在您的 Activity 获得或失去最顶层 resumed 位置时收到通知。这相当于 Android 10 之前的 resumed 状态,如果您的应用正在使用可能需要与其他应用共享的独占或单例资源,这可以作为一个有用的提示。
resizeableActivity 清单属性的行为也发生了变化。如果应用在 Android 10 (API 级别 29) 或更高版本中设置了 resizeableActivity=false,当可用屏幕尺寸发生变化,或者应用从一个屏幕移动到另一个屏幕时,它可能会被置于兼容模式。
应用可以使用 Android 10 中引入的 android:minAspectRatio 属性来指示您的应用支持的屏幕比例。
从 3.5 版本开始,Android Studio 的模拟器工具包含 7.3 英寸和 8 英寸虚拟设备,供您在更大屏幕上测试代码。
有关详细信息,请参阅为可折叠设备设计应用。