自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

源碼分析廣播運(yùn)行原理

移動(dòng)開發(fā) Android
在 Android 里面有各種各樣的廣播,比如電池的使用狀態(tài),電話的接收和短信的接收都會(huì)產(chǎn)生一個(gè)廣播,應(yīng)用程序開發(fā)者也可以監(jiān)聽這些廣播并做出程序邏輯的處理。

[[436974]]

前言

在 Android 里面有各種各樣的廣播,比如電池的使用狀態(tài),電話的接收和短信的接收都會(huì)產(chǎn)生一個(gè)廣播,應(yīng)用程序開發(fā)者也可以監(jiān)聽這些廣播并做出程序邏輯的處理;

今天我們就來(lái)分析下廣播的運(yùn)行機(jī)制

一、廣播原理機(jī)制詳解

1、靜態(tài)廣播注冊(cè)流程分析

  • 靜態(tài)廣播是通過(guò)PackageManagerService在啟動(dòng)的時(shí)候掃描已安裝的應(yīng)用去注冊(cè)的;
  • 在PackageManagerService的構(gòu)造方法中,會(huì)去掃描應(yīng)用安裝目錄,順序是先掃描系統(tǒng)應(yīng)用安裝目錄再掃描第三方應(yīng)用安裝目錄;

PackageManagerService.scanDirLI就是用于掃描目錄的方法:

  1. private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { 
  2.    String[] files = dir.list(); 
  3.    if (files == null) { 
  4.        return
  5.    } 
  6.    int i; 
  7.    for (i=0; i<files.length; i++) { 
  8.        File file = new File(dir, files[i]); 
  9.        if (!isPackageFilename(files[i])) { 
  10.            continue
  11.        } 
  12.        PackageParser.Package pkg = scanPackageLI(file, 
  13.                flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); 
  14.        if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && 
  15.                mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) { 
  16.            file.delete(); 
  17.        } 
  18.    } 
  19. private static final boolean isPackageFilename(String name) { 
  20.    return name != null && name.endsWith(".apk"); 
  • 可以看到,它通過(guò)File.list方法列出目錄下的所有后綴為".apk"的文件傳給scanPackageLI去處理;
  • 而scanPackageLI(File scanFile,int parseFlags, int scanMode, long currentTime, UserHandle user)內(nèi)部會(huì)調(diào)用它的重載方法;
  1. scanPackageLI(PackageParser.Package pkg,int parseFlags, int scanMode, long currentTime, UserHandle user): 
  2. private PackageParser.Package scanPackageLI(File scanFile,int parseFlags, int scanMode, long currentTime, UserHandle user) { 
  3.   ... 
  4.   final PackageParser.Package pkg = pp.parsePackage(scanFile,scanPath, mMetrics, parseFlags); 
  5.   ... 
  6.   PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); 
  7.   ... 

在這個(gè)scanPackageLIl里面會(huì)解析Package并且將AndroidManifest.xml中注冊(cè)的BroadcastReceiver保存下來(lái):

  1. ... 
  2. N = pkg.receivers.size(); 
  3. r = null
  4. for (i=0; i<N; i++) { 
  5.    PackageParser.Activity a = pkg.receivers.get(i); 
  6.    a.info.processName = fixProcessName(pkg.applicationInfo.processName, 
  7.            a.info.processName, pkg.applicationInfo.uid); 
  8.    mReceivers.addActivity(a, "receiver"); 
  9.    ... 
  10. ... 

靜態(tài)廣播的流程:

  • 系統(tǒng)應(yīng)用的廣播先于第三方應(yīng)用的廣播注冊(cè);
  • 而安裝在同一個(gè)目錄下的應(yīng)用的靜態(tài)廣播的注冊(cè)順序是按照File.list列出來(lái)的apk的順序注冊(cè)的;
  • 他們的注冊(cè)順序就決定了它們接收廣播的順序;
  • 通過(guò)靜態(tài)廣播的注冊(cè)流程,我們已經(jīng)將靜態(tài)廣播注冊(cè)到了PackageManagerService的mReceivers中;

而我們可以使用PackageManagerService.queryIntentReceivers方法查詢intent對(duì)應(yīng)的靜態(tài)廣播

  1. public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { 
  2.    if (!sUserManager.exists(userId)) return Collections.emptyList(); 
  3.    ComponentName comp = intent.getComponent(); 
  4.    if (comp == null) { 
  5.        if (intent.getSelector() != null) { 
  6.            intent = intent.getSelector(); 
  7.            comp = intent.getComponent(); 
  8.        } 
  9.    } 
  10.    if (comp != null) { 
  11.        List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); 
  12.        ActivityInfo ai = getReceiverInfo(comp, flags, userId); 
  13.        if (ai != null) { 
  14.            ResolveInfo ri = new ResolveInfo(); 
  15.            ri.activityInfo = ai; 
  16.            list.add(ri); 
  17.        } 
  18.        return list; 
  19.    } 
  20.    synchronized (mPackages) { 
  21.        String pkgName = intent.getPackage(); 
  22.        if (pkgName == null) { 
  23.            return mReceivers.queryIntent(intent, resolvedType, flags, userId); 
  24.        } 
  25.        final PackageParser.Package pkg = mPackages.get(pkgName); 
  26.        if (pkg != null) { 
  27.            return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers, 
  28.                    userId); 
  29.        } 
  30.        return null
  31.    } 

2、動(dòng)態(tài)廣播注冊(cè)流程分析

我們調(diào)用Context.registerReceiver最后會(huì)調(diào)到ActivityManagerService.registerReceiver:

  1. public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { 
  2.   ... 
  3.   ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); 
  4.   ... 
  5.   BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); 
  6.   ... 
  7.   mReceiverResolver.addFilter(bf); 
  8.   ... 

