Android 10 系统组件模块化

Android 10模块化了一些Android系统组件,使其能在Android大版本升级之外进行独立升级,即系统组件模块化(Modular System Components)。这些模块化的系统组件打包到一起,可以通过OTA方式推送给终端用户进行升级。模块升级不会引入新的API ,仅使用CTS验证过的SDK和系统API,以及稳定的C API或稳定的AIDL接口。

模块化的系统组件主要有:

模块名 包名 类型
Runtime com.android.runtime.release.apex APEX
Captive Portal Login com.android.captiveportallogin APK
Conscrypt com.android.conscrypt APEX
DNS Resolver com.android.resolv APEX
DocumentsUI com.android.documentsui APK
ExtServices com.android.ext.services APK
Media Codecs com.android.media.swcodec APEX
Media Extractors and MediaPlayer2 com.android.media APEX
ModuleMetadata com.android.modulemetadata APK
Network Stack Permission Configuration com.android.networkstack.permissionconfig APK
Network Components com.android.networkstack APK
PermissionController com.android.permissioncontroller APK
Time Zone Data com.android.tzdata APEX

1. Android Runtime

Runtime(com.android.runtime.release.apex)是用于原生和托管Android runtime的APEX模块。该模块包括以下组件:

(1)ART

构建Android时会生成Runtime模块和其它编译组件。它与Conscrypt(com.android.conscrypt.apex)和时区数据(com.android.tzdata.apex)紧密结合,也是Android 10中的新功能。

在Android 10中,ART编译系统以两种变体创建Runtime模块:发布和调试。发行版本安装在user版本上,调试版本安装在userdebug和eng版本上。当设备启动时,apexd将runtime模块安装在/apex/com.android.runtime下。在该模块中,启动类路径分为托管核心库类,其他模块中的类(如Conscrypt和Media)以及系统分区中的类(如framework.jar)之间进行拆分。如果更新模块,dex2oat JIT将编译模块中的引导类。

Android 10 中的API变化有:DEX文件支持的新API提供了系统代码和ART之间的稳定接口。新API用作系统的ART特定平台抽象层(PAL)。系统元素(libartpalette-system.so)提供了ART所依赖的系统功能,可通过客户端库(libartpalette.so)进行访问,该库可加载设备上安装的系统库。

Android 10还重构了一些ART二进制文件的路径,将以下二进制文件从/system/bin移动到Runtime模块:dalvikvm,dalvikvm32,dalvikvm64,dex2oat,dexdiag,dexdump,dexlist,dexoptanalyzer,oatdump和profman。为了兼容性,重构包括/system/bin中的符号链接。

(2)Bionic

libc的tzcode使用Runtime(/apex/com.android.runtime/etc/tz/)和时区数据(/apex/com.android.tzdata/etc/tz/)提供的时区数据。tzcode通过基于APEX的时区更新(由时区数据提供)对来自基于APK的时区更新的数据进行优先级排序,并回退到/system数据。libc使用新库(libandroidicu)而不是libicuuc / libicui18n。另外,Bionic共享库和动态链接器路径现在是符号链接(适用于64位变体)。如:

1
2
3
4
/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

(3)托管核心库(Android 10新功能)

托管核心库是一个低层级,可更新,托管式(由Android Runtiem执行的dex)代码的集合,以前称为libcore。在Android 10中,托管核心库包括多个Git项目(除了platform/libcore/),指的是代码集合。

托管核心库由Runtime,Time Zone Data和Conscrypt提供,并依赖于Runtime中存在的本机库,例如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元数据。

核心平台API提供了一个稳定的托管代码API供Android框架使用,通过确保清楚地理解所有framework依赖关系来更新托管核心库。核心平台API:表示除公共SDK API之外的依赖项。如libcore/mmodules/core_platform_api/。使用@ libcore.api.CorePlatformApi显式标注托管代码。如libcore/ojluni/annotations/mmodule/中的注释。

编译系统默认在编译Java源代码平台目标时使用核心平台API(即在.bp文件中没有“sdk_version:”或.mk文件中没有“LOCAL_SDK_VERSION =”)。此默认行为可确保Android框架代码仅限于使用公共API和核心平台 API(无实现类)。其他sdk_version值(如“core_current”和“current”)正常工作(它们仅允许使用公共SDK API)。编译系统还报告对核心平台API表面的更改,并防止目标(少数情况例外)依赖于托管核心库内部。

