天天看點

JavaAgent學習筆記什麼是JavaAgent?如何實作簡單的JavaAgent

       粗略檢視了它的手冊,發現其使用了JavaAgent的技術。那麼,什麼是JavaAgent呢?

可以在加載class檔案之前做攔截把位元組碼做修改

可以在運作期将已經加載的類的位元組碼做變更,但是這種情況下會有很多的限制,後面會詳細說

還有其他的一些小衆的功能

擷取所有已經被加載過的類

擷取所有已經被初始化過了的類(執行過了clinit方法,是上面的一個子集)

擷取某個對象的大小

将某個jar加入到bootstrapclasspath裡作為高優先級被bootstrapClassloader加載

将某個jar加入到classpath裡供AppClassloard去加載

設定某些native方法的字首,主要在查找native方法的時候做規則比對

是以 ,初步認為是故障演練平台使用了mkagent,對hsf接口進行了mock,讓其模拟異常。實作接口調用的失敗。

     現階段實作agent至少有二種方式,

通過加載使用C編譯的動态庫的方式實作。在linux與mac下動态庫是“libname.so”,windows下動态庫是“libname.dll”。一般會實作以下三個方法。

<code>Agent_OnLoad</code>函數,如果agent是在啟動的時候加載的,也就是在vm參數裡通過-agentlib來指定,那在啟動過程中就會去執行這個agent裡的<code>Agent_OnLoad</code>函數。

<code>Agent_OnAttach</code>函數,如果agent不是在啟動的時候加載的,是我們先attach到目标程序上,然後給對應的目标程序發送load指令來加載agent,在加載過程中就會調用<code>Agent_OnAttach</code>函數。

<code>Agent_OnUnload</code>函數,在agent做解除安裝的時候調用,不過貌似基本上很少實作它。

首先是一段C++的動态庫代碼,注意頭檔案jvmti.h與jni_md.h

以上代碼主要實作了2個方法,Agent_OnAttach是在程式在運作時加載,并列印所有的加載類。Agent_OnLoad是在程式啟動時加載,列印一個語句。

然後對這個CPP進行編譯。生成一個.so的動态庫檔案。

然後是被agent的目标的類,并且對其進行編譯

然後開始嘗試程式啟動階段的agent,使用以下指令進行運作

 可以看到日志檔案的輸出。

這是程式在啟動的時候進行agent了,jvm執行了動态庫中的Agent_OnLoad代碼。

另外就是程式運作中的agent了。現在需要以下代碼。

 當運作TestMain的main函數的時候,ps aux | grep java 檢視TestMain的PID,然後修改以上代碼中的pid參數,讓Agent加載到指定的java程序中。然後立馬運作TestAgent,就會看到以下日志。

計數器列印到一半時,執行了動态庫中的Agent_OnAttach方法。

以上是使用JVMTI實作的agent。但是故障演練平台應該不是用這種方法。在改平台的手冊上看到了這句話:

先看以下代碼

除了該段代碼,還要在該類包接口下建立META-INF檔案夾,并建立MANIFEST.MF檔案,以下為檔案内容:

指定agent.MyAgent為PremainClass。同時将MyAgent與MF檔案打包,我使用的是eclipse導出。然後使用以下指令(可以參考故障演練平台的配置)

 最後,生成了一個test.class。對其反編譯

打開該檔案,就是利用asm位元組碼操作生成的一個接口

推測,可能故障演練平台上就是使用的就是javaagent+asm技術,在應用啟動或運作時,通過修改類的位元組碼,模拟系統的各種故障。(以上都是瞎猜,猜錯了我不負責,演練平台的同學别找我^o^)

PS:文章中的代碼大多來自于網絡,但本人親測有效。