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.javaframeworks/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;// 该组件所包含的IntentFilterpublic final String className;// 组件的类名public Bundle metaData;// 组件的元数据ComponentName componentName;// 组件信息(组件所在的包名和类)String componentShortName;// 组件简称}...
}

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

2.3 XXXIntentInfo内部类

  在前面的章节2.1 IntentInfo内部类中我们有说到了包管理设计者从架构层次出发设计了一个数据结构基类IntentInfo来表示组件可以过滤接收的Intent信息。而Android包管理中具体到不同的组件,会继承它扩展它,这里共有如下三个扩展类:

  • ActivityIntentInfo
  • ServiceIntentInfo
  • ProviderIntentInfo

细心的读者可以留意了,Android常见的四大组件不是四个吗,上述定义的XXXIntentInfo为啥只有三个啊!好吗,实际原因是receiver广播组件和Activity复用了同一个类ActivityIntentInfo而已。

接下来我们简单来看下上述的几个类的源码实现,如下:

public class PackageParser {...public final static class ActivityIntentInfo extends IntentInfo {/*注意此处的Activity是PackageParse的内部类,而不是我们通常意义上的Activity.java对应的Activity*/public final Activity activity;public ActivityIntentInfo(Activity _activity) {activity = _activity;}...}public final static class ServiceIntentInfo extends IntentInfo {/*注意此处的Service是PackageParse的内部类,而不是我们通常意义上的Service.java对应的Service*/public final Service service;public ServiceIntentInfo(Service _service) {service = _service;}...}public static final class ProviderIntentInfo extends IntentInfo {/*注意此处的Service是PackageParse的内部类,而不是我们通常意义上的Service.java对应的Service*/    public final Provider provider;public ProviderIntentInfo(Provider provider) {this.provider = provider;}...}}

上述的源码比较简单,就是Android包的组件根据实际意图情况继承扩展了IntentInfo 最终通过我们如上一番分析,我们会得到如下的类图:

2.4 Component子类组件实现

  通过前面的博客总结我么可知,一个包中有很多组件,为此设计了一个高层的基类Component,所有具体的组件都是Component的子类。什么是组件呢?AndroidManifest.xml文件中所定义的的一些标签,就是组件,譬如<activity>,<service>,<provider>,<permission>等,这些标签分别对应到包解析器中的一个数据结构,它们各自有自身的属性。并且这些组件我们可以将其归纳为如下两大类:

  • Android四大组件为代表的Component子类组件:

    • Activity:注意此Activity是表示包组件的<activity>和<receiver>而不是Activity.java类中的Activity
    • Service:注意此Service是表示包组件的<service>而不是Service.java类中的Service
    • Provider:注意此Porvider是表示包组件的<service>而不是Service.java类中的Service
  • 其它组件类型的的Component子类组件:

    • Instrumentation: 对应包组件<instrumentation>,这个组件通常用于自动化测试的时候使用
    • Permission:对应包组件<permission>,这个组件没有好说的了,比较常见
    • PermissionGroup:对应包组件<permission-group>,存储权限组的相关信息

接下来我们简单来看下上述的几个类的源码实现,如下:

// 【 PackageParser.java 】
public class PackageParser {...public final static class Activity extends Component<ActivityIntentInfo> {public final ActivityInfo info;//此处的info指向的前面博客我们介绍的包信息体类ActivityInfo /*这里的参数args表示的是解析包中单个组件的参数类,后续会简单介绍下*/public Activity(final ParseComponentArgs args, final ActivityInfo _info) {...}        }public final static class Service extends Component<ServiceIntentInfo> {public final ServiceInfo info;//此处的info指向的前面博客我们介绍的包信息体类ServiceInfopublic Service(final ParseComponentArgs args, final ServiceInfo _info) {...}}public final static class Provider extends Component<ProviderIntentInfo> {public final ProviderInfo info;//此处的info指向的前面博客我们介绍的包信息体类ProviderInfo public boolean syncable;public Provider(final ParseComponentArgs args, final ProviderInfo _info) {...}}public final static class Instrumentation extends Component<IntentInfo> {public final InstrumentationInfo info;//此处的info指向的前面博客我们介绍的包信息体类InstrumentationInfo/*这里的参数args表示的是解析包中包单个item的参数基类,后续会简单介绍下*/public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {...}   }public final static class Permission extends Component<IntentInfo> {public final PermissionInfo info;//此处的info指向的前面博客我们介绍的包信息体类PermissionInfo public boolean tree;public PermissionGroup group;public Permission(Package _owner) {...}public Permission(Package _owner, PermissionInfo _info) {...}}public final static class PermissionGroup extends Component<IntentInfo> {public final PermissionGroupInfo info;//此处的info指向的前面博客我们介绍的包信息体类PermissionGroupInfopublic PermissionGroup(Package _owner) {...}public PermissionGroup(Package _owner, PermissionGroupInfo _info) {            ...}}
}

上述的源码比较简单,就是Android包的组件根据实际组件情况继承扩展了Component基类,最终通过我们如上一番分析,我们会得到如下的类图:

2.5 内部类ParsePackageItemArgs和ParseComponentArgs

分析源码就是这么枯燥且乏味的一件事件,蜻蜓点水吗不能深入!太深入了,又限于细节不能自拔了。所以对于一些细节型的类,我们就简单过下!

ParsePackageItemArgs和ParseComponentArgs是一对父子关系类,其设计的用途主要是用来存储Android包组件中额外的一些参数。这个没有啥好说的,简单看下源码:

// 【 PackageParser.java 】
public class PackageParser {.../*解析包单个item的参数*/static class ParsePackageItemArgs {final Package owner; //表示安装包的包对象Packagefinal String[] outError;//表示错误信息final int nameRes;//表示安装包中组件名字对应的资源idfinal int labelRes;//表示安装包中组件label对应的资源idfinal int iconRes;//表示安装包中组件icon对应的资源idfinal int roundIconRes;//以下类推,不说了final int logoRes;//final int bannerRes;String tag;TypedArray sa;ParsePackageItemArgs(Package _owner, String[] _outError,int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,int _bannerRes) {...}}/*主要为解析包中单个组件的参数,它是ParsePackageItemArgs的子类*/static class ParseComponentArgs extends ParsePackageItemArgs {final String[] sepProcesses;//表示该组件对应的进程,如果设置独立进程则为独立进程的名字final int processRes;//表示该组件对应的进程的资源idfinal int descriptionRes;//表示该组件对应的描述idfinal int enabledRes;//表示该组件是否可用int flags;//该组件标志位信息ParseComponentArgs(Package _owner, String[] _outError,int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,int _bannerRes,String[] _sepProcesses, int _processRes,int _descriptionRes, int _enabledRes) {...}}...
}

关于二者的介绍,就先这样吗,类图也省了,小芝麻的就不捡起来了!

2.6 内部类NewPermissionInfo和SplitPermissionInfo

Android包解析器中的组件的基类以及子类基本介绍完毕,剩下来的就是一些零碎的一些成员类信息,譬如这个章节要说的NewPermissionInfo和SplitPermissionInfo。

NewPermissionInfo和SplitPermissionInfo见名思意,是和Android组件权限有关的,我们还是简单来看下!

// 【 PackageParser.java 】
public class PackageParser {/** @hide *//*主要用于记录组件新权限信息*/    public static class NewPermissionInfo {public final String name;//权限的名称public final int sdkVersion;//表示新权限开始的版本public final int fileVersion;//表示文件的版本号,一般为0public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {...}}/** @hide *//*主要是记录一个权限拆分为颗粒度更小的权限*/public static class SplitPermissionInfo {public final String rootPerm;//表示旧的权限public final String[] newPerms;//表示旧的权限拆分为颗粒度更小的权限public final int targetSdk;//表示在那个版本上拆分的public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {...}}
}

关于二者的介绍,就先这样吗,类图也省了,小芝麻的就不捡起来了!

2.7 内部类ApkLite

前面的几个章节中我们分析了Android包组件相关的一些基类和其它的一些零碎类,从这个章节开始我们将要分析的是组织结构更高一个级别关于Android包的一些类的信息。

ApkLite抛开源码字面意思是精简的APK,通过注释看它表示的是轻量级的存储解析独立APK信息的一个数据结构类,我们从源码入手来看下!

// 【 PackageParser.java 】
public class PackageParser {.../*轻量级的存储解析APK信息的一个数据结构类*/public static class ApkLite {public final String codePath;// 表示APK的路径,譬如/system/app/xxx/xxx.apkpublic final String packageName;// 表示应用程序包名public final String splitName; // 表示“拆包”的包名public final int versionCode;// 表示版本号public final int revisionCode; // 表示调试的版本号public final int installLocation;// 应用安装位置,内置SD卡,外置SD卡等/*包含包验证过程中PackageManagerService}使用的包验证器的信息*/public final VerifierInfo[] verifiers;// 校验信息public final Signature[] signatures;// 表示签名信息public final Certificate[][] certificates;// 证书信息public final boolean coreApp;// 是否是核心应用public final boolean multiArch;// 是否支持多软件架构,这里主要指的是CPU平台public final boolean use32bitAbi;// 是否使用32位系统指令public final boolean extractNativeLibs;// 是否依赖额外的本地库public ApkLite(String codePath, String packageName, String splitName, int versionCode,int revisionCode, int installLocation, List<VerifierInfo> verifiers,Signature[] signatures, Certificate[][] certificates, boolean coreApp,boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs) {...}}...
}

最终经过我们的一顿倒腾,可以得到如下的一个类图:

2.8 内部类PackageLite

如果说前面的ApkLite是用来封装APK文件的一个数据结构类,那么这里的PackageLite则是用来封装一个“独立的”应用程序包信息轻量级数据结构类!

这里特别注意二者的维度是不同的,一个安装包下可能存在几个APK文件!

PackageLite抛开源码字面意思是精简的安装包信息,通过注释看它表示的是轻量级的存储解析独立安装包信息的一个数据结构类,我们从源码入手来看下!

// 【 PackageParser.java 】
public class PackageParser {.../*** Lightweight parsed details about a single package.*//*轻量级的存储应用安装包的一个数据结构类**/public static class PackageLite {public final String packageName;// 表示安装包中base apk应用程序的包名public final int versionCode;//表示安装包中base apk应用程序版本号/*表示应用安装的位置,Android预置了几个常量来选择比如PackageInfo.INSTALL_LOCATION_AUTO的值等*/public final int installLocation;/*包含包验证过程中PackageManagerService}使用的包验证器的信息*/public final VerifierInfo[] verifiers;        public final String[] splitNames;// 表示安装包有拆包的apk名称/*表示"代码"的路径,对于"单一APK",则对应的是"base APK"的路径如果是"集群APK",则对应的是"集群APK"目录的路径,譬如/system/app/xxx*/public final String codePath;public final String baseCodePath;//表示 base APK的路径,譬如/system/app/xxx/xxx.apkpublic final String[] splitCodePaths;   // 表示"拆分"APK的路径public final int baseRevisionCode;// base apk的修订版版本号public final int[] splitRevisionCodes;// 拆分a apk的修订版本号信息public final boolean coreApp;//是不是核心apppublic final boolean multiArch;// 表示是不是支持多平台,这里主要是指CPU平台public final boolean use32bitAbi;// 是否是使用32位abipublic final boolean extractNativeLibs;// 表示是否依赖额外的本地库public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,String[] splitCodePaths, int[] splitRevisionCodes) {...}...}
}

过于其中的每个变量信息,建议读者最好是带入实际情况进行分析,并且最好不要开始就分析有拆包的情况,先得到主干,拆分的情况可以对整体调理清楚之后再行深入!

总之,最终经过我们的一顿倒腾,可以得到如下的一个类图:

2.8 内部类Package

分析至此,读者有没有一个感觉就是PackageParser包解析器为我们捣鼓了一大堆关于Android包的零部件,都是算乱的遗落在角落各处!有一种十分凌乱拉跨的感觉,难道Android包管理的设计者没有考虑拿一个大一点的容器或者收纳箱将那么一大堆零件归纳起来吗?肯定有了,它就是我们将要介绍的Package类,它才是Android包对应的集大成者的一个数据结构类,几乎囊括了Android包的方方面面。我们来看下,Android包管理者是怎么对它进行设计的!

// 【 PackageParser.java 】
public class PackageParser {.../*** Representation of a full package parsed from APK files on disk. A package* consists of a single base APK, and zero or more split APKs.*//*这个类其实就是通过解析APK而对应的一个"包"的类,这个包代表一个完整的安装包的信息这个包可以是一个包由一个"基础"APK和多个"拆分"APK构成*/public final static class Package {       public String packageName;//表示包名public String[] splitNames;//表示"拆包"的包名,是个数组,每个元素代表一个"拆分"包名public String volumeUuid;// 表示代码的路径,如果是单个包,则表示"base"的APK的路径,如果是"集群"包,则表示的"集群"包的目录public String codePath;public String baseCodePath;// base APK的路径public String[] splitCodePaths;// 拆分 APK的路径public int baseRevisionCode;// base APK的调整版本号public int[] splitRevisionCodes;// 拆分APK的调整版本号public int[] splitFlags; // "拆分APK"的标志数组public int[] splitPrivateFlags; // "拆分APK"的标志数组public boolean baseHardwareAccelerated;// 是否支持硬件加速// 对应ApplicationInfo对象 对应AndroidManifest里面的Applicationpublic final ApplicationInfo applicationInfo = new ApplicationInfo();// 安装包中AndroidManifest里面的<Permission>public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);// 安装包中AndroidManifest里面的<PermissionGroup>对应的数据存储结构public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);// 存储Android包组件相关信息public final ArrayList<Activity> activities = new ArrayList<Activity>(0);public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);public final ArrayList<Provider> providers = new ArrayList<Provider>(0);/*存放APK安装包中配置文件AndroidManifest.xml里面的<service>标签信息对应的数据结构类Service的列表,关于Service在掐面博客中国已经有介绍了*/public final ArrayList<Service> services = new ArrayList<Service>(0);/*存放APK安装包中配置文件AndroidManifest.xml里面的<instrumentation>标签信息对应的数据结构类Instrumentation的列表,关于Instrumentation在掐面博客中国已经有介绍了*/public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);public final ArrayList<String> requestedPermissions = new ArrayList<String>();    // 安装包中请求的权限        public ArrayList<String> protectedBroadcasts;// 安装包中广播受保护的的Actionpublic Package parentPackage;//父包信息public ArrayList<Package> childPackages;//子包信息public ArrayList<String> libraryNames = null;// 安装包需要依赖的库  public ArrayList<String> usesLibraries = null;// 安装包中使用的库public ArrayList<String> usesOptionalLibraries = null;   // APK安装包中使用选项库的名字  public String[] usesLibraryFiles = null;// 安装包中使用库的路径// 在AndroidManifest里面的<preferred>标签意图信息集合public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;       public ArrayList<String> mOriginalPackages = null;// APK安装包中AndroidManifest中对应"original-package"的集合    public String mRealPackage = null;//真实包名,通常和mOriginalPackages一起使用   public ArrayList<String> mAdoptPermissions = null;   // APK安装包中AndroidManifest中对应"adopt-permissions"集合 public Bundle mAppMetaData = null;// 我们独立存储应用程序的元数据,以避免多个不需要的引用public int mVersionCode;  // 版本号     public String mVersionName;     // 版本名  public String mSharedUserId;// 共享idpublic int mSharedUserLabel;//共享用户标签public Signature[] mSignatures;// 签名信息public Certificate[][] mCertificates;// 证书信息public int mPreferredOrder = 0;public long[] mLastPackageUsageTimeInMills =new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];//最后package被使用时间//附件数据public Object mExtras;// 硬件配置信息,对应AndroidManifest里面的<uses-configuration>标签信息public ArrayList<ConfigurationInfo> configPreferences = null;//特性信息,对应AndroidManifest里面的<uses-feature>标签信息public ArrayList<FeatureInfo> reqFeatures = null;//特性组信息,对应AndroidManifest里面的<feature-group>标签 信息public ArrayList<FeatureGroupInfo> featureGroups = null;public int installLocation;// 安装的位置    public boolean coreApp;     //是否是核心应用public boolean mRequiredForAllUsers; // 是否是全局必要,所有用户都需要的应用程序,无法为用户卸载public String mRestrictedAccountType;// 受限账户的 验证类型public String mRequiredAccountType;//  是否是受信任的Overlaypublic String mOverlayTarget;public int mOverlayPriority;public boolean mTrustedOverlay;// 下面是用来给KeySetManagerService的数据public ArraySet<PublicKey> mSigningKeys;// 签名public ArraySet<String> mUpgradeKeySets;public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; // 公钥信息public String cpuAbiOverride;//如果有abi,则abi覆盖public boolean use32bitAbi;//是否是使用32位abipublic byte[] restrictUpdateHash;...}...
}

上面的有些注释是我直接翻译过来的,所以有些指代不是很明确,这个各位见谅!因为Pakcage的成员变量太多了,关于各个成员的具体指代只能强烈建议读者在学习的时候最好是自己代入实际情况,然后自行进行相关的验证是再好不过的了。

并且还是我开头说的,在这分析的过程中不要代入拆包的这种情况进来,否则分析起来就会很麻烦造成主干,细节纠缠不清!

通过注释和源码我们可以知道Package是对Android包的集大成者的一个数据结构类,它是通过解析APK而对应的一个"包"的大类,这个包代表的就是一个磁盘上的APK安装包所有的信息。总之经过我们一顿猛虎一半的操作,我们最终会得到如下的一个Android包机制的大类图,如下:


三.PackageParser重要方法

