PKMS中卸载应用是通过deletePackage函数来执行,这个函数主要是调用了一些Observer回调,然后调用了deletePackageX函数。
- public void deletePackage(final String packageName,
- final IPackageDeleteObserver2 observer, final int userId, final int flags) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.DELETE_PACKAGES, null);
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(observer);
- final int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "deletePackage for user " + userId);
- }
- if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
- try {
- observer.onPackageDeleted(packageName,//回调
- PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
- } catch (RemoteException re) {
- }
- return;
- }
- boolean uninstallBlocked = false;
- if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {
- int[] users = sUserManager.getUserIds();
- for (int i = 0; i < users.length; ++i) {
- if (getBlockUninstallForUser(packageName, users[i])) {
- uninstallBlocked = true;
- break;
- }
- }
- } else {
- uninstallBlocked = getBlockUninstallForUser(packageName, userId);
- }
- if (uninstallBlocked) {
- try {
- observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,
- null);
- } catch (RemoteException re) {
- }
- return;
- }
- if (DEBUG_REMOVE) {
- Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
- }
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {//异步调用deletePackageX函数
- public void run() {
- mHandler.removeCallbacks(this);
- final int returnCode = deletePackageX(packageName, userId, flags);
- if (observer != null) {
- try {
- observer.onPackageDeleted(packageName, returnCode, null);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- } //end catch
- } //end if
- } //end run
- });
- }
我们来看下deletePackageX函数,主要是调用deletePackageLI函数继续执行,关键当返回的info不为空就调用info.args.doPostDeleteLI(true)删除应用。
- private int deletePackageX(String packageName, int userId, int flags) {
- ......
- synchronized (mInstallLock) {
- if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
- res = deletePackageLI(packageName, removeForUser,
- true, allUsers, perUserInstalled,
- flags | REMOVE_CHATTY, info, true);
- systemUpdate = info.isRemovedPackageSystemUpdate;
- if (res && !systemUpdate && mPackages.get(packageName) == null) {
- removedForAllUsers = true;
- }
- if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
- + " removedForAllUsers=" + removedForAllUsers);
- }
- ......
- // Force a gc here.
- Runtime.getRuntime().gc();
- // Delete the resources here after sending the broadcast to let
- // other processes clean up before deleting resources.
- if (info.args != null) {
- synchronized (mInstallLock) {
- info.args.doPostDeleteLI(true);//删除资源、apk等
- }
- }
- return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
- }
我们来看deletePackageLI函数,如果只有data,直接调用removePackageDataLI函数。如果是系统应用调用deleteSystemPackageLI,不是调用deleteInstalledPackageLI函数。
- private boolean deletePackageLI(String packageName, UserHandle user,
- boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo,
- boolean writeSettings) {
- ......
- if (dataOnly) {
- // Delete application data first
- if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only");
- removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
- return true;
- }
- boolean ret = false;
- if (isSystemApp(ps)) {
- 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 partition
- ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
- flags, outInfo, writeSettings);
- } else {
- if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
- // Kill application pre-emptively especially for apps on sd.
- killApplication(packageName, ps.appId, "uninstall pkg");
- ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
- allUserHandles, perUserInstalled,
- outInfo, writeSettings);
- }
- return ret;
- }
卸载系统应用
为什么会有卸载系统应用呢,当我们调用scanPackageLI扫描目录时有时候失败,也需要调用deletePackageLI来删除apk,这个时候就会有系统应用了。
- private boolean deleteSystemPackageLI(PackageSetting newPs,
- int[] allUserHandles, boolean[] perUserInstalled,
- int flags, PackageRemovedInfo outInfo, boolean writeSettings) {
- final boolean applyUserRestrictions
- = (allUserHandles != null) && (perUserInstalled != null);
- PackageSetting disabledPs = null;
- // Confirm if the system package has been updated
- // An updated system app can be deleted. This will also have to restore
- // the system pkg from system partition
- // reader
- synchronized (mPackages) {
- disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);
- }
- if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + newPs
- + " disabledPs=" + disabledPs);
- if (disabledPs == null) {
- Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);
- return false;
- } else if (DEBUG_REMOVE) {
- Slog.d(TAG, "Deleting system pkg from data partition");
- }
- // Delete the updated package
- outInfo.isRemovedPackageSystemUpdate = true;
- if (disabledPs.versionCode < newPs.versionCode) {
- // Delete data for downgrades
- flags &= ~PackageManager.DELETE_KEEP_DATA;//是否保留资源
- } else {
- // Preserve data by setting flag
- flags |= PackageManager.DELETE_KEEP_DATA;
- }
- boolean ret = deleteInstalledPackageLI(newPs, true, flags,//卸载apk
- allUserHandles, perUserInstalled, outInfo, writeSettings);
- if (!ret) {
- return false;
- }
- // writer
- synchronized (mPackages) {
- // Reinstate the old system package
- mSettings.enableSystemPackageLPw(newPs.name);
- // Remove any native libraries from the upgraded package.
- NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);
- }
- // Install the system package
- int parseFlags = PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM;
- if (locationIsPrivileged(disabledPs.codePath)) {
- parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
- }
- final PackageParser.Package newPkg;
- try {
- newPkg = scanPackageLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);//重新apk扫描目录
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
- return false;
- }
- // writer
- synchronized (mPackages) {
- PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
- // Propagate the permissions state as we do not want to drop on the floor
- // runtime permissions. The update permissions method below will take
- // care of removing obsolete permissions and grant install permissions.
- ps.getPermissionsState().copyFrom(newPs.getPermissionsState());
- updatePermissionsLPw(newPkg.packageName, newPkg,
- UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
- if (applyUserRestrictions) {
- if (DEBUG_REMOVE) {
- Slog.d(TAG, "Propagating install state across reinstall");
- }
- for (int i = 0; i < allUserHandles.length; i++) {
- if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + allUserHandles[i]
- + " => " + perUserInstalled[i]);
- }
- ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
- mSettings.writeRuntimePermissionsForUserLPr(allUserHandles[i], false);
- }
- // Regardless of writeSettings we need to ensure that this restriction
- // state propagation is persisted
- mSettings.writeAllUsersPackageRestrictionsLPr();
- }
- // can downgrade to reader here
- if (writeSettings) {
- mSettings.writeLPr();//更新packages.xml
- }
- }
- return true;
- }
卸载系统应用,最后也是调用deleteInstalledPackageLI来完成卸载的,我们来看下这个函数。
卸载普通应用
卸载普通应用就直接调用了deleteInstalledPackageLI函数
- private boolean deleteInstalledPackageLI(PackageSetting ps,
- boolean deleteCodeAndResources, int flags,
- int[] allUserHandles, boolean[] perUserInstalled,
- PackageRemovedInfo outInfo, boolean writeSettings) {
- if (outInfo != null) {
- outInfo.uid = ps.appId;
- }
- // Delete package data from internal structures and also remove data if flag is set
- removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings);
- // Delete application code and resources
- if (deleteCodeAndResources && (outInfo != null)) {
- outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
- }
- return true;
- }
我们先看removePackageDataLI函数,就是删除各种资源,但是我们没看到删除apk文件。
- private void removePackageDataLI(PackageSetting ps,
- int[] allUserHandles, boolean[] perUserInstalled,
- PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
- String packageName = ps.name;
- if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
- removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
- // Retrieve object to delete permissions for shared user later on
- final PackageSetting deletedPs;
- // reader
- synchronized (mPackages) {
- deletedPs = mSettings.mPackages.get(packageName);
- if (outInfo != null) {
- outInfo.removedPackage = packageName;
- outInfo.removedUsers = deletedPs != null
- ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
- : null;
- }
- }
- if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
- removeDataDirsLI(ps.volumeUuid, packageName);// 卸载data目录
- schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
- }
- // writer
- synchronized (mPackages) {
- if (deletedPs != null) {
- if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
- clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
- clearDefaultBrowserIfNeeded(packageName);
- if (outInfo != null) {
- mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
- outInfo.removedAppId = mSettings.removePackageLPw(packageName);
- }
- updatePermissionsLPw(deletedPs.name, null, 0);
- if (deletedPs.sharedUser != null) {
- // Remove permissions associated with package. Since runtime
- // permissions are per user we have to kill the removed package
- // or packages running under the shared user of the removed
- // package if revoking the permissions requested only by the removed
- // package is successful and this causes a change in gids.
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
- userId);
- if (userIdToKill == UserHandle.USER_ALL
- || userIdToKill >= UserHandle.USER_OWNER) {
- // If gids changed for this user, kill all affected packages.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // This has to happen with no lock held.
- killApplication(deletedPs.name, deletedPs.appId,
- KILL_APP_REASON_GIDS_CHANGED);
- }
- });
- break;
- }
- }
- }
- clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
- }
- // make sure to preserve per-user disabled state if this removal was just
- // a downgrade of a system app to the factory package
- if (allUserHandles != null && perUserInstalled != null) {
- if (DEBUG_REMOVE) {
- Slog.d(TAG, "Propagating install state across downgrade");
- }
- for (int i = 0; i < allUserHandles.length; i++) {
- if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + allUserHandles[i]
- + " => " + perUserInstalled[i]);
- }
- ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
- }
- }
- }
- // can downgrade to reader
- if (writeSettings) {
- // Save settings now
- mSettings.writeLPr();//更新packages.xml
- }
- }
- if (outInfo != null) {
- // A user ID was deleted here. Go through all users and remove it
- // from KeyStore.
- removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
- }
我们再来看deleteInstalledPackageLI函数,最后一段代码,
- if (deleteCodeAndResources && (outInfo != null)) {
- outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
- if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
- }
我们来看下这个函数,如果不是安装在sd卡上,最后新建一个FileInstallArgs对象。
- private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
- String resourcePath, String[] instructionSets) {
- final boolean isInAsec;
- if (installOnExternalAsec(installFlags)) {
- /* Apps on SD card are always in ASEC containers. */
- isInAsec = true;
- } else if (installForwardLocked(installFlags)
- && !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
- /*
- * Forward-locked apps are only in ASEC containers if they're the
- * new style
- */
- isInAsec = true;
- } else {
- isInAsec = false;
- }
- if (isInAsec) {
- return new AsecInstallArgs(codePath, instructionSets,
- installOnExternalAsec(installFlags), installForwardLocked(installFlags));
- } else {
- return new FileInstallArgs(codePath, resourcePath, instructionSets);
- }
- }
最后返回到deletePackageX函数,最后调用如下代码,直接到FileInstallArgs的doPostDeleteLI函数。
- if (info.args != null) {
- synchronized (mInstallLock) {
- info.args.doPostDeleteLI(true);
- }
- }
doPostDeleteLI函数如下:
- boolean doPostDeleteLI(boolean delete) {
- // XXX err, shouldn't we respect the delete flag?
- cleanUpResourcesLI();
- return true;
- }
cleanUpResourcesLI函数会删除资源和代码文件,dex文件
- void cleanUpResourcesLI() {
- // Try enumerating all code paths before deleting
- List<String> allCodePaths = Collections.EMPTY_LIST;
- if (codeFile != null && codeFile.exists()) {
- try {
- final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
- allCodePaths = pkg.getAllCodePaths();
- } catch (PackageParserException e) {
- // Ignored; we tried our best
- }
- }
- cleanUp();
- removeDexFiles(allCodePaths, instructionSets);
- }
- private boolean cleanUp() {
- if (codeFile == null || !codeFile.exists()) {
- return false;
- }
- if (codeFile.isDirectory()) {
- mInstaller.rmPackageDir(codeFile.getAbsolutePath());
- } else {
- codeFile.delete();
- }
- if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
- resourceFile.delete();
- }
- return true;
- }
时序图