diff options
author | 2017-04-18 15:20:38 -0700 | |
---|---|---|
committer | 2017-04-19 09:44:25 -0700 | |
commit | d78ddec5f8eaf1f27e9043f6f42be90149ccb966 (patch) | |
tree | e3c21f93e419ba35486cf8f641d816523a06b9a3 /test/986-native-method-bind/native_bind.cc | |
parent | 66f43b988ad84568a46c1760b314723e9229e6d0 (diff) |
Implement can_generate_native_method_bind capability
This capability lets one observe and even replace the implementations
of native methods when they are bound.
Test: ./test.py --host -j40
Bug: 37432636
Change-Id: I2432a8e4da1a677e8011ce495296f4ab9f42eb3e
Diffstat (limited to 'test/986-native-method-bind/native_bind.cc')
-rw-r--r-- | test/986-native-method-bind/native_bind.cc | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/test/986-native-method-bind/native_bind.cc b/test/986-native-method-bind/native_bind.cc new file mode 100644 index 0000000000..4f93f87dfe --- /dev/null +++ b/test/986-native-method-bind/native_bind.cc @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <inttypes.h> +#include <memory> +#include <stdio.h> +#include <dlfcn.h> + +#include "android-base/stringprintf.h" +#include "jni.h" +#include "jvmti.h" + +// Test infrastructure +#include "jni_binder.h" +#include "jvmti_helper.h" +#include "test_env.h" +#include "scoped_local_ref.h" + +namespace art { +namespace Test986NativeBind { + +static void doUpPrintCall(JNIEnv* env, const char* function) { + ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986")); + jmethodID targetMethod = env->GetStaticMethodID(klass.get(), function, "()V"); + env->CallStaticVoidMethod(klass.get(), targetMethod); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test986_00024Transform_sayHi( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayHi"); +} + +extern "C" JNIEXPORT void JNICALL NoReallySayGoodbye(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { + doUpPrintCall(env, "doSayBye"); +} + +static void doJvmtiMethodBind(jvmtiEnv* jvmtienv ATTRIBUTE_UNUSED, + JNIEnv* env, + jthread thread ATTRIBUTE_UNUSED, + jmethodID m, + void* address, + /*out*/void** out_address) { + ScopedLocalRef<jclass> method_class(env, env->FindClass("java/lang/reflect/Method")); + ScopedLocalRef<jobject> method_obj(env, env->ToReflectedMethod(method_class.get(), m, false)); + Dl_info addr_info; + if (dladdr(address, &addr_info) == 0 || addr_info.dli_sname == nullptr) { + ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception")); + env->ThrowNew(exception_class.get(), "dladdr failure!"); + return; + } + ScopedLocalRef<jstring> sym_name(env, env->NewStringUTF(addr_info.dli_sname)); + ScopedLocalRef<jclass> klass(env, env->FindClass("art/Test986")); + jmethodID upcallMethod = env->GetStaticMethodID( + klass.get(), + "doNativeMethodBind", + "(Ljava/lang/reflect/Method;Ljava/lang/String;)Ljava/lang/String;"); + if (env->ExceptionCheck()) { + return; + } + ScopedLocalRef<jstring> new_symbol(env, + reinterpret_cast<jstring>( + env->CallStaticObjectMethod(klass.get(), + upcallMethod, + method_obj.get(), + sym_name.get()))); + const char* new_symbol_chars = env->GetStringUTFChars(new_symbol.get(), nullptr); + if (strcmp(new_symbol_chars, addr_info.dli_sname) != 0) { + *out_address = dlsym(RTLD_DEFAULT, new_symbol_chars); + if (*out_address == nullptr) { + ScopedLocalRef<jclass> exception_class(env, env->FindClass("java/lang/Exception")); + env->ThrowNew(exception_class.get(), "dlsym failure!"); + return; + } + } + env->ReleaseStringUTFChars(new_symbol.get(), new_symbol_chars); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test986_setupNativeBindNotify( + JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) { + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.NativeMethodBind = doJvmtiMethodBind; + jvmti_env->SetEventCallbacks(&cb, sizeof(cb)); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test986_setNativeBindNotify( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) { + jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE, + JVMTI_EVENT_NATIVE_METHOD_BIND, + nullptr); + if (res != JVMTI_ERROR_NONE) { + JvmtiErrorToException(env, jvmti_env, res); + } +} + +} // namespace Test986NativeBind +} // namespace art |