summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author dimitry <dimitry@google.com> 2024-03-27 11:55:07 +0100
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-04-05 13:26:56 +0000
commit5fe81fd246fe073c5d903a4cb50182fb7132a939 (patch)
tree9aafbad282304a2edfe6886166d82d2f79586214
parent4e6db6efb36ab9cb9a5990346e77d7976e1b3c66 (diff)
Add getTrampolineForFunctionPointer method to native bridge
Add a function to native bridge that generates trampolines for guest pointers and call it for native-bridged namespaces. Bug: http://b/330367443 Test: art/libnativebridge/tests/runtests.sh --skip-target Test: ./android-cts/tools/cts-tradefed run cts -m CtsJniTestCases Change-Id: I02cab5ea6c87cb4d5065033a4b6793eb57fe0f52
-rw-r--r--libnativebridge/include/nativebridge/native_bridge.h19
-rw-r--r--libnativebridge/native_bridge.cc17
-rw-r--r--libnativebridge/native_bridge_lazy.cc8
-rw-r--r--libnativebridge/tests/NativeBridge7CriticalNative_lib.cpp12
-rw-r--r--libnativebridge/tests/NativeBridge7CriticalNative_lib.h4
-rw-r--r--libnativebridge/tests/NativeBridge7CriticalNative_test.cpp9
-rw-r--r--libnativebridge/tests/NativeBridgeTestCase7.cpp12
-rw-r--r--libnativeloader/include/nativeloader/native_loader.h3
-rw-r--r--libnativeloader/native_loader.cpp2
-rw-r--r--runtime/jni/jni_internal.cc45
10 files changed, 127 insertions, 4 deletions
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 <cstdarg>
#include <log/log.h>
+
+#include <cstdarg>
#include <memory>
#include <utility>
@@ -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<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+#if defined(__ANDROID__)
+ ScopedLocalRef<jobject> jclass_loader(soa.Env(), soa.AddLocalReference<jobject>(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 <typename ArrayT, typename ElementT, typename ArtArrayT>
static ElementT* GetPrimitiveArray(JNIEnv* env, ArrayT java_array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(java_array);