Runtime对核心平台API涵盖的字段和方法执行访问检查。当平台代码访问核心平台API中的方法时,将执行检查。系统属性persist.debug.dalvik.vm.core_platform_api_policy控制这些检查遵循的策略。有效的策略值enabled,disabled和just-warn。对于debug和eng版本,标准策略just-warn,它会在检测到策略违规时记录警告。对于user版本,默认disabled并且不执行任何操作。当本机代码通过Java本机接口(JNI)解析字段和方法时,Runtime模块还会执行核心平台API检查。

Android 10还包含许多更改,以简化Android框架和托管核心库之间的API,运行时依赖项和编译时依赖项。Android 10重新打包com.android.org.kxml2下的org.kxml2解析器。

(4)Native库

Android 10重构支持管理核心库的本机库。之前与平台其他部分共享的几个动态链接库(例如,libcrypto,libexpat和zlib)现在已复制,因此Runtime模块将自己的副本加载到运行时链接程序命名空间中。 Runtime模块提供的动态链接本机库位于/apex/com.android.runtime/{lib,lib64}中。

(5)ICU库

Runtime包括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的符号链接。

(6)libnativebridge

Android 10将libnativebridge库移到了Runtime模块,因为该库与libnativeloader和作为Runtime模块一部分的Bionic C库紧密耦合。

(7)libnativehelper

在Android 10中,Runtime模块使libnativehelper可用于系统和框架代码,而Runtime模块之外的代码则链接到libnativehelper的存根API(仅限C)。libnativehelper库包括:

a. 减少了一组缓存的JNI类,方法和字段。

b. 改进了platform_include/jni_macros.h中的JNI宏。

c.用于从本机代码访问java.nio.Buffer类内部的新JNI帮助器方法(libnativehelper/include/nativehelper/JNIHelp.h中以jniGetNio开头的方法)。框架代码使用这些方法。

(8)libnativeloader

在Android 10中,Runtime模块包含libnativeloader库,该库负责为Java类加载器创建链接器名称空间。链接器名称空间适用于由托管代码编写的Android应用程序加载的本机库。该库与Bionic链接器紧密耦合,Bionic链接器也在模块中。

(9)链接器配置更改

在Android 10中,链接器命名空间用于将Runtime模块中的内部动态本机库依赖项与平台和其他APEX模块分开。运行时链接程序命名空间是为运行时模块库设置的,具有与外部依赖项的其他命名空间之间的适当链接。

链接器配置驻留在/system/etc/ld.config.txt中,用于/vendor和/system中的二进制文件,以及/etx/com.android.runtime/etc/ld.config.txt中的二进制文件,用于运行时模块本身中的二进制文件( /apex/com.android.runtime/bin)。

(10)SystemServer和框架更改

在Android 10中,SystemServer管理一个新的RuntimeService,用于报告来自Runtime模块的信息。使用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和Runtime模块中的其他工具。

(11)启动顺序更改

为了支持Runtime模块,Android 10将启动顺序更新为以下内容:

a. init准备引导程序和默认的mount命名空间。tmpfs挂载在/apex上,挂载点的传播类型设置为private。

b. apexd在任何其他进程之前以引导模式启动。它激活/system/apex中的APEX文件,并将它们挂载在bootstrap mount命名空间中。

c. 其他pre-apexd流程开始。这些进程位于引导程序挂载命名空间中,并提供有来自系统APEX文件的库。

d. /data挂载。init切换到默认的mount命名空间并启动apexd作为守护进程。

e. apexd扫描/data/ape和/system/apex并激活这些目录中的最新APEX文件。在此阶段激活的APEX文件仅挂载在默认命名空间中,并且对于pre-apexd进程不可见。

2. Conscrypt

Conscrypt可以加速安全性改进并提高设备安全性,而无需依赖OTA升级。它使用Java代码和本机库来提供Android TLS实现以及大部分Android加密功能,如密钥生成器,密码和消息摘要。Conscrypt作为开源库提供,但它包含在Android平台中时有一些特殊化。

Conscrypt使用BoringSSL,是OpenSSL的Google分支本地库,在许多Google产品中用于加密和TLS。BoringSSL没有正式版本(所有用户都是从头部构建的)并且不保证API或ABI的稳定性。

