Android6.0 PackageManagerService卸载应用

PKMS中卸载应用是通过deletePackage函数来执行,这个函数主要是调用了一些Observer回调,然后调用了deletePackageX函数。

    public void deletePackage(final String packageName,
            final IPackageDeleteObserver2 observer, final int userId, final int flags) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.DELETE_PACKAGES, null);
        Preconditions.checkNotNull(packageName);
        Preconditions.checkNotNull(observer);
        final int uid = Binder.getCallingUid();
        if (UserHandle.getUserId(uid) != userId) {
            mContext.enforceCallingPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                    "deletePackage for user " + userId);
        }
        if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
            try {
                observer.onPackageDeleted(packageName,//回调
                        PackageManager.DELETE_FAILED_USER_RESTRICTED, null);
            } catch (RemoteException re) {
            }
            return;
        }

        boolean uninstallBlocked = false;
        if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {
            int[] users = sUserManager.getUserIds();
            for (int i = 0; i < users.length; ++i) {
                if (getBlockUninstallForUser(packageName, users[i])) {
                    uninstallBlocked = true;
                    break;
                }
            }
        } else {
            uninstallBlocked = getBlockUninstallForUser(packageName, userId);
        }
        if (uninstallBlocked) {
            try {
                observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,
                        null);
            } catch (RemoteException re) {
            }
            return;
        }

        if (DEBUG_REMOVE) {
            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
        }
        // Queue up an async operation since the package deletion may take a little while.
        mHandler.post(new Runnable() {//异步调用deletePackageX函数
            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
        });
    }

我们来看下deletePackageX函数,主要是调用deletePackageLI函数继续执行,关键当返回的info不为空就调用info.args.doPostDeleteLI(true)删除应用。



    private int deletePackageX(String packageName, int userId, int flags) {
        ......
        synchronized (mInstallLock) {
            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
            res = deletePackageLI(packageName, removeForUser,
                    true, allUsers, perUserInstalled,
                    flags | REMOVE_CHATTY, info, true);
            systemUpdate = info.isRemovedPackageSystemUpdate;
            if (res && !systemUpdate && mPackages.get(packageName) == null) {
                removedForAllUsers = true;
            }
            if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
                    + " removedForAllUsers=" + removedForAllUsers);
        }

        ......
        // Force a gc here.
        Runtime.getRuntime().gc();
        // Delete the resources here after sending the broadcast to let
        // other processes clean up before deleting resources.
        if (info.args != null) {
            synchronized (mInstallLock) {
                info.args.doPostDeleteLI(true);//删除资源、apk等
            }
        }

        return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
    }

我们来看deletePackageLI函数,如果只有data,直接调用removePackageDataLI函数。如果是系统应用调用deleteSystemPackageLI,不是调用deleteInstalledPackageLI函数。

    private boolean deletePackageLI(String packageName, UserHandle user,
            boolean deleteCodeAndResources, int[] allUserHandles, boolean[] perUserInstalled,
            int flags, PackageRemovedInfo outInfo,
            boolean writeSettings) {
        ......

        if (dataOnly) {
            // Delete application data first
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only");
            removePackageDataLI(ps, null, null, outInfo, flags, writeSettings);
            return true;
        }

        boolean ret = false;
        if (isSystemApp(ps)) {
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
            // When an updated system application is deleted we delete the existing resources as well and
            // fall back to existing code in system partition
            ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
                    flags, outInfo, writeSettings);
        } else {
            if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
            // Kill application pre-emptively especially for apps on sd.
            killApplication(packageName, ps.appId, "uninstall pkg");
            ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
                    allUserHandles, perUserInstalled,
                    outInfo, writeSettings);
        }

        return ret;
    }

卸载系统应用

为什么会有卸载系统应用呢,当我们调用scanPackageLI扫描目录时有时候失败,也需要调用deletePackageLI来删除apk,这个时候就会有系统应用了。

    private boolean deleteSystemPackageLI(PackageSetting newPs,
            int[] allUserHandles, boolean[] perUserInstalled,
            int flags, PackageRemovedInfo outInfo, boolean writeSettings) {
        final boolean applyUserRestrictions
                = (allUserHandles != null) && (perUserInstalled != null);
        PackageSetting disabledPs = null;
        // Confirm if the system package has been updated
        // An updated system app can be deleted. This will also have to restore
        // the system pkg from system partition
        // reader
        synchronized (mPackages) {
            disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);
        }
        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + newPs
                + " disabledPs=" + disabledPs);
        if (disabledPs == null) {
            Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);
            return false;
        } else if (DEBUG_REMOVE) {
            Slog.d(TAG, "Deleting system pkg from data partition");
        }

        // Delete the updated package
        outInfo.isRemovedPackageSystemUpdate = true;
        if (disabledPs.versionCode < newPs.versionCode) {
            // Delete data for downgrades
            flags &= ~PackageManager.DELETE_KEEP_DATA;//是否保留资源
        } else {
            // Preserve data by setting flag
            flags |= PackageManager.DELETE_KEEP_DATA;
        }
        boolean ret = deleteInstalledPackageLI(newPs, true, flags,//卸载apk
                allUserHandles, perUserInstalled, outInfo, writeSettings);
        if (!ret) {
            return false;
        }
        // writer
        synchronized (mPackages) {
            // Reinstate the old system package
            mSettings.enableSystemPackageLPw(newPs.name);
            // Remove any native libraries from the upgraded package.
            NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);
        }
        // Install the system package
        int parseFlags = PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM;
        if (locationIsPrivileged(disabledPs.codePath)) {
            parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
        }

        final PackageParser.Package newPkg;
        try {
            newPkg = scanPackageLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);//重新apk扫描目录
        } catch (PackageManagerException e) {
            Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
            return false;
        }

        // writer
        synchronized (mPackages) {
            PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);

            // Propagate the permissions state as we do not want to drop on the floor
            // runtime permissions. The update permissions method below will take
            // care of removing obsolete permissions and grant install permissions.
            ps.getPermissionsState().copyFrom(newPs.getPermissionsState());
            updatePermissionsLPw(newPkg.packageName, newPkg,
                    UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);

            if (applyUserRestrictions) {
                if (DEBUG_REMOVE) {
                    Slog.d(TAG, "Propagating install state across reinstall");
                }
                for (int i = 0; i < allUserHandles.length; i++) {
                    if (DEBUG_REMOVE) {
                        Slog.d(TAG, "    user " + allUserHandles[i]
                                + " => " + perUserInstalled[i]);
                    }
                    ps.setInstalled(perUserInstalled[i], allUserHandles[i]);

                    mSettings.writeRuntimePermissionsForUserLPr(allUserHandles[i], false);
                }
                // Regardless of writeSettings we need to ensure that this restriction
                // state propagation is persisted
                mSettings.writeAllUsersPackageRestrictionsLPr();
            }
            // can downgrade to reader here
            if (writeSettings) {
                mSettings.writeLPr();//更新packages.xml
            }
        }
        return true;
    }

