We described the broadcast mechanism of the Android system, in essence, it is a message subscription/advertisement mechanism, so the first step to use such a message-driven model is to subscribe to the message, and for Android applications, the subscription message is actually a register broadcast receiver, This article explores how the Android app will register a broadcast receiver and where to register the broadcast receiver.
In the Android broadcasting mechanism, Activitymanagerservice plays the role of Broadcast Center, responsible for all the broadcast in the system of the registration and publishing operations, therefore, The process for the Android app to register the broadcast receiver is to register the broadcast receiver with the Activitymanagerservice. The Android app calls the Registerreceiver function of the Contextwrapper class to broadcastreceiver the broadcast receiver to Activitymanagerservice, The Contextwrapper class itself also uses the Contextimpl class to register the broadcast receiver.
In the Android application framework, the activity and service classes inherit the Contextwrapper class, so we can call the Registerreceiver function in the activity or subclass of the service to register the broadcast receiver. Activity, Service, The relationship between the four classes of Contextwrapper and Contextimpl can be a reference to the Activity class diagram described in the previous Android system starting its own definition service process (StartService) in the new process.
This article continues with an example of the scenario analysis, the sample used in the previous article on the Android System broadcast (broadcast) mechanism brief introduction and learning program introduced in the application, so I hope readers before continuing to read this article, first look at this article And because the Android app is a activitymanagerservice of the broadcast connector, so it's going to be involved in the binder interprocess communication mechanism, so I want readers to know about the binder interprocess communication mechanism of the Android system, Specifically, please refer to the Android interprocess communication (IPC) Mechanism Binder Brief introduction and Learning Plan article.
Starting with the topic, in the example presented in the brief introduction of the broadcast (broadcast) mechanism in the Android system and the Learning Plan article, the operation of the Register broadcast receiver is mainactivity initiated, let's take a look at the sequence diagram of the register process:
Before analyzing this sequence diagram, let's take a look at how mainactivity calls the Registerreceiver function to register the broadcast receiver:
public class Mainactivity extends Activity implements Onclicklistener { ... @Override public void Onresume () { Super.onresume (); Intentfilter counteractionfilter = new Intentfilter (counterservice.broadcast_counter_action); Registerreceiver (Counteractionreceiver, counteractionfilter); } ......}
Mainactivity in the Onresume function, a Broadcastreceiver instance Counteractionreceiver is registered through the Registerreceiver function of its parent class Contextwrapper. And by Intentfilter instance Counteractionfilter tells Activitymanagerservice that the broadcast it wants to subscribe to is Counterservice.broadcast_counter_ Action type, so that when Activitymanagerservice receives a broadcast of type counterservice.broadcast_counter_action, will be distributed to the OnReceive function of the Counteractionreceiver instance.
Next, you begin to analyze each step in the registration process.
Step 1. Contextwrapper.registerreceiver
This function is actually in the Frameworks/base/core/java/android/content/contextwrapper.java file today:
public class Contextwrapper extends context {context mbase;. @Overridepublic Intent Registerreceiver ( Broadcastreceiver receiver, Intentfilter filter) {return Mbase.registerreceiver (receiver, filter);} ......}
Here's the member variable mbase is a Contextimpl instance, wondering why, able to go back and look at the Android app launch process source code analysis this article >~<.
Step 2. Contextimpl.registerreceiver
This function is actually in the Frameworks/base/core/java/android/app/contextimpl.java file today:
Class Contextimpl extends Context {... @Overridepublic Intent registerreceiver (broadcastreceiver receiver, Intentfilter filter) {return Registerreceiver (receiver, filter, NULL, NULL);} @Overridepublic Intent Registerreceiver (broadcastreceiver receiver, Intentfilter filter,string broadcastpermission, Handler Scheduler) {return registerreceiverinternal (receiver, filter, Broadcastpermission,scheduler, Getoutercontext ());} Private Intent registerreceiverinternal (broadcastreceiver receiver,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 ();} RD = Mpackageinfo.getreceiverdispatcher (receiver, context, Scheduler,mmainthread.getinstrumentation (), true);} else {...}} try {return Activitymanagernative.getdefault (). Registerreceiver (Mmainthread.getapplicationthread (), RD, filter, broadcastpermission);} CAtch (RemoteException e) {return null;}} ......}
Through the two functions of the relay, finally entered into the contextimpl.registerreceiverinternal this function. Here the member variable mpackageinfo is a loadedapk instance, it is used to handle the reception of the broadcast, in a later article on the transmission of the broadcast (SENDBROADCAST), will be described in detail. The parameters broadcastpermission and scheduler are null, and the reference context is the function Getoutercontext obtained by calling the function, here it is pointing to mainactivity, Because Mainactivity is inherited from the context class, it is referenced here using the context type.
Because the condition mpackageinfo! = NULL and Context! = NULL are true, and the condition scheduler = = NULL is also established, So call Mmainthread.gethandler to get a handler, this hanlder is used to distribute Activitymanagerservice sent broadcast. Here the member variable mmainthread is a Activitythread instance, in front of the Android application launch process source code Analysis This article also describes the narrative. Let's take a look at the implementation of the Activitythread.gethandler function and then go back and analyze the contextimpl.registerreceiverinternal function.
Step 3. Activitythread.gethandler
This function is actually in the Frameworks/base/core/java/android/app/activitythread.java file today:
Public final class Activitythread {... final h MH = new H ();p Rivate final class H extends Handler {... public void Han Dlemessage (Message msg) {... switch (msg.what) {...} ......} ......} ... final Handler gethandler () {return mH;} ......}
With this handler, you are able to distribute the message to the application for processing.
Back to the Contextimpl.registerreceiverinternal function in the previous step, it obtains a Iintentreceiver interface object through the Mpackageinfo.getreceiverdispatcher function Rd, which is a binde The R object, which is then passed to Activitymanagerservice,activitymanagerservice when it receives the corresponding broadcast, is the binder object that notifies mainactivity to receive.
Let's take a look at the implementation of the Mpackageinfo.getreceiverdispatcher function, and then go back and analyze the contextimpl.registerreceiverinternal function.
Step 4. Loadedapk.getreceiverdispatcher
This function is actually in the Frameworks/base/core/java/android/app/loadedapk.java file today:
Final class loadedapk {... public iintentreceiver getreceiverdispatcher (broadcastreceiver r,context Context, Handler Handler,instrumentation Instrumentation, Boolean registered) {synchronized (mreceivers) { Loadedapk.receiverdispatcher rd = null; Hashmap<broadcastreceiver, loadedapk.receiverdispatcher> map = null;if (registered) {map = MReceivers.get ( context); if (map! = null) {rd = Map.get (r);}} if (rd = = null) {rd = new Receiverdispatcher (r, Context, handler,instrumentation, registered); if (registered) {if (map = = NULL) {map = new hashmap<broadcastreceiver, loadedapk.receiverdispatcher> (); Mreceivers.put (context, map);} Map.put (R, RD);}} else {rd.validate (context, handler);} return Rd.getiintentreceiver ();}} ... static final class Receiverdispatcher {final static class Innerreceiver extends Iintentreceiver.stub {final WeakRef Erence<loadedapk.receiverdispatcher> Mdispatcher; Innerreceiver (Loadedapk.receiverdispatcher Rd, Boolean strong) {Mdispatcher = new Weakreference<loadedapk.receiverdispatcher> (RD); ...} ......} ... final iintentreceiver.stub miintentreceiver;final Handler mactivitythread; ..... Receiverdispatcher (broadcastreceiver receiver, Context context,handler Activitythread, instrumentation Instrumentation,boolean registered) {... miintentreceiver = new Innerreceiver (this,!registered); mactivitythread = Activitythread, ...} ...... Iintentreceiver Getiintentreceiver () {return miintentreceiver;}} ......}
In the Loadedapk.getreceiverdispatcher function, first look at the parameter R is not already have a corresponding receiverdispatcher exist, if there is, directly returned, otherwise a new receiverdispatcher, and R is the key value In a hashmap, and this hashmap in the context, where mainactivity is the key value stored in the LOADEDAPK member variable mreceivers, so that Just given an activity and broadcastreceiver, it is possible to see if there is a corresponding broadcast receiver Receiverdispatcher in the loadedapk.
When you create a new broadcast receive advertisement Receiverdispatcher, a Innerreceiver instance is created inside the constructor, which is a binder object that implements the Iintentreceiver interface. It can be obtained through the Receiverdispatcher.getiintentreceiver function, which is then passed to Activitymanagerservice to receive the broadcast. In the constructor of the Receiverdispatcher class, the parameters of the handle type that are passed in Activitythread are also saved so that they can be used later when the broadcast is distributed.
Now And then back to the Contextimpl.registerreceiverinternal function, after acquiring the binder object of the Iintentreceiver type, it started to register it in Activitymanagerservice.
Step 5. Activitymanagerproxy.registerreceiver
This function is now frameworks/base/core/java/android/app/ Activitymanagernative.java file:
Class Activitymanagerproxy implements Iactivitymanager{......public Intent Registerreceiver (iapplicationthread Caller,iintentreceiver receiver,intentfilter filter, String perm) throws Remoteexception{parcel data = Parcel.obtain (); Parcel reply = Parcel.obtain ();d Ata.writeinterfacetoken (iactivitymanager.descriptor);d Ata.writestrongbinder ( Caller! = null? Caller.asbinder (): null);d ata.writestrongbinder (receiver! = null? Receiver.asbinder (): null); Filter.writetoparcel ( Data, 0);d ata.writestring (Perm), Mremote.transact (register_receiver_transaction, data, reply, 0); Reply.readexception (); Intent Intent = Null;int haveintent = Reply.readint (); if (haveintent! = 0) {Intent = Intent.creator. Createfromparcel (reply);} Reply.recycle ();d ata.recycle (); return intent;} ......}
This function goes through the binder driver into the Registerreceiver function in Activitymanagerservice.
Step 6. Activitymanagerservice.registerreceiver
This function is actually in the Frameworks/base/services/java/com/android/server/am/activitymanagerservice.java file today:
Public final class Activitymanagerservice extends Activitymanagernativeimplements watchdog.monitor, Batterystatsimpl.batterycallback {... public Intent registerreceiver (Iapplicationthread caller,iintentreceiver Receiver, Intentfilter filter, String permission) {synchronized (this) {Processrecord Callerapp = null;if (caller! = NULL) {Callerapp = getrecordforapplocked (caller), if (Callerapp = = null) {...}} List Allsticky = null;//look for any matching sticky broadcasts ... Iterator actions = Filter.actionsiterator (), if (actions! = null) {while (Actions.hasnext ()) {String action = (string) actio Ns.next (); allsticky = getstickieslocked (action, filter, Allsticky);}} else {...} The first sticky in the list was returned directly back to//the client. Intent sticky = allsticky! = null? (Intent) allsticky.get (0): null;......if (receiver = = null) {return sticky;} Receiverlist rl= (receiverlist) Mregisteredreceivers.get (Receiver.asbinder ()); if (RL = = NULL) {RL = new Receiverlist ( This, Callerapp,Binder.getcallingpid (), Binder.getcallinguid (), receiver), if (Rl.app! = null) {Rl.app.receivers.add (RL);} else {... }mregisteredreceivers.put (Receiver.asbinder (), RL);} Broadcastfilter bf = new Broadcastfilter (filter, RL, permission); Rl.add (BF); ... mreceiverresolver.addfilter (BF);// Enqueue broadcasts for all existing stickies the match//this filter.if (allsticky! = null) {...} return sticky;}} ......}
The function is first to get the application process record block that calls the Registerreceiver function:
Processrecord Callerapp = null; if (caller! = null) {Callerapp = getrecordforapplocked (caller); if (Callerapp = = null) { ... } }
Here is the last article on the Android system in the broadcast (broadcast) mechanism brief introduction and learning Plan introduced in the application broadcast process record block, Mainactivity is in the inside started up.
List allsticky = null; Look for any matching sticky broadcasts ... Iterator actions = Filter.actionsiterator (); if (actions! = null) {while (Actions.hasnext ()) {String action = (string) actions.next (); allsticky = getstickieslocked (act Ion, filter, allsticky);} } else {... } The first sticky in the list was returned directly back to //the client. Intent sticky = allsticky! = null? (Intent) allsticky.get (0): null;
The filter that comes in here has only one action, which is the counterservice.broadcast_counter_action of the previous description, Here first through the getstickieslocked function to find out if there is no corresponding sticky intent list exists. What is sticky intent? When we last called the Sendstickybroadcast function to send a broadcast of an action type, the system will save the intent representing the broadcast, so that Later call Registerreceiver to register the same action type of broadcast receiver, you will get this last broadcast. This is why it is called sticky intent, and this last broadcast, although processed, is still stuck in activitymanagerservice so that the next register of broadcast receivers corresponding to the action type can inherit processing.
Here, if we don't use Sendstickybroadcast to send counterservice.broadcast_counter_action types of broadcasts, then the allsticky and sticky here are null.
Keep looking down, the receiver here is not NULL, so, continue to run down:
Receiverlist rl= (receiverlist) Mregisteredreceivers.get (Receiver.asbinder ()); if (RL = = NULL) {RL = new Receiverlist (this, Callerapp,binder.getcallingpid (), Binder.getcallinguid (), receiver); Rl.app! = null) {Rl.app.receivers.add (RL);} else {...} Mregisteredreceivers.put (Receiver.asbinder (), RL); }
In fact, the broadcast receiver receiver is saved in a receiverlist list, The host process of this list is Rl.app, this is the process where mainactivity is located, in Activitymanagerservice, a process record block is used to represent the application process, it has a list of receivers, dedicated to save the process register of the broadcast receiver 。 Next, the Receiverlist list is saved in the Activitymanagerservice member variable mregisteredreceivers with receiver as the key value, all of which are for the convenience of receiving the broadcast, The corresponding broadcast receivers are found at high speed.
Then look down:
Broadcastfilter bf = new Broadcastfilter (filter, RL, permission); Rl.add (BF); ...... Mreceiverresolver.addfilter (BF);
The above simply saves the radio receiver receiver, but does not associate it with the filter, creating a broadcastfilter to correlate the broadcast receiver list RL with the filter. Then save the member variable Mreceiverresolver in the Activitymanagerservice.
In this way, the broadcast receiver register process is finished, relatively simple, but the work is more trivial, mainly is the broadcast receiver receiver and its receiver to receive the broadcast type filter stored in the Activitymanagerservice, In order to be able to receive the corresponding broadcast and processing, in the next article, we will specifically analyze this process, please pay attention.
Lao Luo's Sina Weibo: Http://weibo.com/shengyangluo, welcome attention!
Process analysis of the Android application Registration broadcast receiver (REGISTERRECEIVER)