Android PackageManagerService总结(五) APK卸载流程

落日映苍穹つ 2024-03-26 22:03 185阅读 0赞

一. 概述

PackageManagerService(简称PKMS),是Android系统中核心服务之一,管理着所有与package相关的工作,常见的比如安装、卸载应用, 信息查询等工作, 主要完成以下核心功能

  1. 解析AndroidManifest.xml清单文件,解析清单文件中的所有节点信息

  2. 扫描本地文件,主要针对apk,主要是系统应用、本地安装应用等。

  3. 管理本地apk,主要包括安装、删除等等

  4. 管理设备上安装的所有应用程序,并在系统启动时加载应用程序

  5. 根据请求的Intent匹配到对应的Activity、Provider、Service,提供包含包名和Component的信息对象

  6. 调用需要权限的系统函数时,检查程序是否具备相应权限从而保证系统安全

  7. 提供应用程序的安装、卸载的接口

本篇文章重点介绍一下apk卸载流程

二. 卸载流程

2.1 Settings界面——>PackageInstaller界面

卸载一个apk的方式:

  1. 长按apk拖住移动到最上栏,就可以卸载

  2. 长按apk,点击下方的应用信息,跳转到设置中的应用信息界面 点击中间的按钮卸载

  3. 设置—应用和通知—打开应用信息列表——选择apk, 弹出应用信息界面, 点击中间的卸载按钮

应用信息界面,对应的文件是

packages/apps/Settings/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java

卸载按钮对应的代码

  1. @Override
  2. public void displayPreference(PreferenceScreen screen) {
  3. super.displayPreference(screen);
  4. if (isAvailable()) {
  5. mButtonsPref = ((ActionButtonsPreference) screen.findPreference(
  6. KEY_ACTION_BUTTONS))
  7. //打开按钮
  8. .setButton1Text(R.string.launch_instant_app)
  9. .setButton1Icon(R.drawable.ic_settings_open)
  10. .setButton1OnClickListener(v -> launchApplication())
  11. //卸载按钮
  12. .setButton2Text(R.string.uninstall_text)
  13. .setButton2Icon(R.drawable.ic_settings_delete)
  14. .setButton2OnClickListener(new UninstallAndDisableButtonListener())
  15. //强行停止按钮
  16. .setButton3Text(R.string.force_stop)
  17. .setButton3Icon(R.drawable.ic_settings_force_stop)
  18. .setButton3OnClickListener(new ForceStopButtonListener())
  19. .setButton3Enabled(false);
  20. }
  21. }

点击卸载事件处理:

  1. private class UninstallAndDisableButtonListener implements View.OnClickListener {
  2. final String packageName = mAppEntry.info.packageName;
  3. .....
  4. } else {
  5. //走这里的逻辑
  6. uninstallPkg(packageName, false, false);
  7. }
  8. }

继续看uninstallPkg方法:

  1. void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
  2. stopListeningToPackageRemove();
  3. // Create new intent to launch Uninstaller activity
  4. Uri packageUri = Uri.parse("package:" + packageName);
  5. Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
  6. uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
  7. mMetricsFeatureProvider.action(
  8. mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP);
  9. mFragment.startActivityForResult(uninstallIntent, mRequestUninstall);
  10. mDisableAfterUninstall = andDisable;
  11. }

封装了一个ACTION为Intent.ACTION_UNINSTALL_PACKAGE的intent,我们全局搜索源码,发现只有一个Activity匹配上,那就是com.android.packageinstaller 中的 UninstallerActivity.java

/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java

然后呈现给用户的界面图如下:

5632b2152db048d39657fa23b4fb0253.png

如果点击确定按钮,就开始卸载

确定按钮的逻辑在:

frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java中

  1. @Override
  2. public void onClick(DialogInterface dialog, int which) {
  3. if (which == Dialog.BUTTON_POSITIVE) {
  4. ((UninstallerActivity) getActivity()).startUninstallProgress(
  5. mKeepData != null && mKeepData.isChecked());
  6. } else {
  7. ((UninstallerActivity) getActivity()).dispatchAborted();
  8. }
  9. }

