Android开发艺术探索:四大组件的工作过程之发送广播

发送广播分为普通广播,有序广播,Sticky广播,AMS会根据广播类型做相应的处理。

sendBroadcast

发送普通广播的入口在ContextImpl:

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();//系统进程调用打印日志
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess();
        ActivityManagerNative.getDefault().broadcastIntent(
            mMainThread.getApplicationThread(), intent, resolvedType, null,
            Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
            getUserId());
    } catch (RemoteException e) {
    }
}

几乎啥事没做直接调用ActivityManagerNative.getDefault()得到ActivityManagerProxy,向AMS发起IPC调用broadcastIntent,下面注释为上面参数调用的值:

public int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType,  IIntentReceiver resultTo/*null*/,
        int resultCode/*Activity.RESULT_OK*/, String resultData/*null*/, Bundle map/*null*/,
        String requiredPermission/*null*/, int appOp/*AppOpsManager.OP_NONE*/, boolean serialized/*false*/,
        boolean sticky/*false*/, int userId) throws RemoteException
{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
    data.writeInt(resultCode);
    data.writeString(resultData);
    data.writeBundle(map);
    data.writeString(requiredPermission);
    data.writeInt(appOp);
    data.writeInt(serialized ? 1 : 0);
    data.writeInt(sticky ? 1 : 0);
    data.writeInt(userId);
    mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
    reply.readException();
    int res = reply.readInt();
    reply.recycle();
    data.recycle();
    return res;
}

然后进入到ActivityManagerService#broadcastIntent:

public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType,  IIntentReceiver resultTo/*null*/,
        int resultCode/*Activity.RESULT_OK*/, String resultData/*null*/, Bundle map/*null*/,
        String requiredPermission/*null*/, int appOp/*AppOpsManager.OP_NONE*/, boolean serialized/*false*/,
        boolean sticky/*false*/, int userId) {
    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, map, requiredPermission, appOp, serialized, sticky,
                callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

获取调用进程pid和uid,切换调用发送广播为AMS当前进程pid,调用broadcastIntentLocked进行处理:

private final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle map, String requiredPermission, int appOp,
        boolean ordered, boolean sticky, int callingPid, int callingUid,
        int userId) {
    intent = new Intent(intent);

    // By default broadcasts do not go to stopped apps.
    //广播不向处于Stopped状态的App发送广播
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    userId = handleIncomingUser(callingPid, callingUid, userId,
            true, ALLOW_NON_FULL, "broadcast", callerPackage);

    //...

    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) {
        //系统应用可以发送任何广播
    } else if (callerApp == null || !callerApp.persistent) {
       //...是否发送的是系统广播则抛异常,应该不会影响AMS进程吧?
       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())) {
              //...
          }
    }

    final String action = intent.getAction();
    if (action != null) {
        switch (action) {
            //检查某些广播action的权限,比如BROADCAST_PACKAGE_REMOVED
            //某些广播的特殊处理,比如package remove,进程状态的处理
    }

    //sticky广播的处理
    if (sticky) {
        //...
    }

    //处理多用户下接受广播的userId
    int[] users;
    if (userId == UserHandle.USER_ALL) {
        // Caller wants broadcast to go to all started users.
        users = mStartedUserArray;
    } else {
        // Caller wants broadcast to go to one specific user.
        users = new int[] {userId};
    }

    List receivers = null;//静态注册的广播,从PackagerManagerService里面解析处理的
    List<BroadcastFilter> registeredReceivers = null;//动态注册的广播,从mReceiverResolver里面取出来的

    //如果设置了这个表示位那么只有动态注册的广播才能接收到
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }
    if (intent.getComponent() == null) {
        if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
            //...
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                    resolvedType, false, userId);
        }
    }

    //如果设置了这个标志位,那么将会替换队列里面还没有发出去的广播
    final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    //普通广播处理
    if (!ordered && NR > 0) {
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
                appOp, registeredReceivers, resultTo, resultCode, resultData, map,
                ordered, sticky, false, userId);
        final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
        if (!replaced) {
            queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
        //处理完之后置null,并且NR为零,如果没有执行这一步那么说明是有序广播
        registeredReceivers = null;
        NR = 0;
    }

    //...静态注册广播的处理

    return ActivityManager.BROADCAST_SUCCESS;
}

首先,判断是否是系统广播,非系统应用不能发送系统广播。检查某些广播action的权限,比如BROADCAST_PACKAGE_REMOVED 某些广播的特殊处理,比如如果是package remove,进程状态需要处理。讲静态注册的广播和动态注册的广播分开处理,分别保存在receivers和registeredReceivers里面,并且先处理动态注册的广播。

给Intent设置了Intent.FLAG_RECEIVER_REPLACE_PENDING这个标志位,那个将会替换掉队列里面还没有发送出去的广播。
给Intent设置了Intent.FLAG_RECEIVER_REGISTERED_ONLY这个标志位,那么将会只有动态注册的广播才能收到。
处理完之后置null,并且NR为零,如果没有执行这一步那么说明是有序广播。
根据Intent的类型调用broadcastQueueForIntent得到BroadcastQueue:

BroadcastQueue broadcastQueueForIntent(Intent intent) {
    final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
    //没有指定Intent.FLAG_RECEIVER_FOREGROUND,得到的就是mBgBroadcastQueue
    return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}

AMS里面保存了两个用于发送广播的队列,用于保存前台和后台的优先级,在实例化AMS的时候就会创建,并且关联的Handelr也是AMS的Handelr。ServerThread类型是HandlerThread,所有处理广播是在AMS的子线程里面处理的:

public ActivityManagerService(Context systemContext) {
    mContext = systemContext;
    mSystemThread = ActivityThread.currentActivityThread();

    //ServerThread是一个HandlerThread,s
    mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    mHandlerThread.start();
    mHandler = new MainHandler(mHandlerThread.getLooper());

    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", /**10s**/BROADCAST_FG_TIMEOUT, false);

    //最后一个参数true, we can delay broadcasts while waiting services to finish in the previous receiver's process.
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", /**60s**/BROADCAST_BG_TIMEOUT, true);
    //...
  }

将广播集合放到queue里面,然后调用scheduleBroadcastsLocked处理分发广播:

public final class BroadcastQueue {

  public void scheduleBroadcastsLocked() {
      //广播还没有发到队列里面则返回
      if (mBroadcastsScheduled) {
          return;
      }
      mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
      mBroadcastsScheduled = true;
  }
}

向Handler发消息:

private final class BroadcastHandler extends Handler {
    //...

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_INTENT_MSG: {
                processNextBroadcast(true);
            } break;
           //...
        }
    }
};

final void processNextBroadcast(boolean fromMsg) {
      synchronized(mService) {
          BroadcastRecord r;
          if (fromMsg) {
              mBroadcastsScheduled = false;
          }

          //找到添加在无序广播集合里面的BroadcastRecord
          while (mParallelBroadcasts.size() > 0) {
              r = mParallelBroadcasts.remove(0);
              r.dispatchTime = SystemClock.uptimeMillis();
              r.dispatchClockTime = System.currentTimeMillis();
              final int N = r.receivers.size();
              for (int i=0; i<N; i++) {
                  Object target = r.receivers.get(i);
                  deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
              }
              addBroadcastToHistoryLocked(r);
          }
        //...
        }       
}

mParallelBroadcasts集合里面的内容就是刚才调用enqueueParallelBroadcastLocked添加进去的。
调用deliverToRegisteredReceiverLocked做分发处理:

//分发广播到某个接受者
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered) {
    boolean skip = false;
    //如果注册广播的时候声明了权限,需要检查发送者是否拥有这个权限
    if (filter.requiredPermission != null) {
        int perm = mService.checkComponentPermission(filter.requiredPermission,
                r.callingPid, r.callingUid, -1, true);
        if (perm != PackageManager.PERMISSION_GRANTED) {
            skip = true;
        }
    }

    //检查接受者的权限
    if (!skip && r.requiredPermission != null) {
        int perm = mService.checkComponentPermission(r.requiredPermission,
                filter.receiverList.pid, filter.receiverList.uid, -1, true);
        if (perm != PackageManager.PERMISSION_GRANTED) {
            skip = true;
        }
    }

    //...

    //如果接受者进程挂掉这不分发
    if (filter.receiverList.app == null || filter.receiverList.app.crashing) {
        skip = true;
    }

    if (!skip) {
        if (ordered) {
            //...
        }
        try {
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                new Intent(r.intent), r.resultCode, r.resultData,
                r.resultExtras, r.ordered, r.initialSticky, r.userId);
           //...
        } catch (RemoteException e) {
          //...
        }
    }
}

检查接受者和发送者的权限,没有问题就调用performReceiveLocked做真正的广播处理:

private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
    if (app != null) {
        if (app.thread != null) {
            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);
    }
}

向注册广播的客户端发起IPC调用scheduleRegisteredReceiver,所以就执行到ApplicationThread#scheduleRegisteredReceiver:

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
        int resultCode, String dataStr, Bundle extras, boolean ordered,
        boolean sticky, int sendingUser, int processState) throws RemoteException {
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

执行注册广播的时候往LoadedApk里面添加的InnerReceiver的方法performReceive:

final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                LoadedApk.ReceiverDispatcher rd = mDispatcher.get();

                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                  //...
                }
            }
        }

接着执ReceiverDispatcher#performReceive:

public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    Args args = new Args(intent, resultCode, data, extras, ordered,
            sticky, sendingUser);
    if (!mActivityThread.post(args)) {
        if (mRegistered && ordered) {
            //...有序广播需要做相应的处理
        }
    }
}

Args是一个Runnable对象,向主线程的Handler发送Args里面的内容为:

final class Args extends BroadcastReceiver.PendingResult implements Runnable {
           private Intent mCurIntent;
           private final boolean mOrdered;


           public void run() {
               final BroadcastReceiver receiver = mReceiver;
               final boolean ordered = mOrdered;
               final Intent intent = mCurIntent;
               mCurIntent = null;

               //...

               try {
                   ClassLoader cl =  mReceiver.getClass().getClassLoader();
                   intent.setExtrasClassLoader(cl);
                   setExtrasClassLoader(cl);
                   receiver.setPendingResult(this);
                   receiver.onReceive(mContext, intent);
               } catch (Exception e) {
                   //...
               }

              //...
           }
       }

