preface

We know that the general Android engineers are in the application layer development, will not involve system source code, but if you want to go to the bottom, or in-depth plug-in, Framework system layer development work, if you do not understand Android source code but not, So the next I based on their own understanding and learning to record with Android development is closely related to the source analysis, probably from the Android SystemServer start, four components start, AMS, PMS and other dimensions to introduce, the following is my plan, of course, may change in the future.

If you haven’t paid attention to it yet, you can pay attention to it first. The series of articles will be updated continuously.

Android 8.0 source code analysis (a) SystemServer process started

Android 8.0 source code analysis (ii) Launcher

Android 8.0 source code analysis (three) application process creation to the application startup process

Android 8.0 source code analysis (four) Activity start

Android 8.0 source code analysis (5) Service startup

Android 8.0 source code analysis (6) BroadcastReceiver launch

Android 8.0 source code analysis (seven) ContentProvider start

ActivityManagerService

Android 8.0 source code analysis (nine) WindowManager

Android 8.0 source code analysis (ten) WindowManagerService window management

introduce

As one of the four components, broadcast is not used as frequently as Activity, but it is also used in a wide range of scenarios, such as monitoring startup, screen light, sending messages between components or processes, etc. Next, we will introduce the working process of broadcasting, from the three points of registration, sending and receiving.

Source code analysis

The registration process for broadcasts

The registration of broadcast is divided into static and dynamic registration, static registration needs to parse the Android manifest file through PMS and so on complex operations, here we explain to dynamic registration broadcast. Let’s take a look at the registration sequence diagram:

To use a broadcast, you need to register a broadcast using the registerReceiver method, which is also implemented in ContextWrapper, the parent class of the Activity.

//ContextWrapper.java
		/** * Apply the call to register the broadcast function *@param receiver The BroadcastReceiver to handle the broadcast.
     * @param filter Selects the Intent broadcasts to be received.
     *
     * @return* /
    @Override
    public Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) {
        //mBase is a reference to Context
        return mBase.registerReceiver(receiver, filter);
    }
Copy the code

We in the interpretation of the Android 8.0 source code analysis (5) the Service started, first introduced the Activity, the Context, the relationship between the ContextImpl, here not much said, have not understand can go to have a look at last an article. ContextImpl (ContextImpl); ContextImpl (ContextImpl);

    /** * Context calls *@param receiver The BroadcastReceiver to handle the broadcast.
     * @param filter Selects the Intent broadcasts to be received.
     *
     * @return* /
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        // Call the internal overloaded method
        return registerReceiver(receiver, filter, null.null);
    }



    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
        // Call the internal overloaded method
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    }


    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                                            IntentFilter filter, String broadcastPermission,
                                            Handler scheduler, Context context, int flags) {
        IIntentReceiver rd = null;
        if(receiver ! =null) {
            / * * * 1 * /
            if(mPackageInfo ! =null&& context ! =null) {
                if (scheduler == null) {
                    // Get ActivityThread H
                    scheduler = mMainThread.getHandler();
                }
                // Get the IIntentReceiver object, which interacts with AMS and passes messages through a Handler
                rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        / * * * 2. * /
                        mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                / * * * 3. * /
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null.true).getIIntentReceiver(); }}try {
            // Call AMS registerReceiver
            4 / * * * * /
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            if(intent ! =null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throwe.rethrowFromSystemServer(); }}Copy the code

Note 1 to check whether mPackageInfo and context are empty. If they are not, note 2 will execute the code. Call the getReceiverDispatch method via the mPackageInfo method to get the RD object, otherwise call the code in Note 3 to create the RD object. This step 2 code is mainly to obtain IIntentReceiver object, it is a Binder interface, across processes for radio communication, it in LoadedApk. ReceiverDispatcher. InnerReceiver implemented, the code is as follows:

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

Back to the registerReceiverInternal method, call the registerReceiver method of the AMS proxy class IActivityManager at comment 4, Through interprocess communication, the AMS class registerReceiver method is finally passed into AMS with the RD reference of the IIntentReceiver type. The BroadcastReceiver is not passed directly to the client, but to the IIntetnReceiver, because registering broadcast is a cross-process process, which requires an IIntentReceiver with cross-process communication function. You can also think of it as an intermediary. There are many internal registerReceiver methods, which are divided into two parts to explain. First, let’s look at Part1, the code is as follows:

1. Part1 of the registerReceiver method

//AMS.java
    /** * this is called with Binder notification *@return Intent
     */
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        enforceNotIsolatedCaller("registerReceiver");
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        final booleanvisibleToInstantApps = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) ! =0;
        int callingUid;
        int callingPid;
        boolean instantApp;
        synchronized(this) {
            if(caller ! =null) {
                /** * 1. Get the callerApp object of type ProcessRecord using the getRecordForAppLocked method
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid()
                            + ") when registering receiver " + receiver);
                }
                if(callerApp.info.uid ! = SYSTEM_UID && ! callerApp.pkgList.containsKey(callerPackage) && !"android".equals(callerPackage)) {
                    throw new SecurityException("Given caller package " + callerPackage
                            + " is not running in process " + callerApp);
                }
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }

            instantApp = isInstantApp(callerApp, callerPackage, callingUid);
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            /** * 2. Get an action list */ based on the filter of type IntentFilter passed in
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Collect stickies of users
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                
                String action = actions.next();
                for (int id : userIds) {
                    // Get all the sticky broadcast intents from the actions list and userIds and pass them into stickyIntents at comment 3
                    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>();
                            }
                            /** * 3. Store the matched sticky broadcast action in the container */
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        ArrayList<Intent> allSticky = null;
        if(stickyIntents ! =null) {
            final ContentResolver resolver = mContext.getContentResolver();
            // Look for any matching sticky broadcasts...
            /** * traverse to find matching sticky broadcasts */
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                // Don't provided intents that aren't available to instant apps.
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                // Start matching
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    /** * 4. Insert the intent into the allSticky list */allSticky.add(intent); }}}...// the following code is explained in part2

            returnsticky; }}Copy the code

