0%

JVMTI

jvmti 全名jvm tooling interface,可以监控jvm虚拟机,并且可以监控如下事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
typedef enum {
JVMTI_MIN_EVENT_TYPE_VAL = 50,
JVMTI_EVENT_VM_INIT = 50,
JVMTI_EVENT_VM_DEATH = 51,
JVMTI_EVENT_THREAD_START = 52,
JVMTI_EVENT_THREAD_END = 53,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK = 54,
JVMTI_EVENT_CLASS_LOAD = 55,
JVMTI_EVENT_CLASS_PREPARE = 56,
JVMTI_EVENT_VM_START = 57,
JVMTI_EVENT_EXCEPTION = 58,
JVMTI_EVENT_EXCEPTION_CATCH = 59,
JVMTI_EVENT_SINGLE_STEP = 60,
JVMTI_EVENT_FRAME_POP = 61,
JVMTI_EVENT_BREAKPOINT = 62,
JVMTI_EVENT_FIELD_ACCESS = 63,
JVMTI_EVENT_FIELD_MODIFICATION = 64,
JVMTI_EVENT_METHOD_ENTRY = 65, //方法执行开始
JVMTI_EVENT_METHOD_EXIT = 66, // 方法执行完成
JVMTI_EVENT_NATIVE_METHOD_BIND = 67,
JVMTI_EVENT_COMPILED_METHOD_LOAD = 68,
JVMTI_EVENT_COMPILED_METHOD_UNLOAD = 69,
JVMTI_EVENT_DYNAMIC_CODE_GENERATED = 70,
JVMTI_EVENT_DATA_DUMP_REQUEST = 71,
JVMTI_EVENT_MONITOR_WAIT = 73,
JVMTI_EVENT_MONITOR_WAITED = 74,
JVMTI_EVENT_MONITOR_CONTENDED_ENTER = 75,
JVMTI_EVENT_MONITOR_CONTENDED_ENTERED = 76,
JVMTI_EVENT_RESOURCE_EXHAUSTED = 80,
JVMTI_EVENT_GARBAGE_COLLECTION_START = 81, // 垃圾回收开始
JVMTI_EVENT_GARBAGE_COLLECTION_FINISH = 82, // 垃圾回收结束
JVMTI_EVENT_OBJECT_FREE = 83, // 对象回收
JVMTI_EVENT_VM_OBJECT_ALLOC = 84, // 对象创建
JVMTI_MAX_EVENT_TYPE_VAL = 84
} jvmtiEvent;

使用

加载so

1
2
3
4
// 加载so
System.load(agentPath)
// 绑定jvmti
Debug.attachJvmtiAgent(agentPath, null, classLoader)

绑定完成后会回调

创建jvmtiEnv

1
2
3
4
5
6
7
//创建JVMTI环境,
jvmtiEnv *mJvmtiEnv;
vm->GetEnv((void **) &mJvmtiEnv, JVMTI_VERSION_1_2);
//开启JVMTI的能力
jvmtiCapabilities caps;
mJvmtiEnv->GetPotentialCapabilities(&caps);
mJvmtiEnv->AddCapabilities(&caps);
  • 创建jvmtiEnv应该在Agent_OnAttach中进行
  • 注意这里的JVMTI_VERSION_1_2,GetEnv的时候会根据这个version 返回jvmtiEnv,如果版本号错误可能导致问题

    设置监听

    1
    2
    3
    4
    5
    6
    7
    8
    //设置callback
    jvmtiEventCallbacks callbacks;
    callbacks.VMObjectAlloc = &objectAlloc;
    callbacks.MethodEntry = &methodEntry;
    mJvmtiEnv->SetEventCallbacks(&callbacks, sizeof(callbacks));
    //开启监听
    mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr);
    mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, nullptr);
    这里jvmti监控就已经完成了,上方的代码监控了对象创建和进入方法执行。

    原理

    加载so

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //
    // library 是 so
    // options 是args
    // classloader
    public static void attachJvmtiAgent(@NonNull String library, @Nullable String options,
    @Nullable ClassLoader classLoader) throws IOException {
    Preconditions.checkNotNull(library);
    Preconditions.checkArgument(!library.contains("="));

    if (options == null) {
    VMDebug.attachAgent(library, classLoader);
    } else {
    VMDebug.attachAgent(library + "=" + options, classLoader);
    }
    }
    这里直接调用了VMDebug attachAgent
    1
    2
    3
    4
    5
    6
    public static void attachAgent(String agent, ClassLoader classLoader) throws IOException {
    nativeAttachAgent(agent, classLoader);
    }

    private static native void nativeAttachAgent(String agent, ClassLoader classLoader)
    throws IOException;
    VMDebug对应的c++为aosp/art/runtime/native/dalvik_system_VMDebug.cc
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) {

    std::string filename;
    {
    ScopedUtfChars chars(env, agent);
    if (env->ExceptionCheck()) {
    return;
    }
    filename = chars.c_str(); // so文件名字
    }

    Runtime::Current()->AttachAgent(env, filename, classloader);
    }
    这里最后调用了runtime.cc(aosp/art/runtime/runtime.cc)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) {
// 这个是关键,加载 libopenjdkjvmti.so
if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
LOG(WARNING) << "Could not load plugin: " << error_msg;
ScopedObjectAccess soa(Thread::Current());
ThrowIOException("%s", error_msg.c_str());
return;
}

