青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

專職C++

不能停止的腳步

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  163 Posts :: 7 Stories :: 135 Comments :: 0 Trackbacks

常用鏈接

留言簿(28)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

原文:http://www.cnblogs.com/zjoch/p/6018432.html

Dexposed是基于久負盛名的開源Xposed框架實現的一個Android平臺上功能強大的無侵入式運行時AOP框架。

Dexposed的AOP實現是完全非侵入式的,沒有使用任何注解處理器,編織器或者字節碼重寫器。集成Dexposed框架很簡單,只需要在應用初始化階段加載一個很小的JNI庫就可以,這個加載操作已經封裝在DexposedBridge函數庫里面的canDexposed函數中,源碼如下所示:

/**  * Check device if can run dexposed, and load libs auto.  */ public synchronized static boolean canDexposed(Context context) {     if (!DeviceCheck.isDeviceSupport(context)) {         return false;     }     //load xposed lib for hook.     return loadDexposedLib(context); }  private static boolean loadDexposedLib(Context context) {     // load xposed lib for hook.     try {         if (android.os.Build.VERSION.SDK_INT > 19){             System.loadLibrary("dexposed_l");         } else if (android.os.Build.VERSION.SDK_INT == 10                 || android.os.Build.VERSION.SDK_INT == 9 ||                  android.os.Build.VERSION.SDK_INT > 14){             System.loadLibrary("dexposed");         }         return true;     } catch (Throwable e) {         return false;     } }

Dexposed實現的hooking,不僅可以hook應用中的自定義函數,也可以hook應用中調用的Android框架的函數。Android開發者將從這一點得到很多好處,因為我們嚴重依賴于Android SDK的版本碎片化。

基于動態類加載技術,運行中的app可以加載一小段經過編譯的Java AOP代碼,在不需要重啟app的前提下實現修改目標app的行為。

典型的使用場景

  • AOP編程
  • 插樁(例如測試,性能監控等)
  • 在線熱更新,修復嚴重的,緊急的或者安全性的bug
  • SDK hooking以提供更好的開發體驗

如何集成

集成方式很簡單,只需要將一個jar包加入項目的libs文件夾中,同時將兩個so文件添加到jniLibs中對應的ABI目錄中即可。Gradle依賴如下所示:

buildscript {   repositories {     mavenCentral()   }   dependencies {     classpath 'com.android.tools.build:gradle:0.10.+'     classpath 'com.nabilhachicha:android-native-dependencies:0.1'   } }  ...  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') }

其中,native_dependencies是一個第三方插件,使用方法可參考《如何在Android Gradle中添加原生so文件依賴》。當然,我們也可以直接把需要用到的so文件直接拷貝到jniLibs目錄中,這樣的話,可以把上面的native_dependencies代碼段注釋掉。

同時應該在應用初始化的地方(盡可能早的添加)添加初始化Dexposed的代碼,例如在MyApplication中添加:

public class MyApplication extends Application {      private boolean mIsSupported = false; // 設備是否支持dexposed      private boolean mIsLDevice = false;  // 設備Android系統是否是Android 5.0及以上      @Override     public void onCreate() {         super.onCreate();          // check device if support and auto load libs         mIsSupported = DexposedBridge.canDexposed(this);         mIsLDevice = Build.VERSION.SDK_INT >= 21;     }      public boolean isSupported() {         return mIsSupported;     }      public boolean isLDevice() {         return mIsLDevice;     } }

基本用法

對于某個函數而言,有三個注入點可供選擇:函數執行前注入(before),函數執行后注入(after),替換函數執行的代碼段(replace),分別對應于抽象類XC_MethodHook及其子類XC_MethodReplacement中的函數:

public abstract class XC_MethodHook extends XCallback {      /**      * Called before the invocation of the method.      * <p>Can use {@link MethodHookParam#setResult(Object)} and {@link MethodHookParam#setThrowable(Throwable)}      * to prevent the original method from being called.      */     protected void beforeHookedMethod(MethodHookParam param) throws Throwable {}      /**      * Called after the invocation of the method.      * <p>Can use {@link MethodHookParam#setResult(Object)} and {@link MethodHookParam#setThrowable(Throwable)}      * to modify the return value of the original method.      */     protected void afterHookedMethod(MethodHookParam param) throws Throwable  {} }
public abstract class XC_MethodReplacement extends XC_MethodHook {      @Override     protected final void beforeHookedMethod(MethodHookParam param) throws Throwable {         try {             Object result = replaceHookedMethod(param);             param.setResult(result);         } catch (Throwable t) {             param.setThrowable(t);         }     }      protected final void afterHookedMethod(MethodHookParam param) throws Throwable {     }      /**      * Shortcut for replacing a method completely. Whatever is returned/thrown here is taken      * instead of the result of the original method (which will not be called).      */     protected abstract Object replaceHookedMethod(MethodHookParam param) throws Throwable; }

可以看到這三個注入回調函數都有一個類型為MethodHookParam的參數,這個參數包含了一些很有用的信息:

  • MethodHookParam.thisObject:這個類的一個實例
  • MethodHookParam.args:用于傳遞被注入函數的所有參數
  • MethodHookParam.setResult:用于修改原函數調用的結果,如果在beforeHookedMethod回調函數中調用setResult,可以阻止對原函數的調用。但是如果有返回值的話仍然需要通過hook處理器進行return操作。

MethodHookParam代碼如下所示:

public static class MethodHookParam extends XCallback.Param {     /** Description of the hooked method */     public Member method;     /** The <code>this</code> reference for an instance method, or null for static methods */     public Object thisObject;     /** Arguments to the method call */     public Object[] args;      private Object result = null;     private Throwable throwable = null;     /* package */ boolean returnEarly = false;      /** Returns the result of the method call */     public Object getResult() {         return result;     }      /**      * Modify the result of the method call. In a "before-method-call"      * hook, prevents the call to the original method.      * You still need to "return" from the hook handler if required.      */     public void setResult(Object result) {         this.result = result;         this.throwable = null;         this.returnEarly = true;     }      /** Returns the <code>Throwable</code> thrown by the method, or null */     public Throwable getThrowable() {         return throwable;     }      /** Returns true if an exception was thrown by the method */     public boolean hasThrowable() {         return throwable != null;     }      /**      * Modify the exception thrown of the method call. In a "before-method-call"      * hook, prevents the call to the original method.      * You still need to "return" from the hook handler if required.      */     public void setThrowable(Throwable throwable) {         this.throwable = throwable;         this.result = null;         this.returnEarly = true;     }      /** Returns the result of the method call, or throws the Throwable caused by it */     public Object getResultOrThrowable() throws Throwable {         if (throwable != null)             throw throwable;         return result;     } }

例子一:AOP編程

AOP(Aspect Oriented Programming),也就是面向方面編程,是通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

AOP一般應用在日志記錄,性能統計,安全控制,事務處理,異常處理等方面,它的主要意圖是將日志記錄,性能統計,安全控制,事務處理,異常處理等代碼從業務邏輯代碼中劃分出來,通過對這些行為的分離,我們希望可以將它們獨立到非業務邏輯的方法中,進而改變這些行為的時候不影響業務邏輯的代碼。

例如我們可以在應用中所有的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 before 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() will 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);     } });

