1. 程式人生 > >Android新技術學習——阿里巴巴免Root無侵入AOP框架Dexposed

Android新技術學習——阿里巴巴免Root無侵入AOP框架Dexposed

阿里巴巴無線事業部最近開源的Android平臺下的無侵入執行期AOP框架Dexposed,該框架基於AOP思想,支援經典的AOP使用場景,可應用於日誌記錄,效能統計,安全控制,事務處理,異常處理等方面。
針對Android平臺,Dexposed支援函式級別的線上熱更新,例如對已經發布在應用市場上的宿主APK,當我們從crash統計平臺上發現某個函式呼叫有bug,導致經常性crash,這時,可以在本地開發一個補丁APK,併發布到伺服器中,宿主APK下載這個補丁APK並整合後,就可以很容易修復這個crash。

Dexposed是基於久負盛名的開源Xposed框架實現的一個Android平臺上功能強大的無侵入式執行時AOP框架。Dexposed的AOP實現是完全非侵入式的,沒有使用任何註解處理器,編織器或者位元組碼重寫器

先來講講整合方法,從專案地址下載整個專案dexposed,將..\dexposed\sample\patchsample\app\libs目錄下的兩個jar拷出來備用,以及將..\dexposed\sample\dexposedexamples\app\src\main\jniLibs目錄下的native庫拷出來備用。

開啟Android Studio,新建專案,將前面拷出來的jar拷到libs目錄下,在main目錄下新建jniLibs目錄,將native庫拷進去。最終專案結構會成這樣
這裡寫圖片描述

為了應用熱更新,所以我們還要建一個module用於編寫熱更新的程式碼,用Android studio新建一個module,這裡讓其名叫patch,將之前的jar拷入到patch下的libs目錄。而native庫不需要拷。之後進行同步,點選如圖圖示
這裡寫圖片描述

我們在Application中檢查是否支援Dexposed,編寫一個子類繼承Application類,並在Manifest檔案中指定該類。

/**
 * User:lizhangqu([email protected])
 * Date:2015-08-06
 * Time: 13:46
 */
public class App extends Application {
    private boolean mIsSupported = false;
    private boolean mIsLDevice = false;
    @Override
    public void
onCreate() { super.onCreate(); mIsSupported= DexposedBridge.canDexposed(this); mIsLDevice= Build.VERSION.SDK_INT>=21; if (mIsSupported) { //do something } public boolean isSupported(){ return mIsSupported; } public boolean isLDevice(){ return mIsLDevice; } }

我們呼叫了 DexposedBridge.canDexposed函式用於判斷是否支援Dexposed,如果支援,我們則做下一步動作。

現在有這麼一個需求,需要給每個Activity的onCreate呼叫前增加日誌,呼叫完成後增加日誌,呼叫完成後需要呼叫另外一個統計用的方法。同時,需要直接替換掉MainActivity中的一個叫replaceMethod的方法。我們來編寫程式碼。

private void hook() {
        DexposedBridge.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                Log.e("TAG", "onCreate:" + param.thisObject.getClass().getSimpleName() + "start");
            }

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                Log.e("TAG", "onCreate:" + param.thisObject.getClass().getSimpleName() + "end");
                XposedHelpers.callMethod(param.thisObject, "statics", new Class[]{long.class}, System.currentTimeMillis());
            }
        });

        DexposedBridge.findAndHookMethod(MainActivity.class, "replaceMethod", new XC_MethodReplacement() {
            @Override
            protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                Log.e("TAG", "the method has replaced by DexposedBridge!");

                return "has replaced";
            }
        });

    }

程式碼中呼叫了 XposedHelpers.callMethod進行反射呼叫統計方法statics。

replcaeMethod方法的原型

    public String replaceMethod(){
        Log.e("TAG","replaceMethod");
        return "replaceMethod";
    }

statics方法原型

public void statics(long a){
        Log.e("TAG","==now:"+a+"==");
        //do something
    }

然後我們呼叫hook函式

if (mIsSupported) {
            hook();
        }

同時我們的MainActivity中進行了呼叫replaceMethod

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String result=replaceMethod();
        Log.d("TAG","result:"+result);


    }

這時候觀察一下日誌輸出

這裡寫圖片描述

我們發現在onCreate方法前後都有日誌輸出,並且onCreate後有統計方法的呼叫,而replaceMethod方法的內容以及完全被替換了。

我們開到前面使用了XposedHelpers類,這個類是一個輔助類,裡面全是跟反射相關的。使用了DexposedBridge.findAndHookMethod進行注入。

