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 firstif (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 partitionret = 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// readersynchronized (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 packageoutInfo.isRemovedPackageSystemUpdate = true;if (disabledPs.versionCode < newPs.versionCode) {// Delete data for downgradesflags &= ~PackageManager.DELETE_KEEP_DATA;//是否保留资源} else {// Preserve data by setting flagflags |= PackageManager.DELETE_KEEP_DATA;}boolean ret = deleteInstalledPackageLI(newPs, true, flags,//卸载apkallUserHandles, perUserInstalled, outInfo, writeSettings);if (!ret) {return false;}// writersynchronized (mPackages) {// Reinstate the old system packagemSettings.enableSystemPackageLPw(newPs.name);// Remove any native libraries from the upgraded package.NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);}// Install the system packageint 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;}// writersynchronized (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 persistedmSettings.writeAllUsersPackageRestrictionsLPr();}// can downgrade to reader hereif (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 setremovePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings);// Delete application code and resourcesif (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 onfinal PackageSetting deletedPs;   // readersynchronized (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);}// writersynchronized (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() {@Overridepublic 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 packageif (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 readerif (writeSettings) {// Save settings nowmSettings.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 deletingList<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);}

cleanUp函数就是删除apk文件。

        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;}

Android6.0 PackageManagerService卸载应用相关推荐

  1. Android7.0 PackageManagerService (2) PKMS构造函数的主要工作

    从本篇博客开始,我们开始分析PKMS的构造函数,看看PKMS到底是如何解析和管理手机中APK的信息的. 由于PKMS的构造函数较长,我们会分段进行研究. public PackageManagerSe ...

  2. Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]

    摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...

  3. android6.0源码分析之AMS服务源码分析

    activitymanagerservice服务源码分析 1.ActivityManagerService概述 ActivityManagerService(以下简称AMS)作为Android中最核心 ...

  4. Android6 0权限机制(一):介绍

    本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布 Android6.0权限机制(一):介绍 Android6.0权限机制(二):封装 Android6.0权限机制(三):6. ...

  5. android 6.0编译环境,MacOS下编译Android6.0源代码

    编译Android系统,只能在OS X环境下或者是Linux环境下,这篇文章,也是买Mac不久后写的,当时想顺便测试一下电脑的性能,编译Android系统要多久.整理笔记的时候发现,也就顺便发布出来. ...

  6. [高通SDM450][Android9.0]CTA认证--Android6.0以下应用默认不授权

    文章目录 开发平台基本信息 问题描述 解决方法 开发平台基本信息 芯片: SDM450 版本: Android 9.0 kernel: msm-4.9 问题描述 设备在进行入网认证的时候,实验室要求应 ...

  7. android6.0 framwork修改

    基于android6.0.7.01.20 默认使用Launcher2,修改Launcher2 packages/apps/Launcher3/src/com/android/launcher3/Lau ...

  8. Android6.0 高通平台 is 32-bit instead of 64-bit 问题

    做高通项目时碰高一个问题:有些apk在32位平台上运行没问题,但是在64位平台上出现crash,出错信息如下: java.lang.UnsatisfiedLinkError: dlopen faile ...

  9. mt7 android6.0 回退,Mate7 M版本(Android 6.0)B553发布说明及问题反馈

    [问题反馈] Mate7 M版本(Android 6.0)B553发布说明及问题反馈 856111452 电梯直达 DP手机产品经理 产品经理 发表于 2016-3-25 09:31:56 来自:浏览 ...

最新文章

  1. java字符串统计英文字符用什么不同_JAVA程序。输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。...
  2. 如果当前没有拿得出手的简历,也别慌,努力的话最多两年情况就能改变
  3. 计算机前端专业术语,学习计算机知识必须懂得50个专业术语
  4. arcgis开发常用源码
  5. BZOJ 1101: [POI2007]Zap
  6. Spring RESTFul Client – RestTemplate Example--转载
  7. Java集合HashMap
  8. 数据挖掘竞赛-员工离职预测训练赛
  9. 什么是IP地址、子网掩码、路由和网关?
  10. Linux---主机字节序与网络字节序
  11. 小小c#算法题 - 1 - 找出数组中满足条件的两个数
  12. Ubuntu18环境下安装ROS
  13. tcpip详解卷一第3章(1)
  14. 6950有史以来最经典玩机宝典/软件包/导航
  15. 透过案例--了解循环栅栏
  16. php实现支付宝对账单打通
  17. [NOIP模拟16]题解
  18. ON-LSTM:用有序神经元表达层次结构
  19. 程序员用简单C语言一顿神操作,瞬间打造植物大战僵尸,无人不服
  20. 周周有惊喜奖,第三期开奖名单 --2007中国软件开发者大调查

热门文章

  1. 钢筋施工及常用文档表格
  2. FGH60N60-ASEMI大功率IGBT管FGH60N60
  3. CAUC数据结构与算法期末复习归纳(二)
  4. 陕西计算机中专学校有哪些,陕西省公办中专学校有哪些 中专好就业的专业
  5. 无线摄像头接有线如何改协议_一对无线网桥能传几个摄像机图像?1公里的无线网桥能传8个400万摄像机吗?...
  6. 面试题和问题总结-面试题
  7. 港科夜闻|香港科技大学副校长(研究及发展)叶玉如教授团队成功开发出简单有效的血液检测方法...
  8. 商标权的一般特征是哪几种
  9. 合肥学计算机的职业学校,合肥计算机专业专科学校排名
  10. 项目经理成长日记(1)—— 启言