• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <inttypes.h>
18 #include <memory>
19 #include <stdio.h>
20 #include <dlfcn.h>
21 
22 #include "android-base/stringprintf.h"
23 #include "jni.h"
24 #include "jvmti.h"
25 
26 // Test infrastructure
27 #include "jni_binder.h"
28 #include "jvmti_helper.h"
29 #include "test_env.h"
30 #include "scoped_local_ref.h"
31 
32 namespace art {
33 namespace Test986NativeBind {
34 
doUpPrintCall(JNIEnv * env,const char * function)35 static void doUpPrintCall(JNIEnv* env, const char* function) {
36   ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986"));
37   jmethodID targetMethod = env->GetStaticMethodID(klass.get(), function, "()V");
38   env->CallStaticVoidMethod(klass.get(), targetMethod);
39 }
40 
Java_art_Test986_00024Transform_sayHi__(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)41 extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi__(
42     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
43   doUpPrintCall(env, "doSayHi");
44 }
45 
Java_art_Test986_00024Transform_sayHi2(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)46 extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi2(
47     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
48   doUpPrintCall(env, "doSayHi2");
49 }
50 
NoReallySayGoodbye(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)51 extern "C" JNIEXPORT void JNICALL NoReallySayGoodbye(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
52   doUpPrintCall(env, "doSayBye");
53 }
54 
doJvmtiMethodBind(jvmtiEnv * jvmtienv ATTRIBUTE_UNUSED,JNIEnv * env,jthread thread ATTRIBUTE_UNUSED,jmethodID m,void * address,void ** out_address)55 static void doJvmtiMethodBind(jvmtiEnv* jvmtienv ATTRIBUTE_UNUSED,
56                               JNIEnv* env,
57                               jthread thread ATTRIBUTE_UNUSED,
58                               jmethodID m,
59                               void* address,
60                               /*out*/void** out_address) {
61   ScopedLocalRef<jclass> method_class(env, env->FindClass("java/lang/reflect/Method"));
62   ScopedLocalRef<jobject> method_obj(env, env->ToReflectedMethod(method_class.get(), m, false));
63   Dl_info addr_info;
64   if (dladdr(address, &addr_info) == 0 || addr_info.dli_sname == nullptr) {
65     ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception"));
66     env->ThrowNew(exception_class.get(), "dladdr failure!");
67     return;
68   }
69   ScopedLocalRef<jstring> sym_name(env, env->NewStringUTF(addr_info.dli_sname));
70   ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986"));
71   jmethodID upcallMethod = env->GetStaticMethodID(
72       klass.get(),
73       "doNativeMethodBind",
74       "(Ljava/lang/reflect/Method;Ljava/lang/String;)Ljava/lang/String;");
75   if (env->ExceptionCheck()) {
76     return;
77   }
78   ScopedLocalRef<jstring> new_symbol(env,
79                                      reinterpret_cast<jstring>(
80                                          env->CallStaticObjectMethod(klass.get(),
81                                                                  upcallMethod,
82                                                                  method_obj.get(),
83                                                                  sym_name.get())));
84   const char* new_symbol_chars = env->GetStringUTFChars(new_symbol.get(), nullptr);
85   if (strcmp(new_symbol_chars, addr_info.dli_sname) != 0) {
86     *out_address = dlsym(RTLD_DEFAULT, new_symbol_chars);
87     if (*out_address == nullptr) {
88       ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception"));
89       env->ThrowNew(exception_class.get(), "dlsym failure!");
90       return;
91     }
92   }
93   env->ReleaseStringUTFChars(new_symbol.get(), new_symbol_chars);
94 }
95 
Java_art_Test986_setupNativeBindNotify(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)96 extern "C" JNIEXPORT void JNICALL Java_art_Test986_setupNativeBindNotify(
97     JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) {
98   jvmtiEventCallbacks cb;
99   memset(&cb, 0, sizeof(cb));
100   cb.NativeMethodBind = doJvmtiMethodBind;
101   jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
102 }
103 
Java_art_Test986_setNativeBindNotify(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jboolean enable)104 extern "C" JNIEXPORT void JNICALL Java_art_Test986_setNativeBindNotify(
105     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) {
106   jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
107                                                        JVMTI_EVENT_NATIVE_METHOD_BIND,
108                                                        nullptr);
109   if (res != JVMTI_ERROR_NONE) {
110     JvmtiErrorToException(env, jvmti_env, res);
111   }
112 }
113 
Java_art_Test986_rebindTransformClass(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jclass k)114 extern "C" JNIEXPORT void JNICALL Java_art_Test986_rebindTransformClass(
115     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jclass k) {
116   JNINativeMethod m[2];
117   m[0].name= "sayHi";
118   m[0].signature = "()V";
119   m[0].fnPtr = reinterpret_cast<void*>(Java_art_Test986_00024Transform_sayHi__);
120   m[1].name= "sayHi2";
121   m[1].signature = "()V";
122   m[1].fnPtr = reinterpret_cast<void*>(Java_art_Test986_00024Transform_sayHi2);
123   env->RegisterNatives(k, m, 2);
124 }
125 
126 }  // namespace Test986NativeBind
127 }  // namespace art
128