  如果说前面我们分析的PackageParser成员变量等相关的信息,是包管理器为了烹饪Android包准备的各种顶级食材的话,那么PackageParser中定义的各种方法就是为了烹饪Android包准备的各种烹饪技术了。是不是很好奇,Android包管理器是怎么将前面的各种食材进行烹饪得到各种美味呢?这也是本章节和后续博客重点要分析的内容!

这里我回过头来一看,好家伙关于PackageParser中的成员相关的介绍就捣鼓了蛮多了,如果再将其中的方法也放在一起来分析,估计读者和我自己都要奔溃了!所以这里我先简单介绍下PackageParser中重要的方法(方法详细的实现在后续博客介绍),如下:

  • parsePackage()
  • parseClusterPackage()
  • parseMonolithicPackage()
  • parsePackageLite()
  • parseClusterPackageLite()
  • parseMonolithicPackageLite()
  • parseApkLite()

好了,这里只简单的将PackageParser核心方法摆了出来,由于篇幅和排版限制就不在这篇博客中放出来了,在接下来中会专门来一篇博客来分析上述几个核心的方法看看包管理器是怎么烹饪各种Android包组件,得到美味可口的Android包的。


总结

  好了,到这里PackageManagerService启动详解(四)之Android包信息体和解析器(上)分析就告一段落了,在本篇博客中我们重点阐述了如下知识点:

  • Android包管理机制中的Android包解析器设计思想,以及它的重要成员等相关信息

但是由于篇幅,这里就将Android包解析器怎么通过各种方法烹饪它定义的各种成员,得到美味可口的Android包信息放在后续的博客中来进行分析和讲解了!

好了,各位青山不改绿水长流,各位江湖见!当然各位读者的点赞和关注是我写作路上前进的最大动力了,如果有啥不对或者不爽的也可以踩一踩也无妨!未完待续,欢迎读者继续关注。“关不掉的收音机”下一篇PKMS启动详解(六)之Android包信息体和包解析器(下)。

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

  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启动详解(二)之怎么通过packages.xml对已安装应用信息进行持久化管理?

    PKMS启动详解(二)之怎么通过packages.xml对已安装应用信息进行持久化管理? Android PackageManagerService系列博客目录: PKMS启动详解系列博客概要 PKM ...

  4. 详解Spring MVC 4之ViewResolver视图解析器

    所有的We MVC框架都有一套它自己的解析视图的机制,Spring MVC也不例外,它使用ViewResolver进行视图解析,让用户在浏览器中渲染模型.ViewResolver是一种开箱即用的技术, ...

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

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

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

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

  7. 【正点原子MP157连载】 第五章 STM32MP1启动详解-摘自【正点原子】【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  8. Launch 桌面启动详解