對於某個函式而言,有三個注入點可供選擇:函式執行前注入(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操作。

下面我們來應用一下線上熱更新

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

為了實現這個功能,需要再引入一個名為patchloader的jar包,我們已將將它拷到libs目錄下,這個函式庫實現了一個熱更新框架,宿主apk在釋出時會將這個jar包一起打包進apk中,而補丁apk只是在編譯時需要這個jar包,但打包成apk時不包含這個jar包,以免補丁apk整合到宿主apk中時發生衝突。因此,補丁apk將會以provided的形式依賴dexposedbridge.jar和patchloader.jar,補丁apk也就是patch的build.gradle檔案中依賴部分指令碼如下所示:

dependencies {
    provided fileTree(dir: 'libs', include: ['*.jar'])
}

現在假設我們MainActivity中有一個初始化資料的方法

    public List<String> initData() {
        return null;
    }

但是我們手誤返回了null,但是在MainActivity中呼叫了這個返回值的內容

    public void showTextView(){
        tv.setText(initData().get(0) + "");
    }

於是就產生了常見的異常,即空指標異常。我們使用patch來修復這個bug。我們需要實現IPatch介面

public class TestPatch implements IPatch {
    @Override
    public void handlePatch(PatchParam patchParam) throws Throwable {
        Log.e("TAG","handlePatch");
        Class<?> cls = null;
        try {
            cls= patchParam.context.getClassLoader()
                    .loadClass("zafu.edu.cn.dexposed.MainActivity");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return;
        }
        DexposedBridge.findAndHookMethod(cls, "initData",
                new XC_MethodReplacement() {
                    @Override
                    protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                        List<String> list=new ArrayList<String>();
                        list.add("1111111111");
                        list.add("2222222222");
                        list.add("3333333333");
                        list.add("4444444444");
                        //param.setResult(list);
                        return list;
                    }
                });
    }
}

我們的補丁程式返回了幾個資料,完成後我們生成module為patch的apk。然後將該apk拷到對應的目錄下,這裡簡單的將其拷到Android/data/your package/cache/pacth.apk目錄下。然後我們要應用該補丁

public void runPatchApk(){
        if (isLDevice()){
            Log.e("TAG","it does not support L");
            return;
        }

        if (!isSupported()){
            Log.e("TAG","It does not support!");
            return ;
        }

        File cacheDir = getExternalCacheDir();
        if(cacheDir != null){

            String fullpath = cacheDir.getAbsolutePath() + File.separator + "patch.apk";
            Log.e("PATH",fullpath);
            PatchResult result = PatchMain.load(this, fullpath, null);
            if (result.isSuccess()) {
                Log.e("Hotpatch", "patch success!");
            } else {
                Log.e("Hotpatch", "patch error is " + result.getErrorInfo());
            }
        }

    }
        if (mIsSupported) {
            hook();
            runPatchApk();
        }

之後你會發現不再報空指標了。

對於熱更新,我們可以在手機淘寶中找到它的影子。如下圖

這裡寫圖片描述

總之,該庫前途無量,但是目前支援的系統有限,也希望它能不斷髮展,造福開發者。

相關推薦

Android技術學習——阿里巴巴Root侵入AOP框架Dexposed

阿里巴巴無線事業部最近開源的Android平臺下的無侵入執行期AOP框架Dexposed,該框架基於AOP思想,支援經典的AOP使用場景,可應用於日誌記錄,效能統計,安全控制,事務處理,異常處理等方面。 針對Android平臺,Dexposed支援函

技術學習思路——工作一年的總結

感激 doc 谷歌 如果 自己 url 配置 官網 pip 在狼長正式工作一年有余,對於接觸到的新技術的學習已經不再有那麽多的畏懼感了,總結一下我對新技術的學習思路,希望能給大家提供一個參考。 工作一年接觸的新技術: bigpipe AMQ Elasticsearch k

技術學習之路

技術類 最好 好的 項目 身邊 bsp 百度谷歌 nbsp 運行 學習一門新技術,我們需要馬上能夠上手。作為一名新手,我談談自身的學習想法。 1.編程語言類 了解這門語言是什麽,主要用來做什麽,他的優缺點; 我們可以現在本機上安裝好運行環境,寫個hello wo

AIOPS案例學習-阿里巴巴構建通用智慧運維平臺

2017年線上技術分會——運維/DevOps線上技術峰會上,來自阿里基礎架構事業部大資料SRE團隊的池楓分享了構建通用化智慧運維體系的實踐。他主要介紹了智慧運維體系的設計以及通用核心套件,從T-flow操作執行、ICS事件連線、IAS智慧分析三個核心套件的實際案例出發詳細介紹了阿里的運維經驗。

Android中利用ZipEntry漏洞實現root寫惡意檔案到應用的沙盒中

http://blog.csdn.net/jiangwei0910410003/article/details/52118575   版權宣告:本文為博主原創文章,未經博主允許不得轉載。 目錄(?)[-] 一前言 二漏洞場景分析 三漏洞出現的原因 四

android技術

timg.jpg (16.33 KB, 下載次數: 34)下載附件  儲存到相簿2017-8-29 18:37 上傳Kotlin2018最新Java視訊教程http://www.apkbus.com/plugin.php?id=apkbus_video&op=item

Android技術PWA與GDD