回到UninstallerActivity.java中的startUninstallProgress()方法中

  1. public void startUninstallProgress(boolean keepData) {
  2. ....
  3. //我是用手机调试的,不是TV设备, 通过判断条件它走的是else分支
  4. } else if (returnResult || mDialogInfo.callback != null || getCallingActivity() != null) {
  5. Intent newIntent = new Intent(this, UninstallUninstalling.class);
  6. ....
  7. }

然后跳转到UninstallUninstalling.java中, 我们来看看其onCreate方法

/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java

  1. @Override
  2. protected void onCreate(@Nullable Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setFinishOnTouchOutside(false);
  5. .....
  6. try {
  7. ActivityThread.getPackageManager().getPackageInstaller().uninstall(
  8. new VersionedPackage(mAppInfo.packageName,
  9. PackageManager.VERSION_CODE_HIGHEST),
  10. getPackageName(), flags, pendingIntent.getIntentSender(),
  11. user.getIdentifier());
  12. } catch (RemoteException e) {
  13. e.rethrowFromSystemServer();
  14. }
  15. .....
  16. }

通过IPackageInstaller.java这个接口实现跨进程通信,此时的客户端为PackageInstaller.apk, 服务端为 PackageInstallerService.java , 就直接调用到 PackageInstallerService.java中的 uninstall方法中去了

好了到这里,先梳理一下应用层的逻辑,时序图为:

641c104013b243a6a2061b088e3b8b64.png

2.2 PackageInstallerService >>> uninstall()

继续上一小结分析

进入到frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java

  1. @Override
  2. public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
  3. IntentSender statusReceiver, int userId) {
  4. // 先获取 UID
  5. final int callingUid = Binder.getCallingUid();
  6. // 检查执行权限
  7. mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
  8. //创建PackageDeleteObserverAdapter对象,用于接收响应删除的结果
  9. final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
  10. statusReceiver, versionedPackage.getPackageName(),
  11. canSilentlyInstallPackage, userId);
  12. if(mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
  13. == PackageManager.PERMISSION_GRANTED) {
  14. // Sweet, call straight through!
  15. // 调用 mPm mPm.deletePackageVersioned
  16. mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
  17. ......
  18. }

这个方法主要做了3件事情:

  1. 创建PackageDeleteObserverAdapter对象,用于接收响应删除的结果
  2. 检查当前程序是否具有删除权限, 如果有的话,就调用 mPm.deletePackageVersioned方法
  3. 调用PMS的deletePackageVersioned()方法执行程序的卸载

最后卸载调用了 mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); 所以走到了 PackageManagerService 的 deletePackageVersioned()

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

  1. @Override
  2. public void deletePackageVersioned(VersionedPackage versionedPackage,
  3. final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
  4. mHandler.post(() -> {
  5. int returnCode;
  6. final PackageSetting ps = mSettings.mPackages.get(internalPackageName);
  7. boolean doDeletePackage = true;
  8. if (ps != null) {
  9. final boolean targetIsInstantApp =
  10. ps.getInstantApp(UserHandle.getUserId(callingUid));
  11. doDeletePackage = !targetIsInstantApp
  12. || canViewInstantApps;
  13. }
  14. if (doDeletePackage) {
  15. if (!deleteAllUsers) {
  16. //走这里的逻辑
  17. returnCode = deletePackageX(internalPackageName, versionCode,
  18. userId, deleteFlags);
  19. } else {
  20. try {
  21. //删除apk后的回调方法
  22. observer.onPackageDeleted(packageName, returnCode, null);
  23. } catch (RemoteException e) {
  24. Log.i(TAG, "Observer no longer exists.");
  25. } //end catch
  26. }

在deletePackageVersioned()中发送Post事件执行异步删除操作,在Handler事件中调用

deletePackageX()方法

  1. int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
  2. ....
  3. if (isPackageDeviceAdmin(packageName, removeUser)) {
  4. Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
  5. return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
  6. }
  7. synchronized (mInstallLock) {
  8. if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
  9. try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
  10. deleteFlags, "deletePackageX")) {
  11. //调用这个方法
  12. res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
  13. deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);
  14. }
  15. ....
  16. }

在deletePackageX()中首先判断要卸载的程序是否是admin管理的,如果是则直接return,如果不是则执行deletePackageLIF()方法继续卸载程序

  1. private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
  2. boolean deleteCodeAndResources, int[] allUserHandles, int flags,
  3. PackageRemovedInfo outInfo, boolean writeSettings,
  4. PackageParser.Package replacingPackage) {
  5. .....
  6. try {
  7. executeDeletePackageLIF(action, packageName, deleteCodeAndResources,
  8. allUserHandles, writeSettings, replacingPackage);
  9. } catch (SystemDeleteException e) {
  10. if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e);
  11. return false;
  12. }
  13. .....
  14. }