Get the callerApp object of type ProcessRecord from the getRecordForAppLocked method in comment 1, which describes the application process where the Activity that asked AMS to register the broadcast receiver is located. In comment 2, get a list of actions based on the filter of type IntentFilter passed in, Get all of the sticky broadcast intents from the actions list and userIds and pass them into stickyIntents in comment 3. Next, sticky broadcast intents that match the filter passed in from stickyIntent are stored in the allSticky list in comment 4.

Part2 of the registerReceiver method

The rest of AMS’s registerReceiver method looks like this:

//AMS.java

    /** * this is called with Binder notification *@return Intent
     */
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {...synchronized (this) {...1. Obtain ReceiverList */
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {// Note 2 for air conditioning
                /** * 2. Create a ReceiverList object, which inherits from ArrayList and is used to store broadcast receivers */
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if(rl.app ! =null) {
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if(rl.uid ! = callingUid) { ... }/** * 3. Build the BroadcastFilter object and add the BroadcastFilter ReceiverList to the BroadcastFilter object
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            /** * 4. Add itself to the list of broadcast receivers */
            rl.add(bf);
            if(! bf.debugCheck()) { Slog.w(TAG,"==> For Dynamic broadcast");
            }
            /** * 5. Add BroadcastFilter to mReceiverResolver of type IntentResolver. * /mReceiverResolver.addFilter(bf); . }Copy the code

The ReceiverList list is obtained in comment 1. If it is empty, a new ReceiverList object is created in comment 2, which inherits from ArrayList and is used to store broadcast receivers. Create BroadcastFilter at comment 3 and pass in the previously created ReceiverList, which describes registered broadcast receivers, and add itself to the ReceiverList with the add method at comment 4. Add BroadcastFilter to the mReceiverResolver of type IntentResolver at comment 5 so that when AMS receives a broadcast it can find the corresponding broadcast receiver from the mReceiverResolver. So as to achieve the purpose of registering broadcast.

The sending and receiving of a broadcast

Broadcast sending and receiving is divided into two stages to analyze, through the application process to AMS SystemServer process call, and then AMS in the process of notifying the application process call, let’s first analyze the application process to AMS process.

ContextImpl call to AMS

Broadcast sends various types of broadcast, such as disordered, ordered and sticky broadcast. Here, the simplest broadcast disordered broadcast is explained, that is, to send a normal broadcast, which is also implemented in ContextWrapper.

ContextWrapper’s sendBroadcast method is as follows:

//ContextWrapper.java
    @Override
    public void sendBroadcast(Intent intent) {
      	// Call the implementation class of the Context ContextImpl
        mBase.sendBroadcast(intent);
    }
Copy the code

ContextImpl (ContextImpl); ContextImpl (ContextImpl); mBase (ContextImpl); mBase (ContextImpl);

//ContextImpl.java
    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null.null.null, AppOpsManager.OP_NONE, null.false.false,
                    getUserId());
        } catch (RemoteException e) {
            throwe.rethrowFromSystemServer(); }}Copy the code

It calls the broadcastIntent function of AMS’s proxy class IActivityManager, We found that the way of calling Activity and Service as we explained before will go through the proxy class IActivityManager of AMS. Then what is AMS? We will introduce this separately after we explain the four components. Let’s look directly at the IMPLEMENTATION of AMS:

//AMS.java

    /** * application process calls *@param caller
     * @param intent
     * @param resolvedType
     * @param resultTo
     * @param resultCode
     * @param resultData
     * @param resultExtras
     * @param requiredPermissions
     * @param appOp
     * @param bOptions
     * @param serialized
     * @param sticky
     * @param userId
     * @return* /
    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) {
            /** * 1. Verify whether the broadcast is valid */
            intent = verifyBroadcastLocked(intent);
            /** * get the process */
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            / * * * 2. * /
            intres = 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);
            returnres; }}Copy the code

Let’s start with comment 1 to internally validate the broadcast code implementation:

//AMS.java

    final Intent verifyBroadcastLocked(Intent intent) {
        // Refuse possible leaked file descriptors
        /** * 1. Verify that the intent is not null and has a file descriptor */
        if(intent ! =null && intent.hasFileDescriptors() == true) {... }/** * 2. Get the intent flags */
        int flags = intent.getFlags();

        if(! mProcessesReady) {/** * 3. The system is being started. If it is a dynamic broadcaster, no processing is done */
            if((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) ! =0) {
                
                /** * 4. If flag is not set to FLAG_RECEIVER_REGISTERED_ONLY Only dynamically registered broadcast receivers are accepted, an exception is thrown */
            } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {... }}...return intent;
    }
Copy the code

Abstract IntEnts are not valid for an Intent. They are not valid for an Intent.

//AMS.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) {.../** * 1. Create the BroadcastRecord object and send it to receivers. * /
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);
      
                  final booleanreplaced = replacePending && (queue.replaceParallelBroadcastLocked(r) ! =null);
           
            if(! replaced) { queue.enqueueParallelBroadcastLocked(r);/ * * * 2. * /
                // Handle broadcast distribution
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0; }... }Copy the code

