Android中BroadcastReceiver的工作过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyz_zyx/article/details/83052096

我们知道,BroadcastReceiver的工作步骤是先注册广播,然后就是发送和接收广播。广播的注册分动态注册和静态注册两种方式,动态注册就是通过代码中使用registerReceiver方法来完在,而静态注册是通过在AndroidManifest.xml文件配置即可,而且静态注册还可以在app不启动也能接收到广播。而发送是通过sendBroadcast方法来完成,接收是要通过BroadcastReceiver类对象的onReceive方法来接收。它们这三个步骤都要必须约定好是同一个action。关于广播的使用可以看之前的文章《Android里广播Broadcast的使用》。今天主要是对BroadcastReceiver的注册、发送和接收过程的工作原理进行介绍。

BroadcastReceiver的注册过程

上面简介时提到注册分动态注册和静态注册两种形式,其中静态注册是通过AndroidManifest.xml配置来完成,其实其它三大组件也是如此。静态注册是在app安装时由系统服务PackageManagerService来完成的。今天我们只来通过registerReceiver方法跟踪分析动态注册的过程。动态注册广播示例如:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("BroadcastAction");
registerReceiver(mBroadcastReceiver, intentFilter);

所以我们就从registerReceiver ()方法入手:

ContextWrapper.java

public class ContextWrapper extends Context {
    Context mBase;
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
}

和Service的工作过程很相似,也是通过mBase对象来处理的,我们在介绍Service的工作过程中有讲过,这个mBase对象就是一个ComtextImpl对象,这里就不作重复介绍了,直接看ComtextImpl的代码:

ContextImpl.java

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext());
}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context) {
    // 关键代码1
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            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 {
        // 关键代码2
        final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
        if (intent != null) {
            intent.setExtrasClassLoader(getClassLoader());
            intent.prepareToEnterProcess();
        }
        return intent;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

请看关键代码1处,IIntentReceiver是一个LoadedApk类的内部类ReceiverDispatcherIntentReceiver对象,它是一个Binder接口,用于跨进程使用,因为BradcastReceiver作为Android的一个组件是不能直接跨进程传递的,所以需要通过IIntentReceiver来中转一下。

再来看关键代码2, ActivityManagerNative.getDefault()这代码是再熟悉不过了,这是它返回一个IActivityManager对象,实现就是跨进程调用ActivityManagerService,原因我们在《Android应用程序启动详解(一)》中有介绍,那我们直接看ActivityManagerServiceregisterReceiver方法:

ActivityManagerService.java

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
    enforceNotIsolatedCaller("registerReceiver");
    ……
    synchronized (this) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            // Original caller already died
            return null;
        }
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                rl.app.receivers.add(rl);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            // 关键代码1
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } 
        ……
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId);
        rl.add(bf);
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        // 关键代码2
        mReceiverResolver.addFilter(bf);
        ……
        return sticky;
    }
}

registerReceiver方法代码够长,我们只看关键两处即可,请看关键代码1 关键代码2,它们分别是把刚才从ContextImpl.java传入的InnerReceiver和 IntentFilter对象存储起来,就这样注册过程就完成了。

BroadcastReceiver发送和接收过程

广播的发送通过sendBroadcast方法来发起,示例如:

扫描二维码关注公众号,回复: 3734540 查看本文章
Intent intentBroadcast = new Intent();
intentBroadcast.setAction("BroadcastAction");             // 设置广播的Action
intentBroadcast.putExtra("parameter", "helloworld!");     // 带的参数
sendBroadcast(intentBroadcast);                           // 发送广播

同样的,也是通过跳转ContextWrapper来完成:

ContextWrapper.java

public class ContextWrapper extends Context {
    Context mBase;
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }
}

mBase对象就是一个ComtextImpl对象,这里就不作重复介绍了,直接看ComtextImpl的代码:

ContextImpl.java

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        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 e.rethrowFromSystemServer();
    }
}

ActivityManagerNative.getDefault()也不必多说了,就是ActivityManagerService,所以直接看ActivityManagerService代码:

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 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;
    }
}

final 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) {
    intent = new Intent(intent);

    // 关键代码1: 表示广播不会发送给已经停止的应用
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    ……
    if ((receivers != null && receivers.size() > 0) || resultTo != null) {
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType,
                requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId);
        ……
        boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
        if (!replaced) {
            // 关键代码2
            queue.enqueueOrderedBroadcastLocked(r);
            // 关键代码3
            queue.scheduleBroadcastsLocked();
        }
    } else {
        ……
    }
    return ActivityManager.BROADCAST_SUCCESS;
}

