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. BZOJ3172 [Tjoi2013]单词 字符串 SA ST表
  2. Windows10下编译NCNN安卓NDK
  3. 云原生下,如何实现高可用的MySQL?
  4. mysql删除属性_SQL语句处理一些修改、新增、删除、修改属性操作(MySql)
  5. 洛谷3195(HNOI2008)玩具装箱
  6. 高空真人特技表演的这些冷知识,你都知道吗?
  7. 中文任务型对话系统中的领域分类
  8. java编译源文件_Java实现编译源文件(Java源码)
  9. MongoDB-数据库-mongoose-图形化操作
  10. Android中Menu的基本用法
  11. 数据访问组件SqlHelper
  12. 修改pip下载存放和安装位置
  13. 流浪宠物管理系统-基于SSM
  14. 已解决-Windows10没有windows照片查看器-Windows10打开照片是黑底的
  15. GigabitEthernet和Ethernet接口的区别
  16. php直接拨号代码,c#自动ADSL拨号代码
  17. 初中OJ1998【2015.8.3普及组模拟赛】饥饿的WZK(hunger)
  18. Jetson nano串口的使用——UART
  19. socket 编程基础
  20. 浙江大学电子信息计算机,浙江大学城市学院计算机与计算科学学院 党政办 计算学院新增12名浙江大学电子信息专业硕士研究生导师...

热门文章

  1. 如何选择接口自动化测试工具
  2. 安装python模块
  3. 移除Selenium的浏览器window.navigator.webdriver等20多个指纹特征
  4. 颐和园终于上CSDN头条了
  5. java框架之ArrayList集合类及常用方法
  6. RS485电压测试(电工Demo)
  7. 计算机图形学笔记——第7章 二维几何变换 Python
  8. springboot使用拦截器拦截验证签名sign
  9. Android模仿奇怪的大冒险主界面表情变化
  10. linux版笔记本如何装win10,Linux系统的笔记本是什么样的?如何装Win10?这里给你详细解答...