안드로이드 브로드캐스트 리시버: 등록, 전송 및 수신 메커니즘 분석

안드로이드 브로드캐스트 리시버: 등록, 전송 및 수신 메커니즘 분석

안드로이드 운영체제에서 BroadcastReceiver는 시스템 전반에 걸쳐 발생하는 이벤트나 다른 애플리케이션이 보내는 메시지에 반응하는 핵심 컴포넌트입니다. 이 글에서는 브로드캐스트 리시버가 시스템에 어떻게 등록되고, 브로드캐스트 메시지가 전송되며, 최종적으로 리시버에서 메시지를 수신하는지 그 과정을 안드로이드 프레임워크 코드의 흐름을 통해 상세히 탐구합니다.

1. 브로드캐스트 리시버 등록 과정

BroadcastReceiver를 시스템에 등록하는 방식은 크게 두 가지로 구분됩니다. 첫 번째는 AndroidManifest.xml 파일을 통해 정적으로 선언하는 방식이고, 두 번째는 애플리케이션 코드 내에서 런타임에 동적으로 등록하는 방식입니다. 정적 등록은 애플리케이션 설치 시 PackageManagerService에 의해 처리되는데, 본 문서에서는 주로 동적 등록의 내부 작동 방식을 중점적으로 다룹니다.

동적 브로드캐스트 리시버 등록 요청

BroadcastReceiver를 동적으로 등록하려면 Context 클래스의 registerReceiver() 메서드를 호출해야 합니다. 이 호출은 ContextWrapper를 거쳐 ContextImpl의 구현으로 위임됩니다.


// frameworks/base/core/java/android/content/ContextWrapper.java
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return mBase.registerReceiver(receiver, filter);
}
    

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) {
              if (scheduler == null) {
                  scheduler = mMainThread.getHandler();
              }
              // LoadedApk로부터 ReceiverDispatcher 객체를 획득합니다.
              // 이 객체는 Binder IPC를 통해 ActivityManagerService(AMS)와 통신하는 데 사용됩니다.
              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 {
          // ActivityManagerService(AMS)에 브로드캐스트 리시버 등록을 요청합니다.
          final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                  mMainThread.getApplicationThread(), mBasePackageName,
                  rd, filter, broadcastPermission, userId);
          if (intent != null) {
              intent.setExtrasClassLoader(getClassLoader());
              intent.prepareToEnterProcess();
          }
          return intent;
      } catch (RemoteException e) {
          throw e.rethrowFromSystemServer();
      }
}
    

위 코드에서 IIntentReceiver 타입의 rd 객체 생성은 중요한 단계입니다. IIntentReceiver는 Binder 인터페이스로, 애플리케이션 프로세스와 시스템의 ActivityManagerService (AMS) 프로세스 간의 통신을 담당합니다. rd 객체는 LoadedApk.ReceiverDispatcher.InnerReceiver의 인스턴스이며, 이는 IIntentReceiver.Stub을 상속하여 Binder 통신 프로토콜을 구현합니다.


// 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;
        }
        // ... (performReceive 메서드 등)
    }
    // ...
}
    

ContextImplregisterReceiverInternal() 메서드는 최종적으로 ActivityManagerNative.getDefault().registerReceiver()를 호출하여, 실제 리시버 등록 요청과 IIntentReceiver 객체를 ActivityManagerService (AMS)로 전달합니다.

ActivityManagerService (AMS)의 리시버 정보 처리

AMSregisterReceiver() 메서드는 전달받은 리시버 정보를 내부적으로 처리합니다.


// 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) {
        // ...
        // IntentFilter에 정의된 액션 목록을 반복합니다.
        Iterator<String> actions = filter.actionsIterator();
        // ...
        // 스티키 브로드캐스트(sticky broadcast) 처리:
        // 이전에 전송되었지만 아직 유효한 스티키 브로드캐스트가 있다면 수집합니다.
        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);
                    }
                }
            }
        }
    }
    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);
            // IntentFilter와 일치하는 스티키 브로드캐스트를 최종 목록에 추가합니다.
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                allSticky.add(intent);
            }
        }
    }
    // ...       
}
    

이 부분의 코드는 IntentFilter에 정의된 액션과 사용자 ID를 기반으로 이전에 전송된 스티키 브로드캐스트(sticky broadcast)를 찾고 수집합니다. 스티키 브로드캐스트는 AMSmStickyBroadcasts 맵에 저장되어 있으며, 리시버 등록 시점에 필터와 일치하는 브로드캐스트가 있다면 즉시 리시버로 전달될 수 있도록 준비됩니다.

이어서 AMS는 등록된 리시버를 효율적으로 관리하기 위한 내부 구조를 설정합니다.


