PKMS启动详解(二)之怎么通过packages.xml对已安装应用信息进行持久化管理?

Android PackageManagerService系列博客目录:

PKMS启动详解系列博客概要
PKMS启动详解(一)之整体流程分析
PKMS启动详解(二)之怎么通过packages.xml对已安装应用信息进行持久化管理?
PKMS启动详解(三)之BOOT_PROGRESS_PMS_START流程分析
PKMS启动详解(四)之Android包信息体和包解析器(上)
PKMS启动详解(五)之Android包信息体和包解析器(中)
PKMS启动详解(六)之Android包信息体和包解析器(下)
PKMS启动详解(七)之BOOT_PROGRESS_PMS_SYSTEM_SCAN_START阶段流程分析
PKMS启动详解(八)之BOOT_PROGRESS_PMS_DATA_SCAN_START阶段流程分析


引言

  在前面的博客PackageManagerService启动详解(一)之整体流程分析中我们概述了PKMS启动的整体流程,按照正常的逻辑本篇博客将要对PKMS启动的第一阶段BOOT_PROGRESS_PMS_START来个详细的分析,但是发现在这之前非常有必要单独拉出来一篇博客对该阶段将要涉及的Settings以及关联的packages.xml等文件来先分析一番,怎么说呢只有将这块分析透了后续才好进行下去。

是不是感觉上述的描述有点平淡无奇啊,不抛出点灵魂拷问,估计读者都没有兴趣要拍屁股走人了(是时候展示点真正的技术了):
1.PKMS对于扫描成功后的应用信息(也包括第三方安装成功的应用),有没有进行持久化的存储,进行持久化的存储位置是什么

2.如果有进行持久化,那么持久化的形式是什么

3.为什么PKMS需要对已经安装应用的相关信息进行持久化处理

4.对于安装应用被持久化的信息,PKSM是怎么加载的呢

5.PKMS服务既然是加会不会加载上述持久化的数据,如果要加载,是不是应该存在一个管理者,来全局管理,那个这个类是什么

6.系统应用被覆盖升级(即通过普通安装升级)之后重启,PKMS是怎么辨别是使用安装在data分区的还是使用在系统分区的呢

7.如果应用安装目录被删除了,那么PKMS对于它的数据目录会怎么处理呢

是不是前面这一番灵魂大拷问,激起了了你的战斗欲望。读者如果对PKMS服务的管理机制不是很熟悉的话,一时半会回答不上也没有关系!这篇文章要干的就是初步解决上面的疑问,然后为后续具体的PKMS扫描等相关流程打好基础。


注意:本篇的介绍是基于Android 7.xx平台为基础的(并且为了书写简便后续PackageManagerService统一简称为PKMS),其中涉及的代码路径如下:

--- frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java Settings.javaPackageSettingBase.javaPackageSignatures.javaSettingBase.javaSharedUserSetting.java--- frameworks/base/core/res/res/values/attrs_manifest.xml--- frameworks/base/core/java/android/os/Process.java--- frameworks/base//core/java/android/content/pm/ApplicationInfo.java

一.Android安装应用信息持久化区域是什么,涉及到了那些文件

  做人要有始有终方得始终不是,博主是一个负责人的人,所以抛出了问题,必须解决问题不是,这不就安排上了!上面说的安装应用信息持久化区域其实在我们的Android终端的/data/system目录下,这个目录下存储了许多应用运行中生成的配置文件,关于PKMS有如下的几个文件,分别是:

  • packages.xml:记录了系统中所有安装的应用信息,包括基本信息、签名和权限,这个是Android应用信息持久化的关键文件(章节1.2会详细介绍)
  • pakcages-back.xml:packages.xml文件的备份,用于描述系统中所安装的所有 Package 信息,PMS 会先把数据写入 packages-backup.xml,信息写成功后,再改名为 packages.xml
  • pakcages-stoped.xml:记录系统中被强制停止的运行的应用信息。系统在强制停止某个应- 用的时候,会将应用的信息记录在该文件中
  • pakcages-stoped-backup.xml:pakcages-stoped.xml文件的备份
  • package-usage.list:记录了应用的使用情况,譬如使用了多久
  • packages.list:记录了应用的一些简单情况(章节1.1会详细介绍)

这里我们来看下我当前Android系统中相关存储区域涉及的文件信息,如下:



细心的读者看到上面的截图,估计会说博主你这个骗子,欺骗我们的感情,说好的pakcages-back.xml和pakcages-stoped-backup.xml文件怎么没有看到啊!我是无辜的,真的,我没有欺骗你们。

当Android对文件packages.xml和pakcages-stoped.xml写之前,会先把它们备份,如果写文件成功了,再把备份文件删除。如果写的时候,系统出问题了,重启后在需要读取这两个文件时,如果发现备份文件存在,会使用备份文件的内容,因为源文件可能已经损坏了。所以正常情况下我们是看不到的。

1.1 packages.list简介

packages.list文件内容相对简单,我们打开packages.list文件后,我们会发现其中对于系统中所有安装的应用都有类似如下的描述类容(这里我们选择了一个复杂点的):

com.android.settings 1000 0 /data/user_de/0/com.android.settings platform:privapp 3002,1023,1015,3003,3001,1021,3004,3005,1000,2002,2950,1010,1007

是不是被上述一长串信息整蒙了,读者朋友先展开想象,每个字符串代表的意思是什么呢!我们先看下Android源码中对于它的描述,如下:

                // we store on each line the following information for now://// pkgName    - package name// userId     - application-specific user id// debugFlag  - 0 or 1 if the package is debuggable.// dataPath   - path to package's data path// seinfo     - seinfo label for the app (assigned at install time)// gids       - supplementary gids this app launches with//// NOTE: We prefer not to expose all ApplicationInfo flags for now.//// DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES://   frameworks/base/libs/packagelistparser//   system/core/run-as/run-as.c//

有了前面的英文注释,估计读者应该了解的差不多了,这里对每行使用用空格符分了六列,分别代表了每个应用六个相关的信息,如下:

  • 第一列表示安装的应用的包名:也就是AndroidManifest.xml文件中的package=”xxx.xxx.xxx”设置的内容
  • 第二列表示安装的应用userid:如果没有在AndroidManifext.xml里使用android:sharedUserId属性指定UID, 在应用安装的时候,系统会给这个应用自动分配一uid,以后应用运行时,就用这个UID运行
  • 第三列表示安装的应用是否处于调试模式:由AndroidManifext.xml里android:debuggable指定,如果没有指定则通常情况默认为非调试模式,其值为0
  • 第四列表示安装的应用的数据存放路径:一般是”/data/data/${package_name}”这样的文件夹
  • 第五列表示安装的应用的seinfo信息:这个和Android的SELinux有关(如果对于SELinux不是很熟悉的读者可以详见博客Android SELinux开发多场景实战指南有非常详细的介绍),此时的platform是它的标签,我们可以通过如下的命令进行查看:

  • 第六列是安装的应用的所属的user group:如果一个应用不属于任何group, 这里的值是none。

这里我们可以看到com.android.settings存在多个user group,这个也比较好理解就好像你,既属于国家,也属于你老婆,也属于你公司的一个组织罢了。

1.2 packages.xml简介

关于这块建议读者最好了解一下xml的语法,即元素,标签,属性,文本,XML树结构等概念,不是很清楚的可以简单看下博客XML树结构了解一下!

Android安装应用信息持久化核心的文件packages.xml要登场了,我们pull到本地听过文本编辑器打开基本是一样望不到头,它非常非常的长。我看了下我当前的Android终端设备中的该文件有6000多行,这还得了我要是贴上来不会爆了去啊,所以先列出这个文件的框架,以便对它有个整体的认知,然后我们逐一分析:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages><version sdkVersion="xxx" databaseVersion="xxx" fingerprint="xxx" /><version volumeUuid="xxx" sdkVersion="xxx" databaseVersion="xxx" fingerprint="xxx" /><permissions><item name="android.permission.REAL_GET_TASKS" package="android" protection="18" />...</permissions>   <package name="com.android.providers.telephony" codePath="/system/priv-app/TelephonyProvider" nativeLibraryPath="/system/priv-app/TelephonyProvider/lib" publicFlags="1007402501" privateFlags="8" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="25" versionName="7.1.2" applicationName="电话和短信存储" sharedUserId="1001" isOrphaned="true"><sigs count="1"><cert index="1" key="xxx" /></sigs><perms><item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />...</perms><proper-signing-keyset identifier="1" /></package>  ...       <updated-package name="xxx.xxx.xxx" codePath="/system/app/xxx" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="11" nativeLibraryPath="/system/app/xxx/lib" primaryCpuAbi="armeabi-v7a" sharedUserId="1000" /><shared-user name="android.media" userId="10005"><sigs count="1"><cert index="2" /></sigs><perms><item name="android.permission.ACCESS_CACHE_FILESYSTEM" granted="true" flags="0" />...</perms></shared-user>...<keyset-settings version="1"><keys><public-key identifier="1" value="xxx" /><public-key identifier="2" value="xxx" /><public-key identifier="3" value="xxx" />...</keys><keysets><keyset identifier="1"><key-id identifier="1" /></keyset><keyset identifier="2"><key-id identifier="2" /></keyset><keyset identifier="3"><key-id identifier="3" /></keyset>...</keysets><lastIssuedKeyId value="6" /><lastIssuedKeySetId value="6" /></keyset-settings>
</packages>

