日韩性视频-久久久蜜桃-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ò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 伊人久久影视 | 超碰精品在线 | 国产又粗又猛又爽又黄的视频在线观看动漫 | 中文字幕在线观看免费视频 | 一区二区免费在线观看视频 | va婷婷在线免费观看 | 先锋成人 | 污网站在线观看免费 | 国产成人av一区二区三区不卡 | 成人短视频在线观看 | 午夜诱惑痒痒网 | 男人操女人下面视频 | jizz一区二区三区 | 国产无人区码熟妇毛片多 | 97爱视频 | 欧美日韩69 | 久久情趣视频 | 日本午夜一区二区三区 | 9999在线视频 | 色吧久久| 扒开腿揉捏花蒂h | 亚洲激情视频在线 | 黄色成人毛片 | 玖玖热在线视频 | 久久大香 | 91网站永久免费看nba视频 | 色呦呦中文字幕 | a级免费观看 | 欧美乱欲视频 | 久久精品2019中文字幕 | 精品国产一区二区三区久久久 | 在线精品一区 | 欧美日韩大片在线观看 | 毛片亚洲av无码精品国产午夜 | 欧美日韩在线观看一区二区三区 | 高清乱码免费网 | 日韩一区在线播放 | 超碰97在线播放 | 秋霞午夜网 | 成人国产精品免费观看动漫 | 97久久国产亚洲精品超碰热 | 午夜精品一区二区三区在线 | 日韩中文无 | 精品人妻少妇嫩草av无码 | 校园春色欧美 | 在线播放无码后入内射少妇 | 日韩电影一区二区在线观看 | 国产乱论| 免费的黄色av | 献给魔王伊伏洛基亚吧动漫在线观看 | 夫妻淫语绿帽对白 | 熟女肥臀白浆大屁股一区二区 | 日日噜夜夜噜 | 三女同志亚洲人狂欢 | 国产精品国产三级国产专播品爱网 | 精品麻豆av | 亚洲一级片网站 | 日韩精品无码一区二区 | 亚洲xx网站 | 亚洲一区二区av在线 | 黑人巨大国产9丨视频 | 桃色网址 | 在线中文字幕av | 亚洲一区二区免费看 | 最新黄色av网址 | 天天色天天干天天 | 肉丝肉足丝袜一区二区三区 | 成年人黄色片 | 91精品国产麻豆 | 日韩色道 | 成人免费看av | 在线观看日韩一区 | 无码无套少妇毛多18pxxxx | 69精品国产 | 亚洲国产三区 | 久久老司机 | 男男做性免费视频网 | 国产乱淫av免费 | 三级少妇 | www.日韩视频| 国产高清不卡一区 | 下面一进一出好爽视频 | av收藏小四郎最新地址 | 亚洲激情视频在线观看 | 男人狂揉女人下部视频 | 一区二区三区免费毛片 | 粗大的内捧猛烈进出在线视频 | 成年人视频在线观看免费 | 日本三级精品 | 亚洲精品aⅴ | 国产女在线| 蜜桃tv在线观看 | 超碰日日夜夜 | 日韩va中文 | 亚洲国产欧美精品 | 亚洲一区二区三区四区在线播放 | 香蕉久久久久久久av网站 | 白白色免费视频 | 国产欧美日韩高清 |