Framework - PMS

二、PMS

  • 手机系统启动,Zygote 启动 SystemServer,SystemServer 启动 AMS、PMS,并注册到 ServiceManager。
  • PMS 扫描 /data/app/ 和 /system/app/ 目录下的所有 apk 文件,获取每个 apk 文件的 AndroidManifest.xml 文件,并进行 dom 解析。
  • 解析 AndroidManifest.xml 将权限、四大组件等数据信息转换为 Java Bean 记录到内存中。
  • 当 AMS 需要获取 apk 数据信息时,通过 ServiceManager 获取到 PMS 的 Binder 代理通过 Binder 通信获取。

2.1 概念

PMS(Package Manager Service)是 Android 提供的包管理系统服务,用来管理所有的包信息(安装、卸载、更新、解析AndroidManefest)。

2.2 作用

AndroidManefest中注册了 APP 所有的四大组件和权限等信息,PMS提前 AMS 要用的信息解析保存在内存中提供快速调用。

2.3 过程 

PMS运行在手机开机时(至少消耗70%的开机时间),会扫描已安装软件目录,解压包名目录下的 apk 文件,对 AndroidManefest.xml 进行 dom 解析,将这些节点信息转化为 JavaBean 保存在内存中提供查询功能。

2.3.1 扫描

scanDirLI() 使用 for 循环遍历已安装软件目录(系统system/app、第三方data/app),如果是 apk 文件就调用 parallelPackageParser.submit() 提交任务给子线程的包解析器处理(Android 10.0开始使用子线程加快开机速度,之前版本是直接解析)。

PackageManagerService.java 

public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
	// 扫描 /system/app 目录下的 apk 文件
    scanDirTracedLI(systemAppDir, mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_AS_SYSTEM, 0);	
	// 扫描用户目录下的apk文件
	scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
}

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
    for (File file : files) {
        // 判断是否是 .apk 后缀的文件
        final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            continue;    // Ignore entries which are not packages
        }
        // 提交给子线程包解析器处理apk文件
        parallelPackageParser.submit(file, parseFlags);
    }
}

2.3.2 解析

根据传过来的 apk 路径判断是分包还是整包,整包走 parseMonolithicPackage() 调用 parseBaseApk() 解析 apk 文件,通过 dom 解析 AndroidManefest 将节点信息存放到 Package 对象的不同字段中,最后放在内存中方便后续 AMS 查询。(Android 9.0开始解析结果会开启缓存,没有缓存就解析每个 app 的 AndroidManefest)。

ParallelPackageParser.java

public void submit(File scanFile, int parseFlags) {
    pr.scanFile = scanFile;    //传入待解析的apk文件
    pr.pkg = parsePackage(pp, scanFile, parseFlags);    //交给packageParser解析
}

 PackageParser.java

PackageParser.java

public Package parsePackage(File packageFile, int flags, boolean useCaches) throws PackageParserException {
     // 如果有缓存,直接返回解析后的信息
     Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
     if (parsed != null) {
         return parsed;
     }        
	 // apk 文件不是目录,所以会走的 parseMonolithicPackage()
     if (packageFile.isDirectory()) {
         parsed = parseClusterPackage(packageFile, flags);
     } else {
         parsed = parseMonolithicPackage(packageFile, flags);
     }
}

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
    // 解析apk文件
    final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
}

private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException {
	//开始 dom 解析 AndroidManifest.xml
    parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
    final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
}

private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException {
     //后续的流程就是将 xml 解析的信息如权限、四大组件等信息存到 Package 对象中
     final Package pkg = new Package(pkgName);
     return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}

public final static class Package implements Parcelable {
	// 包名
	public String packageName;
	// 申请的权限
    public final ArrayList permissions = new ArrayList(0);
    public final ArrayList permissionGroups = new ArrayList(0);
    // 四大组件
    public final ArrayList activities = new ArrayList(0);
    public final ArrayList receivers = new ArrayList(0);
    public final ArrayList providers = new ArrayList(0);
    public final ArrayList services = new ArrayList(0);
}
跳转一个APP或Activity的过程

根据包名遍历 data/app 或 system/app 目录

PMS

手机开机的时候

解压 apk 文件

DOM 解析 AndroidManefest.xml
定位到 MainActivity 节点

AMS

手机运行的时候

你可能感兴趣的:(Framework,android)