国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

一次Java字節碼插樁實戰

eternalshallow / 1917人閱讀

摘要:理解本文需要一定的字節碼指令基礎,可以閱讀筆者的另一篇文章大話圖說字節碼指令只為讓你懂利用字節碼插樁技術可以很方便地幫助我們實現很多手術刀式的代碼設計,如無埋點統計上報輕量級等。

理解本文需要一定的Java字節碼指令基礎,可以閱讀筆者的另一篇文章:大話+圖說:Java字節碼指令——只為讓你懂
利用Android字節碼插樁技術可以很方便地幫助我們實現很多手術刀式的代碼設計,如無埋點統計上報、輕量級AOP等。下面我們就通過一次實戰,把這門技術真正用起來。
奇葩需求

假設有這樣一個需求,我們需要在本項目工程的所有組件(Activity/Receiver/Service/Provider)的on系列生命周期類方法執行時,調用一個我們寫好的方法,傳入組件的實例對象,來對組件的相關狀態進行監測,如何實現?
一般的思路有兩種:

通過Java繼承體系,為我們實現的四大組件分別建立基類,在基類父方法里對監測方法進行調用。

通過Android API Hook技術,即通過動態代理等方法替換關鍵節點,抓住組件的節點方法并調用我們的監測方法。

上面的第一種方法比較麻煩,而且控制力較弱,也無法顧及我們所依賴的Jar或者aar中的組件,比如小米推送中自帶的Service和Receiver,是完全無法觸及的。第二種方法則比較強大,但是需要考慮兼容性問題,技術實現上的成本也比較高,畢竟有一些生命周期的節點不好找,難免焦頭爛額。

本文對此的實戰即通過字節碼插樁,在class文件編譯成dex之前(同時也是proguard操作之前),遍歷所有要編譯的class文件并對其中符合條件的方法進行修改,注入我們要調用的監測方法的代碼,從而實現這個需求。

HiBeaver 是目前這方面比較完善的字節碼插樁Gradle插件,目前最新的1.2.4版本支持通過通配符或正則表達式的方法來匹配目標類和目標方法,進行方法的批量插樁注入和修改,非常靈活易用。對于類似上文提出的需求,實現起來非常方便,唯一前提的僅僅是:知道所有組件的類的全名就可以了。

準備工作

好,基于這些,正式開始實戰,牛刀小試一下:
首先建立一個工程,為便于演示,我們引入小米推送(接入方式不再贅述,詳見小米推送文檔),然后完善代碼到如下狀態:

MainActivity內容很簡單,注冊了小米推送,有一個TextView點擊后可以跳轉到SecondActivity,僅此而已。具體如下:

SecondActivity中一切從簡:

至于DemoMessageReceiver這個類里完全依照小米推送接入文檔中的配置,沒有實質改動,不再貼出。
注意到還有一個MonitorUtil的類,內容如下:

其中的monitorThis的方法就是我們打算在各個生命周期方法里插入的調用方法。

開始實戰

下面我們就開始實現開頭處提到的需求:通過字節碼插樁的方法,本工程里的所有組件的生命周期方法return之前調用我們的monitorThis方法,傳入組件實例等信息作為參數。

首先,要引入HiBeaver插件:
然后在項目的根build.gradle下面增加classpath如下:

classpath "com.bryansharp:hibeaver:1.2.4"

隨后為我們工程的app/build.gradle增加如下配置:

apply plugin: "hiBeaver"
import com.bryansharp.gradle.hibeaver.utils.MethodLogAdapter
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes

hiBeaver {
    modifyMatchMaps = [
            //類名稱匹配規則,*表示任意長度任意字符,|為分隔符,可以理解為或
            "*Activity|*Receiver|*Service|!android*": [
                    //方法名匹配規則與類名類似,同時也支持正則表達式匹配(需要加r:);adapter后為一個閉包,進行具體的修改
                    ["methodName": "on**", "methodDesc": null, "adapter": {
                        //下面這些為閉包傳入的參數,可以幫助我們進行方法過濾,以及根據方法參數來調整字節碼修改方式
                        ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                            //這里我們有了ClassVisitor實例,其實可以為類添加新的方法。
                            MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
                            MethodVisitor adapter = new MethodLogAdapter(methodVisitor) {

                                @Override
                                void visitCode() {
                                    super.visitCode();
                                    //實例對象入棧
                                    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
                                    //下面兩句我們將方法的名稱和描述作為常量入棧
                                    methodVisitor.visitLdcInsn(name);
                                    methodVisitor.visitLdcInsn(desc);
                                    //調用我們的靜態方法
                                    methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                                            //下面這個MethodLogAdapter.className2Path(String)為
                                            // hibeaver插件提供的方法,可以將類名轉為路徑名
                                            MethodLogAdapter.className2Path("bruce.com.testhibeaver.MonitorUtil"),
                                            "monitorThis", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V");
                                }
                            }
                            return adapter;
                    }]
            ]
    ]
}