所以通過(guò)mReceiverResolver.queryIntent就能獲得intent對(duì)應(yīng)的動(dòng)態(tài)廣播了;

3、發(fā)送廣播流程分析

ContextImpl.sendBroadcast中會(huì)調(diào)用ActivityManagerNative.getDefault().broadcastIntent()

  1. public void sendBroadcast(Intent intent) { 
  2.     warnIfCallingFromSystemProcess(); 
  3.     String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); 
  4.     try { 
  5.         intent.prepareToLeaveProcess(); 
  6.         ActivityManagerNative.getDefault().broadcastIntent( 
  7.             mMainThread.getApplicationThread(), intent, resolvedType, null
  8.             Activity.RESULT_OK, nullnullnull, AppOpsManager.OP_NONE, falsefalse,getUserId()); 
  9.     } catch (RemoteException e) { 
  10.     } 

實(shí)際是調(diào)用ActivityManagerService.broadcastIntent:

  1. public final int broadcastIntent(IApplicationThread caller, 
  2.         Intent intent, String resolvedType, IIntentReceiver resultTo, 
  3.         int resultCode, String resultData, Bundle map, 
  4.         String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) { 
  5.     enforceNotIsolatedCaller("broadcastIntent"); 
  6.     synchronized(this) { 
  7.         intent = verifyBroadcastLocked(intent); 
  8.         final ProcessRecord callerApp = getRecordForAppLocked(caller); 
  9.         final int callingPid = Binder.getCallingPid(); 
  10.         final int callingUid = Binder.getCallingUid(); 
  11.         final long origId = Binder.clearCallingIdentity(); 
  12.         int res = broadcastIntentLocked(callerApp, 
  13.                 callerApp != null ? callerApp.info.packageName : null
  14.                 intent, resolvedType, resultTo, 
  15.                 resultCode, resultData, map, requiredPermission, appOp, serialized, sticky, 
  16.                 callingPid, callingUid, userId); 
  17.         Binder.restoreCallingIdentity(origId); 
  18.         return res; 
  19.     } 

調(diào)用ActivityManagerService.broadcastIntentLocked,而broadcastIntentLocked中的關(guān)鍵代碼如下:

  1. broadcastIntentLocked 
  2. // 靜態(tài)廣播 
  3. List receivers = null
  4. // 動(dòng)態(tài)廣播 
  5. List<BroadcastFilter> registeredReceivers = null
  6. if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) 
  7.       == 0) { 
  8.    // 查詢靜態(tài)廣播 
  9.    receivers = collectReceiverComponents(intent, resolvedType, users); 
  10. if (intent.getComponent() == null) { 
  11.    // 查詢動(dòng)態(tài)廣播 
  12.    registeredReceivers = mReceiverResolver.queryIntent(intent, 
  13.            resolvedType, false, userId); 
  14. final boolean replacePending = 
  15.        (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; 
  16. int NR = registeredReceivers != null ? registeredReceivers.size() : 0; 
  17. if (!ordered && NR > 0) { 
  18.    final BroadcastQueue queue = broadcastQueueForIntent(intent); 
  19.    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, 
  20.            callerPackage, callingPid, callingUid, resolvedType, requiredPermission, 
  21.            appOp, registeredReceivers, resultTo, resultCode, resultData, map, 
  22.            ordered, sticky, false, userId); 
  23.    final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); 
  24.    if (!replaced) { 
  25.        // 發(fā)送動(dòng)態(tài)廣播 
  26.        queue.enqueueParallelBroadcastLocked(r); 
  27.        queue.scheduleBroadcastsLocked(); 
  28.    } 
  29.    registeredReceivers = null
  30.    NR = 0; 
  31. ... 
  32. if ((receivers != null && receivers.size() > 0) 
  33.     || resultTo != null) { 
  34.    BroadcastQueue queue = broadcastQueueForIntent(intent); 
  35.    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, 
  36.            callerPackage, callingPid, callingUid, resolvedType, 
  37.            requiredPermission, appOp, receivers, resultTo, resultCode, 
  38.            resultData, map, ordered, sticky, false, userId); 
  39.    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); 
  40.    if (!replaced) { 
  41.        // 發(fā)送靜態(tài)廣播 
  42.        queue.enqueueOrderedBroadcastLocked(r); 
  43.        queue.scheduleBroadcastsLocked(); 
  44.    } 
  • 動(dòng)態(tài)廣播會(huì)優(yōu)先于靜態(tài)廣播,從上面的代碼我們可以看到;
  • 實(shí)際上靜態(tài)廣播靜態(tài)就是從PackageManagerService中查詢的:

  1. private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, 
  2.             int[] users) { 
  3.     ... 
  4.     List<ResolveInfo> newReceivers = AppGlobals.getPackageManager() 
  5.                         .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user); 
  6.     ... 

