概述
Android的应用安装分为三种情况,我们从adb命令可以窥探一二。
install [-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 的解析。
/**
* 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函数主要还是进行安装的准备工作,我稍微做了些总结,大概如下:
preparePackageLI
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数据结构
private 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来进行提交, 提交之后该应用就算完整发布了。
commitPackagesLocked(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锁外面执行。
executePostCommitSteps(commitRequest)
private void executePostCommitSteps(CommitRequest commitRequest)
1 prepareAppDataAfterInstallLIF
2 准备/data/data下的文件夹
3 mArtManagerService.prepareAppProfiles
4 mViewCompiler.compileLayouts(pkg)
5 mPackageDexOptimizer.performDexOpt
handlePackagePostInstall 就是最后完成安装的一些通知工作了。
private 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 10)->应用安装的整体流程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复