静态广播注册时序图
动态广播注册时序图
发送广播时序图
前言
广播接收器可以分为动态和静态,静态广播接收器就是在 AndroidManifest.xml 中注册的,而动态的广播接收器是在代码中通过 Context#registerReceiver() 注册的。
这里先从静态广播的流程开始分析。
1. 静态广播的注册
1.1 pkms#processInstallRequestsAsync处理安装请求
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
14379 // Queue up an async operation since the package installation may take a little while.
14380 private void processInstallRequestsAsync(boolean success,
14381 List<InstallRequest> installRequests) {
14382 mHandler.post(() -> {
14383 if (success) {
14384 for (InstallRequest request : installRequests) {
14385 request.args.doPreInstall(request.installResult.returnCode);
14386 }
14387 synchronized (mInstallLock) {// 调用installPackagesTracedLI执行安装
14388 installPackagesTracedLI(installRequests);
14389 }
14390 for (InstallRequest request : installRequests) {
14391 request.args.doPostInstall(
14392 request.installResult.returnCode, request.installResult.uid);
14393 }
14394 }
14395 for (InstallRequest request : installRequests) {
14396 restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
14397 new PostInstallData(request.args, request.installResult, null));
14398 }
14399 });
14400 }
1.2 pkms#installPackagesTracedLI
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
安装函数,加个installPackages的trace tag ,这里的tag也可以从systrace上观察到
16218 @GuardedBy({"mInstallLock", "mLock"})
16219 private void installPackagesTracedLI(List<InstallRequest> requests) {
16220 try {
16221 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
16222 installPackagesLI(requests);
16223 } finally {
16224 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
16225 }
16226 }
1.3 pkms#installPackagesLI
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
安装应用的关键函数,实际安装函数
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);}//...}
1.4 pkms#preparePackageLI
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
准备包的信息
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()) {//开始对包进行解析parsePackageparsedPackage = 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
1.5 PackageParser2#parsePackage
/frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java
解析package
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)throws PackageParserException {//...ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);//...}
1.6 ParsingPackageUtils#parsePackage
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
//解析包信息public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,int flags)throws PackageParserException {if (packageFile.isDirectory()) {//目前大部分跑的是这里,如类似/data/app/vmdl1597983231.tmp的目录,里面包含***.apkreturn parseClusterPackage(input, packageFile, flags);} else {return parseMonolithicPackage(input, packageFile, flags);}}
1.7 ParsingPackageUtils#parseClusterPackage
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
//解析包的簇群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());//解析BaseApkfinal ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,lite.getPath(), assetLoader, flags);//...}
1.8 ParsingPackageUtils#parseBaseApk
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
解析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,解析BaseApkParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,parser, flags);//...}
1.9 ParsingPackageUtils#parseBaseApk
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
传入解析器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中的各类TAGfinal ParseResult<ParsingPackage> result =parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);//...}
1.10 ParsingPackageUtils#parseBaseApkTags
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
解析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);//...}
1.11 ParsingPackageUtils#parseBaseApplication
/frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
解析"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-throughcase "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.xx"、"android.intent.action.xxx"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的receiverspkg.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();}//...}
1.12 ParsingPackageImpl#addReceiver
/frameworks/base/core/java/android/content/pm/parsing/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就可以获得相应的ParsedActivitymReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceive”))
mComponentResolver是PackageManagerService的一个成员变量(也就是相当于将该receiver保存在系统的变量中),同时将该组件的IntentFilter(intent-filter)/action添加到mComponentResolver(继承IntentResolver)的mFilters/mActionToFilter中。
前面分析了包解析的结果,现在分析将调和后的扫描结果保存到系统中。
1.13 pkms#installPackagesLI
/frameworks/base/services/core/java/com/android/server/pm/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);}//...}
1.14 pkms#commitPackagesLocked
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
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()是1for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {//...//提交已经协调好的扫描结果AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);//...}
1.15 pkms#commitReconciledScanResultLocked
/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private AndroidPackage commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {//...// Modify state for the given package setting//提交到包信息里面,从上面可以知道(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0默认是true,也就是chatty是truecommitPackageSettings(pkg, oldPkg, pkgSetting, oldPkgSetting, scanFlags,(parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);//...}
1.16 pkms#commitPackageSettings
/frameworks/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) {//...//通过injector获得ComponentResolver//mComponentResolver = injector.getComponentResolver();//相当于new ComponentResolver(第一次调用才会new)获取的mInstance(ComponentResolver)实例//通过组件解析器mComponentResolver添加pkg(PackageImpl实例)中的组件//PackageImpl父类是ParsingPackageImpl(存放我们之前说的receivers的地方),而且实现了AndroidPackage接口mComponentResolver.addAllComponents(pkg, chatty);//...}
1.17 ComponentResolver#addAllComponents
/frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
添加AndroidPackage pkg中的所有组件
470 void addAllComponents(AndroidPackage pkg, boolean chatty) {
471 final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>();
472 synchronized (mLock) {//Activity组件的添加
473 addActivitiesLocked(pkg, newIntents, chatty);//Receiver组件的添加
474 addReceiversLocked(pkg, chatty);//Provider组件的添加
475 addProvidersLocked(pkg, chatty);//Service组件的添加
476 addServicesLocked(pkg, chatty);
477 }
478 // expect single setupwizard package
479 final String setupWizardPackage = ArrayUtils.firstOrNull(
480 sPackageManagerInternal.getKnownPackageNames(
481 PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM));
482
483 for (int i = newIntents.size() - 1; i >= 0; --i) {
484 final Pair<ParsedActivity, ParsedIntentInfo> pair = newIntents.get(i);
485 final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal
486 .getDisabledSystemPackage(pair.first.getPackageName());
487 final AndroidPackage disabledPkg =
488 disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
489 final List<ParsedActivity> systemActivities =
490 disabledPkg != null ? disabledPkg.getActivities() : null;
491 adjustPriority(systemActivities, pair.first, pair.second, setupWizardPackage);
492 }
493 }
1.18 ComponentResolver#addReceiversLocked
/frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
添加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,如此处的MyReceiverParsedActivity a = pkg.getReceivers().get(i);//添加mComponentResolver的mReceiversmReceivers.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));}}
1.19 ComponentResolver#addActivity
/frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
//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));}}
1.20 IntentResolver#addFilter
/frameworks/base/services/core/java/com/android/server/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>添加到mFiltersmFilters.add(f);//将mDataSchemes放入mSchemeToFilterint 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: ");}}
1.21 小结
- 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.MyReceiver”)),既可以获得MyReceiver的ParsedActivity
- receiver中的一个IntentFilter(intent-filter)对应一个ParsedIntentInfo,一个Pair<ParsedActivity, ParsedIntentInfo>
- Pair<ParsedActivity, ParsedIntentInfo>被放入mComponentResolver的mFilters
- mActions被放入mComponentResolver的mActionToFilter
- 部分静态广播注册需要权限,不是注册了就能收到。其实要接收广播还:涉及权限、进程优先级、flag标签等各类无法接收到广播的情况。
(系统一般是skip或者根本不发送给静态广播或者mComponentResolver解析时就跳过了)
2. 动态广播注册
2.1 ContextWrapper#registerReceiver
/frameworks/base/core/java/android/content/ContextWrapper.java
665 @Override
666 public Intent registerReceiver(
667 BroadcastReceiver receiver, IntentFilter filter) {
668 return mBase.registerReceiver(receiver, filter);
669 }
2.1.1 mBase在哪里设置?
mBase就是ContextImpl
一个是在构造函数里面设置,一个是调用attachBaseContext
设置,
如果是activity的mBase则是调用attachBaseContext
设置
//ContextWrapper.javapublic ContextWrapper(Context base) {mBase = base;}protected void attachBaseContext(Context base) {if (mBase != null) {throw new IllegalStateException("Base context already set");}mBase = base;}
2.1.1 新建new ContextImpl
在ActivityThread.java的performLaunchActivity(启动应用时发出的LaunchActivityItem会执行activity生命周期的内容)会新建new ContextImpl,并进行mBase赋值.
新建new ContextImpl流程:
ActivityThread.java: performLaunchActivity->createBaseContextForActivity
ContextImpl.java: ->createActivityContext->new ContextImpl
得到ContextImpl之后通过activity.attach进行mBase下一步赋值:
//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//...
//创建ContextImpl
ContextImpl appContext = createBaseContextForActivity(r);
//...
//将ContextImpl的mOuterContext设置成activity
appContext.setOuterContext(activity);
//将appContext赋值给Activity(Activity是ContextWrapper的子类)的mBase对象,
//在这里上面2个(mBase/mOuterContext)是一样的
activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback,r.assistToken, r.shareableActivityToken);
//...
}private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {final int displayId = ActivityClient.getInstance().getDisplayId(r.token);//此处在ActivityThread将this传入ContextImpl的mMainThreadContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);//...return appContext;
}//ContextImpl.java
static ContextImpl createActivityContext(ActivityThread mainThread,LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,Configuration overrideConfiguration) {if (packageInfo == null) throw new IllegalArgumentException("packageInfo");String[] splitDirs = packageInfo.getSplitResDirs();//这里是LoadedApk的getClassLoaderClassLoader classLoader = packageInfo.getClassLoader();if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");try {classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);} catch (NameNotFoundException e) {// Nothing above us can handle a NameNotFoundException, better crash.throw new RuntimeException(e);} finally {Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);}}final String attributionTag;if (activityInfo.attributionTags != null && activityInfo.attributionTags.length > 0) {attributionTag = activityInfo.attributionTags[0];} else {attributionTag = null;}//新建new ContextImpl,注意传入参数mainThread、classLoader等,还有createActivityContext函数的一些resources初始化//传入的UserHandle user是nullContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,null);context.mContextType = CONTEXT_TYPE_ACTIVITY;context.mIsConfigurationBasedContext = true;// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)? packageInfo.getCompatibilityInfo(): CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;final ResourcesManager resourcesManager = ResourcesManager.getInstance();// Create the base resources for which all configuration contexts for this Activity// will be rebased upon.context.setResources(resourcesManager.createBaseTokenResources(activityToken,packageInfo.getResDir(),splitDirs,packageInfo.getOverlayDirs(),packageInfo.getOverlayPaths(),packageInfo.getApplicationInfo().sharedLibraryFiles,displayId,overrideConfiguration,compatInfo,classLoader,packageInfo.getApplication() == null ? null: packageInfo.getApplication().getResources().getLoaders()));context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,context.getResources());return context;
}
2.1.2 mBase赋值的流程
ActivityThread.java: performLaunchActivity
Activity.java: ->attach->attachBaseContext
attachBaseContext: Activity/ContextThemeWrapper/ContextWrapper (extends继承关系)
最终在ContextWrapper中设置mBase为activity的ContextImpl
得到ContextImpl之后通过activity.attach进行mBase下一步赋值
//Activity.javafinal void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,IBinder shareableActivityToken) {attachBaseContext(context);//...}protected void attachBaseContext(Context newBase) {super.attachBaseContext(newBase);if (newBase != null) {newBase.setAutofillClient(this);newBase.setContentCaptureOptions(getContentCaptureOptions());}}//ContextThemeWrapper.javaprotected void attachBaseContext(Context newBase) {super.attachBaseContext(newBase);}//ContextWrapper.javaprotected void attachBaseContext(Context base) {if (mBase != null) {throw new IllegalStateException("Base context already set");}mBase = base;}
前面调用registerReceiver之后经过了ContextWrapper,然后又调用到ContextImpl#registerReceiver
2.2 ContextImpl#registerReceiver
/frameworks/base/core/java/android/app/ContextImpl.java
@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,int flags) {return registerReceiver(receiver, filter, null, null, flags);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermission, Handler scheduler) {return registerReceiverInternal(receiver, getUserId(),filter, broadcastPermission, scheduler, getOuterContext(), 0);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermission, Handler scheduler, int flags) {return registerReceiverInternal(receiver, getUserId(),filter, broadcastPermission, scheduler, getOuterContext(), flags);}
2.3 ContextImpl#registerReceiverInternal
/frameworks/base/core/java/android/app/ContextImpl.java
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,IntentFilter filter, String broadcastPermission,Handler scheduler, Context context, int flags) {//IIntentReceiver rd才是系统system_server需要发送广播到app的接口对象IIntentReceiver rd = null;//receiver如果接受者不为null,则会新建IIntentReceiver rd//我们例子里面是存在receiver的,至于不存在receiver的情况也是有使用场景的,这个就后面点讲if (receiver != null) {//在本例中LoadedApk mPackageInfo不为null,context也不为nullif (mPackageInfo != null && context != null) {//传入的广播调度器scheduler是nullif (scheduler == null) {//那就直接使用主线程ActivityThread的handler(mH)作为调度器scheduler = mMainThread.getHandler();}//从mPackageInfo中取得IIntentReceiver,并将该receiver放入LoadedApk mPackageInfo的mReceivers中//LoadedApk的mReceivers(可以作为检测app注册多少个广播的其中一个插装的地方)//这里我们先记住LoadedApk.ReceiverDispatcher.mIIntentReceiver这个东西,后面分发广播的时候有用到//registered = true代表是注册接受者rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);} else {//如果mPackageInfo或者context有一个为null//scheduler为null的时候直接使用主线程mMainThreadif (scheduler == null) {scheduler = mMainThread.getHandler();}//此处直接new一个LoadedApk.ReceiverDispatcher得到mIIntentReceiver,赋值给IIntentReceiver rd(这种没有记录在LoadedApk的mReceivers)rd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver();}}try {//实际调用的是AMS的registerReceiverWithFeaturefinal Intent intent = ActivityManager.getService().registerReceiverWithFeature(mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,flags);if (intent != null) {//如果intent不为null,设置mExtras的ClassLoaderintent.setExtrasClassLoader(getClassLoader());// TODO: determine at registration time if caller is// protecting themselves with signature permission// 设置注册的是否保护的广播,还有AttributionSourceintent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),getAttributionSource());}return intent;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
2.4 LoadedApk#getReceiverDispatcher
/frameworks/base/core/java/android/app/LoadedApk.java
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,Context context, Handler handler,Instrumentation instrumentation, boolean registered) {synchronized (mReceivers) {LoadedApk.ReceiverDispatcher rd = null;ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;if (registered) {//从mReceivers取出对于该context的ReceiverDispatcher mapmap = mReceivers.get(context);if (map != null) {//从map取出对于该BroadcastReceiver的ReceiverDispatcher//注意: 一个BroadcastReceiver对应一个ReceiverDispatcherrd = map.get(r);}}//如果没有BroadcastReceiver对应的ReceiverDispatcherif (rd == null) {//根据BroadcastReceiver r新建一个ReceiverDispatcherrd = new ReceiverDispatcher(r, context, handler,instrumentation, registered);//此处registered是trueif (registered) {//将ReceiverDispatcher rd放入map中,而map是存储在mReceivers中的if (map == null) {map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();mReceivers.put(context, map);}map.put(r, rd);}} else {rd.validate(context, handler);}rd.mForgotten = false;//获取mIIntentReceiverreturn rd.getIIntentReceiver();}}ReceiverDispatcher(BroadcastReceiver receiver, Context context,Handler activityThread, Instrumentation instrumentation,boolean registered) {if (activityThread == null) {throw new NullPointerException("Handler must not be null");}//传递给AMS的就是mIIntentReceiver(IIntentReceiver.Stub对象,实现了IIntentReceiver接口)mIIntentReceiver = new InnerReceiver(this, !registered);mReceiver = receiver;mContext = context;mActivityThread = activityThread;mInstrumentation = instrumentation;mRegistered = registered;mLocation = new IntentReceiverLeaked(null);mLocation.fillInStackTrace();}//返回mIIntentReceiverIIntentReceiver getIIntentReceiver() {return mIIntentReceiver;}
2.5 AMS#registerReceiverWithFeature
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
//本例中的caller: mMainThread.getApplicationThread()应用的ApplicationThread//callerPackage: 是调用者的包名//callerFeatureId: 是getAttributionTag返回的attributionTag//receiverId: 是获取的call name + id的string(如果是PendingIntent的话,得到的是PendingIntentRecord的lastTag)//receiver: 就是LoadedApk.ReceiverDispatcher用户接受广播的地方//filter: 是意图过滤器//permission: 是发送这个广播需要的权限,一般不设置,//如果设置了如VpnManagerService注册广播有使用NETWORK_STACK,则发送者需要有这个权限才能发送到VpnManagerService的接受者//userId: 是用户的组别id,如USER_OWNER/USER_SYSTEM(0)、USER_ALL(-1)、USER_CURRENT(-2)、USER_CURRENT_OR_SELF(-3)、USER_NULL(-10000)//而这里是activity的Process.myUserHandle()->Os.getuid(),此处是0//flags: 此处默认是0public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,String callerFeatureId, String receiverId, IIntentReceiver receiver,IntentFilter filter, String permission, int userId, int flags) {
a. 权限判断,callerApp、instantApp等的初始化
//uid是Isolated的应用是不能调用registerReceiverWithFeature的enforceNotIsolatedCaller("registerReceiver");//stickyIntents粘性广播的意图ArrayList<Intent> stickyIntents = null;//callerApp调用者ProcessRecord callerApp = null;//visibleToInstantApps是否允许发送到InstantApps即时appfinal boolean visibleToInstantApps= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;//调用者的uid和pidint callingUid;int callingPid;//是否instantApp(即时app),在安装的时候就已经确定,PMS识别安装带有INSTALL_INSTANT_APP flag的应用boolean instantApp;synchronized(this) {if (caller != null) {//如果存在caller(IApplicationThread),则从mProcessList中取出caller对应的callerAppcallerApp = getRecordForAppLOSP(caller);if (callerApp == null) {throw new SecurityException("Unable to find app for caller " + caller+ " (pid=" + Binder.getCallingPid()+ ") when registering receiver " + receiver);}if (callerApp.info.uid != SYSTEM_UID&& !callerApp.getPkgList().containsKey(callerPackage)&& !"android".equals(callerPackage)) {throw new SecurityException("Given caller package " + callerPackage+ " is not running in process " + callerApp);}//通过callerApp取得callingUid、callingPidcallingUid = callerApp.info.uid;callingPid = callerApp.getPid();} else {//否则callerPackage设置为null, callingUid、callingPid设置成binder调用者的uid和pid//如MonkeyNetworkMonitor.java中 am.registerReceiverWithFeature(null, null,callerPackage = null;callingUid = Binder.getCallingUid();callingPid = Binder.getCallingPid();}// Android Instant App 正是这一理念的集中体现——这是一种用户无需安装即可运行 Android 应用的全新方式// 由于不需要事先安装应用,Instant App 能在任何场合直接抵达用户。“瞬间抵达用户” 这个概念// Android Instant App 需要由大小不超过 4MB 的可通过 URL 寻址的模块构建而成。// 如果应用大小超过 4MB,开发者就需要将应用重构为可下载的、响应 URL 导航独立运行的较小的模块instantApp = isInstantApp(callerApp, callerPackage, callingUid);//多用户广播动态注册,如果是callingUid、userId同一个用户组,则直接返回userIduserId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
b. 获取filter的action,看一下是否粘性广播stickyIntents(粘性广播这个东西也很有意思,经常听到),获取其filter对应的所有所有粘性广播allSticky
粘性广播:只要该粘性广播发送过(就算是之前发送的),注册接收粘性广播的时候可以马上收到该广播,不用担心注册在发送广播之前就收不到的问题
//遍历IntentFilter中包含的所有actionIterator<String> actions = filter.actionsIterator();if (actions == null) {ArrayList<String> noAction = new ArrayList<String>(1);noAction.add(null);//如果没有action,则放入一个null的noAction到actions中,确保actions不为nullactions = noAction.iterator();}// Collect stickies of usersint[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };//遍历所有的actionwhile (actions.hasNext()) {String action = actions.next();for (int id : userIds) {//遍历mStickyBroadcasts已经发送了的粘性广播列表stickiesArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);if (stickies != null) {//获取这个动态注册接受者action的粘性广播ArrayList<Intent> intents = stickies.get(action);//如果系统发送过这个action的粘性广播if (intents != null) {if (stickyIntents == null) {stickyIntents = new ArrayList<Intent>();}//则将粘性广播intents全部放入stickyIntentsstickyIntents.addAll(intents);}}}}}//粘性广播的列表,默认是nullArrayList<Intent> allSticky = null;//如果之前已经发送过这个action的粘性广播,则stickyIntents不为null,否则为nullif (stickyIntents != null) {//获取内容解析器ContentResolverfinal ContentResolver resolver = mContext.getContentResolver();// Look for any matching sticky broadcasts...//遍历粘性广播的Intent:stickyIntentsfor (int i = 0, N = stickyIntents.size(); i < N; i++) {//遍历粘性广播的IntentIntent intent = stickyIntents.get(i);// Don't provided intents that aren't available to instant apps.//如果是instantApp,而且没有单独设置接受粘性广播FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS//则默认是处理粘性广播的if (instantApp &&(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {continue;}// If intent has scheme "content", it will need to acccess// provider that needs to lock mProviderMap in ActivityThread// and also it may need to wait application response, so we// cannot lock ActivityManagerService here.//匹配一下注册广播的filter,是否和intent一致,如果大于0则表示匹配成功if (filter.match(resolver, intent, true, TAG) >= 0) {if (allSticky == null) {allSticky = new ArrayList<Intent>();}//如果匹配成功则将该粘性广播intent保存在allStickyallSticky.add(intent);}}}
c. 如果receiver == null,而且其注册的是粘性广播,那么将粘性广播的Intent返回给app,
如获取粘性广播的一些信息(比如电池信息),可以将receiver设为空,可以在注册的时候获取一次
信息,这种使用场景不会有后续监听。
// The first sticky in the list is returned directly back to the client.//取得匹配成功后的第一个粘性广播stickyIntent sticky = allSticky != null ? allSticky.get(0) : null;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);// 判断receiver是否为空,如果为空则直接返回找到的对应Sticky Intent。// 正常情况下receiver是不为空的,但是有时候为了获取粘性广播的一些信息(比如电池信息),可以将receiver设为空,// 只为了从返回的Sticky Intent中获取这些信息。// 这时的注册广播可以写成这种形式:mBatteryBroadcast = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));// 但是注意,这种形式只能在注册的时候获得一次信息,而不会有后续的继续监听。if (receiver == null) {//只在粘性广播这种注册方式才有价值,用于单次更新return sticky;}// SafetyNet logging for b/177931370. If any process other than system_server tries to// listen to this broadcast action, then log it.//非system_server系统进程if (callingPid != Process.myPid()) {//如果filter包含了SNOOZE_WARNING、SNOOZE_RAPID,则输入日志if (filter.hasAction("com.android.server.net.action.SNOOZE_WARNING")|| filter.hasAction("com.android.server.net.action.SNOOZE_RAPID")) {EventLog.writeEvent(0x534e4554, "177931370", callingUid, "");}}
d. 构建接受者列表ReceiverList rl, mRegisteredReceivers 保存了所有动态注册的receiver.asBinder使用IntentFilter filter, 构建接受者列表ReceiverList rl构建BroadcastFilter bf广播过滤器,并把bf到mReceiverResolver中去,该变量用于在broadcastIntentLocked分发广播的时候, 查询符合条件的动态注册的广播。
这里注意:mReceiverResolver就是动态广播最终存放的地方,后面发送广播的时候就从这里找到动态注册的接受者。
synchronized (this) {IApplicationThread thread;// 取得callerApp的IApplicationThread应用线程if (callerApp != null && ((thread = callerApp.getThread()) == null|| thread.asBinder() != caller.asBinder())) {// Original caller already died//如果callerApp没有IApplicationThread(或者caller和callerApp的IApplicationThread不一致),// 则代表进程之前已经死掉了return null;}//获取这个接受者receiver,是否已经保存在AMS的mRegisteredReceivers动态注册者列表里面ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());//如果之前没有注册过(没有在mRegisteredReceivers中)if (rl == null) {//如果ReceiverList rl是null,则新建一个ReceiverList//传入参数是: AMS, callerApp, callingPid, callingUid, userId, receiver(接受者)rl = new ReceiverList(this, callerApp, callingPid, callingUid,userId, receiver);if (rl.app != null) {//如果callerApp不为null,获取一下当前mReceiversfinal int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();//一个进程最多1000个接受者(动态)if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {throw new IllegalStateException("Too many receivers, total of "+ totalReceiversForApp + ", registered for pid: "+ rl.pid + ", callerPackage: " + callerPackage);}//将ReceiverList rl添加到mReceivers(ProcessReceiverRecord.java)中去(有点循环的感觉)rl.app.mReceivers.addReceiver(rl);} else {//callerApp == null的情况, 如MonkeyNetworkMonitortry {//持有receiver的进程死亡之后会回调ReceiverList rl的binderDied//binderDied会设置linkedToDeath = false;和调用AMS的unregisterReceiver(receiver),里面会有// rl.receiver.asBinder().unlinkToDeath(rl, 0);的操作receiver.asBinder().linkToDeath(rl, 0);} catch (RemoteException e) {return sticky;receivers = collectReceiverComponents}//设置有死亡监听rl.linkedToDeath = true;}//将以receiver为key,ReceiverList rl为value,保存在mRegisteredReceivers中//mRegisteredReceivers保存了所有的动态注册的receivermRegisteredReceivers.put(receiver.asBinder(), rl);} else if (rl.uid != callingUid) {throw new IllegalArgumentException("Receiver requested to register for uid " + callingUid+ " was previously registered for uid " + rl.uid+ " callerPackage is " + callerPackage);} else if (rl.pid != callingPid) {throw new IllegalArgumentException("Receiver requested to register for pid " + callingPid+ " was previously registered for pid " + rl.pid+ " callerPackage is " + callerPackage);} else if (rl.userId != userId) {throw new IllegalArgumentException("Receiver requested to register for user " + userId+ " was previously registered for user " + rl.userId+ " callerPackage is " + callerPackage);}// ReceiverList rl接收列表 (ReceiverList extends ArrayList<BroadcastFilter>),它的元素是BroadcastFilter bf// BroadcastFilter bf广播过滤器// 上面只是把广播接收着receiver的一些信息保存在ReceiverList rl中,但是还没有把它和filter关联起来,// 这里就创建一个BroadcastFilter(bf)来把广播接收器列表rl和filter关联起来BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);//如果ReceiverList rl已经包含这个filter,则不再加入if (rl.containsFilter(filter)) {Slog.w(TAG, "Receiver with filter " + filter+ " already registered for pid " + rl.pid+ ", callerPackage is " + callerPackage);} else {//如果ReceiverList rl之前没添加过BroadcastFilter(bf),则加入接收列表中rl.add(bf);if (!bf.debugCheck()) {Slog.w(TAG, "==> For Dynamic broadcast");}//同时添加bf到mReceiverResolver中去//该变量用于在broadcastIntentLocked分发广播的时候, 查询符合条件的动态注册的广播mReceiverResolver.addFilter(bf);}
e. 最后就是粘性广播发送的地方, 将所有满足条件的粘性广播allSticky,发送给BroadcastFilter bf(我们认为是IIntentReceiver receiver就行了)
// Enqueue broadcasts for all existing stickies that match// this filter.// 粘性广播的处理:如果allSticky不为空,// 广播接受者注册的广播的是粘性广播。// 所以就将这个粘性广播添加到mParallelBroadcasts平行队列中等待调度(具体的可参考后面广播发送流程的最后几步)。// 最后再返回sticky// (如果非粘性的,则为空;反之,sticky不为空,附带着粘性广播里的一些数据)。if (allSticky != null) {ArrayList receivers = new ArrayList();//BroadcastFilter bf才是实际的接受者,接受者receivers只有一个BroadcastFilter bf,//也就是单发给BroadcastFilter bfreceivers.add(bf);final int stickyCount = allSticky.size();//遍历匹配成功的粘性广播列表allStickyfor (int i = 0; i < stickyCount; i++) {Intent intent = allSticky.get(i);//取出intent对应的广播队列BroadcastQueue queue = broadcastQueueForIntent(intent);//新建BroadcastRecord广播记录对象,_initialSticky = true, 粘性广播//包含receivers(BroadcastFilter bf)//_timeoutExempt = falseBroadcastRecord r = new BroadcastRecord(queue, intent, null,null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,null, 0, null, null, false, true, true, -1, false, null,false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);//粘性广播接受者注册后, 马上之前发送过的粘性广播构建的BroadcastRecord r,就放入mParallelBroadcasts中queue.enqueueParallelBroadcastLocked(r);//这里会马上处理刚才的平行广播队列,也就是达到注册了之后马上执行的效果queue.scheduleBroadcastsLocked();}}return sticky;}}
2.6 小结
服务端对于动态注册的广播接收器的处理过程如下
- 使用 mRegisteredReceivers 建立客户端与服务端的广播接收器的映射。ReceiverList 代表服务端的广播接收器,IIntentReceiver 代表客户端的广播接收器。
- 使用客户端的 IntentFilter , 创建服务端的广播过滤器 BroadcastFilter,并保存到 mReceiverResolver。注意,这一步中,ReceiverList 和 BroadcastFilter 互相保存了引用。
这些数据结构都是相互关联的,有何种用意呢?当发送方发送广播到 AMS,AMS 会使用 mReceiverResolver 匹配 BroadcastFilter,BroadcastFilter 找到 ReceiverList,ReceiverList 找到 IIntentReceiver,IIntentReceiver 发送广播给接收方。
另外,由于 sticky 广播是会被缓存的,当注册 sticky 广播的接收器时,有以下两种处理方式
- 如果注册的广播接收器为 null,那么会返回最近的一次广播数据给接收方。
- 如果注册的广播接收器不为null,那么会把匹配到的 sticky 广播发送给接收方的广播接收器,也就是会调用 BroadcastReceiver#onReceive()。
3. 广播发送
3.1 ContextWrapper#sendBroadcast
/frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context { Context mBase; @Override public void sendBroadcast(Intent intent) { mBase.sendBroadcast(intent); } @Override public void sendBroadcast(Intent intent, String receiverPermission) { mBase.sendBroadcast(intent, receiverPermission); }
}
3.2 ContextImpl#sendBroadcast
/frameworks/base/core/java/android/app/ContextImpl.java
public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); // 调用AMS的broadcastIntentWithFeature方法 ActivityManager.getService().broadcastIntentWithFeature( mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
3.3 AMS处理发送广播
我们发送广播的类型可分为:无序广播(并行)、有序广播(有序)。对于动态注册的广播接收器如果接收到的是并行广播则并行执行,如果是串行广播则串行执行。如果是静态注册的工广播接收器则无论发送的广播是否为并行还是串行,都按串行执行。
3.3.1 AMS#broadcastIntentWithFeature
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle resultExtras,String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,boolean serialized, boolean sticky, int userId) {enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {intent = verifyBroadcastLocked(intent);//通过IApplicationThread获取调用者ProcessRecord callerAppfinal ProcessRecord callerApp = getRecordForAppLOSP(caller);final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();try {//获取callerApp、callingPid、callingUid用于广播发送参数传入return broadcastIntentLocked(callerApp,callerApp != null ? callerApp.info.packageName : null, callingFeatureId,intent, resolvedType, resultTo, resultCode, resultData, resultExtras,requiredPermissions, excludedPermissions, appOp, bOptions, serialized,sticky, callingPid, callingUid, callingUid, callingPid, userId);} finally {Binder.restoreCallingIdentity(origId);}}}
3.3.2 AMS#broadcastIntentLocked修改增加默认flag解析可选广播参数BroadcastOptions
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- 如默认会增加 FLAG_EXCLUDE_STOPPED_PACKAGES ,不让stop(如通过forcestop会设置)的三方app接收静态广播
- 根据是否粘性广播输出类似的日志:Broadcast (sticky) intent ordered=(true/false) userid=(userId)
- 解析BroadcastOptions brOptions广播可选参数
@GuardedBy("this")final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,@Nullable String callerFeatureId, Intent intent, String resolvedType,IIntentReceiver resultTo, int resultCode, String resultData,Bundle resultExtras, String[] requiredPermissions,String[] excludedPermissions, int appOp, Bundle bOptions,boolean ordered, boolean sticky, int callingPid, int callingUid,int realCallingUid, int realCallingPid, int userId,boolean allowBackgroundActivityStarts,@Nullable IBinder backgroundActivityStartsToken,@Nullable int[] broadcastAllowList) {intent = new Intent(intent);//调用者是否即时appfinal boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS//如果调用者是即时app,不能添加FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,可以让即时app接收的flagif (callerInstantApp) {intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);}// broadcastAllowList: 允许接收该广播uid的列表;一般包信息改变的时候才会传入,通过ContextImpl发送广播是不带这个参数的// broadcastAllowList目前只在PMS的doSendBroadcast发送package相关广播的时候才可能使用到// PackageManagerService.sendPackageBroadcast/sendMyPackageSuspendedOrUnsuspended->doSendBroadcast->// ActivityManagerService.LocalService.broadcastIntentif (userId == UserHandle.USER_ALL && broadcastAllowList != null) {Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "+ "Assuming restrictive whitelist.");broadcastAllowList = new int[]{};}// By default broadcasts do not go to stopped apps.//默认广播是不发送给stop的应用的,类似于安装后进程从未启动过,或者给强行停止的应用,//是无法通过接收静态注册的广播来启动的(具体在IntentResolver.java的buildResolveList会使用)intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);// If we have not finished booting, don't allow this to launch new processes.//mProcessesReady在systemReady的时候会设置为true//在系统没有启动完成的时候,而且广播发送没有带FLAG_RECEIVER_BOOT_UPGRADE的flagif (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {//则默认只能发送到动态注册的接收者中,静态注册的全部无法接收intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);}//DEBUG_BROADCAST_LIGHT这个是调试日志的开关,这里输出是否order有序广播if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent+ " ordered=" + ordered + " userid=" + userId);//如果是非ordered的广播,而且有resultTo则输出warning的信息//一般情况下orderd的广播才会设置resultTo(发送完成后返回完成的结果到发送者)if ((resultTo != null) && !ordered) {Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");}//多用户判断,如果是callingUid、userId同一个用户组,则直接返回userIduserId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,ALLOW_NON_FULL, "broadcast", callerPackage);// Make sure that the user who is receiving this broadcast or its parent is running.// If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.//如果userId不是发送到所有用户USER_ALL(-1),而且当前userId和它的父亲userId都没有在运行if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {//如果调用者不是系统或者没有设置FLAG_RECEIVER_BOOT_UPGRADE,而且不是关机广播,//则跳过本次广播发送,不允许stop的userId发送广播,原因是user已经stop了if ((callingUid != SYSTEM_UID|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {Slog.w(TAG, "Skipping broadcast of " + intent+ ": user " + userId + " and its parent (if any) are stopped");return ActivityManager.BROADCAST_FAILED_USER_STOPPED;}}//获取其意图的actionfinal String action = intent.getAction();BroadcastOptions brOptions = null;//是否有传入BroadcastOptions的Bundle,开机广播有传入bOptions,亮屏幕广播没有bOptionsif (bOptions != null) {//将Bundle转换成BroadcastOptions brOptionsbrOptions = new BroadcastOptions(bOptions);//如果mTemporaryAppAllowlistDuration的值大于0if (brOptions.getTemporaryAppAllowlistDuration() > 0) {// See if the caller is allowed to do this. Note we are checking against// the actual real caller (not whoever provided the operation as say a// PendingIntent), because that who is actually supplied the arguments.// 检查一下realCallingPid/realCallingUid是否拥有CHANGE_DEVICE_IDLE_TEMP_WHITELIST(修改临时白名单)、// START_ACTIVITIES_FROM_BACKGROUND(后台启动activity)、// START_FOREGROUND_SERVICES_FROM_BACKGROUND(后台启动前台服务)的权限,// 如果一个都没有,则不允许发送该广播,并抛出安全异常// (在部分情况下callingPid/callingUid调用该发送广播的调用者,// 于realCallingPid/realCallingUid真实调用者不是一样的)if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED&& checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED&& checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: " + intent.getAction()+ " broadcast from " + callerPackage + " (pid=" + callingPid+ ", uid=" + callingUid + ")"+ " requires "+ CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "+ START_ACTIVITIES_FROM_BACKGROUND + " or "+ START_FOREGROUND_SERVICES_FROM_BACKGROUND;Slog.w(TAG, msg);throw new SecurityException(msg);}}//如果带有mDontSendToRestrictedApps不发送给受限制的app// callingUid不在mActiveUids中,而且callingUid/callerPackage后台限制操作// 则由于“background restrictions”不允许发送广播if (brOptions.isDontSendToRestrictedApps()&& !isUidActiveLOSP(callingUid)&& isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage+ " has background restrictions");return ActivityManager.START_CANCELED;}//是否允许mAllowBackgroundActivityStarts后台启动activityif (brOptions.allowsBackgroundActivityStarts()) {// See if the caller is allowed to do this. Note we are checking against// the actual real caller (not whoever provided the operation as say a// PendingIntent), because that who is actually supplied the arguments.//如果没有START_ACTIVITIES_FROM_BACKGROUND则抛出权限异常if (checkComponentPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: " + intent.getAction()+ " broadcast from " + callerPackage + " (pid=" + callingPid+ ", uid=" + callingUid + ")"+ " requires "+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;Slog.w(TAG, msg);throw new SecurityException(msg);} else {//否者将allowBackgroundActivityStarts设置成true,允许后台启动activityallowBackgroundActivityStarts = true;// We set the token to null since if it wasn't for it we'd allow anyway herebackgroundActivityStartsToken = null;}}}
在AMS
的broadcastIntentLocked
方法中:
- 通过
Intent
去PKMS
和AMS.mReceiverResolver
变量查询到对应的广播接收器,其中变量receivers存储静态接收器,registeredReceivers变量存储动态接收器。 - 如果发送的是并行广播,则查看是否有对应的动态广播接收器,并创建一个拥有Intent和registeredReceivers的
BroadcastRecord
对象,并保存在BroadcastQueue.mParallelBroadcasts变量中,最终执行queue.scheduleBroadcastsLocked()
处理广播,并把registeredReceivers信息置null。 - 如果此时registeredReceivers不为null,说明发送的是串行广播,则把registeredReceivers合并到receivers变量,一起串行执行。
- 对receivers进行串行执行,创建一个拥有Intent和receivers的
BroadcastRecord
对象,并保存到队列的mOrderedBroadcasts变量中,最终执行queue.scheduleBroadcastsLocked()
处理广播。
3.4 BroadcastQueue处理广播
3.4.1 BroadcastQueue#scheduleBroadcastsLocked
/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
public void scheduleBroadcastsLocked() {if (mBroadcastsScheduled) {return;}// 发送BROADCAST_INTENT_MSG类型消息mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));mBroadcastsScheduled = true;}
3.4.2 BroadcastHandler处理消息
/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private final class BroadcastHandler extends Handler {public BroadcastHandler(Looper looper) {super(looper, null, true);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {// 执行此消息case BROADCAST_INTENT_MSG: {processNextBroadcast(true);}break;}}}
3.4.3 BroadcastQueue#processNextBroadcast
/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {synchronized (mService) {processNextBroadcastLocked(fromMsg, false);}}
3.4.4 BroadcastQueue#processNextBroadcastLocked
/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {BroadcastRecord r;//...//处理并行广播while (mParallelBroadcasts.size() > 0) {//把mParallelBroadcasts队列的BroadcastRecord执行完r = mParallelBroadcasts.remove(0);r.dispatchTime = SystemClock.uptimeMillis();r.dispatchClockTime = System.currentTimeMillis();// r.receivers就是AMS的registeredReceivers变量final int N = r.receivers.size();for (int i = 0; i < N; i++) {Object target = r.receivers.get(i);//分发广播给已注册的receiverdeliverToRegisteredReceiverLocked(r, (BroadcastFilter) target, false, i);}addBroadcastToHistoryLocked(r);}// 处理当前有序广播do {// 获取BroadcastRecordfinal long now = SystemClock.uptimeMillis();r = mDispatcher.getNextBroadcastLocked(now);//没有更多的广播等待处理if (r == null) {mDispatcher.scheduleDeferralCheckLocked(false);mService.scheduleAppGcsLocked();if (looped) {mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);}if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {mLogLatencyMetrics = false;}return;}boolean forceReceive = false;// 获取Receivers的大小int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;//当广播处理时间超时,则强制结束这条广播if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {if ((numReceivers > 0) &&(now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {broadcastTimeoutLocked(false); // forcibly finish this broadcastforceReceive = true;r.state = BroadcastRecord.IDLE;}}//...if (r.receivers == null || r.nextReceiver >= numReceivers|| r.resultAbort || forceReceive) {if (r.resultTo != null) {//...//处理广播消息消息,调用到onReceive()performReceiveLocked(r.callerApp, r.resultTo,new Intent(r.intent), r.resultCode,r.resultData, r.resultExtras, false, false, r.userId);//...}//...mDispatcher.retireBroadcastLocked(r);r = null;looped = true;continue;}//..} while (r == null);//获取下一个receiver的indexint recIdx = r.nextReceiver++;r.receiverTime = SystemClock.uptimeMillis();if (recIdx == 0) {r.dispatchTime = r.receiverTime;r.dispatchClockTime = System.currentTimeMillis();}if (!mPendingBroadcastTimeoutMessage) {long timeoutTime = r.receiverTime + mTimeoutPeriod;//设置广播超时时间,发送BROADCAST_TIMEOUT_MSGsetBroadcastTimeoutLocked(timeoutTime);}final BroadcastOptions brOptions = r.options;//获取下一个广播接收者final Object nextReceiver = r.receivers.get(recIdx);if (nextReceiver instanceof BroadcastFilter) {//对于动态注册的广播接收者,deliverToRegisteredReceiverLocked处理广播BroadcastFilter filter = (BroadcastFilter) nextReceiver;deliverToRegisteredReceiverLocked(r, filter, r.ordered);if (r.receiver == null || !r.ordered) {r.state = BroadcastRecord.IDLE;scheduleBroadcastsLocked();} else {...}return;}//对于静态注册的广播接收者ResolveInfo info = (ResolveInfo) nextReceiver;ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName,info.activityInfo.name);...//执行各种权限检测,此处省略,当权限不满足时skip=trueif (skip) {r.receiver = null;r.curFilter = null;r.state = BroadcastRecord.IDLE;scheduleBroadcastsLocked();return;}r.state = BroadcastRecord.APP_RECEIVE;String targetProcess = info.activityInfo.processName;r.curComponent = component;final int receiverUid = info.activityInfo.applicationInfo.uid;if (r.callingUid != Process.SYSTEM_UID && isSingleton&& mService.isValidSingletonCall(r.callingUid, receiverUid)) {info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);}r.curReceiver = info.activityInfo;...//Broadcast正在执行中,stopped状态设置成falseAppGlobals.getPackageManager().setPackageStoppedState(r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));//该receiver所对应的进程已经运行,则直接处理ProcessRecord app = mService.getProcessRecordLocked(targetProcess,info.activityInfo.applicationInfo.uid, false);if (app != null && app.thread != null) {try {app.addPackage(info.activityInfo.packageName,info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);processCurBroadcastLocked(r, app);return;} catch (RemoteException e) {} catch (RuntimeException e) {finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false);scheduleBroadcastsLocked();r.state = BroadcastRecord.IDLE; //启动receiver失败则重置状态return;}}//该receiver所对应的进程尚未启动,则创建该进程if ((r.curApp=mService.startProcessLocked(targetProcess,info.activityInfo.applicationInfo, true,r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,"broadcast", r.curComponent,(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))== null) {//创建失败,则结束该receiverfinishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);scheduleBroadcastsLocked();r.state = BroadcastRecord.IDLE;return;}mPendingBroadcast = r;mPendingBroadcastRecvIndex = recIdx;//...}
3.4.5 BroadcastQueue#deliverToRegisteredReceiverLocked
/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,BroadcastFilter filter, boolean ordered, int index) {//...// 调用performReceiveLocked方法performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,new Intent(r.intent), r.resultCode, r.resultData,r.resultExtras, r.ordered, r.initialSticky, r.userId);//...}
3.4.6 BroadcastQueue#performReceiveLocked
/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,Intent intent, int resultCode, String data, Bundle extras,boolean ordered, boolean sticky, int sendingUser)throws RemoteException {if (app != null) {// 如果ProcessRecord != null,且ApplicationThread不为空if (app.thread != null) {try {// 调用ApplicationThread.scheduleRegisteredReceiverapp.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.getReportedProcState());} catch (RemoteException ex) {synchronized (mService) {app.scheduleCrash("can't deliver broadcast");}throw ex;}} else {// Application has died. Receiver doesn't exist.throw new RemoteException("app.thread must not be null");}} else {// 如果ProcessRecord为空receiver.performReceive(intent, resultCode, data, extras, ordered,sticky, sendingUser);}}
BroadcastQueue就是将队列中列表拿出来执行,最后调用app.thread.scheduleRegisteredReceiver
对广播进行回调。
3.5 回调广播
3.5.1 ActivityThread#ApplicationThread#scheduleRegisteredReceiver
/frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,int resultCode, String dataStr, Bundle extras, boolean ordered,boolean sticky, int sendingUser, int processState) throws RemoteException {updateProcessState(processState, false);// 调用IntentReceiver的performReceive方法receiver.performReceive(intent, resultCode, dataStr, extras, ordered,sticky, sendingUser);}}
3.5.2 LoadedApk#performReceive
/frameworks/base/core/java/android/app/LoadedApk.java
static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {final WeakReference<ReceiverDispatcher> mDispatcher;final LoadedApk.ReceiverDispatcher mStrongRef;InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);mStrongRef = strong ? rd : null;}@Overridepublic void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser) {final LoadedApk.ReceiverDispatcher rd;//...if (rd != null) {// 调用ReceiverDispatcher的performReceive方法rd.performReceive(intent, resultCode, data, extras,ordered, sticky, sendingUser);}//...}}// ReceiverDispatcher的performReceive方法public void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser) {final Args args = new Args(intent, resultCode, data, extras, ordered,sticky, sendingUser);//...// 通过Handler执行args的Runnableif (intent == null || !mActivityThread.post(args.getRunnable())) {if (mRegistered && ordered) {IActivityManager mgr = ActivityManager.getService();args.sendFinished(mgr);}}}
3.5.3 LoadedApk#Args#getRunnable
/frameworks/base/core/java/android/app/LoadedApk.java
final class Args extends BroadcastReceiver.PendingResult {public final Runnable getRunnable() {return () -> {final BroadcastReceiver receiver = mReceiver;//...try {ClassLoader cl = mReceiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess();setExtrasClassLoader(cl);receiver.setPendingResult(this);// 调用BroadcastReceiver的onReceive方法receiver.onReceive(mContext, intent);} catch (Exception e) {//...}if (receiver.getPendingResult() != null) {finish();}};}}
3.5.4 BroadcastReceiver#onReceive
/frameworks/base/core/java/android/content/BroadcastReceiver.java
3.6 广播ANR
只有“串行”广播才会发生 ANR,因为它要等待 receiver 的处理结果。
根据前面分析,“串行”广播发送给 receiver 前,会发送一个超时消息,如下:
// BroadcastQueue.javaif (! mPendingBroadcastTimeoutMessage) {long timeoutTime = r.receiverTime + mConstants.TIMEOUT;setBroadcastTimeoutLocked(timeoutTime);
}
当这个消息被执行的时候,会调用如下代码:
// BroadcastQueue.javafinal void broadcastTimeoutLocked(boolean fromMsg) {if (fromMsg) {mPendingBroadcastTimeoutMessage = false;}if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {return;}long now = SystemClock.uptimeMillis();// 获取当前正在处理的广播BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();if (fromMsg) {// 系统还没有就绪if (!mService.mProcessesReady) {return;}// 广播超时被豁免if (r.timeoutExempt) {if (DEBUG_BROADCAST) {Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: "+ r.intent.getAction());}return;}// 1. 广播没有超时long timeoutTime = r.receiverTime + mConstants.TIMEOUT;if (timeoutTime > now) {// 发送下一个超时消息setBroadcastTimeoutLocked(timeoutTime);return;}}if (r.state == BroadcastRecord.WAITING_SERVICES) {// ...return;}// 2. 走到这里,表示广播超时,触发 ANRfinal boolean debugging = (r.curApp != null && r.curApp.isDebugging());r.receiverTime = now;if (!debugging) {r.anrCount++;}ProcessRecord app = null;String anrMessage = null;Object curReceiver;if (r.nextReceiver > 0) {curReceiver = r.receivers.get(r.nextReceiver-1);r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;} else {curReceiver = r.curReceiver;}logBroadcastReceiverDiscardLocked(r);// 获取 receiver 进程if (curReceiver != null && curReceiver instanceof BroadcastFilter) {BroadcastFilter bf = (BroadcastFilter)curReceiver;if (bf.receiverList.pid != 0&& bf.receiverList.pid != ActivityManagerService.MY_PID) {synchronized (mService.mPidsSelfLocked) {app = mService.mPidsSelfLocked.get(bf.receiverList.pid);}}} else {app = r.curApp;}if (app != null) {anrMessage = "Broadcast of " + r.intent.toString();}if (mPendingBroadcast == r) {mPendingBroadcast = null;}// 强制结束当前广播的发送流程finishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);// 调度下一次的广播发送scheduleBroadcastsLocked();// app 不处于 debug 模式,引发 ANRif (!debugging && anrMessage != null) {mService.mAnrHelper.appNotResponding(app, anrMessage);}
}
第2步,引发 ANR ,很简单,就是因为整个发送与反馈过程超时了。
而第1步,就是处理不超时的情况。这里大家是不是很疑惑,移除超时消息不是在接收到广播反馈后进行的吗? 我可以负责地告诉你,并不是!那这里第1步怎么理解呢?
首先这个超时消息一定触发,但是触发这个超时消息,并不代表一定会引发 ANR。
假如当前 receiver 的广播处理流程,在超时时间之前就完成了,那么 AMS 会调度广播发送给下一个 receiver。
于是,针对下一个 receiver ,会更新 r.receiverTime,那么第一步此时计算出来的 timeoutTime 是下一个 receiver 的广播超时时间,很显然是大于 now 的,于是就不会走第2步的 ANR 流程。
最后利用这个 timeoutTime,为下一个 receiver 再发送一个超时消息,简直是完美!
广播接收器是在主线程中运行的,不要执行耗时任务,或者潜在耗时的任务,我在工作中看到了无数血与泪的案例。
3.7 小结
1、广播为啥会阻塞呢?发送给接收器就行了,为啥还要等着接收器处理完才处理下一个?
从上面的源码分析可知,广播的处理分为并行和有序两个队列,出问题的无序广播静态接收器放在了有序处理列表中,而有序处理列表的执行是串行的,只有前面的执行完,才会轮到下一个处理,所以前面的广播如果在onReceive中有耗时操作,后面的广播就会堵塞。
2、 由普通的后台广播改为前台广播后,为啥处理的会更快?
在上面源码中有个变量的注释:mTimeoutPeriod。这个变量初始化是在BroadcastQueue初始化的时候传入的,也就是在AMS(AMS构造函数中)中初始化mFgBroadcastQueue和mBgBroadcastQueue时传入的,前台广播的超时时间是10s,后台的超时时间是60s。 也会出现一种问题,就是产生发生ANR的时间段时间不一样.
BROADCAST_FG_TIMEOUT = 10 * 1000
BROADCAST_BG_TIMEOUT = 60 * 1000
后台广播的设计思想就是当前应用优先,尽可能多让收到广播的应用有充足的时间把事件做完。
而前台广播的目的是紧急通知,设计上就倾向于当前应用赶快处理完,尽快传给下一个。
也就是说在设计上前台广播主要用于响应性能较高的场景,因为ANR时间是10s,所以开发设计的时候应该尽可能少用。因为前台广播使用的比较少,所以队列相对空闲,响应速度快。
3、对照源码分析总结:
(1) 前后台队列都有自己并行和有序广播队列,互相不影响;
(2) 并行队列里是无序广播+动态注册接收者;
(3) 有序队列里是有序广播+动态接收者和静态接收者,静态接收者默认就是有序的;
(4) 有序广播+动态接收者执行优于静态接收者先执行,综合起来就是广播相同的情况下,动态接收器优于静态接收器;
(5) Android版本高的,很多系统广播只支持动态注册,静态注册的话收不到广播,例如:息屏亮屏广播。因为静态注册的话,发广播的时候会把所有注册未启动的app全部拉起来,静态处理器又默认串行处理,增加了广播的处理时间。
附:
1. instant app :谷歌推出的类似于微信小程序(或者说小程序类似于instant app)的一项技术,用户无须安装应用,用完就走,同时兼备h5的便捷和原生应用的优质体验。