4、廣播隊(duì)列

  • 從ActivityManagerService.broadcastIntentLocked中我們可以看到,實(shí)際上它不是直接將廣播發(fā)送到BroadcastReceiver中;
  • 而是將他包裝到BroadcastRecord中,再放進(jìn)BroadcastQueue:
  1. BroadcastQueue queue = broadcastQueueForIntent(intent); 
  2. BroadcastRecord r = new BroadcastRecord(queue, intent, null
  3.         null, -1, -1, nullnull, AppOpsManager.OP_NONE, receivers, null, 0, 
  4.         nullnullfalsetruetrue, -1); 
  5. queue.enqueueParallelBroadcastLocked(r); 
  6. queue.scheduleBroadcastsLocked(); 
  7. enqueueParallelBroadcastLocked方法用于并發(fā)執(zhí)行廣播的發(fā)送.它很簡(jiǎn)單,就是將BroadcastRecord放到了mParallelBroadcasts中: 
  8. public void enqueueParallelBroadcastLocked(BroadcastRecord r) { 
  9.     mParallelBroadcasts.add(r); 

scheduleBroadcastsLocked方法同樣很簡(jiǎn)單,就是向mHandler發(fā)送了個(gè)BROADCAST_INTENT_MSG消息:

  1. public void scheduleBroadcastsLocked() { 
  2.    if (mBroadcastsScheduled) { 
  3.        return
  4.    } 
  5.    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); 
  6.    mBroadcastsScheduled = true

mHandler在接收到BROADCAST_INTENT_MSG消息的時(shí)候會(huì)做些什么:

  1. final Handler mHandler = new Handler() { 
  2.    public void handleMessage(Message msg) { 
  3.        switch (msg.what) { 
  4.            case BROADCAST_INTENT_MSG: { 
  5.                processNextBroadcast(true); 
  6.            } break; 
  7.            case BROADCAST_TIMEOUT_MSG: { 
  8.                synchronized (mService) { 
  9.                    broadcastTimeoutLocked(true); 
  10.                } 
  11.            } break; 
  12.        } 
  13.    } 
  14. }; 

processNextBroadcast方法用于從隊(duì)列中獲取廣播消息并發(fā)送給BroadcastReceiver,它內(nèi)部有兩個(gè)分支,并行處理和串行處理;

5、并行處理

動(dòng)態(tài)注冊(cè)的非有序廣播等就是使用并行處理:

  1. final void processNextBroadcast(boolean fromMsg) { 
  2.   synchronized(mService) { 
  3.       BroadcastRecord r; 
  4.       mService.updateCpuStats(); 
  5.       if (fromMsg) { 
  6.          mBroadcastsScheduled = false
  7.       } 
  8.       while (mParallelBroadcasts.size() > 0) { 
  9.          r = mParallelBroadcasts.remove(0); 
  10.          r.dispatchTime = SystemClock.uptimeMillis(); 
  11.          r.dispatchClockTime = System.currentTimeMillis(); 
  12.          final int N = r.receivers.size(); 
  13.          for (int i=0; i<N; i++) { 
  14.              Object target = r.receivers.get(i); 
  15.              // 發(fā)送消息給Receiver 
  16.              deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); 
  17.          } 
  18.          addBroadcastToHistoryLocked(r); 
  19.       } 
  20.       ... 
  21.    } 
  22.    ... 
  23. private final void deliverToRegisteredReceiverLocked(BroadcastRecord r, 
  24.             BroadcastFilter filter, boolean ordered) { 
  25.     ... 
  26.     // 獲取BroadcastReceiver的Binder 
  27.     r.receiver = filter.receiverList.receiver.asBinder(); 
  28.     ... 
  29.     // 使用Binder機(jī)制將消息傳遞給BroadcastReceiver 
  30.     performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, 
  31.                     new Intent(r.intent), r.resultCode, r.resultData, 
  32.                     r.resultExtras, r.ordered, r.initialSticky, r.userId); 
  33.     ... 
  34. void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, 
  35.         Intent intent, int resultCode, String data, Bundle extras, 
  36.         boolean ordered, boolean sticky, int sendingUser) throws RemoteException { 
  37.     ...... 
  38.         //通過(guò)Binder將消息處理傳到應(yīng)用進(jìn)程,應(yīng)用進(jìn)程內(nèi)部再使用Handler機(jī)制,將消息處理放到主線程中 
  39.         app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, 
  40.                         data, extras, ordered, sticky, sendingUser, app.repProcState); 
  41.     ...... 
  42.     } 