执行动态注册的广播onReceive方法。静态注册的广播与动态注册的广播处理方式不同,是放在receivers里面处理的,并且处理方式是串行的,防止并发启动多个广播接受者的进程。

private final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle map, String requiredPermission, int appOp,
        boolean ordered, boolean sticky, int callingPid, int callingUid,
        int userId) {

        //...静态注册广播的处理

        //这个会将有序广播和静态注册的广播根据优先级合并在一起
        // Merge into one list.
        int ir = 0;
        if (receivers != null) {
            //注释说得很清楚,防止安装应用接受PACKAGE_ADD这个广播将自身启动,被安装的应用如果静态监听了,需要去掉

            // A special case for PACKAGE_ADDED: do not allow the package
            // being added to see this broadcast.  This prevents them from
            // using this as a back door to get run as soon as they are
            // installed.  Maybe in the future we want to have a special install
            // broadcast or such for apps, but we'd like to deliberately make
            // this decision.
            String skipPackages[] = null;
            if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
                    || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
                    || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
                Uri data = intent.getData();
                if (data != null) {
                    String pkgName = data.getSchemeSpecificPart();
                    if (pkgName != null) {
                        skipPackages = new String[] { pkgName };
                    }
                }
            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
                skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
            }
            if (skipPackages != null && (skipPackages.length > 0)) {
                for (String skipPackage : skipPackages) {
                    if (skipPackage != null) {
                        int NT = receivers.size();
                        for (int it=0; it<NT; it++) {
                            ResolveInfo curt = (ResolveInfo)receivers.get(it);
                            if (curt.activityInfo.packageName.equals(skipPackage)) {
                                receivers.remove(it);
                                it--;
                                NT--;
                            }
                        }
                    }
                }
            }

            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 r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType,
                    requiredPermission, appOp, receivers, resultTo, resultCode,
                    resultData, map, ordered, sticky, false, userId);
            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return ActivityManager.BROADCAST_SUCCESS;}

上面的代码就是静态广播和有序广播的处理,会将静态注册的广播和有序广播放到统一放到receivers里面,然后根据某些情况过滤接受者,然后调用
queue.enqueueOrderedBroadcastLocked(r);将这个一次要发送的广播相关信息放到有序广播的集合mOrderedBroadcasts里,然后在调用queue做分发处理:

public void scheduleBroadcastsLocked() {
    //上一个消息还没得到处理就先返回
    if (mBroadcastsScheduled) {
        return;
    }
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

向Hanlder发送消息之后调用processNextBroadcast做处理:

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        BroadcastRecord r;
        if (fromMsg) {
            mBroadcastsScheduled = false;
        }

        while (mParallelBroadcasts.size() > 0) {
            //无序广播的处理  
         }

        //新启动的进程的广播正在被处理,那么返回继续等待
        if (mPendingBroadcast != null) {
            boolean isDead;
            synchronized (mService.mPidsSelfLocked) {
                ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
                isDead = proc == null || proc.crashing;
            }
            if (!isDead) {
                // It's still alive, so keep waiting
                return;
            } else {
                mPendingBroadcast.state = BroadcastRecord.IDLE;
                mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                mPendingBroadcast = null;
            }
        }
        boolean looped = false;
        do {
            //..找到集合里面的第一个广播,并且判断是不是最后一个广播做相应处理
            r = mOrderedBroadcasts.get(0);
            boolean forceReceive = false;
            mOrderedBroadcasts.remove(0);
            //..
            }
        } while (r == null);

        int recIdx = r.nextReceiver++;

        Object nextReceiver = r.receivers.get(recIdx);
        //如果广播类型是BroadcastFilter说明是动态注册的有序广播
        if (nextReceiver instanceof BroadcastFilter) {
                  BroadcastFilter filter = (BroadcastFilter)nextReceiver;
                  deliverToRegisteredReceiverLocked(r, filter, r.ordered);
                  if (r.receiver == null || !r.ordered) {
                      r.state = BroadcastRecord.IDLE;
                      scheduleBroadcastsLocked();
                  }
                  return;
              }

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

        //检查权限相关操作...

        // 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) {
                 return;
            }

        }

        //开启进程处理,并将mPendingBroadcast赋值,等待进程启动之后向AMS发起attachApplication请求
         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) {
             finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            scheduleBroadcastsLocked();
            r.state = BroadcastRecord.IDLE;
            return;
        }

        mPendingBroadcast = r;
        mPendingBroadcastRecvIndex = recIdx;
    }
}

从有序广播集合里面取得一个接收者,判断是静态注册的广播还是动态注册的广播,如果是动态注册的广播,那么就是有序广播,直接向客户端逐个分发。

如果是静态注册的广播,先判断接受者的进程是否存在,如果存在就不用开启进程。如果不存在,开启进程处理,并将mPendingBroadcast赋值,等待进程启动之后向AMS发起attachApplication请求,再处理放到mPendingBroadcast的广播。