JPDA 架構研究4 - JDWP的傳輸器

引入:架構

上一篇文章主要分析JDWP層傳輸的數據包的格式,這篇文章咱們主要關注於JDWP層是如何傳輸的。jvm


分析:socket

傳輸的具體實現是根據各個JVM本身實現,可是他們有個共同點就是都是用C/C++實現的,而且都實現了jdwpTransport.h (和上篇同樣的這個文件)。實現根據咱們的知識能夠得知是以dll文件(或者Unix平臺下是so文件)的形式存在。由於咱們從前面瞭解到,JDWP層有Agent負責在數據包和JVMTI的函數調用之間轉換,因此瓜熟蒂落知道,傳輸層的DLL文件也一定會有一個onload方法,而且讓Agent啓動時候調用的。ide



分析1:Agent如何訪問VM環境呢?函數

答案是經過環境指針(environment pointer), 該指針會在onload()方法中返回給Agent.這個環境指針的定義以下:測試

struct _jdwpTransportEnv;

#ifdef __cplusplus
typedef _jdwpTransportEnv jdwpTransportEnv;

...
struct _jdwpTransportEnv {
    const struct jdwpTransportNativeInterface_ *functions;

因此這裏能夠看出,環境指針本質就是拿到一組能夠訪問目標VM環境的native接口。spa


分析2:Agent啓動時調用的onload()方法。指針

當Target VM加載了Agent以後,JDWP會根據參數去加載具體的JDWP的實現,Sun 的 JDK 在 Windows 提供 socket 和 share memory 兩種傳輸方式,而在 Linux 上只有 socket 方式)。傳輸層實現的動態連接庫實現必須暴露 jdwpTransport_OnLoad 接口,來對傳輸層初始化。blog

該方法簽名以下:接口

JNIEXPORT jint JNICALL 
jdwpTransport_OnLoad(JavaVM *jvm,
                     jdwpTransportCallback *callback,
                     jint version,
                     jdwpTransportEnv** env);

從這裏能夠看出_OnLoad方法須要下面幾個入參:

jvm: 它讓Agent經過GetJavaVM方法來獲取JVM信息。

callback:它是一個函數表的指針,傳輸層用它來進行內存的分配與釋放。

version:它讓Agent得到指望的JDWPTRANSPORT的版本。

而後返回值就是在第四個參數中,它就是咱們想要的環境指針。

若是傳輸層初始化成功,那麼_OnLoad方法就會返回JNI_OK,不然會返回對應的錯誤碼。


分析3:jdwpTransport支持的方法概覽。

由於jdwpTransport須要維繫着Debugger和Target VM之間的關係,因此它有許多方法。咱們從幾大類來看。


分類1:用於管理鏈接

管理鏈接的方法其主要做用是用於創建和關閉到Debugger的鏈接。

a. Attach.它主要用於關聯到Debugger,創建到Debugger之間的可信鏈路.

步驟1:鏈接到指定的地址

步驟2:鏈接成功,則經過交換 」JDWP-Handshake"來確保到Debugger的鏈接的確被創建。

    /*  3 : Attach */
    jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
        const char* address,
        jlong attach_timeout,
        jlong handshake_timeout);

從這裏能夠看出,除了環境指針外,它須要下面3個參數:

address: Debugger的地址和端口

attach_timeout:設置鏈接超時值,單位毫秒。若是設爲0則說明永不超時。

handshake_timeout:設置握手超時值,單位毫秒。若是設爲0則說明永不超時。


b.StartListening.它主要用於讓傳輸器處於listen模式,這樣它就能夠監聽來自Debugger的鏈接了。

  /*  4: StartListening */
    jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
        const char* address,
        char** actual_address);

除環境指針外,它還須要1個參數:

address:Debugger的地址和端口

actualAddress:返回值,返回傳輸器從address參數得到的真實字符串形式的地址。


c.StopListening.它主要用於讓傳輸器離開listen模式,這樣它就再也不監聽來自Debugger的鏈接了。

    /*  5: StopListening */
    jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);


d.Accept.它主要用於創建來自Debugger的鏈接。

 /*  6: Accept */
    jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
        jlong accept_timeout,
        jlong handshake_timeout);


e.IsOpen.它用於測試Debugger的鏈接是否開着。

   /*  7: IsOpen */
    jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);


f.Close.它用於關閉到Debugger的鏈接。

   /*  8: Close */
    jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);



分類2:用於讀來自Debugger的數據包和發送到Debugger的數據包。

a. ReadPacket. 它用於在鏈接開着的狀態,從Debugger讀取數據包。

  /*  9: ReadPacket */
    jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
        jdwpPacket *pkt);

須要注意的是,該方法只對數據包作長度校驗,而不作完整性校驗。


b.WritePacket.它用於在鏈接開着的狀態,往Debugger寫數據包。

  /*  10: Write Packet */
    jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
        const jdwpPacket* pkt);


分類3:輔助功能。

a.GetLastError.它用於返回用字符串表示的上次錯誤。

    /*  11:  GetLastError */
    jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
        char** error);


b.GetCapabilities.它用於返回JDWP傳輸器全部支持的能力。

 /*  2 : Get Capabilities */
    jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
         JDWPTransportCapabilities *capabilities_ptr);

能力的啓用和禁用是經過一組位圖位來標示的。


整個傳輸器的架構以下:

wKioL1SJKfygLz4kAAExNZHnNuU512.jpg

相關文章
相關標籤/搜索