当前位置:   article > 正文

Android Framework 包管理子系统(04)应用卸载_安卓framework 卸载系统应用

安卓framework 卸载系统应用

该系列文章总纲链接:专题分纲目录 Android Framework 包管理子系统


本章关键点总结 & 说明:

导图是不断迭代的,这里主要关注➕ PkgMS卸载应用部分。主要是删除应用的文件、数据和缓存数据。

卸载应用和安装应用的分析流程是极其类似的,因此会感觉有些代码有些重复但却不同,也是从adb uninstall命令开始分析。

1 卸载应用程序(从 adb unInstall 到PkgMS)

一般我们会使用adb uninstall 来安装应用,因此这里就从adb uninstall开始分析,adb命令,uninstall参数。直接看adb命令 处理install参数的代码,如下所示:

  1. int adb_commandline(int argc, char **argv)
  2. {
  3. char buf[4096];
  4. //...
  5. if (!strcmp(argv[0], "install")) {
  6. if (argc < 2) return usage();
  7. return install_app(ttype, serial, argc, argv);
  8. }
  9. //...
  10. if (!strcmp(argv[0], "uninstall")) {
  11. if (argc < 2) return usage();
  12. return uninstall_app(ttype, serial, argc, argv);
  13. }
  14. //...
  15. usage();
  16. return 1;
  17. }

这里继续分析uninstall_app实现,代码如下:

  1. int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
  2. {
  3. if (argc == 3 && strcmp(argv[1], "-k") == 0)
  4. {
  5. return -1;
  6. }
  7. return pm_command(transport, serial, argc, argv);
  8. }

这里比安装apk简单,主要关注pm_command方法(下面这一小段与上节相同),代码如下:

  1. static int pm_command(transport_type transport, char* serial,
  2. int argc, char** argv)
  3. {
  4. char buf[4096];
  5. snprintf(buf, sizeof(buf), "shell:pm");
  6. while(argc-- > 0) {
  7. char *quoted = escape_arg(*argv++);
  8. strncat(buf, " ", sizeof(buf) - 1);
  9. strncat(buf, quoted, sizeof(buf) - 1);
  10. free(quoted);
  11. }
  12. send_shellcommand(transport, serial, buf);
  13. return 0;
  14. }

这里调用了send_shellcommand 发送"shell:pm uninstall 参数"给手机端的adbd,这里继续分析pm命令,pm是脚本文件,构成如下:

  1. # Script to start "pm" on the device,which has a very rudimentary
  2. # shell.
  3. #
  4. base=/system
  5. export CLASSPATH=$base/frameworks/pm.jar
  6. exec app_process $base/bincom.android.commands.pm.Pm "$@"

在编译system镜像时,Android.mk中会将该脚本复制到system/bin目录下。从pm脚本的内容来看,它就是通过app_process执行pm.jar包的main函数。pm的main函数实现如下:

  1. public static void main(String[] args) {
  2. int exitCode = 1;
  3. exitCode = new Pm().run(args);
  4. //...
  5. System.exit(exitCode);
  6. }

这里的run方法实现如下(这里主要关注uninstall命令):

  1. public int run(String[] args) throws IOException, RemoteException {
  2. //...
  3. //获取UserM 和 PkgMS的binder客户端
  4. mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
  5. mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
  6. //...
  7. mInstaller = mPm.getPackageInstaller();
  8. //...
  9. //处理其他命令,这里仅考虑uninstall的处理
  10. if ("uninstall".equals(op)) {
  11. return runUninstall();
  12. }
  13. //...
  14. }

这里仅仅关注uninstall部分相关代码,runUninstall代码实现如下:

  1. private int runUninstall() throws RemoteException {
  2. int flags = 0;
  3. int userId = UserHandle.USER_ALL;
  4. //参数与错误处理...
  5. if (userId == UserHandle.USER_ALL) {
  6. userId = UserHandle.USER_OWNER;
  7. flags |= PackageManager.DELETE_ALL_USERS;
  8. } else {
  9. PackageInfo info;
  10. try {
  11. //获取package信息
  12. info = mPm.getPackageInfo(pkg, 0, userId);
  13. } catch (RemoteException e) {
  14. //...
  15. }
  16. //...
  17. final boolean isSystem =
  18. (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
  19. if (isSystem) {
  20. flags |= PackageManager.DELETE_SYSTEM_APP;
  21. }
  22. }
  23. final LocalIntentReceiver receiver = new LocalIntentReceiver();
  24. //调用PackageInstallerService的uninstall方法来处理
  25. mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId);
  26. final Intent result = receiver.getResult();
  27. final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
  28. PackageInstaller.STATUS_FAILURE);
  29. //...
  30. }

 

继续分析PackageInstallerService的uninstall方法,代码如下:

  1. public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) {
  2. mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true, "uninstall");
  3. final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
  4. statusReceiver, packageName);
  5. if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
  6. == PackageManager.PERMISSION_GRANTED) {
  7. //关键点,这里调用了PkgMS的deletePackage方法
  8. mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
  9. } else {
  10. // Take a short detour to confirm with user
  11. final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
  12. intent.setData(Uri.fromParts("package", packageName, null));
  13. intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
  14. adapter.onUserActionRequired(intent);
  15. }
  16. }

至此,从adb unistall就调用到了PkgMS的deletePackage方法。接下来会从deletePackage开始继续分析。

2 卸载应用程序(删除文件)

