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

PKMS启动详解(四):深入解析Android包解析器PackageParser
本文详细剖析了Android包解析器PackageParser的设计思想、核心成员变量和关键方法,展示了如何通过这些工具构建Android包信息。

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


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阶段流程分析



引言

  在前面的博客PKMS启动详解(四)之Android包信息体和包解析器(上)中我们重点从Android包管理机制的设计者角度出发,着重分析了:

  • Android包管理机制中的Android包信息体设计思想和源码逻辑
  • Android包管理机制中的Android包解析器PackageParser设计思想

那么在今天的博客中,我们将再接再厉,一鼓作气的继续分析Android包解析器PackageParser源码实现逻辑!

在正式开始本篇的博客相关分析前,还是非常有必要放出包解析器PackageParser的核心结构图(前面是借用其他博主的,这里就自己花费些时间单独画了):
在这里插入图片描述
同时本篇博客对于包解析器PackageParser类源码,会遵从如下几个方面来进行入手来分析(也可以人为是本篇博客的中心):
1.从包管理机制设计者意图了解它,即它的概述和定义是什么

2.它作为一个工具类,它的核心成员变量是什么(当然是和包信息体的封装有关)

3.它作为一个工具类,它的核心方法有那些(核心方法就是解析Android包)

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

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

frameworks/base/core/java/android/content/pm/PackageParser.java



一.从源码的角度概述Android包解析器PackageParser

在前面的博客中,我们从理论上知道了包解析器PackageParser是Android包管理机制设计的一个用于解析Android包的工具类,但是对于它的具体实现我们知之甚少,从这个章节开始我们就从源码角度出发对其展开猛烈的攻势,争取将其一举拿下!实干出真知!

  通常了解一个人首先是从看脸开始(也不排除其它的位置啊,哈哈!),而看Android源码类通常可以从设计者着对它的概述开始,我们这里对于包解析器PackageParser的深入了解也不能免俗的遵循这个定理,我们看看设计者是如何对它进行定义的,如下:

// 【 PackageParser.java】

/**
* Parser for package files (APKs) on disk. This supports apps packaged either 
* as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
* APKs in a single directory. 

* Apps packaged as multiple APKs always consist of a single "base" APK (with a 
* null split name) and zero or more "split" APKs (with unique split 
* names). Any subset of those split APKs are a valid install, as long as the 
* following constraints are met: 
* 	All APKs must have the exact same package name, version code, and signing certificates. 
* 	All APKs must have unique split names. 
* 	All installations must contain a single base APK. 
* 
* @hide
*/


public class PackageParser {
   
   
	...
}

对于上述的描述,英文比较好的读者估计连蒙带猜基本能内部消化了,对于不能内部消化的只能且听我来分解了:

上述的注释非常经典没有过多的拖泥带水,我们对其强撸一番!
1.PackageParser是用于磁盘上包文件(APKs)的解析器。它即支持打包成单个“单块”APK的应用程序的解析,同时也支持打包成多个APK在单个目录中的“集群”应用程序的解析

2.一个"集群"APK有一个"基准"APK(base APK)组成和其他一些"分割"APK(“split” APKs)构成,其中这些"分割"APK用一些数字来分割。这些"分割"APK的必须都是有效的安装,同时必须满足下面的几个条件:

  • 所有APKs必须具有完全相同的包名、版本代码和签名证书。
  • 所有APK必须有唯一的拆分名称。
  • 所有安装必须包含一个单一的APK

3.并且该类是一个hide类,说明它只能用于Android内部使用,不能被第三方应用使用


1.1 Android安装包的形态

在前面的注释中,多次提到了single APK和multiple APKS这两个概念,那么它们纠结表示什么呢!我们们分别来说(其实从单复数就说明情况了)。

1.1.1 Single APK

对于Single APK就比较好理解了,它通常所开发的APK,即每一个应用安装包有且只存在一个.apk文件,形如下面的形式:

xxx:/system/system_ext/priv-app/Settings $ ls
Settings.apk
1.1.2 Multiple APKS

在Android L(5.0)以后,支持APK拆分,即一个APK可以分割成很多部分,位于相同的目录下,每一个部分都是一个单独的APK文件,所有的APK文件具备相同的签名,在APK解析过程中,会将拆分的APK重新组合成内存中的一个Package。对于一个完整的APK,Android称其为signle APK;对于拆分后的APK,Android称其为multiple APKS。此时形如下面的形式:

xxx:/system/system_ext/priv-app/Settings $ ls
Settings-base.apk Settings-split.apk

对于有过一定Android开发经验的读者一定知道在Android L(5.0)以前,APK文件都是直接位于app或priv-app目录下,譬如短彩信APK的目录就是/system/priv-app/Mms.apk;到了Android L(5.0)之后,多了一级目录结构,譬如短彩信APK的目录是/system/priv-app/Mms/Mms.apk,这是Android为了支持APK拆分而做的改动,如果要将短彩信APK进行拆分,那所有被拆出来的APK都位于/system/priv-app/Mms/即可,这样在包解析时,就会变成以multiple APKS的方式解析目录。

并且这里有一点需要注意,对于/system/priv-app/Mms/下面的安装包,无论他是否multiple APKS形式的,最后都会调用parseClusterPackage方法来进行解析,这个读者一定要注意,注意!千万不要把Multiple APKS和Cluster解析混淆了!它们之间的前提是Multiple APKS一定是采取Cluster解析方式,但是采取Cluster不一定是Multiple APKS也可能是Single APK。