ti::AgentSpec agent_spec(agent_arg);// 创建一个 AgentSpec,将so名字传递进去

int res = 0;
ti::LoadError error;
// 这里是关键
std::unique_ptr<ti::Agent> agent = agent_spec.Attach(env, class_loader, &res, &error, &error_msg);

if (agent != nullptr) {
agents_.push_back(std::move(agent)); // 加入到agent list中
} else {
LOG(WARNING) << "Agent attach failed (result=" << error << ") : " << error_msg;
ScopedObjectAccess soa(Thread::Current());
ThrowIOException("%s", error_msg.c_str());
}
}

static bool EnsureJvmtiPlugin(Runtime* runtime,
std::vector<Plugin>* plugins,
std::string* error_msg) {
constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so";

// Is the plugin already loaded?
for (const Plugin& p : *plugins) {
if (p.GetLibrary() == plugin_name) {
return true; // 这里表示plugin已经加载过了
}
}

Plugin new_plugin = Plugin::Create(plugin_name);

if (!new_plugin.Load(error_msg)) { // 调用plugin的load,这里我们不讲,在下方创建jvmtiEnv中讲解
return false;
}

plugins->push_back(std::move(new_plugin));
return true;
}

AgentSpec (aosp/art/runtime/ti/agent.cc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
AgentSpec::AgentSpec(const std::string& arg) {
size_t eq = arg.find_first_of('=');
// 这里会有两个参数,一个是so的名字,另一个是初始化时的options
if (eq == std::string::npos) {
name_ = arg;
} else {
name_ = arg.substr(0, eq);
args_ = arg.substr(eq + 1, arg.length());
}
}

std::unique_ptr<Agent> AgentSpec::Attach(JNIEnv* env,
jobject class_loader,
/*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg) {
VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
return DoLoadHelper(env, true, class_loader, call_res, error, error_msg);
}




std::unique_ptr<Agent> AgentSpec::DoLoadHelper(JNIEnv* env,
bool attaching,
jobject class_loader,
/*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg) {
// 调用 DoDlOpen
std::unique_ptr<Agent> agent = DoDlOpen(env, class_loader, error, error_msg);
// 获取我们写的Agent_OnAttach
AgentOnLoadFunction callback = attaching ? agent->onattach_ : agent->onload_;
// args参数
std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]);
strlcpy(copied_args.get(), args_.c_str(), args_.size() + 1);
// 调用 Agent_OnAttach并将java端的options传递过来
*call_res = callback(Runtime::Current()->GetJavaVM(),
copied_args.get(),
nullptr);
return agent;
}

std::unique_ptr<Agent> AgentSpec::DoDlOpen(JNIEnv* env,
jobject class_loader,
/*out*/LoadError* error,
/*out*/std::string* error_msg) {
// so路径
ScopedLocalRef<jstring> library_path(env,
class_loader == nullptr
? nullptr
: JavaVMExt::GetLibrarySearchPath(env, class_loader));
//打开so
void* dlopen_handle = android::OpenNativeLibrary(env,
Runtime::Current()->GetTargetSdkVersion(),
name_.c_str(),
class_loader,
nullptr,
library_path.get(),
&needs_native_bridge,
// 创建so对应的agent
std::unique_ptr<Agent> agent(new Agent(name_, dlopen_handle));
// 这里是关键,主要是获取so中的方法描述符 onAttach
agent->PopulateFunctions();
*error = kNoError;
return agent;
}

void Agent::PopulateFunctions() {
onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME));
if (onload_ == nullptr) {
VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this;
}
onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME));
if (onattach_ == nullptr) {
VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this;
}
onunload_ = reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME));
if (onunload_ == nullptr) {
VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this;
}
}