deletePackage函数代码实现如下:

  1. public void deletePackage(final String packageName,
  2. final IPackageDeleteObserver2 observer, final int userId, final int flags) {
  3. //检查执行权限
  4. mContext.enforceCallingOrSelfPermission(
  5. android.Manifest.permission.DELETE_PACKAGES, null);
  6. final int uid = Binder.getCallingUid();
  7. if (UserHandle.getUserId(uid) != userId) {
  8. mContext.enforceCallingPermission(
  9. android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
  10. "deletePackage for user " + userId);
  11. }
  12. //权限错误相关处理...
  13. //...
  14. // Queue up an async operation since the package deletion may take a little while.
  15. mHandler.post(new Runnable() {//post消息,在处理方法中执行卸载应用操作
  16. public void run() {
  17. mHandler.removeCallbacks(this);
  18. //调用deletePackageX执行卸载应用操作
  19. final int returnCode = deletePackageX(packageName, userId, flags);
  20. if (observer != null) {
  21. try {//回调,发送卸载应用结果
  22. observer.onPackageDeleted(packageName, returnCode, null);
  23. } catch (RemoteException e) {
  24. Log.i(TAG, "Observer no longer exists.");
  25. } //end catch
  26. } //end if
  27. } //end run
  28. });
  29. }

这里最后post了一个消息,在消息处理中继续执行卸载操作,这样避免了Binder调用的时间过长;实际卸载通过deletePackageX来完成,代码实现如下:

  1. private int deletePackageX(String packageName, int userId, int flags) {
  2. final PackageRemovedInfo info = new PackageRemovedInfo();
  3. final boolean res;
  4. final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
  5. ? UserHandle.ALL : new UserHandle(userId);
  6. //检查用户removeForUser 是否有权限删除该应用
  7. if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
  8. return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
  9. }
  10. boolean removedForAllUsers = false;
  11. boolean systemUpdate = false;
  12. // for the uninstall-updates case and restricted profiles, remember the per-
  13. // userhandle installed state
  14. int[] allUsers;
  15. boolean[] perUserInstalled;
  16. synchronized (mPackages) {
  17. //获取setting信息
  18. PackageSetting ps = mSettings.mPackages.get(packageName);
  19. //检查并记录系统中所有用户是否都安装了该应用
  20. allUsers = sUserManager.getUserIds();
  21. perUserInstalled = new boolean[allUsers.length];
  22. for (int i = 0; i < allUsers.length; i++) {
  23. perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
  24. }
  25. }
  26. synchronized (mInstallLock) {
  27. //核心,卸载应用
  28. res = deletePackageLI(packageName, removeForUser,
  29. true, allUsers, perUserInstalled,
  30. flags | REMOVE_CHATTY, info, true);
  31. //...
  32. }
  33. if (res) {
  34. //如果卸载的是某个应用升级包,这里会导致低版本的系统应用重新使用
  35. //代码发送广播通知这种变化。
  36. info.sendBroadcast(true, systemUpdate, removedForAllUsers);
  37. // If the removed package was a system update, the old system package
  38. // was re-enabled; we need to broadcast this information
  39. if (systemUpdate) {
  40. Bundle extras = new Bundle(1);
  41. extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
  42. ? info.removedAppId : info.uid);
  43. extras.putBoolean(Intent.EXTRA_REPLACING, true);
  44. sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
  45. extras, null, null, null);
  46. sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
  47. extras, null, null, null);
  48. sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
  49. null, packageName, null, null);
  50. }
  51. }
  52. //清理相关工作
  53. Runtime.getRuntime().gc();
  54. if (info.args != null) {
  55. synchronized (mInstallLock) {
  56. info.args.doPostDeleteLI(true);
  57. }
  58. }
  59. return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
  60. }

该方法搜集了应用在不同用户下的安装情况后,调用deletePackageLI方法继续执行删除操作。如果删除的是某个系统应用的升级包,这里还会发出广播通知以前的应用可以重新使用。deletePackageLI代码实现如下:

  1. private boolean deletePackageLI(String packageName, UserHandle user,...) {
  2. //...
  3. PackageSetting ps;
  4. boolean dataOnly = false;
  5. int removeUser = -1;
  6. int appId = -1;
  7. synchronized (mPackages) {
  8. ps = mSettings.mPackages.get(packageName);
  9. //...
  10. if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
  11. && user.getIdentifier() != UserHandle.USER_ALL) {
  12. //卸载某个用户下的应用
  13. ps.setUserState(user.getIdentifier(),...);
  14. if (!isSystemApp(ps)) {
  15. if (ps.isAnyInstalled(sUserManager.getUserIds())) {
  16. removeUser = user.getIdentifier();
  17. appId = ps.appId;
  18. mSettings.writePackageRestrictionsLPr(removeUser);
  19. } else {
  20. //没有用户使用,完全删除应用
  21. ps.setInstalled(true, user.getIdentifier());
  22. }
  23. } else {
  24. //只清除用户目录下的数据
  25. removeUser = user.getIdentifier();
  26. appId = ps.appId;
  27. mSettings.writePackageRestrictionsLPr(removeUser);
  28. }
  29. }
  30. }
  31. //...
  32. if (dataOnly) {
  33. //删除应用数据
  34. removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
  35. return true;
  36. }
  37. boolean ret = false;
  38. if (isSystemApp(ps)) {
  39. //删除系统应用
  40. ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
  41. flags, outInfo, writeSettings);
  42. } else {
  43. // 停止应用进程,删除文件
  44. killApplication(packageName, ps.appId, "uninstall pkg");
  45. ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,...);
  46. }
  47. return ret;
  48. }

这里主要工作是根据不同用户的安装情况来删除应用的apk文件和数据。删除的不仅有文件和数据,还要将PkgMS中缓存的应用数据也清除掉。

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/199169
推荐阅读
相关标签
  

闽ICP备14008679号