PackageManagerService分析(一)

         PackageManagerService(以下简称PKMS)是Android系统中最重要的几个服务之一。PKMS负责管理系统的Package,包括APK的安装,卸载,信息的查询等等。它的功能非常的多,也非常的强大。这里从开机入手,分析PKMS的启动流程,本文源码基于Android6.0.1。

PKMS启动流程分为以下几个部分

1.   PKMS的创建

2.   扫描XML文件并解析成对应的数据结构

3.   扫描apk目录并解析成对应的数据结构

4.   解析完文件后的收尾工作


一  PKMS的创建

PackageManagerService作为系统核心服务,由SystemServer创建。

《PackageManagerService分析(一)》

1.1 Zygote fork出SystemServer后,SystemServer执行其main函数。在main函数中调用其静态方法run().

public static void main(String[] args) {
    new SystemServer().run();
 }

1.2 在run方法中首先设置系统的语言环境、设置虚拟机运行内存,加载运行库等。然后启动服务,分别调用startBootstrapServices()startCoreServices()startOtherServices()

1.3 PKMS就是在startBootstrapServices()中被启动起来的,startBootstrapServices()调用了PKMSmain函数

1.4 PKMSmian函数中首先创建了PKMS的对象,然后将该对象添加到ServiceManager中。创建PKMS对象就是我们本文需要分析的重点。


二  扫描XML文件并解析成对应的数据结构

《PackageManagerService分析(一)》

2.1 PKMS会获取SystemConfig的实例,SystemConfig是一个单例,其构造函数中会调用readPermissions(),分别从手机目录etc/sysconfig、etc/permissions、oem/sysconfig、oem/permissions文件中读取权限。

文件中权限主要有以下几类

1)permission

<permission name="android.permission.WRITE_MEDIA_STORAGE" > <group gid="media_rw" /> <group gid="sdcard_rw" /> </permission>

建立权限名和gid的映射关系,因为这些权限涉及和linux内核交互,所以需要在底层权限(有不同的用户组界定)和Android层权限(由不同的字符串界定)之间建立映射关系。

2)assign-permission

<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />

赋予uid相应的权限

3)library

<library name="android.test.runner" file="/system/framework/android.test.runner.jar" />

4)feature

 例如在文件android.hardware.camera.xml:

<!– This is the standard set offeatures for an camera. –>

<permissions> <feature name="android.hardware.camera" /> <!-- unmark following line if the hardware supports autofocus --> <feature name="android.hardware.camera.autofocus" /> <feature name="android.hardware.camera.flash" /> <feature name="android.hardware.camera.front" /> <feature name="android.hardware.camera.any" /> </permissions> 

表示手机相机所应该支持的特性。


2.2. 解析完这些文件后PKMS会调用getGlobalGids()等方法获取解析后的数据,并保存在自己的数据结构中,数据结构如下

mGlobalGids int[]  用于存储group标签定义的gid

mSharedlibraries HashMap<String ,String> 解析library标签所得,Key为库的名字,value为库文件位置

mSystemPermissionsSparseArray<HashSet<String>> 解析assign-permission标签所得,UID为索引,HashSet存储的是UID所拥有的权限

mAvailableFeatures HashMap<String ,FeatureInfo>解析feature标签所得,Key为feature的字符串描述,value为FeatureInfo对象

mSettings.mPermissions Hashmap<String ,BasePermissions> 解析permission标签所得,Key为权限名,value为BasePermission对象,BasePermission对象中一个gids数组,用于保存权限对应的gid。


2.3. 接着PKMS调用Settings的readLpw()解析上一次安装的信息,xml文件保存在data/system/package.xml和data/system/package-backup.xml,其中后一个是用来备份前一个文件的。

      package.xml内容标签如下:

1)package