执行到executeDeletePackageLIF方法中

笔者用的是展锐平台的代码跟踪的流程, 这个executeDeletePackageLIF方法和源码命名不一致,但是整体流程的逻辑没有太大差别

  1. private void executeDeletePackageLIF(DeletePackageAction action,
  2. String packageName, boolean deleteCodeAndResources,
  3. int[] allUserHandles, boolean writeSettings,
  4. PackageParser.Package replacingPackage) throws SystemDeleteException {
  5. ....
  6. //是否是系统app
  7. final boolean systemApp = isSystemApp(ps);
  8. // TODO(b/109941548): break reasons for ret = false out into mayDelete method
  9. if (systemApp) {
  10. if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
  11. // When an updated system application is deleted we delete the existing resources
  12. // as well and fall back to existing code in system partition
  13. deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);
  14. } else {
  15. if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
  16. /* SPRD: Add for boot performance with multi-thread and preload scan @{*/
  17. if(ps.pkg != null && ps.pkg.baseCodePath != null){
  18. String path = ps.pkg.baseCodePath.substring(0, ps.pkg.baseCodePath.lastIndexOf("/"));
  19. if(PackageManager.isPreloadOrVitalApp(path)) mPackageManagerServiceExUtils.delAppRecord(ps.pkg.packageName, flags);
  20. }
  21. /* @} */
  22. //我删除的就是一个普通的第三方apk,所以走的是这里的流程
  23. deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
  24. outInfo, writeSettings, replacingPackage);
  25. }
  26. ....
  27. }

在executeDeletePackageLIF函数中根据是否是systemApp调用不同的流程,如果是systemApp,则调用deleteSystemPackageLIF完成卸载;如果非systemApp,则调用deleteInstalledPackageLIF完成卸载,当然在卸载之前,首先会调用AMS的killApplication方法先让这个APP停止运行, 我们继续来分析deleteInstalledPackageLIF 这个方法

  1. private void deleteInstalledPackageLIF(PackageSetting ps,
  2. boolean deleteCodeAndResources, int flags, int[] allUserHandles,
  3. PackageRemovedInfo outInfo, boolean writeSettings,
  4. PackageParser.Package replacingPackage) {
  5. .....
  6. // Delete package data from internal structures and also remove data if flag is set
  7. //从内部结构中删除包数据,如果设置了标志,也删除数据
  8. removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);
  9. .....
  10. }