卸载系统应用,最后也是调用deleteInstalledPackageLI来完成卸载的,我们来看下这个函数。

卸载普通应用

卸载普通应用就直接调用了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);

        // Delete application code and resources
        if (deleteCodeAndResources && (outInfo != null)) {
            outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                    ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
            if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
        }
        return true;
    }

我们先看removePackageDataLI函数,就是删除各种资源,但是我们没看到删除apk文件。

    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);
        // Retrieve object to delete permissions for shared user later on
        final PackageSetting deletedPs;   
        // reader
        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);// 卸载data目录
            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);
                        outInfo.removedAppId = mSettings.removePackageLPw(packageName);
                    }
                    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() {
                                    @Override
                                    public void run() {
                                        // This has to happen with no lock held.
                                        killApplication(deletedPs.name, deletedPs.appId,
                                                KILL_APP_REASON_GIDS_CHANGED);
                                    }
                                });
                                break;
                            }
                        }
                    }
                    clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
                }
                // make sure to preserve per-user disabled state if this removal was just
                // a downgrade of a system app to the factory package
                if (allUserHandles != null && perUserInstalled != null) {
                    if (DEBUG_REMOVE) {
                        Slog.d(TAG, "Propagating install state across downgrade");
                    }
                    for (int i = 0; i < allUserHandles.length; i++) {
                        if (DEBUG_REMOVE) {
                            Slog.d(TAG, "    user " + allUserHandles[i]
                                    + " => " + perUserInstalled[i]);
                        }
                        ps.setInstalled(perUserInstalled[i], allUserHandles[i]);
                    }
                }
            }
            // can downgrade to reader
            if (writeSettings) {
                // Save settings now
                mSettings.writeLPr();//更新packages.xml
            }
        }
        if (outInfo != null) {
            // A user ID was deleted here. Go through all users and remove it
            // from KeyStore.
            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
        }

我们再来看deleteInstalledPackageLI函数,最后一段代码,

        if (deleteCodeAndResources && (outInfo != null)) {
            outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                    ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
            if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
        }

我们来看下这个函数,如果不是安装在sd卡上,最后新建一个FileInstallArgs对象。

    private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
            String resourcePath, String[] instructionSets) {
        final boolean isInAsec;
        if (installOnExternalAsec(installFlags)) {
            /* Apps on SD card are always in ASEC containers. */
            isInAsec = true;
        } else if (installForwardLocked(installFlags)
                && !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
            /*
             * Forward-locked apps are only in ASEC containers if they're the
             * new style
             */
            isInAsec = true;
        } else {
            isInAsec = false;
        }

        if (isInAsec) {
            return new AsecInstallArgs(codePath, instructionSets,
                    installOnExternalAsec(installFlags), installForwardLocked(installFlags));
        } else {
            return new FileInstallArgs(codePath, resourcePath, instructionSets);
        }
    }

最后返回到deletePackageX函数,最后调用如下代码,直接到FileInstallArgs的doPostDeleteLI函数。

        if (info.args != null) {
            synchronized (mInstallLock) {
                info.args.doPostDeleteLI(true);
            }
        }

doPostDeleteLI函数如下:

        boolean doPostDeleteLI(boolean delete) {
            // XXX err, shouldn't we respect the delete flag?
            cleanUpResourcesLI();
            return true;
        }

cleanUpResourcesLI函数会删除资源和代码文件,dex文件

        void cleanUpResourcesLI() {
            // Try enumerating all code paths before deleting
            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) {
                    // Ignored; we tried our best
                }
            }

            cleanUp();
            removeDexFiles(allCodePaths, instructionSets);
        }

cleanUp函数就是删除apk文件。

        private boolean cleanUp() {
            if (codeFile == null || !codeFile.exists()) {
                return false;
            }

            if (codeFile.isDirectory()) {
                mInstaller.rmPackageDir(codeFile.getAbsolutePath());
            } else {
                codeFile.delete();
            }

            if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
                resourceFile.delete();
            }

            return true;
        }
    原文作者:kc专栏
    原文地址: https://blog.csdn.net/kc58236582/article/details/53260779
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