Android PackageManagerService总结(五) APK卸载流程

一. 概述


        PackageManagerService(简称PKMS),是Android系统中核心服务之一,管理着所有与package相关的工作,常见的比如安装、卸载应用, 信息查询等工作, 主要完成以下核心功能

1. 解析AndroidManifest.xml清单文件,解析清单文件中的所有节点信息

2. 扫描本地文件,主要针对apk,主要是系统应用、本地安装应用等。

3. 管理本地apk,主要包括安装、删除等等

4. 管理设备上安装的所有应用程序,并在系统启动时加载应用程序

5. 根据请求的Intent匹配到对应的Activity、Provider、Service,提供包含包名和Component的信息对象

6. 调用需要权限的系统函数时,检查程序是否具备相应权限从而保证系统安全

7. 提供应用程序的安装、卸载的接口


本篇文章重点介绍一下apk卸载流程

二. 卸载流程

2.1 Settings界面---->PackageInstaller界面

卸载一个apk的方式:

1. 长按apk拖住移动到最上栏,就可以卸载

2. 长按apk,点击下方的应用信息,跳转到设置中的应用信息界面   点击中间的按钮卸载

3.  设置--应用和通知--打开应用信息列表----选择apk, 弹出应用信息界面, 点击中间的卸载按钮

应用信息界面,对应的文件是

packages/apps/Settings/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java

卸载按钮对应的代码

@Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        if (isAvailable()) {
            mButtonsPref = ((ActionButtonsPreference) screen.findPreference(
                    KEY_ACTION_BUTTONS))
                     //打开按钮
                    .setButton1Text(R.string.launch_instant_app)
                    .setButton1Icon(R.drawable.ic_settings_open)
                    .setButton1OnClickListener(v -> launchApplication())
                     //卸载按钮
                    .setButton2Text(R.string.uninstall_text)
                    .setButton2Icon(R.drawable.ic_settings_delete)
                    .setButton2OnClickListener(new UninstallAndDisableButtonListener())
                     //强行停止按钮
                    .setButton3Text(R.string.force_stop)
                    .setButton3Icon(R.drawable.ic_settings_force_stop)
                    .setButton3OnClickListener(new ForceStopButtonListener())
                    .setButton3Enabled(false);
        }
    }

点击卸载事件处理: 

 private class UninstallAndDisableButtonListener implements View.OnClickListener {

    final String packageName = mAppEntry.info.packageName;
.....

     } else {
         //走这里的逻辑
         uninstallPkg(packageName, false, false);
     }
}

继续看uninstallPkg方法:

 void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
        stopListeningToPackageRemove();
        // Create new intent to launch Uninstaller activity
        Uri packageUri = Uri.parse("package:" + packageName);
        Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
        uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);

        mMetricsFeatureProvider.action(
                mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP);
        mFragment.startActivityForResult(uninstallIntent, mRequestUninstall);
        mDisableAfterUninstall = andDisable;
    }

封装了一个ACTION为Intent.ACTION_UNINSTALL_PACKAGE的intent,我们全局搜索源码,发现只有一个Activity匹配上,那就是com.android.packageinstaller 中的 UninstallerActivity.java

/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java

然后呈现给用户的界面图如下:

 如果点击确定按钮,就开始卸载

确定按钮的逻辑在:

frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java中

  @Override
    public void onClick(DialogInterface dialog, int which) {
        if (which == Dialog.BUTTON_POSITIVE) {
            ((UninstallerActivity) getActivity()).startUninstallProgress(
                    mKeepData != null && mKeepData.isChecked());
        } else {
            ((UninstallerActivity) getActivity()).dispatchAborted();
        }
    }

回到UninstallerActivity.java中的startUninstallProgress()方法中

 public void startUninstallProgress(boolean keepData) {
....
    //我是用手机调试的,不是TV设备, 通过判断条件它走的是else分支
    } else if (returnResult || mDialogInfo.callback != null || getCallingActivity() != null) {
            Intent newIntent = new Intent(this, UninstallUninstalling.class);
....
}

