xref: /aosp_15_r20/art/tools/jvmti-agents/simple-force-redefine/forceredefine.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker // Copyright (C) 2019 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 <android-base/macros.h>
18*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
19*795d594fSAndroid Build Coastguard Worker #include <jni.h>
20*795d594fSAndroid Build Coastguard Worker #include <jvmti.h>
21*795d594fSAndroid Build Coastguard Worker #include <nativehelper/scoped_local_ref.h>
22*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include <cstddef>
25*795d594fSAndroid Build Coastguard Worker #include <fstream>
26*795d594fSAndroid Build Coastguard Worker #include <memory>
27*795d594fSAndroid Build Coastguard Worker #include <mutex>
28*795d594fSAndroid Build Coastguard Worker #include <sstream>
29*795d594fSAndroid Build Coastguard Worker #include <string>
30*795d594fSAndroid Build Coastguard Worker #include <unordered_set>
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker // Slicer's headers have code that triggers these warnings. b/65298177
33*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic push
34*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wunused-parameter"
35*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wsign-compare"
36*795d594fSAndroid Build Coastguard Worker #include <slicer/code_ir.h>
37*795d594fSAndroid Build Coastguard Worker #include <slicer/dex_bytecode.h>
38*795d594fSAndroid Build Coastguard Worker #include <slicer/dex_ir.h>
39*795d594fSAndroid Build Coastguard Worker #include <slicer/dex_ir_builder.h>
40*795d594fSAndroid Build Coastguard Worker #include <slicer/reader.h>
41*795d594fSAndroid Build Coastguard Worker #include <slicer/writer.h>
42*795d594fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker namespace forceredefine {
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker namespace {
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker struct AgentInfo {
49*795d594fSAndroid Build Coastguard Worker   std::fstream stream;
50*795d594fSAndroid Build Coastguard Worker   std::unordered_set<std::string> classes;
51*795d594fSAndroid Build Coastguard Worker   std::mutex mutex;
52*795d594fSAndroid Build Coastguard Worker };
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker // Converts a class name to a type descriptor
55*795d594fSAndroid Build Coastguard Worker // (ex. "java.lang.String" to "Ljava/lang/String;")
classNameToDescriptor(const char * className)56*795d594fSAndroid Build Coastguard Worker std::string classNameToDescriptor(const char* className) {
57*795d594fSAndroid Build Coastguard Worker   std::stringstream ss;
58*795d594fSAndroid Build Coastguard Worker   ss << "L";
59*795d594fSAndroid Build Coastguard Worker   for (auto p = className; *p != '\0'; ++p) {
60*795d594fSAndroid Build Coastguard Worker     ss << (*p == '.' ? '/' : *p);
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker   ss << ";";
63*795d594fSAndroid Build Coastguard Worker   return ss.str();
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker 
66*795d594fSAndroid Build Coastguard Worker // Converts a descriptor (Lthis/style/of/name;) to a jni-FindClass style Fully-qualified class name
67*795d594fSAndroid Build Coastguard Worker // (this/style/of/name).
DescriptorToFQCN(const std::string & descriptor)68*795d594fSAndroid Build Coastguard Worker std::string DescriptorToFQCN(const std::string& descriptor) {
69*795d594fSAndroid Build Coastguard Worker   return descriptor.substr(1, descriptor.size() - 2);
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker 
GetAgentInfo(jvmtiEnv * jvmti)72*795d594fSAndroid Build Coastguard Worker static AgentInfo* GetAgentInfo(jvmtiEnv* jvmti) {
73*795d594fSAndroid Build Coastguard Worker   AgentInfo* ai = nullptr;
74*795d594fSAndroid Build Coastguard Worker   CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&ai)), JVMTI_ERROR_NONE);
75*795d594fSAndroid Build Coastguard Worker   CHECK(ai != nullptr);
76*795d594fSAndroid Build Coastguard Worker   return ai;
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker class JvmtiAllocator : public dex::Writer::Allocator {
80*795d594fSAndroid Build Coastguard Worker  public:
JvmtiAllocator(jvmtiEnv * jvmti)81*795d594fSAndroid Build Coastguard Worker   explicit JvmtiAllocator(jvmtiEnv* jvmti) : jvmti_(jvmti) {}
Allocate(size_t size)82*795d594fSAndroid Build Coastguard Worker   void* Allocate(size_t size) override {
83*795d594fSAndroid Build Coastguard Worker     unsigned char* res = nullptr;
84*795d594fSAndroid Build Coastguard Worker     jvmti_->Allocate(size, &res);
85*795d594fSAndroid Build Coastguard Worker     return res;
86*795d594fSAndroid Build Coastguard Worker   }
Free(void * ptr)87*795d594fSAndroid Build Coastguard Worker   void Free(void* ptr) override {
88*795d594fSAndroid Build Coastguard Worker     jvmti_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
89*795d594fSAndroid Build Coastguard Worker   }
90*795d594fSAndroid Build Coastguard Worker 
91*795d594fSAndroid Build Coastguard Worker  private:
92*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti_;
93*795d594fSAndroid Build Coastguard Worker };
94*795d594fSAndroid Build Coastguard Worker 
Transform(const std::shared_ptr<ir::DexFile> & ir)95*795d594fSAndroid Build Coastguard Worker static void Transform(const std::shared_ptr<ir::DexFile>& ir) {
96*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ir::Builder> builder;
97*795d594fSAndroid Build Coastguard Worker   for (auto& method : ir->encoded_methods) {
98*795d594fSAndroid Build Coastguard Worker     // Do not look into abstract/bridge/native/synthetic methods.
99*795d594fSAndroid Build Coastguard Worker     if ((method->access_flags &
100*795d594fSAndroid Build Coastguard Worker          (dex::kAccAbstract | dex::kAccBridge | dex::kAccNative | dex::kAccSynthetic)) != 0) {
101*795d594fSAndroid Build Coastguard Worker       continue;
102*795d594fSAndroid Build Coastguard Worker     }
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker     struct AddNopVisitor : public lir::Visitor {
105*795d594fSAndroid Build Coastguard Worker       explicit AddNopVisitor(lir::CodeIr* cir) : cir_(cir) {}
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker       bool Visit(lir::Bytecode* bc) override {
108*795d594fSAndroid Build Coastguard Worker         if (seen_first_inst) {
109*795d594fSAndroid Build Coastguard Worker           return false;
110*795d594fSAndroid Build Coastguard Worker         }
111*795d594fSAndroid Build Coastguard Worker         seen_first_inst = true;
112*795d594fSAndroid Build Coastguard Worker         auto new_inst = cir_->Alloc<lir::Bytecode>();
113*795d594fSAndroid Build Coastguard Worker         new_inst->opcode = dex::OP_NOP;
114*795d594fSAndroid Build Coastguard Worker         cir_->instructions.InsertBefore(bc, new_inst);
115*795d594fSAndroid Build Coastguard Worker         return true;
116*795d594fSAndroid Build Coastguard Worker       }
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker       lir::CodeIr* cir_;
119*795d594fSAndroid Build Coastguard Worker       bool seen_first_inst = false;
120*795d594fSAndroid Build Coastguard Worker     };
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker     lir::CodeIr c(method.get(), ir);
123*795d594fSAndroid Build Coastguard Worker     AddNopVisitor visitor(&c);
124*795d594fSAndroid Build Coastguard Worker     for (auto it = c.instructions.begin(); it != c.instructions.end(); ++it) {
125*795d594fSAndroid Build Coastguard Worker       lir::Instruction* fi = *it;
126*795d594fSAndroid Build Coastguard Worker       if (fi->Accept(&visitor)) {
127*795d594fSAndroid Build Coastguard Worker         break;
128*795d594fSAndroid Build Coastguard Worker       }
129*795d594fSAndroid Build Coastguard Worker     }
130*795d594fSAndroid Build Coastguard Worker     c.Assemble();
131*795d594fSAndroid Build Coastguard Worker   }
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker 
CbClassFileLoadHook(jvmtiEnv * jvmti,JNIEnv * env,jclass classBeingRedefined,jobject loader,const char * name,jobject protectionDomain,jint classDataLen,const unsigned char * classData,jint * newClassDataLen,unsigned char ** newClassData)134*795d594fSAndroid Build Coastguard Worker static void CbClassFileLoadHook(jvmtiEnv* jvmti,
135*795d594fSAndroid Build Coastguard Worker                                 [[maybe_unused]] JNIEnv* env,
136*795d594fSAndroid Build Coastguard Worker                                 [[maybe_unused]] jclass classBeingRedefined,
137*795d594fSAndroid Build Coastguard Worker                                 [[maybe_unused]] jobject loader,
138*795d594fSAndroid Build Coastguard Worker                                 const char* name,
139*795d594fSAndroid Build Coastguard Worker                                 [[maybe_unused]] jobject protectionDomain,
140*795d594fSAndroid Build Coastguard Worker                                 jint classDataLen,
141*795d594fSAndroid Build Coastguard Worker                                 const unsigned char* classData,
142*795d594fSAndroid Build Coastguard Worker                                 jint* newClassDataLen,
143*795d594fSAndroid Build Coastguard Worker                                 unsigned char** newClassData) {
144*795d594fSAndroid Build Coastguard Worker   std::string desc(classNameToDescriptor(name));
145*795d594fSAndroid Build Coastguard Worker   std::string fqcn(DescriptorToFQCN(desc));
146*795d594fSAndroid Build Coastguard Worker   AgentInfo* ai = GetAgentInfo(jvmti);
147*795d594fSAndroid Build Coastguard Worker   {
148*795d594fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> mu(ai->mutex);
149*795d594fSAndroid Build Coastguard Worker     if (ai->classes.find(fqcn) == ai->classes.end()) {
150*795d594fSAndroid Build Coastguard Worker       return;
151*795d594fSAndroid Build Coastguard Worker     }
152*795d594fSAndroid Build Coastguard Worker   }
153*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "Got CFLH for " << name << " on env " << static_cast<void*>(jvmti);
154*795d594fSAndroid Build Coastguard Worker   JvmtiAllocator allocator(jvmti);
155*795d594fSAndroid Build Coastguard Worker   dex::Reader reader(classData, classDataLen);
156*795d594fSAndroid Build Coastguard Worker   dex::u4 index = reader.FindClassIndex(desc.c_str());
157*795d594fSAndroid Build Coastguard Worker   reader.CreateClassIr(index);
158*795d594fSAndroid Build Coastguard Worker   std::shared_ptr<ir::DexFile> ir(reader.GetIr());
159*795d594fSAndroid Build Coastguard Worker   Transform(ir);
160*795d594fSAndroid Build Coastguard Worker   dex::Writer writer(ir);
161*795d594fSAndroid Build Coastguard Worker   size_t new_size;
162*795d594fSAndroid Build Coastguard Worker   *newClassData = writer.CreateImage(&allocator, &new_size);
163*795d594fSAndroid Build Coastguard Worker   *newClassDataLen = new_size;
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker 
FindClass(jvmtiEnv * jvmti,JNIEnv * env,const std::string & name)166*795d594fSAndroid Build Coastguard Worker static jclass FindClass(jvmtiEnv* jvmti, JNIEnv* env, const std::string& name) {
167*795d594fSAndroid Build Coastguard Worker   jclass res = env->FindClass(name.c_str());
168*795d594fSAndroid Build Coastguard Worker   if (res != nullptr) {
169*795d594fSAndroid Build Coastguard Worker     return res;
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jthrowable> exc(env, env->ExceptionOccurred());
172*795d594fSAndroid Build Coastguard Worker   env->ExceptionClear();
173*795d594fSAndroid Build Coastguard Worker   // Try to find it in other classloaders.
174*795d594fSAndroid Build Coastguard Worker   env->PushLocalFrame(1 << 18);
175*795d594fSAndroid Build Coastguard Worker   do {
176*795d594fSAndroid Build Coastguard Worker     jint cnt;
177*795d594fSAndroid Build Coastguard Worker     jclass* klasses;
178*795d594fSAndroid Build Coastguard Worker     if (jvmti->GetLoadedClasses(&cnt, &klasses) != JVMTI_ERROR_NONE) {
179*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Unable to get loaded classes!";
180*795d594fSAndroid Build Coastguard Worker       break;
181*795d594fSAndroid Build Coastguard Worker     }
182*795d594fSAndroid Build Coastguard Worker     for (jint i = 0; i < cnt; i++) {
183*795d594fSAndroid Build Coastguard Worker       char* sig;
184*795d594fSAndroid Build Coastguard Worker       if (jvmti->GetClassSignature(klasses[i], &sig, nullptr) != JVMTI_ERROR_NONE) {
185*795d594fSAndroid Build Coastguard Worker         continue;
186*795d594fSAndroid Build Coastguard Worker       }
187*795d594fSAndroid Build Coastguard Worker       if (sig[0] == 'L' && DescriptorToFQCN(sig) == name) {
188*795d594fSAndroid Build Coastguard Worker         res = klasses[i];
189*795d594fSAndroid Build Coastguard Worker         break;
190*795d594fSAndroid Build Coastguard Worker       }
191*795d594fSAndroid Build Coastguard Worker     }
192*795d594fSAndroid Build Coastguard Worker     jvmti->Deallocate(reinterpret_cast<unsigned char*>(klasses));
193*795d594fSAndroid Build Coastguard Worker   } while (false);
194*795d594fSAndroid Build Coastguard Worker   res = reinterpret_cast<jclass>(env->PopLocalFrame(res));
195*795d594fSAndroid Build Coastguard Worker   if (res == nullptr && exc.get() != nullptr) {
196*795d594fSAndroid Build Coastguard Worker     env->Throw(exc.get());
197*795d594fSAndroid Build Coastguard Worker   }
198*795d594fSAndroid Build Coastguard Worker   return res;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker 
RedefineClass(jvmtiEnv * jvmti,JNIEnv * env,const std::string & klass_name)201*795d594fSAndroid Build Coastguard Worker static void RedefineClass(jvmtiEnv* jvmti, JNIEnv* env, const std::string& klass_name) {
202*795d594fSAndroid Build Coastguard Worker   jclass klass = nullptr;
203*795d594fSAndroid Build Coastguard Worker   if ((klass = FindClass(jvmti, env, klass_name)) == nullptr) {
204*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << "Failed to find class for " << klass_name;
205*795d594fSAndroid Build Coastguard Worker     env->ExceptionDescribe();
206*795d594fSAndroid Build Coastguard Worker     env->ExceptionClear();
207*795d594fSAndroid Build Coastguard Worker     return;
208*795d594fSAndroid Build Coastguard Worker   }
209*795d594fSAndroid Build Coastguard Worker   jvmti->RetransformClasses(1, &klass);
210*795d594fSAndroid Build Coastguard Worker   env->DeleteLocalRef(klass);
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker 
AgentMain(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)213*795d594fSAndroid Build Coastguard Worker static void AgentMain(jvmtiEnv* jvmti, JNIEnv* jni, [[maybe_unused]] void* arg) {
214*795d594fSAndroid Build Coastguard Worker   AgentInfo* ai = GetAgentInfo(jvmti);
215*795d594fSAndroid Build Coastguard Worker   std::string klass_name;
216*795d594fSAndroid Build Coastguard Worker   jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr);
217*795d594fSAndroid Build Coastguard Worker   // TODO Replace this with something that can read from a fifo and ignore the 'EOF's.
218*795d594fSAndroid Build Coastguard Worker   while (std::getline(ai->stream, klass_name, '\n')) {
219*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Redefining class " << klass_name << " with " << static_cast<void*>(jvmti);
220*795d594fSAndroid Build Coastguard Worker     {
221*795d594fSAndroid Build Coastguard Worker       std::lock_guard<std::mutex> mu(ai->mutex);
222*795d594fSAndroid Build Coastguard Worker       ai->classes.insert(klass_name);
223*795d594fSAndroid Build Coastguard Worker     }
224*795d594fSAndroid Build Coastguard Worker     RedefineClass(jvmti, jni, klass_name);
225*795d594fSAndroid Build Coastguard Worker   }
226*795d594fSAndroid Build Coastguard Worker }
227*795d594fSAndroid Build Coastguard Worker 
CbVmInit(jvmtiEnv * jvmti,JNIEnv * env,jthread thr)228*795d594fSAndroid Build Coastguard Worker static void CbVmInit(jvmtiEnv* jvmti, JNIEnv* env, [[maybe_unused]] jthread thr) {
229*795d594fSAndroid Build Coastguard Worker   // Create a Thread object.
230*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("Agent Thread"));
231*795d594fSAndroid Build Coastguard Worker   if (thread_name.get() == nullptr) {
232*795d594fSAndroid Build Coastguard Worker     env->ExceptionDescribe();
233*795d594fSAndroid Build Coastguard Worker     env->ExceptionClear();
234*795d594fSAndroid Build Coastguard Worker     return;
235*795d594fSAndroid Build Coastguard Worker   }
236*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
237*795d594fSAndroid Build Coastguard Worker   if (thread_klass.get() == nullptr) {
238*795d594fSAndroid Build Coastguard Worker     env->ExceptionDescribe();
239*795d594fSAndroid Build Coastguard Worker     env->ExceptionClear();
240*795d594fSAndroid Build Coastguard Worker     return;
241*795d594fSAndroid Build Coastguard Worker   }
242*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
243*795d594fSAndroid Build Coastguard Worker   if (thread.get() == nullptr) {
244*795d594fSAndroid Build Coastguard Worker     env->ExceptionDescribe();
245*795d594fSAndroid Build Coastguard Worker     env->ExceptionClear();
246*795d594fSAndroid Build Coastguard Worker     return;
247*795d594fSAndroid Build Coastguard Worker   }
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker   env->CallNonvirtualVoidMethod(
250*795d594fSAndroid Build Coastguard Worker       thread.get(),
251*795d594fSAndroid Build Coastguard Worker       thread_klass.get(),
252*795d594fSAndroid Build Coastguard Worker       env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V"),
253*795d594fSAndroid Build Coastguard Worker       thread_name.get());
254*795d594fSAndroid Build Coastguard Worker   env->CallVoidMethod(thread.get(), env->GetMethodID(thread_klass.get(), "setPriority", "(I)V"), 1);
255*795d594fSAndroid Build Coastguard Worker   env->CallVoidMethod(
256*795d594fSAndroid Build Coastguard Worker       thread.get(), env->GetMethodID(thread_klass.get(), "setDaemon", "(Z)V"), JNI_TRUE);
257*795d594fSAndroid Build Coastguard Worker 
258*795d594fSAndroid Build Coastguard Worker   jvmti->RunAgentThread(thread.get(), AgentMain, nullptr, JVMTI_THREAD_MIN_PRIORITY);
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker }  // namespace
262*795d594fSAndroid Build Coastguard Worker 
263*795d594fSAndroid Build Coastguard Worker template <bool kIsOnLoad>
AgentStart(JavaVM * vm,char * options,void * reserved)264*795d594fSAndroid Build Coastguard Worker static jint AgentStart(JavaVM* vm, char* options, [[maybe_unused]] void* reserved) {
265*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* jvmti = nullptr;
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_1) != JNI_OK ||
268*795d594fSAndroid Build Coastguard Worker       jvmti == nullptr) {
269*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "unable to obtain JVMTI env.";
270*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
271*795d594fSAndroid Build Coastguard Worker   }
272*795d594fSAndroid Build Coastguard Worker   std::string sopts(options);
273*795d594fSAndroid Build Coastguard Worker   AgentInfo* ai = new AgentInfo;
274*795d594fSAndroid Build Coastguard Worker   ai->stream.open(options, std::ios_base::in);
275*795d594fSAndroid Build Coastguard Worker   if (!ai->stream.is_open()) {
276*795d594fSAndroid Build Coastguard Worker     PLOG(ERROR) << "Could not open file " << options << " for triggering class-reload";
277*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker 
280*795d594fSAndroid Build Coastguard Worker   jvmtiCapabilities caps{
281*795d594fSAndroid Build Coastguard Worker     .can_retransform_classes = 1,
282*795d594fSAndroid Build Coastguard Worker   };
283*795d594fSAndroid Build Coastguard Worker   if (jvmti->AddCapabilities(&caps) != JVMTI_ERROR_NONE) {
284*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to get retransform_classes capability!";
285*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
286*795d594fSAndroid Build Coastguard Worker   }
287*795d594fSAndroid Build Coastguard Worker   jvmtiEventCallbacks cb{
288*795d594fSAndroid Build Coastguard Worker     .VMInit = CbVmInit,
289*795d594fSAndroid Build Coastguard Worker     .ClassFileLoadHook = CbClassFileLoadHook,
290*795d594fSAndroid Build Coastguard Worker   };
291*795d594fSAndroid Build Coastguard Worker   jvmti->SetEventCallbacks(&cb, sizeof(cb));
292*795d594fSAndroid Build Coastguard Worker   jvmti->SetEnvironmentLocalStorage(reinterpret_cast<void*>(ai));
293*795d594fSAndroid Build Coastguard Worker   if (kIsOnLoad) {
294*795d594fSAndroid Build Coastguard Worker     jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, nullptr);
295*795d594fSAndroid Build Coastguard Worker   } else {
296*795d594fSAndroid Build Coastguard Worker     JNIEnv* jni = nullptr;
297*795d594fSAndroid Build Coastguard Worker     vm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_2);
298*795d594fSAndroid Build Coastguard Worker     jthread thr;
299*795d594fSAndroid Build Coastguard Worker     jvmti->GetCurrentThread(&thr);
300*795d594fSAndroid Build Coastguard Worker     CbVmInit(jvmti, jni, thr);
301*795d594fSAndroid Build Coastguard Worker   }
302*795d594fSAndroid Build Coastguard Worker   return JNI_OK;
303*795d594fSAndroid Build Coastguard Worker }
304*795d594fSAndroid Build Coastguard Worker 
305*795d594fSAndroid Build Coastguard Worker // Late attachment (e.g. 'am attach-agent').
Agent_OnAttach(JavaVM * vm,char * options,void * reserved)306*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
307*795d594fSAndroid Build Coastguard Worker   return AgentStart<false>(vm, options, reserved);
308*795d594fSAndroid Build Coastguard Worker }
309*795d594fSAndroid Build Coastguard Worker 
310*795d594fSAndroid Build Coastguard Worker // Early attachment
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)311*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) {
312*795d594fSAndroid Build Coastguard Worker   return AgentStart<true>(jvm, options, reserved);
313*795d594fSAndroid Build Coastguard Worker }
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker }  // namespace forceredefine
316