-
PkMS是怎么知道apk的位置
-
系统应用和普通应用的区别
-
应用扫描的过程以及应用信息的保存
PkMS怎么知道apk的位置
答案是按照路径,对于手机用户安装应用都是放在/data/app
,对于系统应用则是分布各个分区中,可以简单的认为是目录,/data
就是data分区,以下的分区都会被扫描,并且只会扫描priv-app和app目录:
-
system分区下的priv-app,app目录
/system/priv-app
,/system/app
-
product分区
-
odm分区
-
oem分区
-
vendor分区
-
system_ext分区
-
data分区,最后扫描
不过这些分区都执行不是特别严格,没涉及到gms测试的基本都不怎么管,那么apk是存在什么地方呢?例如:Settings就放在/system_ext/priv-app/Settings/Settings.apk
,其他分区都是类似的,下面分析应用扫描过程还会说到。这里解释一下,为什么要分priv-app和app两个目录进行扫描? priv-app意思是这个目录里面都是privileged应用,可以获取privilege权限,权限的定义frameworks/base/core/res/AndroidManifest.xml
中找到
系统应用和普通应用的区别
答案还是路径,data分区内的应用是普通应用,其他分区安装的应用都是系统应用,系统应用均不可卸载
应用扫描过程
scanDirLI
scanDirLI的几个参数说明一下,
-
scanDir,应用目录的集合,以上面Settings为例,目录是
/system_ext/priv-app
-
scanFlags,扫描的标志,当为系统应用时,会加上
SCAN_AS_SYSTEM
标志,如果是priv-app目录还要加上SCAN_AS_PRIVILGED
-
packageParser,这个就是解析AndroidManifest.xml主要工具类
-
executorService,生产者线程
scanDirLI的逻辑比较简单,
-
以上面
/system_ext/priv-app
为例,遍历目录下的每个目录和apk -
使用ExecutorService(线程池)对所有目录和apk进行解析
-
获取ParsedPackage并进行调用`addForI
nitLI()`
addForInitLI
逻辑相当的复杂,考虑情况也要很多,有些自己也没搞懂,只挑能说的说一下
-
首先重命名包名的逻辑,在PkMS当中所有的package都是按照包名作为唯一的主键值,那么就可能出现应用需要更换包名的情况,PkMS给出解决方案是加上
<original-package android:name="com.android.oldpackagename" />
指明需要覆盖安装的包名,但是这样就需要考虑到诸多情况了 -
包名修改多次怎么办
-
之前有安装过老包名的应用的处理情况
-
之前未安装过老包名的应用的处理情况
-
之前安装过当前包名的应用的处理情况
那么PkMS是怎么做的呢?
- 设计了一个
originalPackages
表示之前原始package,当遇到original-package
时,就将包名加入到originalPackages当中,代码如下
//ParsingPackageUtils.parseOriginalPackage()
String orig = sa.getNonConfigurationString(
R.styleable.AndroidManifestOriginalPackage_name,
0);
if (!pkg.getPackageName().equals(orig)) {
if (pkg.getOriginalPackages().isEmpty()) {
pkg.setRealPackage(pkg.getPackageName());
}
pkg.addOriginalPackage(orig);
}
复制代码
-
然后在
addForInitLI()
中根据realPkgName获取originalPkgSetting -
接下来判断是否要覆盖安装应用
不过我感觉里面还是有些bug,似乎只是为了用gms应用替换AOSP里面的应用(如:PackageInstaller和PermissionController)专门设计的,并不具备普遍性,安装的应用及时加了标签也还是会被认为是两个应用
-
对于覆盖安装系统应用的data区应用进行处理,什么是覆盖安装系统应用?即系统应用有更新,可以通过应用商店下载覆盖安装,但是并不会去卸载系统应用,而是disable系统应用,例如:Google的gms应用都是如此
-
如果安装的应用出现问题了,重新enable被disabled应用
-
如果是系统更新的应用,则需要扫描disabled系统应用,因为可能会有OTA升级导致系统应用更新apk的情况,调用
scanPackageOnlyLI()
,进行扫描,后面还会分析 -
接下来是根据disabled系统应用和安装应用的版本号,判断是否需要重新使用系统应用
-
处理签名,对于安装的应用,必须要签名
-
确认是否需要重新签名,对于非系统应用来说,无需重新收集,这部分AOSP压根没写,注释里面的第二条还没实现
// Verify certificates against what was last scanned. Force re-collecting certificate in two
// special cases:
// 1) when scanning system, force re-collect only if system is upgrading.
// 2) when scannning /data, force re-collect only if the app is privileged (updated from
// preinstall, or treated as privileged, e.g. due to shared user ID).
-
final boolean forceCollect = scanSystemPartition ? mIsUpgrade
- PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
- 是否跳过签名验证,这个是覆盖安装时候使用
// Full APK verification can be skipped during certificate collection, only if the file is
// in verified partition, or can be verified on access (when apk verity is enabled). In both
// cases, only data in Signing Block is verified instead of the whole file.
// TODO(b/136132412): skip for Incremental installation
final boolean skipVerify = scanSystemPartition
|| (forceCollect && canSkipForcedPackageVerification(parsedPackage));
collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
-
还要处理一下第三步的反方向,即一开始有个安装的应用(data分区),而后OTA升级有添加了该系统应用(system或其他分区),分为三种情况进行讨论
-
签名不相同,则卸载data分区的应用
-
如果系统应用的版本号更高,则移除data分区的应用,但保留应用的数据
-
如果系统应用的版本号更低,则将
shouldHideSystemApp
设置为true,也就是将在下面disable系统应用 -
调用
scanPackageNewLI()
继续扫描