然后跳转到UninstallUninstalling.java中, 我们来看看其onCreate方法

/frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setFinishOnTouchOutside(false);
.....
        try {
                        ActivityThread.getPackageManager().getPackageInstaller().uninstall(
                            new VersionedPackage(mAppInfo.packageName,
                                    PackageManager.VERSION_CODE_HIGHEST),
                            getPackageName(), flags, pendingIntent.getIntentSender(),
                            user.getIdentifier());
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
.....
}

通过IPackageInstaller.java这个接口实现跨进程通信,此时的客户端为PackageInstaller.apk,          服务端为 PackageInstallerService.java , 就直接调用到 PackageInstallerService.java中的 uninstall方法中去了

好了到这里,先梳理一下应用层的逻辑,时序图为:

2.2   PackageInstallerService >>> uninstall()

继续上一小结分析

进入到frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java

 @Override
    public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
                IntentSender statusReceiver, int userId) {
        // 先获取 UID
        final int callingUid = Binder.getCallingUid();
        // 检查执行权限
        mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
        //创建PackageDeleteObserverAdapter对象,用于接收响应删除的结果
        final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                statusReceiver, versionedPackage.getPackageName(),
                canSilentlyInstallPackage, 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);
......
}

这个方法主要做了3件事情:

1. 创建PackageDeleteObserverAdapter对象,用于接收响应删除的结果
2. 检查当前程序是否具有删除权限, 如果有的话,就调用 mPm.deletePackageVersioned方法
3. 调用PMS的deletePackageVersioned()方法执行程序的卸载 

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

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

 @Override
public void deletePackageVersioned(VersionedPackage versionedPackage,
            final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
    
    mHandler.post(() -> {
            int returnCode;
            final PackageSetting ps =     mSettings.mPackages.get(internalPackageName);
            boolean doDeletePackage = true;
            if (ps != null) {
                final boolean targetIsInstantApp =
                        ps.getInstantApp(UserHandle.getUserId(callingUid));
                doDeletePackage = !targetIsInstantApp
                        || canViewInstantApps;
            }
            if (doDeletePackage) {
                if (!deleteAllUsers) {
                    //走这里的逻辑
                    returnCode = deletePackageX(internalPackageName, versionCode,
                            userId, deleteFlags);
                } else {


     try {
                //删除apk后的回调方法
                observer.onPackageDeleted(packageName, returnCode, null);
            } catch (RemoteException e) {
                Log.i(TAG, "Observer no longer exists.");
            } //end catch

}
在deletePackageVersioned()中发送Post事件执行异步删除操作,在Handler事件中调用
deletePackageX()方法
int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
....
      
      if (isPackageDeviceAdmin(packageName, removeUser)) {
            Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
            return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
        }


    synchronized (mInstallLock) {
            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
            try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
                    deleteFlags, "deletePackageX")) {
                //调用这个方法
                res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
                        deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);
            }
....
}

在deletePackageX()中首先判断要卸载的程序是否是admin管理的,如果是则直接return,如果不是则执行deletePackageLIF()方法继续卸载程序

 private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
            boolean deleteCodeAndResources, int[] allUserHandles, int flags,
            PackageRemovedInfo outInfo, boolean writeSettings,
            PackageParser.Package replacingPackage) {
.....
    try {
            executeDeletePackageLIF(action, packageName, deleteCodeAndResources,
                    allUserHandles, writeSettings, replacingPackage);
        } catch (SystemDeleteException e) {
            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e);
            return false;
        }
.....
}

执行到executeDeletePackageLIF方法中

笔者用的是展锐平台的代码跟踪的流程, 这个executeDeletePackageLIF方法和源码命名不一致,但是整体流程的逻辑没有太大差别

