Android Source code Deskclock (iii) PROXY/DELEGATE application Framework Application

Source: Internet
Author: User

I. Overviewwhen the project has a shell, plug-in or heat repair requirements, the ability to use the Proxy/delegate application framework, in normal mode, a program generally only has a application entrance, and proxy/ Delegate mode needs to have two application, the original program application changed to delegate application, and then a new proxy application, by proxy application Provides a range of personalization, and then all the context and context related references all converted to delegate application instances, let the outside world contain delegate Application itself thought the app's application entrance was delegate application.
Two. Examplebefore 1.proxy/delegatehere is a demo sample using the Proxy/delegate framework on Android 4.4 native Deskclock programThe native Deskclock program does not have its own definition application, here first define a, and print the program now ApplicationContext name (the log used in Deskclock is defined by itself)
/** * Created by Jesse on 15-7-17. */public class MyApplication extends application{    private final String TAG = MyApplication.class.getSimpleName (); c2/> @Override public    void OnCreate () {        super.oncreate ();        LOG.I (TAG + ", onCreate" + this.getapplicationcontext (). GetClass (). Getsimplename ());}    }
and at the entrance to the Deskclock Activity,deskclock also print out the program right now ApplicationContext name for the control after the proxy.the manifest configuration of the application is
    <application android:name= "cn.jesse.MyApplication"                 android:label= "@string/app_label"                 android:icon= "@ Mipmap/ic_launcher_alarmclock "                 android:requiredforallusers=" true "                 android:supportsrtl=" true ">
Filtered Execution log: A simple process is to start their own definition MyApplication before launch Deskclock, the same time to print out the name of ApplicationContext

Watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqv/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/dissolve/70/ Gravity/center

2. After using the Proxy/delegate framework         using the proxy/delegate framework, you need to build a new proxyapplication again, Used to do proxy application, the original MyApplication function for delegateapplication         So the configuration of manifest needs to change, the main entrance of the app is changed to Myproxyapplication, the delegateapplication information is stored in the form of Meta-data child elements (of course, can be used in other ways)

    <application android:name= "cn.jesse.MyProxyApplication"                 android:label= "@string/app_label"                 android: icon= "@mipmap/ic_launcher_alarmclock"                 android:requiredforallusers= "true"                 android:supportsrtl= "true" >        <meta-data            android:name= "delegate_application_class_name"            android:value= " Cn.jesse.MyApplication ">        </meta-data>    </application>
defines an abstract class that provides an abstract method (or some other personalization) to replace the classloader of the current proxyapplication ClassLoader into a parent class
* Created by Jesse on 15-7-17. */public abstract class Proxyapplication extends application{    protected abstract void Initproxyapplication ();}
when we want to replace the ClassLoader of the current proxyapplication with the ClassLoader of the parent class, the action of this substitution is early enough (to ensure that the ClassLoader is replaced at the first entry in the app context), Otherwise there will be a replacement is not clean, there will be most of the procedures used in the Delegateapplication ClassLoader, and a small part of the use of Proxyapplication ClassLoader, This may cause some unexpected bugs to occur.It is usually enough to replace the OnCreate in application, but when the app has a contentprovider, contentprovider:oncreate call is in Application:o Ncreate before, so we have to make sure that the action to replace ClassLoader is before ContentProvider.by looking at the source code, you can see that application is inherited from Contextwrapper, and the first callback is through the Attachbasecontext method after the system has been built in the contextwrapper context. In this case, we can convert the ClassLoader by copying the method in Proxyapplication to obtain the context of the freshly baked hot spray.
    /**     * Set The base context for this contextwrapper.  All calls'll then being     * delegated to the base context.  Throws     * illegalstateexception If a base context has already been set.     *      * @param base the new base context for this wrapper.     */    protected void Attachbasecontext (Context base) {        if (mbase! = null) {            throw new IllegalStateException (" Base context already set ");        }        Mbase = base;    }