// 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) {
        // ...
        // 해당 Binder 객체에 연결된 ReceiverList를 찾거나 새로 생성합니다.
        // ReceiverList는 특정 Binder 객체(IIntentReceiver)와 관련된 모든 BroadcastFilter를 관리합니다.
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                rl.app.receivers.add(rl);
            } 
            // ...
        }
        // ...
        // BroadcastFilter 객체는 등록된 리시버와 그 IntentFilter를 캡슐화합니다.
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId);
        rl.add(bf); // ReceiverList에 BroadcastFilter를 추가합니다.
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        // mReceiverResolver에 BroadcastFilter를 추가하여,
        // 나중에 브로드캐스트가 전송될 때 이 필터를 통해 적절한 리시버를 찾을 수 있도록 합니다.
        mReceiverResolver.addFilter(bf);
        // ...
        return sticky; // 스티키 브로드캐스트가 있다면 반환
    }
}
    

이 단계에서 AMSReceiverList 객체를 생성하거나 기존 객체를 재활용하여 BroadcastReceiver 정보를 저장합니다. ReceiverListArrayList를 상속하며 여러 BroadcastFilter 객체를 관리합니다. 각 BroadcastFilter는 등록된 BroadcastReceiver와 그 IntentFilter의 매핑 정보를 포함합니다. 최종적으로 이 BroadcastFiltermReceiverResolver에 추가됩니다. mReceiverResolverAMS가 브로드캐스트를 수신했을 때, 해당 브로드캐스트를 처리할 적절한 BroadcastReceiver를 효율적으로 검색하는 데 활용됩니다.

다음은 브로드캐스트 리시버의 동적 등록 과정을 보여주는 시퀀스 다이어그램입니다.

브로드캐스트 리시버 등록 시퀀스 다이어그램

2. 브로드캐스트 전송 및 수신 과정

안드로이드 브로드캐스트는 일반(unordered) 브로드캐스트, 순서 있는(ordered) 브로드캐스트, 스티키(sticky) 브로드캐스트 등 다양한 방식으로 전송될 수 있습니다. 여기서는 일반 브로드캐스트의 전송 및 수신 과정을 중점적으로 설명합니다.

ContextImpl에서 AMS로의 브로드캐스트 전송 요청

브로드캐스트를 전송하려면 ContextsendBroadcast() 메서드를 호출해야 합니다. 이 호출은 ContextWrapper를 거쳐 ContextImplsendBroadcast() 메서드를 실행하게 됩니다.


// frameworks/base/core/java/android/content/ContextWrapper.java
@Override
public void sendBroadcast(Intent intent) {
    mBase.sendBroadcast(intent);
}
    

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);
        // ActivityManagerService (AMS)에 브로드캐스트 전송을 요청합니다.
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
    

이전 등록 과정과 유사하게, 여기에서도 ActivityManagerNative.getDefault().broadcastIntent() 호출을 통해 브로드캐스트 전송 요청이 Binder IPC를 통해 AMS로 전달됩니다.

ActivityManagerService (AMS)에서의 브로드캐스트 처리

AMSbroadcastIntent() 메서드는 전달된 Intent를 받아 처리합니다.


// 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의 유효성을 검사합니다.
          intent = verifyBroadcastLocked(intent);
          // ...
          // 실제 브로드캐스트 로직을 처리하는 broadcastIntentLocked 메서드를 호출합니다.
          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;
      }
  }
    

verifyBroadcastLocked() 메서드에서는 전송되는 Intent의 유효성을 검사합니다. 예를 들어, 잠재적으로 위험한 파일 디스크립터가 포함되어 있는지, 시스템 부팅 완료 전에 특정 플래그가 잘못 설정되었는지 등을 확인합니다.


// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final Intent verifyBroadcastLocked(Intent intent) {
    // 파일 디스크립터가 포함되어 있으면 IllegalArgumentException을 발생시킵니다.
    if (intent != null && intent.hasFileDescriptors() == true) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }
    int flags = intent.getFlags();
    if (!mProcessesReady) { // 시스템 부팅 전 상태 확인
        if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
            // 이 플래그가 설정된 경우 특별 처리
        } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            // 동적 리시버 전용이 아닌 브로드캐스트는 부팅 완료 전에는 허용하지 않습니다.
            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;
}
    

유효성 검사를 통과하면, 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) {
        // ... (생략된 부분에서는 정적 및 동적 리시버들을 찾아 'receivers' 리스트에 병합)
        if ((receivers != null && receivers.size() > 0) || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            // 브로드캐스트의 모든 정보를 담는 BroadcastRecord 객체를 생성합니다.
            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();
            }
        } 
        // ...
        return ActivityManager.BROADCAST_SUCCESS; 
    }
    

broadcastIntentLocked() 메서드에서는 시스템에 등록된 모든 브로드캐스트 리시버(정적 및 동적)를 찾아 하나의 receivers 목록으로 통합합니다. 그리고 이 모든 정보를 담아 BroadcastRecord 객체를 생성합니다. 마지막으로, 이 BroadcastRecordBroadcastQueue에 추가하고 scheduleBroadcastsLocked()를 호출하여 브로드캐스트 처리를 스케줄링합니다.

다음은 ContextImpl에서 AMS로 브로드캐스트 전송을 요청하는 과정의 시퀀스 다이어그램입니다.

브로드캐스트 전송 요청 시퀀스 다이어그램

