Android S静态广播注册流程
1. 静态广播注册的流程
上一篇文章讲了动态广播的注册(系统存储在mReceiverResolver中),
这篇文章主要讲解静态广播的注册流程
=> 解析包中的receiver
=> 将receiver相关信息添加到mComponentResolver中
2. 在AndroidManifest静态注册广播
- 还是以亮屏SCREEN_ON和开机BOOT_COMPLETED静态广播为例子
//在AndroidManifest.xml中定义如下
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
//MyReceiver.java
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.e("yunhen", "MyReceiver static intent = " + intent.getAction());
}
}
- 测试发现这个不管是亮屏SCREEN_ON还是开机BOOT_COMPLETED的广播都收不到,
BOOT_COMPLETED没有收到的日志如下(大概意思是少了一个RECEIVE_BOOT_COMPLETED权限定义):
04-26 09:00:26.506 1337 1549 W BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.BOOT_COMPLETED flg=0x89000010 (has extras) } to co
m.example.myapplication/.MyReceiver requires android.permission.RECEIVE_BOOT_COMPLETED due to sender null (uid 1000)
那就补上RECEIVE_BOOT_COMPLETED权限:
//在AndroidManifest.xml中定义如下
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
顺利收到BOOT_COMPLETED的广播:
04-26 09:45:26.198 7894 7894 E yunhen : MyReceiver static intent = android.intent.action.BOOT_COMPLETED
-
不过SCREEN_ON,没有收到任何日志报错,就是没收到
-
我们带着这个例子的疑问,一起去代码里面找答案(下一篇广播发送才能找到答案)。
本次先看静态广播是注册到系统的哪里去了
3. AndroidManifest静态注册接受者的安装过程
- 先从安装过程中的processInstallRequestsAsync(PackageManagerService.java)处理安装请求开始讲起,
处理安装请求=>
调用流程
->processInstallRequestsAsync(PackageManagerService.java) //处理安装请求
->installPackagesTracedLI //安装函数,加个installPackages的trace tag
->installPackagesLI //实际安装函数
->preparePackageLI //准备包的信息
->parsePackage(PackageParser2.java) //解析包的信息
PackageManagerService.java
// Queue up an async operation since the package installation may take a little while.
//处理安装请求
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
//...
synchronized (mInstallLock) {
installPackagesTracedLI(apkInstallRequests);
}
//...
});
}
//安装函数,加个installPackages的trace tag
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
//这个是安装应用的关键函数,实际安装函数
private void installPackagesLI(List<InstallRequest> requests) {
//...
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
// TODO(b/109941548): remove this once we've pulled everything from it and into
// scan, reconcile or commit.
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
//准备包的信息,如解析这个应用的内容
prepareResult =
preparePackageLI(request.args, request.installResult);
}
//...
}
//准备包的信息
private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
throws PrepareFailure {
//通过args.installFlags获得如是否instantApp、fullApp、virtualPreload等应用
final int installFlags = args.installFlags;
//...
//注意默认是包含PARSE_CHATTY的tag的
@ParseFlags final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
| ParsingPackageUtils.PARSE_ENFORCE_CODE
| (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
try (PackageParser2 pp = mInjector.getPreparingPackageParser()) {
//开始对包进行解析parsePackage
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
} catch (PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- 包解析,获取相关receiver的组件放入ParsingPackageImpl的receivers中,
我们记住receivers是存放ParsedActivity
调用流程
->parsePackage(PackageParser2.java) //V2版本的解析包的信息
->parsePackage(ParsingPackageUtils.java) //包解析的工具类
->parseClusterPackage //如果是目录,解析目录的簇群
->parseBaseApk //解析BaseApk(最基础的apk)
->parseBaseApkTags //解析AndroidManifest.xml的“application”相关tag
->parseBaseApplication //解析application
->addReceiver(ParsingPackageImpl.java) //将通过parseActivityOrReceiver获取的ParsedActivity放入receivers
//PackageParser2.java
//V2版本的包解析代码
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
//...
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
//...
}
//ParsingPackageUtils.java
//解析包信息
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
//目前大部分跑的是这里,如类似/data/app/vmdl1597983231.tmp的目录,里面包含***.apk
return parseClusterPackage(input, packageFile, flags);
} else {
return parseMonolithicPackage(input, packageFile, flags);
}
}
//解析包的簇群
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
//得到一些包的基本信息,如mBaseApkPath = "/data/app/vmdl1597983231.tmp/base.apk"
//parseClusterPackageLite->composePackageLiteFromApks->new PackageLite(找到".apk"结尾的)
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
//...
try {
final File baseApk = new File(lite.getBaseApkPath());
//解析BaseApk
final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.getPath(), assetLoader, flags);
//...
}
//解析BaseApk
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags)
throws PackageParserException {
//...
//创建解析器parser,来解析ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
//传入解析器parser,解析BaseApk
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags);
//...
}
//传入解析器parser,解析BaseApk
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
//...
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
try {
final boolean isCoreApp =
parser.getAttributeBooleanValue(null, "coreApp", false);
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
//解析apk中的各类TAG
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
//...
}
//解析apk中的各类TAG
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
//...
// <application> has special logic, so it's handled outside the general method
//如果tag是TAG_APPLICATION = "application"的话
if (TAG_APPLICATION.equals(tagName)) {
//...
} else {
foundApp = true;
//则进行application的内容解析
result = parseBaseApplication(input, pkg, res, parser, flags);
//...
}
//解析"application"下的各个内容
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
//...
final ParseResult result;
String tagName = parser.getName();
boolean isActivity = false;
//Android四大组件解析的地方
switch (tagName) {
//activity和receiver的解析是一样的,它们比较类似
case "activity":
isActivity = true;
// fall-through
case "receiver":
//activity和receiver的解析是一样的,它们比较类似
//parseActivityOrReceiver->parseActivityOrAlias中每一个"intent-filter"会对应一个ParsedIntentInfo,
//并放入ParsedComponent(继承关系ParsedActivity/ParsedMainComponent/ParsedComponent)的intents
//本例中解析出来的接收器如{ParsedActivity@38497} "Activity{8f994ed com.example.myapplication/.MyReceiver}"
//ParsedActivity.intents.mActions包括"android.intent.action.SCREEN_ON"、"android.intent.action.BOOT_COMPLETED"
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);
pkg.addActivity(activity);
} else {
//该receiver是否有设置android:order的tag,这个用的比较少,默认order是0
//对于一个包有多个receivers,order进行排序,按照order越大放在越前面
hasReceiverOrder |= (activity.getOrder() != 0);
//将该ParsedActivity activity(receiver)放入ParsingPackageImpl的receivers
pkg.addReceiver(activity);
}
}
result = activityResult;
break;
case "service":
//...
case "provider":
//...
case "activity-alias":
//...
default:
result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
break;
}
//...
//按照android:order进行排序,order越大的receiver放在receivers列表的前面
if (hasReceiverOrder) {
pkg.sortReceivers();
}
//...
}
//ParsingPackageImpl.java
//将该receiver放入ParsingPackageImpl的receivers,
//目前可以看到,包解析后receiver放入的地方是ParsingPackageImpl的receivers中
public ParsingPackageImpl addReceiver(ParsedActivity parsedReceiver) {
this.receivers = CollectionUtils.add(this.receivers, parsedReceiver);
addMimeGroupsFromComponent(parsedReceiver);
return this;
}
将之前receiver解析的ParsedActivity全部放入mComponentResolver(ComponentResolver)的mReceivers中
mReceivers包含了所有安装应用的receiver,通过ComponentName就可以获得相应的ParsedActivity
mReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceive”))
mComponentResolver是PackageManagerService的一个成员变量(也就是相当于将该receiver保存在系统的变量中)
同时将该组件的IntentFilter(intent-filter)/action添加到mComponentResolver(继承IntentResolver)的mFilters/mActionToFilter中
具体流程如下=>
(安装应用有很多阶段,前面说的是包解析,现在说的是将调和后的扫描结果保存到系统中)
->installPackagesLI(PackageManagerService.java) //安装函数
->commitPackagesLocked //将安装信息提交给系统
->commitReconciledScanResultLocked //提交已经协调好的扫描结果
->commitPackageSettings //提交到包信息里面
->mComponentResolver.addAllComponents //添加AndroidPackage pkg中的所有组件
->addReceiversLocked //Receiver组件的添加
->mReceivers.addActivity/addFilter //添加receiver到mComponentResolver的mReceivers,添加IntentFilter/action到mComponentResolver的mFilters/mActionToFilter等
//PackageManagerService.java
//安装函数
private void installPackagesLI(List<InstallRequest> requests) {
//...
//准备包的信息,如解析这个应用的内容
prepareResult =
preparePackageLI(request.args, request.installResult);
//...
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
//将安装信息提交给系统
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
//...
}
private void commitPackagesLocked(final CommitRequest request) {
// TODO: remove any expected failures from this method; this should only be able to fail due
// to unavoidable errors (I/O, etc.)
//本例安装request.reconciledPackages.size()是1
for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
//...
//提交已经协调好的扫描结果
AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);
//...
}
private AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
//...
// Modify state for the given package setting
//提交到包信息里面,从上面可以知道(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0默认是true,也就是chatty是true
commitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags,
(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
//...
}
private void commitPackageSettings(@NonNull AndroidPackage pkg, @Nullable AndroidPackage oldPkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
//...
//通过injector获得ComponentResolver
//mComponentResolver = injector.getComponentResolver();
//相当于new ComponentResolver(第一次调用才会new)获取的mInstance(ComponentResolver)实例
//通过组件解析器mComponentResolver添加pkg(PackageImpl实例)中的组件
//PackageImpl父类是ParsingPackageImpl(存放我们之前说的receivers的地方),而且实现了AndroidPackage接口
mComponentResolver.addAllComponents(pkg, chatty);
//...
}
//ComponentResolver.java
//添加AndroidPackage pkg中的所有组件
void addAllComponents(AndroidPackage pkg, boolean chatty) {
final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>();
synchronized (mLock) {
//Activity组件的添加
addActivitiesLocked(pkg, newIntents, chatty);
//Receiver组件的添加
addReceiversLocked(pkg, chatty);
//Provider组件的添加
addProvidersLocked(pkg, chatty);
//Service组件的添加
addServicesLocked(pkg, chatty);
//状态改变通知到相关mObservers
onChanged();
}
//...
}
//添加AndroidPackage pkg中的Receiver到mComponentResolver的mReceivers
private void addReceiversLocked(AndroidPackage pkg, boolean chatty) {
final int receiversSize = ArrayUtils.size(pkg.getReceivers());
StringBuilder r = null;
for (int i = 0; i < receiversSize; i++) {
//逐个取出ParsingPackageImpl的receivers,如此处的MyReceiver
ParsedActivity a = pkg.getReceivers().get(i);
//添加mComponentResolver的mReceivers
mReceivers.addActivity(a, "receiver", null);
//DEBUG_PACKAGE_SCANNING这个PMS的调试开关,用于判断是否输出日志
//可以将全部pms debug相关的开关做成动态开关
if (DEBUG_PACKAGE_SCANNING && chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.getName());
}
}
//输出相关添加Receivers的日志
if (DEBUG_PACKAGE_SCANNING && chatty) {
Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r));
}
}
//mReceivers是ReceiverIntentResolver对象,其父类是ActivityIntentResolver
//添加ParsedActivity a到mActivities中
protected void addActivity(ParsedActivity a, String type,
List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {
//其mActivities以ComponentName为key,保存着ParsedActivity(此处是MyReceiver)
mActivities.put(a.getComponentName(), a);
//DEBUG_SHOW_INFO这个是调试信息的开关,可以打开查看流程
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " " + type + ":");
Log.v(TAG, " Class=" + a.getName());
}
//取得ParsedIntentInfo,这里只有1个intent-filter就对应1个ParsedIntentInfo
//如果写2个intent-filter,就会有2个ParsedIntentInfo(继承的IntentFilter)
final int intentsSize = a.getIntents().size();
for (int j = 0; j < intentsSize; j++) {
ParsedIntentInfo intent = a.getIntents().get(j);
if (newIntents != null && "activity".equals(type)) {
newIntents.add(Pair.create(a, intent));
}
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
//这个也是调试使用,末日是不输出的
if (!intent.debugCheck()) {
Log.w(TAG, "==> For Activity " + a.getName());
}
//Pair.create(a, intent)相当于new Pair<ParsedActivity, ParsedIntentInfo>(a, intent);
//添加到ComponentResolver(继承IntentResolver)的mFilters/mActionToFilter中
addFilter(Pair.create(a, intent));
}
}
//IntentResolver.java
//添加IntentFilter
public void addFilter(F f) {
IntentFilter intentFilter = getIntentFilter(f);
//localLOGV这些都是调试日志
if (localLOGV) {
Slog.v(TAG, "Adding filter: " + f);
intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
Slog.v(TAG, " Building Lookup Maps:");
}
//将Pair<ParsedActivity, ParsedIntentInfo>添加到mFilters
mFilters.add(f);
//将mDataSchemes放入mSchemeToFilter
int numS = register_intent_filter(f, intentFilter.schemesIterator(),
mSchemeToFilter, " Scheme: ");
int numT = register_mime_types(f, " Type: ");
if (numS == 0 && numT == 0) {
//将mActions放入mActionToFilter, key是action,value是Pair<ParsedActivity, ParsedIntentInfo>的list
//如mActionToFilter.get("android.intent.action.BOOT_COMPLETED") = {Pair[316]@38034}
//107 = {Pair@38369} "Pair{Activity{7d26902 com.example.myapplication/.MyReceiver2} ParsedIntentInfo{a218213}}"
//108 = {Pair@38370} "Pair{Activity{3985c50 com.example.myapplication/.MyReceiver} ParsedIntentInfo{9dfde49}}"
register_intent_filter(f, intentFilter.actionsIterator(),
mActionToFilter, " Action: ");
}
if (numT != 0) {
register_intent_filter(f, intentFilter.actionsIterator(),
mTypedActionToFilter, " TypedAction: ");
}
}
4. 总结
- AndroidManifest.xml中的receiver解析成ParsedActivity, 存放在PackageImpl的receivers(PackageImpl父类是ParsingPackageImpl而且实现了AndroidPackage接口)
- receivers最终会存放在mComponentResolver(PMS)的mReceivers中,mReceivers包含了所有安装应用的receiver,通过ComponentName就可以获得相应的ParsedActivity,如:
mReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceive”)),既可以获得MyReceiver的ParsedActivity - receiver中的一个IntentFilter(intent-filter)对应一个ParsedIntentInfo,一个Pair<ParsedActivity, ParsedIntentInfo>
- Pair<ParsedActivity, ParsedIntentInfo>被放入mComponentResolver的mFilters
- mActions被放入mComponentResolver的mActionToFilter
- 部分静态广播注册需要权限,不是注册了就能收到。其实要接收广播还:涉及权限、进程优先级、flag标签等各类无法接收到广播的情况。
(系统一般是skip或者根本不发送给静态广播或者mComponentResolver解析时就跳过了)