private void executeDeletePackageLIF(DeletePackageAction action,
            String packageName, boolean deleteCodeAndResources,
            int[] allUserHandles, boolean writeSettings,
            PackageParser.Package replacingPackage) throws SystemDeleteException {
....
    //是否是系统app
    final boolean systemApp = isSystemApp(ps);
    



      // TODO(b/109941548): break reasons for ret = false out into mayDelete method
     if (systemApp) {
            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 partition
            deleteSystemPackageLIF(action, ps, allUserHandles, flags, outInfo, writeSettings);
        } else {
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
            /* SPRD: Add for boot performance with multi-thread and preload scan @{*/
            if(ps.pkg != null && ps.pkg.baseCodePath != null){
                String path = ps.pkg.baseCodePath.substring(0, ps.pkg.baseCodePath.lastIndexOf("/"));
                if(PackageManager.isPreloadOrVitalApp(path)) mPackageManagerServiceExUtils.delAppRecord(ps.pkg.packageName, flags);
            }
            /* @} */
            //我删除的就是一个普通的第三方apk,所以走的是这里的流程
            deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
                    outInfo, writeSettings, replacingPackage);
        }
....
}

在executeDeletePackageLIF函数中根据是否是systemApp调用不同的流程,如果是systemApp,则调用deleteSystemPackageLIF完成卸载;如果非systemApp,则调用deleteInstalledPackageLIF完成卸载,当然在卸载之前,首先会调用AMS的killApplication方法先让这个APP停止运行, 我们继续来分析deleteInstalledPackageLIF 这个方法

private void deleteInstalledPackageLIF(PackageSetting ps,
            boolean deleteCodeAndResources, int flags, int[] allUserHandles,
            PackageRemovedInfo outInfo, boolean writeSettings,
            PackageParser.Package replacingPackage) {
.....
  // Delete package data from internal structures and also remove data if flag is set     
//从内部结构中删除包数据,如果设置了标志,也删除数据
        removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);


.....
}

我们重点来看一下这个方法removePackageDataLIF

private void removePackageDataLIF(PackageSetting ps, int[] allUserHandles,
		PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
	String packageName = ps.name;
	if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
	// 检索对象以稍后删除共享用户的权限
	final PackageParser.Package deletedPkg;
	final PackageSetting deletedPs;
	// reader
	synchronized (mPackages) {
		deletedPkg = mPackages.get(packageName);
		deletedPs = mSettings.mPackages.get(packageName);
		if (outInfo != null) {
			outInfo.removedPackage = packageName;
			outInfo.installerPackageName = ps.installerPackageName;
			outInfo.isStaticSharedLib = deletedPkg != null
					&& deletedPkg.staticSharedLibName != null;
			outInfo.populateUsers(deletedPs == null ? null
					: deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true), deletedPs);
		}
	}
	//注释1 删除数据
	removePackageLI(ps, (flags & FLAGS_REMOVE_CHATTY) != 0);
 
	if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
		final PackageParser.Package resolvedPkg;
		if (deletedPkg != null) {
			resolvedPkg = deletedPkg;
		} else {
			// We don't have a parsed package when it lives on an ejected
			// adopted storage device, so fake something together
			resolvedPkg = new PackageParser.Package(ps.name);
			resolvedPkg.setVolumeUuid(ps.volumeUuid);
		}
		//注释二 删除目录和配置文件
		destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
				StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
		destroyAppProfilesLIF(resolvedPkg, UserHandle.USER_ALL);
		if (outInfo != null) {
			outInfo.dataRemoved = true;
		}
	}
 
	int removedAppId = -1;
 
	// writer
	synchronized (mPackages) {
		boolean installedStateChanged = false;
		if (deletedPs != null) {
			if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
				clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
				clearDefaultBrowserIfNeeded(packageName);
				mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
               //移除mSetting中保存的数据
				removedAppId = mSettings.removePackageLPw(packageName);
				if (outInfo != null) {
					outInfo.removedAppId = removedAppId;
				}
				//更新权限信息
				updatePermissionsLPw(deletedPs.name, null, 0);
				if (deletedPs.sharedUser != null) {
					//删除与包关联的权限。由于运行时权限是按用户分配的,
					//所以如果撤销仅由已删除的包请求的权限成功且这将导致gids的更改,
					//则必须终止已删除的包或在已删除包的共享用户下运行的包。
					for (int userId : UserManagerService.getInstance().getUserIds()) {
						final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
								userId);
						if (userIdToKill == UserHandle.USER_ALL
								|| userIdToKill >= UserHandle.USER_SYSTEM) {
							// 如果为这个用户更改了gid,则杀死所有受影响的包。
							mHandler.post(new Runnable() {
								@Override
								public void run() {
									// 这必须在没有持有锁的情况下发生。这里是上文提到的
//杀掉应用的地方
									killApplication(deletedPs.name, deletedPs.appId,
											KILL_APP_REASON_GIDS_CHANGED);
								}
							});
							break;
						}
					}
				}
				clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
			}
			// 如果删除只是将系统应用程序降级到工厂包,请确保保留每个用户禁用状态
			if (allUserHandles != null && outInfo != null && outInfo.origUsers != null) {
				if (DEBUG_REMOVE) {
					Slog.d(TAG, "Propagating install state across downgrade");
				}
				for (int userId : allUserHandles) {
					final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
					if (DEBUG_REMOVE) {
						Slog.d(TAG, "    user " + userId + " => " + installed);
					}
					if (installed != ps.getInstalled(userId)) {
						installedStateChanged = true;
					}
					ps.setInstalled(installed, userId);
				}
			}
		}
		// can downgrade to reader
		if (writeSettings) {
			//写入mSettings信息,更新Package.xml文件
			mSettings.writeLPr();
		}
		if (installedStateChanged) {
			mSettings.writeKernelMappingLPr(ps);
		}
	}
	if (removedAppId != -1) {
		// A user ID was deleted here. Go through all users and remove it
		// from KeyStore.
        //此处删除了用户ID。浏览所有用户并将其从KeyStore中删除
		removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId);
	}
}

