Home | History | Annotate | Download | only in 986-native-method-bind
      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 
     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 
     41 extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi__(
     42     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
     43   doUpPrintCall(env, "doSayHi");
     44 }
     45 
     46 extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi2(
     47     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
     48   doUpPrintCall(env, "doSayHi2");
     49 }
     50 
     51 extern "C" JNIEXPORT void JNICALL NoReallySayGoodbye(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
     52   doUpPrintCall(env, "doSayBye");
     53 }
     54 
     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 
     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 
    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 
    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