PackageManagerService安装应用流程
PackageManagerService主要负责Android系统的应用管理,它提供对各种APK文件的安装、卸载、优化和查询服务。PackageManagerService在系统启动时会扫描所有存在的APK文件和Jar包信息,并将它们读取、保存起来;这样系统在运行时,就能很快的查询到各种应用和相关组件的信息。
一、 PackageManagerService初始化
参数介绍:
Installer=>负责与installd通讯的客户端
实例化在systemServer中
FactoryTest=>是否当前系统进去的是工厂模式,这里假设走false
OnlyCore=>是否处理系统核心应用,假设走false
对应的核心应用在哪里指定:
1. 构造函数—1
添加几种SharedUserId对象到Settings中,sharedUserId属性相同的package可以运行在同一个进程中,或者相互读取资源;
Settings可以看做是一个数据动态管理类,它主要会管理packages.xml文件中的信息;
- packages.xml:记录了系统中所有安装应用的基本信息,如果签名、权限等等
- packages-backup.xml:packages.xml文件的备份
- packages-stopped.xml:记录系统中所有被强制停止运行的应用的信息(如我们在系统设置中,选择某个应用,并将它强制停止)
- packages-stopped-back.xml:packages-stopped.xml文件的备份
- packages.list:保存了应用的数据目录和UID等信息
Android系统在修改packages.xml、packages-stopped.xml之前,会先对它们进行备份。当对它们的修改操作正常完成,则会删掉之前建立的备份文件。如果,在修改过程中系统出现问题重启了,会再次去读取这两个文件。
2. 构造函数—2
SystemConfig是一个工具类,它负责读取系统中全局的某些权限、特性信息,展开SystemConfig,看做了什么:
通过readPermissions()读取指定/system/etc/、/oem/etc/等目录下的permission xml文件,解析其中的内容。
我们列举一些其中的文件的内容,来大致看下配置文件的内容:
platform.xml
plateform.xml中出现的标签种类则较为多样,它们的含义分别是:
- <permission >标签:把属性name所描述的权限赋予给<group>标签中属性gid所表示的用户组
- <assign-permission>标签:把属性name所描述的权限赋予给uid属性所表示的用户
- <library>标签:除framework中动态库以外的,所有系统会自动加载的动态库
最后将上面xml解析出来的数据做如下存储:
- <group>标签gid属性的值会存放在mGlobalGids数组中;
- <permission>标签,解析得到的值会存放在mPermissions集合中;
- <assign-permission>标签解析得到的值会存放在mSystemPermissions中;
- <library>标签解析得到的值会存放在mSharedLibraries中;
-
3. 构造函数—3
-
该部分介绍apk扫描过程
-
PackageManagerService(PKMS)构造中触发APK扫描的函数调用是:scanDirTracedLI(),它会遍历我们传入的文件路径,然后循环解析其中存在的APK文件,并将信息解析出来存入PKMS内部,供后续的运行时信息管理。PKMS这一部分的函数调用很深,我们这里只看其中的几个关键函数调用,以此来熟悉APK扫描工作的基本内容。
-
PKMS解析APK文件主要依靠PackageParser实现.
其中,PackageParser::Package信息是最丰富的。说是解析APK文件,其实主要是解析应用的Androidmanifest.xml配置文件;因为配置文件中描述了所有有关该应用的组件、权限、包名等信息。对它的解析过程,就是我们获取APK信息的过程。
PackageParser::parseBaseApkCommon()负责Androidmanifest.xml的解析,将生成的信息保存到PMS的相关变量中
-
-
-
-
我们只看里面关于application标签的解析。
-
-
调用parseBaseApplicaton()函数解析<application>标签。
-
-
我们从代码中看到了对Application中声明的Android四大组件的解析调用,它们的解析过程类似:都是调用XmlPullParser解析器解析各个节点的内容并保存。我们以解析Activity为例,来看它是如何解析<activity>节点、并保存其各个节点的信息的,以<intent-filter>节点的内容;我们设置的intent内容都包含在<intent-filter>节点内,PMS对外提供了组件查询的业务,它主要就是根据这里的intent来查找的。:
-
-
解析到了Intent信息会保存到Activity实例内部的intents集合中;这一部分对Service/Provider/Receiver的解析都是一样的;<activity>标签解析完后,返回的activity实例又会被保存到Package类的activities中。其他三大组件的处理也跟此类似,所以这里就略过它们的解析过程了。
parseBaseApplication()函数执行完毕后,我们得到了一个保存有绝大部分APK信息的Package实例;得到了Package实例,我们还需要把它的信息整合到PMS中,让PMS统一管理;这个过程由PMS::scanPackageDirtyLI()处理。scanPackageDirtyLI()函数的处理较长,这里不做详细分析。
经过了scanPackageDirtyLI(),我们解析到的一个APK的Package实例添加到了PMS中,并且它所有重要组件也已经由PMS统一管理。这样PMS就能很好的管理这个APK的信息了。
到这里,APK扫描所涉及到的主要函数调用分析也就结束了。
二、 apk安装
不管是三方市场,或系统自带的packageInstaller,其实到后面的动作都是一样的,我们这里以最复杂的adb install来分析流程。
在android中,adbd以后台进程运行。当我们输入"adb install"命令时,/syste/core/adb/目录下commandline.cpp文件会被执行,其中adb_commandline()函数会接受该条指令,并进行处理,这里只看install命令的执行:
-
-
-
-
然后,流程会去执行pm脚本进行安装操作。手机的端的adbd程序接收到客户机发送的shell pm命令后,会开启一个shell去执行pm脚本。pm脚本的内容如下:
-
-
frameworks\base\cmds\pm\src\com\android\commands\pm\Pm.java
-
-
-
最终还是调用到PMS里面,层层调用,最后来到installPackageAsUser()
-
-
-
-
-
进入handleStartCopy后:
- 首先会进行一些安装标志的判断
- 调用DCS::getMinimalPackageInfo()方法获取该apk安装需要的大小及其他信息
- 如果检测到当前的目录下的大小不足以安装应用,还回去进行cache的清理工作
- 随后会以当前的InstallParams实例,创建FileInstallArgs对象,并保存一份到InstallParams对象的mArgs字段中
- 后续是一段组件校验工作,这里不做分析
- 最后FileInstallArgs::copyApk()函数,进行下一步处理
-
handleStartCopy最终调用到doCopyApk,完成下面动作:
- 通过PackageInstallService为要安装的apk在/data/app/下生成一个零时文件tempDir
- 为该tempDir创建IParcelFileDescriptorFactory文件描述符,它可以在进程间传递
- 调用DefaultContainerService::copyPackage()方法执行apk临时文件的复制
- 最后再将apk中包含的一些库文件提取出来,放置到对应的lib/目录下
-
如果一切过程都正常,至此,APK安装的第一部分的工作:APK文件的拷贝,就结束了,接着处理下一步:
-
processPendingInstall->installPackageTracedLI
->installPackageLI->installNewPackageLIF->scanPackageTracedLI
->scanPackageLI->scanPackageDirtyLI 完成信息的整合
在Android系统中,PackageManagerService用于管理系统中的所有安装包信息及应用程序的安装卸载,但是应用程序的安装与卸载并非PackageManagerService来完成,而是通过PackageManagerService来访问installd服务来执行程序包的安装与卸载的。
-
-
Android O上面installd与PMS直接的通讯已经由socket换为binder了。
Installd服务的启动在systemServer中:
相关实现在:
frameworks\native\cmds\installd\installd.cpp
frameworks\native\cmds\installd\InstalldNativeService.cpp
frameworks\base\services\core\java\com\android\server\pm\Installer.java
-
-
frameworks\native\cmds\installd\installd.rc
service installd /system/bin/installd
class main相关执行最终在installd中完成。
-
-
-
处理结束后,发送相关广播通知其他应用,如launcher收到广播后,通过PMS查找先关activity,显示图标等信息。
-
-
-
-
到此apk安装结束。