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

本文深入解析了Android系统中广播发送的详细流程,包括广播的发送方式、系统处理过程、广播队列管理及接收者处理逻辑。涉及广播类型如普通、有序、粘性广播及其发送方法,以及AMS如何调度和分发广播给静态与动态注册的接收者。

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, null, 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);
                    throw new SecurityException(msg);
                } else {
   
   
                    //否者将allowBackgroundActivityStarts设置成true,允许后台启动activity
                    allowBackgroundActivityStarts = true;
                    // We set the token to null since if it wasn't for it we'd allow anyway here
                    backgroundActivityStartsToken = null;
                }
            }
        }

3.4 保护广播isProtectedBroadcast、特定action的处理

  1. 识别是否保护广播,这类广播不能给系统之外的app调用;而系统尽量发送保护广播,不然也会发出警告
  2. 后台是否可以接收广播的识别(如果在system/etc、/product/etc等地方加入“allow-implicit-broadcast”的广播则可以让后台接收,
    会加上FLAG_RECEIVER_INCLUDE_BACKGROUND的flag)
  3. 特定action如包状态改变等的广播的处理
        // Verify that protected broadcasts are only being sent by system code,
        // and that system code is only sending protected broadcasts.
        //保护广播的判断逻辑isProtectedBroadcast,这类广播只有系统才能发送
        final boolean isProtectedBroadcast;
        try {
   
   
            //查询该广播是否包含在mProtectedBroadcasts,在isProtectedBroadcast也可以增加字符串过滤条件
            //例如在frameworks/base/core/res/AndroidManifest.xml等定义的带有“protected-broadcast”的广播
            // <protected-broadcast android:name="android.intent.action.SCREEN_ON" />
            isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
        } catch (RemoteException e) {
   
   
            Slog.w(TAG, "Remote exception", e);
            return ActivityManager.BROADCAST_SUCCESS;
        }

        final boolean isCallerSystem;
        //判断是否系统调用
        switch (UserHandle.getAppId(callingUid)) {
   
   
            case ROOT_UID:
            case SYSTEM_UID:
            case PHONE_UID:
            case BLUETOOTH_UID:
            case NFC_UID:
            case SE_UID:
            case NETWORK_STACK_UID:
                //root用户、系统、phone、蓝牙、nfc、安全、网络等相关调用则被认为是系统
                isCallerSystem = true;
                break;
            default:
                //其它就看是否常驻内存,如果是常驻内存调用,也被认为是系统
                isCallerSystem = (callerApp != null) && callerApp.isPersistent();
                break;
        }

        // First line security check before anything else: stop non-system apps from
        // sending protected broadcasts.
        //如果不是系统调用,会进行安全检查
        if (!isCallerSystem) {
   
   
            //如果是保护的广播,则不是系统进程,不允许发送,抛出权限异常
            if (isProtectedBroadcast) {
   
   
                String msg = "Permission Denial: not allowed to send broadcast "
                        + action + " from pid="
                        + callingPid + ", uid=" + callingUid;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);

            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
   
   
                // Special case for compatibility: we don't want apps to send this,
                // but historically it has not been protected and apps may be using it
                // to poke their own app widget.  So, instead of making it protected,
                // just limit it to the caller.
                //如果是widget配置(ACTION_APPWIDGET_CONFIGURE)和更新(ACTION_APPWIDGET_UPDATE)
                //则调用callerPackage不能是空
                if (callerPackage == null) {
   
   
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + action + " from unknown caller.";
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                //如果调用组件不等于null
                } else if (intent.getComponent() != null) {
   
   
                    // They are good enough to send to an explicit component...  verify
                    // it is being sent to the calling app.
                    //这种情况只能自己发送给自己,不然抛出权限异常
                    if (!intent.getComponent().getPackageName().equals(
                            callerPackage)) {
   
   
                        String msg = "Permission Denial: not allowed to send broadcast "
                                + action + " to "
                                + intent.getComponent().getPackageName() + " from "
                                + callerPackage;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                } else {
   
   
                    // Limit broadcast to their own package.
                    //这类广播只能发给它自己,用于自身widget的更新
                    intent.setPackage(callerPackage);
                }
            }
        }

        //这个是广播超时豁免只有ACTION_PRE_BOOT_COMPLETED才会设置
        //设置了之后这个广播不会超时,谨慎使用
        boolean timeoutExempt = false;

        if (action != null) {
   
   
            //查看是否background的进程也可以接收该广播,具体列表在SystemConfig.java的mAllowImplicitBroadcasts
            //这个列表是扫描**/etc(如system/etc/sysconfig/framework-sysconfig.xml、
            // /product/etc/sysconfig/google.xml)带有“<allow-implicit-broadcast”的广播
            // 如:google的云推送”com.google.android.c2dm.intent.RECEIVE“、simcard状态改变
            // android.intent.action.SIM_STATE_CHANGED就是这类广播
            if (getBackgroundLaunchBroadcasts().contains(action)) {
   
   
                if (DEBUG_BACKGROUND_CHECK) {
   
   
                    Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
                }
                //直接增加可以被后台进程接收的flag FLAG_RECEIVER_INCLUDE_BACKGROUND
                // (如何使用在讲解BroadcastQueue的processNextBroadcastLocked时会说明)
                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            }

            switch (action) {
   
   
                case Intent.ACTION_UID_REMOVED:
                case Intent.ACTION_PACKAGE_REMOVED:
                case Intent.ACTION_PACKAGE_CHANGED:
                case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                case Intent.ACTION_PACKAGES_SUSPENDED:
                case Intent.ACTION_PACKAGES_UNSUSPENDED:
                    // Handle special intents: if this broadcast is from the package
                    // manager about a package being removed, we need to remove all of
                    // its activities from the history stack.
                    // 如果是ACTION_UID_REMOVED/ACTION_PACKAGE_REMOVED/ACTION_PACKAGE_CHANGED/
                    // ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE/ACTION_EXTERNAL_APPLICATIONS_AVAILABLE/
                    // ACTION_PACKAGES_SUSPENDED/ACTION_PACKAGES_UNSUSPENDED这类广播,
                    // 则发送广播需要BROADCAST_PACKAGE_REMOVED的权限,不然是没法发送的
                    if (checkComponentPermission(
                            android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
                            callingPid, callingUid, -1, true)
                            != PackageManager.PERMISSION_GRANTED) {
   
   
                        String msg = "Permission Denial: " + intent.getAction()
                                + " broadcast from " + callerPackage + " (pid=" + callingPid
                                + ", uid=" + callingUid + ")"
                                + " requires "
                                + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                    switch (action) {
   
   
                        case Intent.ACTION_UID_REMOVED:
                            final int uid = getUidFromIntent(intent);
                            //如果发送的是ACTION_UID_REMOVED的广播
                            if (uid >= 0) {
   
   
                                //电池状态服务的removeUid
                                mBatteryStatsService.removeUid(uid);
                                //mAppOpsService app操作相关管理的处理
                                if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
   
   
                                    mAppOpsService.resetAllModes(UserHandle.getUserId(uid),
                                            intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME));
                                } else {
   
   
                                    mAppOpsService.uidRemoved(uid);
                                }
                            }
                            break;
                        case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                            // If resources are unavailable just force stop all those packages
                            // and flush the attribute cache as well.
                            String list[] =
                                    intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                            if (list != null && list.length > 0) {
   
   
                                for (int i = 0; i < list.length; i++) {
   
   
                                    forceStopPackageLocked(list[i], -1, false, true, true,
                                            false, false, userId, "storage unmount");
                                }
                                mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                                sendPackageBroadcastLocked(
                                        ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,
                                        list, userId);
                            }
                            break;
                        case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                            mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                            break;
                        case Intent.ACTION_PACKAGE_REMOVED:
                        case Intent.ACTION_PACKAGE_CHANGED:
                            //应用移除或者改变
                            Uri data = intent.getData();
                            String ssp;
                            if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
   
   
                                boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
                                final boolean replacing =
                                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                                final boolean killProcess =
                                        !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
                                final boolean fullUninstall = removed && !replacing;
                                if (removed) {
   
   
                                    if (killProcess) {
   
   
                                        forceStopPackageLocked(ssp, UserHandle.getAppId(
                                                intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                                false, true, true, false, fullUninstall, userId,
                                                removed ? "pkg removed" : "pkg changed");
                                    } else {
   
   
                                        // Kill any app zygotes always, since they can't fork new
                                        // processes with references to the old code
                                        forceStopAppZygoteLocked(ssp, UserHandle.getAppId(
                                                intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                                userId);
                                    }
                                    final int cmd = killProcess
                                            ? ApplicationThreadConstants.PACKAGE_REMOVED
                                            : ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;
                                    sendPackageBroadcastLocked(cmd,
                                            new String[] {
   
   ssp}, userId);
                                    if (fullUninstall) {
   
   
                                        mAppOpsService.packageRemoved(
                                                intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

                                        // Remove all permissions granted from/to this package
                                        mUgmInternal.removeUriPermissionsForPackage(ssp, userId,
                                                true, false);

                                        mAtmInternal.removeRecentTasksByPackageName(ssp, userId);

                                        mServices.forceStopPackageLocked(ssp, userId);
                                        mAtmInternal.onPackageUninstalled(ssp);
                                        mBatteryStatsService.notePackageUninstalled(ssp);
                                    }
                                } else {
   
   
                                    if (killProcess) {
   
   
                                        final int extraUid = intent.getIntExtra(Intent.EXTRA_UID,
                                                -1);
                                        synchronized (mProcLock) {
   
   
                                            mProcessList.killPackageProcessesLSP(ssp,
                                                    UserHandle.getAppId(extraUid),
                                                    userId, ProcessList.INVALID_ADJ,
                                                    ApplicationExitInfo.REASON_USER_REQUESTED,
                                                    ApplicationExitInfo.SUBREASON_UNKNOWN,
                                                    "change " + ssp);
                                        }
                                    }
                                    cleanupDisabledPackageComponentsLocked(ssp, userId,
                                            intent.getStringArrayExtra(
                                                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                    mServices.schedulePendingServiceStartLocked(ssp, userId);
                                }                            }
                            break;
                        case Intent.ACTION_PACKAGES_SUSPENDED:
                        case Intent.ACTION_PACKAGES_UNSUSPENDED:
                            final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.equals(
                                    intent.getAction());
                            final String[] packageNames = intent.getStringArrayExtra(
                                    Intent.EXTRA_CHANGED_PACKAGE_LIST);
                            final int userIdExtra = intent.getIntExtra(
                                    Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);

                            mAtmInternal.onPackagesSuspendedChanged(packageNames, suspended,
                                    userIdExtra);
                            break;
                    }
                    break;
                case Intent.ACTION_PACKAGE_REPLACED:
                {
   
   
                    final Uri data = intent.getData();
                    final String ssp;
                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
   
   
                        ApplicationInfo aInfo = null;
                        try {
   
   
                            aInfo = AppGlobals.getPackageManager()
                                    .getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
                        } catch (RemoteException ignore) {
   
   }
                        if (aInfo == null) {
   
   
                            Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
                                    + " ssp=" + ssp + " data=" + data);
                            return ActivityManager.BROADCAST_SUCCESS;
                        }
                        updateAssociationForApp(aInfo);
                        mAtmInternal.onPackageReplaced(aInfo);
                        mServices.updateServiceApplicationInfoLocked(aInfo);
                        sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
                                new String[] {
   
   ssp}, userId);
                    }
                    break;
                }
                case Intent.ACTION_PACKAGE_ADDED:
                {
   
   
                    //应用安装
                    // Special case for adding a package: by default turn on compatibility mode.
                    Uri data = intent.getData();
                    String ssp;
                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
   
   
                        final boolean replacing =
                                intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                        mAtmInternal.onPackageAdded(ssp, replacing);
                        try {
   
   
                            ApplicationInfo ai = AppGlobals.getPackageManager().
                                    getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
                            mBatteryStatsService.notePackageInstalled(ssp,
                                    ai != null ? ai.longVersionCode : 0);
                        } catch (RemoteException e) {
   
   
                        }
                    }
                    break;
                }
                case Intent.ACTION_PACKAGE_DATA_CLEARED:
                {
   
   
                    //应用数据清除
                    Uri data = intent.getData();
                    String ssp;
                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
   
   
                        mAtmInternal.onPackageDataCleared(ssp);
                    }
                    break;
                }
                case Intent.ACTION_TIMEZONE_CHANGED:
                    // If this is the time zone changed action, queue up a message that will reset
                    // the timezone of all currently running processes. This message will get
                    // queued up before the broadcast happens.
                    //时区改变
                    mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
                    break;
                case Intent.ACTION_TIME_CHANGED:
                    // EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between
                    // the tri-state value it may contain and "unknown".
                    // For convenience we re-use the Intent extra values.
                    //系统时间改变
                    final int NO_EXTRA_VALUE_FOUND = -1;
                    final int timeFormatPreferenceMsgValue = intent.getIntExtra(
                            Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,
                            NO_EXTRA_VALUE_FOUND /* defaultValue */);
                    // Only send a message if the time preference is available.
                    if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {
   
   
                        Message updateTimePreferenceMsg =
                                mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,
                                        timeFormatPreferenceMsgValue, 0);
                        mHandler.sendMessage(updateTimePreferenceMsg);
                    }
                    mBatteryStatsService.noteCurrentTimeChanged();
                    break;
                case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:
                    mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                    break;
                case Proxy.PROXY_CHANGE_ACTION:
                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));
                    break;
                case android.hardware.Camera.ACTION_NEW_PICTURE:
                case android.hardware.Camera.ACTION_NEW_VIDEO:
                    // In N we just turned these off; in O we are turing them back on partly,
                    // only for registered receivers.  This will still address the main problem
                    // (a spam of apps waking up when a picture is taken putting significant
                    // memory pressure on the system at a bad point), while still allowing apps
                    // that are already actively running to know about this happening.
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                    break;
                case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
                    mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);
                    break;
                case "com.android.launcher.action.INSTALL_SHORTCUT":
                    // As of O, we no longer support this broadcasts, even for pre-O apps.
                    // Apps should now be using ShortcutManager.pinRequestShortcut().
                    Log.w(TAG, "Broadcast " + action
                            + " no longer supported. It will not be delivered.");
                    return ActivityManager.BROADCAST_SUCCESS;
                case Intent.ACTION_PRE_BOOT_COMPLETED:
                    //如果是ACTION_PRE_BOOT_COMPLETED广播则设置超时豁免timeoutExempt = true
                    timeoutExempt = true;
                    break;
                case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
                    //需要有BROADCAST_CLOSE_SYSTEM_DIALOGS的权限,不然直接返回
                    if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,
                            callerPackage)) {
   
   
                        // Returning success seems to be the pattern here
                        return ActivityManager.BROADCAST_SUCCESS;
                    }
                    break;
            }

            if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
                    Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
                    Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
   
   
                final int uid = getUidFromIntent(intent);
                if (uid != -1) {
   
   
                    final UidRecord uidRec = mProcessList.getUidRecordLOSP(uid);
                    if (uidRec != null) {
   
   
                        uidRec.updateHasInternetPermission();
                    }
                }
            }
        }

