Android6.0 PackageManagerService卸载应用
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卸载应用相关推荐
- Android7.0 PackageManagerService (2) PKMS构造函数的主要工作
从本篇博客开始,我们开始分析PKMS的构造函数,看看PKMS到底是如何解析和管理手机中APK的信息的. 由于PKMS的构造函数较长,我们会分段进行研究. public PackageManagerSe ...
- Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]
摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...
- android6.0源码分析之AMS服务源码分析
activitymanagerservice服务源码分析 1.ActivityManagerService概述 ActivityManagerService(以下简称AMS)作为Android中最核心 ...
- Android6 0权限机制(一):介绍
本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布 Android6.0权限机制(一):介绍 Android6.0权限机制(二):封装 Android6.0权限机制(三):6. ...
- android 6.0编译环境,MacOS下编译Android6.0源代码
编译Android系统,只能在OS X环境下或者是Linux环境下,这篇文章,也是买Mac不久后写的,当时想顺便测试一下电脑的性能,编译Android系统要多久.整理笔记的时候发现,也就顺便发布出来. ...
- [高通SDM450][Android9.0]CTA认证--Android6.0以下应用默认不授权
文章目录 开发平台基本信息 问题描述 解决方法 开发平台基本信息 芯片: SDM450 版本: Android 9.0 kernel: msm-4.9 问题描述 设备在进行入网认证的时候,实验室要求应 ...
- android6.0 framwork修改
基于android6.0.7.01.20 默认使用Launcher2,修改Launcher2 packages/apps/Launcher3/src/com/android/launcher3/Lau ...
- Android6.0 高通平台 is 32-bit instead of 64-bit 问题
做高通项目时碰高一个问题:有些apk在32位平台上运行没问题,但是在64位平台上出现crash,出错信息如下: java.lang.UnsatisfiedLinkError: dlopen faile ...
- mt7 android6.0 回退,Mate7 M版本(Android 6.0)B553发布说明及问题反馈
[问题反馈] Mate7 M版本(Android 6.0)B553发布说明及问题反馈 856111452 电梯直达 DP手机产品经理 产品经理 发表于 2016-3-25 09:31:56 来自:浏览 ...
最新文章
- BZOJ3172 [Tjoi2013]单词 字符串 SA ST表
- Windows10下编译NCNN安卓NDK
- 云原生下,如何实现高可用的MySQL?
- mysql删除属性_SQL语句处理一些修改、新增、删除、修改属性操作(MySql)
- 洛谷3195(HNOI2008)玩具装箱
- 高空真人特技表演的这些冷知识,你都知道吗?
- 中文任务型对话系统中的领域分类
- java编译源文件_Java实现编译源文件(Java源码)
- MongoDB-数据库-mongoose-图形化操作
- Android中Menu的基本用法
- 数据访问组件SqlHelper
- 修改pip下载存放和安装位置
- 流浪宠物管理系统-基于SSM
- 已解决-Windows10没有windows照片查看器-Windows10打开照片是黑底的
- GigabitEthernet和Ethernet接口的区别
- php直接拨号代码,c#自动ADSL拨号代码
- 初中OJ1998【2015.8.3普及组模拟赛】饥饿的WZK(hunger)
- Jetson nano串口的使用——UART
- socket 编程基础
- 浙江大学电子信息计算机,浙江大学城市学院计算机与计算科学学院 党政办 计算学院新增12名浙江大学电子信息专业硕士研究生导师...
热门文章
- 如何选择接口自动化测试工具
- 安装python模块
- 移除Selenium的浏览器window.navigator.webdriver等20多个指纹特征
- 颐和园终于上CSDN头条了
- java框架之ArrayList集合类及常用方法
- RS485电压测试(电工Demo)
- 计算机图形学笔记——第7章 二维几何变换 Python
- springboot使用拦截器拦截验证签名sign
- Android模仿奇怪的大冒险主界面表情变化
- linux版笔记本如何装win10,Linux系统的笔记本是什么样的?如何装Win10?这里给你详细解答...