Loading core/jni/Android.bp +15 −3 Original line number Diff line number Diff line Loading @@ -64,7 +64,6 @@ cc_library_shared { "libbase", "libcutils", "libharfbuzz_ng", "libhwui", "liblog", "libminikin", "libz", Loading Loading @@ -266,6 +265,7 @@ cc_library_shared { "libui", "libgraphicsenv", "libgui", "libhwui", "libmediandk", "libpermission", "libsensor", Loading Loading @@ -344,9 +344,21 @@ cc_library_shared { ], static_libs: [ "libandroidfw", "libcompiler_rt", "libutils", "libbinary_parse", "libdng_sdk", "libft2", "libhostgraphics", "libhwui", "libimage_type_recognition", "libjpeg", "libpiex", "libpng", "libtiff_directory", "libui-types", "libutils", "libwebp-decode", "libwebp-encode", "libwuffs_mirror_release_c", ], }, linux_glibc: { Loading core/jni/LayoutlibLoader.cpp +250 −44 Original line number Diff line number Diff line Loading @@ -14,15 +14,31 @@ * limitations under the License. */ #include "jni.h" #include "core_jni_helpers.h" #include <android-base/logging.h> #include <android-base/properties.h> #include <android/graphics/jni_runtime.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/jni_macros.h> #include <unicode/putil.h> #include <unicode/udata.h> #include <clocale> #include <sstream> #include <unordered_map> #include <vector> #include "core_jni_helpers.h" #include "jni.h" #ifdef _WIN32 #include <windows.h> #else #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #endif #include <iostream> using namespace std; /* Loading @@ -33,6 +49,33 @@ using namespace std; */ static JavaVM* javaVM; static jclass bridge; static jclass layoutLog; static jmethodID getLogId; static jmethodID logMethodId; extern int register_android_os_Binder(JNIEnv* env); extern int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env); typedef void (*FreeFunction)(void*); static void NativeAllocationRegistry_Delegate_nativeApplyFreeFunction(JNIEnv*, jclass, jlong freeFunction, jlong ptr) { void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr)); FreeFunction nativeFreeFunction = reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction)); nativeFreeFunction(nativePtr); } static JNINativeMethod gMethods[] = { NATIVE_METHOD(NativeAllocationRegistry_Delegate, nativeApplyFreeFunction, "(JJ)V"), }; int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env) { return jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry_Delegate", gMethods, NELEM(gMethods)); } namespace android { Loading @@ -47,6 +90,7 @@ extern int register_android_database_SQLiteGlobal(JNIEnv* env); extern int register_android_database_SQLiteDebug(JNIEnv* env); extern int register_android_os_FileObserver(JNIEnv* env); extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); Loading @@ -54,6 +98,11 @@ extern int register_android_text_AndroidCharacter(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); extern int register_android_util_jar_StrictJarFile(JNIEnv* env); extern int register_android_view_KeyCharacterMap(JNIEnv* env); extern int register_android_view_KeyEvent(JNIEnv* env); extern int register_android_view_MotionEvent(JNIEnv* env); extern int register_android_view_ThreadedRenderer(JNIEnv* env); extern int register_android_view_VelocityTracker(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); #define REG_JNI(name) { name } Loading @@ -78,8 +127,10 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = { {"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)}, {"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)}, #ifdef __linux__ {"android.os.Binder", REG_JNI(register_android_os_Binder)}, {"android.os.FileObserver", REG_JNI(register_android_os_FileObserver)}, {"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)}, {"android.os.Parcel", REG_JNI(register_android_os_Parcel)}, #endif {"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)}, {"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)}, Loading @@ -88,11 +139,15 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = { {"android.util.EventLog", REG_JNI(register_android_util_EventLog)}, {"android.util.Log", REG_JNI(register_android_util_Log)}, {"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)}, {"android.view.KeyCharacterMap", REG_JNI(register_android_view_KeyCharacterMap)}, {"android.view.KeyEvent", REG_JNI(register_android_view_KeyEvent)}, {"android.view.MotionEvent", REG_JNI(register_android_view_MotionEvent)}, {"android.view.VelocityTracker", REG_JNI(register_android_view_VelocityTracker)}, {"com.android.internal.util.VirtualRefBasePtr", REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)}, {"libcore.util.NativeAllocationRegistry_Delegate", REG_JNI(register_libcore_util_NativeAllocationRegistry_Delegate)}, }; // Vector to store the names of classes that need delegates of their native methods static vector<string> classesToDelegate; static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& jniRegMap, const vector<string>& classesToRegister, JNIEnv* env) { Loading @@ -102,36 +157,17 @@ static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& return -1; } } if (register_android_graphics_classes(env) < 0) { return -1; } return 0; } int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { string classNameString = string(className); if (find(classesToDelegate.begin(), classesToDelegate.end(), classNameString) != classesToDelegate.end()) { // Register native methods to the delegate class <classNameString>_NativeDelegate // by adding _Original to the name of each method. replace(classNameString.begin(), classNameString.end(), '$', '_'); string delegateClassName = classNameString + "_NativeDelegate"; jclass clazz = env->FindClass(delegateClassName.c_str()); JNINativeMethod gTypefaceDelegateMethods[numMethods]; for (int i = 0; i < numMethods; i++) { JNINativeMethod gTypefaceMethod = gMethods[i]; string newName = string(gTypefaceMethod.name) + "_Original"; gTypefaceDelegateMethods[i].name = strdup(newName.c_str()); gTypefaceDelegateMethods[i].signature = gTypefaceMethod.signature; gTypefaceDelegateMethods[i].fnPtr = gTypefaceMethod.fnPtr; } int result = env->RegisterNatives(clazz, gTypefaceDelegateMethods, numMethods); for (int i = 0; i < numMethods; i++) { free((char*)gTypefaceDelegateMethods[i].name); } return result; } jclass clazz = env->FindClass(className); return env->RegisterNatives(clazz, gMethods, numMethods); return jniRegisterNativeMethods(env, className, gMethods, numMethods); } JNIEnv* AndroidRuntime::getJNIEnv() { Loading Loading @@ -164,6 +200,125 @@ static vector<string> parseCsv(JNIEnv* env, jstring csvJString) { return result; } void LayoutlibLogger(base::LogId, base::LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* message) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jint logPrio = severity; jstring tagString = env->NewStringUTF(tag); jstring messageString = env->NewStringUTF(message); jobject bridgeLog = env->CallStaticObjectMethod(bridge, getLogId); env->CallVoidMethod(bridgeLog, logMethodId, logPrio, tagString, messageString); env->DeleteLocalRef(tagString); env->DeleteLocalRef(messageString); env->DeleteLocalRef(bridgeLog); } void LayoutlibAborter(const char* abort_message) { // Layoutlib should not call abort() as it would terminate Studio. // Throw an exception back to Java instead. JNIEnv* env = AndroidRuntime::getJNIEnv(); jniThrowRuntimeException(env, "The Android framework has encountered a fatal error"); } // This method has been copied/adapted from system/core/init/property_service.cpp // If the ro.product.cpu.abilist* properties have not been explicitly // set, derive them from ro.system.product.cpu.abilist* properties. static void property_initialize_ro_cpu_abilist() { const std::string EMPTY = ""; const char* kAbilistProp = "ro.product.cpu.abilist"; const char* kAbilist32Prop = "ro.product.cpu.abilist32"; const char* kAbilist64Prop = "ro.product.cpu.abilist64"; // If the properties are defined explicitly, just use them. if (base::GetProperty(kAbilistProp, EMPTY) != EMPTY) { return; } std::string abilist32_prop_val; std::string abilist64_prop_val; const auto abilist32_prop = "ro.system.product.cpu.abilist32"; const auto abilist64_prop = "ro.system.product.cpu.abilist64"; abilist32_prop_val = base::GetProperty(abilist32_prop, EMPTY); abilist64_prop_val = base::GetProperty(abilist64_prop, EMPTY); // Merge ABI lists for ro.product.cpu.abilist auto abilist_prop_val = abilist64_prop_val; if (abilist32_prop_val != EMPTY) { if (abilist_prop_val != EMPTY) { abilist_prop_val += ","; } abilist_prop_val += abilist32_prop_val; } // Set these properties const std::pair<const char*, const std::string&> set_prop_list[] = { {kAbilistProp, abilist_prop_val}, {kAbilist32Prop, abilist32_prop_val}, {kAbilist64Prop, abilist64_prop_val}, }; for (const auto& [prop, prop_val] : set_prop_list) { base::SetProperty(prop, prop_val); } } static void* mmapFile(const char* dataFilePath) { #ifdef _WIN32 // Windows needs file path in wide chars to handle unicode file paths int size = MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, NULL, 0); std::vector<wchar_t> wideDataFilePath(size); MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, wideDataFilePath.data(), size); HANDLE file = CreateFileW(wideDataFilePath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); if ((HANDLE)INVALID_HANDLE_VALUE == file) { return nullptr; } struct CloseHandleWrapper { void operator()(HANDLE h) { CloseHandle(h); } }; std::unique_ptr<void, CloseHandleWrapper> mmapHandle( CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr)); if (!mmapHandle) { return nullptr; } return MapViewOfFile(mmapHandle.get(), FILE_MAP_READ, 0, 0, 0); #else int fd = open(dataFilePath, O_RDONLY); if (fd == -1) { return nullptr; } struct stat sb; if (fstat(fd, &sb) == -1) { close(fd); return nullptr; } void* addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { close(fd); return nullptr; } close(fd); return addr; #endif } static bool init_icu(const char* dataPath) { void* addr = mmapFile(dataPath); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(addr, &err); if (err != U_ZERO_ERROR) { return false; } return true; } } // namespace android using namespace android; Loading @@ -175,37 +330,82 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_ERR; } init_android_graphics(); // Configuration is stored as java System properties. // Get a reference to System.getProperty jclass system = FindClassOrDie(env, "java/lang/System"); jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); // Get the names of classes that have to delegate their native methods auto delegateNativesToNativesString = (jstring) env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("delegate_natives_to_natives"), env->NewStringUTF("")); classesToDelegate = parseCsv(env, delegateNativesToNativesString); // Get the names of classes that need to register their native methods auto nativesClassesJString = (jstring) env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("native_classes"), (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("core_native_classes"), env->NewStringUTF("")); vector<string> classesToRegister = parseCsv(env, nativesClassesJString); jstring registerProperty = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF( "register_properties_during_load"), env->NewStringUTF("")); const char* registerPropertyString = env->GetStringUTFChars(registerProperty, 0); if (strcmp(registerPropertyString, "true") == 0) { // Set the system properties first as they could be used in the static initialization of // other classes if (register_android_os_SystemProperties(env) < 0) { return JNI_ERR; } classesToRegister.erase(find(classesToRegister.begin(), classesToRegister.end(), "android.os.SystemProperties")); bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge"); bridge = MakeGlobalRefOrDie(env, bridge); jmethodID setSystemPropertiesMethod = GetStaticMethodIDOrDie(env, bridge, "setSystemProperties", "()V"); env->CallStaticVoidMethod(bridge, setSystemPropertiesMethod); property_initialize_ro_cpu_abilist(); } env->ReleaseStringUTFChars(registerProperty, registerPropertyString); if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) { return JNI_ERR; } // Set the location of ICU data auto stringPath = (jstring) env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("icu.dir"), auto stringPath = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("icu.data.path"), env->NewStringUTF("")); const char* path = env->GetStringUTFChars(stringPath, 0); u_setDataDirectory(path); bool icuInitialized = init_icu(path); env->ReleaseStringUTFChars(stringPath, path); if (!icuInitialized) { return JNI_ERR; } jstring useJniProperty = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("use_bridge_for_logging"), env->NewStringUTF("")); const char* useJniString = env->GetStringUTFChars(useJniProperty, 0); if (strcmp(useJniString, "true") == 0) { layoutLog = FindClassOrDie(env, "com/android/ide/common/rendering/api/ILayoutLog"); layoutLog = MakeGlobalRefOrDie(env, layoutLog); logMethodId = GetMethodIDOrDie(env, layoutLog, "logAndroidFramework", "(ILjava/lang/String;Ljava/lang/String;)V"); if (bridge == nullptr) { bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge"); bridge = MakeGlobalRefOrDie(env, bridge); } getLogId = GetStaticMethodIDOrDie(env, bridge, "getLog", "()Lcom/android/ide/common/rendering/api/ILayoutLog;"); android::base::SetLogger(LayoutlibLogger); android::base::SetAborter(LayoutlibAborter); } else { // initialize logging, so ANDROD_LOG_TAGS env variable is respected android::base::InitLogging(nullptr, android::base::StderrLogger); } env->ReleaseStringUTFChars(useJniProperty, useJniString); // Use English locale for number format to ensure correct parsing of floats when using strtof setlocale(LC_NUMERIC, "en_US.UTF-8"); Loading @@ -213,3 +413,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_VERSION_1_6; } JNIEXPORT void JNI_OnUnload(JavaVM* vm, void*) { JNIEnv* env = nullptr; vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); env->DeleteGlobalRef(bridge); env->DeleteGlobalRef(layoutLog); } Loading
core/jni/Android.bp +15 −3 Original line number Diff line number Diff line Loading @@ -64,7 +64,6 @@ cc_library_shared { "libbase", "libcutils", "libharfbuzz_ng", "libhwui", "liblog", "libminikin", "libz", Loading Loading @@ -266,6 +265,7 @@ cc_library_shared { "libui", "libgraphicsenv", "libgui", "libhwui", "libmediandk", "libpermission", "libsensor", Loading Loading @@ -344,9 +344,21 @@ cc_library_shared { ], static_libs: [ "libandroidfw", "libcompiler_rt", "libutils", "libbinary_parse", "libdng_sdk", "libft2", "libhostgraphics", "libhwui", "libimage_type_recognition", "libjpeg", "libpiex", "libpng", "libtiff_directory", "libui-types", "libutils", "libwebp-decode", "libwebp-encode", "libwuffs_mirror_release_c", ], }, linux_glibc: { Loading
core/jni/LayoutlibLoader.cpp +250 −44 Original line number Diff line number Diff line Loading @@ -14,15 +14,31 @@ * limitations under the License. */ #include "jni.h" #include "core_jni_helpers.h" #include <android-base/logging.h> #include <android-base/properties.h> #include <android/graphics/jni_runtime.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/jni_macros.h> #include <unicode/putil.h> #include <unicode/udata.h> #include <clocale> #include <sstream> #include <unordered_map> #include <vector> #include "core_jni_helpers.h" #include "jni.h" #ifdef _WIN32 #include <windows.h> #else #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #endif #include <iostream> using namespace std; /* Loading @@ -33,6 +49,33 @@ using namespace std; */ static JavaVM* javaVM; static jclass bridge; static jclass layoutLog; static jmethodID getLogId; static jmethodID logMethodId; extern int register_android_os_Binder(JNIEnv* env); extern int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env); typedef void (*FreeFunction)(void*); static void NativeAllocationRegistry_Delegate_nativeApplyFreeFunction(JNIEnv*, jclass, jlong freeFunction, jlong ptr) { void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr)); FreeFunction nativeFreeFunction = reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction)); nativeFreeFunction(nativePtr); } static JNINativeMethod gMethods[] = { NATIVE_METHOD(NativeAllocationRegistry_Delegate, nativeApplyFreeFunction, "(JJ)V"), }; int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env) { return jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry_Delegate", gMethods, NELEM(gMethods)); } namespace android { Loading @@ -47,6 +90,7 @@ extern int register_android_database_SQLiteGlobal(JNIEnv* env); extern int register_android_database_SQLiteDebug(JNIEnv* env); extern int register_android_os_FileObserver(JNIEnv* env); extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); Loading @@ -54,6 +98,11 @@ extern int register_android_text_AndroidCharacter(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); extern int register_android_util_jar_StrictJarFile(JNIEnv* env); extern int register_android_view_KeyCharacterMap(JNIEnv* env); extern int register_android_view_KeyEvent(JNIEnv* env); extern int register_android_view_MotionEvent(JNIEnv* env); extern int register_android_view_ThreadedRenderer(JNIEnv* env); extern int register_android_view_VelocityTracker(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); #define REG_JNI(name) { name } Loading @@ -78,8 +127,10 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = { {"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)}, {"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)}, #ifdef __linux__ {"android.os.Binder", REG_JNI(register_android_os_Binder)}, {"android.os.FileObserver", REG_JNI(register_android_os_FileObserver)}, {"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)}, {"android.os.Parcel", REG_JNI(register_android_os_Parcel)}, #endif {"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)}, {"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)}, Loading @@ -88,11 +139,15 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = { {"android.util.EventLog", REG_JNI(register_android_util_EventLog)}, {"android.util.Log", REG_JNI(register_android_util_Log)}, {"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)}, {"android.view.KeyCharacterMap", REG_JNI(register_android_view_KeyCharacterMap)}, {"android.view.KeyEvent", REG_JNI(register_android_view_KeyEvent)}, {"android.view.MotionEvent", REG_JNI(register_android_view_MotionEvent)}, {"android.view.VelocityTracker", REG_JNI(register_android_view_VelocityTracker)}, {"com.android.internal.util.VirtualRefBasePtr", REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)}, {"libcore.util.NativeAllocationRegistry_Delegate", REG_JNI(register_libcore_util_NativeAllocationRegistry_Delegate)}, }; // Vector to store the names of classes that need delegates of their native methods static vector<string> classesToDelegate; static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& jniRegMap, const vector<string>& classesToRegister, JNIEnv* env) { Loading @@ -102,36 +157,17 @@ static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& return -1; } } if (register_android_graphics_classes(env) < 0) { return -1; } return 0; } int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { string classNameString = string(className); if (find(classesToDelegate.begin(), classesToDelegate.end(), classNameString) != classesToDelegate.end()) { // Register native methods to the delegate class <classNameString>_NativeDelegate // by adding _Original to the name of each method. replace(classNameString.begin(), classNameString.end(), '$', '_'); string delegateClassName = classNameString + "_NativeDelegate"; jclass clazz = env->FindClass(delegateClassName.c_str()); JNINativeMethod gTypefaceDelegateMethods[numMethods]; for (int i = 0; i < numMethods; i++) { JNINativeMethod gTypefaceMethod = gMethods[i]; string newName = string(gTypefaceMethod.name) + "_Original"; gTypefaceDelegateMethods[i].name = strdup(newName.c_str()); gTypefaceDelegateMethods[i].signature = gTypefaceMethod.signature; gTypefaceDelegateMethods[i].fnPtr = gTypefaceMethod.fnPtr; } int result = env->RegisterNatives(clazz, gTypefaceDelegateMethods, numMethods); for (int i = 0; i < numMethods; i++) { free((char*)gTypefaceDelegateMethods[i].name); } return result; } jclass clazz = env->FindClass(className); return env->RegisterNatives(clazz, gMethods, numMethods); return jniRegisterNativeMethods(env, className, gMethods, numMethods); } JNIEnv* AndroidRuntime::getJNIEnv() { Loading Loading @@ -164,6 +200,125 @@ static vector<string> parseCsv(JNIEnv* env, jstring csvJString) { return result; } void LayoutlibLogger(base::LogId, base::LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* message) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jint logPrio = severity; jstring tagString = env->NewStringUTF(tag); jstring messageString = env->NewStringUTF(message); jobject bridgeLog = env->CallStaticObjectMethod(bridge, getLogId); env->CallVoidMethod(bridgeLog, logMethodId, logPrio, tagString, messageString); env->DeleteLocalRef(tagString); env->DeleteLocalRef(messageString); env->DeleteLocalRef(bridgeLog); } void LayoutlibAborter(const char* abort_message) { // Layoutlib should not call abort() as it would terminate Studio. // Throw an exception back to Java instead. JNIEnv* env = AndroidRuntime::getJNIEnv(); jniThrowRuntimeException(env, "The Android framework has encountered a fatal error"); } // This method has been copied/adapted from system/core/init/property_service.cpp // If the ro.product.cpu.abilist* properties have not been explicitly // set, derive them from ro.system.product.cpu.abilist* properties. static void property_initialize_ro_cpu_abilist() { const std::string EMPTY = ""; const char* kAbilistProp = "ro.product.cpu.abilist"; const char* kAbilist32Prop = "ro.product.cpu.abilist32"; const char* kAbilist64Prop = "ro.product.cpu.abilist64"; // If the properties are defined explicitly, just use them. if (base::GetProperty(kAbilistProp, EMPTY) != EMPTY) { return; } std::string abilist32_prop_val; std::string abilist64_prop_val; const auto abilist32_prop = "ro.system.product.cpu.abilist32"; const auto abilist64_prop = "ro.system.product.cpu.abilist64"; abilist32_prop_val = base::GetProperty(abilist32_prop, EMPTY); abilist64_prop_val = base::GetProperty(abilist64_prop, EMPTY); // Merge ABI lists for ro.product.cpu.abilist auto abilist_prop_val = abilist64_prop_val; if (abilist32_prop_val != EMPTY) { if (abilist_prop_val != EMPTY) { abilist_prop_val += ","; } abilist_prop_val += abilist32_prop_val; } // Set these properties const std::pair<const char*, const std::string&> set_prop_list[] = { {kAbilistProp, abilist_prop_val}, {kAbilist32Prop, abilist32_prop_val}, {kAbilist64Prop, abilist64_prop_val}, }; for (const auto& [prop, prop_val] : set_prop_list) { base::SetProperty(prop, prop_val); } } static void* mmapFile(const char* dataFilePath) { #ifdef _WIN32 // Windows needs file path in wide chars to handle unicode file paths int size = MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, NULL, 0); std::vector<wchar_t> wideDataFilePath(size); MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, wideDataFilePath.data(), size); HANDLE file = CreateFileW(wideDataFilePath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); if ((HANDLE)INVALID_HANDLE_VALUE == file) { return nullptr; } struct CloseHandleWrapper { void operator()(HANDLE h) { CloseHandle(h); } }; std::unique_ptr<void, CloseHandleWrapper> mmapHandle( CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr)); if (!mmapHandle) { return nullptr; } return MapViewOfFile(mmapHandle.get(), FILE_MAP_READ, 0, 0, 0); #else int fd = open(dataFilePath, O_RDONLY); if (fd == -1) { return nullptr; } struct stat sb; if (fstat(fd, &sb) == -1) { close(fd); return nullptr; } void* addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { close(fd); return nullptr; } close(fd); return addr; #endif } static bool init_icu(const char* dataPath) { void* addr = mmapFile(dataPath); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(addr, &err); if (err != U_ZERO_ERROR) { return false; } return true; } } // namespace android using namespace android; Loading @@ -175,37 +330,82 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_ERR; } init_android_graphics(); // Configuration is stored as java System properties. // Get a reference to System.getProperty jclass system = FindClassOrDie(env, "java/lang/System"); jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); // Get the names of classes that have to delegate their native methods auto delegateNativesToNativesString = (jstring) env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("delegate_natives_to_natives"), env->NewStringUTF("")); classesToDelegate = parseCsv(env, delegateNativesToNativesString); // Get the names of classes that need to register their native methods auto nativesClassesJString = (jstring) env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("native_classes"), (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("core_native_classes"), env->NewStringUTF("")); vector<string> classesToRegister = parseCsv(env, nativesClassesJString); jstring registerProperty = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF( "register_properties_during_load"), env->NewStringUTF("")); const char* registerPropertyString = env->GetStringUTFChars(registerProperty, 0); if (strcmp(registerPropertyString, "true") == 0) { // Set the system properties first as they could be used in the static initialization of // other classes if (register_android_os_SystemProperties(env) < 0) { return JNI_ERR; } classesToRegister.erase(find(classesToRegister.begin(), classesToRegister.end(), "android.os.SystemProperties")); bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge"); bridge = MakeGlobalRefOrDie(env, bridge); jmethodID setSystemPropertiesMethod = GetStaticMethodIDOrDie(env, bridge, "setSystemProperties", "()V"); env->CallStaticVoidMethod(bridge, setSystemPropertiesMethod); property_initialize_ro_cpu_abilist(); } env->ReleaseStringUTFChars(registerProperty, registerPropertyString); if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) { return JNI_ERR; } // Set the location of ICU data auto stringPath = (jstring) env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("icu.dir"), auto stringPath = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("icu.data.path"), env->NewStringUTF("")); const char* path = env->GetStringUTFChars(stringPath, 0); u_setDataDirectory(path); bool icuInitialized = init_icu(path); env->ReleaseStringUTFChars(stringPath, path); if (!icuInitialized) { return JNI_ERR; } jstring useJniProperty = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod, env->NewStringUTF("use_bridge_for_logging"), env->NewStringUTF("")); const char* useJniString = env->GetStringUTFChars(useJniProperty, 0); if (strcmp(useJniString, "true") == 0) { layoutLog = FindClassOrDie(env, "com/android/ide/common/rendering/api/ILayoutLog"); layoutLog = MakeGlobalRefOrDie(env, layoutLog); logMethodId = GetMethodIDOrDie(env, layoutLog, "logAndroidFramework", "(ILjava/lang/String;Ljava/lang/String;)V"); if (bridge == nullptr) { bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge"); bridge = MakeGlobalRefOrDie(env, bridge); } getLogId = GetStaticMethodIDOrDie(env, bridge, "getLog", "()Lcom/android/ide/common/rendering/api/ILayoutLog;"); android::base::SetLogger(LayoutlibLogger); android::base::SetAborter(LayoutlibAborter); } else { // initialize logging, so ANDROD_LOG_TAGS env variable is respected android::base::InitLogging(nullptr, android::base::StderrLogger); } env->ReleaseStringUTFChars(useJniProperty, useJniString); // Use English locale for number format to ensure correct parsing of floats when using strtof setlocale(LC_NUMERIC, "en_US.UTF-8"); Loading @@ -213,3 +413,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_VERSION_1_6; } JNIEXPORT void JNI_OnUnload(JavaVM* vm, void*) { JNIEnv* env = nullptr; vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); env->DeleteGlobalRef(bridge); env->DeleteGlobalRef(layoutLog); }