當然也可以替換目標函數原來執行的代碼段:

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.             ...         }      });

例子二:在線熱更新

在線熱更新一般用于修復線上嚴重的,緊急的或者安全性的bug,這里會涉及到兩個apk文件,一個我們稱為宿主apk,也就是發布到應用市場的apk,一個稱為補丁apk。宿主apk出現bug時,通過在線下載的方式從服務器下載到補丁apk,使用補丁apk中的函數替換原來的函數,從而實現在線修復bug的功能。

為了實現這個功能,需要再引入一個名為patchloader的jar包,這個函數庫實現了一個熱更新框架,宿主apk在發布時會將這個jar包一起打包進apk中,而補丁apk只是在編譯時需要這個jar包,但打包成apk時不包含這個jar包,以免補丁apk集成到宿主apk中時發生沖突。因此,補丁apk將會以provided的形式依賴dexposedbridge.jar和patchloader.jar,補丁apk的build.gradle文件中依賴部分腳本如下所示:

dependencies {     provided files('libs/dexposedbridge.jar')     provided files('libs/patchloader.jar') }

這里我們假設宿主apk的MainActivity.showDialog函數出現問題,需要打補丁,宿主代碼如下所示:(類完整路徑是com.taobao.dexposed.MainActivity)

package com.taobao.dexposed;  public class MainActivity extends Activity {      private void showDialog() {         AlertDialog.Builder builder = new AlertDialog.Builder(this);         builder.setTitle("Dexposed sample")                 .setMessage(                         "Please clone patchsample project to generate apk, and copy it to \"/Android/data/com.taobao.dexposed/cache/patch.apk\"")                 .setPositiveButton("ok", new DialogInterface.OnClickListener() {                     public void onClick(DialogInterface dialog, int whichButton) {                     }                 }).create().show();     } }

