1.PKMS功能概述
PackageManagerService是系统的核心服务之一,负责系统中Package的管理,应用程序的安装、卸载、信息查询等。
2.类继承结构图
IPackageManager:接口类,定义了服务端和客户端通信的函数以及Stub(从Binder派生并实现IPackageManager接口),在编译过程中由IPackageManager.aidl文件生成。
PackageManagerService: 继承 IPackageManager.stub,具体实现功能类,是Binder通信中的服务端。
IPackageManager.Stub: 类中定义了一个内部类 Proxy,该类有一个 IBinder 类型的成员变量 mRemote,mRemote 用于和服务端 PackageManagerService 通信;
PackageManager: 抽象类,封装了提供给上层应用使用的一些方法。Context中通过getPackageManager()方法获得PackageManager对象, 实际返回的对象是其子类ApplicationPackageManager ,可以具体查看ContextImpl中getPackageManager方法。
ApplicationPackageManager: 并没有直接参与Binder通信,而是通过其 IPackageManager 类型的成员变量 mPM,它指向一个 IPackageManager.Stub.Proxy 类型的对象(最终是在ActivityThread的getPackageManager()中进行初始化)。
ActivityThread中getPackageManager():
asInterface(b)返回的是IPackageManager.Stub.Proxy 类型的对象:
return new android.content.pm.IPackageManager.Stub.Proxy(obj);
3.PKMS启动流程
(1)启动流程图
(2)5个阶段
在PKMS的构造方法中,分为5个阶段(有参考网络上博客):
BOOT_PROGRESS_PMS_START:
构造DisplayMetrics,保存分辨率等相关信息;
创建Installer对象与InstallId交互;
把PackageManagerInternalImpl 添加到本地服务LocalServices;
创建sUserManager对象,进行多用户管理;
创建mPermissionManager对象,进行权限管理;
构造Settings类,保存安装包信息,清除路径不存在的孤立应用,主要涉及/data/system目录下的packages.xml,package-backup.xml,packages.list,packages-stopped.xml,packages-stopped-backup.xml等文件。
调用造PackageDexOptimizer及DexManager类,处理dex优化;
创建SystemConfig实例,获取系统配置信息,主要是加载etc目录下配置信息,如platform.xml等,配置共享lib库。
创建PackageManager的handler线程,循环处理外部安装相关消息(安装、卸载)。
调用Settings的readLPw来读取并解析data/system目录下的xml内容。
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START:
对于旧版本升级的情况,将安装时获取权限变更为运行时申请权限;
扫描system/vendor/product/odem/oem 等目录的priv-app ,app ,overlay包。
清除安装时临时文件以及其他不必要的信息。
BOOT_PROGRESS_PMS_DATA_SCAN_START
解析data/app应用,处理应用信息,更新,删除不必要的数据
BOOT_PROGRESS_PMS_SCAN_END
sdk版本变更,更新权限
OTA升级后首次启动,清除不必要的缓存数据
权限等默认更新后,清理相关数据
更新data/system目录下的package.xml,packages.list文件
BOOT_PROGRESS_PMS_READY
创建PackageInstallerService
GC回收内存
(3)关键点说明
mSettings.addSharedUserLPw:创建SharedUserSetting对象并添加到Settings的成员变量mSharedUsers中,在Android系统中,多个package通过设置shareUserid属性可以运行在同一进程,共享同一个UID。这里添加system, phone, log, nfc, bluetooth, shell,se,networkstack 这8种shareUserId到mSettings;
mSettings.readLPw:扫描data/system目录下的文件:packages.xml(),package-backup.xml,packages.list,packages-stopped.xml(在Android 10 的机器上data/system目录下没有此文件),packages-stopped-backup.xml(在Android 10 的机器上data/system目录下没有此文件)等。
packages.xml:PKMS 扫描完目标文件夹后会创建该文件。当系统进行程序安装、卸载和更新等操作时,均会更新该文件。该文件保存了系统中与 package 相关的一些信息。
packages.list:描述系统中存在的所有APK 的信息。当这些程序有变动时,PKMS 就会更新该文件。
mSettings.writeLPw:更新data/system目录下的package.xml,packages.list文件
SharedUserSetting:继承关系图
4.扫描流程scanDirTracedLI
关键点说明:
(1)parsePackage系列:实际上就是解析出Package对应的数据结构。 代码看起来相当繁琐,但实际思想确实很简单的,就是解析AndroidManifest.xml对应的标签项,然后形成对应的数据结构插入到Package中。
(2)scanPackage系列:将Package中的信息加入到了PKMS的Settings对象中,在此之前四大组件的信息都属于Package的私有财产,现在统一注册到PKMS中,于是PKMS就可以对外提供统一的组件;最终创建PackageSetting实例,创建好后可以进行查询等操作。
(3)scanPackageNewLI与应用安装中的流程一致了,不再具体分析。
(4)scanDirTracedLI流程中没有updateSettingsLI(会调用到mSettings.writeLPr),因为在扫描完所有的目录后会直接调用mSettings.writeLPr;
(5)scanDirTracedLI流程中没有performDexOpt,是因为在PKMS的构造方法完成后在SystemServer中会调用到PKMS.java#updatePackagesIfNeeded(),这个后面有介绍。
(6)ParallelPackageParser是一个并行解析package的类,里面使用线程池来完成并行解析的工作。
(7)负责将静态文件转换内存中数据结构的工具就是PackageParser,包解析器。
5.关系图
(1)解析的数据结构关系图
包通过parsePackage后最终在内存中的数据结构Package:
它包含了一个包的所有信息,如包名、包路径、权限、四大组件等,其数据来源主要就是AndroidManifest.xml文件
一个包中有很多组件,为此设计了一个高层的基类Component,所有具体的组件都是Component的子类。什么是组件呢?AndroidManifest.xml文件中所定义的的一些标签,就是组件,譬如<activity>,<service>,<provider>,<permission>等,这些标签分别对应到包解析器中的一个数据结构,它们各自有自身的属性。
诸如<activity>,<service>标签,都可以配置<intent-filter>,来过滤其可以接收的Intent,这些信息也需要在包解析器中体现出来,为此组件Component依赖于IntentInfo这个数据结构。每一个具体的组件所依赖的IntentInfo不同,所以Component和IntentInfo之间的依赖关系采用了桥接(Bridge)这种设计模式,通过泛型的手段实现。
各种组件最终聚合到Package这个数据结构中,形成了最终包解析器的输出。
当然,在解析的过程中,还有利用了一些数据结构来优化设计,PackageLite和ApkLite就是一些很简单的数据封装。
(2)Info类相关
包解析器从静态文件中获取的数据,很多都是需要用于跨进程传递的,譬如初次启动Activity时,就需要把包信息从系统进程传递到应用进程,先完成应用进程的启动。在包解析器的类图中,我们看到Activity、Service、Provider、Permission、Instrumentaion这些类都有一个共同的特征:都具备info这个属性,其实这些类的结构非常简单,就是对info的一次封装,info这个结构体才是真正的包数据。所有的info都实现了Parcelable接口,意图很明显,info是可以进行跨进程传递的。不同组件的info类型是不同的,除了实现了Parcelable接口,它们之间又构成了一个庞大的数据结构:
(3)授权机制对应的数据结构
BasePermission:权限持有者所定义的每一项权限都会生成一个BasePermission,所有BasePermission都聚合在PMS的Settings中。BasePermission有三种类型: NORMAL、BUILTIN、DYNAMIC。
PackageSetting: 每一个解析成功的包都会生成一个PackageSetting,所有的PackageSetting都聚合在PMS的Settings中。PackageSetting继承了其祖宗SettingBase的属性mPermissionsState,这个属性表示一个包的授权状态。
PermissionsState(注意,这是复数):聚合了包中所有权限的授予状态,在多用户的场景下,不同用户的授权情况不同,因此要区分出一个权限针对每个用户的授予情况,为此设计了一个数据封装类PermissionData(注意,这是单数),记录了一个BasePermission与多个用户mUserState之间的关系。每一个用户的权限授予状态用PermissionState(注意,这是单数)来记录。
6.Dex优化
PKMS.java#updatePackagesIfNeeded()
在SystemServer的startOtherServices()中被调用;
检查是否需要去更新Packages并进行dex优化,如果没有OTA升级,不是第一次开机或大版本升级,没有清除dalvik虚拟机缓存,则不需要,否则可以去更新packages。最终调用的是Installer的dexopt进行优化。
更新packages的优先级:core app> system app > other app,调用performDexOptUpgrade()进行系统更新
7.systemReady
systemReady主要完成默认授权和更新package的信息,通知等待pms的一些组件。