-
第8步 APK加载
上面主要分析到APK的copy过程,这里我们开始分析APK的加载过程。直接看之前流程进行到下一步的processPendingInstall()
方法:
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
//***1***
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
//***2***
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success, List installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
//***3***
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
//***4*** 核心流程
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
//**5***
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
//***6***
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
- 1.
InstallArgs.doPreInstall()
方法(FileInstallArgs对象)主要是对安装失败时清除安装过程中的临时文件的处理:
#FileInstallArgs
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
//***7***
cleanUp();
}
return status;
}
private boolean cleanUp() {
if (codeFile == null || !codeFile.exists()) {
return false;
}
//***8***
removeCodePathLI(codeFile);
if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
resourceFile.delete();
}
return true;
}
@GuardedBy("mInstallLock")
void removeCodePathLI(File codePath) {
if (codePath.isDirectory()) {
try {
//***9***
mInstaller.rmPackageDir(codePath.getAbsolutePath());
} catch (InstallerException e) {
Slog.w(TAG, "Failed to remove code path", e);
}
} else {
codePath.delete();
}
}
#Installer
public void rmPackageDir(String packageDir) throws InstallerException {
if (!checkBeforeRemote()) return;
BlockGuard.getVmPolicy().onPathAccess(packageDir);
try {
//***10***
mInstalld.rmPackageDir(packageDir);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- 2.
installPackagesTracedLI()
扫描安装apk包,这个是核心流程:
#PackageManagerService
@GuardedBy({"mInstallLock", "mPackages"})
private void installPackagesTracedLI(List requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
//***11***
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
/**
* Installs one or more packages atomically. This operation is broken up into four phases:
*
* - Prepare
*
Analyzes any current install state, parses the package and does initial
* validation on it.
* - Scan
*
Interrogates the parsed packages given the context collected in prepare.
* - Reconcile
*
Validates scanned packages in the context of each other and the current system
* state to ensure that the install will be successful.
* - Commit
*
Commits all scanned packages and updates system state. This is the only place
* that system state may be modified in the install flow and all predictable errors
* must be determined before this phase.
*
*
* Failure at any phase will result in a full failure to install all packages.
*/
@GuardedBy("mInstallLock")
private void installPackagesLI(List requests) {
...
for (InstallRequest request : requests) {
// TODO(b/109941548): remove this once we've pulled everything from it and into
// scan, reconcile or commit.
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
//***12*** 准备阶段
prepareResult = preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
...
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
...
try {
//***13*** 扫描解析阶段
final List scanResults = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user);
...
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
//整合验证阶段
...
synchronized (mPackages) {
Map reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
//***14***
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
} catch (ReconcileFailure e) {
...
}
//确认提交阶段
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
sUserManager.getUserIds());
//***15***
commitPackagesLocked(commitRequest);
success = true;
} finally {
for (PrepareResult result : prepareResults.values()) {
if (result.freezer != null) {
result.freezer.close();
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//***16***
executePostCommitSteps(commitRequest);
} finally {
if (!success) {
for (ScanResult result : preparedScans.values()) {
if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
//***17***
cleanUpAppIdCreation(result);
}
}
// TODO(patb): create a more descriptive reason than unknown in future release
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
for (PrepareResult result : prepareResults.values()) {
if (result.freezer != null) {
result.freezer.close();
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
installPackagesLI()
可以支持单包和多包加载,加载主要分为4个阶段:
- 2-1.准备阶段:分析任何当前安装状态,解析包并对其进行初始验证。
准备阶段的方法很长,主要做了以下几个事情:# PackageManagerService @GuardedBy("mInstallLock") private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res) throws PrepareFailure { ... final PackageParser.Package pkg; try { //***18*** pkg = pp.parsePackage(tmpPackageFile, parseFlags); //***19*** DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // Instant apps have several additional install-time checks. if (instantApp) { ... } if (pkg.applicationInfo.isStaticSharedLibrary()) { // Static shared libraries have synthetic package names //***20*** renameStaticSharedLibraryPackage(pkg); ... } // If we are installing a clustered package add results for the children if (pkg.childPackages != null) { ... } // If package doesn't declare API override, mark that we have an install // time CPU ABI override. if (TextUtils.isEmpty(pkg.cpuAbiOverride)) { pkg.cpuAbiOverride = args.abiOverride; } ... try { // either use what we've been given or parse directly from the APK if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) { pkg.setSigningDetails(args.signingDetails); } else { //***21**** 设置签名文件 PackageParser.collectCertificates(pkg, false /* skipVerify */); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); } ... //***22*** PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); // Static shared libs have same package with different versions where // we internally use a synthetic package name to allow multiple versions // of the same package, therefore we need to compare signatures against // the package setting for the latest library version. PackageSetting signatureCheckPs = ps; if (pkg.applicationInfo.isStaticSharedLibrary()) { SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg); if (libraryInfo != null) { signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName()); } } // Quick sanity check that we're signed correctly if updating; // we'll check this again later when scanning, but we want to // bail early here before tripping over redefined permissions. final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { ... } else { ... } if (ps.pkg != null && ps.pkg.applicationInfo != null) { systemApp = (ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); } int N = pkg.permissions.size(); for (int i = N - 1; i >= 0; i--) { //***23*** final PackageParser.Permission perm = pkg.permissions.get(i); final BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name); // Don't allow anyone but the system to define ephemeral permissions. if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 && !systemApp) { ... } // Check whether the newly-scanned package wants to define an already-defined perm if (bp != null) { // If the defining package is signed with our cert, it's okay. This // also includes the "updating the same package" case, of course. // "updating same package" could also involve key-rotation. final boolean sigsOk; final String sourcePackageName = bp.getSourcePackageName(); final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting(); final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (sourcePackageName.equals(pkg.packageName) && (ksms.shouldCheckUpgradeKeySetLocked( sourcePackageSetting, scanFlags))) { sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg); } else { // in the event of signing certificate rotation, we need to see if the // package's certificate has rotated from the current one, or if it is an // older certificate with which the current is ok with sharing permissions if (sourcePackageSetting.signatures.mSigningDetails.checkCapability( pkg.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { sigsOk = true; } else if (pkg.mSigningDetails.checkCapability( sourcePackageSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { // the scanned package checks out, has signing certificate rotation // history, and is newer; bring it over ... } if (!sigsOk) { // If the owning package is the system itself, we log but allow // install to proceed; we fail the install on all other permission // redefinitions. ... } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) { // Prevent apps to change protection level to dangerous from any other // type as this would allow a privilege escalation where an app adds a // normal/signature permission in other app's group and later redefines // it as dangerous leading to the group auto-grant. ... } } } } if (systemApp) { ... } if (args.move != null) { // We did an in-place move, so dex is ready to roll ... } else { // Enable SCAN_NO_DEX flag to skip dexopt at a later stage scanFlags |= SCAN_NO_DEX; try { String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ? args.abiOverride : pkg.cpuAbiOverride); final boolean extractNativeLibs = !pkg.isLibrary(); derivePackageAbi(pkg, abiOverride, extractNativeLibs); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI"); } } //***24*** //在这里存在两种路径,一种是变化前的路径,名字为/data/app/vmdlsessionId/base.apk, //另一种是安装后的路径,通过getNextCodePath()方法获得 if (!args.doRename(res.returnCode, pkg)) { throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); } try { //***25*** setUpFsVerityIfPossible(pkg); } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) { throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Failed to set up verity: " + e); } if (!instantApp) { //***26*** startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg); } else { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName); } } //***27*** final PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags, "installPackageLI"); boolean shouldCloseFreezerBeforeReturn = true; try { ... //***28*** if (replace) { targetVolumeUuid = null; if (pkg.applicationInfo.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // and cannot be updated as an update would get a new package name, // unless this is the exact same version code which is useful for // development. ... } ... synchronized (mPackages) { ... // verify signatures are valid final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) { ... } else { // default to original signature matching ... } // don't allow a system upgrade unless the upgrade hash matches if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) { ... // retain upgrade restriction pkg.restrictUpdateHash = oldPackage.restrictUpdateHash; } // Check for shared user id changes ... // In case of rollback, remember per-user/profile install state ... // don't allow an upgrade from full to ephemeral if (isInstantApp) { ... } else if (!ps.getInstantApp(args.user.getIdentifier())) { // can't downgrade from full to instant ... } } } // Update what is removed ... for (int i = 0; i < installedUsers.length; i++) { final int userId = installedUsers[i]; res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId)); } childPackages = mSettings.getChildSettingsLPr(ps); if (childPackages != null) { ... } sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { // Set the system/privileged/oem/vendor/product flags as needed ... } else { // non system replace replace = true; ... } } else { // new package install ... // Remember this for later, in case we need to rollback this install String pkgName1 = pkg.packageName; ... synchronized (mPackages) { renamedPackage = mSettings.getRenamedPackageLPr(pkgName1); if (renamedPackage != null) { // A package with the same name is already installed, though // it has been renamed to an older name. The package we // are trying to install should be installed as an update to // the existing one, but that has not been requested, so bail. ... } if (mPackages.containsKey(pkgName1)) { // Don't allow installation over an existing package with the same name. ... } } // we're passing the freezer back to be closed in a later phase of install shouldCloseFreezerBeforeReturn = false; //***29*** return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName, args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg, replace /* clearCodeCache */, sysPkg, renamedPackage, freezer, ps, disabledPs, childPackages); } finally { if (shouldCloseFreezerBeforeReturn) { freezer.close(); } } }
2-1-1.PackageParser.parsePackage 扫描apk包中完整的AndroidManifest.xml内容,并把解析的package结果缓存到磁盘和内存中(//***18***
)。
2-1-2.往Package对象中设置好签名信息(//***21***
)。
2-1-3.从Settings中获取是否有当前包名对应的PackageSetting 包配置信息,此时还没有则跳开这里的if。获取PermissionManagerService查询权限信息。如果还是能查到,说明是包的升级,此时会进行包权限的校验。判断前后两次是不是内部包含的包权限内容都是一致,而只是顺序变了。当然如果之前没有安装,或者内容不一致,都会触发KeySetManagerService的checkUpgradeKeySetLocked进行更新(//***22***
)。
2-1-4.调用InstallArgs.doRename 把当前的包的名字给更新了(//***24***
)。
2-1-5.判断当前是否允许对包进行校验,如果允许则调用VerityUtils.generateApkVeritySetupData()
对包的签名进行校验,校验通过根路径则调用Installd服务进一步调用installApkVerity进行校验,详细可以看setUpFsVerityIfPossible()
方法(//***25***
)。
2-1-6.返回PrepareResult(//***29***
)
具体详细流程:
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返回
-
2-2.扫描解析阶段:根据准备阶段中收集的上下文对包进行解析,主要用于生成PackageSetting数据结构。调用
scanPackageTracedLI()
扫描包内容,此时其实已经解析过一次包内容,在这里能直接获得缓存。#PackageManagerService @GuardedBy({"mInstallLock", "mPackages"}) private List
scanPackageTracedLI(PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); // If the package has children and this is the first dive in the function // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see // whether all packages (parent and children) would be successfully scanned // before the actual scan since scanning mutates internal state and we want // to atomically install the package and its children. if ((scanFlags & SCAN_CHECK_ONLY) == 0) { if (pkg.childPackages != null && pkg.childPackages.size() > 0) { scanFlags |= SCAN_CHECK_ONLY; } } else { scanFlags &= ~SCAN_CHECK_ONLY; } final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; final List scanResults = new ArrayList<>(1 + childCount); try { // Scan the parent //***30*** scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user)); // Scan the children for (int i = 0; i < childCount; i++) { PackageParser.Package childPkg = pkg.childPackages.get(i); //***31*** scanResults.add(scanPackageNewLI(childPkg, parseFlags, scanFlags, currentTime, user)); } } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } if ((scanFlags & SCAN_CHECK_ONLY) != 0) { //***32*** return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user); } return scanResults; } @GuardedBy({"mInstallLock", "mPackages"}) private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage); final String realPkgName = getRealPackageName(pkg, renamedPkgName); if (realPkgName != null) { //***33*** ensurePackageRenamed(pkg, renamedPkgName); } final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName); final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName); final PackageSetting disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(pkg.packageName); if (mTransferedPackages.contains(pkg.packageName)) { Slog.w(TAG, "Package " + pkg.packageName + " was transferred to another, but its .apk remains"); } //***34*** scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg); synchronized (mPackages) { applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage); assertPackageIsValid(pkg, parseFlags, scanFlags); SharedUserSetting sharedUserSetting = null; if (pkg.mSharedUserId != null) { // SIDE EFFECTS; may potentially allocate a new shared user sharedUserSetting = mSettings.getSharedUserLPw( pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } } final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting, originalPkgSetting, realPkgName, parseFlags, scanFlags, (pkg == mPlatformPackage), user); //***35*** return scanPackageOnlyLI(request, mFactoryTest, currentTime); } } 扫描解析阶段的代码流程其实也挺长,具体细节如下:
- 对于包含child的包,先check扫描一遍,再非check扫描一遍
- 不包含child的包直接非check扫描一遍
- 扫描函数
scanPackageNewLI()
1.adjustScanFlags()
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. directBootAware 设置所有组件的directBootAware标志
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()
扫描软件包设置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
执行完2-2的scanPackageTrackLI()
之后Pms的两大核心数据结构都已经准备好了,一个是代表扫描结果的final ArrayMap
- 2-3.整合验证阶段:在2-2生成PackageSetting和PackageParser.Package数据结构后,还需要对多个安装apk结果进行调和,一般在 install-multi-package的时候会同时安装多个apk。调用方法是
reconcilePackagesLocked()
:@GuardedBy("mPackages") private static Map
reconcilePackagesLocked( final ReconcileRequest request, KeySetManagerService ksms) throws ReconcileFailure { final Map scannedPackages = request.scannedPackages; final Map result = new ArrayMap<>(scannedPackages.size()); // make a copy of the existing set of packages so we can combine them with incoming packages final ArrayMap combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size()); combinedPackages.putAll(request.allPackages); final Map > incomingSharedLibraries = new ArrayMap<>(); for (String installPackageName : scannedPackages.keySet()) { final ScanResult scanResult = scannedPackages.get(installPackageName); // add / replace existing with incoming packages combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg); // in the first pass, we'll build up the set of incoming shared libraries final List allowedSharedLibInfos = getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource); final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo; if (allowedSharedLibInfos != null) { for (SharedLibraryInfo info : allowedSharedLibInfos) { if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) { throw new ReconcileFailure("Static Shared Library " + staticLib.getName() + " is being installed twice in this set!"); } } } // the following may be null if we're just reconciling on boot (and not during install) final InstallArgs installArgs = request.installArgs.get(installPackageName); final PackageInstalledInfo res = request.installResults.get(installPackageName); final PrepareResult prepareResult = request.preparedPackages.get(installPackageName); final boolean isInstall = installArgs != null; if (isInstall && (res == null || prepareResult == null)) { throw new ReconcileFailure("Reconcile arguments are not balanced for " + installPackageName + "!"); } final DeletePackageAction deletePackageAction; // we only want to try to delete for non system apps if (isInstall && prepareResult.replace && !prepareResult.system) { final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0; final int deleteFlags = PackageManager.DELETE_KEEP_DATA | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs, prepareResult.childPackageSettings, deleteFlags, null /* all users */); if (deletePackageAction == null) { throw new ReconcileFailure( PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE, "May not delete " + installPackageName + " to replace"); } } else { deletePackageAction = null; } final int scanFlags = scanResult.request.scanFlags; final int parseFlags = scanResult.request.parseFlags; final PackageParser.Package pkg = scanResult.request.pkg; final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting; final PackageSetting lastStaticSharedLibSetting = request.lastStaticSharedLibSettings.get(installPackageName); final PackageSetting signatureCheckPs = (prepareResult != null && lastStaticSharedLibSetting != null) ? lastStaticSharedLibSetting : scanResult.pkgSetting; boolean removeAppKeySetData = false; boolean sharedUserSignaturesChanged = false; SigningDetails signingDetails = null; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. } else { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); } else { String msg = "System package " + pkg.packageName + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } } signingDetails = pkg.mSigningDetails; } else { try { final VersionInfo versionInfo = request.versionInfos.get(installPackageName); final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo); final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo); final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { removeAppKeySetData = true; } // We just determined the app is signed correctly, so bring // over the latest parsed certs. signingDetails = pkg.mSigningDetails; // if this is is a sharedUser, check to see if the new package is signed by a // newer // signing certificate than the existing one, and if so, copy over the new // details if (signatureCheckPs.sharedUser != null) { if (pkg.mSigningDetails.hasAncestor( signatureCheckPs.sharedUser.signatures.mSigningDetails)) { signatureCheckPs.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails; } if (signatureCheckPs.sharedUser.signaturesChanged == null) { signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE; } } } catch (PackageManagerException e) { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(e); } signingDetails = pkg.mSigningDetails; // If the system app is part of a shared user we allow that shared user to // change // signatures as well as part of an OTA. We still need to verify that the // signatures // are consistent within the shared user for a given boot, so only allow // updating // the signatures on the first package scanned for the shared user (i.e. if the // signaturesChanged state hasn't been initialized yet in SharedUserSetting). if (signatureCheckPs.sharedUser != null) { final Signature[] sharedUserSignatures = signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures; if (signatureCheckPs.sharedUser.signaturesChanged != null && compareSignatures(sharedUserSignatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) { // Mismatched signatures is an error and silently skipping system // packages will likely break the device in unforeseen ways. // However, we allow the device to boot anyway because, prior to Q, // vendors were not expecting the platform to crash in this // situation. // This WILL be a hard failure on any new API levels after Q. throw new ReconcileFailure( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Signature mismatch for shared user: " + scanResult.pkgSetting.sharedUser); } else { // Treat mismatched signatures on system packages using a shared // UID as // fatal for the system overall, rather than just failing to install // whichever package happened to be scanned later. throw new IllegalStateException( "Signature mismatch on system package " + pkg.packageName + " for shared user " + scanResult.pkgSetting.sharedUser); } } sharedUserSignaturesChanged = true; signatureCheckPs.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails; signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE; } // File a report about this. String msg = "System package " + pkg.packageName + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } catch (IllegalArgumentException e) { // should never happen: certs matched when checking, but not when comparing // old to new for sharedUser throw new RuntimeException( "Signing certificates comparison made on incomparable signing details" + " but somehow passed verifySignatures!", e); } } result.put(installPackageName, new ReconciledPackage(request, installArgs, scanResult.pkgSetting, res, request.preparedPackages.get(installPackageName), scanResult, deletePackageAction, allowedSharedLibInfos, signingDetails, sharedUserSignaturesChanged, removeAppKeySetData)); } for (String installPackageName : scannedPackages.keySet()) { // Check all shared libraries and map to their actual file path. // We only do this here for apps not on a system dir, because those // are the only ones that can fail an install due to this. We // will take care of the system apps by updating all of their // library paths after the scan is done. Also during the initial // scan don't update any libs as we do this wholesale after all // apps are scanned to avoid dependency based scanning. final ScanResult scanResult = scannedPackages.get(installPackageName); if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0 || (scanResult.request.parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { continue; } try { result.get(installPackageName).collectedSharedLibraryInfos = collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages, request.sharedLibrarySource, incomingSharedLibraries); } catch (PackageManagerException e) { throw new ReconcileFailure(e.error, e.getMessage()); } } return result; }
-
2-4.确认提交阶段:提交所有扫描的包并更新系统状态。这是唯一可以在安装流中修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。经过上述几个步骤,两个核心数据结构已经生成,但是并没有添加到容器中去(PackageManagerService.mPackages 和 PackageManagerService.mSettings.mPackage), 所以该包里面的组件等还不能查询到,也不能启动。 所以需要调用
commitPackagesLocked()
来进行提交, 提交之后该应用就算完整发布了。@GuardedBy("mPackages") private void commitPackagesLocked(final CommitRequest request) { // TODO: remove any expected failures from this method; this should only be able to fail due // to unavoidable errors (I/O, etc.) for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) { final ScanResult scanResult = reconciledPkg.scanResult; final ScanRequest scanRequest = scanResult.request; final PackageParser.Package pkg = scanRequest.pkg; final String packageName = pkg.packageName; final PackageInstalledInfo res = reconciledPkg.installResult; //***36*** if (reconciledPkg.prepareResult.replace) { PackageParser.Package oldPackage = mPackages.get(packageName); // Set the update and install times PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras; setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime, System.currentTimeMillis()); if (reconciledPkg.prepareResult.system) { //***37*** // Remove existing system package removePackageLI(oldPackage, true); if (!disableSystemPackageLPw(oldPackage, pkg)) { // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. res.removedInfo.args = createInstallArgsForExisting( oldPackage.applicationInfo.getCodePath(), oldPackage.applicationInfo.getResourcePath(), getAppDexInstructionSets(oldPackage.applicationInfo)); } else { res.removedInfo.args = null; } // Update the package dynamic state if succeeded // Now that the install succeeded make sure we remove data // directories for any child package the update removed. final int deletedChildCount = (oldPackage.childPackages != null) ? oldPackage.childPackages.size() : 0; final int newChildCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; for (int i = 0; i < deletedChildCount; i++) { PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i); boolean childPackageDeleted = true; for (int j = 0; j < newChildCount; j++) { PackageParser.Package newChildPkg = pkg.childPackages.get(j); if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) { childPackageDeleted = false; break; } } if (childPackageDeleted) { PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr( deletedChildPkg.packageName); if (ps1 != null && res.removedInfo.removedChildPackages != null) { PackageRemovedInfo removedChildRes = res.removedInfo .removedChildPackages.get(deletedChildPkg.packageName); removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0, false); removedChildRes.removedForAllUsers = mPackages.get(ps1.name) == null; } } } } else { try {//***38*** executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName, true, request.mAllUsers, true, pkg); } catch (SystemDeleteException e) { if (Build.IS_ENG) { throw new RuntimeException("Unexpected failure", e); // ignore; not possible for non-system app } } // Successfully deleted the old package; proceed with replace. // If deleted package lived in a container, give users a chance to // relinquish resources before killing. if (oldPackage.isForwardLocked() || isExternal(oldPackage)) { if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + oldPackage + " is ASEC-hosted -> UNAVAILABLE"); } final int[] uidArray = new int[]{oldPackage.applicationInfo.uid}; final ArrayList
pkgList = new ArrayList<>(1); pkgList.add(oldPackage.applicationInfo.packageName); //***39*** sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } // Update the in-memory copy of the previous code paths. PackageSetting ps1 = mSettings.mPackages.get( reconciledPkg.prepareResult.existingPackage.packageName); if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP) == 0) { if (ps1.mOldCodePaths == null) { ps1.mOldCodePaths = new ArraySet<>(); } Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath); if (oldPackage.splitCodePaths != null) { Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths); } } else { ps1.mOldCodePaths = null; } if (ps1.childPackageNames != null) { for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) { final String childPkgName = ps1.childPackageNames.get(i); final PackageSetting childPs = mSettings.mPackages.get(childPkgName); childPs.mOldCodePaths = ps1.mOldCodePaths; } } if (reconciledPkg.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName); if (ps2 != null) { res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null; if (res.removedInfo.removedChildPackages != null) { final int childCount1 = res.removedInfo.removedChildPackages.size(); // Iterate in reverse as we may modify the collection for (int i = childCount1 - 1; i >= 0; i--) { String childPackageName = res.removedInfo.removedChildPackages.keyAt(i); if (res.addedChildPackages.containsKey(childPackageName)) { res.removedInfo.removedChildPackages.removeAt(i); } else { PackageRemovedInfo childInfo = res.removedInfo .removedChildPackages.valueAt(i); childInfo.removedForAllUsers = mPackages.get( childInfo.removedPackage) == null; } } } } } } } //***40*** commitReconciledScanResultLocked(reconciledPkg); //***41*** updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers, res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason); final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); ps.setUpdateAvailable(false /*updateAvailable*/); } final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; for (int i = 0; i < childCount; i++) { PackageParser.Package childPkg = pkg.childPackages.get(i); PackageInstalledInfo childRes = res.addedChildPackages.get( childPkg.packageName); PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); if (childPs != null) { childRes.newUsers = childPs.queryInstalledUsers( sUserManager.getUserIds(), true); } } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { //***42*** updateSequenceNumberLP(ps, res.newUsers); //***43*** updateInstantAppInstallerLocked(packageName); } } } 确认阶段详细流程如下:
replace
1. 设置了一遍ps的firstInstalltime 和lastUpdateTime
2. 系统应用
1. 删除旧的package
2. 删除覆盖安装的system 应用的应用,需要删除的东西放在removedInfo中
3. 处理child package
3. 非系统应用
1. 删除package
2. 手机要删除的数据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()
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()
撤销需要撤销的权限updateSettingsLI()
1. 系统应用
1. 设置多用户
2. 删除多余的用户
3. 写配置文件updateSequenceNumberLP(ps, res.newUsers)
updateInstantAppInstallerLocked(packageName)
-
2.5
executePostCommitSteps()
方法主要是dexoat部分工作,这部分不会修改核心数据结构,所以在mPackage锁外面执行。/** * On successful install, executes remaining steps after commit completes and the package lock * is released. These are typically more expensive or require calls to installd, which often * locks on {@link #mPackages}. */ private void executePostCommitSteps(CommitRequest commitRequest) { for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg; final String packageName = pkg.packageName; //***44*** prepareAppDataAfterInstallLIF(pkg); if (reconciledPkg.prepareResult.clearCodeCache) { clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } if (reconciledPkg.prepareResult.replace) { mDexManager.notifyPackageUpdated(pkg.packageName, pkg.baseCodePath, pkg.splitCodePaths); } // Prepare the application profiles for the new code paths. // This needs to be done before invoking dexopt so that any install-time profile // can be used for optimizations. //***45*** mArtManagerService.prepareAppProfiles( pkg, resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()), /* updateReferenceProfileContent= */ true); // Check whether we need to dexopt the app. // // NOTE: it is IMPORTANT to call dexopt: // - after doRename which will sync the package data from PackageParser.Package and // its corresponding ApplicationInfo. // - after installNewPackageLIF or replacePackageLIF which will update result with the // uid of the application (pkg.applicationInfo.uid). // This update happens in place! // // We only need to dexopt if the package meets ALL of the following conditions: // 1) it is not an instant app or if it is then dexopt is enabled via gservices. // 2) it is not debuggable. // // Note that we do not dexopt instant apps by default. dexopt can take some time to // complete, so we skip this step during installation. Instead, we'll take extra time // the first time the instant app starts. It's preferred to do it this way to provide // continuous progress to the useur instead of mysteriously blocking somewhere in the // middle of running an instant app. The default behaviour can be overridden // via gservices. final boolean performDexopt = (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0); if (performDexopt) { // Compile the layout resources. if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts"); //***46*** mViewCompiler.compileLayouts(pkg); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` may not be in `mPackages` yet. // // Also, don't fail application installs if the dexopt step fails. DexoptOptions dexoptOptions = new DexoptOptions(packageName, REASON_INSTALL, DexoptOptions.DEXOPT_BOOT_COMPLETE | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE); //***47*** mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */, getOrCreateCompilerPackageStats(pkg), mDexManager.getPackageUseInfoOrDefault(packageName), dexoptOptions); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } // Notify BackgroundDexOptService that the package has been changed. // If this is an update of a package which used to fail to compile, // BackgroundDexOptService will remove it from its blacklist. // TODO: Layering violation //***49*** BackgroundDexOptService.notifyPackageChanged(packageName); } }
3.调用
FileInstallArgs.doPostInstall()
再做一些清理工作,和FileInstallArgs.doPreInstall()
执行的内容是相同的。4.调用
PackageManagerService.restoreAndPostInstall()
做一些后续工作,比如发送应用变化相关的广播:
/** @param data Post-install is performed only if this is non-null. */
private void restoreAndPostInstall(
int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
if (DEBUG_INSTALL) {
Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package="
+ res.pkg.packageName);
}
// A restore should be performed at this point if (a) the install
// succeeded, (b) the operation is not an update, and (c) the new
// package has not opted out of backup participation.
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
boolean doRestore = !update
&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
// there's a restore pass performed. Token values are >= 1.
int token;
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
if (data != null) {
mRunningInstalls.put(token, data);
} else if (DEBUG_INSTALL) {
Log.v(TAG, "No post-install required for " + token);
}
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
// Pass responsibility to the Backup Manager. It will perform a
// restore if appropriate, then pass responsibility back to the
// Package Manager to run the post-install observer callbacks
// and broadcasts.
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
// For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
// in the BackupManager. USER_ALL is used in compatibility tests.
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
}
if (DEBUG_INSTALL) {
Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
}
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
try {
if (bm.isBackupServiceActive(userId)) {
bm.restoreAtInstallForUser(
userId, res.pkg.applicationInfo.packageName, token);
} else {
doRestore = false;
}
} catch (RemoteException e) {
// can't happen; the backup manager is local
} catch (Exception e) {
Slog.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
}
} else {
Slog.e(TAG, "Backup Manager not found!");
doRestore = false;
}
}
// If this is an update to a package that might be potentially downgraded, then we
// need to check with the rollback manager whether there's any userdata that might
// need to be restored for the package.
//
// TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
IRollbackManager rm = IRollbackManager.Stub.asInterface(
ServiceManager.getService(Context.ROLLBACK_SERVICE));
final String packageName = res.pkg.applicationInfo.packageName;
final String seInfo = res.pkg.applicationInfo.seInfo;
final int[] allUsers = sUserManager.getUserIds();
final int[] installedUsers;
final PackageSetting ps;
int appId = -1;
long ceDataInode = -1;
synchronized (mSettings) {
ps = mSettings.getPackageLPr(packageName);
if (ps != null) {
appId = ps.appId;
ceDataInode = ps.getCeDataInode(userId);
}
// NOTE: We ignore the user specified in the InstallParam because we know this is
// an update, and hence need to restore data for all installed users.
installedUsers = ps.queryInstalledUsers(allUsers, true);
}
if (ps != null) {
try {
rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
seInfo, token);
} catch (RemoteException re) {
// Cannot happen, the RollbackManager is hosted in the same process.
}
doRestore = true;
}
}
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
//无法进行恢复,或者备份管理器神秘地不可用,则直接触发安装后工作请求
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
//***50***
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
}
1. 如果该应用可以备份恢复,并且BackupManager活跃状态通知尝试恢复数据;
2. 没有restore情况下升级安装可能是降级安装, 尝试使用rollbackMnaager恢复数据, rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,seInfo, token);
3. 没有doRestore的情况下 POST_INSTALL, 否则等安装备份或者rollback调用.
Handler接收POST_INSTALL消息会调用handlePackagePostInstall()
处理,该方法比较长,主要做了以下几个事儿:
- 如果安装成功:
1. remove 发送广播
2. 权限假如白名单
3. 根据安装参数授予运行时全新啊
4. 对每一个安装的用户
1. 发送newuser广播
2. 发送ACTION_PACKAGE_REPLACED广播 - 最后执行
scheduleDeferredNoKillInstallObserver()
或者notifyInstallObserver()
方法,其中scheduleDeferredNoKillInstallObserver()
最后也会调用到notifyInstallObserver()
,所以我们看notifyInstallObserver()
方法:
private void notifyInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
try {
Bundle extras = extrasForInstallResult(info);
//***51***
installObserver.onPackageInstalled(info.name, info.returnCode,
info.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
这里的installObserver
是Android APK安装流程(3)里PackageInstallerSession的localObserver,它的回调方法onPackageInstalled()
执行的是destroyInternal()
和dispatchSessionFinished()
,而dispatchSessionFinished()
前文中出现多次,其主要做了3件事:
1. 发送Handler消息MSG_ON_PACKAGE_INSTALLED
2. 发送了一个ACTION_SESSION_COMMITTED广播到InstallEventReceiver
3. 回调了onSessionFinished
其中第1点的MSG_ON_PACKAGE_INSTALLED的消息处理中又调用了
observer.onPackageInstalled()
回调方法。这个observer是PackageInstallSession的commit流程中生成的对象mRemoteObserver
(参考Android APK安装流程(2)--APK的拷贝的48步)。mRemoteObserver
是PackageInstallObserverAdapter的getBinder()
方法获取的对象。其onPackageInstalled()
方法主要就是创建一个Notification告知用户安装完成:
#PackageInstallerService$PackageInstallObserverAdapter
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
Notification notification = buildSuccessNotification(mContext,
mContext.getResources()
.getString(update ? R.string.package_updated_device_owner :
R.string.package_installed_device_owner),
basePackageName,
mUserId);
if (notification != null) {
NotificationManager notificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(basePackageName,
SystemMessage.NOTE_PACKAGE_STATE,
notification);
}
}
final Intent fillIn = new Intent();
fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
PackageManager.installStatusToPublicStatus(returnCode));
fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
PackageManager.installStatusToString(returnCode, msg));
fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
if (extras != null) {
final String existing = extras.getString(
PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
if (!TextUtils.isEmpty(existing)) {
fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
}
}
try {
mTarget.sendIntent(mContext, 0, fillIn, null, null);
} catch (SendIntentException ignored) {
}
}
其中第2点看以下InstallEventReceiver接收到广播后的处理:
@Override
public void onReceive(Context context, Intent intent) {
getReceiver(context).onEventReceived(context, intent);
}
void onEventReceived(@NonNull Context context, @NonNull Intent intent) {
int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);
if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
context.startActivity(intent.getParcelableExtra(Intent.EXTRA_INTENT));
return;
}
int id = intent.getIntExtra(EXTRA_ID, 0);
String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
int legacyStatus = intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 0);
EventResultObserver observerToCall = null;
synchronized (mLock) {
int numObservers = mObservers.size();
for (int i = 0; i < numObservers; i++) {
if (mObservers.keyAt(i) == id) {
observerToCall = mObservers.valueAt(i);
mObservers.removeAt(i);
break;
}
}
if (observerToCall != null) {
observerToCall.onResult(status, legacyStatus, statusMessage);
} else {
mResults.put(id, new EventResult(status, legacyStatus, statusMessage));
writeState();
}
}
}
从EXTRA_ID 中获取当前EventResultObserver对应的id,并且回调onResult。此时就会回调到InstallInstalling的launchFinishBasedOnResult方法,显示出安装成功/失败的界面,具体可参考Android APK安装流程(2)的3、4、8、9流程。
最后看一下时序图