虽然packages.xml行数着实有点吓人,但是我们抛开表层看本质发现该xml按照层级主要分为下面几个模块标签:

  • permission块标签: 里面包含了系统中所有定义的权限的信息
  • package块标签:里面包含了系统中所有安装的应用的详细信息
  • updated-package块标签:里面包含了被覆盖升级的系统应用的相关信息(如果系统应用存在于这个块中表示被禁用了)

这个块非常重要,因为PKMS服务正是通过它来表明系统应用被升级了,对于这类应用的扫描会采取特殊的规则,从而根据特殊规则确定是使用系统分区的还是data分区的应用最后被安装(因为这其中可能存在着覆盖升级系统应用安装在data分区的应用被异常卸载了,或者系统分区的被root之后异常删除了等等可能的原因)

  • shared-user块标签:里面包含了所有系统定义的shareuser的信息
  • keyset-settings块标签:里面包含了已安装app签名的public key信息

下面我们详细对其中的块的内容,详见的看下(这也是为后续PKMS服务扫描打下基础)。

1.2.1 permissions块标签

permissions块标签的内容如下所示:

    <permissions><item name="android.permission.REAL_GET_TASKS" package="android" protection="18" />...</permissions>

它里面定义了系统中所有的申明的权限信息,可以看到每个item标签块代表一个权限。name属性表示权限的名字,package属性表示申明权限的package, protection表示权限的级别,如normal, dangerous之类的。比较常见protection的含义如下:

  • normal:低风险权限,只要申请了就可以使用(在AndroidManifest.xml中添加标签),安装时不需要用户确认;
  • dangerous:高风险权限,安装时需要用户的确认才可使用;
  • signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它;
  • signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)

关于protection详细介绍可以参见源码的frameworks/base/core/res/res/values/attrs_manifest.xml的grantUriPermissions标签,其中有非常详尽的解释。


1.2.2 keyset-settings块标签

我们接着来看看keyset-settings块标签内容:

    <keyset-settings version="1"><keys><public-key identifier="1" value="xxx" /><public-key identifier="2" value="xxx" /><public-key identifier="3" value="xxx" />...</keys><keysets><keyset identifier="1"><key-id identifier="1" /></keyset><keyset identifier="2"><key-id identifier="2" /></keyset><keyset identifier="3"><key-id identifier="3" /></keyset>...</keysets><lastIssuedKeyId value="6" /><lastIssuedKeySetId value="6" /></keyset-settings>

keyset-settings块标签里收集了所有安装应用签名的公钥信息,和后面介绍的package块中的信息息息相关,这里我们对keyset-settings块标签每个子标签详细介绍下:

  • keysets块标签中包含了很多keyset子标签, 每个keyset都有一个属性编号用identifier表示,keyset里包含的key-id里的identifier和上面keys中public-key的identifier的值相对应
  • keys块中public-key里的value属性值就是从应用安装包中的apk包里的签名文件里提取出来的的公钥的值
  • lastIssuedKeyId和lastIssuedKeySetId标签表示的是最近一次取出来的公钥所属的set编号

1.2.3 shared-user块标签

