Android R 广播注册与发送流程分析

静态广播注册时序图

动态广播注册时序图

发送广播时序图

前言

广播接收器可以分为动态和静态,静态广播接收器就是在 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 小结

  1. AndroidManifest.xml中的receiver解析成ParsedActivity, 存放在PackageImpl的receivers(PackageImpl父类是ParsingPackageImpl而且实现了AndroidPackage接口)
  2. receivers最终会存放在mComponentResolver(PMS)的mReceivers中,mReceivers包含了所有安装应用的receiver,通过ComponentName就可以获得相应的ParsedActivity,如:mReceivers.mActivities.get(new ComponentName(“com.example.myapplication”, “com.example.myapplication.MyReceiver”)),既可以获得MyReceiver的ParsedActivity
  3. receiver中的一个IntentFilter(intent-filter)对应一个ParsedIntentInfo,一个Pair<ParsedActivity, ParsedIntentInfo>
  4. Pair<ParsedActivity, ParsedIntentInfo>被放入mComponentResolver的mFilters
  5. mActions被放入mComponentResolver的mActionToFilter
  6. 部分静态广播注册需要权限,不是注册了就能收到。其实要接收广播还:涉及权限、进程优先级、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 小结

服务端对于动态注册的广播接收器的处理过程如下

  1. 使用 mRegisteredReceivers 建立客户端与服务端的广播接收器的映射。ReceiverList 代表服务端的广播接收器,IIntentReceiver 代表客户端的广播接收器。
  2. 使用客户端的 IntentFilter , 创建服务端的广播过滤器 BroadcastFilter,并保存到 mReceiverResolver。注意,这一步中,ReceiverList 和 BroadcastFilter 互相保存了引用。

这些数据结构都是相互关联的,有何种用意呢?当发送方发送广播到 AMS,AMS 会使用 mReceiverResolver 匹配 BroadcastFilter,BroadcastFilter 找到 ReceiverList,ReceiverList 找到 IIntentReceiver,IIntentReceiver 发送广播给接收方。

另外,由于 sticky 广播是会被缓存的,当注册 sticky 广播的接收器时,有以下两种处理方式

  1. 如果注册的广播接收器为 null,那么会返回最近的一次广播数据给接收方。
  2. 如果注册的广播接收器不为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

  1.  如默认会增加 FLAG_EXCLUDE_STOPPED_PACKAGES ,不让stop(如通过forcestop会设置)的三方app接收静态广播
  2. 根据是否粘性广播输出类似的日志:Broadcast (sticky) intent ordered=(true/false) userid=(userId)
  3. 解析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;}}}

 在AMSbroadcastIntentLocked方法中:

  • 通过IntentPKMSAMS.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构造函数中)中初始化mFgBroadcastQueuemBgBroadcastQueue时传入的,前台广播的超时时间是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的便捷和原生应用的优质体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2906449.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

2020年天津市二级分类土地利用数据(矢量)

天津市&#xff0c;位于华北平原海河五大支流汇流处&#xff0c;东临渤海&#xff0c;北依燕山。地势以平原和洼地为主&#xff0c;北部有低山丘陵&#xff0c;海拔由北向南逐渐下降&#xff0c;地貌总轮廓为西北高而东南低。天津有山地、丘陵和平原三种地形&#xff0c;平原约…

深夜变电站三维可视化:电力之心的全新解读

在寂静的深夜&#xff0c;城市的灯火依旧璀璨夺目&#xff0c;而在这背后&#xff0c;有一个不为人知的守护者正在默默工作——那就是变电站。如今&#xff0c;随着科技的飞速发展&#xff0c;我们有了更直观、更生动的方式来了解这个神秘的电力枢纽——三维可视化技术。 深夜变…

前端超分辨率技术应用:图像质量提升与场景实践探索-设计篇

超分辨率&#xff01; 引言 在数字化时代&#xff0c;图像质量对于用户体验的重要性不言而喻。随着显示技术的飞速发展&#xff0c;尤其是移动终端视网膜屏幕的广泛应用&#xff0c;用户对高分辨率、高质量图像的需求日益增长。然而&#xff0c;受限于网络流量、存储空间和图像…

如何在Win10使用IIS服务搭建WebDAV网站并实现无公网IP访问内网文件内容

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透&#xff0c;将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav&#xff0c;并且结合cpolar的内网穿透工具实现在公网访…

com.alibaba.boot.nacos.config.binder.NacosBootConfigurationPropertiesBinder解决记录

一直正常的服务突然启动失败了&#xff0c;控制台报错 查询后发现是spring-boot-starter版本2.4和nacos-config 0.2.8版本冲突了 于是看了下nacos-config版本&#xff0c;发现有两个如下 但是原来启动正常&#xff0c;看了下老版本代码发现nacos-config-springboot-autoconfig…

接口自动化测试——文件上传/下载

简介&#xff1a; 轻松搞定文件上传接口和文件下载接口。 我们在做接口自动化测试的时候&#xff0c;经常会碰到文件上传接口和文件下载接口。 那么&#xff0c;文件接口跟普通接口有什么区别呢&#xff1f;又该如何实现呢&#xff1f; 〇、前言 文件上传/下载接口与普通接…

怎么让ChatGPT批量写作原创文章

