粗略檢視了它的手冊,發現其使用了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:文章中的代碼大多來自于網絡,但本人親測有效。