Android四大组件-BroadCastReceiver工作过程

BroadCastReceiver工作过程

  • BroadcastReceiver的使用主要包括:注册(动态和静态),发送,接收
  • 先来看一下BroadcastReceiver的简单使用

BroadCastReceiver的简单使用

  • 继承BroadCastReceiver实现自己的Receiver,并重写onReceive方法
public class MyBroadcast extends BroadcastReceiver {
    private final static String TAG = "MyBroadcast";

    @Override
    public void onReceive(Context context, Intent intent) {
        //onReceive不能做耗时的事情
        Log.d(TAG, "onReceive: on receive action = " + intent.getAction());
        //根据Action不同做不同的操作
        switch (intent.getAction()){
            case "":
                break;
        }
    }

}
  • 接下来注册,注册分两种:静态和动态
  • 先看静态,AndroidManifest.xml文件中
<receiver android:name=".LearnBroadCastReceiver.MyBroadcast">
   <intent-filter>
        <action android:name="com.example.learnretrofit.LearnBroadCastReceiver.LAUNCH"/>
    </intent-filter>
</receiver>
  • 或者动态注册
IntentFilter filter = new IntentFilter();
//这里的action是作为我们到时候给广播发送消息的时候,使用的唯一标识,推荐使用包名,或者只要能保证唯一性就可以
filter.addAction("com.example.learnretrofit.LearnBroadCastReceiver.LAUNCH");
mMyBroadcast = new MyBroadcast();
registerReceiver(mMyBroadcast,filter);
  • 动态注册需要在必要的时候解绑
unregisterReceiver(mMyBroadcast);
  • 绑定完成之后就可以发送广播了,像这样
Intent intent = new Intent();
intent.setAction("com.example.learnretrofit.LearnBroadCastReceiver.LAUNCH");
sendBroadcast(intent);
  • 简单的使用就到这里,接下来我们就来分析分析他是怎么工作的

BroadCastReceiver工作过程

注册过程

  • 静态注册过程是由PackageManagerService在应用安装的时候由系统自动完成注册,当然,不只是广播,其他在AndroidManifest.xml中注册的组件也是一样的,这里只分析动态注册的过程,直接从registerReceiver(mMyBroadcast,filter);方法看起
  • 依然是来到了ContextWrapper类
public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
  • 这里引用别人博客的一句话,希望对理解这个有所帮助
    这里写图片描述
  • 交给ContextImpl类registerReceiver方法
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    }
  • 在这里来到了ContextIm的registerReceiverInternal方法
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                //这个Handler是后面用来分发AMS发送的广播用的,可以看到这里是在主线程中分发,
                   //如果你想要在子线程中分发,可以自己指定一个Handler
                    scheduler = mMainThread.getHandler();
                }
                //这里根据名字可以判断,这应该是分发消息的机制
                //这里的内部其实是得到一个跨进程通信的Binder,用来最终广播操作
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
  • 那么最后这个方法来到ActivityManagerService的registerReceiver方法
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        enforceNotIsolatedCaller("registerReceiver");
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        final boolean visibleToInstantApps
                = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
        int callingUid;
        int callingPid;
        boolean instantApp;
        synchronized(this) {
            if (caller != null) {
             //获取当前进程对象
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid()
                            + ") when registering receiver " + receiver);
                }
                if (callerApp.info.uid != SYSTEM_UID &&
                        !callerApp.pkgList.containsKey(callerPackage) &&
                        !"android".equals(callerPackage)) {
                    throw new SecurityException("Given caller package " + callerPackage
                            + " is not running in process " + callerApp);
                }
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }

            instantApp = isInstantApp(callerApp, callerPackage, callingUid);
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
//获取IntentFilter中的action
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Collect stickies of users
            //从actions中,先把粘性广播帅选出来,放进stickyIntents中
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                String action = actions.next();
                for (int id : userIds) {
                 //从mStickyBroadcasts中查看用户的sticky Intent,mStickyBroadcasts存了系统所有的
                  //粘性广播,为什么叫做Sticky Intent,就是这个最后发出的广播虽然被处理完了,但是仍然被粘住在ActivityManagerService中,
                  //以便下一个注册相应Action类型的广播接收器还能继承处理
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            // Look for any matching sticky broadcasts...
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                // Don't provided intents that aren't available to instant apps.
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                // If intent has scheme "content", it will need to acccess
                // provider that needs to lock mProviderMap in ActivityThread
                // and also it may need to wait application response, so we
                // cannot lock ActivityManagerService here.
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }

        // The first sticky in the list is returned directly back to the client.
        Intent sticky = allSticky != null ? allSticky.get(0) : null;
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
        if (receiver == null) {
            return sticky;
        }

        synchronized (this) {
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died
                //进程不存在(死亡了),也是不能注册成功的
                return null;
            }
            //这里其实就是把广播接收器receiver保存一个ReceiverList列表中,这个列的宿主进程是rl.app, 
            //这里就是MainActivity所在的进程了,在AMS中,用一个进程记录块来表示这个应用程序进程, 
            //它里面有一个列表receivers,专门用来保存这个进程注册的广播接收器。
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                 //把广播接收者列表加到这个进程对象的receivers中
                    rl.app.receivers.add(rl);
                } else {
                    try {
                    //注册的进程不存在则销毁接收列表
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for uid " + callingUid
                        + " was previously registered for uid " + rl.uid
                        + " callerPackage is " + callerPackage);
            } else if (rl.pid != callingPid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for pid " + callingPid
                        + " was previously registered for pid " + rl.pid
                        + " callerPackage is " + callerPackage);
            } else if (rl.userId != userId) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for user " + userId
                        + " was previously registered for user " + rl.userId
                        + " callerPackage is " + callerPackage);
            }
            /由filter,rl等参数构建一个BroadcastFilter,看名字可以知道每个广播接收者就是
            //一个BroadcastFilter,这是动态广播注册时候封装的广播接收者对象
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            mReceiverResolver.addFilter(bf);

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            //如果是粘性广播,创建BroadcastRecord,并添加到
        //BroadcastQueue的并行广播队列(mParallelBroadcasts),
        //注册后调用AMS来尽快处理该广播。
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                final int stickyCount = allSticky.size();
                for (int i = 0; i < stickyCount; i++) {
                    Intent intent = allSticky.get(i);
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }
  • 可以看到,最终是将这个广播接收者构建成了一个BroadcastFilter 添加到了ReceiveList,那么这个广播也就相当于注册完成了

