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://www.rhkb.cn/news/290857.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FANUC机器人故障诊断—报警代码(一)

一、SRVO-050碰撞检测报警 [原因]检测出碰撞 [对策] 1.确认机器人是否碰撞。 2.确认是否正确进行了负载设定。 3.确认是否有过载、过度的加速度附加指令。 4.在长期停用后启动&#xff0c;或者外部气温较低时发生该报警。启动后&#xff0c;先短时间内低速运转设备&#…

uniapp开发App——登陆流程 判断是否登陆,是,进入首页,否,跳转到登录页

一、登陆流程 文字描述&#xff1a;用户进入App&#xff0c;之后就是判断该App是否有用户登陆过&#xff0c;如果有&#xff0c;直接进入首页&#xff0c;否则跳转到登陆页&#xff0c;登陆成功后&#xff0c;进入首页。 流程图如下&#xff1a; 二、在uniapp项目中代码实现 实…

google浏览器网站不安全与网站的连接不安全怎么办?

使用google谷歌浏览器访问某些网站打开时google谷歌浏览器提示网站不安全,与网站的连接不安全,您之所以会看到此警告,是因为该网站不支持https造成的怎么办? 目录 1、打开谷歌google浏览器点击右上角【┇】找到设置

React Native框架开发APP,安装免费的图标库(react-native-vector-icons)并使用详解

一、安装图标库 要使用免费的图标库&#xff0c;你可以使用 React Native Vector Icons 库。 首先&#xff0c;确保你已经安装了 react-native-vector-icons&#xff1a; npm install --save react-native-vector-iconsnpm install --save-dev types/react-native-vector-ic…

vue3使用vuedraggable实现拖拽(有过渡)

1. 安装与使用 vue中vuedraggable安装&#xff1a; pnpm i -S vuedraggablenext或者 yarn add vuedraggablenext注意&#xff1a;vue2和vue3安装的是不同版本的vuedraggable&#xff0c;写法上也会有一些区别。 比如在vue3中使用拖拽&#xff0c;要以插槽的方式&#xff0c;…

从 Azure 部署生成本地 .NET 密钥

作者&#xff1a;Frank Boucher 排版&#xff1a;Alan Wang 通常&#xff0c;示例项目以一些“魔术字符串”开始&#xff0c;这些变量包含与部署或外部资源相关的 URL 和关键信息&#xff0c;我们必须更改这些信息才能使用示例。例如在 .NET 中&#xff0c;它可能如下所示&…

使用vue2实现在线创建组件的功能

前言 我们使用vue2构建了一个项目&#xff0c;项目有个需求&#xff1a;用户可以在线创建vue组件&#xff0c;创建后的组件可以动态编译&#xff0c;项目无需重新部署&#xff0c;就可以在表单等位置引入使用组件。 实现记录 引用vue的esm包 项目中引入vue的代码&#xff0…

【Roadmap to learn LLM】Large Language Models in Five Formulas

by Alexander Rush Our hope: reasoning about LLMs Our Issue 文章目录 Perpexity(Generation)Attention(Memory)GEMM(Efficiency)用矩阵乘法说明GPU的工作原理 Chinchilla(Scaling)RASP(Reasoning)结论参考资料 the five formulas perpexity —— generationattention —— m…

电脑分辨率怎么调,电脑分辨率怎么调整

随着电脑的普及以及网络的发展&#xff0c;我们现在在工作中都离不开对电脑的使用&#xff0c;今天小编教大家设置电脑分辨率&#xff0c;现在我们先了解这个分辨率是什么?通常电脑的显示分辨率就是屏幕分辨率&#xff0c;显示屏大小固定时&#xff0c;显示分辨率越高图像越清…

数据可视化为什么能在智慧港口中发挥作用?

随着全球贸易活动日益频繁&#xff0c;港口作为国际贸易的重要节点&#xff0c;其运营效率与智能化程度直接影响着整个物流链的效能。在此背景下&#xff0c;智慧港口的概念应运而生&#xff0c;它借助先进的信息技术手段对传统港口进行改造升级&#xff0c;其中&#xff0c;数…