Android 9不包含针对Conscrypt的特定于Android的公共API,而是使用实现Java加密体系结构(JCA)标准类的安全提供程序,包括Cipher和MessageDigest,以及Java安全套接字扩展(JSSE),包括SSLSocket和SSLEngine。用户与这些类交互,libcore或框架代码使用一些非公开的Conscrypt API。

Android 10在android.net.ssl中添加了少量公共API方法,以访问未在javax.net.ssl下的类公开的Conscrypt功能。Android 10还包括一个精简的Bouncy Castle副本,作为Android Runtime的一部分提供较低流行度的加密工具(未包含在Conscrypt模块中)。

Conscrypt最终以APEX形式分发,其中包含Conscrypt Java代码和动态链接到Android NDK库(如liblog)的Conscrypt本机库。本机库还包括一个BoringSSL副本,该副本在AArch64上具有加密算法验证程序(CAVP)认证。此副本尚未通过NIST的认证测量和验证专业人员(CMVP)进行验证。

Conscrypt模块包括/external/onscrypt和/external/boringssl,但不包括/external/bouncycastle。

Conscrypt模块公开以下API:

(1)公共API,是java.和javax.下的包中的类和接口的扩展,以及android.net.ssl.*下的类。外部应用程序代码不直接调用Conscrypt。平台API标准确保这些API保持向后兼容。

(2)核心平台API,是框架用于访问非公共功能的隐藏API。这些相对有限;最大的用户是NetworkSecurityConfig,它扩展了Conscrypt信任管理器(验证证书的组件)以实现网络安全配置功能。

(3)内核API,仅限于由JCA和JSEE机制反射调用的零参数构造函数。

3. DNS解析器(DNS Resolver)

DNS解析器为DNS拦截、配置更新攻击提供保护,能提高DNS解析的网络性能。该模块包含实现DNS存根解析器的代码,该解析器将诸如www.google.com之类的域名转换为IP地址,例如2001:db8 :: 1。 DNS存根解析器支持Java API元素,如InetAddress#getAllByName和Network#getAllByName,以及本机网络功能,并实现发送和接收DNS查询以及缓存结果。

DNS解析器最终以APEX文件形式呈现,并由netd动态链接,直接为本地套接字/dev/socket/dnsproxyd提供服务。解析器配置的Binder端点从netd移到解析器,这意味着系统服务可以直接调用解析器模块而无需通过netd。DNS解析器模块依赖于libc(Bionic)并静态链接其依赖关系,不需要其他库。

在Android 9之前,DNS解析器代码分布在Bionic和netd上。DNS查找集中在netd守护程序中以允许系统范围的缓存,而应用程序在Bionic中调用函数(例如getaddrinfo)。查询通过UNIX套接字发送到/dev/socket/dnsproxyd到netd守护程序,netd守护程序解析请求并再次调用getaddrinfo以发出DNS查找,然后缓存结果以便其他应用程序可以使用它们。DNS解析器实现主要包含在bionic/libc/dns/中,部分包含在system/netd/server/dns中。

Android 10将DNS解析器代码移动到system/netd/resolv,将其转换为C ++,然后对代码进行了重构。Bionic中的代码因应用程序兼容性原因继续存在,但系统不再调用。下面这些源码路径受到影响:

(1)bionic/libc/dns

(2)system/netd/client

(3)system/netd/server/dns

(4)system/netd/server/DnsProxyListener.*

(5)system/netd/resolv

4. DocumentsUI

DocumentsUI控制对处理文档权限的组件(例如将文件附加到电子邮件)的特定文件的访问。使存储访问和权限进入可更新模块可以增加用户的隐私和安全性,同时允许Android partner通过RRO(Runtime Resource Overlay)自定义应用的功能和主题。DocumentsUI最终以APK形式呈现,它依赖于受签名权限保护的MANAGE_DOCUMENTS权限。

Android 10中,DocumentsUI实现了GET_CONTENT操作,该操作使app能够请求访问用户的其他数据。作为可更新的模块,DocumentsUI:

(1)仅通过稳定的@SystemApi API(不使用@hide API)与framework进行交互。

(2)公开了一种机制,使Android partner能够自定义功能和主题。