shared-user块标签在packages.xml中有好几个,我们这里以最最常见的android.uid.system为例来说明:

    <shared-user name="android.uid.system" userId="1000"><sigs count="1"><cert index="1" /></sigs><perms><item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />...</perms></shared-user>
  • name表示这个shared-user的名字,userId表示这个user在系统中的编号,具体可以查看Process.java文件


  • sigs块里的count表示这个当前这个shared-user有多少个签名信息,有的shared-user可能会被多个证书签名。cert里的index表示这个shared-user使用的证书的序号,当系统发现一个新的证书,这个号就会加1,key是shared-user使用的证书内容的ascii码值
  • perms 表示这个user所具有的权限。在开机扫描应用文件时,它会将所有使用了相同uid的应用的权限收集到一起,然后放在这里。并且最后还会把这些权限再下发给那些使用了相同uid的应用。最后的结果就是,系统中使用相同uid的应用它们具有一样的权限

1.2.4 package块标签

激动人心的时刻来了,还记得我们前面所说的Android系统被安装应用持久化存储管理的吗,这里的package标签就是终极答案,这里我们以安装的"支付宝"应用为例,可以看到在packages.xml中通过标签记录了一个应用的基本信息,签名和声明的权限,从而将一个安装应用的信息进行了持久化的存储。我们来对其中牵涉的标签元素来一一揭秘:

    <package name="com.eg.android.AlipayGphone" codePath="/data/app/com.eg.android.AlipayGphone-1" nativeLibraryPath="/data/app/com.eg.android.AlipayGphone-1/lib" primaryCpuAbi="armeabi" publicFlags="941112900" privateFlags="0" ft="17748d73b68" it="17748d80025" ut="17748d80025" version="146" versionName="10.1.70.8308" applicationName="支付宝" userId="10042"><sigs count="1"><cert index="6" key="30820244308201ad02044b28a3c9300d06092a864886f70d01010405003068310b300906035504061302636e3110300e060355040813076265696a696e673110300e060355040713076265696a696e67310f300d060355040a1306616c69706179310f300d060355040b1306616c69706179311330110603550403130a73686971756e2e7368693020170d3039313231363039303932395a180f32303531303131303039303932395a3068310b300906035504061302636e3110300e060355040813076265696a696e673110300e060355040713076265696a696e67310f300d060355040a1306616c69706179310f300d060355040b1306616c69706179311330110603550403130a73686971756e2e73686930819f300d06092a864886f70d010101050003818d0030818902818100b6cbad6cbd5ed0d209afc69ad3b7a617efaae9b3c47eabe0be42d924936fa78c8001b1fd74b079e5ff9690061dacfa4768e981a526b9ca77156ca36251cf2f906d105481374998a7e6e6e18f75ca98b8ed2eaf86ff402c874cca0a263053f22237858206867d210020daa38c48b20cc9dfd82b44a51aeb5db459b22794e2d6490203010001300d06092a864886f70d010104050003818100b6b5e3854b2d5daaa02d127195d13a1927991176047982feaa3d1625740788296443e9000fe14dfe6701d7e86be06b9282e68d4eff32b19d48555b8a0838a6e146238f048aca986715d7eab0fb445796bbd19360a7721b8d99ba04581af957a290c47302055f813862f3c40b840e95898e72a1de03b6257a1acad4b482cd815c" /></sigs><perms><item name="com.android.launcher3.permission.READ_SETTINGS" granted="true" flags="0" />...</perms><proper-signing-keyset identifier="7" /></package>
  • package标签,其中包含了安装应用的详细信息,我们对其中的属性来详细解读一下:

    • name:表示已安装应用的包名

    • codePath:表示的是已安装应用apk文件存放的路径,如果是系统应用app, 通常存放在system分区(也可能是vendor分区),如果是第三方app, 存在data分区

    • nativeLibraryPath表示应用的native库的存储路径

    • primaryCpuAbi:表示当前应用以哪种abi架构运行

    • publicFlags和privateFlags:是指应用的属性,如FLAG_SYSTEM、FLAG_PERSISTENT等,通常根据AndroidManifest.xml里的设置生成的,譬如android:debuggable,至于它支持那些属性可以在ApplicationInfo.java中查看,如下:

    • ft:表示apk文件上次被更改的时间,

    • it:表示app第一次安装的时间

    • ut:表示app上次被更新时间,它的值好像一直和ft相同( 当应用被OTA或被重装之后,这里的ft和ut会发生变化)

    是不是被上面的英文简称搞糊涂了,请看大屏幕如下:

        serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
    
    • version:是app的版本号信息, 也就是在AndroidManifest.xml里配置的android:versioncode
    • userId:是为app分配的user id, 如果有使用shareUserId, 这里出现的就是SharedUserId
  • sign标签,表示已安装应用的签名信息,我们对其中的属性以及它的子标签来详细解读一下:

    • count:表示这个应用有多少个签名信息(有的应用可能会被多个证书签名)
    • cert子标签:cert里的index表示这个应用使用的证书的序号,当系统发现一个新的证书,这个号就会加1,key是应用使用的证书内容的ascii码值。PKMS在扫apk文件过程中,如果发现它和之前扫描到的apk使用的是相同的签名证书,这里就只会有个index的值,并没有key的值。拥有相同的index的package, 表明它们使用的是相同的签名
  • perms标签,表示应用声明使用的权限,每一个子标签代表一项权限,。我们对其中的属性以及它的子标签来详细解读一下:

    • item:表示当前应用所拥有的权限, 对于一般的应用,这些权限是在AndroidManifest.xml里写明的;那些使用了相同UID的应用, 这里的权限就是所有使用相同UID的应用申请的权限的总和。 granted表示这个权限是不是已经被允许
  • proper-signing-keyset标签,它的的identifier属性值就是上面说的keysets里identifier的值。它是用来标明这个应用使用的是哪个公钥,这个我们就不需要展开了

