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