removePackageDataLIF用于删除应用的/data/data数据目录,并且从PMS内部数据结构里面清除package的信息。首先调用removePackageLI从PMS内部的数据结构上删除要卸载的package信息

继续分析注释1处的删除数据的方法   removePackageLI

void removePackageLI(String packageName, boolean chatty) {
        if (DEBUG_INSTALL) {
            if (chatty)
                Log.d(TAG, "Removing package " + packageName);
        }

        // writer
        synchronized (mPackages) {
            final PackageParser.Package removedPackage = mPackages.remove(packageName);
            if (removedPackage != null) {
                //调用这个方法 删除四大组件相关的信息
                cleanPackageDataStructuresLILPw(removedPackage, chatty);
            }
        }
    }

cleanPackageDataStructuresLILPw用于将package的providers、services、receivers、activities等信息去PMS的全局数据结构上移除,可以看看log打印

adb logcat -s PackageManager

接下来回到removePackageDataLIF中 注释二处

调用destroyAppDataLIF和destroyAppProfilesLIF去删除/data/data下面的目录

destroyAppDataLIF主要顺序

  • destroyAppDataLeafLIF
  • destroyAppData
private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
        final PackageSetting ps;
        synchronized (mPackages) {
            ps = mSettings.mPackages.get(pkg.packageName);
        }
        for (int realUserId : resolveUserIds(userId)) {
            final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
            try {
                mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
                        ceDataInode);
            } catch (InstallerException e) {
                Slog.w(TAG, String.valueOf(e));
            }
            mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
        }
 }