上述关键代码1中,表示广播不会发送给已经停止的应用。Android系统在3.1中为Intent添加了两个标记位,分别是FLAGE_INCLUDE_STOPPED_PACKGES(包含已经停止的应用,这个时候广播会发送给已停止的应用) 和 FLAG_EXCLUDE_STOPPED_PACKAGES(不包含已经停止的应用,这个时候广播不会发送给已停止的应用),用来控制广播是否要对处于停止状态的应用起作用。而从Android3.1开始所有的广播都默认添加了FLAG_EXCLUDE_STOPPED_PACKAGES标志,这样做是为了防止广播无意间或者在不必要时调起已经停止运行的应用。

请看关键代码2,这里会根据intent-filter查找出匹配的广播接收者并经过一系列的条件过滤,最终会将满足条件的广播接收者添加到BroadcastQueue中,enqueueOrderedBroadcastLocked方法代码如下:

BroadcastQueue.java

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

再来看关键代码3,这里就是广播的发送过程:

BroadcastQueue.java

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消息,来看看消息接收地方代码:

private final class BroadcastHandler extends Handler {
    ……
    @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;
           ……
        }
    }
}

消息接收地方又调用了processNextBroadcast方法:

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        ……
        // 关键代码1
        // 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);
            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);
                // 关键代码2
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            addBroadcastToHistoryLocked(r);
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast [" + mQueueName + "] " + r);
        }
      ……
}

请看关键代码1 处的注释意思是:首先,立即发送所有无序的广播。我们普通使用sendBroadcast方法发送的广播就是无序广播(我们知道广播分:普通无序广播、有序广播以及粘性广播)。可以看到无序广播存储在mParallelBroadcasts变量中,上述代码通过遍历此变量并将中其的广播发送给它们所有的接收者,具体的发送和接收过程就是通过关键代码2处调用了deliverToRegisteredReceiverLocked方法来完成:

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
    ……
    try {
        if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
            if (ordered) {
                skipReceiverLocked(r);
            }
        } else {
            // 关键代码
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
        }
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        ……
    }
}

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) {
            try {
                // 关键代码
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.repProcState);
            } catch (RemoteException ex) {
                ……
            }
        } else {
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);
    }
}

由于接收广播会调起应用程序,因为app.thread不为null,我们知道中,app.thread就是ApplicationThread,来看看它的scheduleRegisteredReceiver代码:

ActivityThread.java

private class ApplicationThread extends ApplicationThreadNative {
     ……
    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);
    }
    ……
}

关键代码插中,是通过receiverperformReceive方法来实现广播的接收,我们前面知道,receiver就是IntentReceiver对象,所以请看代码:

LoadedApk.java

static final class ReceiverDispatcher {

    final static class InnerReceiver extends IIntentReceiver.Stub {
        final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
        final LoadedApk.ReceiverDispatcher mStrongRef;
        ……
        @Override
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final LoadedApk.ReceiverDispatcher rd;
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
                rd = null;
            } else {
                rd = mDispatcher.get();
            }
            if (ActivityThread.DEBUG_BROADCAST) {
                int seq = intent.getIntExtra("seq", -1);
                Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
                        + " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
            }
            if (rd != null) {
                // 关键代码
                rd.performReceive(intent, resultCode, data, extras,
                        ordered, sticky, sendingUser);
            } else {
                ……
            }
        }
    }
    ……
}

上述关键代码处是调用了LoadedApk.ReceiverDispatcherperformReceive方法:

LoadedApk.java

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);
        }
    }
    // 关键代码2
    if (intent == null || !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);
        }
    }
}

关键代码1中,创建一个Args对象,在关键代码2处通过mActivityThread的post方法来执行Args中的逻辑。Args也是ReceiverDispatcher的内部类,它实现了Runnable接口,所以我们来看看它的代码和看看它的run方法做了啥事情:

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

        public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                boolean ordered, boolean sticky, int sendingUser) {
            super(resultCode, resultData, resultExtras,
                    mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                    sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
            mCurIntent = intent;
            mOrdered = ordered;
        }

        public void run() {
            ……
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
            try {
                // 关键代码
                ClassLoader cl =  mReceiver.getClass().getClassLoader();
                intent.setExtrasClassLoader(cl);
                intent.prepareToEnterProcess();
                setExtrasClassLoader(cl);
                receiver.setPendingResult(this);
                receiver.onReceive(mContext, intent);
            } catch (Exception e) {
                ……
            }
            
            if (receiver.getPendingResult() != null) {
                finish();
            }
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }
……

这在这里,很明显是通过类加载器获取了广播的接收类,并回调了onReceive方法。到这里整个广播的注册、发送和接收过程已经分析完。

 

 

——本文部分内容参考自《Android开发艺术探索》

猜你喜欢

转载自blog.csdn.net/lyz_zyx/article/details/83052096