    Launch 桌面启动详解 不管是开机还是重启手机,相信我们大家都不陌生吧.大部分的 90 后都经历了从 Android 2.* 的统一开机动画,到现在 Android 10 的各种定制开机动画. 为 ...

  9. java工程在windows环境用bat启动详解

    原 java工程在windows环境用bat启动详解 2016年08月24日 13:19:52 qq_31197461 阅读数:3038 <span class="tags-box a ...

最新文章

  1. mysql字符串外键约束_MySQL中的约束函数主外键
  2. AI量身定制:如何打造符合“中国特色教育”的内容推荐体系?
  3. 深度学习中的图像分割:方法和应用
  4. 数据降维工具箱drtoolbox
  5. [转]内存泄漏简单检测
  6. Nginx基本数据结构之ngx_hash_keys_arrays_t
  7. Linux里怎么进行路由跟踪,[Linux] traceroute 路由跟踪指令用例
  8. NGINX进程的基本操作和基础知识
  9. Memcache 客户端
  10. java方法_Java方法
  11. 计算机图形学实验报告百度云盘,计算机图形学实验报告(一).doc
  12. opencv 梯度幅值_20、 OpenCV导数和梯度
  13. GridView 栏位宽度自由拖动
  14. SpringBoot面试题一网打尽
  15. Leetcode PHP题解--D38 463. Island Perimeter
  16. 计算机无法识别u盘,usb不能识别u盘怎么办_电脑usb突然无法识别u盘修复方法-win7之家...
  17. 弗洛伊德(Floyd)算法之两点之间的最短距离问题
  18. 聚合微信聊天crm调用代码
  19. React Firebase 计账软件 Serverless 项目实战视频教程
  20. 循序渐进学 LoadingDrawable

热门文章

  1. 门禁管理系统设计c语言,基于RFID的门禁系统设计
  2. get几个小技能:轮播图插件、进度条插件、筛选过滤插件
  3. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送
  4. 短视频搬运要如何做,需要哪些软件,可以去重上热门?
  5. 《网上赚钱葵花宝典1.0完整版》
  6. 毕业论文降重方法总结
  7. OCP NIC 3.0设计指南(版本0.85b)
  8. 阅文,不止于网文 | 一点财经
  9. 七彩智能组卷软件系统 V4.9.0.0官方版
  10. 用GPU跑python代码