现在,假设我们现在有这样一个场景,一个App调用另一个App的Activity,该如何调用?
首先,我们要知道,所有的app都是在/data/app文件夹中的,也就是我们需要遍历/data/app文件夹拿到我们对应的apk。
大概的流程如下:
其中,1,2,3步由PMS来处理,4,5,6由AMS处理。
接下来,一起看看PMS如何处理前面三步的。
首先,来到PackageManagerService.java文件(源码:Android10)
会看到一个路径就是/data/app的文件夹

调用scanDirTracedLI方法扫描/data/app的文件夹,(scanDirTracedLI方法调用会从PackageManagerService main方法一层层执行调用,可以自己跟踪下)

最终会来到scanDirLI方法,如下面所示,
第一个红色框:创建一个线程池
第二个红色框:遍历/data/app的文件夹,把每一个文件交给线程池去解析。(注意:如果是Android7.0代码,并不会开启多线程,直接在主线程)

来到submit方法,其中PackageParser就是用来解析文件的,可以理解成Json解析。

跳到parsePackage方法

会来到PackageParser的parsePackage方法。
注意下面两个红色框,
第一个红色框:从这我们可以看出解析后肯定是会有缓存的
第二个红色框:可以解析单个文件或者文件夹,这里我们传入的肯定是文件夹。

来到parseClusterPackage方法,执行 parseClusterPackageLite 方法,但是这个方法只是解析apk的一些包名称、拆分名称和安装位置等。并不是我们要关心的,继续往下看

核心逻辑在parseBaseApk里

来到parseBaseApk方法,开始解析 ANDROID_MANIFEST_FILENAME ,而这个其实就是AndroidManifest.xml,并把结果又传递给了parseBaseApk方法

最终走到,parseBaseApkCommon方法。
第一个红框:不断的拿AndroidManifest的每一个标签
第二个红框:判断标签是不是 TAG_APPLICATION,而这个其实就是 application ,这个标签就是我们平时注册四大组件的地方。
第三个红框:这个方法其实就是解析四大组件的地方,并把解析的内容存储起来

来到parseBaseApplication方法,可以看到,四大组件解析结果


到此,我们知道AndroidManifest里的四大组件信息都会被解析出来,并且最后会把Package返回回去,再回到submit方法,保存所有扫描的每个apk信息。

再回到调用submit方法前,也就是scanDirLI方法。这里take出来的值就是上面mQueue存储的值, 然后通过scanPackageChildLI,最终把结果交给mPackages进行缓存。

缓存
总结一下:
当安卓手机开机时,会去扫描/data/app所有文件,并把每个Apk文件里的信息(例如四大组件信息),并把他缓存下来。
最后提几个问题供大家思考:
1.缓存下来的每个Apk信息有什么用?什么时候会用到?
2.解析AndroidManifest时生成的Activity、Provider等,与我们开发时的Activity、Provider一样嘛?
3.为什么下面图片中data/app不是apk?

死亡小技巧: 如果你有留意这个时间的变化的话,会发现他每次都是开机时间
到这里,PMS的流程就结束了,下一节将会介绍AMS的流程,并且介绍他是如何拿到PMS的四大组件信息。