发送和接收过程

  • 通过上面分析我们知道动态广播注册在AMS中,对应的是BroadcastFilter,还有一点,我们没分析的静态广播是注册在PMS(PackageManagerService)中,对应的是ResolveInf,那么,我们的发送肯定是在这两个里面去找的,找到之后就发送给所有注册了该广播的注册者
  • 通过上面的分析,我们同样知道了广播的发送是将事情最先交给ContextImpl去处理的,我们就直接来到这个类的sendBroadcast方法
public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        //resolvedType表示intent的MIME类型
        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();
        }
    }
  • 然后直接来到AMS的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);
        //从mLruProcesses集合中查找进程记录
            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;
        }
    }
  • 接着会来到broadcastIntentLocked这个方法,这个方法实在太长,我们一点点看,就不贴代码了

    • 最开始有一句intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    • 给intent加上这个标志位,表示不会将广播发送给已经停止的应用,这个机制在android 3.1的
      时候就默认为所有广播添加了
    • 但是如果要调用未启动的应用怎么办呢,我们只需要再为广播的Intent添加FLAG_INCLUDE_STOPPED_PACKAGES标志即可
    • 这里补充,一个应用处于停止状态有两种情况,一种是应用自身未启动,一种是被手动或者其他应用强行停止了,从Android 3.1开始,处于停止状态的应用无法收到开机广播
    • 然后在这个方法的底部,会根据intent-filter查找出匹配的广播接收器并经过一系列的条件过滤,然后最终将这些个满足条件的广播接收者添加到BroadcastQueue中,
    • 接着这个队列会将广播发送给广播接收者
    • 来看一下对着发送过程的实现
public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
  • 可见他只是发送了一条BROADCAST_INTENT_MSG这个消息,我们看看Handler是怎么做的
private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }
  • 然后看processNextBroadcast方法
while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();

                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                        System.identityHashCode(r));
                    Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                        System.identityHashCode(r));
                }

                final int N = r.receivers.size();
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                        + mQueueName + "] " + r);
                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);
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            }
  • 这里只是他对普通广播的处理部分,可以看到,无需广播是由mParallelBroadcasts这个来保存,具体的发送过程由deliverToRegisteredReceiverLocked这个方法完成,在这个方法内部调用了performReceiveLocked来完成具体的发送
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.
                try {
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                // DeadObjectException when the process isn't actually dead.
                //} catch (DeadObjectException ex) {
                // Failed to call into the process.  It's dying so just let it die and move on.
                //    throw ex;
                } catch (RemoteException ex) {
                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
                    synchronized (mService) {
                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                + " (pid " + app.pid + "). Crashing it.");
                        app.scheduleCrash("can't deliver broadcast");
                    }
                    throw ex;
                }
            } 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);
        }
    }
  • 因为接收广播会调起应用程序,所以这里的app.thread不为空,所以来到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 {
            updateProcessState(processState, false);
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }
  • 这里最后通过InnerReceiver来实现广播的接收,在他的performReceive方法内部调用了LoadedApk.ReceiverDispatcher的performReceive方法
public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }
  • 在上面的代码中,会创建一个args对象并通过mActivityThread的post方法来执行Args中的逻辑,而Args实现了Runable的接口,mActivityThread是一个Handler,他其实就是ActivityThread中的mH,mH的类型时ActivityThread的内部类H,在Args的run方法中有如下几行代码
final BroadcastReceiver receiver = mReceiver;
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
  • 在这里,BroadcastReceiver的onReceiver方法被执行,也就是说接收到了广播

猜你喜欢

转载自blog.csdn.net/asffghfgfghfg1556/article/details/81363599