注意:下面的代码比较老,新的apk卸载流程请参考以下两位朋友的文章
http://blog.csdn.net/xinsong1989/article/details/78527439
https://blog.csdn.net/u012439416/article/details/61614326
--------------------------------------------------分割线-------------------------------------------------------
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]
@Override
public 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;
}
至此第三方应用的卸载过程如上所述,当然还有很多细节内容需要一点点的发散去学习。