1.2.5 updated-package块标签

updated-package标签通常是用来存储那些系统应用被覆盖升级之后,系统应用之前被安装的信息。这块标签非常重要,因为它会决定PKMS最后到底使用的是系统分区中的应用,还是data应用目录的应用,这个是一个关键。

这个标签可以解决我们前面提出的问题六,关于存在同包名的应用分别在data和system分区到底选择谁的问题。

    <updated-package name="xxx.xxx.xxx" codePath="/system/app/xxx" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="11" nativeLibraryPath="/system/app/xxx/lib" primaryCpuAbi="armeabi-v7a" sharedUserId="1000" />

至于该标签中的属性含义,可以详见前面的,这里就不再赘述了。

1.2.6 renamed-package块标签

renamed-package标签表示是否有被重命名的安装应用,这个标签我也一时半会解释不清楚,大伙可以详见博客Android “original-package” 机制解析机制。

<renamed-package new="com.android.newpackage" old="com.android.original" /><package name="com.android.original" realName="com.android.newpackage" codePath="/system/app/NewPackage.apk" nativeLibraryPath="/system/lib/NewPackage" primaryCpuAbi="armeabi-v7a" publicFlags="940097095" privateFlags="0" ft="1774cbd5ed8" it="1774cbd0500" ut="1774cbd0500" version="1" versionName="1.0" applicationName="NewPackage" sharedUserId="1000" isOrphaned="true"><sigs count="1"><cert index="1" /></sigs><perms><item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />...</perms><proper-signing-keyset identifier="1" />

1.3 Android安装应用信息持久化小结

  至此我们可以回答最开始提出的几个灵魂拷问的前三问了,即Android有没有对已安装信息进行持久化,持久化的区域是什么,持久化存储的格式是什么,为什么需要持久化等。如果对于上述三个问题,读者还没有得到答案,可以继续回看一下(当然我们反过来思考,对于Android系统新安装的APK,肯定也是把新安装的APK相关信息写入这个packages.xml文件中)。

对于上述几个持久化的文件是必要但是非必须的的,假如我们将其都进行删除,然后重启Android终端,终端依旧能正常运行。但是重启过程中会对上述文件进行重构,就好像Android设备第一次启动一样。


二.Android安装应用信息持久化怎么被加载和管理

  Android系统这么大费周章的设计了这么一套安装应用信息持久化系统,那么对于持久化区域的信息是怎么进行加载和管理的呢?这就是本章节需要重点讨论的,我想有过一定开发经验的读者大概很容易的会想到,Android中一定存在对应的数据结构类对应上述的持久化信息特别是packages.xml中的各个标签,然后使用一个整体的数据结构来管理上述的各个标签对应的数据结构。答案是肯定的,Android系统的确是这样设计的,packages.xml中的每个标签记录信息都对应着一个特定的类,所以在正式开始分析持久化信息怎么被加载和管理前,我们又必要先来看下这其中将要涉及的类图关系图,如下:



