<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      Android深入四大組件(八)廣播的注冊、發送和接收過程

      前言

      我們接著來學習Android四大組件中的BroadcastReceiver,廣播主要就是分為注冊、接收和發送過程。建議閱讀此文前請先閱讀Android深入理解四大組件系列的文章,知識重復的部分,本文不再贅述。

      1.廣播的注冊過程

      BroadcastReceiver的注冊分為兩種,分別是靜態注冊和動態注冊,靜態注冊在應用安裝時由PackageManagerService來完成注冊過程,關于這一過程,我會在后續的介紹PackageManagerService文章中詳細介紹。這里只介紹BroadcastReceiver的動態注冊。
      要想動態注冊BroadcastReceiver,需要調用registerReceiver方法,它的實現在ContextWrapper中,代碼如下所示。

      frameworks/base/core/java/android/content/ContextWrapper.java

      @Override
      public Intent registerReceiver(
          BroadcastReceiver receiver, IntentFilter filter) {
          return mBase.registerReceiver(receiver, filter);
      }
      View Code

      這里mBase具體指向就是ContextImpl,不明白的請查看Android深入四大組件(二)Service的啟動過程這篇文章。ContextImpl的registerReceiver方法有很多重載的方法最終會調用registerReceiverInternal方法:
      frameworks/base/core/java/android/app/ContextImpl.java

      private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                IntentFilter filter, String broadcastPermission,
                Handler scheduler, Context context) {
            IIntentReceiver rd = null;
            if (receiver != null) {
                if (mPackageInfo != null && context != null) {//1
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);//2
                } else {
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    rd = new LoadedApk.ReceiverDispatcher(
                            receiver, context, scheduler, null, true).getIIntentReceiver();//3
                }
            }
            try {
                final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                        mMainThread.getApplicationThread(), mBasePackageName,
                        rd, filter, broadcastPermission, userId);//4
                if (intent != null) {
                    intent.setExtrasClassLoader(getClassLoader());
                    intent.prepareToEnterProcess();
                }
                return intent;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
      View Code

      在注釋1處判斷如果LoadedApk類型的mPackageInfo不等于null并且context不等null就調用注釋2處的代碼通過mPackageInfo的getReceiverDispatcher方法獲取rd對象,否則就調用注釋3處的代碼來創建rd對象。注釋2和3的代碼的目的都是要獲取IIntentReceiver類型的rd對象,IIntentReceiver是一個Binder接口,用于進行跨進程的通信,它的具體實現在
      LoadedApk.ReceiverDispatcher.InnerReceiver,如下所示。

      frameworks/base/core/java/android/app/LoadedApk.java

      static final class ReceiverDispatcher {
            final static class InnerReceiver extends IIntentReceiver.Stub {
                final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
                final LoadedApk.ReceiverDispatcher mStrongRef;
                InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                    mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                    mStrongRef = strong ? rd : null;
                }
              ...  
             }
            ... 
       }
      View Code

      回到registerReceiverInternal方法,在注釋4處調用了ActivityManagerProxy(AMP)的registerReceiver方法,最終會調用AMS的registerReceiver方法,并將rd傳就去。不明白的同學請查看Android深入四大組件(一)應用程序啟動過程(前篇),這里不再贅述。
      查看AMS的registerReceiver方法,如下所示。
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

      public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                  IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
      ...
       synchronized(this) {
        ...
                  Iterator<String> actions = filter.actionsIterator();//1
        ...
                  // Collect stickies of users
                  int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
                  while (actions.hasNext()) {
                      String action = actions.next();
                      for (int id : userIds) {
                          ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                          if (stickies != null) {
                              ArrayList<Intent> intents = stickies.get(action);
                              if (intents != null) {
                                  if (stickyIntents == null) {
                                      stickyIntents = new ArrayList<Intent>();
                                  }
                                  stickyIntents.addAll(intents);//2
                              }
                          }
                      }
                  }
              }
        ArrayList<Intent> allSticky = null;    
              if (stickyIntents != null) {
                  final ContentResolver resolver = mContext.getContentResolver();
                  for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                      Intent intent = stickyIntents.get(i);
                      if (filter.match(resolver, intent, true, TAG) >= 0) {
                          if (allSticky == null) {
                              allSticky = new ArrayList<Intent>();
                          }
                          allSticky.add(intent);//3
                      }
                  }
              }
       ...       
      }
      View Code

      注釋1處根據傳入的IntentFilter類型的filter的得到actions列表,根據actions列表和userIds(userIds可以理解為應用程序的uid)得到所有的粘性廣播的intent,并在注釋2處傳入到stickyIntents中,在注釋3處將這些粘性廣播的intent存入到allSticky列表中,從這里可以看出粘性廣播是存儲在AMS中的。
      接著查看AMS的registerReceiver方法的剩余內容:
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

       public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                  IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
      ...
              synchronized (this) {
                ...
                  ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());//1
                  if (rl == null) {
                      rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                              userId, receiver);//2
                      if (rl.app != null) {
                          rl.app.receivers.add(rl);
                      } 
                      ...
                  }
                  ...
                  BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                          permission, callingUid, userId);//3
                  rl.add(bf);//4
                  if (!bf.debugCheck()) {
                      Slog.w(TAG, "==> For Dynamic broadcast");
                  }
                  mReceiverResolver.addFilter(bf);//5
                  ...
                  return sticky;
              }
      }
      View Code

      注釋1處獲取ReceiverList列表,如果為空則在注釋2處創建,ReceiverList繼承自ArrayList,用來存儲廣播接收者。在注釋3處創建BroadcastFilter并傳入此前創建的ReceiverList,BroadcastFilter用來描述注冊的廣播接收者,并在注釋4通過add方法將自身添加到ReceiverList中。注釋5處將BroadcastFilter添加到mReceiverResolver中,這樣當AMS接收到廣播時就可以從mReceiverResolver中找到對應的廣播接收者了。下面給出廣播的注冊過程的時序圖。

      繪圖1_副本.png繪圖1_副本.png

      2.廣播的發送和接收過程

      ContextImpl到AMS的調用過程

      廣播可以發送多種類型,包括無序廣播(普通廣播)、有序廣播和粘性廣播,這里以無序廣播為例,來講解廣播的發送過程。
      要發送無序廣播需要調用sendBroadcast方法,它的實現同樣在ContextWrapper中:
      frameworks/base/core/java/android/content/ContextWrapper.java

      @Override
        public void sendBroadcast(Intent intent) {
            mBase.sendBroadcast(intent);
        }
      View Code

      接著來看ContextImpl中的sendBroadcast方法,如下所示。
      frameworks/base/core/java/android/app/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());//1
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
      View Code

      注釋1處又是熟悉的代碼,最終會調用AMS的broadcastIntent方法:
      frameworks/base/services/core/java/com/android/server/am/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);//1
              ...
                /**
                * 2
                */
                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;
            }
        }
      View Code

      我們來查看注釋1處的verifyBroadcastLocked方法:
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

      final Intent verifyBroadcastLocked(Intent intent) {
             // Refuse possible leaked file descriptors
             if (intent != null && intent.hasFileDescriptors() == true) {//1
                 throw new IllegalArgumentException("File descriptors passed in Intent");
             }
             int flags = intent.getFlags();//2
             if (!mProcessesReady) {
                 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {//3
                 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {//4
                     Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
                             + " before boot completion");
                     throw new IllegalStateException("Cannot broadcast before boot completed");
                 }
             }
             if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
                 throw new IllegalArgumentException(
                         "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
             }
             return intent;
         }
      View Code

      verifyBroadcastLocked方法主要是驗證廣播是否合法,在注釋1處驗證intent是否不為null并且有文件描述符。注釋2處獲得intent中的flag。注釋3處如果系統正在啟動過程中,判斷如果flag設置為FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT(啟動檢查時只接受動態注冊的廣播接收者)則不做處理,如果不是則在注釋4處判斷如果flag沒有設置為FLAG_RECEIVER_REGISTERED_ONLY(只接受動態注冊的廣播接收者)則會拋出異常。
      我們再回到broadcastIntent方法,在注釋2處調用了broadcastIntentLocked方法,代碼如下所示。
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

       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) {
        ...
             if ((receivers != null && receivers.size() > 0)
                      || resultTo != null) {
                  BroadcastQueue queue = broadcastQueueForIntent(intent);
                  /**
                  * 1
                  */
                  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) {
                      queue.enqueueOrderedBroadcastLocked(r);
                      queue.scheduleBroadcastsLocked();//2
                  }
              } 
              ...
              }
              return Act
      View Code

      這里省略了很多代碼,前面的工作主要是將動態注冊的廣播接收者和靜態注冊的廣播接收者按照優先級高低存儲在不同的列表中,再將這兩個列表合并到receivers列表中,這樣receivers列表包含了所有的廣播接收者(無序廣播和有序廣播)。在注釋1處創建BroadcastRecord對象并將receivers傳進去,在注釋2處調用BroadcastQueue的scheduleBroadcastsLocked方法。
      這里先給出ContextImpl到AMS的調用過程的時序圖。

      繪圖8_副本.png繪圖8_副本.png

      AMS到BroadcastReceiver的調用過程

      BroadcastQueue的scheduleBroadcastsLocked方法的代碼如下所示。
      frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

      public void scheduleBroadcastsLocked() {
      ...
          mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));//1
          mBroadcastsScheduled = true;
      }
      View Code

      在注釋1處向BroadcastHandler類型的mHandler對象發送了BROADCAST_INTENT_MSG類型的消息,這個消息在BroadcastHandler的handleMessage方法中進行處理,如下所示。
      frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

      private final class BroadcastHandler extends Handler {
          public BroadcastHandler(Looper looper) {
              super(looper, null, true);
          }
          @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;
             ...
              }
          }
      }
      View Code

      在handleMessage方法中調用了processNextBroadcast方法,processNextBroadcast方法對無序廣播和有序廣播分別進行處理,旨在將廣播發送給廣播接收者,下面給出processNextBroadcast方法中對無序廣播的處理部分。
      frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

      final void processNextBroadcast(boolean fromMsg) {
      ...
                if (fromMsg) {
                    mBroadcastsScheduled = false;//1
                }
                // First, deliver any non-serialized broadcasts right away.
                while (mParallelBroadcasts.size() > 0) {//2
                    r = mParallelBroadcasts.remove(0);//3
                   ...
                    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);//4
                    }
               ...
                }
      }
      View Code

      從前面的代碼我們得知fromMsg的值為true,因此注釋1處會將mBroadcastsScheduled 設置為flase,表示對于此前發來的BROADCAST_INTENT_MSG類型的消息已經處理了。注釋2處的mParallelBroadcasts列表用來存儲無序廣播,通過while循環將mParallelBroadcasts列表中的無序廣播發送給對應的廣播接收者。在注釋3處獲取每一個mParallelBroadcasts列表中存儲的BroadcastRecord類型的r對象。注釋4處將這些r對象描述的廣播發送給對應的廣播接收者,deliverToRegisteredReceiverLocked方法如下所示。
      frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

      private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
              BroadcastFilter filter, boolean ordered, int index) {
      ...
         try {
                  if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                          "Delivering to " + filter + " : " + r);
                  if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                   ...   
                  } else {
                      performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                              new Intent(r.intent), r.resultCode, r.resultData,
                              r.resultExtras, r.ordered, r.initialSticky, r.userId);//1
                  }
                  if (ordered) {
                      r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                  }
              } catch (RemoteException e) {
       ...
              }
      
      }
      View Code

      這里省去了大部分的代碼,這些代碼是用來檢查廣播發送者和廣播接收者的權限。如果通過了權限的檢查,則會調用注釋1處的performReceiveLocked方法:
      frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

      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) {//1
                if (app.thread != null) {//2
                    // 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);//3          
                    } 
                } 
                ...
            } else {
                receiver.performReceive(intent, resultCode, data, extras, ordered,
                        sticky, sendingUser);/
            }
        }
      View Code

      注釋1和2處的代碼表示如果廣播接收者所在的應用程序進程存在并且正在運行,則執行注釋3處的代碼,表示用廣播接收者所在的應用程序進程來接收廣播,這里app.thread指的是ApplicationThread,我們來查看ApplicationThread的scheduleRegisteredReceiver方法,代碼如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      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);//1
       }
      View Code

      注釋1處調用了IIntentReceiver類型的對象receiver的performReceive方法,這里實現receiver的類為LoadedApk.ReceiverDispatcher.InnerReceiver,代碼如下所示。
      frameworks/base/core/java/android/app/LoadedApk.java

      static final class ReceiverDispatcher {
              final static class InnerReceiver extends IIntentReceiver.Stub {
              ...
                  InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                      mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                      mStrongRef = strong ? rd : null;
                  }
                  @Override
                  public void performReceive(Intent intent, int resultCode, String data,
                          Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                      final LoadedApk.ReceiverDispatcher rd;
                      ...
                      if (rd != null) {
                          rd.performReceive(intent, resultCode, data, extras,
                                  ordered, sticky, sendingUser);//1
                      } else {
                   ...
                  }
      ...
      }
      View Code

      在注釋1處調用了ReceiverDispatcher類型的rd對象的performReceive方法:
      frameworks/base/core/java/android/app/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);//1
                ...
                if (intent == null || !mActivityThread.post(args)) {//2
                    if (mRegistered && ordered) {
                        IActivityManager mgr = ActivityManagerNative.getDefault();
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing sync broadcast to " + mReceiver);
                        args.sendFinished(mgr);
                    }
                }
      View Code

      在注釋1處將廣播的intent等信息封裝為Args對象,并在注釋2處調用mActivityThread的post方法并傳入了Args對象。這個mActivityThread是一個Handler對象,具體指向的就是H,注釋2處的代碼就是將Args對象通過H發送到主線程的消息隊列中。Args繼承自Runnable,這個消息最終會在Args的run方法執行,Args的run方法如下所示。

      frameworks/base/core/java/android/app/LoadedApk.java

      public void run() {
        ...
           try {
               ClassLoader cl =  mReceiver.getClass().getClassLoader();
               intent.setExtrasClassLoader(cl);
               intent.prepareToEnterProcess();
               setExtrasClassLoader(cl);
               receiver.setPendingResult(this);
               receiver.onReceive(mContext, intent);//1
           } catch (Exception e) {
              ...
           }
          ...
       }
      View Code

      在注釋1處執行了廣播接收者的onReceive方法,這樣注冊的廣播接收者就收到了廣播并得到了intent。
      廣播的注冊、發送和接收過程就講到這,最后給出剩余部分的調用時序圖。
      繪圖17.png

       

      posted on 2018-03-18 20:50  安卓筆記俠  閱讀(1452)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 亚洲国产成人无码影片在线播放| 国产一区二区三区小说| 久色伊人激情文学你懂的| 国产女同疯狂作爱系列| 亚洲精品免费一二三区| 午夜福利视频| 国产精品区一二三四久久| 在线看无码的免费网站| 高清| 中文无码vr最新无码av专区| 中国女人熟毛茸茸A毛片| 亚洲肥熟女一区二区三区| 国内自拍小视频在线看| 内射干少妇亚洲69xxx| 国产成人99亚洲综合精品| 五月综合网亚洲乱妇久久| 成人看的污污超级黄网站免费| 亚洲综合在线一区二区三区| 久久99日韩国产精品久久99| 亚洲人成网站在线播放动漫| 亚洲国产一区二区三区四| 国产精品成| 日本内射精品一区二区视频| 一本色道久久东京热| 国产精品成人观看视频国产奇米 | 亚洲欧洲日韩国内高清| аⅴ天堂国产最新版在线中文| 国产高清不卡视频| 中文字幕人妻精品在线| 亚洲天堂成年人在线视频| 国产精品亚洲аv无码播放| 在线精品视频一区二区| 色猫咪av在线网址| 亚洲精品无码乱码成人| 精品久久久bbbb人妻| 国产中文三级全黄| 久久国产精品成人免费| 国产午夜精品亚洲精品国产| 色欲综合久久中文字幕网| 婷婷四房综合激情五月在线| 色综合久久一区二区三区|