Android—Broadcast原理
registerReceiver
registerReceiver方法有很多重載方法,但是最終的入口都是在ContextImpl中,
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) {// 注冊(cè)receiver的時(shí)候可以指定接受receiver的Handler// 如果沒有指定,則默認(rèn)用主線程的handler處理scheduler = mMainThread.getHandler();}// 獲取IIntentReceiver,Binder對(duì)象,當(dāng)廣播來臨時(shí),用于AMS向客戶端發(fā)起回調(diào)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 {// 通過Binder與AMS通信,進(jìn)行廣播注冊(cè)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();}}在新建廣播接收發(fā)布器ReceiverDispatcher時(shí),會(huì)在構(gòu)造函數(shù)里面創(chuàng)建一個(gè)InnerReceiver實(shí)例,這是一個(gè)Binder對(duì)象,實(shí)現(xiàn)了IIntentReceiver接口,可以通過ReceiverDispatcher.getIIntentReceiver函數(shù)來獲得,即獲取到上面的rd對(duì)象,獲得后就會(huì)把它傳給ActivityManagerService,以便接收廣播。
有兩個(gè)重要的地方:1.getReceiverDispatcher方法? ? ? 2.ActivityManager.getService().registerReceiver方法
下面分析第一個(gè)getReceiverDispatcher方法
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,Context context, Handler handler,Instrumentation instrumentation, boolean registered) {synchronized (mReceivers) {LoadedApk.ReceiverDispatcher rd = null;ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;if (registered) {map = mReceivers.get(context);if (map != null) {rd = map.get(r);}}if (rd == null) {rd = new ReceiverDispatcher(r, context, handler,instrumentation, registered);if (registered) {if (map == null) {map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();mReceivers.put(context, map);}map.put(r, rd);}} else {rd.validate(context, handler);}rd.mForgotten = false;return rd.getIIntentReceiver();}}該函數(shù)通過參數(shù)r在ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>判斷ReceiverDispatcher是否存在了,有就直接返回了,否則新建一個(gè)ReceiverDispatcher并保存。接下來是以Context,這里即為MainActivity為Key,以上面ArrayMap為值保存在LoadedApk的成員變量mReceivers中,這樣,只要給定一個(gè)Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已經(jīng)存在相應(yīng)的廣播接收發(fā)布器ReceiverDispatcher了。
所以該方法就是返回一個(gè)ReceiverDispatcher對(duì)象,通過該對(duì)象可以獲取rd實(shí)例。
ActivityManager.getService().registerReceiver方法通過Binder驅(qū)動(dòng)程序就進(jìn)入到ActivityManagerService中的registerReceiver函數(shù)中去了。下面看AMS的registerReceiver方法,rd傳入?yún)?shù)名為receiver。
public Intent registerReceiver(IApplicationThread caller, String callerPackage,IIntentReceiver receiver, IntentFilter filter, String permission, int userId,int flags) {//省略了關(guān)于粘性廣播的代碼 .....ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());if (rl == null) {//receiver封裝到一個(gè)ReceiverList對(duì)象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;}mRegisteredReceivers.put(receiver.asBinder(), rl);} //rl又封裝到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");}//bf添加到mReceiverResolver內(nèi)部的集合中了mReceiverResolver.addFilter(bf);return sticky;} }把廣播接收器receiver保存一個(gè)ReceiverList列表中,這個(gè)列表的宿主進(jìn)程是rl.app,這里就是MainActivity所在的進(jìn)程了,在ActivityManagerService中,用一個(gè)進(jìn)程記錄塊來表示這個(gè)應(yīng)用程序進(jìn)程,它里面有一個(gè)列表receivers,專門用來保存這個(gè)進(jìn)程注冊(cè)的廣播接收器。接著,又把這個(gè)ReceiverList列表以receiver為Key保存在ActivityManagerService的成員變量mRegisteredReceivers中,這些都是為了方便在收到廣播時(shí),快速找到對(duì)應(yīng)的廣播接收器的。
接著創(chuàng)建一個(gè)BroadcastFilter來把廣播接收器列表rl和filter關(guān)聯(lián)起來,然后保存在ActivityManagerService中的成員變量mReceiverResolver中去。
總結(jié):廣播注冊(cè),主要就是將廣播接收器receiver及其要接收的廣播類型filter保存在ActivityManagerService中,以便以后能夠接收到相應(yīng)的廣播并進(jìn)行處理。
sendBroadcast
ActivityManager.getService().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,getUserId());無論是有序還是無序廣播,最后都是通過該方法進(jìn)入到ActivityManagerService中的broadcastIntent函數(shù)中去。
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) {.....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;}}進(jìn)入ActivityManagerService.broadcastIntentLocked方法
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) {....... ........ queue.enqueueOrderedBroadcastLocked(r);queue.scheduleBroadcastsLocked();........ return ActivityManager.BROADCAST_SUCCESS;}內(nèi)部調(diào)用了broadcastIntentLocked方法。這個(gè)方法比較長(zhǎng),前面的流程是在判斷是否是系統(tǒng)的廣播,如果是系統(tǒng)的廣播,則拋出安全權(quán)限異常。對(duì)動(dòng)態(tài),靜態(tài)廣播進(jìn)行合并,獲取所有接收該廣播的廣播接收器,然后封裝到BroadcastRecord對(duì)象,并且添加到BroadcastQueue中。
scheduleBroadcastsLocked方法,發(fā)送了一個(gè)消息 public void scheduleBroadcastsLocked() {if (mBroadcastsScheduled) {return;}mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));mBroadcastsScheduled = true; }此處的handler的線程還是在AMS線程
public void handleMessage(Message msg) {switch (msg.what) {case BROADCAST_INTENT_MSG: {processNextBroadcast(true);} break;case BROADCAST_TIMEOUT_MSG: {synchronized (mService) {broadcastTimeoutLocked(true);}} break;}}processNextBroadcast方法也很長(zhǎng),是廣播調(diào)度與派發(fā)的流程。
?deliverToRegisteredReceiverLocked方法,主要里面調(diào)用了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);} catch (RemoteException ex) {.... }} }調(diào)用了ActivityThread的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); }這里調(diào)用了receiver的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 || !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);}} }post了一個(gè)Runnable,這個(gè)Runnable里面的代碼就會(huì)調(diào)用我們的onReceive方法。
public final Runnable getRunnable() {return () -> {final BroadcastReceiver receiver = mReceiver;final IActivityManager mgr = ActivityManager.getService();final Intent intent = mCurIntent;mCurIntent = null;mDispatched = true;mPreviousRunStacktrace = new Throwable("Previous stacktrace");try {ClassLoader cl = mReceiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess();setExtrasClassLoader(cl);receiver.setPendingResult(this);receiver.onReceive(mContext, intent);} catch (Exception e) {}}; }總結(jié)
以上是生活随笔為你收集整理的Android—Broadcast原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android—数据持久化、SP源码
- 下一篇: 遵循五大设计理念 打造出色设计师