補丁apk只有一個名為DialogPatch的類,實現了patchloader函數庫中的IPatch接口,IPatch接口代碼如下所示:

/**  * The interface implemented by hotpatch classes.  */ public interface IPatch {      void handlePatch(PatchParam lpparam) throws Throwable;  }

DialogPatch類實現IPatch的handlePatch函數,在該函數中通過反射得到宿主APK中com.taobao.dexposed.MainActivity類實例,然后調用dexposedbridge函數庫中的DexposedBridge.findAndHookMethod函數,對MainActivity中的showDialog函數進行Hook操作,替換宿主apk中的相應代碼,DialogPatch代碼如下所示:

public class DialogPatch implements IPatch {      @Override     public void handlePatch(final PatchParam arg0) throws Throwable {                 Class<?> cls = null;         try {             cls= arg0.context.getClassLoader()                 .loadClass("com.taobao.dexposed.MainActivity");         } catch (ClassNotFoundException e) {             e.printStackTrace();             return;         }                   DexposedBridge.findAndHookMethod(cls, "showDialog",             new XC_MethodReplacement() {             @Override             protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {                 Activity mainActivity = (Activity) param.thisObject;                 AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity);                 builder.setTitle("Dexposed sample")                         .setMessage("The dialog is shown from patch apk!")                         .setPositiveButton("ok", new DialogInterface.OnClickListener() {                             public void onClick(DialogInterface dialog, int whichButton) {                             }                         }).create().show();                 return null;                              }         });     }  }

最后宿主apk通過調用patchloader函數庫提供的PatchMain.load函數來動態加載下載到的補丁apk,加載代碼如下所示:

// Run patch apk public void runPatchApk(View view) {     Log.d("dexposed", "runPatchApk button clicked.");     if (isLDevice) {         showLog("dexposed", "It doesn't support this function on L device.");         return;     }     if (!isSupport) {         Log.d("dexposed", "This device doesn't support dexposed!");         return;     }     File cacheDir = getExternalCacheDir();     if(cacheDir != null){         String fullpath = cacheDir.getAbsolutePath() + File.separator + "patch.apk";         PatchResult result = PatchMain.load(this, fullpath, null);         if (result.isSuccess()) {             Log.e("Hotpatch", "patch success!");         } else {             Log.e("Hotpatch", "patch error is " + result.getErrorInfo());         }     }     showDialog(); }

為便于理解,這里也把load函數體貼出來,更詳細內容大家可以看源碼:

/**  * Load a runnable patch apk.  *  * @param context the application or activity context.  * @param apkPath the path of patch apk file.  * @param contentMap the object maps that will be used by patch classes.    * @return PatchResult include if success or error detail.  */ public static PatchResult load(Context context, String apkPath, HashMap<String, Object> contentMap) {      if (!new File(apkPath).exists()) {         return new PatchResult(false, PatchResult.FILE_NOT_FOUND, "FILE not found on " + apkPath);     }      PatchResult result = loadAllCallbacks(context, apkPath,context.getClassLoader());     if (!result.isSuccess()) {         return result;     }      if (loadedPatchCallbacks.getSize() == 0) {         return new PatchResult(false, PatchResult.NO_PATCH_CLASS_HANDLE, "No patch class to be handle");     }      PatchParam lpparam = new PatchParam(loadedPatchCallbacks);             lpparam.context = context;     lpparam.contentMap = contentMap;      return PatchCallback.callAll(lpparam); }

