Android 6.0 PKMS 卸载删除app

PKMS中卸载应用是通过deletePackage函数来执行,这个函数主要是调用了一些Observer回调,然后调用了deletePackageX函数。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. public void deletePackage(final String packageName,  
  2.         final IPackageDeleteObserver2 observer, final int userId, final int flags) {  
  3.     mContext.enforceCallingOrSelfPermission(  
  4.             android.Manifest.permission.DELETE_PACKAGES, null);  
  5.     Preconditions.checkNotNull(packageName);  
  6.     Preconditions.checkNotNull(observer);  
  7.     final int uid = Binder.getCallingUid();  
  8.     if (UserHandle.getUserId(uid) != userId) {  
  9.         mContext.enforceCallingPermission(  
  10.                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,  
  11.                 “deletePackage for user “ + userId);  
  12.     }  
  13.     if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {  
  14.         try {  
  15.             observer.onPackageDeleted(packageName,//回调  
  16.                     PackageManager.DELETE_FAILED_USER_RESTRICTED, null);  
  17.         } catch (RemoteException re) {  
  18.         }  
  19.         return;  
  20.     }  
  21.   
  22.     boolean uninstallBlocked = false;  
  23.     if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {  
  24.         int[] users = sUserManager.getUserIds();  
  25.         for (int i = 0; i < users.length; ++i) {  
  26.             if (getBlockUninstallForUser(packageName, users[i])) {  
  27.                 uninstallBlocked = true;  
  28.                 break;  
  29.             }  
  30.         }  
  31.     } else {  
  32.         uninstallBlocked = getBlockUninstallForUser(packageName, userId);  
  33.     }  
  34.     if (uninstallBlocked) {  
  35.         try {  
  36.             observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,  
  37.                     null);  
  38.         } catch (RemoteException re) {  
  39.         }  
  40.         return;  
  41.     }  
  42.   
  43.     if (DEBUG_REMOVE) {  
  44.         Slog.d(TAG, “deletePackageAsUser: pkg=” + packageName + ” user=” + userId);  
  45.     }  
  46.     // Queue up an async operation since the package deletion may take a little while.  
  47.     mHandler.post(new Runnable() {//异步调用deletePackageX函数  
  48.         public void run() {  
  49.             mHandler.removeCallbacks(this);  
  50.             final int returnCode = deletePackageX(packageName, userId, flags);  
  51.             if (observer != null) {  
  52.                 try {  
  53.                     observer.onPackageDeleted(packageName, returnCode, null);  
  54.                 } catch (RemoteException e) {  
  55.                     Log.i(TAG, “Observer no longer exists.”);  
  56.                 } //end catch  
  57.             } //end if  
  58.         } //end run  
  59.     });  
  60. }  

我们来看下deletePackageX函数,主要是调用deletePackageLI函数继续执行,关键当返回的info不为空就调用info.args.doPostDeleteLI(true)删除应用。


[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private int deletePackageX(String packageName, int userId, int flags) {  
  2.     ……  
  3.     synchronized (mInstallLock) {  
  4.         if (DEBUG_REMOVE) Slog.d(TAG, “deletePackageX: pkg=” + packageName + ” user=” + userId);  
  5.         res = deletePackageLI(packageName, removeForUser,  
  6.                 true, allUsers, perUserInstalled,  
  7.                 flags | REMOVE_CHATTY, info, true);  
  8.         systemUpdate = info.isRemovedPackageSystemUpdate;  
  9.         if (res && !systemUpdate && mPackages.get(packageName) == null) {  
  10.             removedForAllUsers = true;  
  11.         }  
  12.         if (DEBUG_REMOVE) Slog.d(TAG, “delete res: systemUpdate=” + systemUpdate  
  13.                 + ” removedForAllUsers=” + removedForAllUsers);  
  14.     }  
  15.   
  16.     ……  
  17.     // Force a gc here.  
  18.     Runtime.getRuntime().gc();  
  19.     // Delete the resources here after sending the broadcast to let  
  20.     // other processes clean up before deleting resources.  
  21.     if (info.args != null) {  
  22.         synchronized (mInstallLock) {  
  23.             info.args.doPostDeleteLI(true);//删除资源、apk等  
  24.         }  
  25.     }  
  26.   
  27.     return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;  
  28. }  

我们来看deletePackageLI函数,如果只有data,直接调用removePackageDataLI函数。如果是系统应用调用deleteSystemPackageLI,不是调用deleteInstalledPackageLI函数。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private boolean deletePackageLI(String packageName, UserHandle user,  
  2.         boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,  
  3.         int flags, PackageRemovedInfo outInfo,  
  4.         boolean writeSettings) {  
  5.     ……  
  6.   
  7.     if (dataOnly) {  
  8.         // Delete application data first  
  9.         if (DEBUG_REMOVE) Slog.d(TAG, “Removing package data only”);  
  10.         removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);  
  11.         return true;  
  12.     }  
  13.   
  14.     boolean ret = false;  
  15.     if (isSystemApp(ps)) {  
  16.         if (DEBUG_REMOVE) Slog.d(TAG, “Removing system package:” + ps.name);  
  17.         // When an updated system application is deleted we delete the existing resources as well and  
  18.         // fall back to existing code in system partition  
  19.         ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,  
  20.                 flags, outInfo, writeSettings);  
  21.     } else {  
  22.         if (DEBUG_REMOVE) Slog.d(TAG, “Removing non-system package:” + ps.name);  
  23.         // Kill application pre-emptively especially for apps on sd.  
  24.         killApplication(packageName, ps.appId, “uninstall pkg”);  
  25.         ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,  
  26.                 allUserHandles, perUserInstalled,  
  27.                 outInfo, writeSettings);  
  28.     }  
  29.   
  30.     return ret;  
  31. }  

卸载系统应用

为什么会有卸载系统应用呢,当我们调用scanPackageLI扫描目录时有时候失败,也需要调用deletePackageLI来删除apk,这个时候就会有系统应用了。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private boolean deleteSystemPackageLI(PackageSetting newPs,  
  2.         int[] allUserHandles, boolean[] perUserInstalled,  
  3.         int flags, PackageRemovedInfo outInfo, boolean writeSettings) {  
  4.     final boolean applyUserRestrictions  
  5.             = (allUserHandles != null) && (perUserInstalled != null);  
  6.     PackageSetting disabledPs = null;  
  7.     // Confirm if the system package has been updated  
  8.     // An updated system app can be deleted. This will also have to restore  
  9.     // the system pkg from system partition  
  10.     // reader  
  11.     synchronized (mPackages) {  
  12.         disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);  
  13.     }  
  14.     if (DEBUG_REMOVE) Slog.d(TAG, “deleteSystemPackageLI: newPs=” + newPs  
  15.             + ” disabledPs=” + disabledPs);  
  16.     if (disabledPs == null) {  
  17.         Slog.w(TAG, “Attempt to delete unknown system package “+ newPs.name);  
  18.         return false;  
  19.     } else if (DEBUG_REMOVE) {  
  20.         Slog.d(TAG, “Deleting system pkg from data partition”);  
  21.     }  
  22.   
  23.     // Delete the updated package  
  24.     outInfo.isRemovedPackageSystemUpdate = true;  
  25.     if (disabledPs.versionCode < newPs.versionCode) {  
  26.         // Delete data for downgrades  
  27.         flags &= ~PackageManager.DELETE_KEEP_DATA;//是否保留资源  
  28.     } else {  
  29.         // Preserve data by setting flag  
  30.         flags |= PackageManager.DELETE_KEEP_DATA;  
  31.     }  
  32.     boolean ret = deleteInstalledPackageLI(newPs, true, flags,//卸载apk  
  33.             allUserHandles, perUserInstalled, outInfo, writeSettings);  
  34.     if (!ret) {  
  35.         return false;  
  36.     }  
  37.     // writer  
  38.     synchronized (mPackages) {  
  39.         // Reinstate the old system package  
  40.         mSettings.enableSystemPackageLPw(newPs.name);  
  41.         // Remove any native libraries from the upgraded package.  
  42.         NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);  
  43.     }  
  44.     // Install the system package  
  45.     int parseFlags = PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM;  
  46.     if (locationIsPrivileged(disabledPs.codePath)) {  
  47.         parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;  
  48.     }  
  49.   
  50.     final PackageParser.Package newPkg;  
  51.     try {  
  52.         newPkg = scanPackageLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);//重新apk扫描目录  
  53.     } catch (PackageManagerException e) {  
  54.         Slog.w(TAG, “Failed to restore system package:” + newPs.name + “: “ + e.getMessage());  
  55.         return false;  
  56.     }  
  57.   
  58.     // writer  
  59.     synchronized (mPackages) {  
  60.         PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);  
  61.   
  62.         // Propagate the permissions state as we do not want to drop on the floor  
  63.         // runtime permissions. The update permissions method below will take  
  64.         // care of removing obsolete permissions and grant install permissions.  
  65.         ps.getPermissionsState().copyFrom(newPs.getPermissionsState());  
  66.         updatePermissionsLPw(newPkg.packageName, newPkg,  
  67.                 UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);  
  68.   
  69.         if (applyUserRestrictions) {  
  70.             if (DEBUG_REMOVE) {  
  71.                 Slog.d(TAG, “Propagating install state across reinstall”);  
  72.             }  
  73.             for (int i = 0; i < allUserHandles.length; i++) {  
  74.                 if (DEBUG_REMOVE) {  
  75.                     Slog.d(TAG, ”    user “ + allUserHandles[i]  
  76.                             + ” => “ + perUserInstalled[i]);  
  77.                 }  
  78.                 ps.setInstalled(perUserInstalled[i], allUserHandles[i]);  
  79.   
  80.                 mSettings.writeRuntimePermissionsForUserLPr(allUserHandles[i], false);  
  81.             }  
  82.             // Regardless of writeSettings we need to ensure that this restriction  
  83.             // state propagation is persisted  
  84.             mSettings.writeAllUsersPackageRestrictionsLPr();  
  85.         }  
  86.         // can downgrade to reader here  
  87.         if (writeSettings) {  
  88.             mSettings.writeLPr();//更新packages.xml  
  89.         }  
  90.     }  
  91.     return true;  
  92. }  

