本文摘要
这是包管理系列的第四篇文章,apk信息指的是AndroidManifest.xml文件中配置的各种信息,通过本文您将了解到apk信息为啥如此重要,apk信息的解析,apk信息最终被存放在哪。(文中代码基于Android13)本文大纲
4. 总结
首先apk信息指的是AndroidManifest.xml文件中配置的各种信息,比如apk版本信息、apk包名、声明了哪些四大组件、使用了哪些权限、声明了哪些权限、使用了哪些共享库等。首要的原因是因为apk信息对于PackageManagerService服务来说非常的重要,PackageManagerService管理的对象是apk,而要想知道apk内包含了哪些内容是不是需要从AndroidManifest.xml文件中获取到apk信息,只有获取到apk信息才能对apk进行管理。其次是PackageManagerService很多的模块都是为apk信息服务的,比如共享库模块是为apk声明共享库 (在AndroidManifest.xml文件中使用library标签)和使用共享库 (在AndroidManifest.xml文件中使用uses-library标签)信息服务的,权限管理模块是为apk声明权限 (在AndroidManifest.xml文件中使用permission标签)和使用权限 (在AndroidManifest.xml文件中使用uses-permission标签)信息服务的。说了这么多apk信息的重要性,那我们来看下apk信息是如何解析的吧?
PackageManagerService要想知道apk信息,就得需要从apk的AndroidManifest.xml文件中把这些信息解析为对应的标签数据类,那就来介绍下这些数据类吧。介绍数据类时秉持从小到大的原则来介绍,啥叫从小到大呢,也就是先把AndroidManifest.xml文件中的常用小标签对应的数据类开始,逐步在来介绍更大一些的标签对应的数据类,那先从四大组件开始。2.1 四大组件对应的标签数据类
大家都知道四大组件对应的标签是activity、receiver、service、provider,下图展示了它们的类图关系。图解
ParsedComponent
很多的标签都存在一些共同的配置信息,如下代码activity和permission标签都存在android:icon和android:banner配置信息,而ParsedComponent接口的作用就是把多个标签共有的配置信息收集起来,提供统一的方法<activity android:icon="" android:banner="">
<permission android:icon="" android:banner=""/>
ParsedComponentImpl
该类从名字上看就知道它是实现了ParsedComponent接口。ParsedMainComponentImpl
上图没有体现出来,该类实现了ParsedMainComponent接口,而该接口的作用是把四大组件的标签共有的配置信息收集起来,提供统一的方法,如下代码展示了一些共有的配置信息。<provider android:name="" android:process="" android:enabled="" android:exported=""/>
<service android:name="" android:process="" android:enabled="" android:exported=""/>
<receiver android:name="" android:process="" android:enabled="" android:exported=""/>
<activity android:name="" android:exported="" android:enabled="" android:process="">
ParsedActivityImpl
activity、receiver这两个标签会被解析为ParsedActivityImpl类,标签中配置的数据自然而然的就存放在该类中,如android:launchMode配置的信息存放在该类的launchMode属性中。下图是ParsedActivityImpl的继承关系。ParsedActivity是一个接口,它定义了activity和receiver标签独有的接口,而ParsedActivityImpl类实现了ParsedActivity接口同时也继承了ParsedMainComponentImpl类。
ParsedServiceImpl
service标签会被解析为该类,而该类也继承了ParsedMainComponentImpl类,并且它也实现了自己的接口ParsedService。ParsedProviderImpl
provider标签会被解析为该类,它同样也继承了ParsedMainComponentImpl类,并且它也实现了自己的接口ParsedProvider。2.2 权限相关的标签数据类
安装在Android设备上的app基本都会使用到各式各样的权限,权限也属于常用到的标签,故介绍下它们。权限分为声明权限和使用权限。声明权限也就是app可以在AndroidManifest.xml中通过permission标签来声明权限,如下代码:"string resource"
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permissionGroup="string"
android:protectionLevel=["normal" | "dangerous" |
"signature" | ...] />
而使用权限就是在AndroidManifest.xml中通过uses-permission标签来使用权限,如下代码:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
图解
ParsedPermissionImpl
permission标签会被解析为该类,它实现了ParsedPermission接口。ParsedUsesPermissionImpl
uses-permission标签会被解析为该类,它实现了ParsedUsesPermission接口。因为AndroidManifest中的标签很多,只把常用的介绍完就够用了,如果大家想了解其他的标签可以遵循如下的原则:- 标签数据类的命名格式是ParsedXXXXImpl (如ParsedActivityImpl)。
- 每个标签数据类都有自己对应的接口,接口命名格式为ParsedXXXX (如ParsedActivity),即使像ParsedUsesPermissionImpl这么简单的类它都有自己的接口ParsedUsesPermission。
- ParsedComponentImpl类收集了大部分标签共用的信息,而它的接口是ParsedComponent。
- ParsedMainComponentImpl类收集了四大组件标签共用的信息,而它的接口是ParsedMainComponent。
2.3 AndroidManifest对应的数据类
AndroidManifest内有各种标签,基本每个标签都会有自己的标签数据类 (除了application、manifest标签),在AndroidManifest中每个标签都会被包含于某个大标签内 (如 application被包含于 manifest标签),同样也会有一个最终的标签数据类把所有的标签数据类都包含进来,这个类就是PackageImpl,如下是它的类图:图解
PackageImpl
AndroidManifest中的信息会对应一个PackageImpl实例,它实现了ParsedPackage、AndroidPackage接口,并且它继承了ParsingPackageImpl类,大部分逻辑可都是集中在ParsingPackageImpl类中ParsingPackageImpl
- activities它包含了很多的ParsedActivity。
- receivers它包含了很多的ParsedActivity。
- services它包含了很多的ParsedService。
- attributions它包含了很多的ParsedAttribution。
- permissions它包含了很多的ParsedPermission。
ParsingPackageImpl类的属性包含的都是各标签数据类的接口,这就是所谓的面向接口编程,好处就是该类基本不需要改动,比如ParseActivity又增加了一个子类,那在往ParsingPackageImpl中添加该子类的时候就不需要改动ParsingPackageImpl里的代码了。application和manifest标签并没有对应的标签数据类,它们配置的信息也是放在ParsingPackageImpl类中的,比如application标签中配置的android:name信息,它是存放在ParsingPackageImpl的类型为String的className属性中的。2.4 小结
- 四大组件对应的数据类分别是ParsedActivityImpl、ParsedServiceImpl、ParsedProviderImpl。
- 权限相关的标签permission、uses-permission对应的数据类是ParsedPermissionImpl、ParsedUsesPermissionImpl。
- AndroidManifest会对应一个PackageImpl实例,而它的父类ParsingPackageImpl存放了所有的数据类。
标签数据类有一个规则:每个类的命名规则是ParsedXXXXImpl (XXXX 代表对应的标签),每个类都有对应的接口命名规则是ParsedXXXX 。
从apk信息的诞生、apk信息的归属地、apk信息的消亡来介绍apk信息在PackageManagerService服务中的一生。3.1 apk信息的诞生
apk信息的诞生时机主要是在apk安装、apk升级、Android设备启动时扫描所有apk三种情况,不管哪种情况首要做的最重要的工作是从apk的AndroidManifest.xml文件中把配置信息解析出来,配置信息解析出来就代表apk信息诞生了。无论是apk安装、apk升级、扫描所有apk或多或少都会使用apk信息来进行各种验证,比如apk完整性验证、apk版本验证 (如果存在老apk)、新老apk签名验证 (如果存在老apk),经过各种步骤后,apk顺利的安装完成了,而apk信息也需要找一个归属地来存储它们。3.2 apk信息的归属地
apk信息的归属地代表需要在PackageManagerService中把apk信息保存起来,如下代码://PackageManagerService类
//mPackages存储了所有的apk信息,key值为包名,value为apk信息
final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>();
而apk信息中的四大组件,则是存放在四大组件模块,如下代码://PackageManagerService类
//mComponentResolver存储了四大组件
final ComponentResolver mComponentResolver;
apk信息保存下来后就可以被使用了,比如启动该apk的某个Activity,ActivityTaskManagerService就需要从四大组件模块中查询到相应的Activity信息,进而才执行后面的启动操作。再比如某个App获取该apk的ApplicationInfo信息,则会从PackageManagerService的mPackages属性中根据包名找到对应的apk信息,进而返回。3.3 apk信息的消亡
apk被卸载或者systemserver进程死掉的话,PackageManagerService和四大组件模块中保存的apk信息会被移除,代表apk信息消亡了。如果不存在上面的情况,则apk信息会随着PackageManagerService一直存活着。
本文介绍了apk信息在PackageManagerService服务中的重要性,以及apk信息的解析和apk信息在PackageManagerService中的一生。