Note 1 omits a lot of code, such as storing registered dynamic/static broadcast receivers in different lists according to their priority, and merging the two lists into the receivers list so that the receivers list includes all receivers. Create the BroadcastReceiver object at comment 1 and pass it into receivers. Call the scheduleBroadcastsLocked method of The BroadcastQuque at comment 2.

AMS to BroadcastReceiver call process

AMS calls BroadcastReceiver (BroadcastReceiver)

ScheduleBroadcastsLocked () {scheduleBroadcastsLocked;

//BroadcastQueue.java

    public void scheduleBroadcastsLocked(a) {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        // Distributed by Handler
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
Copy the code

The above code sends a message of type BROADCAST_INTENT_MSG to the mHandler object of type BroadcastHandler, which is processed in the handleMessage method of Type BroadcastHandler. As follows:

    //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");
                    // Process the next broadcast
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true); }}break; }}}Copy the code

The processnextBroadcast method is called in the handleMessage method. The processnextBroadcast method handles the unordered broadcast and the ordered broadcast separately, before sending the broadcast to the broadcast receiver with the following code:

//BroadcastQueue.java

    final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) { BroadcastRecord r; . mService.updateCpuStats();if (fromMsg) {
                /** * 1. BROADCAST_INTENT_MSG */
            
                mBroadcastsScheduled = false;
            }

            /** * 2. Run through the list of mParallelBroadcasts that store unordered broadcasts */
            while (mParallelBroadcasts.size() > 0) {
                /*** 3. Get an out-of-order broadcast */
                r = mParallelBroadcasts.remove(0); .for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                 /** * 4. Send the broadcast described by r object to the corresponding broadcaster */
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }

                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                        + mQueueName + "]"+ r); }... }}Copy the code

