一 概述
上一篇 PackageManagerService 源码解析 详细解析了 PackageManagerService 的启动流程。我们也大致知道了 PMS 启动时的工作原理。
但是,里面有一块非常重要的部分我们当时忽略了,那就是 PMS 解析安装目录的过程。
- PMS 是如何解析我们安装到 Android 系统中的应用的?
- 我们写的那些代码文件,PMS 是如何将它变成四大组件启动的?
今天,我们就带着这两个问题,来了解一下 PMS 启动的,解析应用的原理。
二 PMS 的启动
在上一篇启动篇中,我们介绍了 PMS 的初始化分为 5 个流程。其中的流程 2 和流程 3 分别是解析系统文件目录和解析用户安装目录 /data/app。
如下图,就是一个安卓手机的目录情况,今天我们要学习的,就是 PMS 解析 /data/app 目录的原理。这个目录就是我们应用安装的位置。
2.1 构造函数
书接上回,我们介绍了 PMS 构造函数中的五个步骤,说到了 scanDirTracedLI 这个函数,它的作用就是扫描文件目录。
[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
// 如果不是只加载核心apk,一般情况都是false
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
// 扫描 App 安装目录
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
我们继续说说这个函数扫描的流程。
2.2 scanDirTracedLI
注意,这里传入了一个参数 packageParser,类型是 PackageParser2。具体的构造可以看 PackageManagerService 源码解析 。
[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
}
}
2.3 scanDirLI
ParallelPackageParser 的作用其实就是对 PackageParser2 的包装,真正工作的还是 PackageParser2。
class ParallelPackageParser {
private final PackageParser2 mPackageParser;
private final ExecutorService mExecutorService;
ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
mPackageParser = packageParser;
mExecutorService = executorService;
}
}
这种包装的方式主要是用于解耦,后续如果想对 PackageParser2 进行升级,例如改成 PackageParser3 也是非常容易的。
2.4 scanDirLI
[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser2 packageParser, ExecutorService executorService) {
// 要扫描的文件数组
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
return;
}
// 包解析器
// 注意,这里的 packageParser 是 PackageParser2,
// 这是用一个 ParallelPackageParser 包裹 PackageParser2
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(packageParser, executorService);
// 开始扫描
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// 如果不满足 isPackage 的条件就不扫描
// 如果是安装的 apk,那么一定满足条件
continue;
}
// 把apk 文件添加到了 PackageInstallerService 的扫描队列中
// PackageInstallerService 中有一个 mQueue 对象
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// 逐一处理结果
for (; fileCount > 0; fileCount--) {
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;
String errorMsg = null;
if (throwable == null) {
// TODO(toddke): move lower in the scan chain
// Static shared libraries have synthetic package names
if (parseResult.parsedPackage.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.parsedPackage);
}
try {
addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
currentTime, null);
} catch (PackageManagerException e) {
}
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
}
// 删除无效的用户应用程序
if ((scanFlags & SCAN_AS_SYSTEM) == 0
&& errorCode != PackageManager.INSTALL_SUCCEEDED) {
removeCodePathLI(parseResult.scanFile);
}
}
}
调用 ParallelPackageParser 的 submit 提交扫描文件。
三 ParallelPackageParser
3.1 submit
public void submit(File scanFile, int parseFlags) {
mExecutorService.submit(() -> {
ParseResult pr = new ParseResult();
try {
pr.scanFile = scanFile;
// 解析文件
pr.parsedPackage = parsePackage(scanFile, parseFlags);
} ...
try {
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// 将结果传播给take()的调用者。
// 有助于防止主线程在interrupt 时等待
// ParallelPackageParser在中断的情况下完成
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
调用 parsePackage 解析文件,获得一个 ParseResult 结果。
3.2 parsePackage
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
最终结果还是通过传入的 PackageParser2 进行解析文件。
四 PackageParser2
4.1 parsePackage
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
// 先判断是否有缓存
if (useCaches && mCacher != null) {
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
if (parsed != null) {
return parsed;
}
}
ParseInput input = mSharedResult.get().reset();
// 调用 parsingUtils 进行解析 apk 文件
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
// 保存解析结果到缓存
if (mCacher != null) {
mCacher.cacheResult(packageFile, flags, parsed);
}
return parsed;
}
五 ParsingPackageUtils
5.1 parsePackage
[frameworks\base\core\java\android\content\pm\parsing\ParsingPackageUtils.java]
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
int flags)
throws PackageParserException {
// 如果是文件目录就用 parseClusterPackage 解析
// 这里我们是 apk 所以用下面的 parseMonolithicPackage 解析
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
return parseMonolithicPackage(input, packageFile, flags);
}
}
在 parsePackage 中,对目录文件和非目录文件进行了区分,当然最后其实都会调用到同一个函数,所以这里我们只看 parseMonolithicPackage 就足够了。
5.2 parseMonolithicPackage
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
try {
// 解析 apk 文件
final ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
assetLoader, flags);
return input.success(result.getResult().setUse32BitAbi(lite.isUse32bitAbi()));
}
...
}
这里的 parseMonolithicPackage 最后调用了 parseBaseApk 进行解析,当然,如果是解析文件夹的 parseClusterPackage,其实也会调用到 parseBaseApk。
5.3 parseBaseApk
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags)
throws PackageParserException {
// apk 路径
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(MNT_EXPAND)) {
final int end = apkPath.indexOf('/', MNT_EXPAND.length());
volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
}
final AssetManager assets = assetLoader.getBaseAssetManager();
final int cookie = assets.findCookieForPath(apkPath);
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
// 又调用了一个同名的函数 parseBaseApk
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags);
...
}
5.4 parseBaseApk
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
... // 省略代码
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
}
}
调用到了 parseBaseApkTags,看名字也知道是解析 apk 相关属性的。
5.5 parseBaseApkTags
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
...
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;
// 先特殊处理 Application 节点
if (TAG_APPLICATION.equals(tagName)) {
if (foundApp) {
...
} else {
foundApp = true;
// 解析 Application
result = parseBaseApplication(input, pkg, res, parser, flags);
}
} else {
// 解析 apk
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
if (result.isError()) {
return input.error(result);
}
}
...
return input.success(pkg);
}
5.6 parseBaseApplication
parseBaseApplication 就是真正解析应用 apk 文件的地方。
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();
// 获取应用信息,android.content.pm.ApplicationInfo.java
final ApplicationInfo ai = owner.applicationInfo;
// 包名
final String pkgName = owner.applicationInfo.packageName;
// 获取 application 节点
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
// 获取 application 节点下的 icon
ai.iconRes = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
// 获取 application 节点下的 roundIcon
ai.roundIconRes = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, 0);
// 解析 application 节点下的 name,label,icon,roundIcon,logo,banner
// (居然还有一个叫 banner 的属性)
if (!parsePackageItemInfo(owner, ai, outError,
"<application>", sa, false /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestApplication_name,
com.android.internal.R.styleable.AndroidManifestApplication_label,
com.android.internal.R.styleable.AndroidManifestApplication_icon,
com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
com.android.internal.R.styleable.AndroidManifestApplication_logo,
com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
sa.recycle();
// 如果属性错误就会返回false
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
// 是否有 application 的类
if (ai.name != null) {
ai.className = ai.name;
}
... // 省略代码,解析安装包 AndroidManifest 中的各种属性
// 版本,等等……
boolean hasActivityOrder = false;
boolean hasReceiverOrder = false;
boolean hasServiceOrder = 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;
}
final ParseResult result;
String tagName = parser.getName();
boolean isActivity = false;
switch (tagName) {
case "activity":
// 解析 activity,可以发现 activity 和 receiver 的解析方式的一样的。
isActivity = true;
// fall-through
case "receiver":
ParseResult<ParsedActivity> activityResult =
ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
res, parser, flags, sUseRoundIcon, input);
if (activityResult.isSuccess()) {
ParsedActivity activity = activityResult.getResult();
if (isActivity) {
hasActivityOrder |= (activity.getOrder() != 0);
// 添加 Activity
pkg.addActivity(activity);
} else {
hasReceiverOrder |= (activity.getOrder() != 0);
// 添加 Receiver
pkg.addReceiver(activity);
}
}
result = activityResult;
break;
case "service":
ParseResult<ParsedService> serviceResult =
ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
flags, sUseRoundIcon, input);
if (serviceResult.isSuccess()) {
ParsedService service = serviceResult.getResult();
hasServiceOrder |= (service.getOrder() != 0);
// 添加 Service
pkg.addService(service);
}
result = serviceResult;
break;
case "provider":
ParseResult<ParsedProvider> providerResult =
ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
flags, sUseRoundIcon, input);
if (providerResult.isSuccess()) {
// 添加 Provider
pkg.addProvider(providerResult.getResult());
}
result = providerResult;
break;
case "activity-alias":
activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
parser, 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);
}
}
if (TextUtils.isEmpty(pkg.getStaticSharedLibName())) {
// 为普通的应用程序添加一个隐藏的应用程序细节活动,
// 将用户转发到应用程序详情页面。
ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
pkg.addActivity(a.getResult());
}
// 为 Activity 排序
if (hasActivityOrder) {
pkg.sortActivities();
}
// 为 Receiver 排序
if (hasReceiverOrder) {
pkg.sortReceivers();
}
// 为 Service 排序
if (hasServiceOrder) {
pkg.sortServices();
}
// 必须在整个{@link ApplicationInfo}被完全处理之后,并且在
// 每个活动信息有机会从其属性中设置它之后运行。
// 每个活动信息都有机会从其属性中设置它。
setMaxAspectRatio(pkg);
setMinAspectRatio(pkg);
setSupportsSizeChanges(pkg);
pkg.setHasDomainUrls(hasDomainURLs(pkg));
return input.success(pkg);
}
parseBaseApplication 这个函数主要做了三件事
- 解析 application 节点下的属性(我们熟悉的 name,label,icon,roundIcon,logo 都会被解析)
- 解析四大组件节点,并把它们加进 pkg(ParsingPackage)中
- 如果需要排序就进行排序
接下来我们就看看四大组件的节点是如何解析并加到 ParsingPackage 中的,并且加到 ParsingPackage 中之后,是如何被使用的。
5.7 parsePackageItemInfo
private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
String[] outError, String tag, TypedArray sa, boolean nameRequired,
int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
// 这种情况只能发生在单元测试中,在单元测试中,我们有时需要创建假的
// 的各种包解析器数据结构。
if (sa == null) {
outError[0] = tag + " does not contain any attributes";
return false;
}
...
outInfo.packageName = owner.packageName;
return true;
}
parsePackageItemInfo 主要是异常检测,判断安装包里的属性是否正确,如果不正确就会返回 false, 正确就会返回 true。
5.8 parseActivityOrReceiver
parseActivityOrReceiver 是解析 Activity 节点和 Receiver 节点的各种属性。对于 service 和 provider,则是调用 parseService 和 parseProvider 进行解析。
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static ParseResult<ParsedActivity> parseActivityOrReceiver(String[] separateProcesses,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
boolean useRoundIcon, ParseInput input)
throws XmlPullParserException, IOException {
// 包名
final String packageName = pkg.getPackageName();
// 创建一个 ParsedActivity 对象用来保存解析后的数据
final ParsedActivity activity = new ParsedActivity();
boolean receiver = "receiver".equals(parser.getName());
// 获得 Activity 节点的属性
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
try {
// 解析 Activity 节点的属性到 result
ParseResult<ParsedActivity> result =
ParsedMainComponentUtils.parseMainComponent(
activity, tag, separateProcesses,
pkg, sa, flags, useRoundIcon, input,
R.styleable.AndroidManifestActivity_banner,
R.styleable.AndroidManifestActivity_description,
R.styleable.AndroidManifestActivity_directBootAware,
R.styleable.AndroidManifestActivity_enabled,
R.styleable.AndroidManifestActivity_icon,
R.styleable.AndroidManifestActivity_label,
R.styleable.AndroidManifestActivity_logo,
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_process,
R.styleable.AndroidManifestActivity_roundIcon,
R.styleable.AndroidManifestActivity_splitName,
R.styleable.AndroidManifestActivity_attributionTags);
if (result.isError()) {
return result;
}
if (receiver && pkg.isCantSaveState()) {
// A heavy-weight application can not have receivers in its main process
// 一个重量级的应用程序在其主进程中不能有接收者
if (Objects.equals(activity.getProcessName(), packageName)) {
return input.error("Heavy-weight applications can not have receivers "
+ "in main process");
}
}
// 解析 Activity theme
activity.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
activity.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions());
// 解析 Activity 的 flags,Activity 的各种启动相关的属性都会放在 flags 中
activity.flags |= flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
...; // 省略代码 flags 解析
if (!receiver) {
// 解析 Activity 的属性
activity.flags |= flag(ActivityInfo.FLAG_HARDWARE_ACCELERATED, R.styleable.AndroidManifestActivity_hardwareAccelerated, pkg.isBaseHardwareAccelerated(), sa)
... // 省略代码 flags 解析
// 颜色模式
activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT);
// 启动模式
activity.launchMode = sa.getInt(R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
...
// 软键盘
activity.softInputMode = sa.getInt(R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
// 属性改变的通知回调
activity.configChanges = getActivityConfigChanges(
sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
// 屏幕方向
int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED);
int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation);
activity.screenOrientation = screenOrientation;
activity.resizeMode = resizeMode;
// 宽高比
if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
&& sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
== TypedValue.TYPE_FLOAT) {
activity.setMaxAspectRatio(resizeMode,
sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
0 /*default*/));
}
...
}
} else {
// 如果不是 Activity 的解析
activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
activity.configChanges = 0;
activity.flags |= flag(ActivityInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestActivity_singleUser, sa);
}
// @formatter:on
...
return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
false /*isAlias*/, visibleToEphemeral, input,
R.styleable.AndroidManifestActivity_parentActivityName,
R.styleable.AndroidManifestActivity_permission,
R.styleable.AndroidManifestActivity_exported
);
} finally {
sa.recycle();
}
}
parseActivityOrReceiver 看名字也知道是解析 Activity 和 Receiver,这里面的一些属性也是我们非常熟悉的。
5.9 parseActivityOrAlias
@NonNull
private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity,
ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,
TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,
ParseInput input, int parentActivityNameAttr, int permissionAttr,
int exportedAttr) throws IOException, XmlPullParserException {
... // 省略代码
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;
}
final ParseResult result;
if (parser.getName().equals("intent-filter")) {
// 解析 intent-filter
ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,
!isReceiver, visibleToEphemeral, resources, parser, input);
...
result = intentResult;
} else if (parser.getName().equals("meta-data")) {
// 解析 meta-data
result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input);
} else if (parser.getName().equals("property")) {
// 解析 property
result = ParsedComponentUtils.addProperty(activity, pkg, resources, parser, input);
}
... // 解析其他属性
if (result.isError()) {
return input.error(result);
}
}
...
return input.success(activity);
}
在 parseActivityOrAlias 主要用于解析 Activity 属性,当然还有一些其他的属性,不过我们主要关注 Activity 的属性。
- intent-filter
- meta-data
- property
然后再看看 service 和 provider 是如何解析的。
5.10 parseService
[base\core\java\android\content\pm\parsing\component\ParsedServiceUtils.java]
@NonNull
public static ParseResult<ParsedService> parseService(String[] separateProcesses,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
boolean useRoundIcon, ParseInput input)
throws XmlPullParserException, IOException {
boolean visibleToEphemeral;
boolean setExported;
final String packageName = pkg.getPackageName();
final ParsedService service = new ParsedService();
String tag = parser.getName();
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestService);
try {
// 解析 通用的属性
ParseResult<ParsedService> result = ParsedMainComponentUtils.parseMainComponent(
service, tag, separateProcesses, pkg, sa, flags, useRoundIcon, input,
R.styleable.AndroidManifestService_banner,
R.styleable.AndroidManifestService_description,
R.styleable.AndroidManifestService_directBootAware,
R.styleable.AndroidManifestService_enabled,
R.styleable.AndroidManifestService_icon,
R.styleable.AndroidManifestService_label,
R.styleable.AndroidManifestService_logo,
R.styleable.AndroidManifestService_name,
R.styleable.AndroidManifestService_process,
R.styleable.AndroidManifestService_roundIcon,
R.styleable.AndroidManifestService_splitName,
R.styleable.AndroidManifestService_attributionTags
);
// exported 属性,是否可以被隐式调用
setExported = sa.hasValue(R.styleable.AndroidManifestService_exported);
if (setExported) {
service.exported = sa.getBoolean(R.styleable.AndroidManifestService_exported,
false);
}
// service 节点下的权限
String permission = sa.getNonConfigurationString(
R.styleable.AndroidManifestService_permission, 0);
service.setPermission(permission != null ? permission : pkg.getPermission());
// 前台服务类型
service.foregroundServiceType = sa.getInt(
R.styleable.AndroidManifestService_foregroundServiceType,
ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
service.flags |= flag(ServiceInfo.FLAG_STOP_WITH_TASK,
R.styleable.AndroidManifestService_stopWithTask, sa)
| flag(ServiceInfo.FLAG_ISOLATED_PROCESS,
R.styleable.AndroidManifestService_isolatedProcess, sa)
| flag(ServiceInfo.FLAG_EXTERNAL_SERVICE,
R.styleable.AndroidManifestService_externalService, sa)
| flag(ServiceInfo.FLAG_USE_APP_ZYGOTE,
R.styleable.AndroidManifestService_useAppZygote, sa)
| flag(ServiceInfo.FLAG_SINGLE_USER,
R.styleable.AndroidManifestService_singleUser, sa);
visibleToEphemeral = sa.getBoolean(
R.styleable.AndroidManifestService_visibleToInstantApps, false);
if (visibleToEphemeral) {
service.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
pkg.setVisibleToInstantApps(true);
}
} finally {
sa.recycle();
}
// 开始解析 service 节点下的子节点
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;
}
final ParseResult parseResult;
switch (parser.getName()) {
case "intent-filter":
ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils
.parseIntentFilter(service, pkg, res, parser, visibleToEphemeral,
true /*allowGlobs*/, false /*allowAutoVerify*/,
false /*allowImplicitEphemeralVisibility*/,
false /*failOnNoActions*/, input);
parseResult = intentResult;
if (intentResult.isSuccess()) {
ParsedIntentInfo intent = intentResult.getResult();
service.order = Math.max(intent.getOrder(), service.order);
service.addIntent(intent);
}
break;
case "meta-data":
parseResult = ParsedComponentUtils.addMetaData(service, pkg, res, parser, input);
break;
case "property":
parseResult =
ParsedComponentUtils.addProperty(service, pkg, res, parser, input);
break;
default:
parseResult = ParsingUtils.unknownTag(tag, pkg, parser, input);
break;
}
if (parseResult.isError()) {
return input.error(parseResult);
}
}
if (!setExported) {
boolean hasIntentFilters = service.getIntents().size() > 0;
service.exported = hasIntentFilters;
}
return input.success(service);
}
parseService 是解析 service 节点的方法,这里面分别对 service 节点,和 service 节点下的子节点进行了解析。
service 节点主要包含了三种属性
- 通用的属性,例如 icon,logo,name,label 等等。
- exported 属性,表示是否可以被其他进程隐式调用,如果设置为了 false ,其他的进程就无法通过 intent-filter 来找到你这个服务了。
- 然后获取了是否有前台服务类型。相比于后台服务,前台服务更加不容易被系统杀死。例如 location 定位服务,phoneCall 来电提醒服务等,是极难被系统杀死的。
最后就是调用 ParsedMainComponentUtils 解析三种通用的属性。
5.11 parseProvider
[base\core\java\android\content\pm\parsing\component\ParsedProviderUtils.java]
@NonNull
public static ParseResult<ParsedProvider> parseProvider(String[] separateProcesses,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
boolean useRoundIcon, ParseInput input)
throws IOException, XmlPullParserException {
String authority;
boolean visibleToEphemeral;
final int targetSdkVersion = pkg.getTargetSdkVersion();
final String packageName = pkg.getPackageName();
final ParsedProvider provider = new ParsedProvider();
final String tag = parser.getName();
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProvider);
try {
ParseResult<ParsedProvider> result =
ParsedMainComponentUtils.parseMainComponent(provider, tag, separateProcesses,
pkg, sa, flags, useRoundIcon, input,
... ; // 解析通用属性
authority = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_authorities, 0);
provider.exported = sa.getBoolean(R.styleable.AndroidManifestProvider_exported,
targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1);
provider.syncable = sa.getBoolean(R.styleable.AndroidManifestProvider_syncable, false);
String permission = sa.getNonConfigurationString(
R.styleable.AndroidManifestProvider_permission, 0);
String readPermission = sa.getNonConfigurationString(
R.styleable.AndroidManifestProvider_readPermission, 0);
if (readPermission == null) {
readPermission = permission;
}
if (readPermission == null) {
provider.setReadPermission(pkg.getPermission());
} else {
provider.setReadPermission(readPermission);
}
String writePermission = sa.getNonConfigurationString(
R.styleable.AndroidManifestProvider_writePermission, 0);
if (writePermission == null) {
writePermission = permission;
}
if (writePermission == null) {
provider.setWritePermission(pkg.getPermission());
} else {
provider.setWritePermission(writePermission);
}
...
return parseProviderTags(pkg, tag, res, parser, visibleToEphemeral, provider, input);
}
parseProvider 解析内容提供者相比其他的四大组件,里面多了许多权限相关的逻辑。然后调用 parseProviderTags 对我们熟悉的几个子节点的解析。
5.12 parseProviderTags
@NonNull
private static ParseResult<ParsedProvider> parseProviderTags(ParsingPackage pkg, String tag,
Resources res, XmlResourceParser parser, boolean visibleToEphemeral,
ParsedProvider provider, ParseInput input)
throws XmlPullParserException, IOException {
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 name = parser.getName();
final ParseResult result;
switch (name) {
case "intent-filter":
ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils
.parseIntentFilter(provider, pkg, res, parser, visibleToEphemeral,
true /*allowGlobs*/, false /*allowAutoVerify*/,
false /*allowImplicitEphemeralVisibility*/,
false /*failOnNoActions*/, input);
result = intentResult;
if (intentResult.isSuccess()) {
ParsedIntentInfo intent = intentResult.getResult();
provider.order = Math.max(intent.getOrder(), provider.order);
provider.addIntent(intent);
}
break;
case "meta-data":
result = ParsedComponentUtils.addMetaData(provider, pkg, res, parser, input);
break;
case "property":
result = ParsedComponentUtils.addProperty(provider, pkg, res, parser, input);
break;
case "grant-uri-permission": {
result = parseGrantUriPermission(provider, pkg, res, parser, input);
break;
}
case "path-permission": {
result = parsePathPermission(provider, pkg, res, parser, input);
break;
}
default:
result = ParsingUtils.unknownTag(tag, pkg, parser, input);
break;
}
if (result.isError()) {
return input.error(result);
}
}
return input.success(provider);
}
到这里,我们四大节点的解析基本算是理清了。接下来还有几个问题。
- 四大节点的子节点,那些通用属性是怎么解析的(intent-filter,meta-data,property 等)?
- 解析完了之后又做了什么?
六 ParsedMainComponentUtils
首先我们看通用熟悉的 intent-filter 的解析逻辑。
6.1 intent-filter 示例
如下,就是一个简单的 Android 浏览器的 xml 配置。
<activity
android:name="org.chromium.webview_shell.WebViewBrowserActivity"
android:label="@string/title_activity_browser"
android:exported="true"
android:windowSoftInputMode="adjustResize"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Catch intents which do not specify a MIME type -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
</intent-filter>
<!-- Catch intents which do specify a MIME type -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:mimeType="text/html"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="application/xhtml+xml"/>
<data android:mimeType="application/vnd.wap.xhtml+xml"/> <!-- XHTML MP -->
</intent-filter>
</activity>
我们可以对照着这个 xml,看看系统是如何对它进行解析的。
6.2 parseIntentFilter
[base\core\java\android\content\pm\parsing\component\ParsedActivityUtils.java]
static ParseResult<ParsedIntentInfo> parseIntentFilter(
ParsedMainComponent mainComponent,
ParsingPackage pkg, Resources resources, XmlResourceParser parser,
boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify,
boolean allowImplicitEphemeralVisibility, boolean failOnNoActions,
ParseInput input) throws IOException, XmlPullParserException {
// 调用 ParsedIntentInfoUtils 进行解析
ParseResult<ParsedIntentInfo> intentResult = ParsedIntentInfoUtils.parseIntentInfo(
mainComponent.getName(), pkg, resources, parser, allowGlobs,
allowAutoVerify, input);
if (intentResult.isError()) {
return input.error(intentResult);
}
...
return input.success(intentResult.getResult());
}
ParseResult 实际上就是一个泛型,它封装的就是一个 ParsedIntentInfo。用于解析 intent-filter。
七 ParsedIntentInfoUtils
7.1 parseIntentInfo
public static ParseResult<ParsedIntentInfo> parseIntentInfo(String className,
ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs,
boolean allowAutoVerify, ParseInput input)
throws XmlPullParserException, IOException {
// 创建了一个 ParsedIntentInfo,解析的数据都会保存在这里面
ParsedIntentInfo intentInfo = new ParsedIntentInfo();
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestIntentFilter);
try {
intentInfo.setPriority(sa.getInt(R.styleable.AndroidManifestIntentFilter_priority, 0));
intentInfo.setOrder(sa.getInt(R.styleable.AndroidManifestIntentFilter_order, 0));
// label
TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label);
if (v != null) {
intentInfo.labelRes = v.resourceId;
if (v.resourceId == 0) {
intentInfo.nonLocalizedLabel = v.coerceToString();
}
}
// roundIcon
if (ParsingPackageUtils.sUseRoundIcon) {
intentInfo.icon = sa.getResourceId(
R.styleable.AndroidManifestIntentFilter_roundIcon, 0);
}
// icon
if (intentInfo.icon == 0) {
intentInfo.icon = sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0);
}
// autoVerify
if (allowAutoVerify) {
intentInfo.setAutoVerify(sa.getBoolean(
R.styleable.AndroidManifestIntentFilter_autoVerify,
false));
}
} finally {
sa.recycle();
}
// 开始一个循环进行解析
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;
}
final ParseResult result;
String nodeName = parser.getName();
switch (nodeName) {
case "action": {
String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
"name");
intentInfo.addAction(value);
result = input.success(null);
break;
}
case "category": {
String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
"name");
intentInfo.addCategory(value);
result = input.success(null);
break;
}
case "data":
result = parseData(intentInfo, res, parser, allowGlobs, input);
break;
default:
result = ParsingUtils.unknownTag("<intent-filter>", pkg, parser, input);
break;
}
}
// 是否有 CATEGORY_DEFAULT
intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
return input.success(intentInfo);
}
parseIntentInfo 用于解析 IntentInfo,也是一个循环。不过这里我们可以看到最后它会对 intent-filter 做一个判断,就是是否有 Intent.CATEGORY_DEFAULT 标志。
7.2 parseData
然后就是解析 intent-filter 下的 data 节点。我们一般会配置它的 host 或者 scheme。例如前面浏览器配置的 intent-filter。
private static ParseResult<ParsedIntentInfo> parseData(ParsedIntentInfo intentInfo,
Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
TypedArray sa = resources.obtainAttributes(parser, R.styleable.AndroidManifestData);
try {
String str = sa.getNonConfigurationString(
R.styleable.AndroidManifestData_mimeType, 0);
if (str != null) {
try {
intentInfo.addDataType(str);
} catch (IntentFilter.MalformedMimeTypeException e) {
return input.error(e.toString());
}
}
str = sa.getNonConfigurationString(
R.styleable.AndroidManifestData_mimeGroup, 0);
if (str != null) {
intentInfo.addMimeGroup(str);
}
// 解析 scheme 并添加到 intentInfo
str = sa.getNonConfigurationString(
R.styleable.AndroidManifestData_scheme, 0);
if (str != null) {
intentInfo.addDataScheme(str);
}
...
// 解析 host 并添加到 intentInfo
String host = sa.getNonConfigurationString(
R.styleable.AndroidManifestData_host, 0);
String port = sa.getNonConfigurationString(
R.styleable.AndroidManifestData_port, 0);
if (host != null) {
intentInfo.addDataAuthority(host, port);
}
...
return input.success(null);
} finally {
sa.recycle();
}
}
到这里,基本的扫描流程我们已经整理结束了。
八 PMS
接下来我们回到 [2.4] 小节,看看扫描结束之后,是如何处理扫描结果的。
8.1 addForInitLI
addForInitLI 里的逻辑非常长,所以这里我只做一个简单的介绍。
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
final String renamedPkgName;
final PackageSetting disabledPkgSetting;
final boolean isSystemPkgUpdated;
final boolean pkgAlreadyExists;
PackageSetting pkgSetting;
// 首先判断系统应用是否需要更新
synchronized (mLock) {
...
}
// 然后校验安装包
collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
// 如果应用程序的版本发生变化,重置配置文件
maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
/*
* 如果出现了新的系统应用,并且还有一个非系统的同名的应用程序,
*/
boolean shouldHideSystemApp = false;
if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
&& !pkgSetting.isSystem()) {
if (!parsedPackage.getSigningDetails()
.checkCapability(pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
&& !pkgSetting.signatures.mSigningDetails.checkCapability(
parsedPackage.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
parsedPackage.getPackageName(),
"scanPackageInternalLI")) {
deletePackageLIF(parsedPackage.getPackageName(), null, true,
mUserManager.getUserIds(), 0, null, false, null);
}
pkgSetting = null;
} else if (newPkgVersionGreater) {
// 如果/system上的应用比/data上的应用要新。
// 只需删除/data上的应用[保留应用数据]即可。
// 并用/system上的版本替换它
InstallArgs args = createInstallArgsForExisting(
pkgSetting.getPathString(), getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
} else {
// 如果/system上的应用比在/data上的应用旧。则隐藏
// /system上的应用程序,并且再次扫描 /data上的版本
// 并像更新一样重新添加
shouldHideSystemApp = true;
}
}
// 扫描 Package
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user, null);
if (scanResult.success) {
synchronized (mLock) {
boolean appIdCreated = false;
try {
...
// 提交扫描结果
commitReconciledScanResultLocked(
reconcileResult.get(pkgName), mUserManager.getUserIds());
} catch (PackageManagerException e) {
if (appIdCreated) {
cleanUpAppIdCreation(scanResult);
}
throw e;
}
}
}
// 隐藏同名的系统应用
if (shouldHideSystemApp) {
synchronized (mLock) {
mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
}
}
...
return scanResult.pkgSetting.pkg;
}
addForInitLI 这个函数很长,主要处理以下一些事情
- 系统更新后,出现了和应用包名一样的应用怎么办
- 新应用安装包的校验
- 调用 scanPackageNewLI 继续扫描,会传入前面的扫描结果,这个函数在应用安装时也会调用
- 提交扫描结果,用于后续四大组件的启动
8.2 scanPackageNewLI
调用 scanPackageNewLI()继续扫描,主要是更新 packageSetting(PackageSetting 主要包含了一个 APP 的基本信息,如安装位置,lib 位置等信息)。
- 调用 commitReconciledScanResultLocked() 提交包扫描结果、更新系统状态
- 内部又调用了 commitPackageSettings():
private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
...
return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
}
}
8.3 commitReconciledScanResultLocked
private AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
final ScanResult result = reconciledPkg.scanResult;
final ScanRequest request = result.request;
... // 先对扫描的结果进行处理
final int userId = user == null ? 0 : user.getIdentifier();
// 然后进行提交
commitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags,
(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
if (pkgSetting.getInstantApp(userId)) {
mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
}
pkgSetting.setStatesOnCommit();
return pkg;
}
8.4 commitPackageSettings
向系统添加扫描完成的包。
[base\services\core\java\com\android\server\pm\PackageManagerService.java]
private void commitPackageSettings(@NonNull AndroidPackage pkg, @Nullable AndroidPackage oldPkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
final String pkgName = pkg.getPackageName();
... // 省略代码
synchronized (mLock) {
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// 将安装包添加到 mPackages 中
mPackages.put(pkg.getPackageName(), pkg);
// 将软件包的 KeySets 添加到全局 KeySetManagerService 中
KeySetManagerService ksms = mSettings.getKeySetManagerService();
ksms.addScannedPackageLPw(pkg);
// 将 pkg 添加到
mComponentResolver.addAllComponents(pkg, chatty);
...
int i;
for (i = 0; i < collectionSize; i++) {
ParsedInstrumentation a = pkg.getInstrumentations().get(i);
a.setPackageName(pkg.getPackageName());
// 将安装包添加到 mInstrumentation 中
mInstrumentation.put(a.getComponentName(), a);
}
...
// 将安装包添加到权限管理中
mPermissionManager.onPackageAdded(pkg, (scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg);
}
}
到这里,我们终于把安装包的扫描流程理完了。并且,我们也看到了几个熟悉的身影
- 安装包的包名都添加到了 mPackages,这是一个 Map,key 是包名,value 是 AndroidPackage。
- 安装包的 AndroidPackage 添加到了 mComponentResolver,这是一个 ComponentResolver,四大组件启动中经常看到它的身影,我们等下可以看一下。
- 安装包的全类名添加到了 mInstrumentation,这也是一个 map。
- 把扫描安装包的权限结果添加到了 mPermissionManager 中,这是一个 PermissionManagerServiceInternal。
我们接下来看一下 ComponentResolver 是如何添加四大组件的扫描结果的。
九 ComponentResolver
9.1 addAllComponents
void addAllComponents(AndroidPackage pkg, boolean chatty) {
final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>();
synchronized (mLock) {
addActivitiesLocked(pkg, newIntents, chatty);
addReceiversLocked(pkg, chatty);
addProvidersLocked(pkg, chatty);
addServicesLocked(pkg, chatty);
onChanged();
}
...
}
ComponentResolver 的 addAllComponents 添加了四大组件,其实就是调用了四个函数,然后分别把它们添加到了四个集合。
9.2 四大组件的集合
@GuardedBy("mLock")
private final ActivityIntentResolver mActivities;
/** All available providers, for your resolving pleasure. */
@GuardedBy("mLock")
private final ProviderIntentResolver mProviders;
/** All available receivers, for your resolving pleasure. */
@GuardedBy("mLock")
private final ReceiverIntentResolver mReceivers;
/** All available services, for your resolving pleasure. */
@GuardedBy("mLock")
private final ServiceIntentResolver mServices;
9.3 addActivitiesLocked
private void addActivitiesLocked(AndroidPackage pkg,
List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) {
final int activitiesSize = ArrayUtils.size(pkg.getActivities());
StringBuilder r = null;
for (int i = 0; i < activitiesSize; i++) {
// Activity 的信息,添加进 mActivities
ParsedActivity a = pkg.getActivities().get(i);
mActivities.addActivity(a, "activity", newIntents);
}
}
在 addActivitiesLocked 中,
9.4 addReceiversLocked
private void addReceiversLocked(AndroidPackage pkg, boolean chatty) {
final int receiversSize = ArrayUtils.size(pkg.getReceivers());
StringBuilder r = null;
for (int i = 0; i < receiversSize; i++) {
ParsedActivity a = pkg.getReceivers().get(i);
mReceivers.addActivity(a, "receiver", null);
}
}
9.5 addServicesLocked
private void addServicesLocked(AndroidPackage pkg, boolean chatty) {
final int servicesSize = ArrayUtils.size(pkg.getServices());
StringBuilder r = null;
for (int i = 0; i < servicesSize; i++) {
ParsedService s = pkg.getServices().get(i);
mServices.addService(s);
}
}
9.6 addProvidersLocked
private void addProvidersLocked(AndroidPackage pkg, boolean chatty) {
final int providersSize = ArrayUtils.size(pkg.getProviders());
StringBuilder r = null;
for (int i = 0; i < providersSize; i++) {
ParsedProvider p = pkg.getProviders().get(i);
mProviders.addProvider(p);
if (p.getAuthority() != null) {
String[] names = p.getAuthority().split(";");
p.setAuthority(null);
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.isSyncable()) {
// 我们只希望一个提供者的第一个授权可能是
// 可同步的,所以如果我们已经使用不同的授权添加了这个提供者
// 权限,请清除可同步标志。我们在复制提供者之前
// 因为 mProviders 对象包含了一个我们不希望看到的提供者的引用。
// 到一个我们不想改变的提供者的引用。
// 只对第二个授权进行这个操作,因为产生的提供者
// 对象对这个提供者的所有未来授权都是一样的。
p = new ParsedProvider(p);
p.setSyncable(false);
}
if (!mProvidersByAuthority.containsKey(names[j])) {
mProvidersByAuthority.put(names[j], p);
if (p.getAuthority() == null) {
p.setAuthority(names[j]);
} else {
p.setAuthority(p.getAuthority() + ";" + names[j]);
}
} else {
final ParsedProvider other =
mProvidersByAuthority.get(names[j]);
final ComponentName component =
(other != null && other.getComponentName() != null)
? other.getComponentName() : null;
final String packageName =
component != null ? component.getPackageName() : "?";
}
}
}
}
}
好了,现在我们已经看到了四大组件,如何从 AndroidManifast 中的标签,到 PMS 中的四个数组。
接下来,我们就通过 Service,来看看这几个集合,是如何使用的。还是从我们之前的 Service 的流程说起。
十 四大组件的获取
10.1 Service 的启动
在 Service启动源码解析 的 startServiceLocked 中,调用了 retrieveServiceLocked 。
// 没有可以复用的 ServiceRecord,则需要去 Apk 中查找,查找功能 PMS 完成
// 这里是通过 AMS 拿到 PMS
ResolveInfo rInfoForUserId0 = mAm.getPackageManagerInternal().resolveService(service,
resolvedType, flags, userId, callingUid);
10.2 Service 启动中 Service 的获取
mAm 是 ActivityManagerService,这里是获取 AMS 中的 PackageManagerInternal。然后调用 PackageManagerInternal 的 resolveService。
接下来的调用链有些长,这里就不列举代码了。流程如下
- PackageManagerInternal.resolveService
- PackageManagerInternalBase.resolveService
- ResolveIntentHelper.resolveServiceInternal
- ComputerEngine.queryIntentServicesInternal
- ComputerEngine.getServiceInfo
- ComputerEngine.getServiceInfoBody
注意,ComputerEngine 在 Android 12 中是 PackageManagerService 的一个内部类,但是在之后的版本中又移出去了,单独作为一个类。所以路径发生了变化。
最后在 ComputerEngine 的 getServiceInfoBody 中,调用了 mComponentResolver 的 getService。传入的正是全类名。
10.3 getServiceInfoBody
[frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]
protected ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
int callingUid) {
ParsedService s = mComponentResolver.getService(component);
if (s == null) {
return null;
}
AndroidPackage pkg = mPackages.get(s.getPackageName());
if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
return PackageInfoUtils.generateServiceInfo(pkg,
s, flags, ps.readUserState(userId), userId, ps);
}
return null;
}
10.4 getService
在 ComponentResolver 的 getService 中,就是我们熟悉的,从 mServices 的集合中,取出对应的 Service 了。
[base\services\core\java\com\android\server\pm\ComponentResolver.java]
@Nullable
ParsedService getService(@NonNull ComponentName component) {
synchronized (mLock) {
return mServices.mServices.get(component);
}
}
到此 Android 中的 PMS 是如何解析安装的应用,到 四大组件启动时,PMS 是如何查找到对应的组件我们就理清了。
十一 总结
最后我们做一个简单的总结。
- PMS 启动的时候会对系统和安装的应用进行扫描
- 并对扫描的应用进行解析,把他们的四大组件添加到 ComponentResolver 中对应的集合,后续启动的时候,就会从 ComponentResolver 中取
对于具体的流程,我们用一副整体的图做结尾