我们重点来看一下这个方法removePackageDataLIF

  1. private void removePackageDataLIF(PackageSetting ps, int[] allUserHandles,
  2. PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
  3. String packageName = ps.name;
  4. if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
  5. // 检索对象以稍后删除共享用户的权限
  6. final PackageParser.Package deletedPkg;
  7. final PackageSetting deletedPs;
  8. // reader
  9. synchronized (mPackages) {
  10. deletedPkg = mPackages.get(packageName);
  11. deletedPs = mSettings.mPackages.get(packageName);
  12. if (outInfo != null) {
  13. outInfo.removedPackage = packageName;
  14. outInfo.installerPackageName = ps.installerPackageName;
  15. outInfo.isStaticSharedLib = deletedPkg != null
  16. && deletedPkg.staticSharedLibName != null;
  17. outInfo.populateUsers(deletedPs == null ? null
  18. : deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
  19. }
  20. }
  21. //注释1 删除数据
  22. removePackageLI(ps, (flags & FLAGS_REMOVE_CHATTY) != 0);
  23. if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
  24. final PackageParser.Package resolvedPkg;
  25. if (deletedPkg != null) {
  26. resolvedPkg = deletedPkg;
  27. } else {
  28. // We don't have a parsed package when it lives on an ejected
  29. // adopted storage device, so fake something together
  30. resolvedPkg = new PackageParser.Package(ps.name);
  31. resolvedPkg.setVolumeUuid(ps.volumeUuid);
  32. }
  33. //注释二 删除目录和配置文件
  34. destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
  35. StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
  36. destroyAppProfilesLIF(resolvedPkg, UserHandle.USER_ALL);
  37. if (outInfo != null) {
  38. outInfo.dataRemoved = true;
  39. }
  40. }
  41. int removedAppId = -1;
  42. // writer
  43. synchronized (mPackages) {
  44. boolean installedStateChanged = false;
  45. if (deletedPs != null) {
  46. if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
  47. clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
  48. clearDefaultBrowserIfNeeded(packageName);
  49. mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
  50. //移除mSetting中保存的数据
  51. removedAppId = mSettings.removePackageLPw(packageName);
  52. if (outInfo != null) {
  53. outInfo.removedAppId = removedAppId;
  54. }
  55. //更新权限信息
  56. updatePermissionsLPw(deletedPs.name, null, 0);
  57. if (deletedPs.sharedUser != null) {
  58. //删除与包关联的权限。由于运行时权限是按用户分配的,
  59. //所以如果撤销仅由已删除的包请求的权限成功且这将导致gids的更改,
  60. //则必须终止已删除的包或在已删除包的共享用户下运行的包。
  61. for (int userId : UserManagerService.getInstance().getUserIds()) {
  62. final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
  63. userId);
  64. if (userIdToKill == UserHandle.USER_ALL
  65. || userIdToKill >= UserHandle.USER_SYSTEM) {
  66. // 如果为这个用户更改了gid,则杀死所有受影响的包。
  67. mHandler.post(new Runnable() {
  68. @Override
  69. public void run() {
  70. // 这必须在没有持有锁的情况下发生。这里是上文提到的
  71. //杀掉应用的地方
  72. killApplication(deletedPs.name, deletedPs.appId,
  73. KILL_APP_REASON_GIDS_CHANGED);
  74. }
  75. });
  76. break;
  77. }
  78. }
  79. }
  80. clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
  81. }
  82. // 如果删除只是将系统应用程序降级到工厂包,请确保保留每个用户禁用状态
  83. if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
  84. if (DEBUG_REMOVE) {
  85. Slog.d(TAG, "Propagating install state across downgrade");
  86. }
  87. for (int userId : allUserHandles) {
  88. final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
  89. if (DEBUG_REMOVE) {
  90. Slog.d(TAG, " user " + userId + " => " + installed);
  91. }
  92. if (installed != ps.getInstalled(userId)) {
  93. installedStateChanged = true;
  94. }
  95. ps.setInstalled(installed, userId);
  96. }
  97. }
  98. }
  99. // can downgrade to reader
  100. if (writeSettings) {
  101. //写入mSettings信息,更新Package.xml文件
  102. mSettings.writeLPr();
  103. }
  104. if (installedStateChanged) {
  105. mSettings.writeKernelMappingLPr(ps);
  106. }
  107. }
  108. if (removedAppId != -1) {
  109. // A user ID was deleted here. Go through all users and remove it
  110. // from KeyStore.
  111. //此处删除了用户ID。浏览所有用户并将其从KeyStore中删除
  112. removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId);
  113. }
  114. }