HiBeaver在類名和方法名的匹配上非常靈活,可以非常方便地實現批量匹配,除了完整匹配外,還支持通配符匹配和正則表達式匹配兩種模式。通配符匹配模式中主要可以使用兩種符號,即 | 和表示任意長度(>0)的任意字符,而|表示分隔符,這里可以理解為或。因此,上面的:

*Activity|*Receiver|*Service

可以理解為,匹配任意全類名以Activity、Receiver或Service結尾的類。

一般來講,我們的Android組件在命名上都會遵從這個規范,即組件類名以相應的組件名結尾,對于個別不遵從這個原則的,也可以通過|分隔符來把特殊情況納入進去。

除此之外,如果存在更復雜的匹配規則,上述通配符已經無法滿足,hiBeaver也支持正則表達式進行全類名匹配,只需要在表達式前加上“r:”就可以。比如:

r:.*D[a-zA-Z]*Client

表示匹配符合“.*D[a-zA-Z]*Client”這個正則表達式的類名。

更進一步地,HiBeaver 未來 還將支持根據類的繼承關系進行匹配,比如:

>ext>android.support.v4.app.FragmentActivity

表示匹配所有繼承android.support.v4.app.FragmentActivity的類,而:

>imp>android.os.Handler.Callback

表示匹配所有實現android.os.Handler.Callback接口的類。
不過,目前這兩個特性還沒有支持,僅提上了其項目的issue中。
回到剛剛的配置中,下面的methodName方法的匹配規則與類名匹配用法一樣,**和*是一樣的效果,on**即表示名字以on開頭的方法。
好了,編譯運行工程,過程中在Gradle Console中可以看到hibeaver進行字節碼插樁輸出如下(局部):

程序運行起來,插樁成功,成功調用了monitorThis方法,但赫然發現輸出如下:

調用了三個onCreate和若干的onCreateView!這是為什么?我們的MainActivity也沒有這個onCreateView的方法啊!

結合之前Gradle編譯日志,在仔細一琢磨,突然明白了:



原來,我們的*Activity規則會匹配所有的Activity結尾的類,包括一些android v4支持包中的類,什么AppCompatActivity、FragmentActivity等繼承鏈上的Activity通通被hook了一遍,難怪會有那么多輸出了,可辛苦了我們的monitorThis方法。

既然如此,如何是好?針對于當前的需求,我們當然不想匹配v4包里的組件類。

所幸的是,HiBeaver中還有另一種排除匹配,運用!符號改造如下即可:

*Activity|*Receiver|*Service|!android*

這樣就表示,匹配前三種之一(或的關系)且不匹配第四個android*的全類名。
改好后,再次運行,并點擊跳轉到SecondActivity:

可以看到log輸出一下子少多了,證明沒有再注入v4包里的類,同時,小米的組件也被正常注入了,我把網斷掉,可以看到小米的Receiver被喚起:

再開啟調試,打開網,斷點也可以正常進入:

同時,每次HiBeaver進行字節碼插樁后還會把修改過、實際使用的字節碼保存到build/HiBeaver目錄下,以便于查看:

如下圖為修改后的MainActivity類:

修改后的小米推送里的某Receiver:

這樣,無論是進行節點控制還是研究其運行機制都大大地方便了。

HiBeaver

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66774.html

相關文章

  • Android 性能監控系列一(原理篇)

    摘要:全稱應用性能管理監控后面我會通過一系列的文章來介紹的原理框架設計與實現等等。在應用構建期間,通過修改字節碼的方式來進行字節碼插樁就是實現自動化的方案之一。 showImg(https://segmentfault.com/img/bVbbRX6?w=1995&h=1273); 歡迎關注微信公眾號:BaronTalk,獲取更多精彩好文! 一. 前言 性能問題是導致 App 用戶流失的罪魁...

    yacheng 評論0 收藏0
  • 擴展 - 收藏集 - 掘金

    摘要:最新最全的開源項目合集掘金是由整理并維護的安卓相關開源項目庫集合。準備的插件開發必開發者福利史上最全開發和安全系列工具掘金取證工具一個工具箱,用于分析手機元數據。 最新最全的 Android 開源項目合集 - Android - 掘金awesome-github-android-ui 是由OpenDigg整理并維護的安卓UI相關開源項目庫集合。我們會定期同步OpenDigg上的項目到這...

    sewerganger 評論0 收藏0

發表評論

0條評論

eternalshallow

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<