在廣州注冊公司流程和費用長沙網(wǎng)站seo排名
??經(jīng)過前面準備、瀏覽、協(xié)調(diào)這些步驟,馬上要進入提交階段了。所謂提交,就是把這些安裝應(yīng)用的相關(guān)信息和狀態(tài)都放到系統(tǒng)中。對于已安裝普通應(yīng)用,它其實分為兩個步驟,先卸載舊包,再安裝新包。當然,如果是新安裝的應(yīng)用包,只涉及安裝新包這個步驟。
??它實現(xiàn)在commitPackagesLocked(final CommitRequest request)中:
@GuardedBy("mLock")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 ParsedPackage parsedPackage = scanRequest.parsedPackage;final String packageName = parsedPackage.getPackageName();final PackageInstalledInfo res = reconciledPkg.installResult;if (reconciledPkg.prepareResult.replace) {AndroidPackage oldPackage = mPackages.get(packageName);// Set the update and install timesPackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName());reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked());if (reconciledPkg.prepareResult.system) {// Remove existing system packageremovePackageLI(oldPackage, true);if (!disableSystemPackageLPw(oldPackage)) {// 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.getPath(),getAppDexInstructionSets(AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,deletedPkgSetting),AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,deletedPkgSetting)));} else {res.removedInfo.args = null;}} else {try {// Settings will be written during the call to updateSettingsLI().executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,true, request.mAllUsers, false, parsedPackage);} catch (SystemDeleteException e) {if (mIsEngBuild) {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.isExternalStorage()) {if (DEBUG_INSTALL) {Slog.i(TAG, "upgrading pkg " + oldPackage+ " is ASEC-hosted -> UNAVAILABLE");}final int[] uidArray = new int[]{oldPackage.getUid()};final ArrayList<String> pkgList = new ArrayList<>(1);pkgList.add(oldPackage.getPackageName());sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);}// Update the in-memory copy of the previous code paths.PackageSetting ps1 = mSettings.getPackageLPr(reconciledPkg.prepareResult.existingPackage.getPackageName());if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)== 0) {if (ps1.mOldCodePaths == null) {ps1.mOldCodePaths = new ArraySet<>();}Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath());if (oldPackage.getSplitCodePaths() != null) {Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());}} else {ps1.mOldCodePaths = null;}if (reconciledPkg.installResult.returnCode== PackageManager.INSTALL_SUCCEEDED) {PackageSetting ps2 = mSettings.getPackageLPr(parsedPackage.getPackageName());if (ps2 != null) {res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;}}}}AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);final PackageSetting ps = mSettings.getPackageLPr(packageName);if (ps != null) {res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);ps.setUpdateAvailable(false /*updateAvailable*/);}if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {updateSequenceNumberLP(ps, res.newUsers);updateInstantAppInstallerLocked(packageName);}}ApplicationPackageManager.invalidateGetPackagesForUidCache();}
??CommitRequest對象request的成員reconciledPackages是Map<String, ReconciledPackage>對象,它里面是對應(yīng)每一個安裝應(yīng)用,key值是包名。該方法就是對每一個安裝應(yīng)用循環(huán),接著看它的處理。
??ScanResult對象scanResult、ScanRequest對象scanRequest是在 Android 安裝應(yīng)用-瀏覽階段 中生成的對象。ParsedPackage對象parsedPackage是解析對象包,parsedPackage是安裝應(yīng)用的包名,PackageInstalledInfo對象res 是對應(yīng)的應(yīng)用的安裝信息。
??reconciledPkg.prepareResult.replace為true,代表是需要替換舊包進行更新。
??在替換更新的情況下,先得到舊的解析包對象。mPackages是WatchedArrayMap<String, AndroidPackage>,它維持著所有的解析包對象,key值是包名。在替換之前,mPackages中的解析包對象就是舊包對象oldPackage,最后它需要被parsedPackage替換掉。deletedPkgSetting則是即將刪除的PackageSetting對象,reconciledPkg.pkgSetting則是之前Android 安裝應(yīng)用-瀏覽階段生成的新的PackageSetting對象,下面是更新新生成的PackageSetting對象的首次安裝時間和最后更新時間(當前時間)。res.removedInfo.broadcastAllowList是SparseArray<int[]>類型,它的key值是用戶UserId,value則是所有的應(yīng)用的app Ids。request.mAllUsers在這里是所有的用戶UserId數(shù)組,mAppsFilter.getVisibilityAllowList()得到所有的能看到該安裝應(yīng)用的應(yīng)用,res.removedInfo.broadcastAllowList就是是存放的這些能看到它的應(yīng)用的app Ids。
??如果被替換的包是系統(tǒng)包,調(diào)用removePackageLI(oldPackage, true)。該方法主要是將包名對應(yīng)的解析包對象從mPackages中刪除,然后將舊包的聲明的組件刪除,聲明的權(quán)限刪除,所有定義的屬性刪除,定義的instrumentation刪除,如果是系統(tǒng)包,還會將它引用的共享庫去除。如果它聲明了靜態(tài)共享庫,也會將它去除。
??如果被替換的包是系統(tǒng)包,它接著會檢查當前舊包使用的系統(tǒng)預(yù)安裝的還是后續(xù)已經(jīng)升級過的包。它是通過disableSystemPackageLPw(oldPackage)來判斷的,如果它為true,代表當前舊包使用的系統(tǒng)預(yù)安裝的包,是不能刪除的。所以這里將刪除信息的參數(shù)args = null。如果它為false,則代表后續(xù)已經(jīng)升級過新的安裝包,后面需要將它刪除。所以創(chuàng)建新的刪除參數(shù)(包括舊包的安裝路徑和主、副ABI),并將它設(shè)置為res.removedInfo.args。
??如果被替換包不是系統(tǒng)包,它會執(zhí)行executeDeletePackageLIF方法,刪除應(yīng)用包。刪除應(yīng)用包見下面分析。
??刪除包之后,繼續(xù)往下執(zhí)行,如果舊包在外部空間,它會發(fā)送一個資源改變的廣播,通知用戶們。它還會更新PackageSetting對象的舊包的安裝路徑。
??executeDeletePackageLIF方法上面都是用來清除應(yīng)用的,接下來就是要安裝新的應(yīng)用了。
??它是首先調(diào)用commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers) 提交修改系統(tǒng)中對應(yīng)的狀態(tài),然后調(diào)用updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res)用來更新PackageSetting對象的狀態(tài)。
??接下來,res.newUsers則是新應(yīng)用提交并更新PackageSetting對象之后,得到的installed狀態(tài)為true的用戶id數(shù)組。還會將PackageSetting對象的updateAvailable設(shè)置為false。
??目前安裝成功的話,它會調(diào)用updateSequenceNumberLP()來更新對應(yīng)包的更新序號,這個更新序列號就是每次更新會加1。調(diào)用updateInstantAppInstallerLocked(packageName)來更新用來安裝instant應(yīng)用的Activity。
??最后調(diào)用ApplicationPackageManager.invalidateGetPackagesForUidCache()是使CACHE_KEY_PACKAGES_FOR_UID_PROPERTY屬性緩存無效。這個屬性值存儲的是對應(yīng)用戶的安裝應(yīng)用包名。
??下面先看看刪除應(yīng)用包,然后再看提交修改包應(yīng)用的系統(tǒng)的狀態(tài)、更新PackageSetting對象的狀態(tài)。
刪除應(yīng)用包
??刪除應(yīng)用包是由executeDeletePackageLIF方法實現(xiàn)的,看一下它的代碼:
/** Deletes a package. Only throws when install of a disabled package fails. */private void executeDeletePackageLIF(DeletePackageAction action,String packageName, boolean deleteCodeAndResources,@NonNull int[] allUserHandles, boolean writeSettings,ParsedPackage replacingPackage) throws SystemDeleteException {final PackageSetting ps = action.deletingPs;final PackageRemovedInfo outInfo = action.outInfo;final UserHandle user = action.user;final int flags = action.flags;final boolean systemApp = isSystemApp(ps);// We need to get the permission state before package state is (potentially) destroyed.final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray();for (int userId : allUserHandles) {hadSuspendAppsPermission.put(userId, checkPermission(Manifest.permission.SUSPEND_APPS,packageName, userId) == PERMISSION_GRANTED);}final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)&& userId != UserHandle.USER_ALL) {// The caller is asking that the package only be deleted for a single// user. To do this, we just mark its uninstalled state and delete// its data. If this is a system app, we only allow this to happen if// they have set the special DELETE_SYSTEM_APP which requests different// semantics than normal for uninstalling system apps.final boolean clearPackageStateAndReturn;synchronized (mLock) {markPackageUninstalledForUserLPw(ps, user);if (!systemApp) {// Do not uninstall the APK if an app should be cachedboolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);if (ps.isAnyInstalled(mUserManager.getUserIds()) || keepUninstalledPackage) {// Other users still have this package installed, so all// we need to do is clear this user's data and save that// it is uninstalled.if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");clearPackageStateAndReturn = true;} else {// We need to set it back to 'installed' so the uninstall// broadcasts will be sent correctly.if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");ps.setInstalled(true, userId);mSettings.writeKernelMappingLPr(ps);clearPackageStateAndReturn = false;}} else {// This is a system app, so we assume that the// other users still have this package installed, so all// we need to do is clear this user's data and save that// it is uninstalled.if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");clearPackageStateAndReturn = true;}}if (clearPackageStateAndReturn) {clearPackageStateForUserLIF(ps, userId, outInfo, flags);synchronized (mLock) {scheduleWritePackageRestrictionsLocked(user);}return;}}// TODO(b/109941548): break reasons for ret = false out into mayDelete methodif (systemApp) {if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);// When an updated system application is deleted we delete the existing resources// as well and fall back to existing code in system partitiondeleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);} else {if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,outInfo, writeSettings);}// If the package removed had SUSPEND_APPS, unset any restrictions that might have been in// place for all affected users.int[] affectedUserIds = (outInfo != null) ? outInfo.removedUsers : null;if (affectedUserIds == null) {affectedUserIds = resolveUserIds(userId);}for (final int affectedUserId : affectedUserIds) {if (hadSuspendAppsPermission.get(affectedUserId)) {unsuspendForSuspendingPackage(packageName, affectedUserId);removeAllDistractingPackageRestrictions(affectedUserId);}}// Take a note whether we deleted the package for all usersif (outInfo != null) {outInfo.removedForAllUsers = mPackages.get(ps.name) == null;}}
??DeletePackageAction類型對象action是關(guān)于要刪除包行為的,action.deletingPs就是要刪除的PackageSetting對象,action.outInfo是刪除的信息,action.user是用戶,action.flags是刪除標識,變量systemApp代表是系統(tǒng)APP。
??hadSuspendAppsPermission里面存儲每個用戶對應(yīng)的包名packageName的應(yīng)用是否已經(jīng)授權(quán)過SUSPEND_APPS權(quán)限。
??action.user是需要刪除的應(yīng)用的用戶,在我們的例子中,這里是null(可以參考 Android 應(yīng)用安裝-協(xié)調(diào)階段),也就是代表所有用戶。
??接下來這段代碼是是處理某個用戶刪除的情況(userId != UserHandle.USER_ALL),還要滿足不是系統(tǒng)APP或者設(shè)置了刪除系統(tǒng)app標識PackageManager.DELETE_SYSTEM_APP。
??變量clearPackageStateAndReturn代表清除包的對應(yīng)的這個單獨用戶的數(shù)據(jù)之后,就返回,不繼續(xù)向下執(zhí)行。
??markPackageUninstalledForUserLPw(ps, user)用來標記用戶的卸載狀態(tài),PackageSetting對象會維護每個用戶的用戶狀態(tài),這個用戶狀態(tài)是用PackageUserState對象來表示的。這里主要將PackageUserState對象的installed狀態(tài)設(shè)置為false。
??接著對非系統(tǒng)APP進行處理。
??變量keepUninstalledPackage代表保持卸載包。它是由shouldKeepUninstalledPackageLPr(packageName)來決定的,而該方法是由成員變量mKeepUninstalledPackages來判斷的,如果包名在它里面,即為true。像這種情況,會將變量clearPackageStateAndReturn = true。還有一種情況,其他用戶還有這個包的installed狀態(tài)(即ps.isAnyInstalled(mUserManager.getUserIds())為true,上面通過markPackageUninstalledForUserLPw(ps, user)將user的installed設(shè)置為false),也會clearPackageStateAndReturn = true,代表需要將該用戶的數(shù)據(jù)清除就返回,其他用戶的數(shù)據(jù)是不能清除的。如果上面兩個情況不滿足,調(diào)用ps.setInstalled(true, userId)將該用戶對應(yīng)的installed設(shè)置為true,因為剛才通過markPackageUninstalledForUserLPw(ps, user)將用戶對應(yīng)的installed設(shè)置為false,并且也判斷過ps.isAnyInstalled(mUserManager.getUserIds())了,所以在這里是將它的值還原。mSettings.writeKernelMappingLPr(ps)則是處理Settings對象中維持的KernelPackageState對象,它包含著應(yīng)用的appId和installed狀態(tài)已經(jīng)是false的用戶(維持在PackageSetting對象中)。最后將clearPackageStateAndReturn = false。
??接著對系統(tǒng)APP進行處理。直接是將clearPackageStateAndReturn = true,它是假定其他用戶有這個系統(tǒng)應(yīng)用的installed狀態(tài),所以只清理該單獨用戶的。
??上面處理之后,變量clearPackageStateAndReturn為true,代表只需要清理這個userId這個單獨用戶的數(shù)據(jù)就行,它是由clearPackageStateForUserLIF()實現(xiàn),見下面。
??之后調(diào)用scheduleWritePackageRestrictionsLocked(user),它首先執(zhí)行invalidatePackageInfoCache(),讓一些緩存無效(包信息的緩存,包含PackageManagerService對象的Computer緩存),接著向PackageManagerService對象的后臺ServiceThread發(fā)送一個延遲(10s)消息WRITE_PACKAGE_RESTRICTIONS,而在ServiceThread中處理該消息時,會調(diào)用Settings對象的writePackageRestrictionsLPr(userId)方法來處理,它和"/data/system/users/" + userId + “/package-restrictions.xml” 及 “/data/system/users/” + userId + “/package-restrictions-backup.xml"兩個文件有關(guān),后面這個文件是前一個文件的備份。writePackageRestrictionsLPr(userId)方法主要是將用戶對應(yīng)的各個應(yīng)用包狀態(tài)、較好的Activity信息、持久較好的Activity信息、intent配置信息、默認的瀏覽器包名等相關(guān)信息寫入”/package-restrictions.xml"文件。這些處理完畢,就直接return,不再繼續(xù)向下執(zhí)行。
??再接下來如果clearPackageStateAndReturn為false,或者參數(shù)user == null的情況下,它會繼續(xù)向下執(zhí)行代碼,還是分系統(tǒng)APP還是非系統(tǒng)APP的情況。
??系統(tǒng)APP,會執(zhí)行deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);非系統(tǒng)APP會執(zhí)行deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles, outInfo, writeSettings)。這倆方法的區(qū)別是,刪除系統(tǒng)應(yīng)用包時,它會繼續(xù)使用系統(tǒng)分區(qū)中的安裝包,所以在它刪除了更新包之后,會執(zhí)行安裝系統(tǒng)分區(qū)中的安裝包。deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles, outInfo, writeSettings)的實現(xiàn)見下面。
??接下來executeDeletePackageLIF方法會繼續(xù)檢查被刪除應(yīng)用如果被授予Manifest.permission.SUSPEND_APPS權(quán)限,這里會去除它對別的應(yīng)用暫停的影響。
??這樣executeDeletePackageLIF方法就看完了。
??下面看下clearPackageStateForUserLIF(ps, userId, outInfo, flags),它是用來清理userId的數(shù)據(jù)??聪聦崿F(xiàn)的代碼:
刪除包對應(yīng)用戶的數(shù)據(jù)
private void clearPackageStateForUserLIF(PackageSetting ps, int userId,PackageRemovedInfo outInfo, int flags) {final AndroidPackage pkg;synchronized (mLock) {pkg = mPackages.get(ps.name);}destroyAppProfilesLIF(pkg);final SharedUserSetting sus = ps.getSharedUser();List<AndroidPackage> sharedUserPkgs = sus != null ? sus.getPackages() : null;if (sharedUserPkgs == null) {sharedUserPkgs = Collections.emptyList();}final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds(): new int[] {userId};for (int nextUserId : userIds) {if (DEBUG_REMOVE) {Slog.d(TAG, "Updating package:" + ps.name + " install state for user:"+ nextUserId);}if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {destroyAppDataLIF(pkg, nextUserId,FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);}removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);clearPackagePreferredActivities(ps.name, nextUserId);mDomainVerificationManager.clearPackageForUser(ps.name, nextUserId);}mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs, userId);if (outInfo != null) {if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {outInfo.dataRemoved = true;}outInfo.removedPackage = ps.name;outInfo.installerPackageName = ps.installSource.installerPackageName;outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;outInfo.removedAppId = ps.appId;outInfo.removedUsers = userIds;outInfo.broadcastUsers = userIds;}}
??在這里得到mPackages中對應(yīng)的包名的安裝包信息。
??接著調(diào)用destroyAppProfilesLIF(pkg),將包對應(yīng)的配置文件刪除。因為它要與installd 進程通信(實現(xiàn)在InstalldNativeService.cpp中的destroyAppProfiles(const std::string& packageName)中),跳轉(zhuǎn)代碼太多,直接說實現(xiàn)的內(nèi)容了,對"/data/user/“目錄下面的用戶遍歷userid,刪除 “/data/misc/profiles/cur/” + userid + “/” + package_name 目錄及其里面的文件,如果沒在”/data/user/“目錄下面找到userid,就只找尋userid為0的用戶,也就是刪除”/data/misc/profiles/cur/0/" + package_name 目錄及其中的文件,接著刪除"/data/misc/profiles/ref/" + package_name 目錄及其里面的文件。
??接著向下如果userId == UserHandle.USER_ALL(即-1),代表所有用戶,所以取出來所有用戶id;如果是單個用戶id,則將單個用戶放在數(shù)組中,賦值給數(shù)組userIds。
??遍歷用戶數(shù)組userIds開始>>>>>>
??遍歷用戶數(shù)組userIds,如果標識沒有PackageManager.DELETE_KEEP_DATA,會調(diào)用destroyAppDataLIF方法,它是清除所有的APP數(shù)據(jù)。它根據(jù)標識做了以下三件事:
??1、如果設(shè)置了FLAG_STORAGE_CE標識,它會清除用戶的包數(shù)據(jù)。用戶的數(shù)據(jù)存放位置和存儲卷UUID、包名、用戶ID有關(guān)的。如果存儲卷UUID為null,則代表內(nèi)部存儲,那它的根目錄為"/data",如果不為null,根目錄為"/mnt/expand/" + volume_uuid。如果特定用戶userid,則路徑為 根目錄 + “/user/” + userid + “/” + 包名。還有一種常見情況為內(nèi)部存儲,用戶userid為0,如果 “/data/data"存在,并且是目錄,則路徑為”/data/data/" + 包名。所以這里會將這個用戶目錄包括其中的數(shù)據(jù)都清除掉。
??2、如果設(shè)置了FLAG_STORAGE_DE標識,它會清除用戶的設(shè)備加密的數(shù)據(jù)。它的路徑文件路徑和上面有些像,不過它的路徑中的"/user/“換成了”/user_de/“。即為根目錄 + “/user_de/” + userid + “/” + 包名。還以內(nèi)部存儲,用戶userid為例,則它的路徑為”/data/user_de/0/" + 包名。這里會將該目錄及里面文件都刪除掉。如果標識沒有設(shè)置FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES,它還會刪除應(yīng)用和用戶對應(yīng)的配置文件,這和前面destroyAppProfilesLIF(pkg)不一樣的是,它是刪除某個用戶id的。
??3、如果設(shè)置了FLAG_STORAGE_EXTERNAL標識,它需要清除外部存儲上該應(yīng)用的存儲數(shù)據(jù)。外部存儲空間和用戶相關(guān)的路徑目錄有哪些呢,它也是和用戶id和包名相關(guān)。外部空間根目錄是從"/proc/mounts"中讀取出來的,外部空間根目錄 + “/” + userId即是和用戶相關(guān)的目錄,暫稱外部空間用戶根目錄extUserDir。具體刪除的路徑有以下幾個:extUserDir + “/Android/data/” + 包名、extUserDir + “/Android/media/” + 包名、extUserDir + “/Android/obb/” + 包名。
??繼續(xù)看clearPackageStateForUserLIF方法中的執(zhí)行方法,調(diào)用removeKeystoreDataIfNeeded方法,它是在APP卸載時,通知Keystore 2.0,并且對應(yīng)的命名空間被刪除。
??接著是調(diào)用clearPackagePreferredActivities(ps.name, nextUserId),清除這個nextUserId用戶包名等于ps.name的較好的Activity。它們是維護在Settings對象中的成員變量mPreferredActivities中。所以這塊就是把符合要求的對應(yīng)用戶的Activity從它里面去除。如果確實有需要刪除的對應(yīng)用戶的Activity,它接下來會調(diào)用updateDefaultHomeNotLocked(changedUsers)來更新對應(yīng)用戶默認的Home,默認的Home的包名是PackageManagerService對象的成員變量DefaultAppProvider mDefaultAppProvider維持的,如果mDefaultAppProvider維持的Home包名和查詢得到的nextUserId的當前較好的Activity不同,會更新Home包名,并且發(fā)送nextUserId用戶Intent.ACTION_PREFERRED_ACTIVITY_CHANGED廣播。
??如果確實有需要刪除的對應(yīng)用戶的Activity,clearPackagePreferredActivities(ps.name, nextUserId)還會執(zhí)行scheduleWritePackageRestrictionsLocked(userId)方法,它首先執(zhí)行invalidatePackageInfoCache(),讓一些緩存無效(包信息的緩存,包含PackageManagerService對象的Computer緩存)。接著向PackageManagerService對象的后臺ServiceThread發(fā)送一個延遲(10s)消息WRITE_PACKAGE_RESTRICTIONS,而在ServiceThread中處理該消息時,會調(diào)用Settings對象的writePackageRestrictionsLPr(userId)方法來處理,它和"/data/system/users/" + userId + “/package-restrictions.xml” 及 “/data/system/users/” + userId + “/package-restrictions-backup.xml"兩個文件有關(guān),后面這個文件是前一個文件的備份。writePackageRestrictionsLPr(userId)方法主要是將用戶對應(yīng)的各個應(yīng)用包狀態(tài)、較好的Activity信息、持久較好的Activity信息、intent配置信息、默認的瀏覽器包名等相關(guān)信息寫入”/package-restrictions.xml"文件。
??回到clearPackageStateForUserLIF方法中,還是在循環(huán)遍歷中,它接著執(zhí)行mDomainVerificationManager.clearPackageForUser(ps.name, nextUserId)。mDomainVerificationManager在這里是DomainVerificationService對象,在這里它是用來清除對應(yīng)應(yīng)用和對應(yīng)用戶的域名驗證狀態(tài)。
??遍歷用戶數(shù)組userIds結(jié)束<<<<<<
??上面是遍歷用戶的循環(huán)看完了,下面是調(diào)用mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs, userId)。mPermissionManager實際是PermissionManagerServiceInternalImpl對象,這塊是包要卸載了,需要對相應(yīng)權(quán)限進行處理。
??下面outInfo對象則是對清理狀況的一種描述信息。包括刪除的包名,刪除包名的安裝應(yīng)用,數(shù)據(jù)是否刪除(是否調(diào)用了destroyAppDataLIF方法)、是否是靜態(tài)庫、去除了哪個用戶的包信息。
刪除安裝包
??它是由deleteInstalledPackageLIF()實現(xiàn)的,看下它實現(xiàn)的代碼:
private void deleteInstalledPackageLIF(PackageSetting ps,boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,PackageRemovedInfo outInfo, boolean writeSettings) {synchronized (mLock) {if (outInfo != null) {outInfo.uid = ps.appId;outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,allUserHandles, mSettings.getPackagesLocked());}}// Delete package data from internal structures and also remove data if flag is setremovePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);// Delete application code and resources only for parent packagesif (deleteCodeAndResources && (outInfo != null)) {outInfo.args = createInstallArgsForExisting(ps.getPathString(), getAppDexInstructionSets(ps.primaryCpuAbiString, ps.secondaryCpuAbiString));if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);}}
??deleteInstalledPackageLIF()方法會給PackageRemovedInfo對象outInfo中的相關(guān)字段賦值,主要就是調(diào)用removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings)方法。如果參數(shù)deleteCodeAndResources為true,代表需要刪除代碼和資源包。所以構(gòu)造outInfo.args對象,它是FileInstallArgs對象,包含安裝包路徑和指令集。
??removePackageDataLIF()會做如下工作,會給PackageRemovedInfo對象outInfo中的相關(guān)字段賦值,包括removedUsers。接著會調(diào)用removePackageLI()方法,它會去除包相關(guān)的數(shù)據(jù)。如果參數(shù)標識flags沒有PackageManager.DELETE_KEEP_DATA,它還會調(diào)用destroyAppDataLIF(),見上面、destroyAppProfilesLIF(),見上面來刪除對應(yīng)應(yīng)用包的相關(guān)文件。
??如果參數(shù)標識flags沒有PackageManager.DELETE_KEEP_DATA,它還會用來清除對應(yīng)應(yīng)用的域名驗證狀態(tài),應(yīng)用的keySet,它還會調(diào)用mSettings.removePackageLPw(packageName),清除成員變量mSettings中的PackageSetting對象并將與其相關(guān)的內(nèi)容一并清除。如果不是系統(tǒng)包,它也會調(diào)用mPermissionManager.onPackageUninstalled(packageName, deletedPs.appId, deletedPs.pkg, sharedUserPkgs, UserHandle.USER_ALL)把它的權(quán)限狀態(tài)給去除。接著會調(diào)用clearPackagePreferredActivitiesLPw(deletedPs.name, changedUsers, UserHandle.USER_ALL),清除這個nextUserId用戶包名等于ps.name的較好的Activity。它們是維護在Settings對象中的成員變量mPreferredActivities中。所以這塊就是把符合要求的Activity從它里面去除。如果在清除了用戶的較好的Activity時,那接著就需要更新這個用戶的默認home。然后發(fā)送較好Activity發(fā)生變化的廣播(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED)。
??removePackageDataLIF()還會根據(jù)boolean型參數(shù)writeSettings,是否保存Settings類型對象中的狀態(tài)。還會從密鑰庫刪除對應(yīng)應(yīng)用的密鑰。
提交修改包應(yīng)用的系統(tǒng)的狀態(tài)
??commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers)的代碼如下:
/*** Commits the package scan and modifies system state.* <p><em>WARNING:</em> The method may throw an excpetion in the middle* of committing the package, leaving the system in an inconsistent state.* This needs to be fixed so, once we get to this point, no errors are* possible and the system is not left in an inconsistent state.*/@GuardedBy({"mLock", "mInstallLock"})private AndroidPackage commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {final ScanResult result = reconciledPkg.scanResult;final ScanRequest request = result.request;// TODO(b/135203078): Move this even further awayParsedPackage parsedPackage = request.parsedPackage;if ("android".equals(parsedPackage.getPackageName())) {// TODO(b/135203078): Move this to initial parseparsedPackage.setVersionCode(mSdkVersion).setVersionCodeMajor(0);}final AndroidPackage oldPkg = request.oldPkg;final @ParseFlags int parseFlags = request.parseFlags;final @ScanFlags int scanFlags = request.scanFlags;final PackageSetting oldPkgSetting = request.oldPkgSetting;final PackageSetting originalPkgSetting = request.originalPkgSetting;final UserHandle user = request.user;final String realPkgName = request.realPkgName;final List<String> changedAbiCodePath = result.changedAbiCodePath;final PackageSetting pkgSetting;if (request.pkgSetting != null && request.pkgSetting.sharedUser != null&& request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {// shared user changed, remove from old shared userrequest.pkgSetting.sharedUser.removePackage(request.pkgSetting);}if (result.existingSettingCopied) {pkgSetting = request.pkgSetting;pkgSetting.updateFrom(result.pkgSetting);} else {pkgSetting = result.pkgSetting;if (originalPkgSetting != null) {mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(),originalPkgSetting.name);mTransferredPackages.add(originalPkgSetting.name);} else {mSettings.removeRenamedPackageLPw(parsedPackage.getPackageName());}}if (pkgSetting.sharedUser != null) {pkgSetting.sharedUser.addPackage(pkgSetting);}if (reconciledPkg.installArgs != null && reconciledPkg.installArgs.forceQueryableOverride) {pkgSetting.forceQueryableOverride = true;}// If this is part of a standard install, set the initiating package name, else rely on// previous device state.if (reconciledPkg.installArgs != null) {InstallSource installSource = reconciledPkg.installArgs.installSource;if (installSource.initiatingPackageName != null) {final PackageSetting ips = mSettings.getPackageLPr(installSource.initiatingPackageName);if (ips != null) {installSource = installSource.setInitiatingPackageSignatures(ips.signatures);}}pkgSetting.setInstallSource(installSource);}// TODO(toddke): Consider a method specifically for modifying the Package object// post scan; or, moving this stuff out of the Package object since it has nothing// to do with the package on disk.// We need to have this here because addUserToSettingLPw() is sometimes responsible// for creating the application ID. If we did this earlier, we would be saving the// correct ID.parsedPackage.setUid(pkgSetting.appId);final AndroidPackage pkg = parsedPackage.hideAsFinal();mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);if (realPkgName != null) {mTransferredPackages.add(pkg.getPackageName());}if (reconciledPkg.collectedSharedLibraryInfos != null) {executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null,reconciledPkg.collectedSharedLibraryInfos, allUsers);}final KeySetManagerService ksms = mSettings.getKeySetManagerService();if (reconciledPkg.removeAppKeySetData) {ksms.removeAppKeySetDataLPw(pkg.getPackageName());}if (reconciledPkg.sharedUserSignaturesChanged) {pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails;}pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {final String codePathString = changedAbiCodePath.get(i);try {mInstaller.rmdex(codePathString,getDexCodeInstructionSet(getPreferredInstructionSet()));} catch (InstallerException ignored) {}}}final int userId = user == null ? 0 : user.getIdentifier();// Modify state for the given package settingcommitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags,(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);if (pkgSetting.getInstantApp(userId)) {mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);}pkgSetting.setStatesOnCommit();return pkg;}
??所需要的數(shù)據(jù)都封裝在參數(shù)reconciledPkg對象中,ScanResult對象、ScanRequest對象都是前面文章 Android 安裝應(yīng)用-瀏覽階段 中生成的,現(xiàn)在通過reconciledPkg對象取出來。其中parsedPackage是解析出來的包對象,oldPkgSetting是包的舊設(shè)置信息對象。originalPkgSetting是原來的包設(shè)置對象,realPkgName是包的真名字,這倆變量是和改包名相關(guān)的,如果沒有改包名這倆變量為null,如果originalPkgSetting不為null代表是首次安裝更改包名的應(yīng)用。changedAbiCodePath是包共享應(yīng)用中改變了abi的應(yīng)用的路徑。
??接著如果包共享用戶發(fā)生了變化,需要從原來的共享應(yīng)用包中去除之前的應(yīng)用。
??如果result.existingSettingCopied為true,則result.pkgSetting是通過深copy request.pkgSetting創(chuàng)建的對象,并且它里面的值有些可能發(fā)生了變化,所以這里,通過updateFrom方法來更新它的值。如果result.existingSettingCopied為false,則result.pkgSetting是通過new新創(chuàng)建的對象,這里直接將result.pkgSetting賦值給變量pkgSetting。接著如果originalPkgSetting != null,代表包名進行了更改,所以這里通過mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(), originalPkgSetting.name)將現(xiàn)在的包名和之前的舊包名建立對應(yīng)關(guān)系(是通過mSettings的成員mRenamedPackages實現(xiàn)),還會將舊包名放入變量mTransferredPackages中,代表它的包名發(fā)生了變更。如果originalPkgSetting為null,代表沒有變更,所以這里將包名從mSettings的成員mRenamedPackages中去除。
??如果應(yīng)用是共享用戶,這里會將包設(shè)置對象添加到共享用戶中。
??如果安裝參數(shù)中forceQueryableOverride為true,這里會將包設(shè)置對象屬性forceQueryableOverride設(shè)置為true。
??接著設(shè)置包設(shè)置對象的安裝源信息。這里是處理了一下安裝者應(yīng)用的簽名信息。
??再接下來給解析包對象設(shè)置應(yīng)用UId。
??在這里會調(diào)用解析包對象parsedPackage的hideAsFinal()方法,這里parsedPackage實際是PackageImpl對象,
??接著調(diào)用mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting) 它是用來持久化應(yīng)用的一些狀態(tài)的,不過在這里,普通的應(yīng)用安裝應(yīng)該不會去更新,因為現(xiàn)在包已經(jīng)從mSettings中去除了,還沒有加入其中。
??接著如果realPkgName不為null,將包名加入mTransferredPackages中。前面的文章 Android 安裝應(yīng)用-瀏覽階段,如果realPkgName不為null,則pkg.getPackageName()為舊包名,這里將它加入mTransferredPackages中,代表它有新包名。
??如果reconciledPkg.collectedSharedLibraryInfos != null,代表應(yīng)用聲明了庫更新信息,所以這里執(zhí)行庫的更新。
??reconciledPkg.removeAppKeySetData為true,代表需要更新應(yīng)用的簽名key。所以這里先將它們刪除,后續(xù)再更新新的簽名key。
??reconciledPkg.sharedUserSignaturesChanged為true,代表共享用戶的簽名發(fā)生了變化,這里更新對應(yīng)的包設(shè)置對象的共享用戶簽名。
??還會更新包設(shè)置對象的簽名。
??changedAbiCodePath.size() > 0,代表共享用戶中有些用的ABI發(fā)生了變化,這里會將對應(yīng)的dex文件刪除。
??接著會根據(jù)變量user的值來設(shè)置局部變量userId的值,如果為null,將userId設(shè)置為0,也即System用戶。
??解下來就是調(diào)用commitPackageSettings()方法來修改對應(yīng)包的狀態(tài)了,詳細見下面。
??如果應(yīng)用是InstantApp,則會將應(yīng)用的安裝信息添加到mInstantAppRegistry中。
??最后調(diào)用包設(shè)置對象的setStatesOnCommit()方法,提交這個包的安裝狀態(tài)。最后將解析包對象返回。
修改對應(yīng)包的狀態(tài)
??看一下commitPackageSettings()方法的實現(xiàn)
/*** Adds a scanned package to the system. When this method is finished, the package will* be available for query, resolution, etc...*/private void commitPackageSettings(@NonNull AndroidPackage pkg, @Nullable AndroidPackage oldPkg,@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {final String pkgName = pkg.getPackageName();if (mCustomResolverComponentName != null &&mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {setUpCustomResolverActivity(pkg, pkgSetting);}if (pkg.getPackageName().equals("android")) {synchronized (mLock) {// Set up information for our fall-back user intent resolution activity.mPlatformPackage = pkg;// The instance stored in PackageManagerService is special cased to be non-user// specific, so initialize all the needed fields here.mAndroidApplication = pkg.toAppInfoWithoutState();mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);mAndroidApplication.privateFlags =PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);mAndroidApplication.initForUser(UserHandle.USER_SYSTEM);if (!mResolverReplaced) {mResolveActivity.applicationInfo = mAndroidApplication;mResolveActivity.name = ResolverActivity.class.getName();mResolveActivity.packageName = mAndroidApplication.packageName;mResolveActivity.processName = "system:ui";mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;mResolveActivity.exported = true;mResolveActivity.enabled = true;mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE| ActivityInfo.CONFIG_SCREEN_LAYOUT| ActivityInfo.CONFIG_ORIENTATION| ActivityInfo.CONFIG_KEYBOARD| ActivityInfo.CONFIG_KEYBOARD_HIDDEN;mResolveInfo.activityInfo = mResolveActivity;mResolveInfo.priority = 0;mResolveInfo.preferredOrder = 0;mResolveInfo.match = 0;mResolveComponentName = new ComponentName(mAndroidApplication.packageName, mResolveActivity.name);}onChanged();}}ArrayList<AndroidPackage> clientLibPkgs = null;// writersynchronized (mLock) {if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {commitSharedLibraryInfoLocked(info);}final Map<String, AndroidPackage> combinedSigningDetails =reconciledPkg.getCombinedAvailablePackages();try {// Shared libraries for the package need to be updated.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,combinedSigningDetails);} catch (PackageManagerException e) {Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);}// Update all applications that use this library. Skip when booting// since this will be done after all packages are scaned.if ((scanFlags & SCAN_BOOTING) == 0) {clientLibPkgs = updateAllSharedLibrariesLocked(pkg, pkgSetting,combinedSigningDetails);}}}if (reconciledPkg.installResult != null) {reconciledPkg.installResult.libraryConsumers = clientLibPkgs;}if ((scanFlags & SCAN_BOOTING) != 0) {// No apps can run during boot scan, so they don't need to be frozen} else if ((scanFlags & SCAN_DONT_KILL_APP) != 0) {// Caller asked to not kill app, so it's probably not frozen} else if ((scanFlags & SCAN_IGNORE_FROZEN) != 0) {// Caller asked us to ignore frozen check for some reason; they// probably didn't know the package name} else {// We're doing major surgery on this package, so it better be frozen// right now to keep it from launchingcheckPackageFrozen(pkgName);}// Also need to kill any apps that are dependent on the library.if (clientLibPkgs != null) {for (int i=0; i<clientLibPkgs.size(); i++) {AndroidPackage clientPkg = clientLibPkgs.get(i);killApplication(clientPkg.getPackageName(),clientPkg.getUid(), "update lib");}}// writerTrace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");synchronized (mLock) {// We don't expect installation to fail beyond this point// Add the new setting to mSettingsmSettings.insertPackageSettingLPw(pkgSetting, pkg);// Add the new setting to mPackagesmPackages.put(pkg.getPackageName(), pkg);if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {mApexManager.registerApkInApex(pkg);}// Add the package's KeySets to the global KeySetManagerServiceKeySetManagerService ksms = mSettings.getKeySetManagerService();ksms.addScannedPackageLPw(pkg);mComponentResolver.addAllComponents(pkg, chatty);final boolean isReplace =reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;mAppsFilter.addPackage(pkgSetting, isReplace);mPackageProperty.addAllProperties(pkg);if (oldPkgSetting == null || oldPkgSetting.getPkg() == null) {mDomainVerificationManager.addPackage(pkgSetting);} else {mDomainVerificationManager.migrateState(oldPkgSetting, pkgSetting);}int collectionSize = ArrayUtils.size(pkg.getInstrumentations());StringBuilder r = null;int i;for (i = 0; i < collectionSize; i++) {ParsedInstrumentation a = pkg.getInstrumentations().get(i);a.setPackageName(pkg.getPackageName());mInstrumentation.put(a.getComponentName(), a);if (chatty) {if (r == null) {r = new StringBuilder(256);} else {r.append(' ');}r.append(a.getName());}}if (r != null) {if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);}final List<String> protectedBroadcasts = pkg.getProtectedBroadcasts();if (!protectedBroadcasts.isEmpty()) {synchronized (mProtectedBroadcasts) {mProtectedBroadcasts.addAll(protectedBroadcasts);}}mPermissionManager.onPackageAdded(pkg, (scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg);}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}
??前面這兩段代碼主要是處理mResolveActivity、mResolveInfo成員變量的。可見平臺的包名應(yīng)用是"android",并且會將mPlatformPackage指向應(yīng)用包對象。
??我們主要看下面的代碼,它是處理共享庫的代碼。
??reconciledPkg.allowedSharedLibraryInfos是應(yīng)用聲明的庫。它不為空的情況下,遍歷它,調(diào)用commitSharedLibraryInfoLocked(info)是將庫信息加入成員mSharedLibraries中,如果是靜態(tài)庫,還會加入成員mStaticLibsByDeclaringPackage中。
??接著調(diào)用updateSharedLibrariesLocked(pkg, pkgSetting, null, null, combinedSigningDetails) 會將它使用的類庫添加到它聲明的庫中。
??接著如果不是系統(tǒng)啟動中的情況,它會調(diào)用updateAllSharedLibrariesLocked(pkg, pkgSetting, combinedSigningDetails)更新所有使用該庫的應(yīng)用。并且返回值clientLibPkgs為所有使用該類庫的應(yīng)用包。
??下面還會將clientLibPkgs賦值給reconciledPkg.installResult.libraryConsumers。
??接著在系統(tǒng)啟動中或scanFlags有SCAN_DONT_KILL_APP或SCAN_IGNORE_FROZEN標簽的情況下,不檢查應(yīng)用的凍結(jié)狀態(tài),其他情況,需要調(diào)用checkPackageFrozen(pkgName)來檢查。
??接下來,如果存在使用更新庫的應(yīng)用,需要將這些應(yīng)用殺掉。它調(diào)用的是killApplication(clientPkg.getPackageName(), clientPkg.getUid(), “update lib”)方法。
??接下來,就是調(diào)用mSettings.insertPackageSettingLPw(pkgSetting, pkg),將包設(shè)置對象pkgSetting加入mSettings中。它還會處理,如果pkgSetting中的簽名信息不在,需要從pkg.getSigningDetails()取得,賦值到pkgSetting中的簽名信息。最主要的是將pkgSetting對象添加到mSettings中的成員變量mPackages中,它是WatchedArrayMap<String, PackageSetting>類型,key是包名,value是PackageSetting對象。如果是共享用戶,在這里會將PackageSetting對象添加到共享SharedUserSetting對象中。
??調(diào)用mPackages.put(pkg.getPackageName(), pkg)將包解析對象加入mPackages中。
??下面就是將包的KeySet添加到KeySetManagerService對象中。它調(diào)用的是ksms.addScannedPackageLPw(pkg)方法。
??再下面就是調(diào)用mComponentResolver.addAllComponents(pkg, chatty)添加包應(yīng)用的組件信息,包含Activity、BroadCastReceiver、Service、Provider。
??mAppsFilter.addPackage(pkgSetting, isReplace)是用來處理APP之間可見性的。
??mPackageProperty.addAllProperties(pkg)添加包定義的所有屬性值。
??接下來是處理包名配置的域名驗證。它主要是處理配置的Action為Intent.ACTION_VIEW、Category為Intent.CATEGORY_BROWSABLE的Activity其中的域名驗證。
??下面是將包聲明的Instrumentation添加到成員mInstrumentation中。
??將包中的受保護的廣播添加到成員mProtectedBroadcasts中。
??最后調(diào)用mPermissionManager.onPackageAdded(pkg, (scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg),通知應(yīng)用權(quán)限的添加。
更新PackageSetting對象的狀態(tài)
??updateSettingsInternalLI()方法是用來更新PackageSetting對象的相關(guān)數(shù)據(jù)的,接下來看看updateSettingsInternalLI()方法:
private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,int[] allUsers, PackageInstalledInfo res) {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");final String pkgName = pkg.getPackageName();final int[] installedForUsers = res.origUsers;final int installReason = installArgs.installReason;InstallSource installSource = installArgs.installSource;final String installerPackageName = installSource.installerPackageName;if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());synchronized (mLock) {// For system-bundled packages, we assume that installing an upgraded version// of the package implies that the user actually wants to run that new code,// so we enable the package.final PackageSetting ps = mSettings.getPackageLPr(pkgName);final int userId = installArgs.user.getIdentifier();if (ps != null) {if (pkg.isSystem()) {if (DEBUG_INSTALL) {Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);}// Enable system package for requested usersif (res.origUsers != null) {for (int origUserId : res.origUsers) {if (userId == UserHandle.USER_ALL || userId == origUserId) {ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,origUserId, installerPackageName);}}}// Also convey the prior install/uninstall stateif (allUsers != null && installedForUsers != null) {for (int currentUserId : allUsers) {final boolean installed = ArrayUtils.contains(installedForUsers, currentUserId);if (DEBUG_INSTALL) {Slog.d(TAG, " user " + currentUserId + " => " + installed);}ps.setInstalled(installed, currentUserId);}// these install state changes will be persisted in the// upcoming call to mSettings.writeLPr().}if (allUsers != null) {for (int currentUserId : allUsers) {ps.resetOverrideComponentLabelIcon(currentUserId);}}}// Retrieve the overlays for shared libraries of the package.if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) {for (int currentUserId : UserManagerService.getInstance().getUserIds()) {if (!sharedLib.isDynamic()) {// TODO(146804378): Support overlaying static shared librariescontinue;}final PackageSetting libPs = mSettings.getPackageLPr(sharedLib.getPackageName());if (libPs == null) {continue;}ps.setOverlayPathsForLibrary(sharedLib.getName(),libPs.getOverlayPaths(currentUserId), currentUserId);}}}// It's implied that when a user requests installation, they want the app to be// installed and enabled. (This does not apply to USER_ALL, which here means only// install on users for which the app is already installed).if (userId != UserHandle.USER_ALL) {ps.setInstalled(true, userId);ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);}mSettings.addInstallerPackageNames(ps.installSource);// When replacing an existing package, preserve the original install reason for all// users that had the package installed before. Similarly for uninstall reasons.final Set<Integer> previousUserIds = new ArraySet<>();if (res.removedInfo != null && res.removedInfo.installReasons != null) {final int installReasonCount = res.removedInfo.installReasons.size();for (int i = 0; i < installReasonCount; i++) {final int previousUserId = res.removedInfo.installReasons.keyAt(i);final int previousInstallReason = res.removedInfo.installReasons.valueAt(i);ps.setInstallReason(previousInstallReason, previousUserId);previousUserIds.add(previousUserId);}}if (res.removedInfo != null && res.removedInfo.uninstallReasons != null) {for (int i = 0; i < res.removedInfo.uninstallReasons.size(); i++) {final int previousUserId = res.removedInfo.uninstallReasons.keyAt(i);final int previousReason = res.removedInfo.uninstallReasons.valueAt(i);ps.setUninstallReason(previousReason, previousUserId);}}// Set install reason for users that are having the package newly installed.final int[] allUsersList = mUserManager.getUserIds();if (userId == UserHandle.USER_ALL) {// TODO(b/152629990): It appears that the package doesn't actually get newly// installed in this case, so the installReason shouldn't get modified?for (int currentUserId : allUsersList) {if (!previousUserIds.contains(currentUserId)) {ps.setInstallReason(installReason, currentUserId);}}} else if (!previousUserIds.contains(userId)) {ps.setInstallReason(installReason, userId);}// TODO(b/169721400): generalize Incremental States and create a Callback object// that can be used for all the packages.final String codePath = ps.getPathString();if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) {final IncrementalStatesCallback incrementalStatesCallback =new IncrementalStatesCallback(ps.name,UserHandle.getUid(userId, ps.appId),getInstalledUsers(ps, userId));ps.setIncrementalStatesCallback(incrementalStatesCallback);mIncrementalManager.registerLoadingProgressCallback(codePath,new IncrementalProgressListener(ps.name));}// Ensure that the uninstall reason is UNKNOWN for users with the package installed.for (int currentUserId : allUsersList) {if (ps.getInstalled(currentUserId)) {ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);}}mSettings.writeKernelMappingLPr(ps);final PermissionManagerServiceInternal.PackageInstalledParams.BuilderpermissionParamsBuilder =new PermissionManagerServiceInternal.PackageInstalledParams.Builder();final boolean grantPermissions = (installArgs.installFlags& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;if (grantPermissions) {final List<String> grantedPermissions =installArgs.installGrantPermissions != null? Arrays.asList(installArgs.installGrantPermissions): pkg.getRequestedPermissions();permissionParamsBuilder.setGrantedPermissions(grantedPermissions);}final boolean allowlistAllRestrictedPermissions =(installArgs.installFlags& PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;final List<String> allowlistedRestrictedPermissions =allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions(): installArgs.whitelistedRestrictedPermissions;if (allowlistedRestrictedPermissions != null) {permissionParamsBuilder.setAllowlistedRestrictedPermissions(allowlistedRestrictedPermissions);}final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode;permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId);}res.name = pkgName;res.uid = pkg.getUid();res.pkg = pkg;res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);//to update install statusTrace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");writeSettingsLPrTEMP();Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}
??res.origUsers是在 Android 安裝應(yīng)用-準備階段 賦值的,它是PackageSetting對象中 installe狀態(tài)為true的用戶,這里賦值給installedForUsers變量。
??局部變量userId是安裝參數(shù)中的用戶id。
??從mSettings中取得PackageSetting對象ps。
??如果安裝包pkg是系統(tǒng)安裝包,會設(shè)定原來的installe狀態(tài)為true的用戶的enabled狀態(tài)為COMPONENT_ENABLED_STATE_DEFAULT。還會把原來的installe狀態(tài)為true的用戶的installe狀態(tài)繼續(xù)為true,其他的用戶設(shè)置為false。還會調(diào)用PackageSetting對象的resetOverrideComponentLabelIcon(currentUserId),重設(shè)組件的label和icon。
??如果ps.getPkgState().getUsesLibraryInfos()不為null,并且它的庫位動態(tài)的,則會調(diào)用ps.setOverlayPathsForLibrary(sharedLib.getName(), libPs.getOverlayPaths(currentUserId), currentUserId)將動態(tài)庫的遮罩路徑設(shè)置到它里面
??如果安裝用戶是一個固定用戶,不是指所有用戶,則將它的installe狀態(tài)為true,enabled狀態(tài)為COMPONENT_ENABLED_STATE_DEFAULT。
??ps.installSource是和安裝源相關(guān)的對象,這里調(diào)用mSettings.addInstallerPackageNames(ps.installSource)將安裝者包名添加到mSettings中。
??接著就是處理用戶的安裝原因、卸載原因??梢钥吹?#xff0c;它先恢復(fù)之前的安裝原因、卸載原因。對于那些installe狀態(tài)為true的用戶,則設(shè)置它的卸載原因為UNINSTALL_REASON_UNKNOWN。
??下面是處理權(quán)限相關(guān)的。后面通過mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId)通知應(yīng)用包安裝了。
??最后設(shè)置res的name、uid、解析包對象。ReturnCode是安裝結(jié)果。PackageSetting對象更新了之后,調(diào)用writeSettingsLPrTEMP()來持久化相應(yīng)的狀態(tài)。
總結(jié)
??在安裝過程中有兩個類AndroidPackage和PackageSetting,AndroidPackage類對象實際是PackageImpl對象,它是通過解析應(yīng)用安裝包得到的,包含安裝包的所有配置(對應(yīng)Manifest配置文件中的內(nèi)容)。PackageSetting對象則是包數(shù)據(jù)設(shè)置對象,主要是后續(xù)設(shè)置的一些狀態(tài),像應(yīng)用對每個用戶的狀態(tài)(例安裝、停止狀態(tài)),主要、次要CPU ABI,另外PackageSetting對象的成員pkg是指向PackageImpl對象的。
??PackageManagerService對象中成員mPackages是WatchedArrayMap<String, AndroidPackage>,它的key是包名,value則是AndroidPackage對象,安裝成功之后,PackageImpl對象是要添加到mPackages中的。
??PackageManagerService對象中成員mSettings是Settings類。Settings類有成員變量mPackages,它是WatchedArrayMap<String, PackageSetting>,它的key是包名,value則是PackageSetting對象,安裝成功之后,PackageSetting對象是要添加到Settings類的成員變量mPackages中的。
??這兩個類對象的處理,可以從文章中找到。
??當然安裝中還會將各大組件添加到系統(tǒng)中,這個和PackageManagerService對象中成員mComponentResolver相關(guān),后續(xù)查找組件,也會通過該成員變量。
??其實挺復(fù)雜的是權(quán)限的處理,這個等待后面再整理,該篇文章也是疏通了流程,精細的地方還待仔細琢磨。