diff --git a/libnativebridge/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h index a87b04fa36..b2e4d2219b 100644 --- a/libnativebridge/include/nativebridge/native_bridge.h +++ b/libnativebridge/include/nativebridge/native_bridge.h @@ -95,6 +95,11 @@ void* NativeBridgeGetTrampoline2(void* handle, uint32_t len, enum JNICallType jni_call_type); +void* NativeBridgeGetTrampolineForFunctionPointer(const void* method, + const char* shorty, + uint32_t len, + enum JNICallType jni_call_type); + // True if native library paths are valid and is for an ABI that is supported by native bridge. // The *libpath* must point to a library. // @@ -421,6 +426,20 @@ struct NativeBridgeCallbacks { const char* shorty, uint32_t len, enum JNICallType jni_call_type); + + // Get a native bridge trampoline for specified native method implementation pointer. + // + // Parameters: + // method [IN] pointer to method implementation (ususally registered via call to + // RegisterNatives). + // shorty [IN] short descriptor of native method len [IN] length of shorty + // jni_call_type [IN] the type of JNI call + // Returns: + // address of trampoline if successful, otherwise NULL + void* (*getTrampolineForFunctionPointer)(const void* method, + const char* shorty, + uint32_t len, + enum JNICallType jni_call_type); }; // Runtime interfaces to native bridge. diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc index aabdae6205..4ead5ada2d 100644 --- a/libnativebridge/native_bridge.cc +++ b/libnativebridge/native_bridge.cc @@ -593,6 +593,23 @@ void* NativeBridgeGetTrampoline2( return callbacks->getTrampoline(handle, name, shorty, len); } +void* NativeBridgeGetTrampolineForFunctionPointer(const void* method, + const char* shorty, + uint32_t len, + JNICallType jni_call_type) { + if (!NativeBridgeInitialized()) { + return nullptr; + } + + if (isCompatibleWith(CRITICAL_NATIVE_SUPPORT_VERSION)) { + return callbacks->getTrampolineForFunctionPointer(method, shorty, len, jni_call_type); + } else { + ALOGE("not compatible with version %d, getTrampolineFnPtrWithJNICallType() isn't invoked", + CRITICAL_NATIVE_SUPPORT_VERSION); + return nullptr; + } +} + bool NativeBridgeIsSupported(const char* libpath) { if (NativeBridgeInitialized()) { return callbacks->isSupported(libpath); diff --git a/libnativebridge/native_bridge_lazy.cc b/libnativebridge/native_bridge_lazy.cc index 12dfb0ddb9..09eac02fd9 100644 --- a/libnativebridge/native_bridge_lazy.cc +++ b/libnativebridge/native_bridge_lazy.cc @@ -75,6 +75,14 @@ void* NativeBridgeGetTrampoline2( return f(handle, name, shorty, len, jni_call_type); } +void* NativeBridgeGetTrampolineForFunctionPointer(const void* method, + const char* shorty, + uint32_t len, + JNICallType jni_call_type) { + static auto f = GET_FUNC_PTR(NativeBridgeGetTrampolineForFunctionPointer); + return f(method, shorty, len, jni_call_type); +} + const char* NativeBridgeGetError() { static auto f = GET_FUNC_PTR(NativeBridgeGetError); return f(); diff --git a/libnativebridge/tests/NativeBridge7CriticalNative_lib.cpp b/libnativebridge/tests/NativeBridge7CriticalNative_lib.cpp index 6446182487..cfd0dc9fef 100644 --- a/libnativebridge/tests/NativeBridge7CriticalNative_lib.cpp +++ b/libnativebridge/tests/NativeBridge7CriticalNative_lib.cpp @@ -22,6 +22,9 @@ static bool g_legacy_get_trampoline_called = false; static bool g_get_trampoline2_called = false; static JNICallType g_jni_call_type = kJNICallTypeRegular; +static bool g_get_trampoline_fn_ptr_called = false; +static JNICallType g_fn_ptr_jni_call_type = kJNICallTypeRegular; + void ResetTrampolineCalledState() { g_legacy_get_trampoline_called = false; g_get_trampoline2_called = false; @@ -41,4 +44,13 @@ bool IsGetTrampoline2Called() { return g_get_trampoline2_called; } JNICallType GetTrampoline2JNICallType() { return g_jni_call_type; } +void SetGetTrampolineFnPtrCalled(JNICallType jni_call_type) { + g_get_trampoline_fn_ptr_called = true; + g_fn_ptr_jni_call_type = jni_call_type; +} + +bool IsGetTrampolineFnPtrCalled() { return g_get_trampoline_fn_ptr_called; } + +JNICallType GetTrampolineFnPtrJNICallType() { return g_fn_ptr_jni_call_type; } + } // namespace android diff --git a/libnativebridge/tests/NativeBridge7CriticalNative_lib.h b/libnativebridge/tests/NativeBridge7CriticalNative_lib.h index 5a7594b203..7bf5e9991c 100644 --- a/libnativebridge/tests/NativeBridge7CriticalNative_lib.h +++ b/libnativebridge/tests/NativeBridge7CriticalNative_lib.h @@ -30,6 +30,10 @@ void SetGetTrampoline2Called(JNICallType jni_call_type); bool IsGetTrampoline2Called(); JNICallType GetTrampoline2JNICallType(); +void SetGetTrampolineFnPtrCalled(JNICallType jni_call_type); +bool IsGetTrampolineFnPtrCalled(); +JNICallType GetTrampolineFnPtrJNICallType(); + } // namespace android #endif // ART_LIBNATIVEBRIDGE_TESTS_NATIVEBRIDGE7CRITICALNATIVE_LIB_H_ diff --git a/libnativebridge/tests/NativeBridge7CriticalNative_test.cpp b/libnativebridge/tests/NativeBridge7CriticalNative_test.cpp index 0d9f8bdc3a..5662214f40 100644 --- a/libnativebridge/tests/NativeBridge7CriticalNative_test.cpp +++ b/libnativebridge/tests/NativeBridge7CriticalNative_test.cpp @@ -48,6 +48,15 @@ TEST_F(NativeBridgeTest, V7_CriticalNative) { ASSERT_FALSE(IsLegacyGetTrampolineCalled()); ASSERT_TRUE(IsGetTrampoline2Called()); EXPECT_EQ(GetTrampoline2JNICallType(), kJNICallTypeCriticalNative); + + ASSERT_FALSE(IsGetTrampolineFnPtrCalled()); + + EXPECT_EQ( + NativeBridgeGetTrampolineForFunctionPointer(nullptr, "shorty", 6, kJNICallTypeCriticalNative), + nullptr); + ASSERT_FALSE(IsLegacyGetTrampolineCalled()); + ASSERT_TRUE(IsGetTrampolineFnPtrCalled()); + EXPECT_EQ(GetTrampolineFnPtrJNICallType(), kJNICallTypeCriticalNative); } } // namespace android diff --git a/libnativebridge/tests/NativeBridgeTestCase7.cpp b/libnativebridge/tests/NativeBridgeTestCase7.cpp index 03016bdbac..f84930c71b 100644 --- a/libnativebridge/tests/NativeBridgeTestCase7.cpp +++ b/libnativebridge/tests/NativeBridgeTestCase7.cpp @@ -48,6 +48,15 @@ extern "C" void* native_bridge7_getTrampoline2(void* /* handle */, return nullptr; } +extern "C" void* native_bridge7_getTrampolineForFunctionPointer( + const void* /* method */, + const char* /* shorty */, + uint32_t /* len */, + android::JNICallType jni_call_type) { + android::SetGetTrampolineFnPtrCalled(jni_call_type); + return nullptr; +} + extern "C" bool native_bridge7_isSupported(const char* /* libpath */) { return false; } extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge7_getAppEnv( @@ -134,4 +143,5 @@ android::NativeBridgeCallbacks NativeBridgeItf{ // v6 &native_bridge7_preZygoteFork, // v7 - &native_bridge7_getTrampoline2}; + &native_bridge7_getTrampoline2, + &native_bridge7_getTrampolineForFunctionPointer}; diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h index 92d192ff25..6a2046f763 100644 --- a/libnativeloader/include/nativeloader/native_loader.h +++ b/libnativeloader/include/nativeloader/native_loader.h @@ -65,6 +65,9 @@ FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader); __attribute__((visibility("default"))) void* OpenNativeLibraryInNamespace( struct NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge, char** error_msg); + +__attribute__((visibility("default"))) bool IsNamespaceNativeBridged( + const struct NativeLoaderNamespace* ns); #endif __attribute__((visibility("default"))) diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 5b4988ae48..ea06b2041f 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -527,6 +527,8 @@ void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, return handle.ok() ? *handle : nullptr; } +bool IsNamespaceNativeBridged(const struct NativeLoaderNamespace* ns) { return ns->IsBridged(); } + // native_bridge_namespaces are not supported for callers of this function. // This function will return nullptr in the case when application is running // on native bridge. diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc index b98178507c..d5629b8b01 100644 --- a/runtime/jni/jni_internal.cc +++ b/runtime/jni/jni_internal.cc @@ -16,8 +16,9 @@ #include "jni_internal.h" -#include #include + +#include #include #include @@ -37,10 +38,10 @@ #include "dex/dex_file-inl.h" #include "dex/utf-inl.h" #include "fault_handler.h" -#include "handle_scope.h" -#include "hidden_api.h" #include "gc/accounting/card_table-inl.h" #include "gc_root.h" +#include "handle_scope.h" +#include "hidden_api.h" #include "indirect_reference_table-inl.h" #include "interpreter/interpreter.h" #include "java_vm_ext.h" @@ -58,7 +59,9 @@ #include "mirror/string-alloc-inl.h" #include "mirror/string-inl.h" #include "mirror/throwable.h" +#include "nativebridge/native_bridge.h" #include "nativehelper/scoped_local_ref.h" +#include "nativeloader/native_loader.h" #include "parsed_options.h" #include "reflection.h" #include "runtime.h" @@ -2575,6 +2578,9 @@ class JNI { << c->PrettyDescriptor(); return JNI_OK; } + bool is_class_loader_namespace_natively_bridged = + IsClassLoaderNamespaceNativelyBridged(soa, c->GetClassLoader()); + CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods, JNI_ERR); for (jint i = 0; i < method_count; ++i) { const char* name = methods[i].name; @@ -2683,6 +2689,9 @@ class JNI { // TODO: make this a hard register error in the future. } + if (is_class_loader_namespace_natively_bridged) { + fnPtr = GenerateNativeBridgeTrampoline(fnPtr, m); + } const void* final_function_ptr = class_linker->RegisterNative(soa.Self(), m, fnPtr); UNUSED(final_function_ptr); } @@ -2905,6 +2914,36 @@ class JNI { return array; } + static bool IsClassLoaderNamespaceNativelyBridged(ScopedObjectAccess& soa, + ObjPtr class_loader) + REQUIRES_SHARED(Locks::mutator_lock_) { +#if defined(__ANDROID__) + ScopedLocalRef jclass_loader(soa.Env(), soa.AddLocalReference(class_loader)); + android::NativeLoaderNamespace* ns = + android::FindNativeLoaderNamespaceByClassLoader(soa.Env(), jclass_loader.get()); + return ns != nullptr && android::IsNamespaceNativeBridged(ns); +#else + UNUSED(soa, class_loader); + return false; +#endif + } + + static const void* GenerateNativeBridgeTrampoline(const void* fn_ptr, ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_) { +#if defined(__ANDROID__) + uint32_t shorty_length; + const char* shorty = method->GetShorty(&shorty_length); + android::JNICallType jni_call_type = method->IsCriticalNative() ? + android::JNICallType::kJNICallTypeCriticalNative : + android::JNICallType::kJNICallTypeRegular; + return NativeBridgeGetTrampolineForFunctionPointer( + fn_ptr, shorty, shorty_length, jni_call_type); +#else + UNUSED(method); + return fn_ptr; +#endif + } + template static ElementT* GetPrimitiveArray(JNIEnv* env, ArrayT java_array, jboolean* is_copy) { CHECK_NON_NULL_ARGUMENT(java_array);