Plugin for Android broadcast

Source: Internet
Author: User

------This article reproduced from the Android plug-in principle analysis-broadcast management This series of articles is really good to write!
1, overview

In order to realize the plug-in of activity we have paid a great deal of effort; So what are the other components of the Android system, such as Broadcastreceiver,service and ContentProvider?

Much simpler than activity,broadcastreceiver-the life cycle of a broadcast is quite simple; what does it mean if you want the plugin to support broadcasting?

Recall how we use broadcastreceiver in our daily development: registering, sending and receiving; Therefore, to implement the Broadcastreceiver plug-in for these three operations to provide support;

Next we'll step through the process.

Before reading this article, you can clone a copy of Understand-plugin-frameworkand refer to the Receiver-management module for this project. The source code of this article is based on Android 6.0.

2, broadcast source code analysis

We can register a broadcastreceiver and then receive the broadcast we are interested in, or send a broadcast to someone who is destined for it, so our analysis of the source code is carried out in two directions:

2.1 Registration Process

Both static and dynamic broadcasts need to be registered before they are used, and the registration of dynamic broadcasts requires the use of the Registerreceiver method of the context class.

While the registration of static broadcast is directly declared in Androidmanifest.xml, we first analyze the registration process of dynamic broadcast.

The real implementation of the context class Registerreceiver in Contextimpl, and this method indirectly calls the Registerreceiverinternal, the source code is as follows:

Private Intent registerreceiverinternal (broadcastreceiver receiver, int userId, Intentfilter filter, String BROADCA    Stpermission, Handler Scheduler, Context context) {Iintentreceiver rd = null;//IMPORTANT!!!!!                if (receiver! = null) {if (Mpackageinfo! = NULL && context! = null) {if (scheduler = = null) {            Scheduler = Mmainthread.gethandler (); RD = Mpackageinfo.getreceiverdispatcher (receiver, context, scheduler, MMAINTHR        Ead.getinstrumentation (), true);            } else {if (scheduler = = null) {scheduler = Mmainthread.gethandler (); RD = new Loadedapk.receiverdispatcher (receiver, context, scheduler, NULL, TRUE). Getiinten        Treceiver (); }} try {return Activitymanagernative.getdefault (). Registerreceiver (Mmainthread.getapplicati Onthread (), Mbasepackagename, RD, filter, broadcastpermission, userId);    } catch (RemoteException e) {return null; }}

As can be seen, Broadcastreceiver's registration is also done through AMS, before entering AMS to track its Registerreceiver method,

Let's first figure out what this iintentreceiver type of Variable rd is. This class is generated by the Aidl tool, which is a binder object,

So it can be used to transfer across processes; it is used for broadcast distribution.

Because the broadcast distribution process is carried out in AMS, and the process in which AMS resides is different from the process in which the Broadcastreceiver resides,

So to distribute the broadcast to broadcastreceiver specific processes require cross-process communication, the carrier of this communication is the Iintentreceiver class.

In fact, the function of this class is the same as the iapplicationthread mentioned in Activity Lifecycle management, which is the object that the app process uses to communicate with the AMS process.

In addition, Iintentreceiver is an interface, as can be seen from the above code, its implementation class is Loadedapk.receiverdispatcher.

OK, we continue to follow the source code, the AMS class Registerreceiver method codes a bit more, here do not explain, interested in the words can be self-access;

This method mainly does the following two things:

1. To the identity and authority of the sender to make a certain school check

2. Store the broadcastreceiver in broadcastfilter form in the Mreceiverresolver variable of AMS for later use.

In this way, the Broadcastreceiver has been successfully registered in the system, to receive a certain type of broadcast;

So how does static broadcasting registered in Androidmanifest.xml be perceived by the system?

In the plugin loading mechanism we know that the system will parse the Androidmanifest.xml file in the apk via Packageparser, so we have reason to think that

The system will save the corresponding information when parsing the Androidmafest.xml <receiver> tag (i.e., statically registered broadcast);

The APK parsing process is carried out in the PMS, so the static registration broadcast information is stored in the PMS. The following analysis will confirm this conclusion.

2.2 Sending process

Sending the broadcast is very simple, is a context.sendbroadcast (), we trace, follow this method. As mentioned in the previous article,

The call to the method in the context is delegated to the Contextimpl class, and we look directly at the Contextimpl implementation of this method:

public void Sendbroadcast (Intent Intent) {    warnifcallingfromsystemprocess ();    String Resolvedtype = intent.resolvetypeifneeded (Getcontentresolver ());    try {        intent.preparetoleaveprocess ();        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 new RuntimeException ("Failure from System", e);}    }

Sending the broadcast is also done through AMS, we look directly at the Broadcastintent method of the Activitymanagerservice class,

This method only calls the Broadcastintentlocked method, we continue to trace; broadcastintentlocked This method is quite long,

Processing such as sticky broadcasts, sequential broadcasts, various flags, and the reception of dynamic broadcast static broadcasts, which we do not care about for the time being;

It is worth noting that in this method we find that the transmission and reception of the broadcast is in fact integrated. After a broadcast is sent,

AMS will identify all registered Broadcastreceiver recipients that match this broadcast, and then distribute the broadcast to the appropriate recipient for processing.

2.3 Matching Process

After a certain broadcast is issued, not puppy can receive it and deal with it; Broadcastreceiver may only be interested in certain types of broadcasts,

So it can only receive and handle this particular type of broadcast; inside the Broadcastintentlocked method is the following code:

Figure out who's all would receive this broadcast. List receivers = NULL; list<broadcastfilter> registeredreceivers = null;//need to resolve the intent to interested receivers...if ((intent . GetFlags () &intent.flag_receiver_registered_only)         = = 0) {    receivers = collectreceivercomponents (Intent , Resolvedtype, Callinguid, users);} if (intent.getcomponent () = = null) {    if (userId = = Userhandle.user_all && Callinguid = = process.shell_uid) {
   //Query One target user at a time, excluding shell-restricted users        //slightly    } else {        registeredreceivers = MR Eceiverresolver.queryintent (Intent,                Resolvedtype, False, userId);}    }

Here are two lists of receivers and registeredreceivers, with names that appear to be the list of broadcast receivers, and the following are their assignment processes:

Receivers = collectreceivercomponents (Intent, Resolvedtype, Callinguid, users); registeredreceivers = Mreceiverresolver.queryintent (Intent, Resolvedtype, false, userId);

1.receivers is a static broadcastreceiver list of interest for this broadcast; collectreceivercomponents

The static broadcastreceiver information matched with this broadcast was obtained by Packagemanager;

This also confirms our reasoning in analyzing the Broadcasrreceiver registration process-The static Broadcastreceiver registration process is indeed done in the PMS.

2.mReceiverResolver stores the information of dynamically registered Broadcastreceiver; Do you remember this mreceiverresolver?

In the analysis of the registration process of dynamic broadcasting, we find that the related information of dynamically registered Broadcastreceiver is finally stored in this object;

Here, the corresponding Broadcastreceiver is matched by the Mreceiverresolver object for further use.

Now, the system obtains all the required static broadcastreceiver through PMS, and then gets the dynamic broadcastreceiver that meet the requirements from AMS;

So the next task is very simple: Wake up the broadcast recipients. In simple terms, the OnReceive method of recalling them.

2.4 Reception Process

Through the above analysis process we know that in the AMS broadcastintentlocked method to identify all the broadcastreceiver that meet the requirements;

The next step is to distribute the broadcast to these receivers. In the latter part of the Broadcastintentlocked method, the following code is used:

Broadcastqueue queue = broadcastqueueforintent (intent); 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 ();}

