apk的卸载流程相对比较简单,总结大方向就两步,一个是删除安装的文件和数据,另外一个是清除内存信息。另外要注意的是在多用户模式下,apk的卸载删除则不是单纯的删除文件。
下面来看看apk的卸载流程。
[/frameworks/base/core/java/android/app/applicationPackageManager.java]
@Override public void deletePackage(String packageName, ipackageDeleteObserver observer, int flags) { try { mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags); } catch (RemoteException e) { // Should never happen! } }Client端调用PackageManager的deletePackage方法删除对应包名的apk,其中通过注册IPackageDeleteObserver监听卸载结果。实际上通过binder调用pms的deletePackageAsUser方法,在服务中执行卸载动作。
[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
@Overridepublic void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int userId, int flags) { deletePackage(packageName, new LegacyPackageDeleteObserver(observer).getBinder(), userId, flags);}@Override
public void deletePackage(final String packageName,
final IPackageDeleteObserver observer, final int userId, final int flags) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES, null);
if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
try {
observer.onPackageDeleted(packageName,PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
} catch (RemoteException re) {
}
return;
}
// Queue up an async Operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
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
});
}
deletePackageAsUser调用delePackage方法,先校验调用方是否有DELETE_PACKAGE权限,再检查UserRestriction行为限制,都pass以后异步执行deletePackageX方法,最后将结果通过IpackageDeleteObserver返回。下面来看看deletePackageX方法的内容。
PRivate int deletePackageX(String packageName, int userId, int flags) { final PackageRemovedInfo info = new PackageRemovedInfo(); final boolean res; if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) { return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER; } synchronized (mInstallLock) { res = deletePackageLI(packageName, removeForUser,true, allUsers, perUserInstalled, flags | REMOVE_CHATTY, info, true); systemUpdate = info.isRemovedPackageSystemUpdate; if (res && !systemUpdate && mPackages.get(packageName) == null) { removedForAllUsers = true; } } // Force a gc here. Runtime.getRuntime().gc(); if (info.args != null) { synchronized (mInstallLock) { info.args.doPostDeleteLI(true); } } return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; }deletePackageX方法中首先创建PackageRemoveInfo实例,PackageRemoveInfo类结构如下图,主要保存删除应用的基本信息。
然后检查删除的应用是否已激活的DeviceManager,如果是则返回卸载失败,要求先取消激活。
如果没问题继续执行deletePackageLI方法,传入PackageRemoveInfo实例用于记录卸载后应用的基本信息。
private boolean deletePackageLI(String packageName, UserHandle user, boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled, int flags, PackageRemovedInfo outInfo, boolean writeSettings) { if (packageName == null) { Slog.w(TAG, "Attempt to delete null packageName."); return false; } PackageSetting ps; boolean dataOnly = false; int removeUser = -1; int appId = -1; synchronized (mPackages) { ps = mSettings.mPackages.get(packageName); } boolean ret = false; if (isSystemApp(ps)) { ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,flags, outInfo, writeSettings); } else { killApplication(packageName, ps.appId, "uninstall pkg"); ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles, perUserInstalled, outInfo, writeSettings); } return ret; }针对系统应用的卸载我们暂时不跟,来跟下最普遍的第三方应用的卸载过程。在deletePackageLI方法中根据包名获得对应的PackageSetting实例,首先调用killApplication方法杀死应用进程后执行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 set removePackageDataLI(ps, allUserHandles, perUserInstalled, outInfo, flags, writeSettings); return true; }最后调用removePakcageDataLI方法。
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); final PackageSetting deletedPs; synchronized (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); schedulePackageCleaning(packageName, UserHandle.USER_ALL, true); } if (outInfo != null) { // A user ID was deleted here. Go through all users and remove it // from KeyStore. removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId); } }removePakcageDataLI方法是重点,这里主要和开头说的两点,删除内存数据,删除安装文件。
首先调用removePackageLI方法删除应用的内存数据,主要有在mPackages总安装应用列表中删除对应实例,清除所有应用组件,如activity, provider, service, contentresolver, receiver, permissions等,方法内容如下:
void removePackageLI(PackageSetting ps, boolean chatty) { // writer synchronized (mPackages) { mPackages.remove(ps.name); final PackageParser.Package pkg = ps.pkg; if (pkg != null) { cleanPackageDataStructuresLILPw(pkg, chatty); } } } void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) { int N = pkg.providers.size(); int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); mProviders.removeProvider(p); } N = pkg.services.size(); r = null; for (i=0; i<N; i++) { PackageParser.Service s = pkg.services.get(i); mServices.removeService(s); } …}然后调用removeDataDirsLI删除应用的安装和数据文件。
private int removeDataDirsLI(String volumeUuid, String packageName) { int[] users = sUserManager.getUserIds(); int res = 0; for (int user : users) { int resInner = mInstaller.remove(volumeUuid, packageName, user); if (resInner < 0) { res = resInner; } } return res; }至此第三方应用的卸载过程如上所述,当然还有很多细节内容需要一点点的发散去学习。
新闻热点
疑难解答