Preliminary analysis of Alibaba dexposed

Source: Internet
Author: User

Alibaba a new non-intrusive AOP library, feel good, then the landlord this time to learn the specific application of this library, the principle and can achieve the effect.


The corresponding GitHub engineering portal is given here: https://github.com/alibaba/dexposed


1. First of all, how to use the specific usage of dexposed, how to introduce into our project.

This is actually very clear from Dexposed's GitHub project, and here I'll recap.

First we will introduce it into the project:

native_dependencies {    artifact ‘com.taobao.dexposed:dexposed_l:0.2+:armeabi‘    artifact ‘com.taobao.dexposed:dexposed:0.2+:armeabi‘}dependencies {    compile files(‘libs/dexposedbridge.jar‘)}

See Libdexposed.so and Libdexposed_l.so, may think of their differences is what, see loaddexposedlib This method is actually easy to see out:

private static Boolean Loaddexposedlib (context context) {        try {            if (VERSION. Sdk_int! = && VERSION. Sdk_int! = 9) {                if (VERSION. Sdk_int >) {                    system.loadlibrary ("dexposed_l");                } else {                    system.loadlibrary ("dexposed");}            } else {                system.loadlibrary ("dexposed2.3");            }            return true;        } catch (Throwable var2) {            return false;        }    }

When the SDK version is greater than 19, and is more than 5.0, will call dexposed_l, otherwise it will call dexposed, as for why two sets of different native implementations, will be explained later.


Once integrated into our project, if you want to apply it, simply a word:

public class MyApplication extends application {@Override public void onCreate () { Check whether current device was supported (also initialize dexposed framework if not yet) if (Dexposedbridge            . candexposed (this)) {//use dexposed to kick off AOP stuffs.    ...        } }    ...}
Referring to the code given on Git, the official recommendation is to call this method on the application layer. It is worth noting that dexposedbridge.candexposed (this) is a function that corresponds to the return value of the Boolean type, if False it is not possible to implement the hook function, so be careful to record this return value, In order to determine whether the hook can be executed if it is called elsewhere.


2. So now that we've introduced it to the project, the next step is to study how to use the library.

Example 1:attach a piece of code before and after all occurrences of Activity.onCreate(Bundle) .

