1. 静态广播注册的流程
上一篇文章讲了动态广播的注册(系统存储在mReceiverResolver中), 这篇文章主要讲解静态广播的注册流程 => 解析包中的receiver => 将receiver相关信息添加到mComponentResolver中
2. 在AndroidManifest静态注册广播
- 还是以亮屏SCREEN_ON和开机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>
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权限:
<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
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
synchronized (mInstallLock) {
installPackagesTracedLI(apkInstallRequests);
}
});
}
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) {
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 {
final int installFlags = args.installFlags;
@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()) {
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
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
}
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);
}
}
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, 0);
try {
final File baseApk = new File(lite.getBaseApkPath());
final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.getPath(), assetLoader, flags);
}
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags)
throws PackageParserException {
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags);
}
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);
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
}
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
if (TAG_APPLICATION.equals(tagName)) {
} else {
foundApp = true;
result = parseBaseApplication(input, pkg, res, parser, flags);
}
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;
switch (tagName) {
case "activity":
isActivity = true;
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);
pkg.addActivity(activity);
} else {
hasReceiverOrder |= (activity.getOrder() != 0);
pkg.addReceiver(activity);
}
}
result = activityResult;
break;
case "service":
case "provider":
case "activity-alias":
default:
result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
break;
}
if (hasReceiverOrder) {
pkg.sortReceivers();
}
}
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等
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) {
for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);
}
private AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
commitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags,
(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 , reconciledPkg);
}
private void commitPackageSettings(@NonNull AndroidPackage pkg, @Nullable AndroidPackage oldPkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
mComponentResolver.addAllComponents(pkg, chatty);
}
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();
}
}
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);
if (DEBUG_PACKAGE_SCANNING && chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.getName());
}
}
if (DEBUG_PACKAGE_SCANNING && chatty) {
Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r));
}
}
protected void addActivity(ParsedActivity a, String type,
List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {
mActivities.put(a.getComponentName(), a);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " " + type + ":");
Log.v(TAG, " Class=" + a.getName());
}
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());
}
addFilter(Pair.create(a, intent));
}
}
public void addFilter(F f) {
IntentFilter intentFilter = getIntentFilter(f);
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:");
}
mFilters.add(f);
int numS = register_intent_filter(f, intentFilter.schemesIterator(),
mSchemeToFilter, " Scheme: ");
int numT = register_mime_types(f, " Type: ");
if (numS == 0 && numT == 0) {
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解析时就跳过了)
|