一. 概述
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
}
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去删除这些符号链接
@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要解决, 有新的理解会更新进来, 上述内容可以供大家参考,谢谢