运行时模块 (com.android.runtime.release.apex
) 是用于原生和托管 Android 运行时的 APEX 模块。该模块包含以下组件:
- ART
- Bionic
- 托管核心库(Android 10 中的新组件)
- ICU 库
libnativebridge
libnativehelper
libnativeloader
运行时模块是在构建 Android 时生成的,包含其组成项目的构建工件。它与 Conscrypt 模块 (com.android.conscrypt.apex
) 以及时区数据模块 (com.android.tzdata.apex
) 紧密相关,后者也是 Android 10 中的新模块。
Android Runtime (ART) 方面的变更
在 Android 10 中,ART 构建系统以两种变体形式创建运行时模块,分别为发布和调试(包含更多诊断和调试工具)。发布版本安装在 user
build 上,调试版本安装在 userdebug
和 eng
build 上。当设备启动时,apexd
会将运行时模块装载到 /apex/com.android.runtime
下。
在该模块中,启动类路径拆分为托管核心库等类、其他模块(例如 Conscrypt 和媒体)中的类以及系统分区(例如 framework.jar
)中的类。如果更新了模块,dex2oat 会以 JIT 方式编译模块中的启动类。
Android 10 包含 API 方面的以下变更:
- 新增了一个用于支持 DEX 文件的 API,可在系统代码(例如堆栈展开程序)和 ART 之间提供稳定的接口。
- 新增了一个 API,作为 ART 专用平台抽象层 (PAL) 与系统配合使用。系统元素 (
libartpalette-system.so
) 提供了 ART 所依赖的系统功能,并且可通过客户端库 (libartpalette.so
) 进行访问,该客户端库可加载设备上安装的系统库。
Android 10 还重构了一些 ART 二进制文件的路径,并将以下二进制文件从 /system/bin
移到了运行时模块中:dalvikvm
、dalvikvm32
、dalvikvm64
、dex2oat
、dexdiag
、dexdump
、dexlist
、dexoptanalyzer
、oatdump
和 profman
。为了确保兼容性,重构涵盖 /system/bin
中的符号链接。
Bionic 方面的变更
libc
的 tzcode
使用由运行时模块 (/apex/com.android.runtime/etc/tz/
) 和时区数据模块 (/apex/com.android.tzdata/etc/tz/
) 提供的时区数据。tzcode
会优先采用基于 APK 的时区更新中的数据,然后再采用基于 APEX 的时区更新中的数据(由时区数据模块提供),最后回退到 /system
数据。
libc
使用新库 (libandroidicu
),而不是 libicuuc
/libicui18n
。如需了解详情,请参阅托管核心库。
最后,Bionic 共享库和动态链接器路径现在是符号链接(同样适用于 64 位变体)。具体而言,变更情况如下:
/system/lib/libc.so
->/apex/com.android.runtime/lib/bionic/libc.so
/system/lib/libm.so
->/apex/com.android.runtime/lib/bionic/libm.so
/system/lib/libdl.so
->/apex/com.android.runtime/lib/bionic/libdl.so
/system/bin/linker
->/apex/com.android.runtime/bin/linker
启动序列方面的变更
为了支持运行时模块,Android 10 的启动序列更新如下:
init
准备引导程序和默认的装载命名空间。tmpfs
装载在/apex
上,装载点的传播类型设置为private
。apexd
在其他任何进程之前会以引导程序模式启动。它会激活/system/apex
中的 APEX 文件,并将它们装载到引导程序装载命名空间中。- 其他预
apexd
进程启动。这些进程位于引导程序装载命名空间中,并随系统 APEX 文件中的库一起提供。 /data
执行装载。init
切换到默认的装载命名空间,并将apexd
作为守护程序启动。apexd
扫描 /data/apex
和/system/apex
,并激活这些目录中最新的 APEX 文件。在此阶段激活的 APEX 文件只能装载在默认命名空间中,并且对预apexd
进程不可见。
托管核心库
托管核心库是可更新的低层级托管式(由 Android Runtime 执行 dex
)代码的集合,以前称为 libcore。在 Android 10 中,托管核心库包含多个 Git 项目(含 platform/libcore/
),这一新术语指的是代码的集合。
托管核心库由运行时、时区数据和 Conscrypt 模块提供,并依赖于运行时模块中存在的原生库,例如 libjavacore
和 libandroidicu
。所收集的代码来自多个 Git 项目,例如 libcore
、apache-xml
、boringssl
、bouncycastle
、conscrypt
、expat
、fdlibm
、icu
、okhttp
、ziparchive
和 zlib
。该库在启动类路径上的多个 .jar
文件(例如 core-oj.jar
、core-libart.jar
、conscrypt.jar
、okhttp.jar
、bouncycastle.jar
和 apache-xml.jar
)之间进行拆分;但是,其中并不包括 framework.jar
和 ext.jar
文件。
组件重新打包
Android 10 重新打包了以前使用字节码处理工具在 android.*
和 com.android.*
下打包的几个组件(bouncycastle/
、conscrypt/
和 okhttp/
)。这些组件使用源代码转换重新打包,从而使 Java 注释能够用于 API 元数据。
Core Platform API
Core Platform API 提供了供 Android 框架使用的稳定的托管代码 API,它可确保系统能够清楚地了解所有框架依赖项,从而能够对托管核心库进行更新。Core Platform API 具有以下功能:
- 指示包括公共 SDK API 在内的依赖项。如需了解 API 相关的内容,请参阅
libcore/mmodules/core_platform_api/
。 - 使用
@libcore.api.CorePlatformApi
明确标注托管代码。对于libcore/ojluni/src/
中的代码,请参阅libcore/ojluni/annotations/mmodule/
中的注释;对于所有其他项目,请参阅主源代码文件。
构建系统在构建 Java 源代码平台目标(即 .bp
文件中缺少 "sdk_version:"
或者 .mk
文件中缺少 "LOCAL_SDK_VERSION="
)时默认使用 Core Platform API。此默认行为可确保 Android 框架代码只能使用公共 API 和 Core Platform API(无实现类)。其他 sdk_version
值(例如 "core_current"
和 "current"
)将正常工作(它们仅允许使用公共 SDK API)。构建系统还会报告对 Core Platform API 界面所做的更改,并防止目标(少数例外情况除外)依赖于托管核心库内部构件。
运行时模块对 Core Platform API 涵盖的字段和方法执行访问权限检查。当平台代码访问 Core Platform API 中的方法时,模块将执行检查。系统属性 persist.debug.dalvik.vm.core_platform_api_policy
用于控制这些检查所遵循的政策。有效的政策值为 enabled
、disabled
和 just-warn
。对于 debug 和 eng build,标准政策为 just-warn
,用于在检测到违反政策的情况时记录一条警告。对于 user build,默认政策为 disabled
,并且不执行任何操作。当原生代码通过 Java 原生接口 (JNI) 解析字段和方法时,运行时模块也会执行 Core Platform API 检查。
Android 10 还进行了大量更改,用于简化 Android 框架与托管核心库之间的 API、运行时依赖项以及构建时依赖项。
Android 10 重新打包了 com.android.org.kxml2
下的 org.kxml2
解析器。
原生库
Android 10 重构了支持托管核心库的原生库。现在已复制之前与平台的其他部分共用的几个动态链接库(如 libcrypto
、libexpat
和 zlib
),使得运行时模块可以将自己的副本加载到运行时链接器命名空间中。运行时模块提供的动态链接原生库位于 /apex/com.android.runtime/{lib,lib64}
中。
ICU 库
运行时模块包含 ICU 库(ICU4C 和 ICU4J)及关联数据。
Android 10 包括 libandroidicu
,这是一个新的动态库,可以为框架代码提供部分 ICU4C 函数。libandroidicu
的链接器符号在各个 ICU 版本之间是固定的(该符号以 _android
结尾,而不是以 libicuuc
和 libicui18n
中使用的 _icu-version-number
结尾)。但是,为了确保应用兼容性,libicuuc
和 libicui18n
符号仍然可用。同样,为了确保应用兼容性,链接器还会在 dlopen() 调用中将绝对路径重定向到 ICU 库,也就是说,dlopen("/system/lib/libicuuc.so",
...)
和 dlopen("/system/lib/libicui18n.so", ...)
会重定向到 /apex/com.android.runtime/lib/
中相应的库(如果应用符合 targetSdkVersion < 29
这一情况)。
在运行时,ICU 数据文件将安装到 /apex/com.android.runtime/etc/icu/
。为了确保应用兼容性,Android 10 还包含从之前的 ICU 数据文件位置 (/system/usr/icu/
) 到 /apex/com.android.runtime/etc/icu
的符号链接。
Conscrypt 互动
Android 10 将 Conscrypt(逻辑上是托管核心库的一部分)移到了其自身可独立更新的 APEX 模块中。在 Conscrypt 和运行时模块之间,除公共 SDK API 之外,还有一个新的双向 API 接口可指示依赖项(如需了解详情,请参阅 libcore/mmodules/intracoreapi/
)。API 元素使用 @libcore.api.IntraCoreApi
明确注解。
构建系统会验证 Conscrypt 代码是否只能使用公共 API 和核心内 API。Conscrypt 上的其他托管核心库依赖项基于反射;构建系统会尽可能记录此类依赖项,并向 API 接口报告所有更改。
时区数据互动
在 Android 10 中,架构 libcore、运行时 libcore 和 ICU4J/ICU4C 使用由运行时模块 (/apex/com.android.runtime/etc/tz/
) 以及时区数据模块 (/apex/com.android.tzdata/etc/tz/
) 提供的时区数据。此类库具有以下特点:
- 回退到
/system
数据。 - 优先采用基于 APK 的时区更新中的数据,然后再采用基于 APEX 的时区更新中的数据(由时区数据模块提供)。
其他方面的变更
Android 10 将 AsynchronousCloseMonitor
API 从 libnativehelper.so
移到了 libandroidio.so
。该 API 由 AsynchronousCloseMonitor.h
提供。
libnativebridge 方面的变更
Android 10 将 libnativebridge
库移到了运行时模块,因为此库与运行时模块中的 libnativeloader
库和 Bionic C 库紧密关联。
libnativehelper 方面的变更
在 Android 10 中,运行时模块使 libnativehelper
可用于系统代码和框架代码,而运行时模块之外的代码则链接到 libnativehelper
的存根 API(仅限 C)。libnativehelper
库进行了如下变更:
- 减少了缓存的 JNI 类、方法和字段。
- 改进了
platform_include/jni_macros.h
中的 JNI 宏。 - 新增了一些 JNI 帮助程序方法,用于访问原生代码中的
java.nio.Buffer
类的内部构件(请参阅libnativehelper/include/nativehelper/JNIHelp.h
中名称以jniGetNio
开头的方法)。框架代码也会使用这些方法。
libnativeloader 方面的变更
在 Android 10 中,运行时模块包含 libnativeloader
库,该库负责为 Java 类加载器创建链接器命名空间。链接器命名空间适用于以托管代码编写的 Android 应用所加载的原生库。该库与同样位于运行时模块中的 Bionic 链接器紧密关联。
libpac 方面的变更
Android 10 将可为 PacProcessor 提供 C API 的 libpac
移到了运行时模块中。libpac
库包含一个完整的 V8 JavaScript 引擎,只能由 PacProcessor(一个独立的软件包和进程)使用。
链接器配置方面的变更
在 Android 10 中,链接器命名空间用于将运行时模块中的内部动态原生库依赖项与平台和其他 APEX 模块分开。runtime
链接器命名空间是为运行时模块库设置的,并在外部依赖项的其他命名空间之间提供了适当的链接。
对于 /vendor
和 /system
中的二进制文件,链接器配置位于 /system/etc/ld.config.txt
中;对于运行时模块本身中的二进制文件 (/apex/com.android.runtime/bin
),链接器配置位于 /apex/com.android.runtime/etc/ld.config.txt
中。
SystemServer 和框架方面的变更
在 Android 10 中,SystemServer 托管了一项新的 RuntimeService,用于报告来自运行时模块的信息。如需查看这些信息,请使用以下 ADB 命令:
adb shell dumpsys runtimeinfo
RuntimeService 管理的信息是可扩展的。如需了解服务源代码,请参阅 frameworks/base/services/core/java/com/android/server/RuntimeService.java
;如需查看客户端代码示例,请参阅 libcore/luni/src/main/java/libcore/util/CoreLibraryDebug.java
。
Android 10 还更新了无线下载 (OTA) 更新流程,以使用运行时模块中的 dex2oat
和其他工具。