3.5 发送粘性广播的处理

将粘性广播添加到AMS的mStickyBroadcasts(key是用户组,value是粘性广播列表stickies)中,
单个用户组的粘性广播列表stickies(key是action,value是intent)

已经发送的粘性广播会放入AMS的mStickyBroadcasts中,后面动态注册的接收者就可以在注册的时候就接收这类粘性广播, 因为系统有保存这类广播

        // Add to the sticky list if requested.
        // 是否粘性广播,可以通过ContextImpl.java的sendStickyBroadcast/sendStickyBroadcastAsUser/
        // sendStickyOrderedBroadcast/sendStickyOrderedBroadcastAsUser来进行发送
        if (sticky) {
   
   
            //粘性广播需要拥有"android.permission.BROADCAST_STICKY"的权限
            if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                    callingPid, callingUid)
                    != PackageManager.PERMISSION_GRANTED) {
   
   
                String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
                        + callingPid + ", uid=" + callingUid
                        + " requires " + android.Manifest.permission.BROADCAST_STICKY;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }
            //这类广播不能带有requiredPermissions,否则直接返回
            if (requiredPermissions != null && requiredPermissions.length > 0) {
   
   
                Slog.w(TAG, "Can't broadcast sticky intent " + intent
                        + " and enforce permissions " + Arrays.toString(requiredPermissions));
                return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
            }
            //粘性广播不能指定发送到相关组件,否则发出安全异常
            if (intent.getComponent() != null) {
   
   
                throw new SecurityException(
                        "Sticky broadcasts can't target a specific component");
            }
            // We use userId directly here, since the "all" target is maintained
            // as a separate set of sticky broadcasts.
            //如果userId不是发送给所有用户USER_ALL(-1)
            if (userId != UserHandle.USER_ALL) {
   
   
                // But first, if this is not a broadcast to all users, then
                // make sure it doesn't conflict with an existing broadcast to
                // all users.
                //则取出保存粘性广播的列表mStickyBroadcasts里面相同action的Intent
                ArrayMap<String, ArrayList<Intent>> stickies =
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值