Android Source Series < three > in-depth understanding of broadcastreceiver from a security perspective (bottom)

Source: Internet
Author: User

Reprint Please specify source: http://blog.csdn.net/llew2011/article/details/51152723

In the previous article, we combined the experiment to explain the use of broadcastreceiver existing security problems and give the corresponding solution, if you have not read the previous article click here, The final solution is to use the official V4 package of the Localbroadcastmanager to solve, the official said that this way is not only safe and more efficient, today we are from the source of the angle to understand Localbroadcastmanager, If you are familiar with it, you can skip this article (*^__^*) ...

Before we analyze the source code, we first review the usage of Localbroadcastmanager:

1, define the broadcast receiver, the code is as follows:

public class Localbroadcastreceiver extends Broadcastreceiver {public static final String local_custom_action = "Com.llew . seetao.customaction ";p ublic localbroadcastreceiver () {} @Overridepublic void OnReceive (context context, Intent Intent {LOG.E (This.getclass (). Getsimplename (), "Current time is:" + system.currenttimemillis ());}}
2, register the broadcast receiver, the code is as follows:
private void Registerbroadcastreceiver () {Mbroadcastmanager = Localbroadcastmanager.getinstance (MainActivity.this); Mlocalreceiver = new Localbroadcastreceiver (); intentfilter filter = new Intentfilter (Localbroadcastreceiver.local_ custom_action); Mbroadcastmanager.registerreceiver (mlocalreceiver, filter);}
3, send a broadcast, the code is as follows:
public void Sendbroadcast (View v) {Intent Intent = new Intent (localbroadcastreceiver.local_custom_action); Mbroadcastmanager.sendbroadcast (intent);}

Analysis of the source code is generally from the beginning of the analysis, before starting the analysis, we have a general understanding of what properties are defined in Localbroadcastmanager, some of the properties are as follows:

Private final Context mappcontext;//cache collection Private final Hashmap<broadcastreceiver, arraylist<intentfilter> > Mreceivers        = new Hashmap<broadcastreceiver, arraylist<intentfilter>> ();p rivate final HashMap <string, arraylist<receiverrecord>> mactions        = new hashmap<string, Arraylist<receiverrecord >> ();p rivate final arraylist<broadcastrecord> mpendingbroadcasts        = new Arraylist<broadcastrecord > ();p rivate final Handler mhandler;private static Localbroadcastmanager minstance;
It defines the Mappcontext attribute that represents the current app run environment, and then defines the properties of the three collection types, since it is defined as the type of collection that is definitely used to load data, what type of data is loaded, and what type of generic definition is clear, After understanding the relevant properties, we began to analyze the source code.

First Mbroadcastmanager instantiation is the same as the Localbroadcastmanager global static Method getinstance () to achieve, the method needs a context, we directly pass the current context is good. Let's go into the method and see how it's instantiated, with the following code:

public static Localbroadcastmanager getinstance (context context) {    synchronized (mLock) {        if (minstance = = null) {            minstance = new Localbroadcastmanager (Context.getapplicationcontext ());        }        return minstance;}    }
This method is very simple, through a singleton mode to ensure that only one Localbroadcastmanager instance, we go into its construction method, to see what is done inside, the code is as follows:
Private Localbroadcastmanager (Context context) {    Mappcontext = context;    Mhandler = new Handler (Context.getmainlooper ()) {        @Override public        void Handlemessage (Message msg) {            Switch (msg.what) {case                msg_exec_pending_broadcasts:                    executependingbroadcasts ();                    break;                Default:                    super.handlemessage (msg);}}    ;}

In the construction method, the passed in context assignment is given to Mappcontext, and the Mhandler variable is initialized by the context's Getmainlooper () method, which is initialized based on the looper of the main thread. This is the way to initialize the Mhandler because of the main thread of the message queue, about Handler,message and other relevant introduction will be detailed in the subsequent articles to explain) and rewrite the Handlemessage () method, in which only the type is processed by the Msg_ The exec_pending_broadcasts message, when it receives this type of message, calls the Executependingbroadcasts () method and, in other cases, to its parent class for processing, which is the process of initialization.

        We go on to register the broadcast process, register the broadcast is also very simple, directly call Localbroadcastmanager's Registerreceiver () method, This method requires passing broadcastreceiver and Intentfilter instances, and in step 2 above we define Broadcastreceiver and Intentfilter, Then take a look at Localbroadcastmanager's Registerreceiver () methods have done, the code is as follows:

public void Registerreceiver (Broadcastreceiver receiver, Intentfilter filter) {synchronized (mreceivers) {////According to the passed in        Receiver and filter to create a Receiverrecord instance entry Receiverrecord entry = new Receiverrecord (filter, receiver);        Find arraylist<intentfilter> filters = mreceivers.get (receiver) from the cache according to receiver;            if (filters = = null) {//If NULL is created and then added to the cache filters = new arraylist<intentfilter> (1);        Mreceivers.put (receiver, filters);                }//Add Operation Filters.add (filter); Loops through the action for (int i=0; i<filter.countactions (); i++) {//loops through the filter to get each action String AC            tion = filter.getaction (i);            Find arraylist<receiverrecord> entries = Mactions.get (action) from the cache based on action;                 if (entries = = null) {//If the cache does not exist, it is created and then added to the cache entries = new arraylist<receiverrecord> (1);        Mactions.put (action, entries);    }//Add Operation Entries.Add (entry); }    }}

The comments in the code are very detailed, it is still roughly smoothed the process, in this method through the Synchronize keyword to mreceivers Garthon is to ensure the consistency of the data, First, based on the receiver and filter passed in to build a Receiverrecord object entry, see the name can guess is a package, and then according to receiver from the cache collection Mreceivers to find out if there is a corresponding filters, If filters is not present in the cache, create a new one and store the filters in Mreceivers, and finally load the passed in filter into the filters. After caching the incoming receiver and filter, start looping through the action contained in the filter, which, like just the same, first finds entries from the cache based on action, If it does not exist, create a new one and then load the newly created entries into the mactions cache, and finally load the originally created entry into the entries, which is the main process of registering the broadcast receiver. The core idea is to add incoming receiver and filter to the cache.

Let's look at how to send a broadcast with the following code:

public boolean sendbroadcast (Intent Intent) {synchronized (mreceivers) {//Gets the corresponding value from Intent final Contentresolver        Resolver = Mappcontext.getcontentresolver ();        Final String action = Intent.getaction ();        Final String type = intent.resolvetypeifneeded (resolver);        Final Uri data = Intent.getdata ();        Final String scheme = Intent.getscheme ();        Final set<string> categories = Intent.getcategories ();        Find the corresponding value from the cache based on action arraylist<receiverrecord> entries = Mactions.get (intent.getaction ());            if (entries! = null) {arraylist<receiverrecord> receivers = null; The corresponding action set entries is present in the cache and begins looping through entries for (int i=0; i<entries.size (); i++) {//Get every Receiverr                Ecord instance receiver Receiverrecord receiver = entries.get (i);                If Receiver.broadcasting is true, skip this operation to continue looping if (receiver.broadcasting) {continue;     }           Call Intentfilter's Match () method to match the intent, if the return value is less than 0 to indicate a mismatch int match = Receiver.filter.match (action, T                ype, scheme, data, categories, "Localbroadcastmanager");  if (match >= 0) {//Match succeeded if (receivers = = NULL) {receivers =                    New Arraylist<receiverrecord> ();                    }//Add receiver into receivers Receivers.add (receiver);                Set the receiver.broadcasting value to true receiver.broadcasting = true; }}//If receivers does not represent an empty representation to Broadcastreceiver if (receivers! = NULL) {//loops through the horse Receiver, set its broadcasting to FALSE for (int i=0; i<receivers.size (); i++) {Receivers                . get (i). Broadcasting = FALSE; }//According to intent and receivers, a new Broadcastrecord is added to the Mpendingbroadcasts collection Mpendingbroadcasts.add (New BrOadcastrecord (Intent, receivers)); Detects messages in the message queue that contain message.what as msg_exec_pending_broadcasts, and if not, sends a message if (!mhandler.hasmessages (msg_exec_pe                nding_broadcasts)) {mhandler.sendemptymessage (msg_exec_pending_broadcasts);            }//indicates that the Send broadcast succeeded return true; }}}//Send broadcast failed return false;}
The Sendbroadcast () method is simple, receives only one intent, and returns a Boolean value (true: Broadcast sent successfully, false: Broadcast send failed). We then read the code, in order to ensure the consistency of the data or to Mreceivers lock operation, first get to the values carried in the intent, such as: action,type,data,schema,categories, ETC., The entries instance is then looked up from the Mactions cache based on the action in intent, followed by an if statement, which returns false if the condition is true (false is understood to be a failed send broadcast). After entering the IF statement, loop through the entries collection to get each Receiverrecord object in the collection receiver, and if receiver.braodcasting=true skips the current operation to continue the next round of loops, Otherwise, the Receiver.filter.match () method is called to match the carrying value of the intent, and the match () method returns the value of type int by viewing the document, and if the return value is less than 0 indicates that the match failed. When match is greater than or equal to 0 o'clock enter the IF statement, the receiver record that matches to is stored in the Receivers collection and set its broadcasting value to true, After this cycle is complete, the receivers is loaded with receiver, and then a loop is made to set the broadcasting property of the receiver that just meets the conditions to false, and finally put these values into the Pending collection. After joining the collection, the message is checked by Mhandler to see if a message with the message type msg_exec_pending_broadcasts is contained in the column, and if it is not included, a message type of Msg_exec_pending_ is sent. Broadcasts message, returns True after the message is sent, indicating that the broadcast was sent successfully.
        Send message type msg_exec_pending_broadcasts messages via Mhandler that is to say, Mhandler handlemessage () method to respond to such a message, in the Mhandler Handlemessage method called to the Executependingbroadcasts () method, we look at the operation of this method, the code is as follows:
private void        Executependingbroadcasts () {while (true) {broadcastrecord[] BRs = null;  Lock operation synchronized (mreceivers) {//This locked code block is to move the value stored in mpendingbroadcasts to the temporary variable BRS, and then clear the final            int N = Mpendingbroadcasts.size ();            if (N <= 0) {return;            } BRS = new Broadcastrecord[n];            Mpendingbroadcasts.toarray (BRS);        Mpendingbroadcasts.clear (); }//Loops through the BRS, and finally calls to receiver's onreceive () method and passes the corresponding value in for (int i=0; i<brs.length; i++) {Broadcast            Record br = Brs[i]; for (int j=0; j<br.receivers.size (); j + +) {Br.receivers.get (j). Receiver.onreceive (Mappcontext, Br.inten            T); }        }    }}
The logic of the         Method Executependingbroadcats () is simply to move the cached data into a temporary array and empty the cache. It then loops through the Broadcastrecord in the temporary array and then callbacks the receiver's OnReceive () method, which eventually leads to the invocation of the OnReceive () method of our registered Broadcastreceiver. The logic of registering a broadcast and sending a broadcast is analyzed, and the core logic of registering a broadcast receiver is to store each broadcastreceiver in the cache; The core logic of sending broadcasts is to match the Intentfilter match () method. After the matching broadcast receiver is added to a new cache collection, the message is sent, and then the OnReceive () method of the Broadcastreceiver is recalled after the message is captured. Since there are registration and send operations, there must also be a logout operation, this time you will certainly guess the cancellation of the broadcast receiver operation should be the broadcast receiver from the cache to clear it? Congratulations on your correct answer, the code is as follows:
public void Unregisterreceiver (Broadcastreceiver receiver) {synchronized (mreceivers) {arraylist<intentfilt        er> filters = mreceivers.remove (receiver);        If the cache does not exist, return directly if (filters = = null) {return;  }//Loop through the cache to find the matching broadcastreceiver after removing the for (int i=0; i<filters.size (); i++) {Intentfilter            Filter = Filters.get (i);                for (int j=0; j<filter.countactions (); j + +) {String action = filter.getaction (j);                arraylist<receiverrecord> receivers = Mactions.get (action); if (receivers! = null) {for (int k=0; k<receivers.size (); k++) {if (Receive                            Rs.get (k). Receiver = = receiver) {receivers.remove (k);                        k--;                  }} if (Receivers.size () <= 0) {mactions.remove (action);  }                }            }        }    }} 

The core of the logoff broadcast receiver is to remove the relevant values from the receivers and mactions caches, and here the Localbroadcastmanager source is analyzed, the core of which is two points:

    1. Message delivery with Handler
    2. Use the match () feature of Intentfilter

The above mentioned in the application send broadcast using Localbroadcastmanager is the official highly recommended, it is not only safe and efficient, security is mainly using the handler message mechanism, so that messages can only be sent and received within the application It is much more efficient to traverse queries directly in the cache than to communicate using the original binder mechanism. Well, after seeing this, did you decide not to use the original way to send or accept the broadcast? Oh, anyway, I abandoned the original use of the way ...


A deep understanding of broadcastreceiver from a security perspective is over, thanks for watching (*^__^*) ...





Android Source Series < three > in-depth understanding of broadcastreceiver from a security perspective (bottom)

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.