    Target class, method with parameter types, followed by the hook callback (Xc_methodhook). Dexposedbridge.findandhookmethod (Activity.class, "OnCreate", Bundle.class, New Xc_methodhook () {//To be invoked B        Efore activity.oncreate ().  @Override protected void Beforehookedmethod (Methodhookparam param) throws Throwable {//"thisobject" keeps the            Reference to the instance of target class.            Activity instance = (activity) Param.thisobject;            The array args include all the parameters.            Bundle bundle = (bundle) param.args[0];            Intent Intent = new Intent ();            Xposedhelpers provide useful utility methods.            Xposedhelpers.setobjectfield (Param.thisobject, "mintent", intent);            Calling Setresult () would bypass the original method body use the result as method return value directly.        if (Bundle.containskey ("return")) Param.setresult (null); }//To be INVOKed after Activity.oncreate () @Override protected void Afterhookedmethod (Methodhookparam param) throws Throwable {        Xposedhelpers.callmethod (Param.thisobject, "SampleMethod", 2); }    });

example 2:replace the original body of the target method.

    DexposedBridge.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodReplacement() {        @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {            // Re-writing the method logic outside the original method context is a bit tricky but still viable.            ...        }    });
The above two example are the two most basic usage on git. Other uses of overextended are based on the use of these two bases.

In example1, we can see that the implementation of the original function is not changed with dexposed, but there are some other things that can be done before and after the original function is executed, such as changing the entry and return values, and so on.

In example2, it is possible to replace the original function to execute a new execution function that we need.


Based on the above two implementations, what can we derive from the application scenario? Some people say that the hook API specifically can achieve what, all by the user's imagination, in fact, indeed.

Some of the officially listed applications are now more needed:

    • Typical AOP programming

    • Instrumentation (testing, performance monitoring, etc.)

    • Online hot fixes (important, critical, security holes, etc.)

    • SDK hooking for a better development experience


3. Since the application of a library, we must have a certain understanding of its implementation and principles

Here is a more official introduction:

The principle of AOP in dexposed comes from xposed. Under the Dalvik virtual machine, it is mainly implemented by changing the definition of a Method object method in the Dalvik virtual machine, by changing the method's type to native and linking the implementation of this method to a general native dispatch method. This dispatch method uses the JNI callback to the Java side of a unified processing method, and finally in the unified processing method called before, after function to implement AOP. The art virtual machine is also currently implemented by changing an Artmethod entry function.

From the above can know the basic implementation process, in addition to the above mentioned two concepts, Dalvik virtual machine and art virtual machine, here to do a bit of science.


What is Dalvik:

Dalvik is a Java virtual machine designed by Google to be used on Android platforms. Dalvik virtual Machine is one of the core components of Android mobile device platform developed by Google and other manufacturers. It can support the operation of a Java application that has been converted to. Dex (that is, Dalvik executable) format, which is a compression format designed for Dalvik and is suitable for systems with limited memory and processor speed. Dalvik is optimized to allow instances of multiple virtual machines to run concurrently in limited memory, and each Dalvik application executes as a standalone Linux process. A standalone process can prevent all programs from shutting down when the virtual machine crashes.


What is art:
The Android operating system is ripe, and Google's Android team is starting to turn its attention to some of the underlying components, one of which is the Dalvik runtime responsible for running the application. Google developers have spent more than two years developing faster, more efficient and more power-saving alternative art runtimes. Art stands for Android Runtime, which handles application execution in a completely different way than Dalvik,dalvik relies on a just-in-time (JIT) compiler to interpret bytecode. Developer-compiled application code requires an interpreter to run on the user's device, which is not efficient, but makes it easier for applications to run on different hardware and architectures. Art has completely changed this approach by pre-compiling bytecode to machine language when the installation is applied, called Ahead-of-time (AOT) compilation. After removing the process of interpreting the code, application execution is more efficient and faster to start.


Art Benefits:
1, the system performance significantly improved.
2. Applications start faster, run faster, experience smoother, and feel more responsive.
3, longer battery life capability.
4, support the lower hardware.

Art Disadvantages:
1, larger storage space occupancy, may increase by 10%-20%.
2, longer application installation time.

The effect of art is, in general, "space for Time".


Google has replaced the Dalvik with art in the version after android4.4, so it is necessary to hook up with the mechanism of the art virtual machine for android4.4 later versions. This also explains why there are dexposed and dexposed_l two so. At present, the official said that in order to adapt to art dexposed_l is only a beta version, so it is best not to use it in official online products.


Next, a little bit to analyze the Java part code structure of the corresponding jar package:



Actually very concise, Dexposedbrigde is the main function call class, xposedhelpers is a reflection function class, others are some auxiliary classes.

Engineering is used to hook the method Dexposedbridge.findandhookmethod, then here to see the Java part of the function of the execution process:

public static Unhook Findandhookmethod (class<?> clazz, String methodName, Object ... parametertypesandcallback) { if (parametertypesandcallback.length! = 0 && parametertypesandcallback[parametertypesandcallback.length-1] I Nstanceof xc_methodhook) {Xc_methodhook callback = (Xc_methodhook) PARAMETERTYPESANDCALLBACK[PARAMETERTYPESANDC            ALLBACK.LENGTH-1]; <span style= "color: #ff0000;"  >method m = xposedhelpers.findmethodexact (Clazz, MethodName, parametertypesandcallback);</span> Unhook            Unhook = Hookmethod (M, callback); if (! ( Callback instanceof Xc_methodkeephook) &&! (Callback instanceof Xc_methodkeepreplacement))                {ArrayList VAR6 = allunhookcallbacks;                Synchronized (allunhookcallbacks) {allunhookcallbacks.add (unhook);        }} return unhook;    } else {throw new IllegalArgumentException ("No callback defined");    }    } 

First, the corresponding method is found by xposedhelpers the findmethodexact methods of the Reflection tool class.


The Hookmethod is then executed:

public static Unhook Hookmethod (Member Hookmethod, Xc_methodhook callback) {if (! ( Hookmethod instanceof Method) &&! (Hookmethod instanceof Constructor))        {throw new IllegalArgumentException ("Only methods and constructors can be hooked");            } else {Boolean newmethod = false;            Map declaringclass = hookedmethodcallbacks;            Dexposedbridge.copyonwritesortedset callbacks; Synchronized (hookedmethodcallbacks) {callbacks = (Dexposedbridge.copyonwritesortedset) hookedmethodcallback                S.get (Hookmethod);                    if (callbacks = = null) {callbacks = new Dexposedbridge.copyonwritesortedset ();                    Hookedmethodcallbacks.put (Hookmethod, callbacks);                Newmethod = true;            }} callbacks.add (callback);                if (newmethod) {Class declaringClass1 = Hookmethod.getdeclaringclass (); int slot = Runtime= = 1?                Xposedhelpers.getintfield (Hookmethod, "slot"): 0;                Class[] parametertypes;                Class ReturnType;                    if (Hookmethod instanceof Method) {parametertypes = (method) Hookmethod). Getparametertypes ();                ReturnType = (Method) hookmethod). Getreturntype ();                    } else {parametertypes = ((Constructor) hookmethod). Getparametertypes ();                ReturnType = null; } dexposedbridge.additionalhookinfo AdditionalInfo = new Dexposedbridge.additionalhookinfo (callbacks, param                Etertypes, ReturnType, (dexposedbridge.additionalhookinfo) null); <span style= "color: #ff0000;" >hookmethodnative (Hookmethod, DeclaringClass1, slot, additionalinfo);</span>} callback.get            Class ();        return new Unhook (callback, Hookmethod); }    }

The parameters we need to pass to hookmethodnative here are 1. According to the reflection of the location to the hook to the method;2. The declaration defines the tag of the class;3.slot tag runtime for the method, 4. Contains the function entry, Returns a value type and a custom class corresponding to the callback. Then the corresponding Hook,java end of the code is completed is relatively simple and clear. As for the concrete implementation of the native, the landlord is not here in detail analysis. The C code corresponding to Hookmethodnative can be given here.

static void Com_taobao_android_dexposed_dexposedbridge_hookmethodnative (jnienv* env, Jclass Clazz, Jobject Reflectedmethodindirect, Jobject Declaredclassindirect, jint slot, Jobject additionalinfoindirect) {//Usag    E errors? if (Declaredclassindirect = = NULL | | reflectedmethodindirect = = NULL) {dvmthrowillegalargumentexception ("method an        D Declaredclass must not being null ");    Return }//Find The internal representation of the method classobject* Declaredclass = (classobject*) dvmdecodeindirec    TRef (Dvmthreadself (), declaredclassindirect);    method* method = Dvmslottomethod (Declaredclass, slot);        if (method = = NULL) {Dvmthrownosuchmethoderror ("could not get internal representation for method");    Return    } if (dexposedishooked (method)) {//already hooked return; }//Save a copy of the original method and other hooks info dexposedhookinfo* hookinfo = (dexposedhookinfo*) cal LOC (1, sizeof (dexposeDhookinfo));    memcpy (Hookinfo, method, sizeof (hookinfo->originalmethodstruct)); Hookinfo->reflectedmethod = Dvmdecodeindirectref (Dvmthreadself (), Env->newglobalref (reflectedMethodIndirect    )); Hookinfo->additionalinfo = Dvmdecodeindirectref (Dvmthreadself (), Env->newglobalref (AdditionalInfoIndirect))    ;    Replace method with our own code Set_method_flag (method, acc_native);    Method->nativefunc = &dexposedCallHandler;    Method->insns = (const u2*) hookinfo;    Method->registerssize = method->inssize;    method->outssize = 0;    if (Ptr_gdvmjit! = NULL) {//Reset JIT cache Member_val (Ptr_gdvmjit, dvmjitglobals, codecachefull) = true; }}
As for children's shoes interested in research, you can go to GitHub to see the full code, and delve into it, which involves more android underlying knowledge.

4. Since we also understand the implementation and principles of the part, Dexposed has one of the most attractive places is the ability to have hot patches

Android developers know that for Android such a client application, once the online bug, the only solution is to send a repair package to upgrade the repair, which is very inflexible, and the experience is poor. In the case of non-release, the dynamic repair of online bugs is urgently needed. Here's a demonstration of how to apply dexposed to fix a bug on a line.

GitHub has given the corresponding example, the landlord on this basis to expand and improve.


First add this method to your app:

Run taobao.patch apk public    void runpatchapk () {        if (Android.os.Build.VERSION.SDK_INT = =) {            return;
   }        if (!issupport) {            log.d ("dexposed", "This device doesn ' t-support dexposed!");            return;        }        File Cachedir = <span style= "color: #ff0000;" >getexternalcachedir ();</span>        if (cachedir! = null) {            String fullpath = Cachedir.getabsolutepath () + File.separator + "patch.apk";            Patchresult result = <span style= "color: #ff0000;" >patchmain.load (this, fullpath, null);</span>            if (result.issuccess ()) {                log.e ("HotPatch", "Patch Success! ");            } else {                log.e ("HotPatch", "Patch error is" + Result.geterrorinfo ());}}}    

The folder path for storing patch.apk, which is the patch file, can be defined according to your own requirements. The main function of patchmain.load implementation is to traverse the Ipatch class in patch.apk and invoke the Handlepatch method in it. Note: It is best to add this method to the application OnCreate method, which guarantees that the program is initialized with a patch. Then of course you have to have an app must have a go to the background to check if you need to download the patch of the interface, if it is best to use a silent download method, silent repair. When the download is complete, remember to call runpatchapk this method dynamically, otherwise the patch will not take effect.


Then take a look at how the corresponding patch.apk project should be built.


Only need to introduce Dexposedbridge.jar and Patchloader.jar, and then com.taobao.patch the package name, to add the corresponding Ipatch class can be.


Then we imagine the online version of the picture shows a problem, how can we apply dexposed hot patch function to repair it.

public class Viewpatch implements Ipatch {    @Override public    void Handlepatch (Patchparam patchparam) throws Throwable {        class<?> cls = null;        try {            cls = PatchParam.context.getClassLoader ()                    . LoadClass ("com.husor.mizhe.activity.SplashActivity");        } catch (ClassNotFoundException e) {            e.printstacktrace ();            return;        }        Dexposedbridge.findandhookmethod (CLS, "Initview",                new Xc_methodhook () {                    @Override                    protected void Afterhookedmethod (Methodhookparam param) throws Throwable {                        activity mainactivity = (activity) param.thisobject;< C15/>imageview Bottomview = (ImageView) Xposedhelpers.getobjectfield (mainactivity, "Iv_start_bottom");                        Bottomview.setimageresource (0x7f020175);}}                );}    }

We first through the loadclass to locate the problem class, and then through the hook method, the Splashactivity Initview method set the image error ImageView, set to We want to properly resourceid.


Summarize:

This library is mainly applied to the reflection mechanism of Java at Java level, and when applying the library hook function, it will also have higher requirements for the user's reflection knowledge, especially in the application scenario of hot patches, can only get the corresponding function and member variables by reflection, and manipulate them accordingly.


Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Preliminary analysis of Alibaba dexposed

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.