Android---广播(Broadcast)---广播发送的过程分析

  这篇文章重点讲解广播的发送过程,这个过程要比上节的广播接收者的注册过程内容多得多,但是并不复杂,过程的核心部分还是在ActivityManagerService(下面简称AMS)中,下面我们就一步步来分析广播发送过程。
  按照上篇文章的介绍,跟注册广播接收者类似,客户端会调用ContextImpl中的sendBroadcast()方法把广播发送出去。
ContextImpl.java

public void sendBroadcast(Intent intent) {
    ...
    try {
         intent.prepareToLeaveProcess();
         //通过Binder方式调用到AMS的broadcastIntent()方法
         ActivityManagerNative.getDefault().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
}

ActivityManagerService.java

public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle options,
        boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        ...
        int res = broadcastIntentLocked(callerApp,
                callerApp != null ? callerApp.info.packageName : null,
                intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                requiredPermissions, appOp, null, serialized, sticky,
                callingPid, callingUid, userId);
        ...
    }
}

  下面就重点分析broadcastIntentLocked()方法,同理按照里面的实现,把方法分成四个部分来分析:

  • 调用者的检查以及一些特殊广播的预处理

ActivityManagerService.java

//为了避免修改传入的Intent,所以一开始就重新创建了一个同样内容的Intent
intent = new Intent(intent);
// By default broadcasts do not go to stopped apps.
//广播默认不会发送给状态为stop的应用,这里是指安装后从来没有启动过和被用户手动强制停止的应用
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
...
userId = handleIncomingUser(callingPid, callingUid, userId,
                true, ALLOW_NON_FULL, "broadcast", callerPackage);
        ...

       /*
         * Prevent non-system code (defined here to be non-persistent
         * processes) from sending protected broadcasts.
         */
        int callingAppId = UserHandle.getAppId(callingUid);
        if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
            || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
            || callingAppId == Process.NFC_UID || callingUid == 0) {
            // Always okay.
        } else if (callerApp == null || !callerApp.persistent) {
            try {
                if (AppGlobals.getPackageManager().isProtectedBroadcast(
                        intent.getAction())) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + intent.getAction() + " from pid="
                            + callingPid + ", uid=" + callingUid;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
                    ...
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception", e);
                return ActivityManager.BROADCAST_SUCCESS;
            }
        }

        final String action = intent.getAction();
        if (action != null) {
            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_PACKAGE_ADDED:
                    ...
                case Intent.ACTION_TIMEZONE_CHANGED:
                    ...
                case Intent.ACTION_TIME_CHANGED:
                    ...
                case Intent.ACTION_CLEAR_DNS_CACHE:
                    ...
                case Proxy.PROXY_CHANGE_ACTION:
                    ...
            }
        }

  默认情况下,会给Intent添加FLAG_EXCLUDE_STOPPED_PACKAGES这样一个flag,也就是广播默认不会发送给状态为stop的应用,这里是指安装后从来没有启动过和被用户手动强制停止的应用;与此对应的是FLAG_INCLUDE_STOPPED_PACKAGES 这样一个flag,设置了它就表示可以允许发送给stop状态的应用,如果两个flag都同时被设置了,那最终FLAG_INCLUDE_STOPPED_PACKAGES 这个会生效,原因可以查看Intent的isExcludingStopped()方法,该方法会在后面查找广播接收者的时候调用。
Intent.java

public boolean isExcludingStopped() {
    return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES))==
           FLAG_EXCLUDE_STOPPED_PACKAGES;
}

  如果发送的是protected 类型的广播,需要检查发送者的合法性,一些常见的protected类型的广播有android.intent.action.SCREEN_ON,android.intent.action.BOOT_COMPLETED等,这些状态类型的广播不是随便哪个应用都可以发送了,所以为此framework层会做一些特殊管控,系统当前所有的protected类型的广播可以到frameworks/base/core/res/AndroidManifest.xml里面查看protected-broadcast开头的标签,这方面更具体的剖析可以查看文章尾部的参考链接。
  之后再对一些特殊广播来进行一些预处理,可以看出主要是跟应用的安装,时区时钟等有关系,比如收到了ACTION_PACKAGE_REMOVED广播,也即应用卸载了,那此时就需要通知近期任务清除跟此应用有关的所有的记录,其他的广播在这里就不详细分析了,感兴趣的可以去看源码。

  • sticky类型广播的处理

ActivityManagerService.java

if (sticky) {
    ...
    // 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<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
                UserHandle.USER_ALL);
        if (stickies != null) {
            ArrayList<Intent> list = stickies.get(intent.getAction());
            if (list != null) {
                int N = list.size();
                int i;
                for (i=0; i<N; i++) {
                    if (intent.filterEquals(list.get(i))) {
                        throw new IllegalArgumentException(
                                "Sticky broadcast " + intent + " for user "
                                + userId + " conflicts with existing global broadcast");
                    }
                }
            }
        }
    }
    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
    if (stickies == null) {
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
    }
    ArrayList<Intent> 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));
    }
}

  此部分主要针对sticky类型的广播,目的是更新mStickyBroadcasts,它是一个SparseArray类型的对象,userId作为其key,只要是sticky类型的广播,最终都存放到了mStickyBroadcasts中,所以才能保证下次有对应广播接收者注册的时候,可以将sticky广播发送给它,这也解释了上节分析广播接收者注册时里面mStickyBroadcasts的来源了。

  • 搜集广播接收者

ActivityManagerService.java

// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
         == 0) {
    //搜集静态注册的广播接收者
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
    //根据不同的userId来搜集动态注册的广播接收者
    if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
        // Query one target user at a time, excluding shell-restricted users
        UserManagerService ums = getUserManagerLocked();
        for (int i = 0; i < users.length; i++) {
            if (ums.hasUserRestriction(
                    UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                continue;
            }
            //根据userId和intent等信息搜集动态注册的广播接收者,mReceiverResolver内容在之前广播
            //注册时会更新
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(intent,
                            resolvedType, false, users[i]);
            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
            } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
            }
        }
    } else {
        //根据userId和intent等信息搜集动态注册的广播接收者
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}

  不管是receivers还是registeredReceivers,里面的结果都是基于Priority从大到小降序排列的,这个Priority来源于IntentFilter,Priority的范围在IntentFilter.SYSTEM_HIGH_PRIORITY和IntentFilter.SYSTEM_LOW_PRIORITY之间,如果不设置,默认为0,当Priority越大,表示越早接收到广播,应用可以通过IntentFilter.setPriority()或者在AndroidManifest.xml中在“intent-filter”标签下 来变更Priority。

  • 广播加入队列准备发送

  首先要介绍下两个类,第一是BroadcastQueue,广播队列,用来存放即将要发送的广播,然后通过执行消息来最终真正实现广播的发送,内部有两个ArrayList类型的成员mParallelBroadcasts和mOrderedBroadcasts,前者用来存放要发送的无序广播,后者用来存放要发送的有序广播。在framework中,目前存在两个BroadcastQueue,一个foreground,一个background,决定放在哪个队列要看Intent中是否有添加FLAG_RECEIVER_FOREGROUND的flag,默认情况是没有添加的,也就是存放在background队列里。另外要注意两种队列的处理广播超时时间是有区别的,foreground 为10s,background为60s。
ActivityManagerService.java

BroadcastQueue broadcastQueueForIntent(Intent intent) {
     final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
     if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
             "Broadcast intent " + intent + " on "
             + (isFg ? "foreground" : "background") + " queue");
     return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}

  另外一个是BroadcastRecord,查看类的实现可以得知,基本里面都是成员变量,没有什么方法,主要用来记录一次广播的发送,将广播的调用者信息,intent,广播的接收者,以及各阶段广播处理的时间戳等都记录在内,方便后续获取相关信息。
ActivityManagerService.java

...
int NR = registeredReceivers != null ? registeredReceivers.size() : 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.
    //先确定是foreground的BroadcastQueue还是background的BroadcastQueue 
    final BroadcastQueue queue = broadcastQueueForIntent(intent);
    //将这次广播发送所需要的相关数据都封装到BroadcastRecord中
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
            appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
            resultExtras, ordered, sticky, false, userId);
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
    final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
    if (!replaced) {
        queue.enqueueParallelBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    }
    //BroadcastRecord已经插入到了BroadcastQueue中了,所以需要重置registeredReceivers和NR,避免
    //后面又重复添加广播接收者
    registeredReceivers = null;
    NR = 0;
}

BroadcastQueue.java

public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    mParallelBroadcasts.add(r);
    //此处更新enqueueClockTime的值
    r.enqueueClockTime = System.currentTimeMillis();
}
public void scheduleBroadcastsLocked() {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
            + mQueueName + "]: current="
            + mBroadcastsScheduled);
    //用mBroadcastsScheduled 来控制下面消息的发送,所以如果在消息还没完全执行完前又继续调用此方法,
    //是会出现调用失败的情况的
    if (mBroadcastsScheduled) {
        return;
    }
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

  处理完动态注册的接收者后,接下来就处理静态注册者。
ActivityManagerService.java

// Merge into one list.
int ir = 0;
if (receivers != null) {
    ...

    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;
    BroadcastFilter curr = null;
    //如果发送的是有序广播,则需要把动态注册的广播接收者和静态注册的广播接收者按照Priority降序排列,统
    //一合入到receivers中
    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) {
    //先确定是foreground的BroadcastQueue还是background的BroadcastQueue 
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    //将这次广播发送所需要的相关数据都封装到BroadcastRecord中
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, resolvedType,
            requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
            resultData, resultExtras, ordered, sticky, false, userId);

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
            + ": prev had " + queue.mOrderedBroadcasts.size());
    if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
            "Enqueueing broadcast " + r.intent.getAction());

    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
    if (!replaced) {
        添加到mOrderedBroadcasts
        queue.enqueueOrderedBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    }
}

return ActivityManager.BROADCAST_SUCCESS;

  等到都合并到receivers中后,同样针对此次广播发送,创建BroadcastRecord对象,然后调用BroadcastQueue.enqueueOrderedBroadcastLocked()将其存放到BroadcastQueue的mOrderedBroadcasts里面,之后scheduleBroadcastsLocked()来发送消息去异步处理广播的最终发送。
BroadcastQueue.java

public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mOrderedBroadcasts.add(r);
    r.enqueueClockTime = System.currentTimeMillis();
}

  纵观此过程,可以发现,动态注册的广播接收者会优于静态注册的广播接收者先收到消息,广播的发送是异步过程,并不是调用了broadcastIntentLocked()后广播就立马发送出去,其实都是暂存在了BroadcastQueue里面,最终还需要BroadcastQueue里面执行BROADCAST_INTENT_MSG消息时才开始真正的广播发送,执行BROADCAST_INTENT_MSG消息时,会调用到processNextBroadcast()方法,这也是最终要处理广播发送的函数,所以下面就重点分析processNextBroadcast()函数。
  从上面分析可以知道,mParallelBroadcasts里面存储了都是无序广播,并且是动态注册的接收者,mOrderedBroadcasts里面存储的有两类:一类是无序广播,并且是静态注册的接收者;另一类是有序广播,有静态注册的接收者和动态注册的接收者。其实processNextBroadcast()内部也就是分别处理这两种情况,所以将此方法分成两部分来分析:

  • 处理mParallelBroadcasts的发送

BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        ...

        // First, deliver any non-serialized broadcasts right away.
        while (mParallelBroadcasts.size() > 0) {
            r = mParallelBroadcasts.remove(0);
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchClockTime = System.currentTimeMillis();
            final int N = r.receivers.size();
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                    + mQueueName + "] " + r);
            //一个BroadcastRecord对象r,由于每个广播存在多个接收者,所以进一步通过一个for循环从r的
            //receivers中拿到一个接收者
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                        "Delivering non-ordered on [" + mQueueName + "] to registered "
                        + target + ": " + r);
                //由于mParallelBroadcasts都是来自于无序广播,所以下面的方法第三个参数直接传入false
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
            }
            addBroadcastToHistoryLocked(r);
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                    + mQueueName + "] " + r);
        }

  deliverToRegisteredReceiverLocked()从函数名也得知,此方法只处理动态注册的广播接收者,但是又会处理有序广播和无序广播,所以在下面讲mOrderedBroadcasts发送时它也会被调用。
BroadcastQueue.java*

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
       BroadcastFilter filter, boolean ordered) {
   boolean skip = false;
   ...//此处都是一些权限检查,忽略不讲

   //检查广播注册者所在的线程是否存在或者是否正在crash,如果是这两种情况则skip为true,也就是停止广播的
   //发送
   if (filter.receiverList.app == null || filter.receiverList.app.crashing) {
       Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
               + " to " + filter.receiverList + ": process crashing");
       skip = true;
   }

   if (!skip) {
       // If this is not being sent as an ordered broadcast, then we
       // don't want to touch the fields that keep track of the current
       // state of ordered broadcasts.
       //deliverToRegisteredReceiverLocked()方法在发送有序广播的时候也会被调用到,所以里面还是
       //要处理有序广播的情况
       if (ordered) {
           //这里获取的就是广播接收者的binder调用对象
           r.receiver = filter.receiverList.receiver.asBinder();
           r.curFilter = filter;
           filter.receiverList.curBroadcast = r;
           r.state = BroadcastRecord.CALL_IN_RECEIVE;
           if (filter.receiverList.app != null) {
               // Bump hosting application to no longer be in background
               // scheduling class.  Note that we can't do that if there
               // isn't an app...  but we can only be in that case for
               // things that directly call the IActivityManager API, which
               // are already core system stuff so don't matter for this.
               r.curApp = filter.receiverList.app;
               filter.receiverList.app.curReceiver = r;
               mService.updateOomAdjLocked(r.curApp);
           }
       }
       try {
           if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                   "Delivering to " + filter + " : " + r);
           performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                   new Intent(r.intent), r.resultCode, r.resultData,
                   r.resultExtras, r.ordered, r.initialSticky, r.userId);
           //有序广播的话,会修改其state状态,这个在后面finishReceiverLocked()时会用到
           if (ordered) {
               r.state = BroadcastRecord.CALL_DONE_RECEIVE;
           }
       } catch (RemoteException e) {
           Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
           if (ordered) {
               r.receiver = null;
               r.curFilter = null;
               filter.receiverList.curBroadcast = null;
               if (filter.receiverList.app != null) {
                   filter.receiverList.app.curReceiver = null;
               }
           }
       }
   }
}
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
    // Send the intent to the receiver asynchronously using one-way binder calls.
    if (app != null) {
        if (app.thread != null) {
            // If we have an app thread, do the call through that so it is
            // correctly ordered with other one-way calls.
            //这里通过Binder调用到ActivityThread的scheduleRegisteredReceiver()方法,其实去查
            //看这个方法可以得知,它最终也是调用receiver.performReceive()方法,更下面的调用时一样的
            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                    data, extras, ordered, sticky, sendingUser, app.repProcState);
        } else {
            // Application has died. Receiver doesn't exist.
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

  通过上一节广播接收者的注册过程可以得知,receiver其实是广播接收者在AMS的binder对象,其指向LoadedApk.java中的InnerReceiver,所以也就是调用InnerReceiver的performReceive()方法,简单看下就发现其调用了ReceiverDispatcher中的同名方法performReceive(),下面就直接分析此方法:
LoadedApk.java

static final class ReceiverDispatcher {
    ....//中间省略了ReceiverDispatcher内部其他方法或者成员
    public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
        if (ActivityThread.DEBUG_BROADCAST) {
            int seq = intent.getIntExtra("seq", -1);
            Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
                    + " to " + mReceiver);
        }
        //先把广播相关信息都封装到Args类中,从下面得知它实现了Runnable接口
        Args args = new Args(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
        //将args post到ActivityThread里面,最终调用其run()方法
        if (!mActivityThread.post(args)) {
            if (mRegistered && ordered) {
                IActivityManager mgr = ActivityManagerNative.getDefault();
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing sync broadcast to " + mReceiver);
                args.sendFinished(mgr);
            }
        }

        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
           ...

            public void run() {
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;

                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = mCurIntent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                    Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
                            + " mOrderedHint=" + ordered);
                }

                final IActivityManager mgr = ActivityManagerNative.getDefault();
                final Intent intent = mCurIntent;
                mCurIntent = null;

                if (receiver == null || mForgotten) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing null broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    return;
                }

                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
                try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    setExtrasClassLoader(cl);
                    //将args设置到receiver中保存,后面执行也要用到,注意Args是继承自BroadcastReceiver.PendingResult
                    receiver.setPendingResult(this);
                    //这里就是最终调用onReceive的地方,一般应用都会重写此方法,这样达到了广播发送给
                    //接收者的目的
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing failed broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    if (mInstrumentation == null ||
                            !mInstrumentation.onException(mReceiver, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                            "Error receiving broadcast " + intent
                            + " in " + mReceiver, e);
                    }
                }
                //由于上面调用了receiver.setPendingResult(this),所以此处条件满足,接着调用
                //finish()
                if (receiver.getPendingResult() != null) {
                    //此处调用的是BroadcastReceiver.PendingResult里面的finish()方法,但是由于
                    //是给动态注册的接收者发送无序广播,所以其实finish里面基本什么都没干,finish()
                    //函数的分析就留到后面进行。
                    finish();
                }
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
}

  以上就是分析了mParallelBroadcasts里面广播依次发送的流程,整体来看还是比较简单的,AMS端发送广播,最终调用到了BroadcastReceiver的onReceive()方法,完成了整个过程,从中也可以看出对于无序广播来说,如果接收者是动态注册的,AMS只管广播的发送,至于最终有没有送达其实它都不怎么关系的,当然这类广播也是优先发送的,因为下面才开始处理mOrderedBroadcasts里面的广播。

  • 处理mOrderedBroadcasts的发送

  我们继续回到BroadcastQueue的processNextBroadcast()方法中:
BroadcastQueue.java

do {
    if (mOrderedBroadcasts.size() == 0) {
        // No more broadcasts pending, so all done!
        mService.scheduleAppGcsLocked();
        if (looped) {
            // If we had finished the last ordered broadcast, then
            // make sure all processes have correct oom and sched
            // adjustments.
            mService.updateOomAdjLocked();
        }
        return;
    }
    r = mOrderedBroadcasts.get(0);
    boolean forceReceive = false;

    // Ensure that even if something goes awry with the timeout
    // detection, we catch "hung" broadcasts here, discard them,
    // and continue to make progress.
    //
    // This is only done if the system is ready so that PRE_BOOT_COMPLETED
    // receivers don't get executed with timeouts. They're intended for
    // one time heavy lifting after system upgrades and can take
    // significant amounts of time.
    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
    if (mService.mProcessesReady && r.dispatchTime > 0) {
        long now = SystemClock.uptimeMillis();
        //判断是否广播超时
        if ((numReceivers > 0) &&
                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
            Slog.w(TAG, "Hung broadcast ["
                    + mQueueName + "] discarded after timeout failure:"
                    + " now=" + now
                    + " dispatchTime=" + r.dispatchTime
                    + " startTime=" + r.receiverTime
                    + " intent=" + r.intent
                    + " numReceivers=" + numReceivers
                    + " nextReceiver=" + r.nextReceiver
                    + " state=" + r.state);
            //直接结束此次广播的方法,并安排广播发送给下一个接收者        
            broadcastTimeoutLocked(false); // forcibly finish this broadcast
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }

    //此处的条件判断很关键,对于有序广播来说,只有客户端收到了广播,并调用了AMS的finishReceiver()告
    //知此次广播处理完了时,状态才会改成IDLE,也才能继续进行广播给下个注册者的流程。很多时候广播延时接
    //收,就是因为前个广播接收者还没有处理完广播,每次执行到此处就直接返回了。
    if (r.state != BroadcastRecord.IDLE) {
        if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                "processNextBroadcast("
                + mQueueName + ") called when not idle (state="
                + r.state + ")");
        return;
    }

    //此广播已经没有接收者了,或者中途被终止了,超时,或者forceReceive强制被置为true,则最终会将其从
    //mOrderedBroadcasts移除,并将r置为null,保证while循环条件满足,并继续下个广播的发送
    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        // No more receivers for this broadcast!  Send the final
        // result if requested...
        if (r.resultTo != null) {
            try {
                if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                        "Finishing broadcast [" + mQueueName + "] "
                        + r.intent.getAction() + " app=" + r.callerApp);
                performReceiveLocked(r.callerApp, r.resultTo,
                    new Intent(r.intent), r.resultCode,
                    r.resultData, r.resultExtras, false, false, r.userId);
                // Set this to null so that the reference
                // (local and remote) isn't kept in the mBroadcastHistory.
                r.resultTo = null;
            } catch (RemoteException e) {
                r.resultTo = null;
                Slog.w(TAG, "Failure ["
                        + mQueueName + "] sending broadcast result of "
                        + r.intent, e);
            }
        }

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
        cancelBroadcastTimeoutLocked();

        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                "Finished with ordered broadcast " + r);

        // ... and on to the next...
        addBroadcastToHistoryLocked(r);
        mOrderedBroadcasts.remove(0);
        r = null;
        looped = true;
        continue;
    }
} while (r == null);

  这里还是要特意强调下,r.state 只有在置为 BroadcastRecord.IDLE后,才能继续广播的发送,否则就要一直等待前一个广播完成,并调用AMS的finishReceiver()方法,将r.state设置为BroadcastRecord.IDLE后,才能继续下面代码的执行,在平时处理广播相关bug时,经常遇到后面的广播没法及时接收,基本都是执行到此处就return掉了。

  上面while循环退出时,表明此时的r不为null,接下来就要开始发送给相关的广播接收者了,前面说过mOrderedBroadcasts里面既有动态注册的广播接收者,也有静态注册的广播接收者,同样,优先处理动态注册的广播接收者。
BroadcastQueue.java

// Get the next receiver...
//nextReceiver用来标记下一个广播接收者
int recIdx = r.nextReceiver++;

// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
    r.dispatchTime = r.receiverTime;注意每次一个有序广播发送给第一个接收者时才设置dispatchTime时间
    r.dispatchClockTime = System.currentTimeMillis();
    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
            + mQueueName + "] " + r);
}
if (! mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mTimeoutPeriod;
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
            "Submitting BROADCAST_TIMEOUT_MSG ["
            + mQueueName + "] for " + r + " at " + timeoutTime);
    setBroadcastTimeoutLocked(timeoutTime);
}

final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);
//先处理动态注册的广播接收者
if (nextReceiver instanceof BroadcastFilter) {
    // Simple case: this is a registered receiver who gets
    // a direct call.
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
            "Delivering ordered ["
            + mQueueName + "] to registered "
            + filter + ": " + r);
    //这个方法上面在处理mParallelBroadcasts时也被调用了,只是此处第三个参数是直接传入r.ordered
    deliverToRegisteredReceiverLocked(r, filter, r.ordered);
    //如果是无需广播或者接收者为null,则将state置为BroadcastRecord.IDLE,并安排下一次广播的发送
    if (r.receiver == null || !r.ordered) {
        // The receiver has already finished, so schedule to
        // process the next one.
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                + mQueueName + "]: ordered="
                + r.ordered + " receiver=" + r.receiver);
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
    } else {
        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
            scheduleTempWhitelistLocked(filter.owningUid,
                    brOptions.getTemporaryAppWhitelistDuration(), r);
        }
    }
    return;
}

  上面调用deliverToRegisteredReceiverLocked()时传入的第三个参数是r.ordered,也就是有可能是为true,按照之前的分析,最终会调用到BroadcastReceiver.PendingResult.finish()方法,进而调用其sendFinished() 方法。
BroadcastReceiver.java

public final void finish() {
    //mType是在初始化Args时设置的,对于动态注册的广播接收者,mType等于TYPE_REGISTERED,对于静态注
    //册的广播接收者,mType等于TYPE_COMPONENT,对于调用sendOrderedBroadcast之类的方法发送有序广
    //播时,mType等于TYPE_UNREGISTERED
    if (mType == TYPE_COMPONENT) {
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        if (QueuedWork.hasPendingWork()) {
            // If this is a broadcast component, we need to make sure any
            // queued work is complete before telling AM we are done, so
            // we don't have our process killed before that.  We now know
            // there is pending work; put another piece of work at the end
            // of the list to finish the broadcast, so we don't block this
            // thread (which may be the main thread) to have it finished.
            //
            // Note that we don't need to use QueuedWork.add() with the
            // runnable, since we know the AM is waiting for us until the
            // executor gets to it.
            QueuedWork.singleThreadExecutor().execute( new Runnable() {
                @Override public void run() {
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast after work to component " + mToken);
                    sendFinished(mgr);
                }
            });
        } else {
            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                    "Finishing broadcast to component " + mToken);
            sendFinished(mgr);
        }
    } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {//mOrderedHint来自于BroadcastRecord的ordered,所以如果是有序广播,其为true
        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                "Finishing broadcast to " + mToken);
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        sendFinished(mgr);
    }
}

public void sendFinished(IActivityManager am) {
    synchronized (this) {
        if (mFinished) {
            throw new IllegalStateException("Broadcast already finished");
        }
        //设置其为true,表示客户端完成了广播的接收工作,同时避免多次被调用
        mFinished = true;

        try {
            if (mResultExtras != null) {
                mResultExtras.setAllowFds(false);
            }
            //如果是有序广播
            if (mOrderedHint) {
                am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                        mAbortBroadcast, mFlags);
            } else {
                // This broadcast was sent to a component; it is not ordered,
                // but we still need to tell the activity manager we are done.
                am.finishReceiver(mToken, 0, null, null, false, mFlags);
            }
        } catch (RemoteException ex) {
        }
    }
}

  sendFinished()方法通过Binder调用到AMS的finishReceiver()方法。
ActivityManagerService.java

public void finishReceiver(IBinder who, int resultCode, String resultData,
        Bundle resultExtras, boolean resultAbort, int flags) {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);

    // Refuse possible leaked file descriptors
    if (resultExtras != null && resultExtras.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Bundle");
    }

    final long origId = Binder.clearCallingIdentity();
    try {
        boolean doNext = false;
        BroadcastRecord r;

        synchronized(this) {
            BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                    ? mFgBroadcastQueue : mBgBroadcastQueue;
            //确认下是否是刚才进行广播发送时的广播接收者,       
            r = queue.getMatchingOrderedReceiver(who);
            if (r != null) {
                doNext = r.queue.finishReceiverLocked(r, resultCode,
                    resultData, resultExtras, resultAbort, true);
            }
        }
        //如果为true,表示可以继续广播给下一个接收者
        if (doNext) {
            r.queue.processNextBroadcast(false);
        }
        trimApplications();
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

  finishReceiverLocked( )里面进行本次广播的一些收尾工作,其中比较重要的是重置r.state为IDLE,这样才能保证后续广播的正常进行。
BroadcastQueue.java

public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
        String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
    final int state = r.state;
    final ActivityInfo receiver = r.curReceiver;
    //此处重新把r.state置为IDLE,从而保证了后面在执行processNextBroadcast()时能正常进行广播
    r.state = BroadcastRecord.IDLE;
    if (state == BroadcastRecord.IDLE) {
        Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
    }
    r.receiver = null;
    r.intent.setComponent(null);
    if (r.curApp != null && r.curApp.curReceiver == r) {
        r.curApp.curReceiver = null;
    }
    if (r.curFilter != null) {
        r.curFilter.receiverList.curBroadcast = null;
    }
    r.curFilter = null;
    r.curReceiver = null;
    r.curApp = null;
    mPendingBroadcast = null;

    r.resultCode = resultCode;
    r.resultData = resultData;
    r.resultExtras = resultExtras;
    if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
        r.resultAbort = resultAbort;
    } else {
        r.resultAbort = false;
    }

    if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
            && r.queue.mOrderedBroadcasts.size() > 0
            && r.queue.mOrderedBroadcasts.get(0) == r) {
        ActivityInfo nextReceiver;
        if (r.nextReceiver < r.receivers.size()) {
            Object obj = r.receivers.get(r.nextReceiver);
            nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
        } else {
            nextReceiver = null;
        }
        // Don't do this if the next receive is in the same process as the current one.
        if (receiver == null || nextReceiver == null
                || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                || !receiver.processName.equals(nextReceiver.processName)) {
            // In this case, we are ready to process the next receiver for the current broadcast,
            // but are on a queue that would like to wait for services to finish before moving
            // on.  If there are background services currently starting, then we will go into a
            // special state where we hold off on continuing this broadcast until they are done.
            if (mService.mServices.hasBackgroundServices(r.userId)) {
                Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
                r.state = BroadcastRecord.WAITING_SERVICES;
                return false;
            }
        }
    }

    r.curComponent = null;

    // We will process the next receiver right now if this is finishing
    // an app receiver (which is always asynchronous) or after we have
    // come back from calling a receiver.
    //在文章前面分析deliverToRegisteredReceiverLocked()得知,有序广播情况下state是
    //BroadcastRecord.CALL_DONE_RECEIVE,所以函数会返回true
    return state == BroadcastRecord.APP_RECEIVE
            || state == BroadcastRecord.CALL_DONE_RECEIVE;
}

  以上分析了mOrderedBroadcasts中广播接收者是动态注册的情况,下面分析广播接收者是静态注册的情况,所以继续回到BroadcastQueue的processNextBroadcast()方法中,
BroadcastQueue.java

    ResolveInfo info =
        (ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);

    boolean skip = false;
    ...//此处都是一些权限检查以及其他预处理,先忽略

    //此时state又重新修改了新的状态
    r.state = BroadcastRecord.APP_RECEIVE;
    ...

    // Is this receiver's application already running?
    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) {
            Slog.w(TAG, "Exception when sending broadcast to "
                  + r.curComponent, e);
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Failed sending broadcast to "
                    + r.curComponent + " with " + r.intent, e);
            // If some unexpected exception happened, just skip
            // this broadcast.  At this point we are not in the call
            // from a client, so throwing an exception out from here
            // will crash the entire system instead of just whoever
            // sent the broadcast.
            logBroadcastReceiverDiscardLocked(r);
            finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            scheduleBroadcastsLocked();
            // We need to reset the state if we failed to start the receiver.
            r.state = BroadcastRecord.IDLE;
            return;
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }

    // Not running -- get it started, to be executed when the app comes up.
    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
            "Need to start app ["
            + mQueueName + "] " + targetProcess + " for broadcast " + r);
    //此处说明其对应进程不存在,所以需要先调用startProcessLocked()将其进程启动起来
    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) {
        // Ah, this recipient is unavailable.  Finish it if necessary,
        // and mark the broadcast record as ready for the next.
        Slog.w(TAG, "Unable to launch app "
                + info.activityInfo.applicationInfo.packageName + "/"
                + info.activityInfo.applicationInfo.uid + " for broadcast "
                + r.intent + ": process is bad");
        logBroadcastReceiverDiscardLocked(r);
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE;
        return;
    }

    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;
}

  从上看出,需要先区分应用的进程是否存在,如果存在,就继续调用
processCurBroadcastLocked()。
BroadcastQueue.java

private final void processCurBroadcastLocked(BroadcastRecord r,
        ProcessRecord app) throws RemoteException {
    ...
    try {
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                "Delivering to component " + r.curComponent
                + ": " + r);
        mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
        //binder调用到ActivityThread的scheduleReceiver(),说明下,之前在发送给动态注册者时,是
        //binder调用到了ActivityThread的scheduleRegisteredReceiver(),注意区分下这两种情况
        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                app.repProcState);
        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                "Process cur broadcast " + r + " DELIVERED for app " + app);
        started = true;
    } finally {
        if (!started) {
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Process cur broadcast " + r + ": NOT STARTED!");
            r.receiver = null;
            r.curApp = null;
            app.curReceiver = null;
        }
    }
}

  调用ActivityThread的scheduleReceiver(),内部调用流程跟上面分析动态注册者差不多,此处就不再分析了,不过最终也是会回调到AMS的finishReceiver()。
  如果广播所在的应用进程不存在,则要先调用AMS的startProcessLocked()来启动应用进程,由于并不是马上就完成了整个启动过程,所以在函数执行完后,将当前的BroadcastRecord和对应的索引分别记录到mPendingBroadcast和mPendingBroadcastRecvIndex。看过应用进程启动部分知道,在应用进程启动后,会调用AMS的attachApplicationLocked()。
ActivityManagerService.java

// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
    try {
        didSomething |= sendPendingBroadcastsLocked(app);
    } catch (Exception e) {
        // If the app died trying to launch the receiver we declare it 'bad'
        Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
        badApp = true;
    }
}

BroadcastQueue.java

boolean sendPendingBroadcastsLocked(ProcessRecord app) {
    boolean didSomething = false;
    for (BroadcastQueue queue : mBroadcastQueues) {
        didSomething |= queue.sendPendingBroadcastsLocked(app);
    }
    return didSomething;
}

  最终调用了BroadcastQueue的sendPendingBroadcastsLocked(),里面继续调用processCurBroadcastLocked(),上面已经分析了,这里就不再分析了。
BroadcastQueue.java

public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
    boolean didSomething = false;
    final BroadcastRecord br = mPendingBroadcast;
    if (br != null && br.curApp.pid == app.pid) {
        try {
            mPendingBroadcast = null;
            processCurBroadcastLocked(br, app);
            didSomething = true;
        } catch (Exception e) {
            Slog.w(TAG, "Exception in new application when starting receiver "
                    + br.curComponent.flattenToShortString(), e);
            logBroadcastReceiverDiscardLocked(br);
            finishReceiverLocked(br, br.resultCode, br.resultData,
                    br.resultExtras, br.resultAbort, false);
            scheduleBroadcastsLocked();
            // We need to reset the state if we failed to start the receiver.
            br.state = BroadcastRecord.IDLE;
            throw new RuntimeException(e.getMessage());
        }
    }
    return didSomething;
}

  以上全部就都是广播的发送流程分析,文章确实比较长,内容看起来也比较多,但是总结起来可以用下面几点概括:
  1. 首先搜集广播对应的广播接收者,有可能是动态注册的,也有可能是静态注册的。
  2. 搜集完后,如果是无序广播,优先将其发送给的动态注册的广播接收者。
  3. 接着处理有序广播的情况,此时即可能有动态注册的广播接收者,也有静态注册的广播接收者,在广播真正发送的时候,还是优先发送给动态注册的广播接收者。
  4. 对于发送给静态注册广播接收者,需要先检查对应的进程是否存在,如果不存在需要先将其进程调用起来,再接着发送广播。

参考资料
http://blog.csdn.net/thinkinwm/article/details/8713294 Android 4.0新的广播机制FLAG_EXCLUDE_STOPPED_PACKAGES
http://blog.csdn.net/luoshengyang/article/details/6744448Android应用程序发送广播(sendBroadcast)的过程分析
http://blog.csdn.net/kakaxi1o1/article/details/44456763 Android受限广播保护机制
http://blog.csdn.net/guoqifa29/article/details/39049491 Broadcast学习笔记
http://www.jianshu.com/p/59f7437a9c7d 说说Android的广播(4) - 前台广播为什么比后台广播快?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值