文章目录

  • 如果在手机中卸载会有提示卸载页面等,这个一般是 UninstallerActivity;在这里点击卸载调用的是下面代码:
ActivityThread.getPackageManager().getPackageInstaller().uninstall(new VersionedPackage(mDialogInfo.appInfo.packageName,PackageManager.VERSION_CODE_HIGHEST),getPackageName(), flags, pendingIntent.getIntentSender(),mDialogInfo.user.getIdentifier());

上面代码是IPC操作 getPackageManager() 为下面代码

    public static IPackageManager getPackageManager() {if (sPackageManager != null) {//Slog.v("PackageManager", "returning cur default = " + sPackageManager);return sPackageManager;}IBinder b = ServiceManager.getService("package");//Slog.v("PackageManager", "default service binder = " + b);sPackageManager = IPackageManager.Stub.asInterface(b);//Slog.v("PackageManager", "default service = " + sPackageManager);return sPackageManager;}

对应的IPackageManager 就是 PMS;所以调用的 PMS 中的 getPackageInstaller() ,代码如下:

    @Overridepublic IPackageInstaller getPackageInstaller() {if (getInstantAppPackageName(Binder.getCallingUid()) != null) {return null;}return mInstallerService;}

mInstallerService 为 PackageInstallerService ,所以看一下 PackageInstallerService 中的 uninstall() 方法

PackageInstallerService >> uninstall()

@Overrideprivate final PackageManagerService mPm;public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,IntentSender statusReceiver, int userId) throws RemoteException {// 先获取 UIDfinal int callingUid = Binder.getCallingUid();// 检查执行权限mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {mAppOps.checkPackage(callingUid, callerPackageName);}// Check whether the caller is device owner or affiliated profile owner, in which case we do// it silently.final int callingUserId = UserHandle.getUserId(callingUid);DevicePolicyManagerInternal dpmi =LocalServices.getService(DevicePolicyManagerInternal.class);final boolean isDeviceOwnerOrAffiliatedProfileOwner =dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)&& dpmi.isUserAffiliatedWithDevice(callingUserId);final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,statusReceiver, versionedPackage.getPackageName(),isDeviceOwnerOrAffiliatedProfileOwner, userId);if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)== PackageManager.PERMISSION_GRANTED) {// Sweet, call straight through!// 调用 mPm mPm.deletePackageVersioned mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);} else if (isDeviceOwnerOrAffiliatedProfileOwner) {// Allow the device owner and affiliated profile owner to silently delete packages// Need to clear the calling identity to get DELETE_PACKAGES permissionlong ident = Binder.clearCallingIdentity();try {mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);} finally {Binder.restoreCallingIdentity(ident);}} else {// 需要和用户确认卸载消息ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,null);}// Take a short detour to confirm with userfinal Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());adapter.onUserActionRequired(intent);}}

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

  • deletePackageVersioned() 主要功能
    @Overridepublic void deletePackageVersioned(VersionedPackage versionedPackage,final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {// 获取 UIDfinal int callingUid = Binder.getCallingUid();// 检查权限mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES, null);// 。。。// 。。。// 卸载应用是耗时的 所以开启异步线程mHandler.post(new Runnable() {public void run() {// 为了防止重复发送mHandler.removeCallbacks(this);int returnCode;// ...// ...// 最后就是调用了 deletePackageX returnCode = deletePackageX(internalPackageName, versionCode,userId, deleteFlags);});}
  • deletePackageX()
    int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {final PackageRemovedInfo info = new PackageRemovedInfo(this);final boolean res;final int removeUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0? UserHandle.USER_ALL : userId;// 检查该用户是否有删除这个应用的权限if (isPackageDeviceAdmin(packageName, removeUser)) {Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;}PackageSetting uninstalledPs = null;PackageParser.Package pkg = null;// for the uninstall-updates case and restricted profiles, remember the per-// user handle installed stateint[] allUsers;synchronized (mPackages) {// 获取应用在 mSettings 中的信息uninstalledPs = mSettings.mPackages.get(packageName);if (uninstalledPs == null) {return PackageManager.DELETE_FAILED_INTERNAL_ERROR;}if (versionCode != PackageManager.VERSION_CODE_HIGHEST&& uninstalledPs.versionCode != versionCode) {return PackageManager.DELETE_FAILED_INTERNAL_ERROR;}pkg = mPackages.get(packageName);allUsers = sUserManager.getUserIds();if (pkg != null && pkg.staticSharedLibName != null) {SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(pkg.staticSharedLibName,pkg.staticSharedLibVersion);if (libEntry != null) {for (int currUserId : allUsers) {if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) {continue;}List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(libEntry.info, 0, currUserId);if (!ArrayUtils.isEmpty(libClientPackages)) {return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;}}}}info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);}final int freezeUser;if (isUpdatedSystemApp(uninstalledPs)&& ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {freezeUser = UserHandle.USER_ALL;} else {freezeUser = removeUser;}synchronized (mInstallLock) {try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,deleteFlags, "deletePackageX")) {// 调用 deletePackageLIF 完成卸载应用res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);}synchronized (mPackages) {if (res) {if (pkg != null) {mInstantAppRegistry.onPackageUninstalledLPw(pkg, info.removedUsers);}updateSequenceNumberLP(uninstalledPs, info.removedUsers);updateInstantAppInstallerLocked(packageName);}}}if (res) {final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0;info.sendPackageRemovedBroadcasts(killApp);info.sendSystemPackageUpdatedBroadcasts();info.sendSystemPackageAppearedBroadcasts();}// 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);}}return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;}
  • deletePackageLIF()
    private boolean deletePackageLIF(String packageName, UserHandle user,boolean deleteCodeAndResources, int[] allUserHandles, int flags,PackageRemovedInfo outInfo, boolean writeSettings,PackageParser.Package replacingPackage) {// ...// ...if (((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null&& user.getIdentifier() != UserHandle.USER_ALL)) {// 调用者要求仅为单个用户删除包。// 为此,我们只需标记其已卸载状态并删除其数据。// 如果这是一个系统应用程序,只是标记状态和删除数据// 如果他们设置了特殊的DELETE_SYSTEM_APP,则将调用不同的方式卸载系统app// 设置一些状态属性markPackageUninstalledForUserLPw(ps, user);// 判断是不是系统 appif (!isSystemApp(ps)) {// Do not uninstall the APK if an app should be cachedboolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName);// 如果调用者只要求卸载某个用户下的应用if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) {// Other user still have this package installed, so all// we need to do is clear this user's data and save that// it is uninstalled.// 其他用户仍然安装了这个包,所以我们需要做的就是清除该用户的数据,并将其保存为已卸载。if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");if (!clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo)) {return false;}scheduleWritePackageRestrictionsLocked(user);return true;} else {// We need to set it back to 'installed' so the uninstall// broadcasts will be sent correctly.if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");ps.setInstalled(true, user.getIdentifier());mSettings.writeKernelMappingLPr(ps);}} else {// This is a system app, so we assume that the// other users still have this package installed, so all// we need to do is clear this user's data and save that// it is uninstalled.// 如果是系统应用程序,因此我们假设其他用户仍然安装了这个包,因此我们需要做的就是清除该用户的数据,并保存为已卸载。if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");if (!clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo)) {return false;}scheduleWritePackageRestrictionsLocked(user);return true;}}// 安装的时候有安装包集 卸载也一样 查看packageSetting 下是否是复合包if (ps.childPackageNames != null && outInfo != null) {synchronized (mPackages) {final int childCount = ps.childPackageNames.size();outInfo.removedChildPackages = new ArrayMap<>(childCount);for (int i = 0; i < childCount; i++) {String childPackageName = ps.childPackageNames.get(i);PackageRemovedInfo childInfo = new PackageRemovedInfo(this);childInfo.removedPackage = childPackageName;childInfo.installerPackageName = ps.installerPackageName;outInfo.removedChildPackages.put(childPackageName, childInfo);PackageSetting childPs = mSettings.getPackageLPr(childPackageName);if (childPs != null) {childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);}}}}boolean ret = false;if (isSystemApp(ps)) {if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);// 当一个更新的系统应用程序被删除时,我们也会删除现有的资源 设置一下分区ret = deleteSystemPackageLIF(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);} else {// kill app ; 删除非系统的包和资源 ;删除各种缓存 和 为package.xml  packageSetting 修改对应的数据等ret = deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,outInfo, writeSettings, replacingPackage);}// ...// ...}

整体流程是根据不用用户删除app和数据;包括 package 和 PMS 等缓存数据等。

android 卸载应用流程相关推荐

  1. 一篇文章看明白 Android PackageManagerService 工作流程

    Android - PackageMangerService 分析 相关系列 一篇文章看明白 Android 系统启动时都干了什么 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制 ...

  2. Android手机启动流程与TEE OS

    2019独角兽企业重金招聘Python工程师标准>>> 转载:https://cloud.tencent.com/developer/article/1043659 一个移植了TEE ...

  3. Android View 测量流程(Measure)完全解析

    前言 上一篇文章,笔者主要讲述了DecorView以及ViewRootImpl相关的作用,这里回顾一下上一章所说的内容:DecorView是视图的顶级View,我们添加的布局文件是它的一个子布局,而V ...

  4. android activity启动流程_1307页!一线大厂Android面试全套真题解析!

    /   前言   / 金九银十到了,很多读者都反映有面试的需求,所以我特地给大家准备了一点资料! 下面的题目都是大家在面试一线互联网大厂时经常遇到的面试真题和答案解析,如果大家还有其他好的题目或者好的 ...

  5. 【Android 逆向】加壳的 Android 应用启动流程 | 使用反射替换 LoadedApk 中的类加载器流程

    文章目录 一.加壳的 Android 应用启动流程 二.使用反射替换 LoadedApk 中的类加载器流程 一.加壳的 Android 应用启动流程 加壳的 Android 应用启动流程 : 加壳的 ...

  6. 【Android 逆向】Android 进程简介 ( Android 应用启动流程 )

    文章目录 前言 一.Android 进程 二.Android 应用启动流程 前言 参考 [Android 逆向]Android 系统文件分析 ( /proc/pid 进程号对应进程目录 | oom_a ...

  7. 结合源码深入理解Android Crash处理流程

    应用程序crash在开发过程中还是很常见的,本文主要是从源码的角度去跟踪下Android对于crash的处理流程.App crash的全称:Application crash.而Crash又分为:na ...

  8. Android Camera(5)---Android Camera调用流程

    Android Camera调用流程 http://blog.csdn.net/lushengchu_luis/article/details/11033095 1.Packages/apps/到fr ...

  9. android关机充电流程、充电画面显示

    一.Android正常开机流程.关机充电流程 在写这篇文章之前我们先看两个流程:正常开机流程,关机充电系统启动流程 1.正常开机流程,按开机键. 可大致分成三部分 (1).OS_level:UBOOT ...

最新文章

  1. 【C++】C++11 STL算法(十):使用STL实现排序算法
  2. Visual Studio 2010构建Web浏“.NET研究”览器应用程序
  3. 阿里云首发Dubbo3.0 + Nacos2.0
  4. 刷光借呗额度之后用户突然去世,支付宝会怎么做?
  5. 手机照片丢失或误删如何恢复
  6. Centos中查找文件、目录、内容
  7. Angular v6 正式发布
  8. LKMs:Loadable Kernel Modules
  9. 后台给前台传值 php,前后台传值的几种方式(html,js,php)
  10. python中的编码和解码_Python中“is”和“==”之间的区别,以及编码和解码,与
  11. (篇七)输入任意个数字,输出最大值最小值,且进行排序排序
  12. mysql swarm_【Docker】 Swarm简单介绍
  13. WCF从理论到实践(10):异常处理 (转)
  14. 如何调试一个无法重现的错误?
  15. x390开机键_【ThinkPadX390评测】ThinkPad X390 4G版全球首测:全时在线超长续航的便携商务利器(全文)_ThinkPad X390_笔记本评测-中关村在线...
  16. IT技术人,不可有傲气,但须有傲骨
  17. 网络精英赛模拟练习(8)
  18. 2018杭州·云栖大会:一文直击地表最强黑科技
  19. CRM系统操作权限的实现
  20. android调用高德地图接口,调用高德地图Api

热门文章

  1. JavaFX+SpringBoot+验证码功能的小型薪酬管理系统
  2. 使用WINHEX对回收站清除的文件进行恢复
  3. 算法工程师八股文——序言
  4. 华硕无畏Pro14和 联想小新pro14参数对比 哪个好
  5. Android 5.0 Launcher客制化定制之 主题包协议(MIUI主题、乐蛙主题兼容)
  6. 沙盒不再高端,Windows11将自带沙盒让程序检测更方便
  7. egret 白鹭引擎遇到的问题和解决方案
  8. java下载文件下载不动_java文件下载的问题
  9. 台式计算机参考配置清单,台式电脑中等配置清单
  10. [转载]2011年普通高等等学校招生全国统一考试英语试卷