到这里jvmti就绑定完了

创建jvmtiEnv

加载so中,我们遗留了一个plugin加载问题,这里先将plugin加载
aosp/art/runtime/plugin.cc

1
2
3
4
5
6
7
8
9
10
11
const char* PLUGIN_INITIALIZATION_FUNCTION_NAME = "ArtPlugin_Initialize";

bool Plugin::Load(/*out*/std::string* error_msg) {
DCHECK(!IsLoaded());
void* res = dlopen(library_.c_str(), RTLD_LAZY);
// 获取这个init方法
PluginInitializationFunction init = reinterpret_cast<PluginInitializationFunction>(
dlsym(res, PLUGIN_INITIALIZATION_FUNCTION_NAME));
dlopen_handle_ = res;
return true;
}

OpenjdkJvmTi.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

extern "C" bool ArtPlugin_Initialize() {
art::Runtime* runtime = art::Runtime::Current();

gDeoptManager = new DeoptManager;
gEventHandler = new EventHandler; // EventHandler 主要用于设置Event监听

gDeoptManager->Setup();
if (runtime->IsStarted()) {
PhaseUtil::SetToLive();
} else {
PhaseUtil::SetToOnLoad();
}
PhaseUtil::Register(gEventHandler);
ThreadUtil::Register(gEventHandler);
ClassUtil::Register(gEventHandler);
DumpUtil::Register(gEventHandler);
MethodUtil::Register(gEventHandler);
SearchUtil::Register();
HeapUtil::Register();
Transformer::Setup();

{
art::ScopedSuspendAll ssa(__FUNCTION__);
gDeoptManager->FinishSetup();
}
// 这里是关键, 主要用于创建jvmEnv
runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler);

return true;
}

这里的ArtPlugin_Initialize 只会创建一次,所以gEventHandler也是只有一个,负责管理所有的Event监听

aosp/art/runtime/jni/java_vm_ext.cc

1
2
3
4
void JavaVMExt::AddEnvironmentHook(GetEnvHook hook) {
// 将hook
env_hooks_.push_back(hook);
}

正式开始讲解JavaVM中的GetEnv方法
java_vm_ext.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  static jint GetEnv(JavaVM* vm, void** env, jint version) {

JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
return raw_vm->HandleGetEnv(env, version);
}

jint JavaVMExt::HandleGetEnv(/*out*/void** env, jint version) {
// 遍历 env_hooks_
for (GetEnvHook hook : env_hooks_) {
jint res = hook(this, env, version);
if (res == JNI_OK) {
return JNI_OK;
} else if (res != JNI_EVERSION) {
LOG(ERROR) << "Error returned from a plugin GetEnv handler! " << res;
return res;
}
}
LOG(ERROR) << "Bad JNI version passed to GetEnv: " << version;
return JNI_EVERSION;
}

这里的hook为OpenjdkJvmTi.cc中的GetEnvHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) {
// JavaDebuggable will either be set by the runtime as it is starting up or the plugin if it's
// loaded early enough. If this is false we cannot guarantee conformance to all JVMTI behaviors
// due to optimizations. We will only allow agents to get ArtTiEnvs using the kArtTiVersion.
if (IsFullJvmtiAvailable() && IsJvmtiVersion(version)) {
CreateArtJvmTiEnv(vm, JVMTI_VERSION, env);
return JNI_OK;
} else if (version == kArtTiVersion) {
CreateArtJvmTiEnv(vm, kArtTiVersion, env);
return JNI_OK;
} else {
printf("version 0x%x is not valid!", version);
return JNI_EVERSION;
}
}

// 这里的version是 jvmti的version
static bool IsJvmtiVersion(jint version) {
return version == JVMTI_VERSION_1 ||
version == JVMTI_VERSION_1_0 ||
version == JVMTI_VERSION_1_1 ||
version == JVMTI_VERSION_1_2 ||
version == JVMTI_VERSION;
}


