PMS(Package Manager Service)是 Android 提供的包管理系统服务,用来管理所有的包信息(安装、卸载、更新、解析AndroidManefest)。
AndroidManefest中注册了 APP 所有的四大组件和权限等信息,PMS提前 AMS 要用的信息解析保存在内存中提供快速调用。
PMS运行在手机开机时(至少消耗70%的开机时间),会扫描已安装软件目录,解压包名目录下的 apk 文件,对 AndroidManefest.xml 进行 dom 解析,将这些节点信息转化为 JavaBean 保存在内存中提供查询功能。
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);
}
}
根据传过来的 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 手机运行的时候 |
||