该系列文章总纲链接:专题分纲目录 Android Framework 包管理子系统
本章关键点总结 & 说明:
导图是不断迭代的,这里主要关注➕ PkgMS卸载应用部分。主要是删除应用的文件、数据和缓存数据。
卸载应用和安装应用的分析流程是极其类似的,因此会感觉有些代码有些重复但却不同,也是从adb uninstall命令开始分析。
1 卸载应用程序(从 adb unInstall 到PkgMS)
一般我们会使用adb uninstall 来安装应用,因此这里就从adb uninstall开始分析,adb命令,uninstall参数。直接看adb命令 处理install参数的代码,如下所示:
int adb_commandline(int argc, char **argv)
{
char buf[4096];
//...
if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
return install_app(ttype, serial, argc, argv);
}
//...
if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return usage();
return uninstall_app(ttype, serial, argc, argv);
}
//...
usage();
return 1;
}
这里继续分析uninstall_app实现,代码如下:
int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
{
if (argc == 3 && strcmp(argv[1], "-k") == 0)
{
return -1;
}
return pm_command(transport, serial, argc, argv);
}
这里比安装apk简单,主要关注pm_command方法(下面这一小段与上节相同),代码如下:
static int pm_command(transport_type transport, char* serial,
int argc, char** argv)
{
char buf[4096];
snprintf(buf, sizeof(buf), "shell:pm");
while(argc-- > 0) {
char *quoted = escape_arg(*argv++);
strncat(buf, " ", sizeof(buf) - 1);
strncat(buf, quoted, sizeof(buf) - 1);
free(quoted);
}
send_shellcommand(transport, serial, buf);
return 0;
}
这里调用了send_shellcommand 发送"shell:pm uninstall 参数"给手机端的adbd,这里继续分析pm命令,pm是脚本文件,构成如下:
# Script to start "pm" on the device,which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/frameworks/pm.jar
exec app_process $base/bincom.android.commands.pm.Pm "$@"
在编译system镜像时,Android.mk中会将该脚本复制到system/bin目录下。从pm脚本的内容来看,它就是通过app_process执行pm.jar包的main函数。pm的main函数实现如下:
public static void main(String[] args) {
int exitCode = 1;
exitCode = new Pm().run(args);
//...
System.exit(exitCode);
}
这里的run方法实现如下(这里主要关注uninstall命令):
public int run(String[] args) throws IOException, RemoteException {
//...
//获取UserM 和 PkgMS的binder客户端
mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
//...
mInstaller = mPm.getPackageInstaller();
//...
//处理其他命令,这里仅考虑uninstall的处理
if ("uninstall".equals(op)) {
return runUninstall();
}
//...
}
这里仅仅关注uninstall部分相关代码,runUninstall代码实现如下:
private int runUninstall() throws RemoteException {
int flags = 0;
int userId = UserHandle.USER_ALL;
//参数与错误处理...
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_OWNER;
flags |= PackageManager.DELETE_ALL_USERS;
} else {
PackageInfo info;
try {
//获取package信息
info = mPm.getPackageInfo(pkg, 0, userId);
} catch (RemoteException e) {
//...
}
//...
final boolean isSystem =
(info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
if (isSystem) {
flags |= PackageManager.DELETE_SYSTEM_APP;
}
}
final LocalIntentReceiver receiver = new LocalIntentReceiver();
//调用PackageInstallerService的uninstall方法来处理
mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId);
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
//...
}
继续分析PackageInstallerService的uninstall方法,代码如下:
public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true, "uninstall");
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
statusReceiver, packageName);
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
//关键点,这里调用了PkgMS的deletePackage方法
mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
} else {
// Take a short detour to confirm with user
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.fromParts("package", packageName, null));
intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
adapter.onUserActionRequired(intent);
}
}
至此,从adb unistall就调用到了PkgMS的deletePackage方法。接下来会从deletePackage开始继续分析。
2 卸载应用程序(删除文件)
deletePackage函数代码实现如下:
public void deletePackage(final String packageName,
final IPackageDeleteObserver2 observer, final int userId, final int flags) {
//检查执行权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
final int uid = Binder.getCallingUid();
if (UserHandle.getUserId(uid) != userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"deletePackage for user " + userId);
}
//权限错误相关处理...
//...
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {//post消息,在处理方法中执行卸载应用操作
public void run() {
mHandler.removeCallbacks(this);
//调用deletePackageX执行卸载应用操作
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
});
}
这里最后post了一个消息,在消息处理中继续执行卸载操作,这样避免了Binder调用的时间过长;实际卸载通过deletePackageX来完成,代码实现如下:
private int deletePackageX(String packageName, int userId, int flags) {
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(userId);
//检查用户removeForUser 是否有权限删除该应用
if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
boolean removedForAllUsers = false;
boolean systemUpdate = false;
// for the uninstall-updates case and restricted profiles, remember the per-
// userhandle installed state
int[] allUsers;
boolean[] perUserInstalled;
synchronized (mPackages) {
//获取setting信息
PackageSetting ps = mSettings.mPackages.get(packageName);
//检查并记录系统中所有用户是否都安装了该应用
allUsers = sUserManager.getUserIds();
perUserInstalled = new boolean[allUsers.length];
for (int i = 0; i < allUsers.length; i++) {
perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false;
}
}
synchronized (mInstallLock) {
//核心,卸载应用
res = deletePackageLI(packageName, removeForUser,
true, allUsers, perUserInstalled,
flags | REMOVE_CHATTY, info, true);
//...
}
if (res) {
//如果卸载的是某个应用升级包,这里会导致低版本的系统应用重新使用
//代码发送广播通知这种变化。
info.sendBroadcast(true, systemUpdate, removedForAllUsers);
// If the removed package was a system update, the old system package
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, info.removedAppId >= 0
? info.removedAppId : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, null, null, null);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
null, packageName, null, null);
}
}
//清理相关工作
Runtime.getRuntime().gc();
if (info.args != null) {
synchronized (mInstallLock) {
info.args.doPostDeleteLI(true);
}
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
该方法搜集了应用在不同用户下的安装情况后,调用deletePackageLI方法继续执行删除操作。如果删除的是某个系统应用的升级包,这里还会发出广播通知以前的应用可以重新使用。deletePackageLI代码实现如下:
private boolean deletePackageLI(String packageName, UserHandle user,...) {
//...
PackageSetting ps;
boolean dataOnly = false;
int removeUser = -1;
int appId = -1;
synchronized (mPackages) {
ps = mSettings.mPackages.get(packageName);
//...
if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
&& user.getIdentifier() != UserHandle.USER_ALL) {
//卸载某个用户下的应用
ps.setUserState(user.getIdentifier(),...);
if (!isSystemApp(ps)) {
if (ps.isAnyInstalled(sUserManager.getUserIds())) {
removeUser = user.getIdentifier();
appId = ps.appId;
mSettings.writePackageRestrictionsLPr(removeUser);
} else {
//没有用户使用,完全删除应用
ps.setInstalled(true, user.getIdentifier());
}
} else {
//只清除用户目录下的数据
removeUser = user.getIdentifier();
appId = ps.appId;
mSettings.writePackageRestrictionsLPr(removeUser);
}
}
}
//...
if (dataOnly) {
//删除应用数据
removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
return true;
}
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,...);
}
return ret;
}
这里主要工作是根据不同用户的安装情况来删除应用的apk文件和数据。删除的不仅有文件和数据,还要将PkgMS中缓存的应用数据也清除掉。