-
第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<InstallRequest> 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<InstallRequest> 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:
* <ul>
* <li><b>Prepare</b>
* <br/>Analyzes any current install state, parses the package and does initial
* validation on it.</li>
* <li><b>Scan</b>
* <br/>Interrogates the parsed packages given the context collected in prepare.</li>
* <li><b>Reconcile</b>
* <br/>Validates scanned packages in the context of each other and the current system
* state to ensure that the install will be successful.
* <li><b>Commit</b>
* <br/>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.</li>
* </ul>
*
* Failure at any phase will result in a full failure to install all packages.
*/
@GuardedBy("mInstallLock")
private void installPackagesLI(List<InstallRequest> 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<ScanResult> 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<String, ReconciledPackage> 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.準備階段:分析任何當(dāng)前安裝狀態(tài),解析包并對其進行初始驗證。
準備階段的方法很長,主要做了以下幾個事情:# 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**** 設(shè)置簽名文件 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內(nèi)容,并把解析的package結(jié)果緩存到磁盤和內(nèi)存中(//***18***)。
2-1-2.往Package對象中設(shè)置好簽名信息(//***21***)。
2-1-3.從Settings中獲取是否有當(dāng)前包名對應(yīng)的PackageSetting 包配置信息,此時還沒有則跳開這里的if。獲取PermissionManagerService查詢權(quán)限信息。如果還是能查到,說明是包的升級,此時會進行包權(quán)限的校驗。判斷前后兩次是不是內(nèi)部包含的包權(quán)限內(nèi)容都是一致,而只是順序變了。當(dāng)然如果之前沒有安裝,或者內(nèi)容不一致,都會觸發(fā)KeySetManagerService的checkUpgradeKeySetLocked進行更新(//***22***)。
2-1-4.調(diào)用InstallArgs.doRename 把當(dāng)前的包的名字給更新了(//***24***)。
2-1-5.判斷當(dāng)前是否允許對包進行校驗,如果允許則調(diào)用VerityUtils.generateApkVeritySetupData()對包的簽名進行校驗,校驗通過根路徑則調(diào)用Installd服務(wù)進一步調(diào)用installApkVerity進行校驗,詳細可以看setUpFsVerityIfPossible()方法(//***25***)。
2-1-6.返回PrepareResult(//***29***)
具體詳細流程:
1 準備scanflags: move 表示已經(jīng)初始化過,添加SCAN_INITIAL標志, 不需要殺掉添加 SCAN_DONT_KILL_APP, instantApp 為SCAN_AS_INSTANT_APP, fullApp 為 SCAN_AS_FULL_APP, virtualPreload 虛擬預(yù)加載SCAN_AS_VIRTUAL_PRELOAD
2 instant app 不能安裝在外置存儲
3 pp.parsePackage(tmpPackageFile, parseFlags) 解析, DexMetadataHelper.validatePackageDexMetadata(pkg) 驗證dm文件
4 instantApp 驗證, targetSdkVersion不能小于o, 不能是isharedUid
5 靜態(tài)庫修改包名,包名添加上version信息,方便安裝多版本庫
6 子包的處理
7 cpuAbiOverride 處理, 如果安裝選項設(shè)置了使用安裝選項覆蓋
8 TEST_ONLY app 應(yīng)用判斷是否可以安裝, 沒有-t選項不允許安裝
9 判斷是否是replace安裝
?9.1 包含original-package使用舊包名驗證是否安裝過
?9.2 非original-package使用包名看下是否安裝過
?9.3 子包禁止安裝
?9.4 替換安裝情況下, targetSdk 范圍檢查
?9.5 禁止PERSISTENT 非 stage安裝(因為可能會導(dǎo)致persistent被殺)
?9.6 禁止子包安裝
10 替換安裝情況對簽名進行檢查
11 權(quán)限處理
?11.1 除了系統(tǒng)應(yīng)用之外不允許定義PROTECTION_FLAG_INSTANT級別的權(quán)限
?11.2 對于要更新的權(quán)限執(zhí)行以下操作
??11.2.1 如果是應(yīng)用升級則并且有升級key限制則驗證
??11.2.2 沒有升級key限制則驗證證書匹配才可以升級權(quán)限
??11.2.3 非PLATFORM_PACKAGE_NAME禁止簽名不同升級權(quán)限
??11.2.4 PROTECTION_DANGEROUS 權(quán)限禁止修改(降低) 保護級別
12 系統(tǒng)應(yīng)用禁止是instantApp,禁止安裝在外置存儲
13 abi的處理
?13.1 move 應(yīng)用安裝位置,直接設(shè)置primaryCpuAbi 和 secondaryCpuAbi
?13.2 非move應(yīng)用 derivePackageAbi
14 修改包名
15 fsverify
16 startIntentFilterVerifications
17 創(chuàng)建 freezer 禁止啟動
19 替換安裝情況
?19.1 靜態(tài)庫禁止同版本升級
?19.2 再次驗證簽名
?19.3 驗證系統(tǒng)應(yīng)用升級的restrict-update
?19.4 檢查shareduid是否變化
?19.5 禁止fullapp -> instant app 安裝
?19.6 設(shè)置更新后被移除的子包
?19.7 系統(tǒng)包根據(jù)舊包設(shè)置targetParseFlags targetScanFlags, 設(shè)置setApplicationInfoFlags位FLAG_UPDATED_SYSTEM_APP
20 非替換安裝情況(新安裝)
?20.1 沒有指定INSTALL_REPLACE_EXISTING 禁止非替換安裝
21 創(chuàng)建 PrepareResult返回
-
2-2.掃描解析階段:根據(jù)準備階段中收集的上下文對包進行解析,主要用于生成PackageSetting數(shù)據(jù)結(jié)構(gòu)。調(diào)用
scanPackageTracedLI()掃描包內(nèi)容,此時其實已經(jīng)解析過一次包內(nèi)容,在這里能直接獲得緩存。#PackageManagerService @GuardedBy({"mInstallLock", "mPackages"}) private List<ScanResult> 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<ScanResult> 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); } }掃描解析階段的代碼流程其實也挺長,具體細節(jié)如下:
- 對于包含child的包,先check掃描一遍,再非check掃描一遍
- 不包含child的包直接非check掃描一遍
- 掃描函數(shù)
scanPackageNewLI()
? 1.adjustScanFlags()
? ? 1. 如果覆蓋安裝系統(tǒng)應(yīng)用設(shè)置系統(tǒng)相關(guān)的掃描屬性
? ? 2. 如果instant安裝設(shè)置 SCAN_AS_INSTANT_APP, 如果 VirtulalPreload設(shè)置 SCAN_AS_VIRTUAL_PRELOAD
? ? 3. 如果簽名是系統(tǒng)簽名,并且shareduid 是privleged的,并且要安裝的應(yīng)用簽名和平臺簽名一致,設(shè)置 SCAN_AS_PRIVILEGED(這相當(dāng)于一種權(quán)限提升呀)
? 2.applyPolicy()這一步根據(jù)scanFlags設(shè)置pkg.applicationInfo下的標志和 四大組件的標志
??1. 系統(tǒng)應(yīng)用設(shè)置
???1. directBootAware 設(shè)置所有組件的directBootAware標志
???2. 如果是stub安裝設(shè)置 pkg.isStub = true
??2. 非系統(tǒng)應(yīng)用刪除一些特權(quán)flags,設(shè)置降低權(quán)限組優(yōu)先級,pkg.permissionGroups.get(i).info.priority
??3. 非SCAN_AS_PRIVILEGED app
???1. pkg.protectedBroadcasts = null
???2. 不支持多用戶的receivers services 和 providers 禁止導(dǎo)出
??4. 設(shè)置其他標志
??5. 不是SystemApp 不允許orginial-package
?3.assertPackageIsValid()
??1. PARSE_ENFORCE_CODE 標志,檢查hascode屬性的apk是否包含代碼
??2. 必須設(shè)置codepath或者resourcePath
??3. 不允許用戶安裝和手冊啟動或者ota檢查apex包重復(fù)
??4. 禁止重新安裝平臺包(android.jar)
??5. 非安裝過程禁止同名包
??6. 靜態(tài)庫檢查
?4. 創(chuàng)建ScanRequest
?5.scanPackageOnlyLI()掃描軟件包設(shè)置Package 和PackageSettings
??1. 第一次啟動或者ota需要重新確定abi
??2. sharedUser不能修改
??3. 創(chuàng)建PackageSettings(根據(jù)舊的或者重新創(chuàng)建)
??4. original-package 設(shè)置為舊報名,打日志
??5. 修改狀態(tài) instant_app 或者full_app (full 不能到instant。 instant 能到full?)
??6. 覆蓋安裝系統(tǒng)應(yīng)用設(shè)置 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
??7. seInfo 設(shè)置 seInfoUser設(shè)置
??8. 設(shè)置進程名稱
??9. 初始化系統(tǒng)user
??10. 非安裝流程SCAN_NEW_INSTALL = 0
???1. 需要driverAbi
???2. 不需要driverAbi 設(shè)置primaryCpuAbi, secondaryCpuAbi
??11. 非安裝流程, 設(shè)置primaryCpuAbi secondaryCpuAbi 和applicationInfo
??12. 設(shè)置PackageSettings 的 firstInstallTime lastUpdateTime
??13. pkgSetting.pkg = pkg, pkgSetting.pkgFlags = pkg.applicationInfo.flags, pkgSetting.versionCode = pkg.getLongVersionCode(), pkgSetting.volumeUuid = volumeUuid
??14. return new ScanResult
執(zhí)行完2-2的scanPackageTrackLI()之后Pms的兩大核心數(shù)據(jù)結(jié)構(gòu)都已經(jīng)準備好了,一個是代表掃描結(jié)果的final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();中的PackageParser.Package,另外一個是mSettings.mPackages的PackageSetting 數(shù)據(jù)結(jié)構(gòu),這兩個結(jié)構(gòu)PackageParser.Package代表掃描結(jié)果,為靜態(tài)數(shù)據(jù),掃描完成后就不會發(fā)生變化。PackageSetting用于存儲安裝應(yīng)用的動態(tài)數(shù)據(jù),如權(quán)限授予情況等。PackageParser.Package由于是靜態(tài)數(shù)據(jù),掃描apk就可以獲取。PackageSetting生成之后會被記錄到文件中,以后每次系統(tǒng)啟動都會重新加載。
- 2-3.整合驗證階段:在2-2生成PackageSetting和PackageParser.Package數(shù)據(jù)結(jié)構(gòu)后,還需要對多個安裝apk結(jié)果進行調(diào)和,一般在 install-multi-package的時候會同時安裝多個apk。調(diào)用方法是
reconcilePackagesLocked():@GuardedBy("mPackages") private static Map<String, ReconciledPackage> reconcilePackagesLocked( final ReconcileRequest request, KeySetManagerService ksms) throws ReconcileFailure { final Map<String, ScanResult> scannedPackages = request.scannedPackages; final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size()); // make a copy of the existing set of packages so we can combine them with incoming packages final ArrayMap<String, PackageParser.Package> combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size()); combinedPackages.putAll(request.allPackages); final Map<String, LongSparseArray<SharedLibraryInfo>> 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<SharedLibraryInfo> 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.確認提交階段:提交所有掃描的包并更新系統(tǒng)狀態(tài)。這是唯一可以在安裝流中修改系統(tǒng)狀態(tài)的地方,必須在此階段之前確定所有可預(yù)測的錯誤。經(jīng)過上述幾個步驟,兩個核心數(shù)據(jù)結(jié)構(gòu)已經(jīng)生成,但是并沒有添加到容器中去(PackageManagerService.mPackages 和 PackageManagerService.mSettings.mPackage), 所以該包里面的組件等還不能查詢到,也不能啟動。 所以需要調(diào)用
commitPackagesLocked()來進行提交, 提交之后該應(yīng)用就算完整發(fā)布了。@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<String> 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. 設(shè)置了一遍ps的firstInstalltime 和lastUpdateTime
?2. 系統(tǒng)應(yīng)用
??1. 刪除舊的package
??2. 刪除覆蓋安裝的system 應(yīng)用的應(yīng)用,需要刪除的東西放在removedInfo中
??3. 處理child package
?3. 非系統(tǒng)應(yīng)用
??1. 刪除package
??2. 手機要刪除的數(shù)據(jù)commitReconciledScanResultLocked()正式提交
?1. sharedUser發(fā)生變化,移除舊的sharedUser
?2. 更新應(yīng)用 使用舊的packageSettings更新 packageSettings,pkg.mExtras = pkgSetting
?3. 新安裝 設(shè)置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 應(yīng)用,并且非check, 設(shè)置 mPlatformPackage pkg.mVersionCode = mSdkVersion; pkg.mVersionCodeMajor = 0; mAndroidApplication = pkg.applicationInfo; mResolverReplaced沒有替換,設(shè)置系統(tǒng)的resolveActivity
??3. 更新sharedLibrary
??4. lib更新,殺掉 依賴的包
??5.mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);更新核心數(shù)據(jù)
??6.mComponentResolver.addAllComponents(pkg, chatty)添加所有組件
??7.mPermissionManager.addAllPermissionGroups(pkg, chatty)添加所有權(quán)限組
??8.mPermissionManager.addAllPermissions(pkg, chatty);添加所有權(quán)限
??9. instrumentation
??10. pkg.protectedBroadcasts
??11.mPermissionManager.revokeRuntimePermissionsIfGroupChanged()撤銷需要撤銷的權(quán)限updateSettingsLI()
?1. 系統(tǒng)應(yīng)用
??1. 設(shè)置多用戶
?2. 刪除多余的用戶
?3. 寫配置文件updateSequenceNumberLP(ps, res.newUsers)updateInstantAppInstallerLocked(packageName)
-
2.5
executePostCommitSteps()方法主要是dexoat部分工作,這部分不會修改核心數(shù)據(jù)結(jié)構(gòu),所以在mPackage鎖外面執(zhí)行。/** * 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.調(diào)用
FileInstallArgs.doPostInstall()再做一些清理工作,和FileInstallArgs.doPreInstall()執(zhí)行的內(nèi)容是相同的。4.調(diào)用
PackageManagerService.restoreAndPostInstall()做一些后續(xù)工作,比如發(fā)送應(yīng)用變化相關(guān)的廣播:
/** @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.
//無法進行恢復(fù),或者備份管理器神秘地不可用,則直接觸發(fā)安裝后工作請求
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. 如果該應(yīng)用可以備份恢復(fù),并且BackupManager活躍狀態(tài)通知嘗試恢復(fù)數(shù)據(jù);
?2. 沒有restore情況下升級安裝可能是降級安裝, 嘗試使用rollbackMnaager恢復(fù)數(shù)據(jù), rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,seInfo, token);
?3. 沒有doRestore的情況下 POST_INSTALL, 否則等安裝備份或者rollback調(diào)用.
Handler接收POST_INSTALL消息會調(diào)用handlePackagePostInstall()處理,該方法比較長,主要做了以下幾個事兒:
- 如果安裝成功:
?1. remove 發(fā)送廣播
?2. 權(quán)限假如白名單
?3. 根據(jù)安裝參數(shù)授予運行時全新啊
?4. 對每一個安裝的用戶
??1. 發(fā)送newuser廣播
??2. 發(fā)送ACTION_PACKAGE_REPLACED廣播 - 最后執(zhí)行
scheduleDeferredNoKillInstallObserver()或者notifyInstallObserver()方法,其中scheduleDeferredNoKillInstallObserver()最后也會調(diào)用到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,它的回調(diào)方法onPackageInstalled()執(zhí)行的是destroyInternal()和dispatchSessionFinished(),而dispatchSessionFinished()前文中出現(xiàn)多次,其主要做了3件事:
?1. 發(fā)送Handler消息MSG_ON_PACKAGE_INSTALLED
?2. 發(fā)送了一個ACTION_SESSION_COMMITTED廣播到InstallEventReceiver
?3. 回調(diào)了onSessionFinished
其中第1點的MSG_ON_PACKAGE_INSTALLED的消息處理中又調(diào)用了
observer.onPackageInstalled()回調(diào)方法。這個observer是PackageInstallSession的commit流程中生成的對象mRemoteObserver(參考Android APK安裝流程(2)--APK的拷貝的48步)。mRemoteObserver是PackageInstallObserverAdapter的getBinder()方法獲取的對象。其onPackageInstalled()方法主要就是創(chuàng)建一個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 中獲取當(dāng)前EventResultObserver對應(yīng)的id,并且回調(diào)onResult。此時就會回調(diào)到InstallInstalling的launchFinishBasedOnResult方法,顯示出安裝成功/失敗的界面,具體可參考Android APK安裝流程(2)的3、4、8、9流程。
最后看一下時序圖