removePackageDataLIF用于删除应用的/data/data数据目录,并且从PMS内部数据结构里面清除package的信息。首先调用removePackageLI从PMS内部的数据结构上删除要卸载的package信息

继续分析注释1处的删除数据的方法 removePackageLI

  1. void removePackageLI(String packageName, boolean chatty) {
  2. if (DEBUG_INSTALL) {
  3. if (chatty)
  4. Log.d(TAG, "Removing package " + packageName);
  5. }
  6. // writer
  7. synchronized (mPackages) {
  8. final PackageParser.Package removedPackage = mPackages.remove(packageName);
  9. if (removedPackage != null) {
  10. //调用这个方法 删除四大组件相关的信息
  11. cleanPackageDataStructuresLILPw(removedPackage, chatty);
  12. }
  13. }
  14. }

cleanPackageDataStructuresLILPw用于将package的providers、services、receivers、activities等信息去PMS的全局数据结构上移除,可以看看log打印

adb logcat -s PackageManager

63a6ecf382f743d6b895e2cb44dbffed.png

接下来回到removePackageDataLIF中 注释二处

调用destroyAppDataLIF和destroyAppProfilesLIF去删除/data/data下面的目录

destroyAppDataLIF主要顺序

  • destroyAppDataLeafLIF
  • destroyAppData

    private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {

    1. final PackageSetting ps;
    2. synchronized (mPackages) {
    3. ps = mSettings.mPackages.get(pkg.packageName);
    4. }
    5. for (int realUserId : resolveUserIds(userId)) {
    6. final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
    7. try {
    8. mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
    9. ceDataInode);
    10. } catch (InstallerException e) {
    11. Slog.w(TAG, String.valueOf(e));
    12. }
    13. mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
    14. }

    }

通过 mInstaller.destroyAppData方法, 跳转到 Installer.java

/frameworks/base/services/core/java/com/android/server/pm/ Installer.java

  1. public void destroyAppData(String uuid, String packageName, int userId, int flags,
  2. long ceDataInode) throws InstallerException {
  3. if (!checkBeforeRemote()) return;
  4. try {
  5. mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
  6. } catch (Exception e) {
  7. throw InstallerException.from(e);
  8. }
  9. }

然后在Installd 守护进程执行删除app数据的动作,具体文件和方法:

跨进程调用InstalldNativeService.cpp 的destroyAppData方法

frameworks/native/cmds/installd/InstalldNativeService.cpp

  1. binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std::string>& uuid,
  2. const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
  3. ENFORCE_UID(AID_SYSTEM);
  4. CHECK_ARGUMENT_UUID(uuid);
  5. CHECK_ARGUMENT_PACKAGE_NAME(packageName);
  6. std::lock_guard<std::recursive_mutex> lock(mLock);
  7. const char* uuid_ = uuid ? uuid->c_str() : nullptr;
  8. const char* pkgname = packageName.c_str();
  9. binder::Status res = ok();
  10. if (flags & FLAG_STORAGE_CE) {
  11. auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
  12. if (delete_dir_contents_and_dir(path) != 0) {
  13. res = error("Failed to delete " + path);
  14. }
  15. }
  16. if (flags & FLAG_STORAGE_DE) {
  17. auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
  18. if (delete_dir_contents_and_dir(path) != 0) {
  19. res = error("Failed to delete " + path);
  20. }
  21. destroy_app_current_profiles(packageName, userId);
  22. // TODO(calin): If the package is still installed by other users it's probably
  23. // beneficial to keep the reference profile around.
  24. // Verify if it's ok to do that.
  25. destroy_app_reference_profile(packageName);
  26. }
  27. if (flags & FLAG_STORAGE_EXTERNAL) {
  28. std::lock_guard<std::recursive_mutex> lock(mMountsLock);
  29. for (const auto& n : mStorageMounts) {
  30. auto extPath = n.second;
  31. if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) {
  32. extPath += StringPrintf("/%d", userId);
  33. } else if (userId != 0) {
  34. // TODO: support devices mounted under secondary users
  35. continue;
  36. }
  37. auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
  38. if (delete_dir_contents_and_dir(path, true) != 0) {
  39. res = error("Failed to delete contents of " + path);
  40. }
  41. path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
  42. if (delete_dir_contents_and_dir(path, true) != 0) {
  43. res = error("Failed to delete contents of " + path);
  44. }
  45. path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
  46. if (delete_dir_contents_and_dir(path, true) != 0) {
  47. res = error("Failed to delete contents of " + path);
  48. }
  49. }
  50. }
  51. return res;
  52. }