(3)使用签名权限保护MANAGE_DOCUMENTS权限。

5. ExtServices

ExtServices模块更新framework组件,例如存储,自动填充,通知助手和其他不断运行的服务。该模块与DocumentsUI和PermissionController一起,确保最终用户获得一致的权限UI,同时启用迭代以响应不断变化的隐私环境和政府法规。

com.android.ext.services APK包含以下服务:

(1)AutofillFieldClassificationService

(2)NotificationAssistantService

(3)ResolverRankerService

(4)CacheQuotaService

6. Media Codecs

Media更新机制如下:

现有的OMX编解码器API不可更新,但OEM仍然可以在10中vendor分区中使用它。在10中,SW Codec2组件是可更新的。

对于媒体编解码器,partner需要设置vendor编解码器服务。框架/av/media/codec2/hidl/services/提供了服务的框架实现。该服务需要使用frameworks/av/media/codec2/core/中定义的Codec 2.0接口来调用其组件的实现。 该库的入口点是C2ComponentStore接口,可以在frameworks/av/media/codec2/vndk/C2Store.cpp中引用Android的默认软件编解码器存储实现。

partner可以使用类似于mediaswcodec服务的APEX加载行为。vendor编解码器服务流程的结构与mediaswcodec类似。可以定义和打包负责注册所有C2组件的顶级共享库(具有传递依赖性)到驻留在vendor分区上的APEX包。然后vendor编解码器服务进程可以在启动时加载此顶级入口点。

7. Media Extractors and MediaPlayer2

(1)Media Extractors

为了准备可更新性,媒体提取器Media Extractors已经被制作成单独的组件(而不是编译成libstagefright.so)。它们进一步更新为仅依赖于NDK API。

每个提取器都有自己的.so文件。.so有一个入口点,它提供一个sniffer函数来确定提取器是否可以处理给定的媒体文件,以及一个factory函数,它为给定的媒体文件创建一个提取器实例。每个提取器都被命名和版本化。命名有助于调试,而版本控制指示哪个提取器是最新的。因为Android加载所有可用的提取器.so文件,OEM只需添加新的.so文件即可添加自己的提取器,而无需修改libstagefright或其他媒体框架库。如果OEM更新提取器,那么Google会找到并使用它们(如果需要,有多种方法可以确保OEM提取器优于Google提供的提取器)。

对于媒体提取器,如果Google的默认提取器不符合要求,partner可以使用自己的提取器插件。自定义提取器插件可以放在/system/lib [64]/extractors/下,并且提取器进程从Google APEX包和/system/lib [64]/extractors/加载提取器插件。

(2)MediaPlayer2

Android 10中添加的MediaSession2 API使用一个过程,允许媒体应用程序向其他进程(包括Android框架和其他应用程序)公开其传输控件和回放信息。

对于MediaSession2,在代码为AOSP设备开源时,不允许进行vendor修改。对于传统MediaPlayer和MediaSession API的现有修改,vendor应尽可能向其上游进行更改。当无法进行上游时,Google会考虑通过逐个审核来提供扩展。

8. ModuleMetadata

ModuleMetadata包含设备上的模块列表的元数据。一旦系统服务器启动,就会解析和缓存元数据。ModuleMetadata APK包含ModuleInfoProvider,它实现PackageManager API中的getModuleInfo和getInstalledModules方法。这些方法由从模块元数据提供程序包解析的XML元数据支持。模块元数据包的包名称存储config_defaultModuleMetadataProvider配置值中。

模块元数据提供程序必须包含标记的条目。元数据条目必须包含单个键(android.content.pm.MODULE_METADATA),其值是对XML资源的引用,该XML资源包含设备上的模块列表的元数据。

ModuleMetadata模块作为APK文件,在XML文档中,元数据包括具有一个或多个子元素的单个顶级元素。每个子节点都是元素,包含以下属性:

(1)name是对用户可见包名称的资源引用。映射到ModuleInfo#getName。

(2)packageName是模块的包名称。映射到ModuleInfo#getPackageName。

(3)isHidden表示模块是否被隐藏。映射到ModuleInfo#isHidden。

例如:

1
2
3
4
<module-metadata>
<module name="@string/resource" packageName="package_name" isHidden="false|true" />
<module .... />
</module-metadata>

9. 网络堆栈权限配置Network Stack Permission Configuration