static void CreateArtJvmTiEnv(art::JavaVMExt* vm, jint version, /*out*/void** new_jvmtiEnv) {
// 创建ArtJvmTiEnv
struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, gEventHandler, version);
*new_jvmtiEnv = env;

gEventHandler->RegisterArtJvmTiEnv(env);

art::Runtime::Current()->AddSystemWeakHolder(
ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
}

到这里我们可以发现创建的jvmEnv为 ArtJvmTiEnv,即_jvmtiEnv
这个ArtJvmTiEnv 在 aosp/art/openjdkjvmti/art_jvmti.h

设置监听

OpenjdkJvmTi.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
static jvmtiError SetEventCallbacks(jvmtiEnv* env,
const jvmtiEventCallbacks* callbacks,
jint size_of_callbacks) {

ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
std::unique_ptr<ArtJvmtiEventCallbacks> tmp(new ArtJvmtiEventCallbacks());
// Copy over the extension events.
tmp->CopyExtensionsFrom(art_env->event_callbacks.get());
// Never overwrite the extension events.
size_t copy_size = std::min(sizeof(jvmtiEventCallbacks),
static_cast<size_t>(size_of_callbacks));
copy_size = art::RoundDown(copy_size, sizeof(void*));
// Copy non-extension events.
memcpy(tmp.get(), callbacks, copy_size);

// replace the event table.
art_env->event_callbacks = std::move(tmp); //给jvmtiEnv设置callbacks

return ERR(NONE);
}


static jvmtiError SetEventNotificationMode(jvmtiEnv* env,
jvmtiEventMode mode,
jvmtiEvent event_type,
jthread event_thread,
...) {
ENSURE_VALID_ENV(env);
ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
// gEventHandler
return gEventHandler->SetEvent(art_env,
event_thread,
GetArtJvmtiEvent(art_env, event_type),
mode);
}

events.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
jthread thread,
ArtJvmtiEvent event,
jvmtiEventMode mode) {

...
{

art::WriterMutexLock ei_mu(self, env->event_info_mutex_);
old_thread_state = GetThreadEventState(event, target);
old_state = global_mask.Test(event);
if (mode == JVMTI_ENABLE) {
env->event_masks.EnableEvent(env, target, event); // 设置开关
global_mask.Set(event);
new_state = true;
new_thread_state = true;
DCHECK(GetThreadEventState(event, target));
} else {
DCHECK_EQ(mode, JVMTI_DISABLE);

env->event_masks.DisableEvent(env, target, event);
RecalculateGlobalEventMaskLocked(event);
new_state = global_mask.Test(event);
new_thread_state = GetThreadEventState(event, target);
DCHECK(new_state || !new_thread_state);
}
}

if (new_state != old_state) {
HandleEventType(event, mode == JVMTI_ENABLE); //是否开启
}
if (old_thread_state != new_thread_state) {
return HandleEventDeopt(event, thread, new_thread_state);
}
return OK;
}


void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
switch (event) {
case ArtJvmtiEvent::kVmObjectAlloc:
SetupObjectAllocationTracking(alloc_listener_.get(), enable);
return;
case ArtJvmtiEvent::kMethodEntry:
case ArtJvmtiEvent::kMethodExit:
SetupTraceListener(method_trace_listener_.get(), event, enable);
return;
}
return;
}

static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
if (enable) {
//这里将监听给到了 heap.cc中,我们不再关注
art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
} else {
art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
}
}

void EventHandler::SetupTraceListener(JvmtiMethodTraceListener* listener,
ArtJvmtiEvent event,
bool enable) {
uint32_t new_events = GetInstrumentationEventsFor(event);
...
art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
art::ScopedSuspendAll ssa("jvmti method tracing installation");
if (enable) {
instr->AddListener(listener, new_events); //设置 listen到instrumentation中
} else {
instr->RemoveListener(listener, new_events);
}
return;
}

static uint32_t GetInstrumentationEventsFor(ArtJvmtiEvent event) {
switch (event) {
case ArtJvmtiEvent::kMethodEntry:
return art::instrumentation::Instrumentation::kMethodEntered;
case ArtJvmtiEvent::kMethodExit:
return art::instrumentation::Instrumentation::kMethodExited |
art::instrumentation::Instrumentation::kMethodUnwind;
}
}


这里只举例 对象的监控和方法监控