blob: ea6359e5e0548a1be38fab3f3ae94c52120be863 [file] [log] [blame]
Alex Light1e07ca62016-12-02 11:40:56 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ti-agent/common_helper.h"
18
Andreas Gampe53ae7802017-01-19 21:13:46 -080019#include <dlfcn.h>
Alex Light1e07ca62016-12-02 11:40:56 -080020#include <stdio.h>
Alex Light460d1b42017-01-10 15:37:17 +000021#include <sstream>
Alex Light6ac57502017-01-19 15:05:06 -080022#include <deque>
Alex Light1e07ca62016-12-02 11:40:56 -080023
Andreas Gampe53ae7802017-01-19 21:13:46 -080024#include "android-base/stringprintf.h"
Alex Lightdba61482016-12-21 08:20:29 -080025#include "art_method.h"
Alex Light1e07ca62016-12-02 11:40:56 -080026#include "jni.h"
Andreas Gampe53ae7802017-01-19 21:13:46 -080027#include "jni_internal.h"
Alex Light1e07ca62016-12-02 11:40:56 -080028#include "openjdkjvmti/jvmti.h"
Alex Lightdba61482016-12-21 08:20:29 -080029#include "scoped_thread_state_change-inl.h"
Andreas Gampe53ae7802017-01-19 21:13:46 -080030#include "ScopedLocalRef.h"
Alex Lightdba61482016-12-21 08:20:29 -080031#include "stack.h"
Alex Light1e07ca62016-12-02 11:40:56 -080032#include "ti-agent/common_load.h"
33#include "utils.h"
34
35namespace art {
36bool RuntimeIsJVM;
37
38bool IsJVM() {
39 return RuntimeIsJVM;
40}
41
42void SetAllCapabilities(jvmtiEnv* env) {
43 jvmtiCapabilities caps;
44 env->GetPotentialCapabilities(&caps);
45 env->AddCapabilities(&caps);
46}
47
Andreas Gampe1bdaf732017-01-09 19:21:06 -080048bool JvmtiErrorToException(JNIEnv* env, jvmtiError error) {
49 if (error == JVMTI_ERROR_NONE) {
50 return false;
51 }
52
53 ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
54 if (rt_exception.get() == nullptr) {
55 // CNFE should be pending.
56 return true;
57 }
58
59 char* err;
60 jvmti_env->GetErrorName(error, &err);
61
62 env->ThrowNew(rt_exception.get(), err);
63
64 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
65 return true;
66}
67
Alex Light1e07ca62016-12-02 11:40:56 -080068
Alex Light6ac57502017-01-19 15:05:06 -080069template <bool is_redefine>
70static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
71 JNIEnv* env,
72 jint num_targets,
73 jclass* target,
74 jvmtiError res) {
Alex Light460d1b42017-01-10 15:37:17 +000075 std::stringstream err;
Alex Light460d1b42017-01-10 15:37:17 +000076 char* error = nullptr;
77 jvmti->GetErrorName(res, &error);
Alex Light6ac57502017-01-19 15:05:06 -080078 err << "Failed to " << (is_redefine ? "redefine" : "retransform") << " class";
Alex Light0e692732017-01-10 15:00:05 -080079 if (num_targets > 1) {
80 err << "es";
81 }
82 err << " <";
83 for (jint i = 0; i < num_targets; i++) {
84 char* signature = nullptr;
85 char* generic = nullptr;
86 jvmti->GetClassSignature(target[i], &signature, &generic);
87 if (i != 0) {
88 err << ", ";
89 }
90 err << signature;
91 jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
92 jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
93 }
94 err << "> due to " << error;
Alex Light460d1b42017-01-10 15:37:17 +000095 std::string message = err.str();
Alex Light460d1b42017-01-10 15:37:17 +000096 jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
97 env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
98}
99
Alex Light6ac57502017-01-19 15:05:06 -0800100namespace common_redefine {
101
102static void throwRedefinitionError(jvmtiEnv* jvmti,
103 JNIEnv* env,
104 jint num_targets,
105 jclass* target,
106 jvmtiError res) {
107 return throwCommonRedefinitionError<true>(jvmti, env, num_targets, target, res);
108}
109
Alex Light0e692732017-01-10 15:00:05 -0800110static void DoMultiClassRedefine(jvmtiEnv* jvmti_env,
111 JNIEnv* env,
112 jint num_redefines,
113 jclass* targets,
114 jbyteArray* class_file_bytes,
115 jbyteArray* dex_file_bytes) {
116 std::vector<jvmtiClassDefinition> defs;
117 for (jint i = 0; i < num_redefines; i++) {
118 jbyteArray desired_array = IsJVM() ? class_file_bytes[i] : dex_file_bytes[i];
119 jint len = static_cast<jint>(env->GetArrayLength(desired_array));
120 const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
121 env->GetByteArrayElements(desired_array, nullptr));
122 defs.push_back({targets[i], static_cast<jint>(len), redef_bytes});
Alex Light1e07ca62016-12-02 11:40:56 -0800123 }
Alex Light0e692732017-01-10 15:00:05 -0800124 jvmtiError res = jvmti_env->RedefineClasses(num_redefines, defs.data());
Alex Light1e07ca62016-12-02 11:40:56 -0800125 if (res != JVMTI_ERROR_NONE) {
Alex Light0e692732017-01-10 15:00:05 -0800126 throwRedefinitionError(jvmti_env, env, num_redefines, targets, res);
Alex Light1e07ca62016-12-02 11:40:56 -0800127 }
128}
129
Alex Light0e692732017-01-10 15:00:05 -0800130static void DoClassRedefine(jvmtiEnv* jvmti_env,
131 JNIEnv* env,
132 jclass target,
133 jbyteArray class_file_bytes,
134 jbyteArray dex_file_bytes) {
135 return DoMultiClassRedefine(jvmti_env, env, 1, &target, &class_file_bytes, &dex_file_bytes);
136}
137
Alex Light1e07ca62016-12-02 11:40:56 -0800138// Magic JNI export that classes can use for redefining classes.
139// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
140extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRedefinition(JNIEnv* env,
141 jclass,
142 jclass target,
143 jbyteArray class_file_bytes,
144 jbyteArray dex_file_bytes) {
Alex Light0e692732017-01-10 15:00:05 -0800145 DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
146}
147
148// Magic JNI export that classes can use for redefining classes.
149// To use classes should declare this as a native function with signature
150// ([Ljava/lang/Class;[[B[[B)V
151extern "C" JNIEXPORT void JNICALL Java_Main_doCommonMultiClassRedefinition(
152 JNIEnv* env,
153 jclass,
154 jobjectArray targets,
155 jobjectArray class_file_bytes,
156 jobjectArray dex_file_bytes) {
157 std::vector<jclass> classes;
158 std::vector<jbyteArray> class_files;
159 std::vector<jbyteArray> dex_files;
160 jint len = env->GetArrayLength(targets);
161 if (len != env->GetArrayLength(class_file_bytes) || len != env->GetArrayLength(dex_file_bytes)) {
162 env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
163 "the three array arguments passed to this function have different lengths!");
164 return;
165 }
166 for (jint i = 0; i < len; i++) {
167 classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
168 dex_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(dex_file_bytes, i)));
169 class_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(class_file_bytes, i)));
170 }
171 return DoMultiClassRedefine(jvmti_env,
172 env,
173 len,
174 classes.data(),
175 class_files.data(),
176 dex_files.data());
Alex Light1e07ca62016-12-02 11:40:56 -0800177}
178
Alex Light6ac57502017-01-19 15:05:06 -0800179// Get all capabilities except those related to retransformation.
180jint OnLoad(JavaVM* vm,
181 char* options ATTRIBUTE_UNUSED,
182 void* reserved ATTRIBUTE_UNUSED) {
183 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
184 printf("Unable to get jvmti env!\n");
185 return 1;
186 }
187 jvmtiCapabilities caps;
188 jvmti_env->GetPotentialCapabilities(&caps);
189 caps.can_retransform_classes = 0;
190 caps.can_retransform_any_class = 0;
191 jvmti_env->AddCapabilities(&caps);
192 return 0;
193}
194
195} // namespace common_redefine
196
197namespace common_retransform {
198
199struct CommonTransformationResult {
200 std::vector<unsigned char> class_bytes;
201 std::vector<unsigned char> dex_bytes;
202
203 CommonTransformationResult(size_t class_size, size_t dex_size)
204 : class_bytes(class_size), dex_bytes(dex_size) {}
205
206 CommonTransformationResult() = default;
207 CommonTransformationResult(CommonTransformationResult&&) = default;
208 CommonTransformationResult(CommonTransformationResult&) = default;
209};
210
211// Map from class name to transformation result.
212std::map<std::string, std::deque<CommonTransformationResult>> gTransformations;
Alex Lighte41cad62017-02-01 09:41:26 -0800213bool gPopTransformations = true;
Alex Light6ac57502017-01-19 15:05:06 -0800214
215extern "C" JNIEXPORT void JNICALL Java_Main_addCommonTransformationResult(JNIEnv* env,
216 jclass,
217 jstring class_name,
218 jbyteArray class_array,
219 jbyteArray dex_array) {
220 const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
221 std::string name_str(name_chrs);
222 env->ReleaseStringUTFChars(class_name, name_chrs);
223 CommonTransformationResult trans(env->GetArrayLength(class_array),
224 env->GetArrayLength(dex_array));
225 if (env->ExceptionOccurred()) {
226 return;
227 }
228 env->GetByteArrayRegion(class_array,
229 0,
230 env->GetArrayLength(class_array),
231 reinterpret_cast<jbyte*>(trans.class_bytes.data()));
232 if (env->ExceptionOccurred()) {
233 return;
234 }
235 env->GetByteArrayRegion(dex_array,
236 0,
237 env->GetArrayLength(dex_array),
238 reinterpret_cast<jbyte*>(trans.dex_bytes.data()));
239 if (env->ExceptionOccurred()) {
240 return;
241 }
242 if (gTransformations.find(name_str) == gTransformations.end()) {
243 std::deque<CommonTransformationResult> list;
244 gTransformations[name_str] = std::move(list);
245 }
246 gTransformations[name_str].push_back(std::move(trans));
247}
248
249// The hook we are using.
250void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env,
251 JNIEnv* jni_env ATTRIBUTE_UNUSED,
252 jclass class_being_redefined ATTRIBUTE_UNUSED,
253 jobject loader ATTRIBUTE_UNUSED,
254 const char* name,
255 jobject protection_domain ATTRIBUTE_UNUSED,
256 jint class_data_len ATTRIBUTE_UNUSED,
257 const unsigned char* class_dat ATTRIBUTE_UNUSED,
258 jint* new_class_data_len,
259 unsigned char** new_class_data) {
260 std::string name_str(name);
Alex Lighta7e38d82017-01-19 14:57:28 -0800261 if (gTransformations.find(name_str) != gTransformations.end() &&
262 gTransformations[name_str].size() > 0) {
Alex Light6ac57502017-01-19 15:05:06 -0800263 CommonTransformationResult& res = gTransformations[name_str][0];
264 const std::vector<unsigned char>& desired_array = IsJVM() ? res.class_bytes : res.dex_bytes;
265 unsigned char* new_data;
Alex Lighta7e38d82017-01-19 14:57:28 -0800266 CHECK_EQ(JVMTI_ERROR_NONE, jvmti_env->Allocate(desired_array.size(), &new_data));
Alex Light6ac57502017-01-19 15:05:06 -0800267 memcpy(new_data, desired_array.data(), desired_array.size());
268 *new_class_data = new_data;
269 *new_class_data_len = desired_array.size();
Alex Lighte41cad62017-02-01 09:41:26 -0800270 if (gPopTransformations) {
271 gTransformations[name_str].pop_front();
272 }
273 }
274}
275
276extern "C" JNIEXPORT void Java_Main_setPopRetransformations(JNIEnv*,
277 jclass,
278 jboolean enable) {
279 gPopTransformations = enable;
280}
281
282extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env,
283 jclass,
284 jstring class_name) {
285 const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
286 std::string name_str(name_chrs);
287 env->ReleaseStringUTFChars(class_name, name_chrs);
288 if (gTransformations.find(name_str) != gTransformations.end() &&
289 gTransformations[name_str].size() > 0) {
Alex Light6ac57502017-01-19 15:05:06 -0800290 gTransformations[name_str].pop_front();
Alex Lighte41cad62017-02-01 09:41:26 -0800291 } else {
292 std::stringstream err;
293 err << "No transformations found for class " << name_str;
294 std::string message = err.str();
295 env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
Alex Light6ac57502017-01-19 15:05:06 -0800296 }
297}
298
299extern "C" JNIEXPORT void Java_Main_enableCommonRetransformation(JNIEnv* env,
300 jclass,
301 jboolean enable) {
302 jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
303 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
304 nullptr);
305 if (res != JVMTI_ERROR_NONE) {
306 JvmtiErrorToException(env, res);
307 }
308}
309
310static void throwRetransformationError(jvmtiEnv* jvmti,
311 JNIEnv* env,
312 jint num_targets,
313 jclass* targets,
314 jvmtiError res) {
315 return throwCommonRedefinitionError<false>(jvmti, env, num_targets, targets, res);
316}
317
318static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArray targets) {
319 std::vector<jclass> classes;
320 jint len = env->GetArrayLength(targets);
321 for (jint i = 0; i < len; i++) {
322 classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
323 }
324 jvmtiError res = jvmti_env->RetransformClasses(len, classes.data());
325 if (res != JVMTI_ERROR_NONE) {
326 throwRetransformationError(jvmti_env, env, len, classes.data(), res);
327 }
328}
329
Alex Light6ac57502017-01-19 15:05:06 -0800330extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRetransformation(JNIEnv* env,
331 jclass,
332 jobjectArray targets) {
Alex Light9db679d2017-01-25 15:28:04 -0800333 jvmtiCapabilities caps;
334 jvmtiError caps_err = jvmti_env->GetCapabilities(&caps);
335 if (caps_err != JVMTI_ERROR_NONE) {
336 env->ThrowNew(env->FindClass("java/lang/Exception"),
337 "Unable to get current jvmtiEnv capabilities");
338 return;
339 }
340
341 // Allocate a new environment if we don't have the can_retransform_classes capability needed to
342 // call the RetransformClasses function.
343 jvmtiEnv* real_env = nullptr;
344 if (caps.can_retransform_classes != 1) {
345 JavaVM* vm = nullptr;
346 if (env->GetJavaVM(&vm) != 0 ||
347 vm->GetEnv(reinterpret_cast<void**>(&real_env), JVMTI_VERSION_1_0) != 0) {
348 env->ThrowNew(env->FindClass("java/lang/Exception"),
349 "Unable to create temporary jvmtiEnv for RetransformClasses call.");
350 return;
351 }
352 SetAllCapabilities(real_env);
353 } else {
354 real_env = jvmti_env;
355 }
356 DoClassRetransformation(real_env, env, targets);
357 if (caps.can_retransform_classes != 1) {
358 real_env->DisposeEnvironment();
359 }
Alex Light6ac57502017-01-19 15:05:06 -0800360}
361
362// Get all capabilities except those related to retransformation.
Alex Light1e07ca62016-12-02 11:40:56 -0800363jint OnLoad(JavaVM* vm,
364 char* options ATTRIBUTE_UNUSED,
365 void* reserved ATTRIBUTE_UNUSED) {
366 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
367 printf("Unable to get jvmti env!\n");
368 return 1;
369 }
370 SetAllCapabilities(jvmti_env);
Alex Light6ac57502017-01-19 15:05:06 -0800371 jvmtiEventCallbacks cb;
372 memset(&cb, 0, sizeof(cb));
373 cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable;
374 if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
375 printf("Unable to set class file load hook cb!\n");
376 return 1;
377 }
Alex Light1e07ca62016-12-02 11:40:56 -0800378 return 0;
379}
380
Alex Light6ac57502017-01-19 15:05:06 -0800381} // namespace common_retransform
Alex Light1e07ca62016-12-02 11:40:56 -0800382
Alex Light440b5d92017-01-24 15:32:25 -0800383namespace common_transform {
384
385using art::common_retransform::CommonClassFileLoadHookRetransformable;
386
387// Get all capabilities except those related to retransformation.
388jint OnLoad(JavaVM* vm,
389 char* options ATTRIBUTE_UNUSED,
390 void* reserved ATTRIBUTE_UNUSED) {
391 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
392 printf("Unable to get jvmti env!\n");
393 return 1;
394 }
395 // Don't set the retransform caps
396 jvmtiCapabilities caps;
397 jvmti_env->GetPotentialCapabilities(&caps);
398 caps.can_retransform_classes = 0;
399 caps.can_retransform_any_class = 0;
400 jvmti_env->AddCapabilities(&caps);
401
402 // Use the same callback as the retransform test.
403 jvmtiEventCallbacks cb;
404 memset(&cb, 0, sizeof(cb));
405 cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable;
406 if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
407 printf("Unable to set class file load hook cb!\n");
408 return 1;
409 }
410 return 0;
411}
412
413} // namespace common_transform
414
Andreas Gampe53ae7802017-01-19 21:13:46 -0800415static void BindMethod(jvmtiEnv* jenv,
416 JNIEnv* env,
417 jclass klass,
418 jmethodID method) {
419 char* name;
420 char* signature;
421 jvmtiError name_result = jenv->GetMethodName(method, &name, &signature, nullptr);
422 if (name_result != JVMTI_ERROR_NONE) {
423 LOG(FATAL) << "Could not get methods";
424 }
425
Andreas Gampe53ae7802017-01-19 21:13:46 -0800426 std::string names[2];
Alex Light888a59e2017-01-25 11:41:41 -0800427 if (IsJVM()) {
428 // TODO Get the JNI long name
429 char* klass_name;
430 jvmtiError klass_result = jenv->GetClassSignature(klass, &klass_name, nullptr);
431 if (klass_result == JVMTI_ERROR_NONE) {
432 std::string name_str(name);
433 std::string klass_str(klass_name);
434 names[0] = GetJniShortName(klass_str, name_str);
435 jenv->Deallocate(reinterpret_cast<unsigned char*>(klass_name));
436 } else {
437 LOG(FATAL) << "Could not get class name!";
438 }
439 } else {
Andreas Gampe53ae7802017-01-19 21:13:46 -0800440 ScopedObjectAccess soa(Thread::Current());
Alex Light888a59e2017-01-25 11:41:41 -0800441 ArtMethod* m = jni::DecodeArtMethod(method);
Andreas Gampe53ae7802017-01-19 21:13:46 -0800442 names[0] = m->JniShortName();
443 names[1] = m->JniLongName();
444 }
445 for (const std::string& mangled_name : names) {
Alex Light888a59e2017-01-25 11:41:41 -0800446 if (mangled_name == "") {
447 continue;
448 }
Andreas Gampe9623ca62017-01-20 19:49:11 -0800449 void* sym = dlsym(RTLD_DEFAULT, mangled_name.c_str());
Andreas Gampe53ae7802017-01-19 21:13:46 -0800450 if (sym == nullptr) {
451 continue;
452 }
453
454 JNINativeMethod native_method;
455 native_method.fnPtr = sym;
456 native_method.name = name;
457 native_method.signature = signature;
458
459 env->RegisterNatives(klass, &native_method, 1);
460
461 jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
462 jenv->Deallocate(reinterpret_cast<unsigned char*>(signature));
463 return;
464 }
465
466 LOG(FATAL) << "Could not find " << names[0];
467}
468
469static jclass FindClassWithSystemClassLoader(JNIEnv* env, const char* class_name) {
470 // Find the system classloader.
471 ScopedLocalRef<jclass> cl_klass(env, env->FindClass("java/lang/ClassLoader"));
472 if (cl_klass.get() == nullptr) {
473 return nullptr;
474 }
475 jmethodID getsystemclassloader_method = env->GetStaticMethodID(cl_klass.get(),
476 "getSystemClassLoader",
477 "()Ljava/lang/ClassLoader;");
478 if (getsystemclassloader_method == nullptr) {
479 return nullptr;
480 }
481 ScopedLocalRef<jobject> cl(env, env->CallStaticObjectMethod(cl_klass.get(),
482 getsystemclassloader_method));
483 if (cl.get() == nullptr) {
484 return nullptr;
485 }
486
487 // Create a String of the name.
488 std::string descriptor = android::base::StringPrintf("L%s;", class_name);
489 std::string dot_name = DescriptorToDot(descriptor.c_str());
490 ScopedLocalRef<jstring> name_str(env, env->NewStringUTF(dot_name.c_str()));
491
492 // Call Class.forName with it.
493 ScopedLocalRef<jclass> c_klass(env, env->FindClass("java/lang/Class"));
494 if (c_klass.get() == nullptr) {
495 return nullptr;
496 }
497 jmethodID forname_method = env->GetStaticMethodID(
498 c_klass.get(),
499 "forName",
500 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
501 if (forname_method == nullptr) {
502 return nullptr;
503 }
504
505 return reinterpret_cast<jclass>(env->CallStaticObjectMethod(c_klass.get(),
506 forname_method,
507 name_str.get(),
508 JNI_FALSE,
509 cl.get()));
510}
511
512void BindFunctions(jvmtiEnv* jenv, JNIEnv* env, const char* class_name) {
513 // Use JNI to load the class.
514 ScopedLocalRef<jclass> klass(env, env->FindClass(class_name));
515 if (klass.get() == nullptr) {
516 // We may be called with the wrong classloader. Try explicitly using the system classloader.
517 env->ExceptionClear();
518 klass.reset(FindClassWithSystemClassLoader(env, class_name));
519 if (klass.get() == nullptr) {
520 LOG(FATAL) << "Could not load " << class_name;
521 }
522 }
523
524 // Use JVMTI to get the methods.
525 jint method_count;
526 jmethodID* methods;
527 jvmtiError methods_result = jenv->GetClassMethods(klass.get(), &method_count, &methods);
528 if (methods_result != JVMTI_ERROR_NONE) {
529 LOG(FATAL) << "Could not get methods";
530 }
531
532 // Check each method.
533 for (jint i = 0; i < method_count; ++i) {
534 jint modifiers;
535 jvmtiError mod_result = jenv->GetMethodModifiers(methods[i], &modifiers);
536 if (mod_result != JVMTI_ERROR_NONE) {
537 LOG(FATAL) << "Could not get methods";
538 }
539 constexpr jint kNative = static_cast<jint>(kAccNative);
540 if ((modifiers & kNative) != 0) {
541 BindMethod(jenv, env, klass.get(), methods[i]);
542 }
543 }
544
545 jenv->Deallocate(reinterpret_cast<unsigned char*>(methods));
546}
547
Alex Light1e07ca62016-12-02 11:40:56 -0800548} // namespace art