应该读者看了前面的类图关系图,心理应该就大概有数Android系统怎么对持久化信息进行加载和管理了。即一个大标签对应一个数据结构,然后通过一个大管家类对上述的数据结构统一管理。

下面我们对其中各种标签对应的数据结构类和管理类一一梳理梳理一下,为后续开启PKMS总攻做好准备!

2.1 BasePermission

  BasePermission对应packages.xml中permissions标签的子标签item,对于上述所定义的每一项权限都会生成一个BasePermission,并且所有BasePermission最后都会聚集在Settigns中,其对应的标签如下:

    <permissions><item name="android.permission.REAL_GET_TASKS" package="android" protection="18" />...<permissions/>

其中BasePermission的类图如下,可以和上面的permissions标签的子标签item是一一对应的。



注意上述标签主要表明的是权限的持有者相关信息,这个信息最后会被添加到Setings大管家类mPermissions列表中统一管理。

2.3 PermissionsState

  这个类封装了应用程序安装包或共享用户的权限,它聚合了包中所有权限的授予状态,在多用户的场景下,不同用户的授权情况不同,因此要区分出一个权限针对每个用户的授予情况,为此设计了一个数据封装类PermissionData(注意,这是单数),记录了一个BasePermission与多个用户mUserState之间的关系。每一个用户的权限授予状态用PermissionState(注意,这是单数)来记录。其中PermissionsState涉及的类图关系如下:



这里我们可以看到其中的PermissionState对应的是<package>标签中的子标签<perms>标签中的内容:

            <item name="android.permission.BIND_INCALL_SERVICE" granted="true" flags="0" />
  • name: 对应权限名称
  • granted: 表示赋予情况

PermissionState和BasePermission之间牵涉到Android应用授权的关系,这个不在本章的讨论分为之内!我们可以简单理解为BasePermission为权限持有者,而PermissionState记录的是权限申请者的相关信息譬如有被授权等。关于它们之间的关系的总结墙裂建议读者参见一篇牛逼博客Android包管理机制章节3.3应用授权。

2.4 PackageSetting

  PackageSetting这个数据结构类是packages.xml里面记录安装包信息标签<package>相对应的类,可以看到PackageSetting继承了PackageSettingBase类,PackageSettingBase类继承自SettingBase类。应用的基本信息保存在PackageSettingBase类的成员变量中,签名则保存在PackageSignatures中,权限状态保存在父类的SettingBase的PermissionsState中。

PackageSetting中存储的应用安装信息,最终会被添加到Settings中的mPackages列表中统一进行管理。

2.5 SharedUserSetting

  SharedUserSetting这个数据结构类是packages.xml里面记录安装包信息标签<shared-user>相对应的类,它和PackageSetting有一个共同的父类即SettingBase,即都是通过父类的PermissionsState来保存权限信息。SharedUserSetting被设计的用途主要用来描述具有相同的sharedUserId的应用信息,它的成员变量packages保存了所有具有相同sharedUserId的应用信息引用,而成员变量userId则是记录多个APK共享的UID。共享用户的应用的签名是相同的,签名保存在成员变量signatures中(这里有一点需要注意,由于签名相同,Android运行时很容易检索到某个应用拥有相同的sharedUserId的其他应用)。



这里来补充一下shareUserId与UID的关联知识:
1、两个或多个APK或者进程声明了同一种sharedUserId的APK可以共享批次的数据,并且可以在运行在同一进程中(相当于进程是系统的用户,某些进程可以归为同一用户使用,相当于Linux系统中的GroupId)

2、通过声明特定的sharedUserId,该APK所在的进程将被赋予指定的

3、通过声明特定的sharedUserId,该APK所在的进程将被赋予指定的UID,将被赋予该UID特定的权限。

4、并且有一点需要注意在pacakge的标签中sharedUserId和userId是不能共存的,因为安装应用申请了同一个sharedUserId它们的UID就已经是固定的了

SharedUserSetting中存储的应用安装信息,最终会被添加到Settings中的mSharedUsers列表中统一进行管理。

2.6 Settings终极大管家类

  分析到这里是不是感觉前面的数据结构还是一盘散沙,这些数据结构照科学的架构设计,是不是应该存在一个管理类,来进行全局的管理呢?毋庸置疑答案是肯定的,在PKMS的设计中存在一个这么的类就是Settings终极大管家类(注意此Setings并非设置中的Settings),Settings被设计为Android的包的全局管理者,用于协助PKMS保存所有的安装包信息,同时用于存储PKMS在执行过程中的一些设置信息。

