summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Michael Hoisie <hoisie@google.com> 2024-01-30 23:04:14 +0000
committer Brett Chabot <brettchabot@google.com> 2024-09-17 22:13:41 +0000
commitc80e7d04dbd658420bc985d35d4ccedbe78950ad (patch)
treed89ea4afc5c168f00ffd69c67f8c03dbb45f97e9
parent43db9d0d2d5fd85e1ccfe53c2653d415d8b73ae4 (diff)
Cherry pick customize JNI method binding name.
This commit enables the ability to bind to a native methods that have been renamed according to a fixed pattern. This capability is needed for Robolectric because its bytecode instrumentation renames the original native methods in order to support potentially shadowing them. This capability is cherry picked from the layoutlib-native branch. Flag: EXEMPT: Only changes the behavior on host-side test. Bug: 323057854 Test: m libandroid_runtime Merged-In: I1a25389f7c6eb3270a32d858ee114ddadbc72a65 Change-Id: Idfb9e0900957e3a13bde10ba9626dd9b6ff4ac99
-rw-r--r--core/jni/jni_wrappers.h40
1 files changed, 39 insertions, 1 deletions
diff --git a/core/jni/jni_wrappers.h b/core/jni/jni_wrappers.h
index 3b29e305e410..21b5b1308fcf 100644
--- a/core/jni/jni_wrappers.h
+++ b/core/jni/jni_wrappers.h
@@ -69,9 +69,47 @@ static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
return static_cast<T>(res);
}
+// Inline variable that specifies the method binding format.
+// The expected format is 'XX${method}XX', where ${method} represents the original method name.
+// This variable is shared across all translation units. This is treated as a global variable as
+// per C++ 17.
+inline std::string jniMethodFormat;
+
+inline static void setJniMethodFormat(std::string value) {
+ jniMethodFormat = value;
+}
+
+// Potentially translates the given JNINativeMethods if setJniMethodFormat has been set.
+// Has no effect otherwise
+inline const JNINativeMethod* maybeRenameJniMethods(const JNINativeMethod* gMethods,
+ int numMethods) {
+ if (jniMethodFormat.empty()) {
+ return gMethods;
+ }
+ // Make a copy of gMethods with reformatted method names.
+ JNINativeMethod* modifiedMethods = new JNINativeMethod[numMethods];
+ LOG_ALWAYS_FATAL_IF(!modifiedMethods, "Failed to allocate a copy of the JNI methods");
+
+ size_t methodNamePos = jniMethodFormat.find("${method}");
+ LOG_ALWAYS_FATAL_IF(methodNamePos == std::string::npos,
+ "Invalid jniMethodFormat: could not find '${method}' in pattern");
+
+ for (int i = 0; i < numMethods; i++) {
+ modifiedMethods[i] = gMethods[i];
+ std::string modifiedName = jniMethodFormat;
+ modifiedName.replace(methodNamePos, 9, gMethods[i].name);
+ char* modifiedNameChars = new char[modifiedName.length() + 1];
+ LOG_ALWAYS_FATAL_IF(!modifiedNameChars, "Failed to allocate the new method name");
+ std::strcpy(modifiedNameChars, modifiedName.c_str());
+ modifiedMethods[i].name = modifiedNameChars;
+ }
+ return modifiedMethods;
+}
+
static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods) {
- int res = jniRegisterNativeMethods(env, className, gMethods, numMethods);
+ const JNINativeMethod* modifiedMethods = maybeRenameJniMethods(gMethods, numMethods);
+ int res = jniRegisterNativeMethods(env, className, modifiedMethods, numMethods);
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
return res;
}