From the previous BroadcastHandler method we know that the value of the fromMsg argument passed in is true, so in comment 1 we set mBroadcastsScheduled to flase, The BROADCAST_INTENT_MSG message has been processed. The list of mParallelBroadcasts at note 2 is used to store unordered broadcasts. The unordered broadcasts in the list of mParallelBroadcasts are sent to the corresponding broadcast receiver through a while loop. Get an R object of type BroadcastRecord stored in the list of mParallelBroadcasts at comment 3. In the annotations and described the object r radio sent to the corresponding radio receiver, deliverToRegisteredReceiverLocked method, as shown below:

//BroadcastQueue.java


    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {...if(filter.receiverList.app ! =null && filter.receiverList.app.inFullBackup) {
                 if(ordered) { skipReceiverLocked(r); }}else {
                / * * * * 1 * /
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        newIntent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, r.userId); }... }Copy the code

DeliverToRegisteredReceiverLocked internal code as if used to check the permission of the radio sender and radio receiver, if by the inspection authority, will call comments 1 performReceiveLocked method.

//BroadcastQueue.java

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        / * * * 1 * /
        if(app ! =null) {
            / * * * 2. * /
            if(app.thread ! =null) {
                
                try {
                    / * * * 3. * /app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState); . }Copy the code

The code at comment 1 and 2 indicates that if the application process for the receiver of the broadcast exists and is running, the code at comment 3 indicates that the application process for the receiver of the broadcast is used to receive the broadcast. IApplicationThread.Stub is an ApplicationThread that is stored in the ActivityThread class.

//ActivityThread.java

    private class ApplicationThread extends IApplicationThread.Stub {...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);
      			/***1. Call performReceive */ in IIntentReceiverreceiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); }... }Copy the code

Note 1 calls the performReceive function for IIntentReceiver, which, as mentioned earlier, is used for broadcast cross-process communication, Its concrete implementation in LoadedApk. ReceiverDispatcher. InnerReceiver, code is as follows:

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

            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else{ rd = mDispatcher.get(); }...if(rd ! =null) {
                  / / 1.
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else{... }}}... }Copy the code

IIntentReceiver, like IActivityManager, uses AIDL to communicate between processes. The InnerReceiver inherits from IIntentReceiver.Stub, which is the server side of the Binder communication. The IIntentReceiver is the client side of the Binder communication and the InnerReceiver’s local agent. Its concrete implementation is the InnerReceiver. The performReceive method of the RD object of type ReceiverDispatch is called in comment 1 of the performReceiver method of InnerReceiver as follows:

//LoadedApk.java
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            / * * * 1 * /
            final Args args = newArgs(intent, resultCode, data, extras, ordered, sticky, sendingUser); ./ * * * 2. * /
            if (intent == null| |! mActivityThread.post(args.getRunnable())) {if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to "+ mReceiver); args.sendFinished(mgr); }}}}Copy the code

Comment 1 encapsulates the broadcast intent and other information in an Args object. Comment 2 calls the POST method of mActivityThread and passes in the Args object. The mActivityThread is a Handler object that points to class H. The code in comment 2 is to send the getRunnable method of the Args object to the message queue of the thread. The code is as follows:

//LoadedApk.java

        final class Args extends BroadcastReceiver.PendingResult {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;
            private Throwable mPreviousRunStacktrace; // To investigate b/37809561. STOPSHIP remove.

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }

            public final Runnable getRunnable(a) {
                return() - > {finalBroadcastReceiver receiver = mReceiver; .try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //1. Callback to the onReceiver that receives the broadcast
                        receiver.onReceive(mContext, intent);
                    } catch(Exception e) { ... }; }}Copy the code

The BroadcastReceiver callback **onReceive(mContext, intent) is executed in comment 1. Method, so that the registered broadcast receiver receives the broadcast and gets the intent.

This is the end of the whole process, and the next chapter will bring you the final component of the four components, ContentProvider startup process, stay tuned!

reference

  • Android Advanced Decryption