既然Settings这个终极大管家这么重要,那么它是是怎么管理前面的各种标签对应的数据类(即将它们聚合在一起呢),这个就离不来各种数据容器了,而这些数据容器都被定义在其成员变量中,我们先来看下它的类图,如下:



我们还是从源码入手来解读一下,它的重要成员变量

final class Settings {//被安装应用的包名为key,以安装应用相关信息为value,对应的是packages.xml中的<package>标签final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();/*对应packages.xml中的<updated-package>标签被覆盖升级的系统应用其中key为被覆盖升级的应用包名,value为被覆盖升级前的安装信息*/private final ArrayMap<String, PackageSetting> mDisabledSysPackages =new ArrayMap<String, PackageSetting>();/*对应packages.xml中的<cleaning-package> 标签用来记录那些已经删除,但是数据目录还暂时保留的应用的信息。对应的是PackageCleanItem*/final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();// 存储所有package.xml中shared-user标签的信息// 是一个以String类型的name(比如"android.uid.system")为"key",以SharedUserSetting对象为"value"的HashMapfinal ArrayMap<String, SharedUserSetting> mSharedUsers =new ArrayMap<String, SharedUserSetting>();// 存储是非系统应用的PackageSettingprivate final ArrayList<Object> mUserIds = new ArrayList<Object>();// 存储是系统应用的的的PackageSettingprivate final SparseArray<Object> mOtherUserIds =new SparseArray<Object>();
}

这里将Setings大管家类牵涉的核心数据摆出来,读者应该很容找到对应的关系了。但是这里Settings里面有牵涉到的四个非常重要的成员变量:mPackages,mSharedUsers,mUserIds ,mOtherUserIds 还是有必要重点介绍一下:

  • mPackages:是一个以String类型的name为"key",PackageSetting对象为"value"的ArrayMap

  • mSharedUsers:是一个以String类型的name(比如"android.uid.system")为key,ShareUserSetting对象为"value"的ArrayMap,它对应着各种常见的共享用户信息

  • mUserIds:它存储是的非系统应用的PackageSetting列表对象

  • mOtherUserIds :它存储是系统应用的的PackageSetting相关信息


总结

  至此,"PackageManagerService详解之对已安装应用怎么进行持久化存储管理?"到这里就告一段落了,不知道我前面提出的灵魂拷问是否已经有答案了,如果没有墙裂建议读者再回过头再去看看(如果这么详细还是没有办法理解的话,那我真的也没有办法了!)。

是不是感觉上述的描述有点平淡无奇啊,不抛出点灵魂拷问,估计读者都没有兴趣要拍屁股走人了(是时候展示点真正的技术了):
1.PKMS对于扫描成功后的应用信息(也包括第三方安装成功的应用),有没有进行持久化的存储,进行持久化的存储位置是什么

2.如果有进行持久化,那么持久化的形式是什么

3.为什么PKMS需要对已经安装应用的相关信息进行持久化处理

4.对于安装应用被持久化的信息,PKSM是怎么加载的呢

5.PKMS服务既然是加会不会加载上述持久化的数据,如果要加载,是不是应该存在一个管理者,来全局管理,那个这个类是什么

6.系统应用被覆盖升级(即通过普通安装升级)之后重启,PKMS是怎么辨别是使用安装在data分区的还是使用在系统分区的呢

7.如果应用安装目录被删除了,那么PKMS对于它的数据目录会怎么处理呢

总之读者如果想深入PKMS一定要了解它对于Android安装应用持久化管理的设计思想,因为在后续应用扫描升级,权限管理中会非常依赖这些数据。不要觉得这些不重要,一定在干一个大事件之前先处理好小细节,对于PKMS尤其如此,先把利器打磨好,才开干我想一定会取得事半功倍的成果的。

好了,到这里“PackageManagerService详解之对已安装应用怎么进行持久化存储管理?”分析就告一段落了,各位青山不改绿水长流,各位江湖见!当然各位读者的点赞和关注是我写作路上前进的最大动力了,如果有啥不对或者不爽的也可以踩一踩也无妨!如果对PKMS感兴趣的读者可以继续下一篇章PackageManagerService启动详解(三)之BOOT_PROGRESS_PMS_START流程分析,我们接着分析!

