1.Settings类
1 | // Settins文件 data/system/packages.xml |
1.1 Setting构造函数
1 | Settings(File dataDir, PermissionSettings permission, Object lock) { |
Setting构造函数主要工作是创建系统文件夹,一些包管理的文件
packages.xml、packages-backup.xml是一组,用于描述系统所安装的Package信息,其中packages-backup.xml是packages.xml的备份
packages.list用于描述系统中存在的所有非系统自带的apk信息以及UID大于10000的apk。当APK有变化时,PKMS就会更新该文件。
1.2 addSharedUserLPw方法
该方法将shareUserId name和一个int类型的UID对应起来。UID的定义在Process.java中。
1 | SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) { |
1 | /** |
Setting模块的AndroidManifest.xml里面,如下所示:
1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
在xml里面android:sharedUserId属性设置为”android.uid.system”。sharedUserId这个属性主要有两个作用:
1.两个或者多个声明了同一种sharedUserId的应用可以共享彼此的数据
2.通过声明特定sharedUserId,该应用所在进程将赋予指定的UID。如Setting声明了system的uid,则就可以共享system用户所对应的权限。
除了了xml了声明sharedUserId外,应用编译的时候还必须使用对应的证书进行签名。如Setting需要platform的签名。
1.3 PID、UID、GID的区别
PID是进程的身份识别,程序一旦运行,就会给应用分配唯一的PID。一个应用可能包含多个进程,每个进程有唯一的一个PID。进程终止后PID被系统回收,再次打开应用,会分配一个PID(新进程的PID一般比之前的号大)。
调用adb shell ps可以查看系统运行的进程。
UID是用户ID。UID在linux中就是用户ID,表明哪个用户运行了这个程序,主要用于权限的管理。而Android为单用户系统,这时候UID被赋予了新的使命,数据共享,为了实现数据共享,android为每个应用都分配了不同的uid,不像传统的linux,每个用户相同就为之分配相同的UID。
GID时用户组ID。对于普通的应用程序来说GID等于UID,由于每个应用程序的UID和GID不相同,所以不管是native还是java层都能够达到保护私有数据的作用。
adb shell cat /proc/PID号/status
SharedUserSetting类架构
PKMS的构造函数创建一个Settings的实例mSettings,mSettings有三个成员变量mSharedUsers,mUserIds,mOtherUserIds。addSharedUserLPw方法都涉及这三个成员变量。SharedUserSetting的成员变量packages是一个PackageSetting类型的ArraySet。PackageSetting继承自PackageSettingBase,PackageSetting保存着package的多种信息。
2.SystemConfig类
2.1 SystemConfig构造函数
主要读取下面路径的配置
/system/etc/、/system/etc/、/vendor/etc、/odm/etc、/oem/etc、/product/etc 目录下sysconfig和permissions
1 | SystemConfig() { |
SystemConfig构造函数中主要通过readPermissions函数将对应目录下的xml文件中定义的各个节点读取出来保存到SystemConfig成员变量中。在终端的/system/etc/permissions目录下可以看到很多xml配置文件,如下:
1 | HWSTF:/system/etc/permissions $ ls -all |
这些配置文件都是编译时从framework指定位置拷贝过来的(framework/native/data/etc),下面是platform.xml里面的部分
1 | <permissions> |
readPermissions方法内部调用readPermissionsFromXml方法来解析xml里面的各个节点,其中xml涉及到的标签内容有permission、assign-permission、library、feature等,这些标签的内容解析出来保存到SystemConfig的对应数据结构的全局变量中,以便管理查询。
feature用来描述设备是否支持硬件特性; library用于指定系统库,当应用程序运行时,系统会为进城加载一些必须的库; assign-permission将system中描述的permission与uid关联; permission将permission和gid关联。
总结下SystemConfig初始化时解析xml文件节点以及对应的全局变量。
3. PackageParser
这个类作用是解析APK,在其类中注释如下:
1 | /** |
这个类主要用于解析apk安装包,它能解析单一apk文件,也能够解析multiple APKs(一个apk文件里面包含多个apk文件)。这些multiple APKs需要满足下面几个条件:
1.所有的apk必须具有完全相同的软件包包名,版本代码和签名证书
2.所有的apk必须具有唯一的拆分名称
3.所有安装必须含有一个单一的apk
解析步骤
1.将apk解析成package
2.将package转化为packageinfo
类结构
里面有很多内部类和方法,下面讲介绍里面的主要内部类以及部分解析的方法
3.1 内部类
3.1.1 NewPermissionInfo
记录新的权限
1 | /** @hide */ |
3.1.2 SplitPermissionInfo
主要记录一个权限拆分为颗粒度更小的权限
1 | /** @hide */ |
3.1.3 ParsePackageItemArgs
主要为解析包单个item的参数
1 | static class ParsePackageItemArgs { |
3.1.4 ParseComponentArgs
主要为解析包中单个组件的参数
1 | /** @hide */ |
3.1.5 PackageLite
表示在解析过程中的一个轻量级的独立的安装包
1 | /** |
3.1.6 ApkLite
表示解析过程中的一个轻量级独立的apk
1 | /** |
备注:PackageLite和ApkLite代表不同的含义,前者是包,后者是指apk,一个包中可能包含多个apk
3.1.7 SplitNameComparator
表示类比较器,在拆包中排序用到
1 | /** |
3.1.8 Package
表示从磁盘上的apk文件解析出来的完整包,一个包由一个基础的apk和多个拆分的apk构成。
1 | /** |
3.1.9 Component
1 | public static abstract class IntentInfo extends IntentFilter { |
3.1.10 Permission
继承于Component,对应AndroidManifest里面的
1 | public final static class Permission extends Component<IntentInfo> implements Parcelable { |
继承于Component,对应AndroidManifest里面的
1 | public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable { |
一些其他的基本类似类在这里就不再详细的介绍,下面看下类里面的一些方法:
3.2 内部方法
里面的方法基本上是和解析相关的方法,这里以parseActivity为例说明,其他的解析大同小异。
3.2.1 parsePackage
这个类是解析package最开始的方法,其他的解析方法都是从这个入口进入的,这里分为两种解析,一种是single APK ,另一种是cluster APKs。
1 | /** |
3.2.2 parseActivity
这个方法主要是解析AndroidManifest中activity标签的内容,并将其保存到PackageParser.Activity对象中。
1 | private Activity parseActivity(Package owner, Resources res, |
3.3 PackageParser总结
上图画出了PackageParser解析Apk文件,得到的主要的数据结构,实际的内容远多于这些,我们仅保留了四大组件和权限相关的内容。
上面这些类,全部是定义于PackageParser中的内部类,这些内部类主要的作用就是保存AndroidManifest.xml解析出的对应信息。 以PackageParser.Activity为例,注意到该类持有ActivityInfo类,继承自 Component< ActivityIntentInfo>。其中,ActivityInfo用于保存Activity的信息;Component类是一个模板,对应元素类型是ActivityIntentInfo,顶层基类IntentFilter。四大组件中的其它成员,也有类似的继承结构。
这种设计的原因是:Package除了保存信息外,还需要支持Intent匹配查询。例如,当收到某个Intent后,由于ActivityIntentInfo继承自IntentFilter,因此它能判断自己是否满足Intent的要求。如果满足,则返回对应的ActivityInfo。
PackageParser整个扫描过程如下:
PackageParser首先解析出ApkLite,得到每个Apk文件的简化信息;
利用所有的ApkLite以及Xml中其它信息,解析出PackageLite;
- 利用PackageLite中的信息及XML中的其它信息,解析出Package信息;
Package中基本上涵盖了AndroidManifest中涉及的所有信息。
注意:在上述的解析过程中,PackageParser利用AssetManager存储了Package中资源文件的地址。
附录
源码路径
1 | /frameworks/base/services/core/java/com/android/server/pm/Settings.java |