Android 소스 코드 분석 4 대 구성 요소 시리즈 (7) - 방송의 전송 과정

35653 단어
이 글 의 목차
1. 방송 데이터 구조 분석
2. 스 레 드 전환
3. processNextBroadcast 분석
  • 3.1. 병행 방송 처리
  • 3.2, Pending 방송 처리
  • 3.3. 질서 있 는 방송 처리
  • 3.4. 다음 방송 획득
  • 3.5. 동태 방송 인지 확인
  • 3.6. 정태 방송 인지 확인
  • 3.7, 프로 세 스 시작, 전송 되 지 않 은 정적 방송 처리
  • 4. 동적 방송 수신 기 처리
    5. 정적 방송 receiver 처리
    먼저 방송의 데이터 구 조 를 파악 한 다음 에 방송의 처리 과정 을 분석 하고 있다.본문 을 볼 것 을 건의 하 는데, 먼저 앞의 두 편의 문장 을 보아 야 한다.
    Android 소스 코드 분석 - 방송의 등록 과정 Android 소스 코드 분석 - 방송의 처리 과정
    1. 방송 데이터 구조 분석
    final class BroadcastRecord extends Binder {
      
       final Intent intent;    // the original intent that generated us
       final ComponentName targetComp; // original component name set on the intent
       final ProcessRecord callerApp; //        
     
       final String[] requiredPermissions; //         
      
       final List receivers;   //       ,    BroadcastFilter   ResolveInfo
      
       IIntentReceiver resultTo; // who receives final result if non-null
       long enqueueClockTime;  //        
       long dispatchTime;      //     
       long dispatchClockTime; //    
       long receiverTime;      //     .
       long finishTime;        ////      
     
       int nextReceiver;       //         
       IBinder receiver;       //       
       int state;
       int anrCount;           //  ANR  
     
       ProcessRecord curApp;       // hosting application of current receiver.
       ComponentName curComponent; // the receiver class that is currently running.
       ActivityInfo curReceiver;   // info about the receiver that is currently running.
    
    }
    

    비교적 중요 한 데이터 구성원 은 receivers 가 있 고 저 장 된 것 은 모두 방송 수신 기 입 니 다. callerApp 은 방송 호출 자 프로 세 스 입 니 다. 또한 네 개의 시간 점 을 주의해 야 합 니 다. 대기 열, 배포, 수신, 완성 이 있 습 니 다. 또한 동적 방송 노드 는 BroadcastFilter 로 설명 하고 정적 인 ResolveInfo 로 설명 합 니 다.
  • Receiver Dispatcher: 클 라 이언 트 방송 배포 자 대상 입 니 다. 첫 번 째 편 은 분명히 말 했 습 니 다. Receiver Dispatcher 의 내부 클래스 인 Inner Receiver 는 binder 대상 으로 AMS 와 의 전달 과 통신 에 사 용 됩 니 다.
  • ReceiverList: ArrayList 를 계승 하여 Receiver 의 binder 대상 과 등 록 된 BroadcastFilter 목록 을 저장 합 니 다.AMS 에서 final HashMap mRegistered Receivers = new HashMap < > () 을 정의 합 니 다.key 는 InnerReceiver 의 binder 대상 이 고 값 은 ReceiverList 이 며 ReceiverList 내부 에 동적 으로 등 록 된 방송 수신 자 를 기록 합 니 다. mRegistered Receivers 는 동적 으로 등록 할 때 만 내용 이 있 습 니 다.
  • BroadcastFilter: IntentFilter 를 봉 하여 동적 방송 을 묘사 하고 동적 방송 노드 입 니 다.
  • ResolveInfo: Parcelable 하위 클래스 는 정적 방송 을 묘사 하고 정적 방송 노드 입 니 다.
  • Intent Resolver: Intent 를 분석 하고 addFilter 에서 분석 합 니 다.그 내부 에는 mSchemeToFilter, mAction ToFilter, mTyped Action ToFilter 세 개의 맵 대상 이 있다.key 는 대응 하 는 action (scheme 또는 type) 이 고 value 는 Filter 입 니 다.
  • BroadcastRecord: 하나의 방송 을 묘사 하고 intent 등 한 무더기 의 정 보 를 BroadcastRecord 로 봉 하여 BroadcastQueue 에 맡 겨 처리한다.
  • BroadcastQueue: BroadcastQueue 는 Broadcast 처리 대기 열 로 프론트 대기 열 mFgBroadcastQueue 와 백 스테이지 대기 열 mBgBroadcastQueue, mFgBroadcastQueue 는 더 높 은 권한 을 가지 고 우선 처 리 됩 니 다.mFgBroadcastQueue 와 mBgBroadcastQueue 두 대기 열 에는 mOrdered Broadcasts 와 mParallelBroadcasts 두 개의 목록 이 포함 되 어 있 습 니 다.

  • 2. 스 레 드 전환
    위 에 서 는 질서 있 는 방송 이 든 무질서 한 방송 이 든 점성 방송 이 든 결국 schedule Broadcasts Locked 로 처리 된다 고 말 했다.그럼 schedule Broadcasts Locked 는 뭐 했 어 요?
       public void scheduleBroadcastsLocked() {
           if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                   + mQueueName + "]: current="
                   + mBroadcastsScheduled);
    
           //mBroadcastsScheduled                        BROADCAST_INTENT_MSG  
           if (mBroadcastsScheduled) {
               return;
           }
           //    BROADCAST_INTENT_MSG  
           mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
           mBroadcastsScheduled = true;
       }
    

    mHandler 는 BroadcastQueue 의 구성원 변수 로 다음 과 같이 정의 합 니 다.
    final BroadcastHandler mHandler;
    

    이것 은 BroadcastQueue 구조 함수 에서 초기 화 됩 니 다.
      BroadcastQueue(ActivityManagerService service, Handler handler,
               String name, long timeoutPeriod, boolean allowDelayBehindServices) {
           mService = service;
           mHandler = new BroadcastHandler(handler.getLooper());
           mQueueName = name;
           mTimeoutPeriod = timeoutPeriod;
           mDelayBehindServices = allowDelayBehindServices;
       }
    

    인자 중의 handler 는 AMS 의 MainHandler 이기 때문에 BroadcastHandler 는 Activity Manager 스 레 드 의 Looper 를 사용 하기 때문에 위 를 통 해 BROADCAST 를 보 냅 니 다.INTENT_MSG 메시지, 현재 systemserver 의 binder 스 레 드 를 system 로 전환 합 니 다.server 의 Activity Manager 스 레 드 에 있 습 니 다.
       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;
                   case BROADCAST_TIMEOUT_MSG: {
                       synchronized (mService) {
                         //        
                           broadcastTimeoutLocked(true);
                       }
                   } break;
                   case SCHEDULE_TEMP_WHITELIST_MSG: {
                       DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
                       if (dic != null) {
                           dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
                                   msg.arg2, true, (String)msg.obj);
                       }
                   } break;
               }
           }
       }
    

    그래서 지금 은 프로 세 스 넥 스 트 브 로드 캐 스 트 방법 을 중점적으로 분석 하고 있 습 니 다.
    3. processNextBroadcast 분석
    process NextBroadcast 방법의 코드 는 broadcast IntentLocked 방법 과 마찬가지 로 길 기 때문에 세그먼트 로 분석 합 니 다.
    3.1 병행 방송 처리
      mService.updateCpuStats();
    
       //fromMsg        handleMessage         
       if (fromMsg) {
           //      false,             BROADCAST_INTENT_MSG        
           mBroadcastsScheduled = false;
       }
    
       //               
       while (mParallelBroadcasts.size() > 0) {
           r = mParallelBroadcasts.remove(0);
           r.dispatchTime = SystemClock.uptimeMillis();
           r.dispatchClockTime = System.currentTimeMillis();
           final int N = r.receivers.size();
           if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                   + mQueueName + "] " + r);
           for (int i=0; i

    3.2, Pending 방송 처리
    라디오 가 전송 되 고 있 을 때 프로 세 스 가 시작 되 지 않 으 면 mPendingBroadcast 에 저장 합 니 다.동적 방송 은 반드시 받 을 수 있다 는 보장 이 없 기 때문에 mPendingBroadcast 는 정적 등록 을 기다 리 고 있 는 목표 방송 수신 자가 시작 하 는 방송 을 묘사 하 는 데 사용 된다.
     // Now take care of the next serialized one...
    
       // If we are waiting for a process to come up to handle the next
       // broadcast, then do nothing at this point.  Just in case, we
       // check that the process we're waiting for still exists.
       if (mPendingBroadcast != null) {
           if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                   "processNextBroadcast [" + mQueueName + "]: waiting for "
                   + mPendingBroadcast.curApp);
    
           boolean isDead;
           //                                      
           synchronized (mService.mPidsSelfLocked) {
               ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
               isDead = proc == null || proc.crashing;
           }
                        ,      ,      
           if (!isDead) {
               // It's still alive, so keep waiting
               return;
           } else {
               Slog.w(TAG, "pending app  ["
                       + mQueueName + "]" + mPendingBroadcast.curApp
                       + " died before responding to broadcast");
               mPendingBroadcast.state = BroadcastRecord.IDLE;
               mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
               mPendingBroadcast = null;
           }
       }
       boolean looped = false;
    

    3.3 질서 있 는 방송 처리
    질서 있 는 방송 은 하나씩 처리 되 고 차단 할 수 있다.
    do {
            //       0,    ,  
            if (mOrderedBroadcasts.size() == 0) {
                // No more broadcasts pending, so all done!
                mService.scheduleAppGcsLocked();
                if (looped) {
                    // If we had finished the last ordered broadcast, then
                    // make sure all processes have correct oom and sched
                    // adjustments.
                    //    OOM
                    mService.updateOomAdjLocked();
                }
                return;
            }
            //        (    BroadcastRecord)
            r = mOrderedBroadcasts.get(0);
            boolean forceReceive = false;
    
             //      ,           
            int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
            if (mService.mProcessesReady && r.dispatchTime > 0) {
                long now = SystemClock.uptimeMillis();
                if ((numReceivers > 0) &&
                        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
                    Slog.w(TAG, "Hung broadcast ["
                            + mQueueName + "] discarded after timeout failure:"
                            + " now=" + now
                            + " dispatchTime=" + r.dispatchTime
                            + " startTime=" + r.receiverTime
                            + " intent=" + r.intent
                            + " numReceivers=" + numReceivers
                            + " nextReceiver=" + r.nextReceiver
                            + " state=" + r.state);
                     //      ,       
                    broadcastTimeoutLocked(false); // forcibly finish this broadcast
                    forceReceive = true;
                    //      。
                    r.state = BroadcastRecord.IDLE;
                }
            }
    
            if (r.state != BroadcastRecord.IDLE) {
                if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                        "processNextBroadcast("
                        + mQueueName + ") called when not idle (state="
                        + r.state + ")");
                return;
            }
             //               , :        , :     r.nextReceiver = 0,       ++,          , ++          nextReceiver,  r.nextReceiver >= numReceivers,    , :
              , :              
            if (r.receivers == null || r.nextReceiver >= numReceivers
                    || r.resultAbort || forceReceive) {
                // No more receivers for this broadcast!  Send the final
                // result if requested...
                if (r.resultTo != null) {
                    try {
                        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                                "Finishing broadcast [" + mQueueName + "] "
                                + r.intent.getAction() + " app=" + r.callerApp);
                       //        ,   onReceive()
                        performReceiveLocked(r.callerApp, r.resultTo,
                            new Intent(r.intent), r.resultCode,
                            r.resultData, r.resultExtras, false, false, r.userId);
                        // Set this to null so that the reference
                        // (local and remote) isn't kept in the mBroadcastHistory.
                        r.resultTo = null;
                    } catch (RemoteException e) {
                        r.resultTo = null;
                        Slog.w(TAG, "Failure ["
                                + mQueueName + "] sending broadcast result of "
                                + r.intent, e);
    
                    }
                }
    
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                    //r                      ,  remove    mHandler   BROADCAST_TIMEOUT_MSG  。
                cancelBroadcastTimeoutLocked();
    
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                        "Finished with ordered broadcast " + r);
    
                // ... and on to the next...
                addBroadcastToHistoryLocked(r);
                if (r.intent.getComponent() == null && r.intent.getPackage() == null
                        && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                    // This was an implicit broadcast... let's record it for posterity.
                    mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                            r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
                }
                //  r                      
                mOrderedBroadcasts.remove(0);
                //   null,       
                r = null;
                looped = true;
                continue;
            }
     } while (r == null);
    

    3.4 다음 방송 가 져 오기
      //       ,r    ,       
      int recIdx = r.nextReceiver++;
    
      // Keep track of when this receiver started, and make sure there
      // is a timeout message pending to kill it if need be.
      r.receiverTime = SystemClock.uptimeMillis();
      if (recIdx == 0) {
          r.dispatchTime = r.receiverTime;
          r.dispatchClockTime = System.currentTimeMillis();
          if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
                  + mQueueName + "] " + r);
      }
      if (! mPendingBroadcastTimeoutMessage) {
          long timeoutTime = r.receiverTime + mTimeoutPeriod;
          if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                  "Submitting BROADCAST_TIMEOUT_MSG ["
                  + mQueueName + "] for " + r + " at " + timeoutTime);
          setBroadcastTimeoutLocked(timeoutTime);
      }ComponentName component
    
      final BroadcastOptions brOptions = r.options;
      final Object nextReceiver = r.receivers.get(recIdx);
    

    3.5. 동적 방송 인지 확인
       //         
     if (nextReceiver instanceof BroadcastFilter) {
          BroadcastFilter filter = (BroadcastFilter)nextReceiver;
          if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                  "Delivering ordered ["
                  + mQueueName + "] to registered "
                  + filter + ": " + r);
         //        deliverToRegisteredReceiverLocked  
          deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
         //         
          if (r.receiver == null || !r.ordered) {
              // The receiver has already finished, so schedule to
              // process the next one.
              if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                      + mQueueName + "]: ordered="
                      + r.ordered + " receiver=" + r.receiver);
             //  r.state   IDLE,                           ,  
             //                             
              r.state = BroadcastRecord.IDLE;
          //       ,        
              scheduleBroadcastsLocked();
          } else {
              ....
          }
         //           ,      
          return;
      }
    

    3.6 정적 방송 인지 확인
     //      return,            ,            ResolveInfo
      ResolveInfo info = (ResolveInfo)nextReceiver;
      //  ComponentName      ActivityThread,    new        
      ComponentName component = new ComponentName(
              info.activityInfo.applicationInfo.packageName,
              info.activityInfo.name);
      //       ,skip     true
       boolean skip = false;
       .......
     
       String targetProcess = info.activityInfo.processName;
       ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
              info.activityInfo.applicationInfo.uid, false);
    
       if (skip) {
          if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                  "Skipping delivery of ordered [" + mQueueName + "] "
                  + r + " for whatever reason");
          r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
          r.receiver = null;
          r.curFilter = null;
      //      
          r.state = BroadcastRecord.IDLE;
      //      
          scheduleBroadcastsLocked();
          return;
       }
    
    .......
    //        ,  processCurBroadcastLocked  ,       processCurBroadcastLocked   
    if (app != null && app.thread != null) {
          try {
              app.addPackage(info.activityInfo.packageName,
                      info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
              processCurBroadcastLocked(r, app);
          //       ,      
              return;
          } catch (RemoteException e) {
              Slog.w(TAG, "Exception when sending broadcast to "
                    + r.curComponent, e);
          } catch (RuntimeException e) {
              Slog.wtf(TAG, "Failed sending broadcast to "
                      + r.curComponent + " with " + r.intent, e);
              // If some unexpected exception happened, just skip
              // this broadcast.  At this point we are not in the call
              // from a client, so throwing an exception out from here
              // will crash the entire system instead of just whoever
              // sent the broadcast.
              logBroadcastReceiverDiscardLocked(r);
              finishReceiverLocked(r, r.resultCode, r.resultData,
                      r.resultExtras, r.resultAbort, false);
              scheduleBroadcastsLocked();
              // We need to reset the state if we failed to start the receiver.
              r.state = BroadcastRecord.IDLE;
              return;
          }
    
          // If a dead object exception was thrown -- fall through to
          // restart the application.
      }
    
     //      ,       ,    startProcessLocked    ,
    if ((r.curApp=mService.startProcessLocked(targetProcess,
              info.activityInfo.applicationInfo, true,
              r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
              "broadcast", r.curComponent,
              (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                      == null) {
          // Ah, this recipient is unavailable.  Finish it if necessary,
          // and mark the broadcast record as ready for the next.
          Slog.w(TAG, "Unable to launch app "
                  + info.activityInfo.applicationInfo.packageName + "/"
                  + info.activityInfo.applicationInfo.uid + " for broadcast "
                  + r.intent + ": process is bad");
          logBroadcastReceiverDiscardLocked(r);
          finishReceiverLocked(r, r.resultCode, r.resultData,
                  r.resultExtras, r.resultAbort, false);
      //          
          scheduleBroadcastsLocked();
          r.state = BroadcastRecord.IDLE;
          return;
      }
      //    r   ,       
       mPendingBroadcast = r;
      //     receiver   ,         。
      mPendingBroadcastRecvIndex = recIdx;
    
    

    3.7 프로 세 스 를 시작 하고 보 내지 않 은 정적 방송 을 처리 합 니 다.
    프로 세 스 가 시작 되면 AMS 의 attachapplication 을 되 돌려 attachapplicationLocked 로 갑 니 다.
       // Check if a next-broadcast receiver is in this process...
          if (!badApp && isPendingBroadcastProcessLocked(pid)) {
              try {
                  didSomething |= sendPendingBroadcastsLocked(app);
              } catch (Exception e) {
                  // If the app died trying to launch the receiver we declare it 'bad'
                  Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
                  badApp = true;
              }
         }
    
    
      // The app just attached; send any pending broadcasts that it should receive
      boolean sendPendingBroadcastsLocked(ProcessRecord app) {
          boolean didSomething = false;
          for (BroadcastQueue queue : mBroadcastQueues) {
              didSomething |= queue.sendPendingBroadcastsLocked(app);
          }
          return didSomething;
      }
    
    
     public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
          boolean didSomething = false;
          final BroadcastRecord br = mPendingBroadcast;
          if (br != null && br.curApp.pid == app.pid) {
              if (br.curApp != app) {
                  Slog.e(TAG, "App mismatch when sending pending broadcast to "
                          + app.processName + ", intended target is " + br.curApp.processName);
                  return false;
              }
              try {
                  //           ,  mPendingBroadcast      null 
                  mPendingBroadcast = null;
              //  processCurBroadcastLocked    
                  processCurBroadcastLocked(br, app);
                  didSomething = true;
              } catch (Exception e) {
                  Slog.w(TAG, "Exception in new application when starting receiver "
                          + br.curComponent.flattenToShortString(), e);
                  logBroadcastReceiverDiscardLocked(br);
                  finishReceiverLocked(br, br.resultCode, br.resultData,
                          br.resultExtras, br.resultAbort, false);
                  scheduleBroadcastsLocked();
                  // We need to reset the state if we failed to start the receiver.
                  br.state = BroadcastRecord.IDLE;
                  throw new RuntimeException(e.getMessage());
              }
          }
          return didSomething;
      }
    
    

    위의 세 소절 을 보고 프로 세 스 NextBroadcast () 의 코드 논 리 를 정리 합 니 다.
  • 동적 방송 수신 자 (무질서) 라면 deliverToRegistered Receiver Locked 를 한 번 에 처리 합 니 다. 즉, 병렬 목록 (mParallelBroadcasts) 을 옮 겨 다 니 는 모든 BroadcastRecord 와 그 중의 receivers 목록 은 이중 순환 입 니 다.
  • 정적 방송 수신 자 (질서 있 음) 이 고 해당 프로 세 스 가 생 성 되 었 으 면 processCurBroadcastLocked 를 호출 하여 계속 처리 합 니 다.
  • 정적 방송 수신 자 (질서 있 음) 이 고 해당 프로 세 스 가 생 성 되 지 않 으 면 startProcessLocked 를 호출 하여 프로 세 스 를 만 들 고 그 후에 도 processCurBroadcastLocked 를 호출 하여 계속 처리 합 니 다.

  • 4. 동적 방송 수신 기 처리
    위 에 서 는 주로 동적 방송 수신 자 와 정적 방송 수신 자 를 어떻게 처리 해 야 하 는 지 분 석 했 는데 지금 은 동적 방송 이 어떻게 처리 되 는 지 먼저 본다.deliverToRegistered Receiver Locked 방법 을 분석 하여 실현 하 는 것 입 니 다.
    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
              BroadcastFilter filter, boolean ordered, int index) {
          boolean skip = false;
          //    ,            ,                  ,
      //    ,    skip==true,   return。
          ....
    
          if (skip) {
              r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
              return;
          }
    
            ....
          //              
          if (ordered) {
              r.receiver = filter.receiverList.receiver.asBinder();
              r.curFilter = filter;
              filter.receiverList.curBroadcast = r;
              r.state = BroadcastRecord.CALL_IN_RECEIVE;
              if (filter.receiverList.app != null) {
                  // Bump hosting application to no longer be in background
                  // scheduling class.  Note that we can't do that if there
                  // isn't an app...  but we can only be in that case for
                  // things that directly call the IActivityManager API, which
                  // are already core system stuff so don't matter for this.
                  r.curApp = filter.receiverList.app;
                  filter.receiverList.app.curReceiver = r;
                  mService.updateOomAdjLocked(r.curApp);
              }
          }
          try {
              if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                      "Delivering to " + filter + " : " + r);
              if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                  // Skip delivery if full backup in progress
                  // If it's an ordered broadcast, we need to continue to the next receiver.
                  if (ordered) {
                      skipReceiverLocked(r);
                  }
              } else {
              //    ,filter.receiverList.receiver       ReceiverDispatcher Binder  ——InnerReceiver
                  performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                          new Intent(r.intent), r.resultCode, r.resultData,
                          r.resultExtras, r.ordered, r.initialSticky, r.userId);
              }
              if (ordered) {
                  r.state = BroadcastRecord.CALL_DONE_RECEIVE;
              }
          } catch (RemoteException e) {
             ....
          }
      }
    
    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) {
                   try {
                       //    ActivityThread   
                       app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                               data, extras, ordered, sticky, sendingUser, app.repProcState);
                   } catch (RemoteException ex) {
                       .....
                   }
               } else {
                   // Application has died. Receiver doesn't exist.
                   throw new RemoteException("app.thread must not be null");
               }
           } else {
               //        ,      
               receiver.performReceive(intent, resultCode, data, extras, ordered,
                       sticky, sendingUser);
           }
       }
    
    
          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);
              //  ReceiverDispatcher  performReceive   InnerReceiver        
               receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                       sticky, sendingUser);
           }
    

    드디어 클 라 이언 트 의 Receiver Dispatcher (방송 배포 자) 에 도 착 했 습 니 다. Receiver Dispatcher 는 우리 방송 이 누구 에 게 나 눠 야 하 는 지 알 고 있 습 니 다.이 때 정식으로 SystemServer 프로 세 스 에서 클 라 이언 트 프로 세 스 로 돌 아 왔 습 니 다.
       @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);
           } else {
               // The activity manager dispatched a broadcast to a registered
               // receiver in this process, but before it could be delivered the
               // receiver was unregistered.  Acknowledge the broadcast on its
               // behalf so that the system's broadcast sequence can continue.
               if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                       "Finishing broadcast to unregistered receiver");
               IActivityManager mgr = ActivityManagerNative.getDefault();
               try {
                   if (extras != null) {
                       extras.setAllowFds(false);
                   }
                   mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
               } catch (RemoteException e) {
                   throw e.rethrowFromSystemServer();
               }
           }
       }
    

    ReceiverDispatcher 에서 InnerReceiver 의 performReceive 를 호출 한 후 내부 에서 ReceiverDispatcher 의 performReceive 방법 을 호출 한 다음 ReceiverDispatcher 의 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) {
                   Log.wtf(TAG, "Null intent received");
               } else {
                   if (ActivityThread.DEBUG_BROADCAST) {
                       int seq = intent.getIntExtra("seq", -1);
                       Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                               + " seq=" + seq + " to " + mReceiver);
                   }
               }
               //post         
               if (intent == null || !mActivityThread.post(args)) {
                   if (mRegistered && ordered) {
                       IActivityManager mgr = ActivityManagerNative.getDefault();
                       if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                               "Finishing sync broadcast to " + mReceiver);
                       ///          ,           。
                       args.sendFinished(mgr);
                   }
               }
           }
    

    위의 mActivity Thread 는 첫 번 째 글 에서 메 인 스 레 드 를 대표 하기 때문에 현재 args 의 run 방법 을 실행 할 것 이 라 고 말 했다.
      public void run() {
           final BroadcastReceiver receiver = mReceiver;
           final boolean ordered = mOrdered;
           
           if (ActivityThread.DEBUG_BROADCAST) {
               int seq = mCurIntent.getIntExtra("seq", -1);
               Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
                       + " seq=" + seq + " to " + mReceiver);
               Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
                       + " mOrderedHint=" + ordered);
           }
           
           final IActivityManager mgr = ActivityManagerNative.getDefault();
           final Intent intent = mCurIntent;
           if (intent == null) {
               Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
           }
    
           ......
           try {
               ClassLoader cl =  mReceiver.getClass().getClassLoader();
               intent.setExtrasClassLoader(cl);
               intent.prepareToEnterProcess();
               setExtrasClassLoader(cl);
               receiver.setPendingResult(this);
           //onReceive    
               receiver.onReceive(mContext, intent);
           } catch (Exception e) {
               .....
       }
    
    

    이에 따라 deliverToRegistered Receiver Locked 는 동적 방송 을 어떻게 처리 하 는 지 분석 했다.주요 절 차 를 총괄 하 다
    ------|-BroadcastQueue.performReceiveLocked() ------|-------|-ActivityThread.ApplicationThread.scheduleRegisteredReceiver() ------|-------|-------|- ReceiverDispatcher.InnerReceiver.performReceive() ------|-------|-------|-------|-Handler.post(args) ------|-------|-------|-------|-------|-Args.run() ------|-------|-------|-------|-------|-------|-BroadcastReceiver.onReceive()
    5. 정적 방송 receiver 처리
    방금 정적 라디오 는 프로 세 스 CurBroadcastLocked 가 처리 했다 고 했 어 요.
       private final void processCurBroadcastLocked(BroadcastRecord r,
               ProcessRecord app) throws RemoteException {
           .....
    
           r.receiver = app.thread.asBinder();
           r.curApp = app;
           app.curReceiver = r;
          //      
           app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
           //    
           mService.updateLruProcessLocked(app, false, null);
           //  adj
           mService.updateOomAdjLocked();
    
           // Tell the application to launch this receiver.         receiver
           r.intent.setComponent(r.curComponent);
    
           boolean started = false;
           try {
                 .....
               //   ActivityThread  ApplicationThread      。
               app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                       mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                       r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                       app.repProcState);
               if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                       "Process cur broadcast " + r + " DELIVERED for app " + app);
               started = true;
           } finally {
               .....
               }
            }
        }
    

    이 때 본 격 적 으로 SystemServer 프로 세 스 가 클 라 이언 트 프로 세 스 로 들 어 갔 습 니 다.
    public final void scheduleReceiver(Intent intent, ActivityInfo info,
                   CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                   boolean sync, int sendingUser, int processState) {
               updateProcessState(processState, false);
               ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                       sync, false, mAppThread.asBinder(), sendingUser);
               r.info = info;
               r.compatInfo = compatInfo;
               sendMessage(H.RECEIVER, r);
           }
    

    같은 방법 으로 메 시 지 를 메 인 스 레 드 에 보 내 고 해당 하 는 케이스 에 들 어가 handle Receiver ((ReceiverData) msg. obj) 를 실행 합 니 다.
       private void handleReceiver(ReceiverData data) {
         
          //        processNextBroadcast       ResolveInfo ,new ComponentName。
           String component = data.intent.getComponent().getClassName();
    
           LoadedApk packageInfo = getPackageInfoNoCheck(
                   data.info.applicationInfo, data.compatInfo);
    
           IActivityManager mgr = ActivityManagerNative.getDefault();
    
           BroadcastReceiver receiver;
           try {
           //   BroadcastReceiver
               java.lang.ClassLoader cl = packageInfo.getClassLoader();
               data.intent.setExtrasClassLoader(cl);
               data.intent.prepareToEnterProcess();
               data.setExtrasClassLoader(cl);
               receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
           } catch (Exception e) {
               if (DEBUG_BROADCAST) Slog.i(TAG,
                       "Finishing failed broadcast to " + data.intent.getComponent());
               data.sendFinished(mgr);
               throw new RuntimeException(
                   "Unable to instantiate receiver " + component
                   + ": " + e.toString(), e);
           }
    
           try {
               Application app = packageInfo.makeApplication(false, mInstrumentation);
    
               if (localLOGV) Slog.v(
                   TAG, "Performing receive of " + data.intent
                   + ": app=" + app
                   + ", appName=" + app.getPackageName()
                   + ", pkg=" + packageInfo.getPackageName()
                   + ", comp=" + data.intent.getComponent().toShortString()
                   + ", dir=" + packageInfo.getAppDir());
    
               ContextImpl context = (ContextImpl)app.getBaseContext();
               sCurrentBroadcastIntent.set(data.intent);
               receiver.setPendingResult(data);
           //         ,     onReceive    context RestrictedContext
               receiver.onReceive(context.getReceiverRestrictedContext(),
                       data.intent);
           } catch (Exception e) {
               if (DEBUG_BROADCAST) Slog.i(TAG,
                       "Finishing failed broadcast to " + data.intent.getComponent());
               data.sendFinished(mgr);
               if (!mInstrumentation.onException(receiver, e)) {
                   throw new RuntimeException(
                       "Unable to start receiver " + component
                       + ": " + e.toString(), e);
               }
           } finally {
               sCurrentBroadcastIntent.set(null);
           }
    
           if (receiver.getPendingResult() != null) {
               data.finish();
           }
       }
    

    정적 방송 수신 자의 처리 절 차 를 정리 합 니 다. 다음 과 같 습 니 다. 프로그램 이 시작 되 었 다 면 (app. thread!그렇지 않 으 면 --- | - LoadedApk. ReceiverDispatcher. IntentReceiver. performReceiver () ------------------------------------------------------------------------------------------------------------------------------
    이로써 방송의 처리 과정 이 끝 났 습 니 다. 다음 편 은 방송의 세부 사항 을 쓰 고 이 해 를 깊이 하 겠 습 니 다. 예 를 들 어 방송의 질 서 는 어떻게 보장 합 니까?어떻게 방송 차단 처 리 를 실현 합 니까?방송 시간 초 과 는 어떻게 처리 합 니까?onReceive 방법 중 에 라디오 를 보 내 도 되 나 요?register Receiver 방법 으로 반환 값 을 보 내 면 무슨 소 용이 있 습 니까?점성 방송 등등.

    좋은 웹페이지 즐겨찾기