日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android—Broadcast原理

發(fā)布時(shí)間:2023/12/18 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android—Broadcast原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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) {// 注冊receiver的時(shí)候可以指定接受receiver的Handler// 如果沒有指定,則默認(rèn)用主線程的handler處理scheduler = mMainThread.getHandler();}// 獲取IIntentReceiver,Binder對象,當(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)行廣播注冊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í),會在構(gòu)造函數(shù)里面創(chuàng)建一個(gè)InnerReceiver實(shí)例,這是一個(gè)Binder對象,實(shí)現(xiàn)了IIntentReceiver接口,可以通過ReceiverDispatcher.getIIntentReceiver函數(shù)來獲得,即獲取到上面的rd對象,獲得后就會把它傳給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對象,通過該對象可以獲取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對象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)程注冊的廣播接收器。接著,又把這個(gè)ReceiverList列表以receiver為Key保存在ActivityManagerService的成員變量mRegisteredReceivers中,這些都是為了方便在收到廣播時(shí),快速找到對應(yīng)的廣播接收器的。

接著創(chuàng)建一個(gè)BroadcastFilter來把廣播接收器列表rl和filter關(guān)聯(lián)起來,然后保存在ActivityManagerService中的成員變量mReceiverResolver中去。

總結(jié):廣播注冊,主要就是將廣播接收器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è)方法比較長,前面的流程是在判斷是否是系統(tǒng)的廣播,如果是系統(tǒng)的廣播,則拋出安全權(quán)限異常。對動(dòng)態(tài),靜態(tài)廣播進(jìn)行合并,獲取所有接收該廣播的廣播接收器,然后封裝到BroadcastRecord對象,并且添加到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方法也很長,是廣播調(diào)度與派發(fā)的流程。

  • 進(jìn)程在的情況下processCurBroadcastLocked
  • 進(jìn)程不在則啟動(dòng)進(jìn)程,記錄要處理的廣播mPendingBroadcast
  • final void processNextBroadcast(boolean fromMsg) {synchronized(mService) {BroadcastRecord r;.....// 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();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);}....}

    ?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里面的代碼就會調(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原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。