锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Android S广播发送流程(广播3)

时间:2022-10-28 02:00:00 贴片二极管丝印f17

Android S广播发送过程

  • 1. 广播发送过程
  • 2. 广播发送
  • 3. 系统处理广播发送
    • 3.1 AMS接收广播请求
    • 3.2 修改增加默认flag可选广播参数分析BroadcastOptions
    • 3.4 保护广播isProtectedBroadcast、特定action的处理
    • 3.5 处理粘性广播
    • 3.6 筛选出静态广播接受者
    • 3.7 筛选出动态广播接受者
    • 3.8 非oder平行广播的入队和分发
    • 3.8 order过滤广播接收者
  • 4. 处理广播队列
    • 4.1 新的广播队列
    • 4.2 广播接收者进入队列
    • 4.3 广播队列的分发
    • 4.4 下一个广播广播的分发
      • 4.4.1 mParallelBroadcasts平行广播的分发
      • 4.4.2 mPendingBroadcast挂广播处理
      • 4.4.3 在下一个有序队列中取出广播
      • 4.4.4 处理下一个接收者nextReceiver
      • 4.4.5 发送给动态注册order注册者
      • 4.4.6 静态注册者跳过的逻辑
      • 4.4.7 发送给已启动的静态注册人
      • 4.4.8 静态注册接收人启动过程
    • 4.5 完成广播接收者处理
      • 4.5.1 广播完成后,始下一个广播的调度
      • 4.5.2 广播完成finishReceiverLocked
  • 5. 扩展使用广播

1. 广播发送过程

这一次,我们来谈谈广播发送的过程。老规矩先上流程图
在这里插入图片描述

2. 广播发送

  1. 常见的通过ContextImpl.java发送广播的方法有以下几种
    => sendBroadcast/sendBroadcastAsUser :普通广播发送,默认是目前userId,带有“AsUser它是发送给特定的user
    => sendBroadcastMultiplePermissions/sendBroadcastAsUserMultiplePermissions :有多个权限的广播发送
    => sendOrderedBroadcast/sendOrderedBroadcastAsUser :发送order有序的广播(order广播是一个接收完成下一个接收,接收者按顺序接收)
    => sendStickyBroadcast/sendStickyBroadcastAsUser :发送粘性广播,粘性广播是指注册人注册后可立即收到该类型(以前发送的粘性广播)的广播,
    接收人的注册不需要在发送人面前
    => sendStickyOrderedBroadcast/sendStickyOrderedBroadcastAsUser :发送粘性和顺序order的广播

都是调用AMS的broadcastIntentWithFeature来发送广播

以下是最简单的,只有一个Intent的广播发送

//ContextImpl.java     @Override     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, nll, null, null, null /*excludedPermissions=*/,
                    AppOpsManager.OP_NONE, null, false, false, getUserId());
        } catch (RemoteException e) { 
        
            throw e.rethrowFromSystemServer();
        }
    }
  1. 还是以亮屏SCREEN_ON的广播继续讲解其发送流程
    其调用方法是sendOrderedBroadcastAsUser(ContextImpl.java)->broadcastIntentWithFeature(ActivityManagerService.java)
//Notifier.java
    private final Intent mScreenOnIntent;
	//新建一个Intent,它的action是ACTION_SCREEN_ON,
	//注意此处增加了
	//FLAG_RECEIVER_REGISTERED_ONLY: 只允许动态注册的接收者接受
	//FLAG_RECEIVER_FOREGROUND: 前台接收,也就是前台广播(10s超时)的队列
	//FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS: 可以被即时app接收
	mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
	mScreenOnIntent.addFlags(
			Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
			| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);

    //亮屏广播发送完成后才调用的
    private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() { 
        
        @Override
        public void onReceive(Context context, Intent intent) { 
        
            //开始发送广播之前会打印类似“power_screen_broadcast_send: 1”的日志
            //这里会在event log中打印类似“power_screen_broadcast_done: [1,125,1]“的日志
			//里面包含了发送亮屏广播的时间,此处是“125 ms”
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
            sendNextBroadcast();
        }
    };

   private void sendWakeUpBroadcast() { 
        
        if (DEBUG) { 
        
            Slog.d(TAG, "Sending wake up broadcast.");
        }

        if (mActivityManagerInternal.isSystemReady()) { 
        
            //调用的是ContextImpl的sendOrderedBroadcastAsUser去发送广播
			//mScreenOnIntent是发送的亮屏广播
			//mHandler是PowerManagerService.java的主线程,用来运行mWakeUpBroadcastDone
			//mWakeUpBroadcastDone是亮屏广播发送完成后
            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                    mWakeUpBroadcastDone, mHandler, 0, null, null);
        } else { 
        
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
            sendNextBroadcast();
        }
    }

//ContextImpl.java
    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
            int initialCode, String initialData, Bundle initialExtras) { 
        
		//多带了appOp=OP_NONE、options=null的参数
        sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
                null, resultReceiver, scheduler, initialCode, initialData, initialExtras);
    }

    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { 
        
        IIntentReceiver rd = null;
        if (resultReceiver != null) { 
        
            if (mPackageInfo != null) { 
        
                if (scheduler == null) { 
        
                    //由于传入了scheduler(mHandler),所以这里是不会进来的
                    scheduler = mMainThread.getHandler();
                }
				//进入的是这里获取IIntentReceiver rd(通过mPackageInfo、resultReceiver、scheduler构建)
                rd = mPackageInfo.getReceiverDispatcher(
                    resultReceiver, getOuterContext(), scheduler,
                    mMainThread.getInstrumentation(), false);
            } else { 
        
                if (scheduler == null) { 
        
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
                        scheduler, null, false).getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        String[] receiverPermissions = receiverPermission == null ? null
                : new String[] { 
        receiverPermission};
        try { 
        
            intent.prepareToLeaveProcess(this);
			//实际是调用的AMS的broadcastIntentWithFeature方法
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    rd, initialCode, initialData, initialExtras, receiverPermissions,
                    null /*excludedPermissions=*/, appOp, options, true, false,
                    user.getIdentifier());
        } catch (RemoteException e) { 
        
            throw e.rethrowFromSystemServer();
        }
    }

3. 系统处理广播发送

3.1 AMS接收广播的请求

系统AMS通过broadcastIntentWithFeature接收广播的请求

//ActivityManagerService.java
    //从context过来的都走的这个broadcastIntentWithFeature方法,带特性的发送广播
    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 callerApp
            final 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);
            }
        }
    }

    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, 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) { 
        
        //这里再次增加了3个参数allowBackgroundActivityStarts=false,tokenNeededForBackgroundActivityStarts=false
		//broadcastAllowList=null
        return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
                resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
                excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
                realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
                null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
    }

3.2 修改增加默认flag解析可选广播参数BroadcastOptions

  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);
        //调用者是否即时app
        final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
        // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
        //如果调用者是即时app,不能添加FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,可以让即时app接收的flag
        if (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.broadcastIntent
        if (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的flag
        if (!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同一个用户组,则直接返回userId
        userId = 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;
            }
        }

        //获取其意图的action
        final String action = intent.getAction();
        BroadcastOptions brOptions = null;
        //是否有传入BroadcastOptions的Bundle,开机广播有传入bOptions,亮屏幕广播没有bOptions
        if (bOptions != null) { 
        
            //将Bundle转换成BroadcastOptions brOptions
            brOptions = new BroadcastOptions(bOptions);
            //如果mTemporaryAppAllowlistDuration的值大于0
            if (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后台启动activity
            if (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);
                    thr
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章