<package name="com.android.certinstaller" codePath="/system/app/CertInstaller" nativeLibraryPath="/system/app/CertInstaller/lib" publicFlags="944258629" privateFlags="0" pkgFlagsEx="0" ft="15d07abf440" it="15d07abf440" ut="15d07abf440" version="23" userId="10044"> <sigs count="1"> <cert index="2" /> </sigs> <perms> <item name="android.permission.CHANGE_WIFI_STATE" granted="true" flags="0" /> <item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" /> </perms> <proper-signing-keyset identifier="1" /> </package> 

      上次安装的apk信息,一个package标签会解析为一个PackageSetting对象,当标签为UserID时,保存在mPackages中,当标签为shareUserID,表示使用共享ID,暂时保存在mPendingPackages中,待解析完shareUserID后保存在mPackages中。

       Android系统中,大于或者等于FIRST_APPLICATION_UID(10000)并且小于(FIRST_APPLICATION_UID+ MAX_APPLICATION_UIDS(1000))的linux用户ID是保留给应用程序使用的,而小于FIRST_APPLICATION_UID的Linux用户ID是保留给特权用户使用的。


2)permissions

<permissions> <item name="com.google.android.apps.docs.editors.punch.permission.READ_MY_DATA" package="com.google.android.apps.docs.editors.slides" protection="2" /> <item name="android.permission.REAL_GET_TASKS" package="android" protection="18" /> <item name="android.permission.REMOTE_AUDIO_PLAYBACK" package="android" protection="2" /> <item name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" package="com.android.providers.downloads" /> ….. </permissions> 

     权限的集合,以及每个权限所属的包。保存到mPermissions中,前面解析etc/permissions等目录的权限是这里面的一小部分。


3)share-user

<shared-user name="android.uid.calendar" userId="10043"> <sigs count="1"> <cert index="4" /> </sigs> <perms> <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" /> <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" /> <item name="android.permission.WRITE_SYNC_SETTINGS" granted="true" flags="0" /> <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" /> <item name="android.permission.SUBSCRIBED_FEEDS_READ" granted="true" flags="0" /> <item name="android.permission.SUBSCRIBED_FEEDS_WRITE" granted="true" flags="0" /> <item name="huawei.permission.BIRTHDAY_CALENDAR_CHANGED" granted="true" flags="0" /> <item name="android.permission.READ_SYNC_STATS" granted="true" flags="0" /> <item name="android.permission.READ_SYNC_SETTINGS" granted="true" flags="0" /> <item name="android.permission.WAKE_LOCK" granted="true" flags="0" /> </perms> </shared-user> 

        一个共享用户ID,包含了name 、userId、所拥有的权限等。


        由于解析package.xml 这步涉及较多的数据结构来保存上面解析的数据,下面梳理一下

《PackageManagerService分析(一)》

         主要涉及的是Settings类,Settings的作用是管理Android系统运行过程中的一些设置信息。

上面解析XML过程主要涉及到以下的几个类


Settings  

mPackages:解析package.xml或package-backup.xml中package标签,存储了上次安装APK的信息。

mPermissions:Key为权限名称,value为BasePermission对象。解析permissions标签所得

                       BasePermission成员变量如下

                               name:权限名称

                               sourcePackage:定义权限的包名,由解析etc/sysconfig、etc/permissions oem/sysconfig、                                                                                oem/permissions这几个文件的包名都为Android,且权限都有对应的gid。

                               gids:权限对应的gid

mShareUsers: 解析package.xm中shared-user标签,Key为shared-user名称,value为ShareUserSetting对象

                       ShareUserSetting成员变量如下:

                                 name:共享用户名称

                                 userId:共享用户ID

                                 packages:使用共享ID的包的集合

mUserIds: ArrayList  Object为PackageSetting对象,索引为UID。解析package标签,和mPackages内容类似,只是为了提高读  取速度

mOtherUserIds: SparseArray Object为ShareUserSetting对象 索引为UID。解析share-user标签 和mShareUsers类似,只是为    了提高读取速度

以索引获取数组的元素的速度,比以key获取HashMap中元素的速度要快很多,这是以时间换空间的做法。


至此,PackageManagerService第一部分解析XML文件完成。

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