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