First, a broadcastrecord represents this broadcast, and then throws it into a queue,

Finally, the broadcast is processed by the schedulebroadcastslocked notification queue.

In Broadcastqueue, the broadcast processing message is dispatched through handle, and the scheduling process is done by the Processnextbroadcast method.

This method eventually calls the Performreceive method of Iintentreceiver through performreceivelocked.

This iintentreceiver is the binder object that is provided by the app process to the AMS process during the broadcast registration process.

Now AMS uses this Binder object to notify the broadcast recipient that the process has completed the rest of the operation.

In the above we analyzed the broadcast registration process mentioned, this iitentreceiver realization is loadedapk.receiverdispatcher;

We look at this object's Performreceive method, the source code is as follows:

public void Performreceive (Intent Intent, int resultcode, String data,        Bundle Extras, Boolean ordered, Boolean sticky, int sendinguser) {    args args = new Args (intent, resultcode, data, extras, ordered,            Sticky, sendinguser);    if (!mactivitythread.post (args)) {        if (mregistered && ordered) {            Iactivitymanager mgr = Activitymanagernative.getdefault ();            Args.sendfinished (MGR);}}}    

This method creates a args object and then posts it to the handler of Mactivitythread; we look at the run method of the Args class:

public void Run () {final broadcastreceiver receiver = Mreceiver;      Final Boolean ordered = mordered;    Final Iactivitymanager mgr = Activitymanagernative.getdefault ();    Final Intent Intent = mcurintent;        Mcurintent = null;        if (receiver = = NULL | | mforgotten) {if (mregistered && ordered) {sendfinished (MGR);    } return; try {ClassLoader cl = Mreceiver.getclass (). getClassLoader ();//important!! Load Class intent.setextr        Asclassloader (CL);        Setextrasclassloader (CL);        Receiver.setpendingresult (this); Receiver.onreceive (Mcontext, intent);        Callback} catch (Exception e) {if (mregistered && ordered) {sendfinished (MGR);                } if (minstrumentation = = NULL | | !minstrumentation.onexception (Mreceiver, E)) {throw new RuntimeException ("Error receiving Broa   Dcast "+ Intent +" in "+ Mreceiver, E);     }} if (Receiver.getpendingresult () = null) {finish (); }}

Here, we see the corresponding broadcastreceiver of the onreceive callback; so the work of broadcasting is here.

We will then explore how to implement plug-ins for broadcasting.

3, service plug-in 3.1 thinking analysis

In the above we analyzed the working principle of broadcastreceiver, then how can we realize the plug-in of Broadcastreceiver?

From the analysis process we found that the framework of static broadcast and dynamic broadcast processing is different;

However, this difference is only reflected in the registration process-static broadcasts need to be registered in the Androidmanifest.xml,

and the registered information is stored in the PMS; dynamic broadcasts do not require pre-registration and the registered information is stored in AMS.

We know from the plug-in process of implementing activity that the need to pre-register in Androidmanifest.xml is a rather troublesome thing--

We need to use "surrogates" and "rescue" at the right time, so it seems that the processing of dynamic broadcasts is a little bit easier,

Let's talk about how to implement dynamic registration Broadcastreceiver plug-ins.

First, the broadcast does not have a complex life cycle, its entire survival process is actually a onreceive callback;

Dynamic broadcasts do not need to be pre-registered in Androidmanifest.xml, so the dynamic registration of Broadcastreceiver

Can actually be used as an ordinary Java object; We can implement it entirely with pure ClassLoader technology--

It's not just loading the receiver in the plugin and trying to get it to accept the onreceive callback.

Static Broadcastreceiver look a little more complicated, but we've got the activity going, what's so hard for us?

For the implementation of static Broadcastreceiver plug-in problems, some children's shoes may think, we can learn from the activity of the work of the way-

Use double and hook to solve. Unfortunately, this is not feasible. Why is it?

Broadcastreceiver has a concept of intentfilter, which means that each broadcastreceiver is only interested in a particular broadcast;

In addition, AMS will also match these broadcastreceiver with broadcast broadcasts when they are broadcasting distribution,

Only intent matched receiver can receive the broadcast, and the matching process is also mentioned when analyzing the source code.

If we try to solve the problem of static registration with a surrogate receiver, what does it intentfilter to write?

We cannot predict what type of intentfilter will be used by the statically registered receiver in the plugin, even if we are in Androidmanifest.xml

It's no use declaring aliases-we don't receive a broadcast that doesn't match our intentfilter. In fact

We have this problem with the way the activity is handled, and if you try to start the activity in a intentfilter way, it's not going to work, which is one of the droidplugin flaws.

So, do we really have nothing to do with static broadcastreceiver? Think about what the difficulty here is?

Yes, mainly in the static broadcastreceiver inside this intentfilter we can not determine beforehand, it is dynamic change;

However, is dynamic broadcastreceiver not able to add intentfilter dynamically?

Static broadcasts can be treated as dynamic broadcasts

Since they are all broadcast, their function is to subscribe to a specific message and then perform a specific operation.

We can completely register the static broadcast in the plugin as dynamic broadcast, which solves the problem of static broadcasting.

Of course, this is also flawed, static broadcastreceiver and dynamic Broadcastreceiver a very big difference is:

Dynamic Broadcastreceiver cannot receive broadcasts after a process has died, while static broadcastreceiver can--

The system wakes receiver's process; This is a flaw, of course, his flaws.

3.2 Static broadcast non-static implementation

Static broadcastreceiver can be treated as a dynamic broadcastreceiver, and we will implement this process next.

3.2.1 Parsing

To the static broadcastreceiver in the plug-in as a dynamic broadcastreceiver processing, we first need to know the plug-in in the end of the registration of which broadcast;

The process boils down to getting the <receiver> tag in androidmanifest.xml and we can choose to parse the XML file manually;

Here we choose to use the system's Packageparser help parsing, this way in the previous [plug-in loading process] [] also used, if you forget to be able to brush up.

Packageparser has a series of methods used to extract the information from the APK, but the class has not been searched for the method associated with the "receiver" name;

Eventually we found that the Broadcastreceiver information was stored in the same class as the activity!

This can be found in Packageparser's internal class package-the same type of member variable receivers and activities.

So, we want to parse the APK <receiver> information, you can use the Packageparser Generateactivityinfo method.

Once this is known, the code is simpler, the corresponding hidden interfaces are invoked using reflection, and the corresponding is constructed when necessary

Parameters of the way we have been in the plug-in series of articles have been told a lot, I believe that the reader has been skilled, here do not repeat, directly paste code:

private static void Parserreceivers (File apkfile) throws Exception {class<?> Packageparserclass = Class.forName (    "Android.content.pm.PackageParser");    Method Parsepackagemethod = Packageparserclass.getdeclaredmethod ("Parsepackage", File.class, Int.class);    Object Packageparser = Packageparserclass.newinstance (); First call Parsepackage get the package object corresponding to the APK object packageobj = Parsepackagemethod.invoke (Packageparser, Apkfile,    Packagemanager.get_receivers); Read the Receivers field inside the package object, note that this is a list<activity> (yes, the underlying <receiver> as <activity> processing)// The next thing to do is to get the receiver corresponding to the Activityinfo (still the receiver information is handled with Activity) according to this list<activity> Field Receiversfield =    Packageobj.getclass (). Getdeclaredfield ("receivers");    List receivers = (list) receiversfield.get (packageobj); Call the Generateactivityinfo method and convert the packageparser.activity to class<?> packageparser$activityclass = Class.forName ("    Android.content.pm.packageparser$activity "); Class<?>Packageuserstateclass = Class.forName ("Android.content.pm.PackageUserState");    class<?> Userhandler = Class.forName ("Android.os.UserHandle");    Method Getcallinguseridmethod = Userhandler.getdeclaredmethod ("Getcallinguserid");    int userId = (Integer) getcallinguseridmethod.invoke (null);    Object defaultuserstate = Packageuserstateclass.newinstance ();    class<?> Componentclass = Class.forName ("android.content.pm.packageparser$component");    Field Intentsfield = Componentclass.getdeclaredfield ("intents"); You need to call Android.content.pm.packageparser#generateactivityinfo (android.content.pm.ActivityInfo, int, android.content.pm.PackageUserState, int) Method generatereceiverinfo = Packageparserclass.getdeclaredmethod ("    Generateactivityinfo ", Packageparser$activityclass, Int.class, Packageuserstateclass, Int.class); Parse out receiver and corresponding intentfilter for (Object receiver:receivers) {activityinfo info = (activityinfo) generat Ereceiverinfo.invoke (Packageparser, receiver, 0, defaultuserstate, userId); list<?        Extends intentfilter> filters = (list<? extends intentfilter>) intentsfield.get (receiver);    Scache.put (info, filters); }}
3.2.2 Registration

We have been able to parse the plug-in static registration of the Broadcastreceiver information, now we just need to register these static broadcast dynamically once;

However, since the Broadcastreceiver implementation class exists in the plugin, we need to manually load it with ClassLoader, which is already described in the plugin loading mechanism, not verbose.

ClassLoader cl = null;for (Activityinfo activityInfo:ReceiverHelper.sCache.keySet ()) {    log.i (TAG, "preload Receiver: "+ activityinfo.name);    list<? Extends intentfilter> intentfilters = ReceiverHelper.sCache.get (activityinfo);    if (CL = = null) {        CL = Customclassloader.getpluginclassloader (APK, activityinfo.packagename);    }    Each static receiver that is parsed is registered as dynamic for    (Intentfilter intentfilter:intentfilters) {        Broadcastreceiver receiver = ( Broadcastreceiver) Cl.loadclass (activityinfo.name). newinstance ();        Context.registerreceiver (receiver, intentfilter);}    }

In this way, our support for static broadcastreceiver of plugins has been completed, is it quite simple?

As for the dynamic broadcast in the plugin how to implement the plug-in, this point to the reader to complete their own, I hope you in the process of solving this problem can deepen the understanding of the plug-in solution.

4 bars

In this paper, we introduce the plug-in method of broadcastreceiver components, and we can see that the plug-in scheme

Broadcastreceiver is relatively simple to handle, while the "static broadcast non-static" feature and Broadcastreceiver

Some of the innate characteristics of the plug-in solution has no way to achieve perfection, but this is Grand-in most cases,

This way of handling is to meet the needs.

Although the processing of broadcastreceiver is relatively simple, but the content of the article is not short-

We spent a lot of time talking about Broadcastreceiver's principles, which is what I had in mind: a deeper understanding of the Android Framework with Droidplugin.

Plugin for Android broadcast

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.