sendBroadcast流程(一)

本文基于Androd8.0。

广播发送有很多个函数,此处以最简单的sendBroadcast为例分析:

sendBroadcast实际是调用的ContextImpl的sendBroadcast:

 @Override
 public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntent(
           mMainThread.getApplicationThread(), intent, resolvedType, null,
           Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
           getUserId());
    } catch (RemoteException e) {
           throw e.rethrowFromSystemServer();
    }
}

其中ActivityManger.getService():

/**
* @hide
*/
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton IActivityManagerSingleton =
    new Singleton() {
        @Override
        protected IActivityManager create() {
            final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
            final IActivityManager am = IActivityManager.Stub.asInterface(b);
            return am;
    }
};

经过Binder驱动,最后会调用到ActivityManagerService.broadcastIntent。

public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);

            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                   callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
}

真正做事情的是ActivityManagerService.broadcastIntentLocked:

int broadcastIntentLocked(ProcessRecord callerApp,
    String callerPackage, Intent intent, String resolvedType,
    IIntentReceiver resultTo, int resultCode, String resultData,
    Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
    boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    
    ....

    // By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    
    // If we have not finished booting, don't allow this to launch new processes.
    if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    }

    ....
    
    // Verify that protected broadcasts are only being sent by system code,
    // and that system code is only sending protected broadcasts.
    final String action = intent.getAction();
    final boolean isProtectedBroadcast;
    try {
        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:
            isCallerSystem = true;
            break;
        default:
            isCallerSystem = (callerApp != null) && callerApp.persistent;
            break;
    }
    
    //非system app发送protected broadcast,抛出异常
    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 (...) {
            ....
        }
    }

    if (action != null) {
        if (getBackgroundLaunchBroadcasts().contains(action)) {
            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        }
        
        switch(action) {
            //处理Package等相关的广播
            ....
        }
    }

第一阶段处理一些特殊的广播。

接下来看第二阶段:

// Add to the sticky list if requested.
if (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);
    }
    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.
    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.
        ArrayMap> stickies =
                                         mStickyBroadcasts.get(UserHandle.USER_ALL);
        if (stickies != null) {
            ArrayList list = stickies.get(intent.getAction());
            if (list != null) {
                int N = list.size();
                int i;
                for (i=0; i> stickies = mStickyBroadcasts.get(userId);                
     if (stickies == null) {
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
     }
     ArrayList list = stickies.get(intent.getAction());
     if (list == null) {
        list = new ArrayList<>();
        stickies.put(intent.getAction(), list);
     }
     final int stickiesCount = list.size();
     int i;
     for (i = 0; i < stickiesCount; i++) {
        if (intent.filterEquals(list.get(i))) {
            // This sticky already exists, replace it.
            list.set(i, new Intent(intent));
            break;
        }
     }
     if (i >= stickiesCount) {
        list.add(new Intent(intent));
     }
} //end of if(sticky)
    
    ...
    
// Figure out who all will receive this broadcast.
List receivers = null;//保存匹配该Intent的所有广播接收者,包括静态和动态
List registeredReceivers = null;//保存符合该Intent的动态receiver
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) {
    //如果没有FLAG_RECEIVER_REGISTERED_ONLY flag,则查询PKMS,
    //获得那些在AndroidManifest.xml中声明的广播接收者,即静态广播接收者,并保存到receivers
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) { //没有指定接收的对象
    if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
        // Query one target user at a time, excluding shell-restricted users
        for (int i = 0; i < users.length; i++) {
            if (mUserController.hasUserRestriction(
                        UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                continue;
            }
            List registeredReceiversForUser =
                                         mReceiverResolver.queryIntent(intent,
                                         resolvedType, false /*defaultOnly*/, users[i]);
            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
             } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
             }
        }
      } else {
            //从mReceiver查找符合intent的动态广播接收者
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);
      }
    }
    /*
      判断该广播是否设置了REPLACE_PENDING标签,如果设置了该标签,并且之前的Intent还没有被处理,        
      则可以使用新的的Intent替换旧的Intent。目的是为了减少不必要的广播发送。
    */
    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    
    //先处理动态注册的接收中者
    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    //此次发送的广播为非有序广播,且符合该intent的动态receiver个数不为0
    if (!ordered && NR > 0) {
        // If we are not serializing this broadcast, then send the
        // registered receivers separately so they don't wait for the
        // components to be launched.
        if (isCallerSystem) {
            checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                                    isProtectedBroadcast, registeredReceivers);
        }
        //根据FLAG确定是加入到前台广播队列还是后台广播队列
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        //只需创建一个BrodacstRecord,一个BroadcastRecord对象可包括所有的接收者
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                 callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                 requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                 resultCode, resultData, resultExtras, ordered, sticky, false, userId);
 
        final boolean replaced = replacePending
                                    && (queue.replaceParallelBroadcastLocked(r) != null);
        // Note: We assume resultTo is null for non-ordered broadcasts.
        if (!replaced) {
            //如果没有被替换,则保存到mParallelBroadcasts中
            queue.enqueueParallelBroadcastLocked(r);
            //调度一次广播发送
            queue.scheduleBroadcastsLocked();
        }
        //至此,动态注册的广播接收者已经处理完毕,设置registeredReceivers为null
        registeredReceivers = null;
        NR = 0;
}