AMS에서 BroadcastReceiver로의 메시지 전달

BroadcastQueuescheduleBroadcastsLocked() 메서드는 BROADCAST_INTENT_MSG 메시지를 BroadcastHandler 객체(mHandler)로 보냅니다.


// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
public void scheduleBroadcastsLocked() {
    // ...
    // 메시지를 핸들러로 전송하여 브로드캐스트 처리를 시작하도록 지시합니다.
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}
    

BroadcastHandler는 이 메시지를 받아 handleMessage() 메서드 내에서 processNextBroadcast()를 호출합니다.


// 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;
            // ...
        }
    }
}
    

processNextBroadcast() 메서드는 mParallelBroadcasts 큐에 저장된 일반(non-ordered) 브로드캐스트들을 순회하며 각 리시버에게 전달하는 작업을 수행합니다.


// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {
    // ...
    if (fromMsg) {
        mBroadcastsScheduled = false; // 메시지 처리가 시작되었음을 표시
    }
    // 비순차 브로드캐스트들을 즉시 전달합니다.
    while (mParallelBroadcasts.size() > 0) {
        BroadcastRecord r = mParallelBroadcasts.remove(0); // 큐에서 브로드캐스트 레코드 추출
        // ...
        for (int i=0; i<r.receivers.size(); 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);
        }
        // ...
    }
    // ...
}
    

deliverToRegisteredReceiverLocked() 메서드는 브로드캐스트를 실제로 리시버에게 전달하기 전에 권한 검사 등의 추가 작업을 수행한 후, performReceiveLocked()를 호출합니다.


// 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);
        }
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        // ... (예외 처리)
    }
}
    

performReceiveLocked() 메서드에서는 리시버가 속한 애플리케이션 프로세스가 존재하고 실행 중인 경우, 해당 프로세스 내의 ApplicationThread를 통해 브로드캐스트를 전달하도록 스케줄링합니다. 이는 Binder를 통한 프로세스 간 통신(IPC)을 통해 이루어집니다.


// 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 {
    // 단방향 바인더 호출을 사용하여 리시버에게 비동기적으로 인텐트를 전달합니다.
    if (app != null) { // 애플리케이션 프로세스가 존재하고 실행 중인 경우
        if (app.thread != null) {
            try {
                // ApplicationThread를 통해 등록된 리시버에게 브로드캐스트를 스케줄링합니다.
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.repProcState);
            } catch (Exception e) {
                // ... (예외 처리)
            }
        }
        // ...
    } else { // 애플리케이션 프로세스가 존재하지 않는 경우
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}
    

ApplicationThreadscheduleRegisteredReceiver() 메서드는 IIntentReceiver 타입 객체의 performReceive()를 호출합니다.


// 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);
     // IIntentReceiver의 performReceive 메서드를 호출하여 메시지를 전달합니다.
     receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
             sticky, sendingUser);
 }
    

IIntentReceiver 객체는 앞서 등록 과정에서 생성된 LoadedApk.ReceiverDispatcher.InnerReceiver의 인스턴스입니다. 따라서 이 인스턴스의 performReceive() 메서드가 호출됩니다.


// frameworks/base/core/java/android/app/LoadedApk.java
static final class ReceiverDispatcher {
    final static class InnerReceiver extends IIntentReceiver.Stub {
        // ...
        @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) {
                // 실제 ReceiverDispatcher의 performReceive을 호출하여 메시지를 처리합니다.
                rd.performReceive(intent, resultCode, data, extras,
                        ordered, sticky, sendingUser);
            } else {
                // ... (처리할 ReceiverDispatcher가 없는 경우)
            }
        }
    }
    // ...
}
    

ReceiverDispatcherperformReceive() 메서드는 브로드캐스트의 Intent 및 관련 정보를 Args 객체로 캡슐화한 후, mActivityThread.post(args)를 통해 애플리케이션의 메인 스레드 메시지 큐에 해당 Args 객체(Runnable을 구현)를 게시합니다.


// 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);
    // ...
    // 메인 스레드에 Args 객체(Runnable)를 게시하여 실제 onReceive 메서드를 호출하도록 합니다.
    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);
        }
    }
}
    

최종적으로, 애플리케이션의 메인 스레드에서 Args 객체의 run() 메서드가 실행되며, 여기서 등록된 BroadcastReceiveronReceive() 메서드가 호출됩니다. 이로써 브로드캐스트 메시지가 애플리케이션의 BroadcastReceiver로 성공적으로 전달됩니다.


// 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);
        // 최종적으로 BroadcastReceiver의 onReceive 메서드를 호출하여 브로드캐스트를 수신합니다.
        receiver.onReceive(mContext, intent);
    } catch (Exception e) {
        // ... (예외 처리)
    }
    // ...
}
    

다음은 AMS에서 BroadcastReceiver로 브로드캐스트를 전달하는 과정의 시퀀스 다이어그램입니다.

브로드캐스트 리시버 메시지 전달 시퀀스 다이어그램

태그: Android broadcastreceiver ActivityManagerService ipc Binder

9월 9일 22:00에 게시됨