卸载系统应用,最后也是调用deleteInstalledPackageLI来完成卸载的,我们来看下这个函数。

卸载普通应用

卸载普通应用就直接调用了deleteInstalledPackageLI函数

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private boolean deleteInstalledPackageLI(PackageSetting ps,  
  2.         boolean deleteCodeAndResources, int flags,  
  3.         int[] allUserHandles, boolean[] perUserInstalled,  
  4.         PackageRemovedInfo outInfo, boolean writeSettings) {  
  5.     if (outInfo != null) {  
  6.         outInfo.uid = ps.appId;  
  7.     }  
  8.   
  9.     // Delete package data from internal structures and also remove data if flag is set  
  10.     removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings);  
  11.   
  12.     // Delete application code and resources  
  13.     if (deleteCodeAndResources && (outInfo != null)) {  
  14.         outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),  
  15.                 ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));  
  16.         if (DEBUG_SD_INSTALL) Slog.i(TAG, “args=” + outInfo.args);  
  17.     }  
  18.     return true;  
  19. }  

我们先看removePackageDataLI函数,就是删除各种资源,但是我们没看到删除apk文件。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private void removePackageDataLI(PackageSetting ps,  
  2.         int[] allUserHandles, boolean[] perUserInstalled,  
  3.         PackageRemovedInfo outInfo, int flags, boolean writeSettings) {  
  4.     String packageName = ps.name;  
  5.     if (DEBUG_REMOVE) Slog.d(TAG, “removePackageDataLI: “ + ps);  
  6.     removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);  
  7.     // Retrieve object to delete permissions for shared user later on  
  8.     final PackageSetting deletedPs;     
  9.     // reader  
  10.     synchronized (mPackages) {  
  11.         deletedPs = mSettings.mPackages.get(packageName);          
  12.         if (outInfo != null) {  
  13.             outInfo.removedPackage = packageName;  
  14.             outInfo.removedUsers = deletedPs != null  
  15.                     ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)  
  16.                     : null;  
  17.         }  
  18.     }  
  19.     if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {  
  20.         removeDataDirsLI(ps.volumeUuid, packageName);// 卸载data目录  
  21.         schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);  
  22.     }  
  23.     // writer  
  24.     synchronized (mPackages) {  
  25.         if (deletedPs != null) {  
  26.             if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {  
  27.                 clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);  
  28.                 clearDefaultBrowserIfNeeded(packageName);  
  29.                 if (outInfo != null) {  
  30.                     mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);  
  31.                     outInfo.removedAppId = mSettings.removePackageLPw(packageName);  
  32.                 }  
  33.                 updatePermissionsLPw(deletedPs.name, null, 0);  
  34.                 if (deletedPs.sharedUser != null) {  
  35.                     // Remove permissions associated with package. Since runtime  
  36.                     // permissions are per user we have to kill the removed package  
  37.                     // or packages running under the shared user of the removed  
  38.                     // package if revoking the permissions requested only by the removed  
  39.                     // package is successful and this causes a change in gids.  
  40.                     for (int userId : UserManagerService.getInstance().getUserIds()) {  
  41.                         final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,  
  42.                                 userId);  
  43.                         if (userIdToKill == UserHandle.USER_ALL  
  44.                                 || userIdToKill >= UserHandle.USER_OWNER) {  
  45.                             // If gids changed for this user, kill all affected packages.  
  46.                             mHandler.post(new Runnable() {  
  47.                                 @Override  
  48.                                 public void run() {  
  49.                                     // This has to happen with no lock held.  
  50.                                     killApplication(deletedPs.name, deletedPs.appId,  
  51.                                             KILL_APP_REASON_GIDS_CHANGED);  
  52.                                 }  
  53.                             });  
  54.                             break;  
  55.                         }  
  56.                     }  
  57.                 }  
  58.                 clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);  
  59.             }  
  60.             // make sure to preserve per-user disabled state if this removal was just  
  61.             // a downgrade of a system app to the factory package  
  62.             if (allUserHandles != null && perUserInstalled != null) {  
  63.                 if (DEBUG_REMOVE) {  
  64.                     Slog.d(TAG, “Propagating install state across downgrade”);  
  65.                 }  
  66.                 for (int i = 0; i < allUserHandles.length; i++) {  
  67.                     if (DEBUG_REMOVE) {  
  68.                         Slog.d(TAG, ”    user “ + allUserHandles[i]  
  69.                                 + ” => “ + perUserInstalled[i]);  
  70.                     }  
  71.                     ps.setInstalled(perUserInstalled[i], allUserHandles[i]);  
  72.                 }  
  73.             }  
  74.         }  
  75.         // can downgrade to reader  
  76.         if (writeSettings) {  
  77.             // Save settings now  
  78.             mSettings.writeLPr();//更新packages.xml  
  79.         }  
  80.     }  
  81.     if (outInfo != null) {  
  82.         // A user ID was deleted here. Go through all users and remove it  
  83.         // from KeyStore.  
  84.         removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);  
  85.     }  

