一、PKMS启动过程
1、重要文件目录介绍
1.目录:
/system/ect/permissions/xxx.xml:加载系统feature
/system/ect/permissions/platform.xml:为核心系统进程uid/gid分配默认权限
permission/group:用于建立linux层gid和Android层permission之间的映射关系
assign-permission:用于向指定的uid赋予相应的权限
library:用于指定系统库,应用程序运行时系统自动为这些进程加载这些库
/data/system/packages.xml:所有应用程序与包管理相关信息,保存所有安装程序的基本包信息。当进行程序安装更新卸载是都会更新此文件。
/data/system/packages.list:保存所有应用程序列表,每一行对应于一个应用程序。
/data/system/packages-stopped.xml:保存被用户强行停止的程序信息。
/system/app:系统自带应用程序路径
/data/app:第三方应用程序路径
/data/dalvik-cache/:dex文件输出路径
/system/framework/.apk; .jar:framework中的程序
/data/secure/:加密目录
/data/drm/:drm用户专有目录
/data/app-private/:drm用户专有目录
/data/data/:普通程序数据
2.数据结构:
(1)Settings:
File mSettingsFilename
:配置文件名称,指的是packages.xml文件
File mBackupSettingsFilename
:配置文件的备份文件
File mPackageListFilename
:packages.list文件保存所有程序列表
HashMap<String, PackageSetting> mPackages
:填充从packages.xml文件中读取的包管理信息
HashMap<String, PackageSetting> mDisabledSysPackages
:保存没有经过标准卸载方式删除的程序列表
HashMap<String, SharedUserSetting> mSharedUsers
:保存所有共享id的信息,来源于packages.xml中的
ArrayList<Object> mUserIds
:所有用户id
ArrayList<Signature> mPastSignatures
:保存所有的签名
HashMap<String, BasePermission> mPermissions
:保存所有权限
HashMap<String, BasePermission> mPermissionTrees
:对应packages.xml文件中的permission-tree,没有使用
(2)PMS:
HashMap<String, PackageParser.Package> mPackages
:保存所有程序包信息.来源于扫描程序目录下所有程序文件
Settings mSettings
:上面介绍的类
int[] mGlobalGids
:系统中所有linux用户id
SparseArray<HashSet<String>> mSystemPermissions
:系统中所有权限的名称
HashMap<String, SharedLibraryEntry> mSharedLibraries
:系统所依赖的共享java库,来源于platform.xml中library标签
ActivityIntentResolver mActivities、ActivityIntentResolver mReceivers、ServiceIntentResolver mServices、ProviderIntentResolver mProviders
:用于intent-filter匹配.通过读取manifest提取intent-filter下的数据
保存的framework-res.apk信息:
mPlatformPackage
:保存该package信息
mAndroidApplication
:此package中的ApplicationInfo
mResolveActivity
:指向用于表示ChooserActivity信息的ActivityInfo
mResolveInfo
:存储系统解析Intent后得到的结果信息,根据该信息得到组件
3.系统apk
(1)framework-res.apk包含以下常用Activity:
ChooserActivity
:当多个Activity符合某个intent时弹出此Activity
RingtonePickerActivity
:铃声选择Activity
ShutdownActivity
:关机前确认对话框
4.uid含义
(1)Process.myUid() = ApplicationInfo.uid = PackageSetting.appid;这里的uid标识具体独立应用。
(2)UserHandle.getUid(int userId, int appId); 这类的uid标识多用户下的用户id。如果是单用户与上面的uid一致,这里传入的appid就是上面的uid。
参考:http://blog.youkuaiyun.com/leirenbaobao/article/details/48318753
http://blog.youkuaiyun.com/Gaugamela/article/details/78689580
2、PKMS启动过程
如下图启动流程:
一、在ServerThread中启动PKMS
1.初始化启动PKMS:系统开机时会经过一列调用到ServerThread.initAndLoop()函数,该函数中会初始化启动各个系统服务,其中就包含PKMS服务。
- 启动PKMS服务通过调用PackageManagerService.main()方法实现,传入参数需要关注:installer对象负责辅助程序安装.与SocketServer通信;onlyCore代表是否只扫描系统app正常启动为false。
2.执行已经安装的apk的dex优化:执行完初始化启动PKMS之后,接着调用PackageManagerService.performBootDexOpt()执行所有安装的apk的dex优化操作,这里的优化只有在第一次系统启动之后进行。
3.通知系统PKMS启动完成:调用PackageManagerService.systemReady()通知系统PKSM启动完成。
二、在PKSM.main()中启动服务
1.首先构造PackageManagerService对象,传入参数。
2.将这个新建对象添加到ServiceManager中。
三、PackageManagerService构造函数中执行启动操作
1.赋值变量:将传入参数赋值到内部变量中。mNoDexOpt表示是eng版本扫描apk后不做dex优化。
2.创建辅助类Settings:Settings是Android的全局管理者,用于协助PMS保存所有的安装包信息。
在Settings构造函数中构建带读取的配置文件的File对象及相应目录。
- 创建目录:创建/data/system目录,依次构建文件/data/system/packages.xml、/data/system/packages-backup.xml、/data/system/packages.list、/data/system/packages-stopped.xml、/data/system/packages-stopped-backup.xml。以上文件作用见第一节介绍。
添加共享的uid及name:使用Settings.addSharedUserLPw()预置可以共享的uid及name。
查看是否有缓存:首先会从mSharedUsers获取制定name对应的SharedUserSetting对象,这里不存在对应的SharedUserSetting对象。
新建并保存SharedUserSetting对象:不存在缓存所以新建SharedUserSetting对象保存传入参数uid、name、flag。使用addUserIdLPw()将传入对象以其uid为索引分别存入mUserIds或者mOtherUserIds中。这样做可以直接以uid为索引获取SharedUserSetting提升查询效率。接着存入mSharedUsers以name为key传入该map中。
3.赋值获取变量:赋值installer该对象负责与与SocketServer通信辅助程序安装,获取默认的现实信息保存到mMetrics中。
4.创建消息循环队列:创建PackageHandler消息队列,处理外部的安装请求。
5.创建系统路径及目录存放文件:分别创建/data/data、/data/app、/data/app-lib等数据目录。
6.开始读取系统的权限配置文件:调用readPermissions()从/system/etc/permissions/目录下读取全部xml文件,属性值保存到mSettings.mPermissions中。执行完毕PMS保存系统feature及指定uid的权限。这些文件是有硬件信息编译之后复制到该目录下。
首先遍历该目录下所有文件,先处理除了platform.xml的其他所有文件,这里处理的文件基本是只定义系统的一些feature。遍历执行结束开始真正处理platform.xml。
处理过程主要是解析xml文件中的各个tag并且保存信息到PMS中,platform.xml文件的典型内容如下:
<permissions> <!-- 建立权限名与gid的映射关系--> <permission name="android.permission.READ_EXTERNAL_STORAGE" > <group gid="sdcard_r" /> </permission> <!-- 为指定uid赋予权限--> <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" /> <!-- 系统提供的java库,程序运行必须加载--> <library name="javax.btobex" file="/system/framework/javax.btobex.jar"/> </permissions>
以上文件解析完成生成相关数据结构:mGlobalGids/mSharedLibraries/mSystemPermission/mAvaliableFeature/mSettings.mPermissions。相关介绍见第一节。
7.读取Settings中创建的三个配置文件:调用mSettings.readLPw()主要工作从/data/system/packages.xml读取所有应用程序中和包管理相关的信息,保存到mSettings.mPackages。一个典型的packages.xml文件如下:
<package name="cn.nubia.video" codePath="/system/priv-app/NubiaVideo" nativeLibraryPath="/system/priv-app/NubiaVideo/lib" flags="1078508613" ft="8a8bdd70" it="8a8bdd70" ut="8a8bdd70" version="40001" userId="10014">
<sigs count="1">
<cert index="3" />
</sigs>
<proper-signing-keyset identifier="2" />
<signing-keyset identifier="2" />
</package>
首先根据是否存在packages.xml及其备份文件确定读取备份文件还是源文件。使用XmlPullParser读取文件解析开始。分别解析package、permissions、shared-user等标签。这里以解析package标签为例调用readPackageLPw(parser)。
获取制定属性对应值:name(包名)、userId、realName、codePath、nativeLibraryPath、version…
根据获取到的属性值处理:首先判断userId如果大于0调用addPackageLPw()获取一个该userId对应的PackageSetting对象,该对象描述已安装的pkg的信息。然后保存该对象。接着判断sharedIdStr如果存在则该pkg以共享id运行,新建对象PedingPackage保存信息到mPendingPackages中后续处理。接下来还会判断其他属性并赋值相应信息到该PackageSetting对象省略。
该文件解析结束后处理mPendingPackages中以共享id运行的pkg。
- 循环遍历获取待处理PedingPackage,使用getPackageLPw()获取目标uid对应的PackageSetting,接着拷贝信息到获取的对象中。
接着读取packages-stopped.xml文件省略该过程。
8.对系统核心java库进行dex操作流程:省略该过程。
9.设置监听系统pkg目录,并且扫描目录下的apk文件:系统pkg目录主要包括:/system/frameworks /system/app /verdor/app
首先新建对象mFrameworkInstallObserver监听该目录。
调用scanDirLI()扫描该目录下的apk文件。
首先循环遍历该目录下所有文件,判断只有apk 文件才扫描。接着调用scanPackageLI()扫描该apk文件并且返回PackageParser.Package对象。
在scanPackageLI()中:首先新建PackageParser对象,解析该apk对应的manifest文件生成对应PackageParser.Package对象。
-+处理package升级问题,旧package信息PackageSetting来自于package.xml省略该过程。
-+调用setApplicationInfoPaths()为Package对象的ApplicationInfo设置其codePath/resPath。
-+调用scanPackageLI()将解析到的信息转换到PKMS中。
-++在scanPackageLI()中:
-+++首先单独处理包名为android的及framework-res.apk信息。为mResolveActivity赋值相应信息该组件用途见第一节。
-+++如果该pkg声明了以共享id运行则获取对应SharedUserSetting对象suid。
-+++调用mSettings.getPackageLPw()获取该pkg对应的packageSetting对象,该pkg如果已安装则存在该对象,未安装过则会新建该对象并分配对应的appid,该appid即uid表示一个特定应用。
-+++将packageSetting对象的appid赋值给ApplicationInfo的uid。这里给出了一个android应用的uid的来源。
-+++调用fixProcessName()确定该应用运行的进程名称。
-+++开始设置该pkg对应的数据目录:判断如果是系统pkg即framework-res.apk直接为其ApplicationInfo设置数据目录为/data/system。
-+++如果是普通pkg,调用getDataPathForPackage()获取其对应的数据目录,如果该目录存在判断其所属uid是否一致处理不一致情况,并且为其ApplicationInfo设置数据目录。该目录不存在则创建,调用createDataDirsLI()执行创建并且为其ApplicationInfo设置数据目录。接着为该pkg确定nativelib所在目录。
-+++提取对应的so文件到制定目录。接着开始对apk进行dex优化操作,然后将Package对象中的四大组件信息登记到PKMS中。
10.依次设置文件夹监听后,删除安装失败的报信息及临时文件。
11.设置对非系统pkg目录监听和扫描,非系统pkg目录包括:/data/app /data/app-private
12.重新为应用赋予权限,最后将已安装的apk信息重新写入package.xml。