PackageManagerService启动详解(二)之怎么通过packages.xml对已安装应用信息进行持久化管理?相关推荐

  1. PackageManagerService启动详解(三)之开始初始化阶段流程分析

      PKMS启动详解(三)之BOOT_PROGRESS_PMS_START阶段流程分析 Android PackageManagerService系列博客目录: PKMS启动详解系列博客概要 PKMS ...

  2. PackageManagerService启动详解(七)之扫描系统应用安装目录阶段流程分析

    PKMS启动详解(七)之BOOT_PROGRESS_PMS_SYSTEM_SCAN_START阶段流程分析 Android PackageManagerService系列博客目录: PKMS启动详解系 ...

  3. PackageManagerService启动详解(五)之Android包信息体和解析器(中)

        PKMS启动详解(五)之Android包信息体和包解析器(中) Android PackageManagerService系列博客目录: PKMS启动详解系列博客概要 PKMS启动详解(一)之 ...

  4. Android 10.0 Activity启动详解(二)

    Android 10.0 Activity启动详解(一) 我们在上一篇博客中已经介绍了关于Activity的一些基础概念.这一篇博客我们以Android 10.0的代码来分析Activity的启动流程 ...

  5. linux 进程间通信 dbus-glib【实例】详解二(下) 消息和消息总线(ListActivatableNames和服务器的自动启动)(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  6. linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  7. Android Loader 异步加载详解二:探寻Loader内部机制

    Android Loader 异步加载详解二:探寻Loader内部机制 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/7025991 ...

  8. OS--进程间通信详解(二)

    OS–进程间通信详解(二) 文章目录 OS--进程间通信详解(二) 一.进程间通信 1.互斥量 Futexes Pthreads中的互斥量 2.管程 3.消息传递 消息传递系统的设计要点 用消息传递解 ...

  9. Android中AMS工作原理,Android AMS启动详解

    启动 在Android系统启动流程中中我们提到过,AMS是在system_service中启动的, //frameworks/base/services/java/corri/android/serv ...

最新文章

  1. 《Advanced PHP Programming》读书笔记
  2. 12Singleton(单例)模式
  3. ggplot2笔记8:主题设置、存储导出
  4. CSDN挑战编程——《数学问题》
  5. TStringList 的Sorted属性
  6. bio-linux_Bio-Linux:稳定,可移植的科学研究Linux发行版
  7. TensorFlow HOWTO 1.4 Softmax 回归
  8. 系统集成项目管理工程师考试复习-Part3
  9. ECharts图表tooltip显示时超出canvas图层解决方法
  10. 关于oracle存储微信表情emoji问题 “[[%F0%9F%A4%AA]]“
  11. angular图片裁剪
  12. html5学习计划,关于学习计划模板汇编5篇
  13. detecting current sdk tools version
  14. 补天漏洞平台:让更多的白帽子脱离黑产
  15. 程序员眼中的编程语言和操作系统
  16. 谷爱凌母亲 24 年前重磅采访:远见卓识的人,可以改变世界
  17. 设置字段默认值Java_小书MybatisPlus第9篇-常用字段默认值自动填充
  18. 计算机的键盘怎么调,键盘灵敏度,教您怎么调节电脑键盘灵敏度
  19. 【源码】iOS指纹解锁Touch ID的开发
  20. [附源码]Java计算机毕业设计SSM大学生就业推荐系统

热门文章

  1. 软件有源电力滤波器APF仿真,simulink仿真。三相三线制APF,三相四线制四桥臂APF
  2. 微信开发者工具修改主题颜色
  3. 小林和单字母.CN域名的那些事(下)
  4. 【UI3D】当UI亲吻3D—浅谈手机UI发展
  5. A Lifelong Learning Approach to Brain MR Segmentation Across Scanners and Protocols(附翻译)
  6. ZZULIOJ-1091,童年生活二三事(多实例测试)(Python)
  7. (附源码)计算机毕业设计SSM智慧后勤app
  8. cve-2016-4977(spring-security-oauth) RCE漏洞复现
  9. 启动egg项目时报错ERROR 11104 nodejs AgentWorkerDiedError [master] agent_worker#1:9544 died (code : 1, signa
  10. 幼儿园开学教学课件PPT模板