我们再来看deleteInstalledPackageLI函数,最后一段代码,

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. if (deleteCodeAndResources && (outInfo != null)) {  
  2.     outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),  
  3.             ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));  
  4.     if (DEBUG_SD_INSTALL) Slog.i(TAG, “args=” + outInfo.args);  
  5. }  

我们来看下这个函数,如果不是安装在sd卡上,最后新建一个FileInstallArgs对象。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,  
  2.         String resourcePath, String[] instructionSets) {  
  3.     final boolean isInAsec;  
  4.     if (installOnExternalAsec(installFlags)) {  
  5.         /* Apps on SD card are always in ASEC containers. */  
  6.         isInAsec = true;  
  7.     } else if (installForwardLocked(installFlags)  
  8.             && !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {  
  9.         /* 
  10.          * Forward-locked apps are only in ASEC containers if they’re the 
  11.          * new style 
  12.          */  
  13.         isInAsec = true;  
  14.     } else {  
  15.         isInAsec = false;  
  16.     }  
  17.   
  18.     if (isInAsec) {  
  19.         return new AsecInstallArgs(codePath, instructionSets,  
  20.                 installOnExternalAsec(installFlags), installForwardLocked(installFlags));  
  21.     } else {  
  22.         return new FileInstallArgs(codePath, resourcePath, instructionSets);  
  23.     }  
  24. }  

最后返回到deletePackageX函数,最后调用如下代码,直接到FileInstallArgs的doPostDeleteLI函数。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. if (info.args != null) {  
  2.     synchronized (mInstallLock) {  
  3.         info.args.doPostDeleteLI(true);  
  4.     }  
  5. }  

doPostDeleteLI函数如下:

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. boolean doPostDeleteLI(boolean delete) {  
  2.     // XXX err, shouldn’t we respect the delete flag?  
  3.     cleanUpResourcesLI();  
  4.     return true;  
  5. }  

cleanUpResourcesLI函数会删除资源和代码文件,dex文件

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. void cleanUpResourcesLI() {  
  2.     // Try enumerating all code paths before deleting  
  3.     List<String> allCodePaths = Collections.EMPTY_LIST;  
  4.     if (codeFile != null && codeFile.exists()) {  
  5.         try {  
  6.             final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);  
  7.             allCodePaths = pkg.getAllCodePaths();  
  8.         } catch (PackageParserException e) {  
  9.             // Ignored; we tried our best  
  10.         }  
  11.     }  
  12.   
  13.     cleanUp();  
  14.     removeDexFiles(allCodePaths, instructionSets);  
  15. }  

cleanUp函数就是删除apk文件。

[cpp]
view plain
copy

《Android 6.0 PKMS 卸载删除app》
《Android 6.0 PKMS 卸载删除app》

  1. private boolean cleanUp() {  
  2.     if (codeFile == null || !codeFile.exists()) {  
  3.         return false;  
  4.     }  
  5.   
  6.     if (codeFile.isDirectory()) {  
  7.         mInstaller.rmPackageDir(codeFile.getAbsolutePath());  
  8.     } else {  
  9.         codeFile.delete();  
  10.     }  
  11.   
  12.     if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {  
  13.         resourceFile.delete();  
  14.     }  
  15.   
  16.     return true;  
  17. }  

时序图

《Android 6.0 PKMS 卸载删除app》

    原文作者:_dowork
    原文地址: https://blog.csdn.net/q1183345443/article/details/53285612
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