【AIGC】如何在Windows/Linux上部署stable diffusion

文章目录 整体安装步骤windows10安装stable diffusion环境要求安装步骤注意事项参考博客其他事项安装显卡驱动安装cuda卸载cuda安装对应版本pytorch安装git上的python包Q&A linux安装stable diffusion安装anaconda安装cudagit 加速配置虚拟环境挂载oss&#xff08;optional…

Spring Aop 源码解析(下)

ProxyFactory选择cglib或jdk动态代理原理 ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术: config就是ProxyFactory对象,把自己传进来了,因为ProxyFactory继承了很多类,其中一个父类就是ProxyConfig // config就是ProxyFactory对象// 是不是…

02正式学习第一天

1、windows上加载socket库 链接输入ws2_32.lib 代码code&#xff1a; #ifdef _WIN32 #include<windows.h> #else #include <sys/socket.h> #include<sys/types.h> #include<unistd.h> #include<cstring> #include<arpa/inet.h> #include…

【Java】LinkedList模拟实现

目录 整体框架IMyLinkedList接口IndexNotLegalException异常类MyLinkedList类成员变量(节点信息)addFirst(头插)addLast(尾插)在指定位置插入数据判断是否存在移除第一个相等的节点移除所有相等的节点链表的长度打印链表释放回收链表 整体框架 IMyLinkedList接口 这个接口用来…

WPF 路由事件 数据驱动 、Window 事件驱动

消息层层传递&#xff0c;遇到安装有事件侦听器的对象&#xff0c;通过事件处理器响应事件&#xff0c;并决定事件是否继续传递&#xff1b; 后置代码中使用AddHandler方法设置事件监听器&#xff0c;该方法的 第一个参数是指定监听的路由事件类型对象&#xff0c; 第二个参数…

微服务demo(四)nacosfeigngateway

一、gateway使用&#xff1a; 1、集成方法 1.1、pom依赖&#xff1a; 建议&#xff1a;gateway模块的pom不要去继承父工程的pom&#xff0c;父工程的pom依赖太多&#xff0c;极大可能会导致运行报错&#xff0c;新建gateway子工程后&#xff0c;pom父类就采用默认的spring-b…

CSS之动画

一&#xff0c;动画的制作 实现盒子绕圈走 二&#xff0c; 动画的常用属性 三&#xff0c;动画简写属性 前面两个属性一定要写&#xff0c;第三个linear是指匀速的意思&#xff08;默认是ease&#xff09;

【快速解决】解决谷歌自动更新的问题,禁止谷歌自动更新,如何防止chrome自动升级 chrome浏览器禁止自动升级设置方法

目录 问题描述 解决方法 1、搜索栏搜索控制面板 2、搜索&#xff1a;服务 ​编辑 3、点击Windows工具 4、点击服务 ​5、禁止谷歌更新 问题描述 由于我现在需要装一个谷歌的驱动系统&#xff0c;但是目前的谷歌驱动系统的版本都太旧了&#xff0c;谷歌自身的版本又太新了…

手写简易操作系统(十五)--实现内核线程

前情提要 前面我们实现了内存管理系统&#xff0c;内存管理系统可以实现进程与进程之间的隔离。 Linux中高1GB是操作系统内核的地址&#xff0c;低3GB是用户的地址&#xff0c;高1GB对于所有用户都是一致的&#xff0c;低3GB才是用户自己的自留地。 既然已经实现了内存管理&…

[flink 实时流基础] flink组件栈以及任务执行与资源划分

文章目录 7. Flink组件栈1. 部署层&#xff08;1&#xff09;Local模式&#xff08;2&#xff09;Cluster模式&#xff08;3&#xff09;Cloud模式 2.运行时3.API层4. 上层工具 8. 任务执行与资源划分1. 再谈逻辑视图到物理执行图2. 任务、算子子任务与算子链3. Slot与计算资源…