2009-08-29 79 views
3

一個Java程序加載爲了支持靜態分析工具,我想文書或以這樣的方式,我能夠確定每個反射調用(如Method.invoke(監控Java程序的所有類的名稱。 )):發現使用反射

1),其中C類調用該方法,並 2),它加載器加載這個類C.

理想我要尋找一個解決方案,不要求我靜修改Java運行時庫,即我正在尋找一個加載時間解決方案。然而,該解決方案應該能夠捕捉到所有反射調用,即使是Java運行庫本身內發生的此類電話。 (我用ClassFileTransformer玩過,但是這似乎只適用於ClassFileTransformer本身不依賴的類,特別是ClassFileTransfomer不適用於類「Class」。)

謝謝!

回答

1

您正在尋找的東西,可以在生產環境中運行?或者是否足以讓應用程序在測試環境中運行?如果是後者,可能要考慮在分析工具下運行應用程序。我個人使用,並建議JProfiler,它可以讓你調用跟蹤和建立觸發時被調用的具體方法如日誌來執行操作。它不需要對託管程序進行任何修改,並且可以在Java運行時庫上正常工作。也有開源工具,但我沒有儘可能多的成功讓這些工作。

如果你需要的東西,將在生產環境中運行,您可能需要調查通過了Javassist或者CGLIB實現你自己定製的ClassLoader或字節碼操作,也許是使用AspectJ(AOP)。這顯然是一個更復雜的解決方案,我不確定它會在沒有編譯時支持的情況下工作,所以希望分析工具對您的情況是可行的。

0

,你很可能後JVMTI的API。 JVMTI允許您爲JVM中發生的大多數事件(包括MethodEntry,MethodExit)註冊回調。您傾聽這些事件並提取Method.invoke事件。有API調用來獲取特定類的類加載器。但是,您必須使用C或C++編寫工具。

下面是一個例子,將獲得濾出的java.lang.reflect.Method.invoke呼叫,並打印出來。要獲得有關已被調用的對象的詳細信息,您可能需要查看堆棧幀。

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <jvmti.h> 

static jvmtiEnv *jvmti = NULL; 
static jvmtiCapabilities capa; 

static jint check_jvmti_error(jvmtiEnv *jvmti, 
           jvmtiError errnum, 
           const char *str) { 

    if (errnum != JVMTI_ERROR_NONE) { 
     char *errnum_str; 
     errnum_str = NULL; 
     (void) (*jvmti)->GetErrorName(jvmti, errnum, &errnum_str); 
     printf("ERROR: JVMTI: %d(%s): %s\n", 
       errnum, 
       (errnum_str == NULL ? "Unknown" : errnum_str), 
       (str == NULL ? "" : str)); 
     return JNI_ERR; 
    } 
    return JNI_OK; 
} 

void JNICALL callbackMethodEntry(jvmtiEnv *jvmti_env, 
           JNIEnv* jni_env, 
           jthread thread, 
           jmethodID method) { 

    char* method_name; 
    char* method_signature; 
    char* generic_ptr_method; 
    char* generic_ptr_class; 
    char* class_name; 
    jvmtiError error; 
    jclass clazz; 

    error = (*jvmti_env)->GetMethodName(jvmti_env, 
             method, 
             &method_name, 
             &method_signature, 
             &generic_ptr_method); 
    if (check_jvmti_error(jvmti_env, error, "Failed to get method name")) { 
     return; 
    } 

    if (strcmp("invoke", method_name) == 0) { 

     error 
       = (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, 
         &clazz); 
     if (check_jvmti_error(jvmti_env, error, 
       "Failed to get class for method")) { 
      (*jvmti_env)->Deallocate(jvmti_env, method_name); 
      (*jvmti_env)->Deallocate(jvmti_env, method_signature); 
      (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method); 
      return; 
     } 

     error = (*jvmti_env)->GetClassSignature(jvmti_env, clazz, &class_name, 
       &generic_ptr_class); 
     if (check_jvmti_error(jvmti_env, error, "Failed to get class signature")) { 
      (*jvmti_env)->Deallocate(jvmti_env, method_name); 
      (*jvmti_env)->Deallocate(jvmti_env, method_signature); 
      (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method); 
      return; 
     } 

     if (strcmp("Ljava/lang/reflect/Method;", class_name) == 0) { 
      printf("Method entered: %s.%s.%s\n", class_name, method_name, 
        method_signature); 
     } 
     (*jvmti_env)->Deallocate(jvmti_env, class_name); 
     (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_class); 
    } 

    (*jvmti_env)->Deallocate(jvmti_env, method_name); 
    (*jvmti_env)->Deallocate(jvmti_env, method_signature); 
    (*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method); 
} 

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 

    jint result; 
    jvmtiError error; 
    jvmtiEventCallbacks callbacks; 

    result = (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_1_0); 
    if (result != JNI_OK || jvmti == NULL) { 
     printf("error\n"); 
     return JNI_ERR; 
    } else { 
     printf("loaded agent\n"); 
    } 

    (void) memset(&capa, 0, sizeof(jvmtiCapabilities)); 
    capa.can_generate_method_entry_events = 1; 

    error = (*jvmti)->AddCapabilities(jvmti, &capa); 
    if (check_jvmti_error(jvmti, error, "Unable to set capabilities") != JNI_OK) { 
     return JNI_ERR; 
    } 

    (void) memset(&callbacks, 0, sizeof(callbacks)); 
    callbacks.MethodEntry = &callbackMethodEntry; 
    error = (*jvmti)->SetEventCallbacks(jvmti, 
             &callbacks, 
             (jint) sizeof(callbacks)); 
    if (check_jvmti_error(jvmti, error, "Unable to set callbacks") != JNI_OK) { 
     return JNI_ERR; 
    } 

    error = (*jvmti)->SetEventNotificationMode(jvmti, 
               JVMTI_ENABLE, 
               JVMTI_EVENT_METHOD_ENTRY, 
               (jthread) NULL); 
    if (check_jvmti_error(jvmti, error, 
      "Unable to set method entry notifications") != JNI_OK) { 
     return JNI_ERR; 
    } 

    return JNI_OK; 
}