Android的应用安装分为三种情况,我们从adb命令可以窥探一二。
1
2
3
4
5
6
7
8install [-lrtsdg] [--instant] PACKAGE push a single package to the device and install it install-multiple [-lrtsdpg] [--instant] PACKAGE... push multiple APKs to the device for a single package and install them install-multi-package [-lrtsdpg] [--instant] PACKAGE... push one or more packages to the device and install them atomically
install主要用于安装单个apk文件。
install-multiple 用于安装split apk。关于split apk 请参考Google原生Split APK浅析 。 这里简单说明下,split apk的特点是多个安装包最终被安装成一个程序。
install-multi-package 命令用于同时安装多个应用,可以理解为批量安装。
另外安装有分为 正常安装和移动两种情况。
针对上述几种安装分类,在PackageManagerService中实现了几个类去处理不同情况。
这其中有两个抽象类,分别是HandlerParams和InstallArgs, 这一层用于指导整个安装过程,实现类有MutilPackageInstallParams和InstallParams, MutilPackageInstallParams用于负责批量安装, InstallParams则负责单一安装, MutilPackageInstallParams的成员变量mChildParams指向多个InstallParams, 说明批量安装其实就是调用多个单一安装的实现的。 另外一个抽象类InstallParams用于处理安装过程中的文件相关的操作,比如apk的拷贝,清理工作, 这部分有两个实现类,分别是FileInstallArgs用于正常安装过程的apk拷贝,而另外一个实现类MoveInstallArgs则用于移动应用apk。这里没有体现split apk的安装,其实split apk的安装特殊之处主要在于解析,安装过程会把属于同一split apk的apk文件放在相同的目录下面(比如/data/apk/xxxx/base.apk, /data/apk/xxxx/f1.apk, /data/apk/xxxx/f2.apk** )。这些apk具有相同包名,加载的时候也可以一起加载。 解析过程在PackageParser中,我们可以简单看下apk 的解析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/** * Parse only lightweight details about the package at the given location. * Automatically detects if the package is a monolithic style (single APK * file) or cluster style (directory of APKs). * <p> * This performs sanity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * * @see PackageParser#parsePackage(File, int) */ @UnsupportedAppUsage public static PackageLite parsePackageLite(File packageFile, int flags) throws PackageParserException { if (packageFile.isDirectory()) { return parseClusterPackageLite(packageFile, flags); } else { return parseMonolithicPackageLite(packageFile, flags); } }
如果解析路径是一个文件夹,那么就会执行parseClusterPackageLite函数,对这个目录下的所有apk进行解析,所以split apk安装的apk信息在这个过程中完成并会。
下面忽略异步线程和一些中间函数我们来看下Pms的整体安装过程。
我们忽略安装的前半部分, 按照顺序来说明下安装过程,首先会通过Pms的INIT_COPY消息来通知Pms进行拷贝工作, 拷贝工作会调用HandlerParams来处理,这一步可能是由MutilPackageInstallParams来实现,也可能是由InstallParams来实现,调用handleStartCopy函数, 该函数最重要的工作就是计算应用安装的位置。 位置计算无误之后就会调用InstallParams.handleReturnCode() 函数,handleReturnCode()函数会调用InstallArgs来拷贝应用(一般拷贝到/data/app/${package}下)。 拷贝没有出现问题的话,就可以继续安装流程,通过PackageManagerService.processInstallRequestsAsync()函数将处理流程搞出来。 安装前调用InstallArgs.doPreInstall 函数再做一些准备工作, 然后调用PackageManagerService.installPackagesTracedLI, 这是安装过程中最核心的部分。安装完成后调用InstallArgs.doPostInstall 再做一些清理工作。 最终安装已经完成,调用PackageManagerService.handlePackagePostInstall做一些后续工作(比如发送应用变化相关的广播)。所以这里安装过程的重中之重是PackageManagerService.installPackagesTracedLI。
installPackagesTracedLI 步骤如上图, preparePackageLI函数主要还是进行安装的准备工作,我稍微做了些总结,大概如下:
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45preparePackageLI 1 准备scanflags: move 表示已经初始化过,添加SCAN_INITIAL标志, 不需要杀掉添加 SCAN_DONT_KILL_APP, instantApp 为SCAN_AS_INSTANT_APP, fullApp 为 SCAN_AS_FULL_APP, virtualPreload 虚拟预加载SCAN_AS_VIRTUAL_PRELOAD 2 instant app 不能安装在外置存储 3 pp.parsePackage(tmpPackageFile, parseFlags) 解析, DexMetadataHelper.validatePackageDexMetadata(pkg) 验证dm文件 4 instantApp 验证, targetSdkVersion不能小于o, 不能是isharedUid 5 静态库修改包名,包名添加上version信息,方便安装多版本库 6 子包的处理 7 cpuAbiOverride 处理, 如果安装选项设置了使用安装选项覆盖 8 TEST_ONLY app 应用判断是否可以安装, 没有-t选项不允许安装 9 判断是否是replace安装 9.1 包含original-package使用旧包名验证是否安装过 9.2 非original-package使用包名看下是否安装过 9.3 子包禁止安装 9.4 替换安装情况下, targetSdk 范围检查 9.5 禁止PERSISTENT 非 stage安装(因为可能会导致persistent被杀) 9.6 禁止子包安装 10 替换安装情况对签名进行检查 11 权限处理 11.1 除了系统应用之外不允许定义PROTECTION_FLAG_INSTANT级别的权限 11.2 对于要更新的权限执行以下操作 11.2.1 如果是应用升级则并且有升级key限制则验证 11.2.2 没有升级key限制则验证证书匹配才可以升级权限 11.2.3 非PLATFORM_PACKAGE_NAME禁止签名不同升级权限 11.2.4 PROTECTION_DANGEROUS 权限禁止修改(降低) 保护级别 12 系统应用禁止是instantApp,禁止安装在外置存储 13 abi的处理 13.1 move 应用安装位置,直接设置primaryCpuAbi 和 secondaryCpuAbi 13.2 非move应用 derivePackageAbi 14 修改包名 15 fsverify 16 startIntentFilterVerifications 17 创建 freezer 禁止启动 19 替换安装情况 19.1 静态库禁止同版本升级 19.2 再次验证签名 19.3 验证系统应用升级的restrict-update 19.4 检查shareduid是否变化 19.5 禁止fullapp -> instant app 安装 19.6 设置更新后被移除的子包 19.7 系统包根据旧包设置targetParseFlags targetScanFlags, 设置setApplicationInfoFlags位FLAG_UPDATED_SYSTEM_APP 20 非替换安装情况(新安装) 20.1 没有指定INSTALL_REPLACE_EXISTING 禁止非替换安装 21 创建 PrepareResult返回
scanPackageTrackLI函数主要用于生成PackageSetting数据结构
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException 1 对于包含child的包 先check扫描一遍 再非check扫描一遍 2 不包含child的包直接非check扫描一遍 扫描函数scanPackageNewLI private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException 1 private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user, PackageParser.Package pkg) 1 如果覆盖安装系统应用设置系统相关的扫描属性 2 如果instant安装设置 SCAN_AS_INSTANT_APP, 如果 VirtulalPreload设置 SCAN_AS_VIRTUAL_PRELOAD 3 如果签名是系统签名,并且shareduid 是privleged的,并且要安装的应用签名和平台签名一致,设置 SCAN_AS_PRIVILEGED(这相当于一种权限提升呀) 2 applyPolicy 这一步根据scanFlags设置pkg.applicationInfo下的标志和 四大组件的标志 1 系统应用设置 1.1 directBootAware 设置所有组件的directBootAware标志 1.2 如果是stub安装设置 pkg.isStub = true 2 非系统应用删除一些特权flags,设置降低权限组优先级,pkg.permissionGroups.get(i).info.priority 3 非SCAN_AS_PRIVILEGED app 1 pkg.protectedBroadcasts = null 2 不支持多用户的receivers services 和 providers 禁止导出 4 设置其他标志 5 不是SystemApp 不允许orginial-package 3 assertPackageIsValid 1 PARSE_ENFORCE_CODE 标志,检查hascode属性的apk是否包含代码 2 必须设置codepath或者resourcePath 3 不允许用户安装和手册启动或者ota检查apex包重复 4 禁止重新安装平台包(android.jar) 5 非安装过程禁止同名包 6 静态库检查 4 创建ScanRequest 5 scanPackageOnlyLI private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request, boolean isUnderFactoryTest, long currentTime) 扫描软件包设置Package 和PackageSettings 1 第一次启动或者ota需要重新确定abi 2 sharedUser不能修改 3 创建PackageSettings(根据旧的或者重新创建) 4 original-package 设置为旧报名,打日志 5 修改状态 instant_app 或者full_app (full 不能到instant。 instant 能到full?) 6 覆盖安装系统应用设置 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP 7 seInfo 设置 seInfoUser设置 8 设置进程名称 9 初始化系统user 10 非安装流程SCAN_NEW_INSTALL = 0 1 需要driverAbi 2 不需要driverAbi 设置primaryCpuAbi, secondaryCpuAbi 11 非安装流程, 设置primaryCpuAbi secondaryCpuAbi 和applicationInfo 12 设置PackageSettings 的 firstInstallTime lastUpdateTime 13 pkgSetting.pkg = pkg, pkgSetting.pkgFlags = pkg.applicationInfo.flags, pkgSetting.versionCode = pkg.getLongVersionCode(), pkgSetting.volumeUuid = volumeUuid 14 return new ScanResult
执行完scanPackageTrackLI之后Pms的两大核心数据结构都已经准备好了,一个是代表扫描结果的final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();中的PackageParser.Package,另外一个是mSettings.mPackages的PackageSetting 数据结构,这两个结构PackageParser.Package代表扫描结果,为静态数据,扫描完成后就不会发生变化。PackageSetting用于存储安装应用的动态数据,如权限授予情况等。PackageParser.Package由于是静态数据,扫描apk就可以获取。PackageSetting生成之后会被记录到文件中,以后每次系统启动都会重新加载。
生成PackageSetting和PackageParser.Package数据结构后,还需要对多个安装apk结果进行调和,这就是reconcilePackagesLocked函数, 一般在 install-multi-package的时候会同时安装多个apk。
经过上述几个步骤,两个核心数据结构虽然已经生成,但是并没有添加到容器中去(PackageManagerService.mPackages 和 PackageManagerService.mSettings.mPackage), 所以该包里面的组件等还不能查询到,也不能启动。 所以需要commitPackagesLocked来进行提交, 提交之后该应用就算完整发布了。
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53commitPackagesLocked(commitRequest) 1 replace 1 设置了一遍ps的firstInstalltime 和lastUpdateTime 2 系统应用 1 删除旧的package 2 删除覆盖安装的system 应用的应用,需要删除的东西放在removedInfo中 3 处理child package 3 非系统应用 1 删除package 2 手机要删除的数据 4 commitReconciledScanResultLocked 正式提交 commitReconciledScanResultLocked 1 sharedUser发生变化,移除旧的sharedUser 2 更新应用 使用旧的packageSettings更新 packageSettings,pkg.mExtras = pkgSetting 3 新安装 设置pkgSetting为 result.pkgSetting 4 添加package 到sharedUser 5 写入配置文件 6 更新sharedlibrary 7 更新签名信息 8 transfer permission 9 code path 有变化,mInstaller.rmdex 10 SCAN_CHECK_ONLY mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting) 11 commitPackageSettings private void commitPackageSettings 1 如果因安装的包包含mCustomResolverComponentName, 更新 2 如果是android 应用,并且非check, 设置 mPlatformPackage pkg.mVersionCode = mSdkVersion; pkg.mVersionCodeMajor = 0; mAndroidApplication = pkg.applicationInfo; mResolverReplaced没有替换,设置系统的resolveActivity 3 更新sharedLibrary 4 lib更新,杀掉 依赖的包 5 mSettings.insertPackageSettingLPw(pkgSetting, pkg); // Add the new setting to mPackages mPackages.put(pkg.applicationInfo.packageName, pkg); 更新核心数据 6 mComponentResolver.addAllComponents(pkg, chatty) 添加所有组件 7 mPermissionManager.addAllPermissionGroups(pkg, chatty) 添加所有权限组 8 mPermissionManager.addAllPermissions(pkg, chatty); 添加所有权限 9 instrumentation 10 pkg.protectedBroadcasts 11 mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, allPackageNames, mPermissionCallback)) 撤销需要撤销的权限 private void updateSettingsInternalLI(PackageParser.Package pkg, String installerPackageName, int[] allUsers, int[] installedForUsers, PackageInstalledInfo res, UserHandle user, int installReason) 1 系统应用 1 设置多用户 2 删除多余的用户 3 写配置文件
executePostCommitSteps 函数主要是dexoat部分工作,这部分不会修改核心数据结构,所以在mPackage锁外面执行。
1
2
3
4
5
6
7
8executePostCommitSteps(commitRequest) private void executePostCommitSteps(CommitRequest commitRequest) 1 prepareAppDataAfterInstallLIF 2 准备/data/data下的文件夹 3 mArtManagerService.prepareAppProfiles 4 mViewCompiler.compileLayouts(pkg) 5 mPackageDexOptimizer.performDexOpt
handlePackagePostInstall 就是最后完成安装的一些通知工作了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23private void restoreAndPostInstall( int userId, PackageInstalledInfo res, @Nullable PostInstallData data) 1 如果该应用可以备份恢复,并且BackupManager活跃状态通知尝试恢复数据 2 没有restore情况下升级安装可能是降级安装, 尝试使用rollbackMnaager恢复数据, rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode, seInfo, token); 3 没有doRestore的情况下 POST_INSTALL, 否则等安装备份或者rollback调用 private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions, boolean killApp, boolean virtualPreload, String[] grantedPermissions, List<String> whitelistedRestrictedPermissions, boolean launchedForRestore, String installerPackage, IPackageInstallObserver2 installObserver) 1 安装成功 1 remove 发送广播 2 权限假如白名单 3 根据安装参数授予运行时全新啊 4 对每一个安装的用户 1 发送newuser广播 2 ACTION_PACKAGE_REPLACED
最后
以上就是负责裙子最近收集整理的关于PackageManagerService分析(Android 10)->应用安装的整体流程的全部内容,更多相关PackageManagerService分析(Android内容请搜索靠谱客的其他文章。
发表评论 取消回复