pms包管理服务分析-apk卸载流程

注意:下面的代码比较老,新的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类结构如下图,主要保存删除应用的基本信息。

《pms包管理服务分析-apk卸载流程》

 

 

 

 

然后检查删除的应用是否已激活的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;
    }

 

至此第三方应用的卸载过程如上所述,当然还有很多细节内容需要一点点的发散去学习。

 

    原文作者:freeMos
    原文地址: https://blog.csdn.net/lgglkk/article/details/54918115
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