支持的系統版本

Dexposed支持從Android2.3到4.4(除了3.0)的所有dalvid運行時arm架構的設備,穩定性已經經過實踐檢驗。

支持的系統版本:

  • Dalvik 2.3
  • Dalvik 4.0~4.4

不支持的系統版本:

  • Dalvik 3.0
  • ART 5.1
  • ART M

測試中的系統版本:

  • ART 5.0

未經測試的系統版本:

  • Dalvik 2.2

使用Dexposed的項目

目前阿里系主流app例如手機淘寶,支付寶,天貓都使用了Dexposed支持在線熱更新,而開源項目中,在Github上面能搜到的只有一個XLog項目,它的主要功能是方便的打印函數調用和耗時日志,這也是一個了解Dexposed如何使用的很好的例子。

參考資料



文/asce1885(簡書作者)
原文鏈接:http://www.jianshu.com/p/14edcb444c51
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
posted on 2016-11-29 12:35 冬瓜 閱讀(538) 評論(0)  編輯 收藏 引用 所屬分類: 轉貼
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品国精品久久99热| 国产精品亚洲综合天堂夜夜| 亚洲第一福利视频| 欧美视频国产精品| 久久亚洲风情| 久久免费观看视频| 欧美成人精品在线观看| 久久久久亚洲综合| 久久精品亚洲乱码伦伦中文| 99成人免费视频| 亚洲午夜羞羞片| 国产欧美一区二区三区视频 | 女人色偷偷aa久久天堂| 久久精品成人| 久久都是精品| 久久久99爱| 久久久久国色av免费看影院| 午夜一区二区三视频在线观看| 亚洲美女av电影| 在线亚洲欧美专区二区| 亚洲精品一级| 亚洲欧美日韩精品| 久久天天狠狠| 欧美日韩亚洲一区二区三区在线观看| 欧美精品在线看| 国产精品美女久久久久久久| 欧美激情视频一区二区三区在线播放| 欧美激情综合色| 欧美无砖砖区免费| 国产老肥熟一区二区三区| 国产伦精品一区二区三区照片91 | 国产精品ⅴa在线观看h| 亚洲国产精品久久久| 亚洲黄色成人网| 亚洲欧美国产精品va在线观看| 久久大逼视频| 亚洲三级影院| 久久精品国产第一区二区三区| 欧美成年人视频网站欧美| 国产精品国内视频| 亚洲国产精品v| 久久―日本道色综合久久| 欧美成人精品一区二区三区| 亚洲成人资源| 欧美一区二区三区久久精品茉莉花 | 乱码第一页成人| 国产精品国产一区二区| 亚洲第一精品夜夜躁人人爽 | 一区二区三区色| 免费欧美日韩| 国产一区二区观看| 中日韩在线视频| 亚洲国产精品久久久久婷婷老年| 亚洲精品裸体| 蜜桃av一区二区| 韩国精品主播一区二区在线观看| 国产综合网站| 亚洲一区二区三区精品在线| 香蕉久久久久久久av网站| 欧美国产日韩二区| 久久婷婷成人综合色| 亚洲视频欧洲视频| 欧美另类一区| 一区二区日韩伦理片| 免费美女久久99| 欧美性色aⅴ视频一区日韩精品| 亚洲视频一区二区在线观看| 亚洲欧美一区二区在线观看| 老司机午夜精品视频在线观看| 国产精品久久久久av免费| 亚洲精品国产系列| 欧美国产精品久久| 麻豆成人91精品二区三区| 国产亚洲欧美一区二区| 一卡二卡3卡四卡高清精品视频| 久久男女视频| 久久免费99精品久久久久久| 国产精品久久77777| 亚洲调教视频在线观看| 亚洲人妖在线| 老司机精品视频一区二区三区| 国产精品网站在线| 久久aⅴ乱码一区二区三区| 99热这里只有精品8| 欧美jizzhd精品欧美喷水| 亚洲国产日韩欧美在线99| 久久亚裔精品欧美| 欧美xx69| 在线亚洲一区观看| 在线视频精品一| 国产精品呻吟| 久久国产精品网站| 久久午夜精品| 亚洲天堂av图片| 欧美亚洲一级| 国产精品二区在线| 久久免费视频在线观看| 美女91精品| 亚洲国产经典视频| 在线亚洲欧美视频| 国产亚洲欧美日韩日本| 久久大香伊蕉在人线观看热2| 欧美专区日韩专区| 亚洲日产国产精品| 亚洲桃色在线一区| 一区二区亚洲欧洲国产日韩| 免费欧美日韩| 国产精品一区久久久| 久久久久网址| 欧美精品自拍偷拍动漫精品| 亚洲伊人色欲综合网| 久久黄色影院| 亚洲欧美一区二区三区极速播放 | 国产午夜精品麻豆| 亚洲黄页一区| 国产视频一区在线| 日韩特黄影片| 亚洲国产三级网| 午夜精品福利一区二区蜜股av| 国产亚洲精品高潮| 一区二区日韩免费看| 黄网站色欧美视频| 欧美中文字幕不卡| 美女黄色成人网| 国产精品免费网站| 欧美二区在线播放| 国产婷婷一区二区| 国产精品99久久不卡二区| 国产麻豆精品theporn| 亚洲二区视频在线| 国产亚洲欧洲一区高清在线观看| 91久久香蕉国产日韩欧美9色| 国产一区二区看久久| 亚洲精品一区中文| 亚洲精品国产精品国自产观看| 性久久久久久久久久久久| 一区二区三区日韩| 欧美国产日韩一区二区在线观看 | 亚洲欧美日韩国产成人精品影院 | 欧美国产欧美亚洲国产日韩mv天天看完整 | 久久av二区| 久久大综合网| 国产亚洲va综合人人澡精品| 麻豆精品网站| 亚洲第一黄网| 免费成人毛片| 欧美激情四色| 亚洲精选久久| 欧美日韩亚洲三区| 一本色道久久88亚洲综合88| 黄色一区三区| 日韩午夜剧场| 欧美在线亚洲在线| 国产情侣久久| 久久久久一区二区三区| 欧美亚洲一级片| 国精品一区二区三区| 香蕉国产精品偷在线观看不卡| 亚洲一区三区电影在线观看| 免费观看国产成人| 亚洲精品无人区| 午夜一区二区三区不卡视频| 欧美国产大片| 亚洲精品永久免费| 欧美三区在线视频| 午夜亚洲精品| 欧美黄色小视频| 亚洲一区二区三区四区视频| 欧美激情中文不卡| 亚洲午夜激情网页| 久久综合五月天婷婷伊人| 亚洲国产精品福利| 欧美日韩在线观看视频| 亚洲深夜av| 欧美 日韩 国产 一区| 亚洲国产精品va| 国产精品v欧美精品v日本精品动漫| 亚洲精品美女91| 亚洲精品一区在线| 亚洲欧美日韩天堂| 亚洲国产高清在线观看视频| 香蕉久久国产| 亚洲精品影院| 美女精品网站| 亚洲欧美日韩一区二区| 欧美凹凸一区二区三区视频| 在线观看视频亚洲| 欧美日韩一区二区三区免费看| 亚洲一区高清| 亚洲欧洲精品一区二区三区| 一本大道久久精品懂色aⅴ| 国产欧美一区二区精品婷婷| 久久av最新网址| 亚洲一区二区伦理| 亚洲九九九在线观看| 久久色在线观看| 久久成人18免费网站| 免费日韩av| 久久成人精品无人区| 欧美一级黄色网|