第二阶段的工作有两项:

  1. 查询满足条件的动态receiver和静态receiver
  2. 当本地广播不为ordered时,需尽快发送该广播。另,非ordered的广播都被AMS保存在mParallelBroadcasts中。
// Merge into one list.
int ir = 0;
if (receivers != null) {
    String skipPackages[] = null;
    //处理PACKAGE_ADDED、PACKAGE_RESTARTED、PACKAGE_DATA_CLEARED的intent,系统不希望有些应用
    //一安装就启动。
    //这类程序的工作原理是:在改程序内部监听PACKAGE_ADDED广播,如果系统没有防备,则PKMS安装完程序 
    //后所发送的PACKAGE_ADDED消息将触发该应用的启动
    ......
    //处理ACTION_EXTERNAL_APPLICATIONS_AVAILBLE广播
    ......
    //将动态注册的接收者registeredReceiver的元素合并到receivers中去
    //处理完毕后,所有的接收者(无论是动态还是静态)都存储到receivers中了
    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;
    BroadcastFilter curr = null;
    while (it < NT && ir < NR) {
        if (curt == null) {
            curt = (ResolveInfo)receivers.get(it);
        }
        if (curr == null) {
            curr = registeredReceivers.get(ir);
        }
        if (curr.getPriority() >= curt.priority) {
            // Insert this broadcast record into the final list.
            receivers.add(it, curr);
            ir++;
            curr = null;
            it++;
            NT++;
        } else {
            // Skip to the next ResolveInfo in the final list.
            it++;
            curt = null;
        }
    }
}

while (ir < NR) {
    if (receivers == null) {
        receivers = new ArrayList();
    }
    receivers.add(registeredReceivers.get(ir));
    ir++;
}

...

if ((receivers != null && receivers.size() > 0) || resultTo != null) {
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    //创建一个BroadcastRecord对象,它的receivers中包括所有的接收者
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp,         
                    resolvedType, requiredPermissions, appOp, brOptions, receivers, 
                    resultTo, resultCode,resultData, resultExtras, ordered, sticky, 
                    false, userId);
    
    final BroadcastRecord oldRecord =
                        replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
    
     if (oldRecord != null) {
        // Replaced, fire the result-to receiver.
        if (oldRecord.resultTo != null) {
            final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
            try {
                oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                        oldRecord.intent,
                                         Activity.RESULT_CANCELED, null, null,
                                         false, false, oldRecord.userId);
           } catch (RemoteException e) {
               Slog.w(TAG, "Failure ["+ queue.mQueueName + "] sending broadcast result of 
                                                      "+ intent, e);
           }
        }
    } else {
        //如果没被替换,将该条广播记录到mOrderedBroadcasts中
        queue.enqueueOrderedBroadcastLocked(r);
        //调度AMS进行广播发送工作
        queue.scheduleBroadcastsLocked();
    }
} else {
    // There was nobody interested in the broadcast, but we still want to record
    // that it happened.
    if (intent.getComponent() == null && intent.getPackage() == null
             && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        // This was an implicit broadcast... let's record it for posterity.
        addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
    }
}
    return ActivityManager.BROADCAST_SUCCESS;
}  //end of broadcastIntentLocked()       

      由以上分析可得,AMS将动态receiver和静态receiver都合并到了receivers中了。如果本次广播不是ordered,那么表明动态注册者已经在第二阶段中被处理了。因此在合并时,将不会有动态receiver被加到receivers中。最终所创建的广播记录存在mOrderedBroadcasts中,也即,不管是否为串行发送,静态receiver接收到的广播记录都保存在mOrderedBroadcasts中。

为何不将它们保存到mParallelBroadcasts中呢?

      结合code发现,mParallelBroadcasts中的BroadcastRecord所包含的都是动态注册的广播接收者信息,这是因为动态接收者所在的进程是已经存在的,而静态广播接收者就不能保证它已经和一个进程绑定在一起了。如果静态注册的广播接收者所在进程还未启动,则AMS还需要进行创建应用进程,初始化Android运行环境等一系列操作。

      且后面,mParallelBroadcasts中的成员是在一个循环中被逐条处理的,如果将静态广播接收者也保存到mParallelBroadcasts中,会有什么后果呢?假设这些静态接收者所在的进程全部未创建和启动,那么AMS将在循环中创建多个进程!系统压力一下就上去了。所以,静态接收者对应的广播记录都被放到了mOrderedBroadcasts中,AMS在处理这类广播信息时,一个进程一个进程地处理,只有处理完一个接收者才继续下一个接收者。这样的好处是避免了惊群效应的出现,坏处是延时较长。

你可能感兴趣的:(#,Broadcast)