the entrance to the conversion ClassLoader is also determined to be able to define a myproxyapplication, inherit from Proxyapplication and Attachbasecontext method, print related information
/** * Created by Jesse on 15-7-17. */public class Myproxyapplication extends Proxyapplicati    On {private final String TAG = MyProxyApplication.class.getSimpleName ();    Private Context Mcontext;        @Override protected void Attachbasecontext (Context base) {Super.attachbasecontext (base);        LOG.I (TAG + ", Attachbasecontext");        Mcontext = base;    This.initproxyapplication ();        } @Override public void OnCreate () {super.oncreate ();        LOG.I (TAG + ", onCreate" + this.getapplicationcontext (). GetClass (). Getsimplename ());    Bootloader.boot (Mcontext);        } @Override protected void Initproxyapplication () {log.i (TAG + ", initproxyapplication");    Bootloader.resetclassloader (Mcontext); }}
log execution sequence, first enter the Attachbasecontext->initproxyapplication->oncreate->deskclock:oncreate ( Here Deskclock's oncreate gets to the ApplicationContext name is (myproxyapplication)
after the order of the portals is no problem, you can replace the current ClassLoader to the ClassLoader of the parent class in the Initproxyapplication method. And in the oncreate of myproxyapplication, all references to the application layer's application are replaced with MyApplication from Proxyapplication ( Currently in the Deskclock program does not replace the requirements of classloader, just need to replace all the application references can achieve the effect of the agent, so in the Initproxyapplication method is written an empty method took over).get the Delegateapplication property from the metadata in the Androidmanifest config file first .
            String className = class_name;            ApplicationInfo appInfo = Getpackagemanager (). Getapplicationinfo (Super.getpackagename (), Packagemanager.get_meta_ DATA);            Bundle bundle = Appinfo.metadata;            if (bundle! = null && Bundle.containskey (key)) {                className = bundle.getstring (key);                if (Classname.startswith ("."))                    ClassName = Super.getpackagename () + className;            }
get MyApplication based on classname reflection, create MyApplication instances and get Myproxyapplication instances
            Class delegateclass = Class.forName (ClassName, True, getClassLoader ());            Application delegate = (application) delegateclass.newinstance ();            Application Proxyapplication = (application) getapplicationcontext ();
replacing the Moutercontext property in a Myproxyapplication context member with Reflection
            Class Contextimplclass = Class.forName ("Android.app.ContextImpl");            Field Moutercontext = Contextimplclass.getdeclaredfield ("Moutercontext");            Moutercontext.setaccessible (true);            Moutercontext.set (Mcontext, delegate);
gets the PackageInfo object of the myproxyapplication context, replacing the mapplication attribute in the
            Field Mpackageinfofield = Contextimplclass.getdeclaredfield ("Mpackageinfo");            Mpackageinfofield.setaccessible (true);            Object mpackageinfo = Mpackageinfofield.get (mcontext);            Class Loadedapkclass = Class.forName ("android.app.LoadedApk");            Field mapplication = Loadedapkclass.getdeclaredfield ("mapplication");            Mapplication.setaccessible (true);            Mapplication.set (Mpackageinfo, delegate);
based on the previously reflected PackageInfo object gets to the Mactivitythread property, replacing the Minitialapplication property
            Class Activitythreadclass = Class.forName ("Android.app.ActivityThread");            Field Macitivitythreadfield = Loadedapkclass.getdeclaredfield ("Mactivitythread");            Macitivitythreadfield.setaccessible (true);            Object Mactivitythread = Macitivitythreadfield.get (mpackageinfo);            Field Minitialapplicationfield = Activitythreadclass.getdeclaredfield ("minitialapplication");            Minitialapplicationfield.setaccessible (true);            Minitialapplicationfield.set (Mactivitythread, delegate);
take the previous Mactivitythread object to get to the Mallapplications property, note that the property is a list. This removes myproxyapplication to join Delegateapplication, where the reference to the context of the application layer myproxyapplication is replaced by the MyApplication reference.
            Field Mallapplicationsfield = Activitythreadclass.getdeclaredfield ("mallapplications");            Mallapplicationsfield.setaccessible (true);            Arraylist<application> al = (arraylist<application>) mallapplicationsfield.get (mActivityThread);            Al.add (delegate);            Al.remove (proxyapplication);
set Basecontext to MyApplication through reflection and attach internal methods, and call MyApplication OnCreate method to complete the initialization of delegateapplication.
            Method attach = Application.class.getDeclaredMethod ("Attach", context.class);            Attach.setaccessible (true);            Attach.invoke (delegate, Mcontext);            Delegate.oncreate ();
after completing these steps and then executing the view log again, observe that the name of the ApplicationContext obtained at Deskclock has become myapplication.

Watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqv/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/dissolve/70/ Gravity/center "
        But it's not over yet. Do you remember the contentprovider of the beginning? His structure was before the oncreate of application, so does the contentprovider part have a context reference that needs to be replaced? From the Framework/base/core/java/android/app can be found Activitythread.java from the part of the loading contentprovider can be seen, Assuming that the package name of the current context is the same as the Providerinfo package name, ContentProvider will refer to the context of the current myproxyapplication. Because the current myproxyapplication is just for agent start-up, So it is possible to avoid contentprovider reuse of the current context by Myproxyapplication Getpackagename and returning null.

    Private Iactivitymanager.contentproviderholder Installprovider (context context, Iactivitymanager.contentpro Viderholder Holder, Providerinfo info, Boolean noisy, Boolean noreleaseneeded, Boolean stable) {Content        Provider localprovider = null;        Icontentprovider provider; if (Holder = = NULL | | holder.provider = = NULL) {if (Debug_provider | | noisy) {SLOG.D (TAG, "Loa            Ding provider "+ info.authority +": "+ info.name);            } Context c = null;            ApplicationInfo ai = info.applicationinfo;            if (Context.getpackagename (). Equals (Ai.packagename)) {c = context; } else if (minitialapplication! = null && minitialapplication.getpackagename (). Equals (Ai.packag            ename)) {c = minitialapplication;    } else {try {c = context.createpackagecontext (Ai.packagename,                        Context.context_include_code); } catch (Packagemanager.namenotfoundexception e) {//Ignore}}
Three. SummaryThis is just a simple walk down the proxy/delegate framework of the process, the framework in fact there are a lot of use scenarios, such as multi-dex dynamic loading, plug-in, online program hot fix bug, etc. can flexibly use a lot of interesting technology, If you have time, you will be sent a blog with proxy/delegate implementation of online program hot fix bug.

Reprint Please specify source: http://blog.csdn.net/l2show/article/details/46914881

Android Source code Deskclock (iii) PROXY/DELEGATE application Framework Application

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.