Android8.0.0-r4 - broadcast registration, sending and receiving process

Original URL: https://blog.csdn.net/itachi85/article/details/71629201

1. Broadcast registration process

The registration of BroadcastReceiver is divided into two types, namely static registration and dynamic registration. Static registration is completed by PackageManagerService when the application is installed. I will introduce this process in detail in the subsequent articles on PackageManagerService. Only the dynamic registration of BroadcastReceiver is introduced here. 
To dynamically register BroadcastReceiver, you need to call the registerReceiver method, which is implemented in ContextWrapper, and the code is as follows.

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

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

Here mBase specifically points to ContextImpl. If you don't understand, please refer to the article Android In-depth Four Components (2) Startup Process of Service . The registerReceiver method of ContextImpl has many overloaded methods that will eventually call the registerReceiverInternal method: 
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();
        }

Judging at note 1, if the mPackageInfo of LoadedApk type is not equal to null and the context is not equal to null, call the code at note 2 to obtain the rd object through the getReceiverDispatcher method of mPackageInfo, otherwise call the code at note 3 to create the rd object. The purpose of the code in comments 2 and 3 is to obtain the rd object of type IIntentReceiver. IIntentReceiver is a Binder interface used for cross-process communication. Its specific implementation is 
LoadedApk.ReceiverDispatcher.InnerReceiver, as shown below.

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

Going back to the registerReceiverInternal method, the registerReceiver method of ActivityManagerProxy (AMP) is called at comment 4, and finally the registerReceiver method of AMS will be called, and the rd will be passed. For students who don't understand, please check Android In-depth Four Components (1) Application Startup Process (Part 1) , which will not be repeated here. 
Check out the registerReceiver method of AMS as shown below. 
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
                }
            }
        }
 ...       
}

At note 1, the list of actions is obtained according to the incoming filter of IntentFilter type, and all the intents of sticky broadcast are obtained according to the list of actions and userIds (userIds can be understood as the uid of the application), and passed into stickyIntents at note 2, At note 3, the intents of these sticky broadcasts are stored in the allSticky list, from which we can see that sticky broadcasts are stored in AMS. 
Then look at the rest of AMS's registerReceiver method: 
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;
        }
}

Get the ReceiverList list at Note 1, and create it at Note 2 if it is empty. ReceiverList inherits from ArrayList and is used to store broadcast receivers. Create a BroadcastFilter at note 3 and pass in the previously created ReceiverList. BroadcastFilter is used to describe the registered broadcast receiver, and at note 4, it adds itself to the ReceiverList through the add method. Add BroadcastFilter to mReceiverResolver in Note 5, so that when AMS receives the broadcast, it can find the corresponding broadcast receiver from mReceiverResolver. The sequence diagram of the registration process of the broadcast is given below.

drawing1_copy.png

2. Broadcast sending and receiving process

The calling process of ContextImpl to AMS

There are many types of broadcasts that can be sent, including unordered broadcasts (normal broadcasts), ordered broadcasts, and sticky broadcasts. Here, we take unordered broadcasts as an example to explain the sending process of broadcasts. 
To send out-of-order broadcasts, you need to call the sendBroadcast method, which is also implemented in ContextWrapper: 
frameworks/base/core/java/android/content/ContextWrapper.java

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

Then look at the sendBroadcast method in ContextImpl, as shown below. 
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();
        }
    }

Note 1 is another familiar code, which will eventually call the broadcastIntent method of AMS: 
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;
        }
    }

Let's look at the verifyBroadcastLocked method at note 1: 
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;
    }

The verifyBroadcastLocked method is mainly to verify whether the broadcast is legal, and to verify whether the intent is not null and has a file descriptor at Note 1. Get the flag in the intent at note 2. In Note 3, if the system is in the process of starting up, judge that if the flag is set to FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT (only dynamically registered broadcast receivers are accepted when starting the check), no processing will be performed. If not, judge in Note 4 if the flag is not set to FLAG_RECEIVER_REGISTERED_ONLY (only accepting dynamically registered broadcast receivers) will throw an exception. 
We go back to the broadcastIntent method and call the broadcastIntentLocked method at comment 2, the code is as follows. 
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 ActivityManager.BROADCAST_SUCCESS;
}

A lot of code is omitted here. The previous work is mainly to store the dynamically registered broadcast receivers and the statically registered broadcast receivers in different lists according to their priorities, and then merge these two lists into the receivers list, so that the receivers The list contains all broadcast receivers (out-of-order and in-order). Create a BroadcastRecord object at annotation 1 and pass receivers in, and call the scheduleBroadcastsLocked method of BroadcastQueue at annotation 2. 
Here is the sequence diagram of the calling process from ContextImpl to AMS.

drawing8_copy.png

The calling process of AMS to BroadcastReceiver

The code of the scheduleBroadcastsLocked method of BroadcastQueue is shown below. 
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;
}

At note 1, a message of type BROADCAST_INTENT_MSG is sent to the mHandler object of type BroadcastHandler, which is processed in the handleMessage method of BroadcastHandler, as shown below. 
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;
       ...
        }
    }
}

在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
                }
           ...
            }
  }

从前面的代码我们得知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) {
 ...
        }

}

这里省去了大部分的代码,这些代码是用来检查广播发送者和广播接收者的权限。如果通过了权限的检查,则会调用注释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);/
        }
    }

注释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
    }

注释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 {
             ...
            }
...
}

在注释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);
                }
            }
        }

在注释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) {
           ...
        }
       ...
    }

The onReceive method of the broadcast receiver is executed at Note 1, so that the registered broadcast receiver receives the broadcast and gets the intent. 
This is the process of registration, sending and receiving of broadcasts, and finally the call sequence diagram of the remaining parts is given. 
Drawing 17.png


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325647992&siteId=291194637