关于Multiple APKS详细介绍可以参看谷歌官网多APK支持

1.1.3 不同安装包的解析方式

对于Android安装包的形式我们理解清楚了,从而会导致包解析器PackageParser对于上述二者会采取不同的解析方式,但是最后都会徐途同归(至于怎么具体解析的,后续详细分析)!

在这里插入图片描述


并且这里再次强调一点,对于Single APK安装包采取parseMonolithicPackage()还是parseClusterPackage()的解析方式,这个取决于安装包的路径是否是一个文件夹!注意,注意,注意!


1.2 包解析器PackageParser解析Android包的步骤

通过前面的努力我们知道了,PackageParser的核心功能就是解析各种类型的Android包(其实也就两种而已),而解析包的最最主要逻辑就是解析APK文件,在正式开始PackageParser解析Android包之前,这里我们先给出解析一个APK主要是分为两个步骤:

  • 将APK解析成Package数据结构:即解析APK文件为Package对象的过程。

    此处是我们今天博客的重点!

  • 将解析得到的Package填充为PackageInfo数据结构:即由Package对象生成Package对象生成PackageInfo包信息体的过程

    关于Android包信息体我们在前面的博客中已经重点的介绍过,重点关注它是怎么被填充的




二.PackageParser重要成员

  对于PackageParser我们该了解的不该了解的都了解了,是时候对其展开真刀真枪的实干了。这里我们先从其成员(或者是内部类)入手展开!在PackageParser中定义了非常多的内部类用来解析PackageParser,如下所示:

在这里插入图片描述


2.1 IntentInfo内部类

通过前面的博客总结我么可知,对于APK中的androidmanifest.xml的<activity>,<service>标签,都可以配置<intent-filter>,来过滤其可以接收的Intent,这些信息也需要在包解析器中体现出来,为此组件Component依赖于IntentInfo这个数据结构。每一个具体的组件所依赖的IntentInfo不同,所以ComponentIntentInfo之间的依赖关系采用了桥接(Bridge)这种设计模式,通过泛型的手段实现。

所以这里我们就来看下IntentInfo的实现。

没有啥好说的,直接来看源码!

// 【 PackageParser.java 】
public class PackageParser {
   
   
	...
	/*
		这里可以看到IntentInfo就是对IntentFilter意图过滤器的再次封装,
		它是承载包组件<intent-filter>标签的数据结构
	*/
    public static class IntentInfo extends IntentFilter {
   
   
        public boolean hasDefault;
        public int labelRes;
        public CharSequence nonLocalizedLabel;
        public int icon;
        public int logo;
        public int banner;
        public int preferred;
    }
    ...
}

这里这里可以看到IntentInfo就是对IntentFilter意图过滤器的再次封装,它是用来承载包组件<intent-filter>标签的数据结构。最终我们会得到如下的类图:

在这里插入图片描述
最后我们补充一点,对于IntentFilter我想读者肯定很熟悉了,它就是江湖人称的意图过滤器,通常它的过滤规则过滤规则包含以下三个方面:

  • Action: 每一个IntentFilter可以定义零个或多个标签,如果Intent想要通过这个IntentFilter,则Intent所辖的Action需要匹配其中至少一个。
  • Category: 每一个IntentFilter可以定义零个或多个标签,如果Intent想要通过这个IntentFilter,则Intent所辖的Category必须是IntentFilter所定义的Category的子集,才能通过IntentFilter。譬如Intent设置了两个Category:CATEGORY_LAUNCHER和CATEGORY_MAIN,只有那些至少定义了这两项Category的IntentFilter,才会放行该Intent。

    启动Activity时,会为Intent设置默认的Category,即CATEGORY_DEFAULT。目标Activity需要添加一个category为 CATEGORY_DEFAULT的IntentFilter来匹配这一类隐式的Intent。
  • Data:每一个IntentFilter可以定义零个或多个,数据可以通过类型(MIMEType)和位置(URI)来描述,如果Intent想要通过这个IntentFilter,则Intent所辖的Data需要匹配其中至少一个。

2.2 Component内部类

通过前面的博客总结我么可知,一个包中有很多组件,为此设计了一个高层的基类Component,所有具体的组件都是Component的子类。在具体捯饬相关组件前,我们先来看下高层的基类Component组件它是怎么设计并且用代码实现的。

无需多言,直接开撸源码!

// 【 PackageParser.java 】
public class PackageParser {
   
   
	...
    public static class Component<II extends IntentInfo> {
   
   
        public final Package owner;// 该组件依赖的包
        public final ArrayList<II> intents;// 该组件所包含的IntentFilter
        public final String className;// 组件的类名
        public Bundle metaData;// 组件的元数据

        ComponentName componentName;// 组件信息(组件所在的包名和类)
        String componentShortName;// 组件简称
   }
   ...
}

Component被设计成为一个基类,是Android包组件的众多组件的基类数据结构类,然后各个组件类继承并扩展它。并且Android包中每一个具体的组件所依赖的IntentInfo不同,所以Component和IntentInfo之间的依赖关系采用了桥接(Bridge)这种设计模式,通过泛型的手段实现。最终通过我们如上一番分析,我们会得到如下的类图:

在这里插入图片描述


2.3 XXXIntentInfo内部类

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值