笔者c++的基础一般,看源代码也只能大致猜测处理逻辑, 意思就是:

create_data_user_ce_package_path方法构造/data/data/packageName的文件路径名,然后调用delete_dir_contents_and_dir来删除文件内容以及目录(比如Android/data/包名/,

Android/media/包名, Android/obb/包名/ 路径下的文件),前面介绍过,/data/data/packageName的文件其实都是符号链接,所以delete_dir_contents_and_dir的实现中都是调用unlinkat去删除这些符号链接

到此应用程序的app安装文件和使用中产生的数据文件都已被删除,且配置文件已更新完成,此时会回调deletePackageVersioned()中的 observer.onPackageDeleted(packageName, returnCode, null) 方法通知删除结果,这里回调的是PackageDeleteObserverAdapter类中

  1. @Override
  2. public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
  3. if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
  4. NotificationManager notificationManager = (NotificationManager)
  5. mContext.getSystemService(Context.NOTIFICATION_SERVICE);
  6. notificationManager.notify(basePackageName,
  7. SystemMessage.NOTE_PACKAGE_STATE,
  8. mNotification);
  9. }
  10. if (mTarget == null) {
  11. return;
  12. }
  13. final Intent fillIn = new Intent();
  14. fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
  15. fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
  16. PackageManager.deleteStatusToPublicStatus(returnCode));
  17. fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
  18. PackageManager.deleteStatusToString(returnCode, msg));
  19. fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
  20. try {
  21. mTarget.sendIntent(mContext, 0, fillIn, null, null);
  22. } catch (SendIntentException ignored) {
  23. }
  24. }
  25. }

在onPackageDeleted()中,首先调用NotificationManager中方法发送notify()通知卸载成功,然后创建Intent对象并回调mTarget.sendIntent(),这里的mTarget对象其实就是卸载最开始时调用uninstall()方法传入的第二个参数,即IntentSender对象,用于接收删除的结果.