20161208GDD PWA與原生開發之爭。AMP興起。Google Assistant。Daydream 可以提供高質量、沉浸式的虛擬現實體驗給廣大的使用者。 Instant Apps 的興起。

包建強的培訓課程(16):Android技術入門和提高

Android新技術入門和提高 一.簡介 # 課程簡介 結合講師5年來一線工作經驗,對Android業界的各種新技術、新思想的持續學習、研究以及付諸實踐,將研究心得和實踐經驗彙編成本課程。 # 受眾定位 本課程系列適合於從事Android開發1-2年的技術人員,幫助他們使

Ajax 頁面技術學習(GET)

Ajax是一種新的技術,因為不用重新整理頁面就可以讀取資訊,實現對頁面的區域性重新整理,這樣就減少了對全部頁面進行重新整理所帶來的時間響應問題,經過很長時間的學習研究,終於在該技術的學習上有了新的突破,目前的學習還很幼稚,有待提高,下面是本次實踐的成果 //script.js

阿里巴巴開源的通用快取訪問框架JetCache介紹

GenericObjectPoolConfig pc = new GenericObjectPoolConfig();pc.setMinIdle(2);pc.setMaxIdle(10);pc.setMaxTotal(10);JedisPool pool = new JedisPool(pc, "localh

優雅地實現Android主流圖片加載框架封裝,可侵入切換框架

ror 要去 out drawable 如果 jpg gre cached square 項目開發中,往往會隨著需求的改變而切換到其它圖片加載框架上去。如果最初代碼設計的耦合度太高,那麽恭喜你,成功入坑了。至今無法忘卻整個項目一行行去復制粘貼被支配的恐懼。:) 那麽是否存在

阿里感悟 》如何學習一項技術

這個也是阿里面試官比較喜歡問的一個問題,主要考察一位同學的學習能力。這個問題可以拆分成兩個問題,第一個是知道重點學什麼?第二個是怎麼學? 重點學什麼? 學技術應該知道學習一項技術最核心的東西,比如學JAVA應該重點學習垃圾回收機制,JAVA類載入機制等,因為這個是JAVA和其他語言的區別,J

天貓“雙11”狂歡節背後:阿里巴巴加速技術演變

關注ITValue,檢視企業級市場最新鮮、最具價值的報道! 2017年天貓“雙11” 不僅是全民購物狂歡節,更是阿里巴巴的新技術狂歡秀。機器人“魯班”、智慧客服“店小祕”、天貓精靈主持人、天貓

如何快速學習一門技術(轉載)

修改 操作 如何快速 mongodb rom try 深入 tro 分享 前幾天fork了Ruby China的源碼,面對陌生的Ruby技術棧,一頭霧水。 我fork它並不單為了學習,而是要在最短的時間搭建起我腦海中的社區網站。所以我不可能針對每一門新技術都去買一本

2015年Android開發技術盤點

youtube har pro ner j2e bind cor compile -m 又到年末。 利用中午的時間,匯總盤點一下今年Android開發方面的新技術。感覺如今Android開發沒有曾經那麽純粹了,出現了非常多新的開發模式。2015年影響比較普遍的

上海嶽城科技快速學習技術的幾條建議

軟件 精通 重要 www. upload 繼承 項目 bject 開發 面對現在更新迅速的新技術,如何快速掌握,以滿足工作的需要,是大部分開發者所面臨的問題之一。它或許影響著你未來職業生涯的發展。 Hanneli Tavante近日在Our Daily Codes網站上發表

學習技術

允許 出現 提醒 color 技術 百度 ado class ole 學習新技術前言: 常常聽到有的程序猿朋友說:“不做項目了,我都不知道幹啥。我覺得項目中自己才能學到東西”。其實我想說在這個技術日新月異的時代,作為程序猿我們時刻保持著 危機感,你不進步,不

如何學習技術、團隊技術選型時要註意些什麽

地址 redis 價值 高度 man 而是 現在 包括 改善   首先,要說明的是,這裏的“新”不一定是指時間上的新,在後文中,也可能是指,對於個人(或者團隊)來說是“新的”,就是說,這個東西,即使出現了很久,應用廣泛,但是個

如何學習大數據技術?大數據怎麽入門?怎麽做大數據分析?

tex 展示 這才 無法 bec 離線 可選 預測分析 研究 由於大數據技術涉及內容太龐雜,大數據應用領域廣泛,而且各領域和方向采用的關鍵技術差異性也會較大,難以三言兩語說清楚,本文從數據科學和大數據關鍵技術體系角度,來說說大數據的核心技術什麽,到底要怎麽學習它,以及怎

技術的神話 | 技術包袱 | 持續學習

部分 離職 軟件 以及 就是 cloud 結構 簡潔 設計 人們總是在尋找新技術,試圖用新技術替換舊有技術,因為新技術/框架能帶來很多好處:代碼更加簡潔,它總是封裝了復雜的實現細節,通常是一種解決方案。 但公司總會有舊的項目在維護,舊的項目中有些是年代久遠的陳舊框架