Android Framework之PKMS
一,定义
PackageManagerService(简称 PKMS),是 Android 系统中核心服务之一,负责应用程序的安装,卸载,信息查询等工作。
- Android系统启动时,会启动(应用程序管理服务器PKMS),此服务负责扫描系统中特定的目录,寻找里面的APK格式的文件,并对这些文件进行解析,然后得到应用程序相关信息,最后完成应用程序的安装
- PKMS在安装应用过程中, 会全面解析应用程序的AndroidManifest.xml文件, 来得到Activity,Service, BroadcastReceiver, ContextProvider等信息,在结合PKMS服务就可以在OS中正常的使用应用程序了
- 在Android系统中, 系统启动时由SystemServer启动PKMS服务,启动该服务后会执行应用程序的安装过程
1.解析AndroidNanifest.xml清单文件,解析清单文件中的所有节点信息
2.扫描.apk文件,安装系统应用,安装本地应用等
3.管理本地应用,主要有, 安装,卸载,应用信息查询 等
二,PKMS常用到的类
客户端可通过Context.getPackageManager()获得ApplicationPackageManager对象, 而mPM指向的是Proxy代理,当调用到mPM.方法后,将会调用到IPackageManager的Proxy代理方法,然后通过Binder机制中的mRemote与服务端PackageManagerService通信 并调用到PackageManagerService的方法
三,PKMS启动流程
SystemServer启动PKMS: 先是在SystemServer.startBootstrapServices()函数中启动PKMS服务,再调用startOtherServices()函数中对dex优化,磁盘管理功能,让PKMS进入systemReady状态。
startBootstrapServices。()首先启动Installer服务,也就是安装器,随后判断当前的设备是否处于加密状态,如果是则只是解析核心应用,接着调用PackageManagerService的静态方法main来创建pms对象
- 启动Installer服务
- 获取设备是否加密(手机设置密码),如果设备加密了,则只解析”core”应用
- 调用PKMS main方法初始化PackageManagerService,其中调用PackageManagerService()构造函数创建了PKMS对象
- 如果设备没有加密,操作它。管理A/B OTA dexopting。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29private void startBootstrapServices() {
...
// 第一步:启动Installer
// 阻塞等待installd完成启动,以便有机会创建具有适当权限的关键目录,如/data/user。
// 我们需要在初始化其他服务之前完成此任务。
Installer installer = mSystemServiceManager.startService(Installer.class);
mActivityManagerService.setInstaller(installer);
...
// 第二步:获取设别是否加密(手机设置密码),如果设备加密了,则只解析"core"应用,mOnlyCore = true,后面会频繁使用该变量进行条件判断
String cryptState = VoldProperties.decrypt().orElse("");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
// 第三步:调用main方法初始化PackageManagerService
mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
// PKMS是否是第一次启动
mFirstBoot = mPackageManagerService.isFirstBoot();
// 第四步:如果设备没有加密,操作它。管理A/B OTA dexopting。
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false);
OtaDexoptService.main(mSystemContext, mPackageManagerService);
}
...
}
startOtherServices
- updatePackagesIfNeeded ,完成dex优化;
- 执行 performFstrimIfNeeded ,完成磁盘维护;
- 调用systemReady,准备就绪。
1 | private void startOtherServices() { |
四,PKMS main
PKMS main方法概述
main函数主要工作:
- 检查Package编译相关系统属性
- 调用PackageManagerService构造方法
- 启用部分应用服务于多用户场景
- 往ServiceManager中注册”package”和”package_native”。
1 | public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { |
PKMS构造方法详解
PKMS的构造函数中由两个重要的锁和5个阶段构成
两个重要的锁(mInstallLock、mPackages):
mInstallLock :用来保护所有安装apk的访问权限,此操作通常涉及繁重的磁盘数据读写等操作,并 且是单线程操作,故有时候会处理很慢, 此锁不会在已经持有mPackages锁的情况下火的,反之,在已经持有mInstallLock锁的情况下,立即 获取mPackages是安全的
mPackages:用来解析内存中所有apk的package信息及相关状态。
5个阶段
阶段1:BOOT_PROGRESS_PMS_START
阶段2:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
阶段3:BOOT_PROGRESS_PMS_DATA_SCAN_START
阶段4:BOOT_PROGRESS_PMS_SCAN_END
阶段5:BOOT_PROGRESS_PMS_READY
1 | //构造函数 |
阶段1-BOOT_PROGRESS_PMS_START
- 构造 DisplayMetrics ,保存分辨率等相关信息;
- 创建Installer对象,与installd交互;
- 创建mPermissionManager对象,进行权限管理;
- 构造Settings类,保存安装包信息,清除路径不存在的孤立应用,主要涉及/data/system/目录的packages.xml,packages-backup.xml,packages.list,packages-stopped.xml,packages-stopped,backup.xml等文件。
- 构造PackageDexOptimizer及DexManager类,处理dex优化;
- 创建SystemConfig实例,获取系统配置信息,配置共享lib库;
- 创建PackageManager的handler线程,循环处理外部安装相关消息。
1 | public PackageManagerService(...) { |
此readLPw 是上面调下来的哦:
mSettings.readLPw
1 | readLPw()会扫描下面5个文件 |
阶段2-BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
- 从init.rc中获取环境变量BOOTCLASSPATH和SYSTEMSERVERCLASSPATH;
- 对于旧版本升级的情况,将安装时获取权限变更为运行时申请权限;
- 扫描system/vendor/product/odm/oem等目录的priv-app、app、overlay包;
- 清除安装时临时文件以及其他不必要的信息。
1 | public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { |
阶段3-BOOT_PROGRESS_PMS_DATA_SCAN_START
对于不仅仅解析核心应用的情况下,还处理data目录的应用信息,及时更新,祛除不必要的数据。
1 | public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { |
阶段4-BOOT_PROGRESS_PMS_SCAN_END
- sdk版本变更,更新权限;
- OTA升级后首次启动,清除不必要的缓存数据;
- 权限等默认项更新完后,清理相关数据;
- 更新packag
1 | public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { |
阶段5-BOOT_PROGRESS_PMS_READY
GC回收内存 和一些细节而已
1 | public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { |
APK扫描
PKMS的构造函数中调用了 scanDirTracedLI方法 来扫描某个目录的apk文件。注意:Android10.0 和 其他低版本扫描的路径是不一样的:Android 10.0中,PKMS主要扫描以下路径的APK信息:
- /vendor/overlay 系统的APP类别
- /product/overlay 系统的APP类别
- /product_services/overlay 系统的APP类别
- /odm/overlay 系统的APP类别
- /oem/overlay 系统的APP类别
- /system/framework 系统的APP类别
- /system/priv-app 系统的APP类别
- /system/app 系统的APP类别
- /vendor/priv-app 系统的APP类别
- /vendor/app 系统的APP类别
- /odm/priv-app 系统的APP类别
- /odm/app 系统的APP类别
- /oem/app 系统的APP类别
- /oem/priv-app 系统的APP类别
- /product/priv-app 系统的APP类别
- /product/app 系统的APP类别
- /product_services/priv-app 系统的APP类别
- /product_services/app 系统的APP类别
- /product_services/priv-app 系统的APP类别
APK的扫描,整体描述图:
总结:
第一步:扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容
第二步:解析清单文件到的信息由 Package 保存。从该类的成员变量可看出,和 Android 四大组件相关的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此activites 和 receivers等均声明为 ArrayList
五,APK的安装
1.安装步骤概述
- 把Apk的信息通过IO流的形式写入到PackageInstaller.Session中
- 调用PackageInstaller.Session的commit方法, 把Apk的信息交给PKMS处理
- 进行Apk的Copy操作, 进行安装
2. 用户点击 xxx.apk 文件进行安装, 从 开始安装到完成安装流程
3. APK的安装, 整体描述图
点击一个apk后,会弹出安装界面,点击确定按钮后,会进入PackageInstallerActivity 的 bindUi() 中 的mAlert点击事件, 弹出的安装界面底部显示的是一个diaglog,主要由bindUi构成,上面有 ”取消“ 和 ”安装“ 两个按钮,点击安装后 调用startInstall()进行安装:
4. 总结
六,权限扫描
此 “PMS之权限扫描” 学习的目标是: PackageManagerService中执行systemReady()后,需求对/system/etc/permissions中的各种xml进行扫描,进行相应的权限存储,让以后可以使用,这就是本次“PMS只权限扫描”学习的目的。
权限扫描
PackageManagerService执行systemReady()时,通过SystemConfig的readPermissionsFromXml()来扫描读取/system/etc/permissions中的xml文件,包括platform.xml和系统支持的各种硬件模块的feature主要工作
整体图:
总结
权限扫描,扫描/system/etc/permissions中的xml,存入相应的结构体中,供之后权限管理使用
七,requestPermissions流程解析
1. 概述
Google在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。
注意:App每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。
权限的分类:
系统权限分为两类:正常权限 和 危险权限。
正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予
该权限。
危险权限会授予应用访问用户机密数据的权限。如果您的应用在其清单中列出了正常权限,系统将自动
授予该权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。
1 | <!-- 权限组:CALENDAR == 日历读取的权限申请 --> |
核心函数:
ContextCompat.checkSelfPermission
检查应用是否具有某个危险权限。如果应用具有此权限,方法将返回
PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。如果应用不具有此权限,方法将返回
PackageManager.PERMISSION_DENIED,且应用必须明确向用户要求权限。ActivityCompat.requestPermissions
应用可以通过这个方法动态申请权限,调用后会弹出一个对话框提示用户授权所申请的权限。
ActivityCompat.shouldShowRequestPermissionRationale
如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。如果用户在过去拒绝了权限请求,并在 权限请求系统对话框中选择了 Don’t ask again 选项,此方法将返回 false。如果设备规范禁止应用具 有该权限,此方法也会返回 false。
onRequestPermissionsResult
当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用的 onRequestPermissionsResult() 方法,向其传递用户响应,处理对应的场景。
2. 权限申请requestPermissions
MainActivity 调用 requestPermissions 进行动态权限申请;
requestPermissions函数通过隐士意图,激活PackageInstaller的GrantPermissionsActivity界面,让用户选择是否授权;
经过PKMS把相关信息传递给PermissionManagerService处理;
PermissionManagerService处理结束后回调给—->PKMS中的onPermissionGranted方法把处理结果返回;
PKMS通知过程中权限变化,并调用writeRuntimePermissionsForUserLPr函数让PackageManager的settings记录下相关授 权信息;
3. 检查权限流程checkPermission
- MainActivity会调用checkSelfPermission方法检测是否具有权限(红色区域)
- 通过实现类ContextImpl的checkPermission方法经由ActivityManager和ActivityManagerService处理(紫色区域)
- 经过ActivityManager处理后会调用PKMS的checkUidPermission方法把数据传递给PermissionManagerService处理(蓝色)
- 在PermissionManagerService.checkUidPermission中经过一系列查询返回权限授权的状态(绿色区域)