这一章我们介绍APK的卸载过程,大致了解这里的卸载的过程如下:
1.从PMS的内部结构上删除acitivity、service、provider等信息
2.删除code、library和resource等信息
3.调用installd删除/data/data/packageName以及/data/dalvik-cache下面的文件
4.更新Settings中的package信息
当我们在Settings中的应用页面找到一个安装了的应用程序,并点击卸载后,就会发送一个Intent给UninstallerActivity,在UninstallerActivity最后会启动UninstallAppProgress的initView方法,并调用如下卸载函数:
上面的mAllUsers默认是false。getPackageManager()函数的实现在ContextImpl.java,它最后会调用到ApplicantPackageManger.java的deletePackage方法:
通过Binder调用,我们来看PMS中的deletePackage方法:
首先做权限检查,然后就调用deletePackageX方法去执行卸载任务:
deletePackageX在这里我们只考虑当前只有一个user的情况,来看deletePackageLI的实现:
在deletePackageLI函数中根据是否是systemApp调用不同的流程,如果是systemApp,则调用deleteSystemPackageLI完成卸载;如果非systemApp,则调用deleteInstalledPackageLI完成卸载,当然在卸载之前,首先会调用AMS的killApplication方法先让这个APP停止运行。我们主要介绍非systemApp的卸载过程,来看deleteInstalledPackageLI方法的实现(其实deleteSystemPackageLI中还是要调用deleteInstalledPackageLI函数的):
在deleteInstalledPackageLI方法中,分为两步去卸载应用:第一步删除/data/data下面的数据目录,并从PMS的内部数据结构上清除当前卸载的package信息;第二步就删除code和resource文件。我们先来看第一步:
这里首先调用installd的remove方法去删除/data/data下面的目录。然后去删除/data/app-lib下面的应用程序的library信息,但因为这里的nativeLibraryFile为/data/app-lib/packageName,和前面介绍的APK安装过程中的目录/data/app-lib/packageName-num不一样,所以实际上,这里并没有真正的去删除library目录。
先来看installd的remove方法:
最终会调用下面方法:
这里首先调用installd的remove方法去删除/data/data下面的目录。然后去删除/data/app-lib下面的应用程序的library信息,但因为这里的nativeLibraryFile为/data/app-lib/packageName,和前面介绍的APK安装过程中的目录/data/app-lib/packageName-num不一样,所以实际上,这里并没有真正的去删除library目录。先来看installd的remove方法:
create_pkg_path方法构造/data/data/packageName的文件路径名,然后调用delete_dir_contents来删除文件内容以及目录,前面介绍过,/data/data/packageName的文件其实都是符号链接,所以_delete_dir_contents的实现中都是调用unlinkat去删除这些符号链接。回到removePackageDataLI中,接着调用schedulePackageCleaning来安排清理动作:
最终去启动一个服务:DefaultContainerService去做事情:
看得很清楚了吧,是清除的什么数据。
在回到deleteInstalledPackageLI函数,看函数后面,这里首先从Settings中删除PackageSettings的信息:
removePackageLPw首先从mPackages这个map中删除PackageSettings信息,如果不存在sharedUser,则从mUserIds这个数组中删除对应的Package UID信息;如果存在sharedUser,则首先检查这个sharedUser是否所有的package都已经被卸载了,如果都被卸载了,这个sharedUser也就可以删除。然后removePackageDataLI调用updatePermissionsLPw去检查mPermissionTrees和mPermissions两个数组中的权限是否是被删除的Package提供,如果有,则删除。Settings的updateSharedUserPermsLPw方法用于清除sharedUser不用的gid信息,防止权限泄露:
循环的从要被卸载的Package所在的sharedUser组中找被申请的权限是否还被同一组的其它package使用,如果没有使用者,就从sharedUser的grantedPermissions删除。clearPackagePreferredActivitiesLPw与AMS相关,我们留到以后再来介绍。在removePackageDataLI方法最好调用Settings.writeLPr()方法将改动的信息写到Package.xml中。到这里,我们前面所说的deleteInstalledPackageLI方法中的第一步已经完成,来看第二部分,在deleteInstalledPackageLI函数后面调用了下面函数(第3页):
这里根据安装目录的不同,分别构造FileInstallArgs和AsecInstallArgs来完成code和resource资源的清除。这里我们主要介绍卸载内部存储空间上面的APK,这里返回参数InstallArgs供后面准备;来看FileInstallArgs的doPostDeleteLI方法:
这里的调用就是上面返回参数。
cleanUpResourcesLI方法中首先调用cleanUp方法去删除code、resource以及library文件:
然后cleanUpResourcesLI调用installd的rmdex方法去删除存在/data/dalvik-cache文件,最终调用到这里:
create_cache_path依据path构造/data/dalvik-cache下的文件目录,调用unlink去删除文件。到这里卸载APK的deletePackageAsUser函数就已经分析完了。这时会通过observer把卸载结果返回给UninstallAppProgress。
觉得本文对你有用,麻烦点赞或关注或收藏,你的肯定是我创作的无限动力,谢谢!!!