1*795d594fSAndroid Build Coastguard Worker // Copyright (C) 2018 The Android Open Source Project
2*795d594fSAndroid Build Coastguard Worker //
3*795d594fSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*795d594fSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*795d594fSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*795d594fSAndroid Build Coastguard Worker //
7*795d594fSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*795d594fSAndroid Build Coastguard Worker //
9*795d594fSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*795d594fSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*795d594fSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*795d594fSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*795d594fSAndroid Build Coastguard Worker // limitations under the License.
14*795d594fSAndroid Build Coastguard Worker //
15*795d594fSAndroid Build Coastguard Worker
16*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
17*795d594fSAndroid Build Coastguard Worker #include <jni.h>
18*795d594fSAndroid Build Coastguard Worker #include <jvmti.h>
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard Worker #include "base/runtime_debug.h"
21*795d594fSAndroid Build Coastguard Worker #include "jit/jit.h"
22*795d594fSAndroid Build Coastguard Worker #include "runtime-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "thread-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker namespace jitload {
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker // Special env version that allows JVMTI-like access on userdebug builds.
30*795d594fSAndroid Build Coastguard Worker static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
31*795d594fSAndroid Build Coastguard Worker
32*795d594fSAndroid Build Coastguard Worker #define CHECK_CALL_SUCCESS(c) \
33*795d594fSAndroid Build Coastguard Worker do { \
34*795d594fSAndroid Build Coastguard Worker auto vc = (c); \
35*795d594fSAndroid Build Coastguard Worker CHECK(vc == JNI_OK || vc == JVMTI_ERROR_NONE) << "call " << #c << " did not succeed\n"; \
36*795d594fSAndroid Build Coastguard Worker } while (false)
37*795d594fSAndroid Build Coastguard Worker
GetJitThread()38*795d594fSAndroid Build Coastguard Worker static jthread GetJitThread() {
39*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(art::Thread::Current());
40*795d594fSAndroid Build Coastguard Worker auto* jit = art::Runtime::Current()->GetJit();
41*795d594fSAndroid Build Coastguard Worker if (jit == nullptr) {
42*795d594fSAndroid Build Coastguard Worker return nullptr;
43*795d594fSAndroid Build Coastguard Worker }
44*795d594fSAndroid Build Coastguard Worker auto* thread_pool = jit->GetThreadPool();
45*795d594fSAndroid Build Coastguard Worker if (thread_pool == nullptr) {
46*795d594fSAndroid Build Coastguard Worker return nullptr;
47*795d594fSAndroid Build Coastguard Worker }
48*795d594fSAndroid Build Coastguard Worker // Currently we only have a single jit thread so we only look at that one.
49*795d594fSAndroid Build Coastguard Worker return soa.AddLocalReference<jthread>(
50*795d594fSAndroid Build Coastguard Worker thread_pool->GetWorkers()[0]->GetThread()->GetPeerFromOtherThread());
51*795d594fSAndroid Build Coastguard Worker }
52*795d594fSAndroid Build Coastguard Worker
VmInitCb(jvmtiEnv * jvmti,JNIEnv * env,jthread curthread)53*795d594fSAndroid Build Coastguard Worker JNICALL void VmInitCb(jvmtiEnv* jvmti,
54*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] JNIEnv* env,
55*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] jthread curthread) {
56*795d594fSAndroid Build Coastguard Worker jthread jit_thread = GetJitThread();
57*795d594fSAndroid Build Coastguard Worker if (jit_thread != nullptr) {
58*795d594fSAndroid Build Coastguard Worker CHECK_EQ(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, jit_thread),
59*795d594fSAndroid Build Coastguard Worker JVMTI_ERROR_NONE);
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker }
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker struct AgentOptions {
64*795d594fSAndroid Build Coastguard Worker bool fatal;
65*795d594fSAndroid Build Coastguard Worker uint64_t cnt;
66*795d594fSAndroid Build Coastguard Worker };
67*795d594fSAndroid Build Coastguard Worker
DataDumpRequestCb(jvmtiEnv * jvmti)68*795d594fSAndroid Build Coastguard Worker JNICALL static void DataDumpRequestCb(jvmtiEnv* jvmti) {
69*795d594fSAndroid Build Coastguard Worker AgentOptions* ops;
70*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&ops)));
71*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Jit thread has loaded " << ops->cnt << " classes";
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker
ClassPrepareJit(jvmtiEnv * jvmti,JNIEnv * jni_env,jthread thr,jclass klass)74*795d594fSAndroid Build Coastguard Worker JNICALL void ClassPrepareJit(jvmtiEnv* jvmti,
75*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] JNIEnv* jni_env,
76*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] jthread thr,
77*795d594fSAndroid Build Coastguard Worker jclass klass) {
78*795d594fSAndroid Build Coastguard Worker AgentOptions* ops;
79*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&ops)));
80*795d594fSAndroid Build Coastguard Worker char* klass_name;
81*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->GetClassSignature(klass, &klass_name, nullptr));
82*795d594fSAndroid Build Coastguard Worker (ops->fatal ? LOG_STREAM(FATAL)
83*795d594fSAndroid Build Coastguard Worker : LOG_STREAM(WARNING)) << "Loaded " << klass_name << " on jit thread!";
84*795d594fSAndroid Build Coastguard Worker ops->cnt++;
85*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->Deallocate(reinterpret_cast<unsigned char*>(klass_name)));
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker
VMDeathCb(jvmtiEnv * jvmti,JNIEnv * env)88*795d594fSAndroid Build Coastguard Worker JNICALL void VMDeathCb(jvmtiEnv* jvmti, [[maybe_unused]] JNIEnv* env) { DataDumpRequestCb(jvmti); }
89*795d594fSAndroid Build Coastguard Worker
SetupJvmti(JavaVM * vm,const char * options)90*795d594fSAndroid Build Coastguard Worker static jvmtiEnv* SetupJvmti(JavaVM* vm, const char* options) {
91*795d594fSAndroid Build Coastguard Worker android::base::InitLogging(/* argv= */nullptr);
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard Worker jvmtiEnv* jvmti = nullptr;
94*795d594fSAndroid Build Coastguard Worker if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0) != JNI_OK &&
95*795d594fSAndroid Build Coastguard Worker vm->GetEnv(reinterpret_cast<void**>(&jvmti), kArtTiVersion) != JNI_OK) {
96*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unable to setup JVMTI environment!";
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker jvmtiEventCallbacks cb {
99*795d594fSAndroid Build Coastguard Worker .VMInit = VmInitCb,
100*795d594fSAndroid Build Coastguard Worker .VMDeath = VMDeathCb,
101*795d594fSAndroid Build Coastguard Worker .ClassPrepare = ClassPrepareJit,
102*795d594fSAndroid Build Coastguard Worker .DataDumpRequest = DataDumpRequestCb,
103*795d594fSAndroid Build Coastguard Worker };
104*795d594fSAndroid Build Coastguard Worker AgentOptions* ops;
105*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(
106*795d594fSAndroid Build Coastguard Worker jvmti->Allocate(sizeof(AgentOptions), reinterpret_cast<unsigned char**>(&ops)));
107*795d594fSAndroid Build Coastguard Worker ops->fatal = (strcmp(options, "fatal") == 0);
108*795d594fSAndroid Build Coastguard Worker ops->cnt = 0;
109*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->SetEnvironmentLocalStorage(ops));
110*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->SetEventCallbacks(&cb, sizeof(cb)));
111*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, nullptr));
112*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(
113*795d594fSAndroid Build Coastguard Worker jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, nullptr));
114*795d594fSAndroid Build Coastguard Worker return jvmti;
115*795d594fSAndroid Build Coastguard Worker }
116*795d594fSAndroid Build Coastguard Worker
117*795d594fSAndroid Build Coastguard Worker // Early attachment (e.g. 'java -agent[lib|path]:filename.so').
Agent_OnLoad(JavaVM * vm,char * options,void *)118*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* /* reserved */) {
119*795d594fSAndroid Build Coastguard Worker SetupJvmti(vm, options);
120*795d594fSAndroid Build Coastguard Worker return JNI_OK;
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker
123*795d594fSAndroid Build Coastguard Worker // Late attachment (e.g. 'am attach-agent').
Agent_OnAttach(JavaVM * vm,char * options,void *)124*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char* options, void* /* reserved */) {
125*795d594fSAndroid Build Coastguard Worker jvmtiEnv* jvmti = SetupJvmti(vm, options);
126*795d594fSAndroid Build Coastguard Worker
127*795d594fSAndroid Build Coastguard Worker JNIEnv* jni = nullptr;
128*795d594fSAndroid Build Coastguard Worker jthread thr = nullptr;
129*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6));
130*795d594fSAndroid Build Coastguard Worker CHECK_CALL_SUCCESS(jvmti->GetCurrentThread(&thr));
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker // Final setup is done in the VmInitCb.
133*795d594fSAndroid Build Coastguard Worker VmInitCb(jvmti, jni, thr);
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker jni->DeleteLocalRef(thr);
136*795d594fSAndroid Build Coastguard Worker return JNI_OK;
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker #undef CHECK_CALL_SUCCESS
140*795d594fSAndroid Build Coastguard Worker
141*795d594fSAndroid Build Coastguard Worker } // namespace jitload
142*795d594fSAndroid Build Coastguard Worker
143