如下log是卸载第三方apk(懒人听书) 打印出来的, 与上面的流程分析的基本一致

  1. me@ubuntu:~$ adb logcat -s PackageManager
  2. --------- beginning of main
  3. --------- beginning of system
  4. //开始卸载app
  5. 03-26 10:55:15.781 4172 4640 D PackageManager: pms deletePackage start : pkg=bubei.tingshu.hd
  6. // 关键方法deletePackageAsUser
  7. 03-26 10:55:15.781 4172 4640 D PackageManager: deletePackageAsUser: pkg=bubei.tingshu.hd user=0 deleteAllUsers: false version=VERSION_CODE_HIGHEST
  8. //deletePackageX
  9. 03-26 10:55:15.782 4172 4216 D PackageManager: deletePackageX: pkg=bubei.tingshu.hd user=0
  10. //deletePackageLI
  11. 03-26 10:55:15.782 4172 4216 D PackageManager: deletePackageLI: bubei.tingshu.hd user UserHandle{0}
  12. 03-26 10:55:15.783 4172 4216 D PackageManager: Marking package:bubei.tingshu.hd uninstalled for user:0
  13. 03-26 10:55:15.783 4172 4216 D PackageManager: Not installed by other users, full delete
  14. 03-26 10:55:15.809 4172 4216 D PackageManager: Removing non-system package: bubei.tingshu.hd
  15. //removePackageDataLI
  16. 03-26 10:55:15.809 4172 4216 D PackageManager: removePackageDataLI: PackageSetting{906a721 bubei.tingshu.hd/10126}
  17. 03-26 10:55:15.809 4172 4216 D PackageManager: Removing package bubei.tingshu.hd
  18. //执行cleanPackageDataStructuresLILPw方法打印出来log
  19. 03-26 10:55:15.809 4172 4216 D PackageManager: Activities: bubei.tingshu.hd.ui.LogoActivity bubei.tingshu.hd.ui.AppHomeActivity bubei.tingshu.hd.ui.DetailActivity bubei.tingshu.hd.ui.DownloadManagerActivity bubei.tingshu.hd.ui.ClassifyFilterActivity bubei.tingshu.hd.ui.ClassifyDetailActivity bubei.tingshu.hd.ui.ResourceListActivity bubei.tingshu.hd.ui.ResourceListAndMediaplayerActivity bubei.tingshu.hd.ui.AppSettingActivity bubei.tingshu.hd.ui.RecommendHomeActivity bubei.tingshu.hd.ui.RecommendCateTabActivity bubei.tingshu.hd.ui.QRCodeActivity bubei.tingshu.hd.ui.UserInfoActivity bubei.tingshu.hd.ui.SearchTabActivity bubei.tingshu.hd.ui.WebviewActivity bubei.tingshu.hd.ui.DeepLinkActivity com.baidu.voicerecognition.android.ui.BaiduASRDigitalDialog com.journeyapps.barcodescanner.CaptureActivity android.app.AppDetailsActivity
  20. 03-26 10:55:15.809 4172 4216 D PackageManager: Providers: <NONE>
  21. 03-26 10:55:15.809 4172 4216 D PackageManager: Receivers: bubei.tingshu.hd.mediaplayer.MediaButtonReceiver
  22. 03-26 10:55:15.809 4172 4216 D PackageManager: Services: bubei.tingshu.hd.mediaplayer.MediaPlaybackService bubei.tingshu.hd.util.RegularClearCacheService com.baidu.speech.VoiceRecognitionService bubei.tingshu.lib.download.function.DownloadService
  23. 03-26 10:55:15.811 4172 4216 D PackageManager: Propagating install state across downgrade
  24. 03-26 10:55:15.811 4172 4216 D PackageManager: user 0 => true
  25. 03-26 10:55:15.869 4172 4216 D PackageManager: Instant App installer not found with android.intent.action.INSTALL_INSTANT_APP_PACKAGE
  26. 03-26 10:55:15.869 4172 4216 D PackageManager: Clear ephemeral installer activity
  27. //在调用observer.onPackageDeleted方法后,打印卸载结束
  28. 03-26 10:55:15.963 4172 4216 D PackageManager: pms deletePackage end : pkg=bubei.tingshu.hd
  29. 03-26 10:55:15.981 4172 4191 E PackageManager: failed to find package bubei.tingshu.hd

好了,到这里再总结一下卸载apk的工作内容:

  1. 从PMS的内部结构上删除acitivity、service、provider, receivers等信息

  2. 删除code、library和resource等信息

  3. 调用installd守护进程删除/data/data/packageName以及/data/dalvik-cache下面的文件

  4. 更新Settings中的package信息

三. 待更新

本文把整体流程梳理了一下, 后续在针对细节方法, 在工作中有需求实现或bug要解决, 有新的理解会更新进来, 上述内容可以供大家参考,谢谢

发表评论

表情:
评论列表 (有 0 条评论,185人围观)

还没有评论,来说两句吧...

相关阅读