通过 mInstaller.destroyAppData方法, 跳转到 Installer.java

 /frameworks/base/services/core/java/com/android/server/pm/ Installer.java

    public void destroyAppData(String uuid, String packageName, int userId, int flags,
            long ceDataInode) throws InstallerException {
        if (!checkBeforeRemote()) return;
        try {
            mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
    }

然后在Installd 守护进程执行删除app数据的动作,具体文件和方法:

跨进程调用InstalldNativeService.cpp 的destroyAppData方法

frameworks/native/cmds/installd/InstalldNativeService.cpp 

binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std::string>& uuid,
        const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID(uuid);
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
    std::lock_guard<std::recursive_mutex> lock(mLock);

    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
    const char* pkgname = packageName.c_str();

    binder::Status res = ok();
    if (flags & FLAG_STORAGE_CE) {
        auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
        if (delete_dir_contents_and_dir(path) != 0) {
            res = error("Failed to delete " + path);
        }
    }
    if (flags & FLAG_STORAGE_DE) {
        auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
        if (delete_dir_contents_and_dir(path) != 0) {
            res = error("Failed to delete " + path);
        }
        destroy_app_current_profiles(packageName, userId);
        // TODO(calin): If the package is still installed by other users it's probably
        // beneficial to keep the reference profile around.
        // Verify if it's ok to do that.
        destroy_app_reference_profile(packageName);
    }
    if (flags & FLAG_STORAGE_EXTERNAL) {
        std::lock_guard<std::recursive_mutex> lock(mMountsLock);
        for (const auto& n : mStorageMounts) {
            auto extPath = n.second;
            if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) {
                extPath += StringPrintf("/%d", userId);
            } else if (userId != 0) {
                // TODO: support devices mounted under secondary users
                continue;
            }
            auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete contents of " + path);
            }
            path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete contents of " + path);
            }
            path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
            if (delete_dir_contents_and_dir(path, true) != 0) {
                res = error("Failed to delete contents of " + path);
            }
        }
    }
    return res;
}

笔者c++的基础一般,看源代码也只能大致猜测处理逻辑, 意思就是:

create_data_user_ce_package_path方法构造/data/data/packageName的文件路径名,然后调用delete_dir_contents_and_dir来删除文件内容以及目录(比如Android/data/包名/, 

Android/media/包名,  Android/obb/包名/ 路径下的文件),前面介绍过,/data/data/packageName的文件其实都是符号链接,所以delete_dir_contents_and_dir的实现中都是调用unlinkat去删除这些符号链接

到此应用程序的app安装文件和使用中产生的数据文件都已被删除,且配置文件已更新完成,此时会回调deletePackageVersioned()中的 observer.onPackageDeleted(packageName, returnCode, null) 方法通知删除结果,这里回调的是PackageDeleteObserverAdapter类中
@Override
        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
            if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
                NotificationManager notificationManager = (NotificationManager)
                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.notify(basePackageName,
                        SystemMessage.NOTE_PACKAGE_STATE,
                        mNotification);
            }
            if (mTarget == null) {
                return;
            }
            final Intent fillIn = new Intent();
            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
                    PackageManager.deleteStatusToPublicStatus(returnCode));
            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
                    PackageManager.deleteStatusToString(returnCode, msg));
            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
            try {
                mTarget.sendIntent(mContext, 0, fillIn, null, null);
            } catch (SendIntentException ignored) {
            }
        }
    }

在onPackageDeleted()中,首先调用NotificationManager中方法发送notify()通知卸载成功,然后创建Intent对象并回调mTarget.sendIntent(),这里的mTarget对象其实就是卸载最开始时调用uninstall()方法传入的第二个参数,即IntentSender对象,用于接收删除的结果.

如下log是卸载第三方apk(懒人听书) 打印出来的, 与上面的流程分析的基本一致

me@ubuntu:~$ adb logcat -s PackageManager
--------- beginning of main
--------- beginning of system
//开始卸载app
03-26 10:55:15.781  4172  4640 D PackageManager: pms deletePackage start : pkg=bubei.tingshu.hd 

// 关键方法deletePackageAsUser
03-26 10:55:15.781  4172  4640 D PackageManager: deletePackageAsUser: pkg=bubei.tingshu.hd user=0 deleteAllUsers: false version=VERSION_CODE_HIGHEST

//deletePackageX
03-26 10:55:15.782  4172  4216 D PackageManager: deletePackageX: pkg=bubei.tingshu.hd user=0

