卸载应用
我们可以通过下面的代码执行一个应用的卸载工作:
1 | getPackageManager().deletePackage(mAppInfo.packageName, observer, mAllUsers ? PackageManager.DELETE_ALL_USERS : 0); |
它最后会调用到 ApplicantPackageManger
的deletePackage()
方法,通过Binder调用,会调用 PMS 中的deletePackageAsUser()
方法。
那么接下来我们就从 PMS 的 deletePackageAsUser()
方法来开始分析应用的卸载流程。
Android的应用卸载有下面几个阶段的工作:
- 删除和该包相关的 acitivity、service、provider 等信息
- 删除 code、library和resource 等信息
- 调用 installd 删除 /data/data/ 以及 /data/dalvik-cache 下面的文件(经过dexopt过的文件)
- 更新
Settings
中的 package 信息
代码调用流程如下:
1 | ├── PMS.deletePackageAsUser() |
deletePackage()
1 |
|
deletePackageX()
实际的卸载工作是由 deletePackageX()
方法来完成的。
1 | private int deletePackageX(String packageName, int userId, int flags) { |
deletePackageLI()
1 | private boolean deletePackageLI(String packageName, UserHandle user, |
deletePackageLI()
的主要工作就是根据不同用户的安装情况来删除应用的APK文件和数据。
deleteSystemPackageLI()
顾名思义,deleteSystemPackageLI()
就是用来删除系统应用的方法。
1 | private boolean deleteSystemPackageLI(PackageSetting newPs, |
deleteInstalledPackageLI()
卸载非系统应用,包括删除和该包相关的数据结构以及数据目录,以及创建一个FileInstallArgs
来删除 code 和 resources 文件。
1 | private boolean deleteInstalledPackageLI(PackageSetting ps, |
removePackageDataLI()
删除和该包相关的数据,包括activity、provider、service等数据,如果没有设置 PackageManager.DELETE_KEEP_DATA
,还会删除/data/data下面的目录。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79private void removePackageDataLI(PackageSetting ps,
int[] allUserHandles, boolean[] perUserInstalled,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = ps.name;
// 删除和该包相关的数据,包括activity、provider、service等数据
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) {
// 调用installd去删除/data/data下面的目录
removeDataDirsLI(ps.volumeUuid, packageName);
// 调用startCleaningPackages(),调用DefaultContainerService与该package相关的文件去删除
schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
}
// writer
synchronized (mPackages) {
if (deletedPs != null) {
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
clearDefaultBrowserIfNeeded(packageName);
if (outInfo != null) {
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
// 从Settings中删除该包的信息
outInfo.removedAppId = mSettings.removePackageLPw(packageName);
}
// 检查mPermissionTrees和mPermissions两个数组中的权限是否是被删除的Package提供,如果有就删除。
updatePermissionsLPw(deletedPs.name, null, 0);
if (deletedPs.sharedUser != null) {
// Remove permissions associated with package. Since runtime
// permissions are per user we have to kill the removed package
// or packages running under the shared user of the removed
// package if revoking the permissions requested only by the removed
// package is successful and this causes a change in gids.
for (int userId : UserManagerService.getInstance().getUserIds()) {
final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
userId);
if (userIdToKill == UserHandle.USER_ALL
|| userIdToKill >= UserHandle.USER_OWNER) {
// If gids changed for this user, kill all affected packages.
mHandler.post(new Runnable() {
public void run() {
killApplication(deletedPs.name, deletedPs.appId,
KILL_APP_REASON_GIDS_CHANGED);
}
});
break;
}
}
}
// 从Settings.mPreferredActivities中删除相关的PreferredActivity
clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
}
// 设置PackageUserState.installed状态,因为还有可能此次执行的是系统应用降级到初始版本
if (allUserHandles != null && perUserInstalled != null) {
for (int i = 0; i < allUserHandles.length; i++) {
ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
}
}
}
if (writeSettings) {
// 将改动的信息写到package.xml中
mSettings.writeLPr();
}
}
if (outInfo != null) {
// A user ID was deleted here. Go through all users and remove it
// from KeyStore.
removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
}
}
FileInstallArgs.cleanUpResourcesLI()
删除 code、resource、library 文件以及 /data/dalvik-cache 下面相关文件,/data/dalvik-cache 放的是经过 installd dexop t过的文件,可以看一下这篇文章。1
2
3
4
5
6
7
8
9
10
11
12
13void cleanUpResourcesLI() {
List<String> allCodePaths = Collections.EMPTY_LIST;
if (codeFile != null && codeFile.exists()) {
try {
final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
allCodePaths = pkg.getAllCodePaths();
} catch (PackageParserException e) {}
}
// 删除code、resource、library文件
cleanUp();
//删除apk文件
removeDexFiles(allCodePaths, instructionSets);
}
1 | private boolean cleanUp() { |
1 | private void removeDexFiles(List<String> allCodePaths, String[] instructionSets) { |
adb uninstall
可以通过下面的命令来执行一个应用的卸载工作:1
2adb uninstall [-k] <package> - remove this app package from the device
('-k' means keep the data and cache directories)