diff options
| author | 2024-01-30 23:04:14 +0000 | |
|---|---|---|
| committer | 2024-09-17 22:13:41 +0000 | |
| commit | c80e7d04dbd658420bc985d35d4ccedbe78950ad (patch) | |
| tree | d89ea4afc5c168f00ffd69c67f8c03dbb45f97e9 | |
| parent | 43db9d0d2d5fd85e1ccfe53c2653d415d8b73ae4 (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.h | 40 |
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; } |