//deletePackageLI
03-26 10:55:15.782  4172  4216 D PackageManager: deletePackageLI: bubei.tingshu.hd user UserHandle{0}
03-26 10:55:15.783  4172  4216 D PackageManager: Marking package:bubei.tingshu.hd uninstalled for user:0
03-26 10:55:15.783  4172  4216 D PackageManager: Not installed by other users, full delete
03-26 10:55:15.809  4172  4216 D PackageManager: Removing non-system package: bubei.tingshu.hd

//removePackageDataLI
03-26 10:55:15.809  4172  4216 D PackageManager: removePackageDataLI: PackageSetting{906a721 bubei.tingshu.hd/10126}
03-26 10:55:15.809  4172  4216 D PackageManager: Removing package bubei.tingshu.hd

//执行cleanPackageDataStructuresLILPw方法打印出来log
03-26 10:55:15.809  4172  4216 D PackageManager:   Activities: bubei.tingshu.hd.ui.LogoActivity bubei.tingshu.hd.ui.AppHomeActivity bubei.tingshu.hd.ui.DetailActivity bubei.tingshu.hd.ui.DownloadManagerActivity bubei.tingshu.hd.ui.ClassifyFilterActivity bubei.tingshu.hd.ui.ClassifyDetailActivity bubei.tingshu.hd.ui.ResourceListActivity bubei.tingshu.hd.ui.ResourceListAndMediaplayerActivity bubei.tingshu.hd.ui.AppSettingActivity bubei.tingshu.hd.ui.RecommendHomeActivity bubei.tingshu.hd.ui.RecommendCateTabActivity bubei.tingshu.hd.ui.QRCodeActivity bubei.tingshu.hd.ui.UserInfoActivity bubei.tingshu.hd.ui.SearchTabActivity bubei.tingshu.hd.ui.WebviewActivity bubei.tingshu.hd.ui.DeepLinkActivity com.baidu.voicerecognition.android.ui.BaiduASRDigitalDialog com.journeyapps.barcodescanner.CaptureActivity android.app.AppDetailsActivity
03-26 10:55:15.809  4172  4216 D PackageManager:   Providers: <NONE>
03-26 10:55:15.809  4172  4216 D PackageManager:   Receivers: bubei.tingshu.hd.mediaplayer.MediaButtonReceiver
03-26 10:55:15.809  4172  4216 D PackageManager:   Services: bubei.tingshu.hd.mediaplayer.MediaPlaybackService bubei.tingshu.hd.util.RegularClearCacheService com.baidu.speech.VoiceRecognitionService bubei.tingshu.lib.download.function.DownloadService
03-26 10:55:15.811  4172  4216 D PackageManager: Propagating install state across downgrade
03-26 10:55:15.811  4172  4216 D PackageManager:     user 0 => true
03-26 10:55:15.869  4172  4216 D PackageManager: Instant App installer not found with android.intent.action.INSTALL_INSTANT_APP_PACKAGE
03-26 10:55:15.869  4172  4216 D PackageManager: Clear ephemeral installer activity


//在调用observer.onPackageDeleted方法后,打印卸载结束
03-26 10:55:15.963  4172  4216 D PackageManager: pms deletePackage end : pkg=bubei.tingshu.hd
03-26 10:55:15.981  4172  4191 E PackageManager: failed to find package bubei.tingshu.hd

好了,到这里再总结一下卸载apk的工作内容:

1. 从PMS的内部结构上删除acitivity、service、provider, receivers等信息

2. 删除code、library和resource等信息

3. 调用installd守护进程删除/data/data/packageName以及/data/dalvik-cache下面的文件

4. 更新Settings中的package信息
 

三. 待更新

        本文把整体流程梳理了一下, 后续在针对细节方法, 在工作中有需求实现或bug要解决, 有新的理解会更新进来, 上述内容可以供大家参考,谢谢

猜你喜欢

转载自blog.csdn.net/u012514113/article/details/129768088