网络堆栈权限配置不包含代码,而是定义了供网络堆栈和强制网络门户登录模块使用的权限。系统允许获得此权限的模块在设备上执行相关的网络配置任务。

10. 网络组件Network Components

网络组件可确保Android能够适应不断发展的网络标准,并允许与新实施的互操作性。例如,对强制门户检测和登录代码的更新允许Android通过更改强制门户模型保持最新,并且高级策略防火墙(APF)的更新允许Android在新类型的数据包变得普遍时节省Wi-Fi的电力。

网络组件模块包含以下组件:

(1)IP服务。 IpClient(以前称为IpManager)组件处理IP层配置和维护。在Android 9中,它被蓝牙等组件交叉处理,并通过Wi-Fi等组件进行处理。 DhcpClient组件从DHCP服务器获取IP地址,以便将它们分配给接口。

(2)NetworkMonitor。 NetworkMonitor组件在连接到新网络或网络故障时,检测强制网络门户以及验证网络时测试互联网可达性。

(3)强制门户登录应用程序。Captive门户登录应用程序是一个预装的应用程序,负责管理强制门户网站的登录。这是自Android 5.0以来的一个单独的应用程序,但它与NetworkMonitor交互以将一些用户选择转发到系统。

在使用“网络组件”模块的设备上,上述服务将重构为不同的进程,并使用稳定的AIDL接口进行访问。重构路径如下表所示。

IP服务重构路径:

Android 9及之前版本 frameworks/base/services/net/java/android/net/: apf,dhcp,ip,netlink,util (partly)
Android 10 packages/modules/NetworkStack

强制门户登录重构路径:

Android 9及之前版本 在frameworks/base/:core/java/android/net/captiveportal/,services/core/java/com/android/server/connectivity/NetworkMonitor.java,packages/CaptivePortalLogin/ (where = wildcard)
Android 10 packages/modules/CaptivePortalLogin

网络组件模块作为三个APK提供:一个用于IP服务,一个用于强制门户登录,一个用于网络堆栈权限配置。网络组件取决于以下内容:

(1)系统服务器中的特权@hide方法(如在IConnectivityManager.aidl中)。 这些API已使用@SystemApi注释并受到适当保护,以便模块可以访问它们,但不能访问其他特权应用程序(例如,使用新的签名权限)。

(2)在INetd.aidl中定义的Binder IPC至netd。 此接口已转换为稳定的AIDL,并且需要进行一致性测试。

11. PermissionController

PermissionController模块启用可更新的隐私策略和UI元素(例如,围绕授予和管理权限的策略和UI)。此模块处理与权限相关的UI和逻辑(它是从Package Installer重构的)和角色(允许为特定目的访问应用程序)。

com.android.permissioncontroller APK处理与权限相关的UI,逻辑和角色,以允许为特定目的访问应用程序,主要控制内容有:

(1)运行时权限授予(包括授予系统应用程序)。
(2)运行时权限管理(包括权限分组)。
(3)运行时权限使用情况跟踪(Android 10新功能)。
(4)角色(Android 10新功能)。

在Android 9中,此类权限是com.android.packageinstaller的一部分。在Android 10及更高版本中,Package Installer应用程序将被拆分以启用权限逻辑更新。作为可更新的Android模块,PermissionController:

(1)仅通过稳定的@SystemApi API(不使用@hide API)与framework进行交互。
(2)处理优先级大于0的权限相关intent。
(3)公开了一种机制,使Android partner能够自定义主题。
(4)提供系统和应用程序可以绑定的服务,包括角色管理,权限撤销和基本权限信息(对于“设置”)。

12. Time Zone Data

时区数据更新Android设备上的夏令时(DST)和时区,标准化数据(可以根据宗教,政治和地缘政治原因频繁更改)和整个生态系统的更新机制。

Android 10弃用了基于APK的时区数据更新机制(在Android 8.1和Android 9中使用),并将其替换为基于APEX的模块更新机制。AOSP继续包含基于APK的更新所需的平台代码,因此升级到Android 10的设备仍然可以通过APK接收partner提供的时区数据更新。但是,不应在同时接收模块更新的生产设备上使用APK更新机制,因为基于APK的更新会取代基于APEX的更新(即接收APK更新的设备会忽略基于APEX的更新)。