随着人工智能技术的不断发展&#xff0c;自然语言处理模型在文本生成领域的应用也日益广泛。ChatGPT作为其中的佼佼者之一&#xff0c;凭借其强大的文本生成能力和智能对话特性&#xff0c;为用户提供了一种高效、便捷的批量产出内容的解决方案。以下将就ChatGPT批量写作内容进…

colmap 【Feature matching】特征匹配参数解释

&#xff08;Windows&#xff09;Colmap 具体使用教程可参考我的这篇博文 下面只是matching参数解释 Matching这个阶段很重要&#xff0c;匹配方式不同会对最终结果影响很大&#xff0c;要根据实际情况选择合适的匹配方式。下面是各个参数的详细解释。 1.Exhaustive——官方文…

OSPF---开放式最短路径优先协议

1. OSPF描述 OSPF协议是一种链路状态协议。每个路由器负责发现、维护与邻居的关系&#xff0c;并将已知的邻居列表和链路费用LSU报文描述&#xff0c;通过可靠的泛洪与自治系统AS内的其他路由器周期性交互&#xff0c;学习到整个自治系统的网络拓扑结构;并通过自治系统边界的路…

URL编码:原理、应用与安全性

title: URL编码&#xff1a;原理、应用与安全性 date: 2024/3/29 18:32:42 updated: 2024/3/29 18:32:42 tags: URL编码百分号编码特殊字符处理网络安全应用场景标准演变未来发展 在网络世界中&#xff0c;URL&#xff08;统一资源定位符&#xff09;是我们访问网页、发送请求…

day69实现MyBatis 的Mapper接口 封装SqlSession对象 mapper接口形参怎么给占位符赋值

一 创建项目的准备工作 1 添加jar包 MySql.jar .MyBatis.jar 2 在src中配置MyBatis.xml文件 二 封装SqlSession对象 1 SqlSessionFactoryBuilder 生命周期 这个类可以被实例化,使用和丢弃。一旦你创建了 SqlSessionFactory 后…

九河云荣获“华为2024·亚太区年度杰出合作伙伴奖”

2024年3月26日~27日&#xff0c;以“加速智能化&#xff0c;一切皆服务”为主题的华为亚太生态伙伴大会在东莞隆重开幕&#xff0c;九河云作为专业的多云管理服务商&#xff0c;凭借多年来在云领域的赋能发展应邀出席并荣获“亚太区年度杰出伙伴奖”&#xff0c;这不仅彰显了九…

为什么要学Python?Python的优势在哪?

人生苦短&#xff0c;我用 Python 不知道从什么时候开始流行这句话 Python 是个什么神仙编程语言 为啥全世界都在鼓励孩子学 Python 简单容易上手 国内、国际的竞赛机会多&#xff0c;含金量足 Python 好就业、薪资高 下面且看详细分析 01 什么是Python / 科技编程老师…

MYSQL8.0安装、配置、启动、登入与卸载详细步骤总结

文章目录 一.下载安装包1.方式一.官网下载方式二.网盘下载 二.解压安装三.配置1.添加环境变量 三.验证安装与配置成功四.初始化MYSQL五.注册MySQL服务六.启动与停止MYSQL服务七.修改账户默认密码八.登入MySQL九.卸载MySQL补充&#xff1a;彻底粉碎删除Mysql 一.下载安装包 1.方…

A Little Is Enough: Circumventing Defenses For Distributed Learning

联邦学习的攻击方法&#xff1a;LIE 简单的总结&#xff0c;只是为了能快速想起来这个方法。 无目标攻击 例如总共50个客户端&#xff0c;有24个恶意客户端&#xff0c;那么这个时候&#xff0c;他需要拉拢2个良性客户端 计算 50 − 24 − 2 50 − 24 0.923 \frac{50-24-2}{…

rust使用Command库调用cmd命令或者shell命令,并支持多个参数和指定文件夹目录

想要在不同的平台上运行flutter doctor命令&#xff0c;就需要知道对应的平台是windows还是linux&#xff0c;如果是windows就需要调用cmd命令&#xff0c;如果是linux平台&#xff0c;就需要调用sh命令&#xff0c;所以可以通过cfg!实现不同平台的判断&#xff0c;然后调用不同…

【python】深入探讨flask是如何预防CSRF攻击的

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【C++杂货铺】内管管理

目录 &#x1f308;前言&#x1f308; &#x1f4c1; C/C中内存分布 &#x1f4c1; new 和 delete的使用 &#x1f4c1; new 和 delete的优点 &#x1f4c1; new 和 delete的原理 &#x1f4c2; operator new 和 operator delete函数 &#x1f4c2; 内置类型 &#x1f4c2…

对iOS的内存存储的一些理解

最近写项目的时候遇到了一些内存上的问题&#xff08;比如内存泄漏等等&#xff09;&#xff0c;通过网上的方法解决后&#xff0c;好奇iOS的数据是如何存储的&#xff0c;特记于此。 一、iOS的内存区域 iOS 中应用程序使用的计算机内存不是统一分配空间&#xff0c;运行代码使…

Javascript — 异步方法与异常捕获问题

问题&#xff1a;try catch为什么不能捕获未被 await 修饰的异步方法异常 async function throwError() {throw new Error("自定义Error&#xff01;") }let testOne async () > {console.debug("start testOne")try {throwError()} catch (e) {conso…