赞
踩
该系列文章总纲链接:专题分纲目录 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中缓存的应用数据也清除掉。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。