1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "jni.h" 18 #include "core_jni_helpers.h" 19 20 #include <unicode/putil.h> 21 #include <clocale> 22 #include <sstream> 23 #include <unordered_map> 24 #include <vector> 25 26 using namespace std; 27 28 /* 29 * This is responsible for setting up the JNI environment for communication between 30 * the Java and native parts of layoutlib, including registering native methods. 31 * This is mostly achieved by copying the way it is done in the platform 32 * (see AndroidRuntime.cpp). 33 */ 34 35 static JavaVM* javaVM; 36 37 namespace android { 38 39 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); 40 extern int register_android_content_AssetManager(JNIEnv* env); 41 extern int register_android_content_StringBlock(JNIEnv* env); 42 extern int register_android_content_XmlBlock(JNIEnv* env); 43 extern int register_android_content_res_ApkAssets(JNIEnv* env); 44 extern int register_android_database_CursorWindow(JNIEnv* env); 45 extern int register_android_database_SQLiteConnection(JNIEnv* env); 46 extern int register_android_database_SQLiteGlobal(JNIEnv* env); 47 extern int register_android_database_SQLiteDebug(JNIEnv* env); 48 extern int register_android_os_FileObserver(JNIEnv* env); 49 extern int register_android_os_MessageQueue(JNIEnv* env); 50 extern int register_android_os_SystemClock(JNIEnv* env); 51 extern int register_android_os_SystemProperties(JNIEnv* env); 52 extern int register_android_os_Trace(JNIEnv* env); 53 extern int register_android_text_AndroidCharacter(JNIEnv* env); 54 extern int register_android_util_EventLog(JNIEnv* env); 55 extern int register_android_util_Log(JNIEnv* env); 56 extern int register_android_util_jar_StrictJarFile(JNIEnv* env); 57 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); 58 59 #define REG_JNI(name) { name } 60 struct RegJNIRec { 61 int (*mProc)(JNIEnv*); 62 }; 63 64 // Map of all possible class names to register to their corresponding JNI registration function pointer 65 // The actual list of registered classes will be determined at runtime via the 'native_classes' System property 66 static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = { 67 {"android.animation.PropertyValuesHolder", 68 REG_JNI(register_android_animation_PropertyValuesHolder)}, 69 #ifdef __linux__ 70 {"android.content.res.ApkAssets", REG_JNI(register_android_content_res_ApkAssets)}, 71 {"android.content.res.AssetManager", REG_JNI(register_android_content_AssetManager)}, 72 {"android.database.CursorWindow", REG_JNI(register_android_database_CursorWindow)}, 73 {"android.database.sqlite.SQLiteConnection", 74 REG_JNI(register_android_database_SQLiteConnection)}, 75 {"android.database.sqlite.SQLiteGlobal", REG_JNI(register_android_database_SQLiteGlobal)}, 76 {"android.database.sqlite.SQLiteDebug", REG_JNI(register_android_database_SQLiteDebug)}, 77 #endif 78 {"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)}, 79 {"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)}, 80 #ifdef __linux__ 81 {"android.os.FileObserver", REG_JNI(register_android_os_FileObserver)}, 82 {"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)}, 83 #endif 84 {"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)}, 85 {"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)}, 86 {"android.os.Trace", REG_JNI(register_android_os_Trace)}, 87 {"android.text.AndroidCharacter", REG_JNI(register_android_text_AndroidCharacter)}, 88 {"android.util.EventLog", REG_JNI(register_android_util_EventLog)}, 89 {"android.util.Log", REG_JNI(register_android_util_Log)}, 90 {"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)}, 91 {"com.android.internal.util.VirtualRefBasePtr", 92 REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)}, 93 }; 94 // Vector to store the names of classes that need delegates of their native methods 95 static vector<string> classesToDelegate; 96 97 static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& jniRegMap, 98 const vector<string>& classesToRegister, JNIEnv* env) { 99 100 for (const string& className : classesToRegister) { 101 if (jniRegMap.at(className).mProc(env) < 0) { 102 return -1; 103 } 104 } 105 return 0; 106 } 107 108 int AndroidRuntime::registerNativeMethods(JNIEnv* env, 109 const char* className, const JNINativeMethod* gMethods, int numMethods) { 110 string classNameString = string(className); 111 if (find(classesToDelegate.begin(), classesToDelegate.end(), classNameString) 112 != classesToDelegate.end()) { 113 // Register native methods to the delegate class <classNameString>_NativeDelegate 114 // by adding _Original to the name of each method. 115 replace(classNameString.begin(), classNameString.end(), '$', '_'); 116 string delegateClassName = classNameString + "_NativeDelegate"; 117 jclass clazz = env->FindClass(delegateClassName.c_str()); 118 JNINativeMethod gTypefaceDelegateMethods[numMethods]; 119 for (int i = 0; i < numMethods; i++) { 120 JNINativeMethod gTypefaceMethod = gMethods[i]; 121 string newName = string(gTypefaceMethod.name) + "_Original"; 122 gTypefaceDelegateMethods[i].name = strdup(newName.c_str()); 123 gTypefaceDelegateMethods[i].signature = gTypefaceMethod.signature; 124 gTypefaceDelegateMethods[i].fnPtr = gTypefaceMethod.fnPtr; 125 } 126 int result = env->RegisterNatives(clazz, gTypefaceDelegateMethods, numMethods); 127 for (int i = 0; i < numMethods; i++) { 128 free((char*)gTypefaceDelegateMethods[i].name); 129 } 130 return result; 131 } 132 133 jclass clazz = env->FindClass(className); 134 return env->RegisterNatives(clazz, gMethods, numMethods); 135 } 136 137 JNIEnv* AndroidRuntime::getJNIEnv() { 138 JNIEnv* env; 139 if (javaVM->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) 140 return nullptr; 141 return env; 142 } 143 144 JavaVM* AndroidRuntime::getJavaVM() { 145 return javaVM; 146 } 147 148 static vector<string> parseCsv(const string& csvString) { 149 vector<string> result; 150 istringstream stream(csvString); 151 string segment; 152 while(getline(stream, segment, ',')) 153 { 154 result.push_back(segment); 155 } 156 return result; 157 } 158 159 static vector<string> parseCsv(JNIEnv* env, jstring csvJString) { 160 const char* charArray = env->GetStringUTFChars(csvJString, 0); 161 string csvString(charArray); 162 vector<string> result = parseCsv(csvString); 163 env->ReleaseStringUTFChars(csvJString, charArray); 164 return result; 165 } 166 167 } // namespace android 168 169 using namespace android; 170 171 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { 172 javaVM = vm; 173 JNIEnv* env = nullptr; 174 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { 175 return JNI_ERR; 176 } 177 178 // Configuration is stored as java System properties. 179 // Get a reference to System.getProperty 180 jclass system = FindClassOrDie(env, "java/lang/System"); 181 jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty", 182 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 183 184 // Get the names of classes that have to delegate their native methods 185 auto delegateNativesToNativesString = 186 (jstring) env->CallStaticObjectMethod(system, 187 getPropertyMethod, env->NewStringUTF("delegate_natives_to_natives"), 188 env->NewStringUTF("")); 189 classesToDelegate = parseCsv(env, delegateNativesToNativesString); 190 191 // Get the names of classes that need to register their native methods 192 auto nativesClassesJString = 193 (jstring) env->CallStaticObjectMethod(system, 194 getPropertyMethod, env->NewStringUTF("native_classes"), 195 env->NewStringUTF("")); 196 vector<string> classesToRegister = parseCsv(env, nativesClassesJString); 197 198 if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) { 199 return JNI_ERR; 200 } 201 202 // Set the location of ICU data 203 auto stringPath = (jstring) env->CallStaticObjectMethod(system, 204 getPropertyMethod, env->NewStringUTF("icu.dir"), 205 env->NewStringUTF("")); 206 const char* path = env->GetStringUTFChars(stringPath, 0); 207 u_setDataDirectory(path); 208 env->ReleaseStringUTFChars(stringPath, path); 209 210 // Use English locale for number format to ensure correct parsing of floats when using strtof 211 setlocale(LC_NUMERIC, "en_US.UTF-8"); 212 213 return JNI_VERSION_1_6; 214 } 215 216