6、串行處理

有序廣播和靜態(tài)廣播等,會(huì)通過(guò)enqueueOrderedBroadcastLocked傳給BroadcastQueue:

  1. public void enqueueOrderedBroadcastLocked(BroadcastRecord r) { 
  2.    mOrderedBroadcasts.add(r); 

然后在processNextBroadcast里面會(huì)對(duì)mOrderedBroadcasts進(jìn)行特殊處理;

廣播隊(duì)列傳送廣播給Receiver的原理其實(shí)就是將BroadcastReceiver和消息都放到BroadcastRecord里面,然后通過(guò)Handler機(jī)制遍歷BroadcastQueue里面的BroadcastRecord,將消息發(fā)送給BroadcastReceiver;

二、廣播流程總結(jié)

1、Android廣播分為兩個(gè)方面:廣播發(fā)送者和廣播接收者:

  • 廣播作為Android組件間的通信方式,可以使用的場(chǎng)景如下:
  • 同一app內(nèi)部的同一組件(Component)內(nèi)的消息通信(單個(gè)或多個(gè)線程之間);
  • 同一app內(nèi)部的不同組件之間的消息通信(單個(gè)進(jìn)程);
  • 同一app具有多個(gè)進(jìn)程的不同組件之間的消息通信;
  • 不同app之間的組件之間消息通信;
  • Android系統(tǒng)在特定情況下與App之間的消息通信;

2、實(shí)現(xiàn)原理

從實(shí)現(xiàn)原理上看,Android中的廣播使用了觀察者模式,基于消息的發(fā)布/訂閱事件模型。因此,從實(shí)現(xiàn)的角度來(lái)看,Android中的廣播將廣播的發(fā)送者和接受者極大程度上解耦,使得系統(tǒng)能夠方便集成,更易擴(kuò)展。具體實(shí)現(xiàn)流程要點(diǎn)粗略概括如下:

  • 廣播接收者BroadcastReceiver通過(guò)Binder機(jī)制向AMS(Activity Manager Service)進(jìn)行注冊(cè);
  • 廣播發(fā)送者通過(guò)binder機(jī)制向AMS發(fā)送廣播;
  • AMS查找符合相應(yīng)條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發(fā)送到BroadcastReceiver相應(yīng)的消息循環(huán)隊(duì)列中;
  • 消息循環(huán)隊(duì)列拿到此廣播后,回調(diào)BroadcastReceiver中的onReceive()方法;
  • 廣播發(fā)送者和廣播接收者分別屬于觀察者模式中的消息發(fā)布和訂閱兩端,AMS屬于中間的處理中心;
  • 廣播發(fā)送者和廣播接收者的執(zhí)行是異步的,發(fā)出去的廣播不會(huì)關(guān)心有無(wú)接收者接收,也不確定接收者到底是何時(shí)才能接收到;

總結(jié)

學(xué)如逆水行舟,不進(jìn)則退。心似平原跑馬,易放難收;

本文轉(zhuǎn)載自微信公眾號(hào)「Android開發(fā)編程」

 

責(zé)任編輯:姜華 來(lái)源: Android開發(fā)編程
相關(guān)推薦

2021-08-09 11:15:28

MybatisJavaSpring

2022-04-05 12:59:07

源碼線程onEvent

2021-09-05 07:35:58

lifecycleAndroid組件原理

2020-10-10 08:20:27

Spring Boot運(yùn)行原理代碼

2021-12-06 14:52:08

動(dòng)畫Android補(bǔ)間動(dòng)畫

2019-10-16 16:33:41

Docker架構(gòu)語(yǔ)言

2018-10-31 15:54:47

Java線程池源碼

2019-09-20 08:54:38

KafkaBroker消息

2021-09-27 06:29:47

Vue3 響應(yīng)式原理Vue應(yīng)用

2014-12-11 13:37:13

WPF架構(gòu)

2018-11-14 14:33:33

MapReduce數(shù)據(jù)集計(jì)算

2020-10-21 09:11:52

Spring Boot源碼分析代碼

2010-01-25 13:56:58

Android本地廣播

2011-03-15 11:33:18

iptables

2021-08-06 08:33:27

Springboot分布式Seata

2014-08-26 11:11:57

AsyncHttpCl源碼分析

2021-08-12 07:01:23

FlutterRouter Android

2011-05-26 10:05:48

MongoDB

2024-01-18 08:31:22

go實(shí)現(xiàn)gorm框架

2021-11-11 17:40:08

WatchdogAndroid源碼分析
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)