前言
前面我们了解了Zygote的启动流程,知道AMS
、PMS
都是由SystemServer
进程启动的,我们都知道PMS
主要负责App管理工作,这里我们简单从源码角度分析下PMS是如何解析APP解析的;
源码分析(API 30为例)
我们还是从PackageManagerService.main
方法出发;
...
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);//这里会构建一个PackageManagerService对象
...
我们看下PackageManagerService
的构造方法
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
这里会调用scanDirTracedLI
扫描/data/app
目录下的文件;
scanDirTracedLI
又会调用scanDirLI
方法;
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) { //1.首先会判断文件夹下是否有文件;
Log.d(TAG, "No files in app dir " + scanDir);
return;
}
//2.构造一个ParallelPackageParser对象;
ParallelPackageParser parallelPackageParser =
new ParallelPackageParser(packageParser, executorService);
int fileCount = 0;
for (File file : files) {
//3.判断文件是否是apk文件 && 不是临时文件
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
continue;
}
//4.内部实际上是通过线程池提交任务的方式解析file
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
for (; fileCount > 0; fileCount--) {
//5.获取结果
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
...
}
}
}
可以看到scanDirLI
方法主要做了以下几件事:
- 过滤出apk文件;
- 构建parallelPackageParser对象,并向其提交file文件;
- 获取结果做一些其他工作;
那我们接下来就重点关注ParallelPackageParser.submit
方法;
public void submit(File scanFile, int parseFlags) {
mExecutorService.submit(() -> {
ParseResult pr = new ParseResult();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
try {
pr.scanFile = scanFile;
pr.parsedPackage = parsePackage(scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
可以看到只是往线程池中丢入之前扫描到的apk文件,具体解析工作由parsePackage(scanFile, parseFlags);
执行;
我们继续跟进
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
又交给了mPackageParser.parsePackage
方法,这里mPackageParser
在API30上是PackageParser2
类;
我们在跟踪PackageParser2.parsePackage
方法
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
...
ParseInput input = mSharedResult.get().reset();
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
...
return parsed;
}
可以看到最终解析任务又交给了ParsingPackageUtils
这个类;
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
return parseMonolithicPackage(input, packageFile, flags);
}
}
任务进一步交由parseClusterPackage
方法完成;
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.codePath, assets, flags);
}
任务进一步交给parseBaseApk
方法执行;
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, AssetManager assets, int flags) {
final String apkPath = apkFile.getAbsolutePath();
...
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
PackageParser.ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,parser, flags);
final ParsingPackage pkg = result.getResult();
....
return input.success(pkg);
} catch (Exception e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
}
}
可以看到parseBaseApk
五个参数的方法,会去解析AndroidManifest.xml文件得到XmlResourceParser对象,传给六参方法
;
parseBaseApk(ParseInput input, String apkPath, String codePath, Resources res, XmlResourceParser parser, int flags)方法
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException, PackageParserException {
...
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
if (result.isError()) {
return result;
}
return input.success(pkg);
} finally {
manifestArray.recycle();
}
}
我们重点分析下parseBaseApkTags
方法;
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
//解析得到SharedUserId和SharedUserLabel
ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
...
boolean foundApp = false;
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
String tagName = parser.getName();
final ParseResult result;
if (PackageParser.TAG_APPLICATION.equals(tagName)) {
if (foundApp) {
if (PackageParser.RIGID_PARSER) {
result = input.error("<manifest> has more than one <application>");
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
result = input.success(null);
}
} else {
foundApp = true;
//解析Application标签
result = parseBaseApplication(input, pkg, res, parser, flags);
}
} else {
//解析uses-permission、queries等,即非application标签
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
if (result.isError()) {
return input.error(result);
}
}
...
return input.success(pkg);
}
这里,我们可以看到parseBaseApkTags方法
,便是做AndroidManifest.xml
具体解析的方法;
- 解析得到SharedUserId和SharedUserLabel;
- 解析Application标签内容;不用想肯定包含四大组件解析;
- 解析uses-permission、queries等,即非application标签;
那我们就重点看parseBaseApplication
方法是怎么解析四大组件信息的;
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
final String pkgName = pkg.getPackageName();
int targetSdk = pkg.getTargetSdkVersion();
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
try {
...
//解析application标签内的一些配置属性,如allowBackup、LargeHeap等
parseBaseAppBasicFlags(pkg, sa);
...
//解析Android任务栈信息
ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
pkgName, pkgName, taskAffinity, input);
if (taskAffinityResult.isError()) {
return input.error(taskAffinityResult);
}
...
//看着像是处理开进程的情况
ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
pkgName, null, pname, flags, mSeparateProcesses, input);
if (processNameResult.isError()) {
return input.error(processNameResult);
}
String processName = processNameResult.getResult();
pkg.setProcessName(processName);
...
//下面表示解析四大组件
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final ParseResult result;
String tagName = parser.getName();
boolean isActivity = false;
switch (tagName) {
case "activity":
isActivity = true;
// fall-through
case "receiver":
ParseResult<ParsedActivity> activityResult =
ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
res, parser, flags, PackageParser.sUseRoundIcon, input);
if (activityResult.isSuccess()) {
ParsedActivity activity = activityResult.getResult();
if (isActivity) {
hasActivityOrder |= (activity.getOrder() != 0);
pkg.addActivity(activity);
} else {
hasReceiverOrder |= (activity.getOrder() != 0);
pkg.addReceiver(activity);
}
}
result = activityResult;
break;
case "service":
ParseResult<ParsedService> serviceResult =
ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
flags, PackageParser.sUseRoundIcon, input);
if (serviceResult.isSuccess()) {
ParsedService service = serviceResult.getResult();
hasServiceOrder |= (service.getOrder() != 0);
pkg.addService(service);
}
result = serviceResult;
break;
case "provider":
ParseResult<ParsedProvider> providerResult =
ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
flags, PackageParser.sUseRoundIcon, input);
if (providerResult.isSuccess()) {
pkg.addProvider(providerResult.getResult());
}
result = providerResult;
break;
case "activity-alias":
activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
parser, PackageParser.sUseRoundIcon, input);
if (activityResult.isSuccess()) {
ParsedActivity activity = activityResult.getResult();
hasActivityOrder |= (activity.getOrder() != 0);
pkg.addActivity(activity);
}
result = activityResult;
break;
default:
result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
break;
}
if (result.isError()) {
return input.error(result);
}
}
...
return input.success(pkg);
}
至此,完成apk的解析,同时将解析到的信息缓存到ParsingPackage
中,其对应实现类为ParsingPackageImpl
,我们简单看下定义的一些关键属性;
public class ParsingPackageImpl implements ParsingPackage, Parcelable {
//缓存解析到的activity数据
@NonNull
protected List<ParsedActivity> activities = emptyList();
//缓存解析到的receivers数据
@NonNull
protected List<ParsedActivity> receivers = emptyList();
//缓存解析到的services数据
@NonNull
protected List<ParsedService> services = emptyList();
//缓存解析到的providers数据
@NonNull
protected List<ParsedProvider> providers = emptyList();
//缓存解析到的permissions数据
@NonNull
protected List<ParsedPermission> permissions = emptyList();
}
整体流程图
结语
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )