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 <android-base/logging.h>
18 #include <android-base/properties.h>
19 #include <android/graphics/jni_runtime.h>
20 #include <nativehelper/JNIHelp.h>
21 #include <nativehelper/jni_macros.h>
22 #include <unicode/putil.h>
23 #include <unicode/udata.h>
24 
25 #include <clocale>
26 #include <sstream>
27 #include <unordered_map>
28 #include <vector>
29 
30 #include "android_view_InputDevice.h"
31 #include "core_jni_helpers.h"
32 #include "jni.h"
33 #ifdef _WIN32
34 #include <windows.h>
35 #else
36 #include <fcntl.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #endif
40 
41 #include <iostream>
42 
43 using namespace std;
44 
45 /*
46  * This is responsible for setting up the JNI environment for communication between
47  * the Java and native parts of layoutlib, including registering native methods.
48  * This is mostly achieved by copying the way it is done in the platform
49  * (see AndroidRuntime.cpp).
50  */
51 
52 static JavaVM* javaVM;
53 static jclass bridge;
54 static jclass layoutLog;
55 static jmethodID getLogId;
56 static jmethodID logMethodId;
57 
58 extern int register_android_os_Binder(JNIEnv* env);
59 extern int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env);
60 
61 typedef void (*FreeFunction)(void*);
62 
NativeAllocationRegistry_Delegate_nativeApplyFreeFunction(JNIEnv *,jclass,jlong freeFunction,jlong ptr)63 static void NativeAllocationRegistry_Delegate_nativeApplyFreeFunction(JNIEnv*, jclass,
64                                                                       jlong freeFunction,
65                                                                       jlong ptr) {
66     void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr));
67     FreeFunction nativeFreeFunction =
68             reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction));
69     nativeFreeFunction(nativePtr);
70 }
71 
72 static JNINativeMethod gMethods[] = {
73         NATIVE_METHOD(NativeAllocationRegistry_Delegate, nativeApplyFreeFunction, "(JJ)V"),
74 };
75 
register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv * env)76 int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env) {
77     return jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry_Delegate", gMethods,
78                                     NELEM(gMethods));
79 }
80 
81 namespace android {
82 
83 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
84 extern int register_android_content_AssetManager(JNIEnv* env);
85 extern int register_android_content_StringBlock(JNIEnv* env);
86 extern int register_android_content_XmlBlock(JNIEnv* env);
87 extern int register_android_content_res_ApkAssets(JNIEnv* env);
88 extern int register_android_database_CursorWindow(JNIEnv* env);
89 extern int register_android_database_SQLiteConnection(JNIEnv* env);
90 extern int register_android_database_SQLiteGlobal(JNIEnv* env);
91 extern int register_android_database_SQLiteDebug(JNIEnv* env);
92 extern int register_android_os_FileObserver(JNIEnv* env);
93 extern int register_android_os_MessageQueue(JNIEnv* env);
94 extern int register_android_os_Parcel(JNIEnv* env);
95 extern int register_android_os_SystemClock(JNIEnv* env);
96 extern int register_android_os_SystemProperties(JNIEnv* env);
97 extern int register_android_os_Trace(JNIEnv* env);
98 extern int register_android_text_AndroidCharacter(JNIEnv* env);
99 extern int register_android_util_EventLog(JNIEnv* env);
100 extern int register_android_util_Log(JNIEnv* env);
101 extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
102 extern int register_android_view_KeyCharacterMap(JNIEnv* env);
103 extern int register_android_view_KeyEvent(JNIEnv* env);
104 extern int register_android_view_InputDevice(JNIEnv* env);
105 extern int register_android_view_MotionEvent(JNIEnv* env);
106 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
107 extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env);
108 extern int register_android_view_VelocityTracker(JNIEnv* env);
109 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
110 
111 #define REG_JNI(name)      { name }
112 struct RegJNIRec {
113     int (*mProc)(JNIEnv*);
114 };
115 
116 // Map of all possible class names to register to their corresponding JNI registration function pointer
117 // The actual list of registered classes will be determined at runtime via the 'native_classes' System property
118 static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
119         {"android.animation.PropertyValuesHolder",
120          REG_JNI(register_android_animation_PropertyValuesHolder)},
121 #ifdef __linux__
122         {"android.content.res.ApkAssets", REG_JNI(register_android_content_res_ApkAssets)},
123         {"android.content.res.AssetManager", REG_JNI(register_android_content_AssetManager)},
124         {"android.database.CursorWindow", REG_JNI(register_android_database_CursorWindow)},
125         {"android.database.sqlite.SQLiteConnection",
126          REG_JNI(register_android_database_SQLiteConnection)},
127         {"android.database.sqlite.SQLiteGlobal", REG_JNI(register_android_database_SQLiteGlobal)},
128         {"android.database.sqlite.SQLiteDebug", REG_JNI(register_android_database_SQLiteDebug)},
129 #endif
130         {"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)},
131         {"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
132 #ifdef __linux__
133         {"android.os.Binder", REG_JNI(register_android_os_Binder)},
134         {"android.os.FileObserver", REG_JNI(register_android_os_FileObserver)},
135         {"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)},
136         {"android.os.Parcel", REG_JNI(register_android_os_Parcel)},
137 #endif
138         {"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)},
139         {"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)},
140         {"android.os.Trace", REG_JNI(register_android_os_Trace)},
141         {"android.text.AndroidCharacter", REG_JNI(register_android_text_AndroidCharacter)},
142         {"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
143         {"android.util.Log", REG_JNI(register_android_util_Log)},
144         {"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)},
145         {"android.view.KeyCharacterMap", REG_JNI(register_android_view_KeyCharacterMap)},
146         {"android.view.KeyEvent", REG_JNI(register_android_view_KeyEvent)},
147         {"android.view.InputDevice", REG_JNI(register_android_view_InputDevice)},
148         {"android.view.MotionEvent", REG_JNI(register_android_view_MotionEvent)},
149         {"android.view.VelocityTracker", REG_JNI(register_android_view_VelocityTracker)},
150         {"com.android.internal.util.VirtualRefBasePtr",
151          REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)},
152         {"libcore.util.NativeAllocationRegistry_Delegate",
153          REG_JNI(register_libcore_util_NativeAllocationRegistry_Delegate)},
154 };
155 
register_jni_procs(const std::unordered_map<std::string,RegJNIRec> & jniRegMap,const vector<string> & classesToRegister,JNIEnv * env)156 static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& jniRegMap,
157         const vector<string>& classesToRegister, JNIEnv* env) {
158 
159     for (const string& className : classesToRegister) {
160         if (jniRegMap.at(className).mProc(env) < 0) {
161             return -1;
162         }
163     }
164 
165     if (register_android_graphics_classes(env) < 0) {
166         return -1;
167     }
168 
169     return 0;
170 }
171 
registerNativeMethods(JNIEnv * env,const char * className,const JNINativeMethod * gMethods,int numMethods)172 int AndroidRuntime::registerNativeMethods(JNIEnv* env,
173         const char* className, const JNINativeMethod* gMethods, int numMethods) {
174     return jniRegisterNativeMethods(env, className, gMethods, numMethods);
175 }
176 
getJNIEnv()177 JNIEnv* AndroidRuntime::getJNIEnv() {
178     JNIEnv* env;
179     if (javaVM->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK)
180         return nullptr;
181     return env;
182 }
183 
getJavaVM()184 JavaVM* AndroidRuntime::getJavaVM() {
185     return javaVM;
186 }
187 
parseCsv(const string & csvString)188 static vector<string> parseCsv(const string& csvString) {
189     vector<string>   result;
190     istringstream stream(csvString);
191     string segment;
192     while(getline(stream, segment, ','))
193     {
194         result.push_back(segment);
195     }
196     return result;
197 }
198 
parseCsv(JNIEnv * env,jstring csvJString)199 static vector<string> parseCsv(JNIEnv* env, jstring csvJString) {
200     const char* charArray = env->GetStringUTFChars(csvJString, 0);
201     string csvString(charArray);
202     vector<string> result = parseCsv(csvString);
203     env->ReleaseStringUTFChars(csvJString, charArray);
204     return result;
205 }
206 
LayoutlibLogger(base::LogId,base::LogSeverity severity,const char * tag,const char * file,unsigned int line,const char * message)207 void LayoutlibLogger(base::LogId, base::LogSeverity severity, const char* tag, const char* file,
208                      unsigned int line, const char* message) {
209     JNIEnv* env = AndroidRuntime::getJNIEnv();
210     jint logPrio = severity;
211     jstring tagString = env->NewStringUTF(tag);
212     jstring messageString = env->NewStringUTF(message);
213 
214     jobject bridgeLog = env->CallStaticObjectMethod(bridge, getLogId);
215 
216     env->CallVoidMethod(bridgeLog, logMethodId, logPrio, tagString, messageString);
217 
218     env->DeleteLocalRef(tagString);
219     env->DeleteLocalRef(messageString);
220     env->DeleteLocalRef(bridgeLog);
221 }
222 
LayoutlibAborter(const char * abort_message)223 void LayoutlibAborter(const char* abort_message) {
224     // Layoutlib should not call abort() as it would terminate Studio.
225     // Throw an exception back to Java instead.
226     JNIEnv* env = AndroidRuntime::getJNIEnv();
227     jniThrowRuntimeException(env, "The Android framework has encountered a fatal error");
228 }
229 
230 // This method has been copied/adapted from system/core/init/property_service.cpp
231 // If the ro.product.cpu.abilist* properties have not been explicitly
232 // set, derive them from ro.system.product.cpu.abilist* properties.
property_initialize_ro_cpu_abilist()233 static void property_initialize_ro_cpu_abilist() {
234     const std::string EMPTY = "";
235     const char* kAbilistProp = "ro.product.cpu.abilist";
236     const char* kAbilist32Prop = "ro.product.cpu.abilist32";
237     const char* kAbilist64Prop = "ro.product.cpu.abilist64";
238 
239     // If the properties are defined explicitly, just use them.
240     if (base::GetProperty(kAbilistProp, EMPTY) != EMPTY) {
241         return;
242     }
243 
244     std::string abilist32_prop_val;
245     std::string abilist64_prop_val;
246     const auto abilist32_prop = "ro.system.product.cpu.abilist32";
247     const auto abilist64_prop = "ro.system.product.cpu.abilist64";
248     abilist32_prop_val = base::GetProperty(abilist32_prop, EMPTY);
249     abilist64_prop_val = base::GetProperty(abilist64_prop, EMPTY);
250 
251     // Merge ABI lists for ro.product.cpu.abilist
252     auto abilist_prop_val = abilist64_prop_val;
253     if (abilist32_prop_val != EMPTY) {
254         if (abilist_prop_val != EMPTY) {
255             abilist_prop_val += ",";
256         }
257         abilist_prop_val += abilist32_prop_val;
258     }
259 
260     // Set these properties
261     const std::pair<const char*, const std::string&> set_prop_list[] = {
262             {kAbilistProp, abilist_prop_val},
263             {kAbilist32Prop, abilist32_prop_val},
264             {kAbilist64Prop, abilist64_prop_val},
265     };
266     for (const auto& [prop, prop_val] : set_prop_list) {
267         base::SetProperty(prop, prop_val);
268     }
269 }
270 
mmapFile(const char * dataFilePath)271 static void* mmapFile(const char* dataFilePath) {
272 #ifdef _WIN32
273     // Windows needs file path in wide chars to handle unicode file paths
274     int size = MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, NULL, 0);
275     std::vector<wchar_t> wideDataFilePath(size);
276     MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, wideDataFilePath.data(), size);
277     HANDLE file =
278             CreateFileW(wideDataFilePath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr,
279                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
280     if ((HANDLE)INVALID_HANDLE_VALUE == file) {
281         return nullptr;
282     }
283 
284     struct CloseHandleWrapper {
285         void operator()(HANDLE h) { CloseHandle(h); }
286     };
287     std::unique_ptr<void, CloseHandleWrapper> mmapHandle(
288             CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
289     if (!mmapHandle) {
290         return nullptr;
291     }
292     return MapViewOfFile(mmapHandle.get(), FILE_MAP_READ, 0, 0, 0);
293 #else
294     int fd = open(dataFilePath, O_RDONLY);
295     if (fd == -1) {
296         return nullptr;
297     }
298 
299     struct stat sb;
300     if (fstat(fd, &sb) == -1) {
301         close(fd);
302         return nullptr;
303     }
304 
305     void* addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
306     if (addr == MAP_FAILED) {
307         close(fd);
308         return nullptr;
309     }
310 
311     close(fd);
312     return addr;
313 #endif
314 }
315 
init_icu(const char * dataPath)316 static bool init_icu(const char* dataPath) {
317     void* addr = mmapFile(dataPath);
318     UErrorCode err = U_ZERO_ERROR;
319     udata_setCommonData(addr, &err);
320     if (err != U_ZERO_ERROR) {
321         return false;
322     }
323     return true;
324 }
325 
326 // Creates an array of InputDevice from key character map files
init_keyboard(JNIEnv * env,const vector<string> & keyboardPaths)327 static void init_keyboard(JNIEnv* env, const vector<string>& keyboardPaths) {
328     jclass inputDevice = FindClassOrDie(env, "android/view/InputDevice");
329     jobjectArray inputDevicesArray =
330             env->NewObjectArray(keyboardPaths.size(), inputDevice, nullptr);
331     int keyboardId = 1;
332 
333     for (const string& path : keyboardPaths) {
334         base::Result<std::shared_ptr<KeyCharacterMap>> charMap =
335                 KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
336 
337         InputDeviceInfo info = InputDeviceInfo();
338         info.initialize(keyboardId, 0, 0, InputDeviceIdentifier(),
339                         "keyboard " + std::to_string(keyboardId), true, false, 0);
340         info.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
341         info.setKeyCharacterMap(*charMap);
342 
343         jobject inputDeviceObj = android_view_InputDevice_create(env, info);
344         if (inputDeviceObj) {
345             env->SetObjectArrayElement(inputDevicesArray, keyboardId - 1, inputDeviceObj);
346             env->DeleteLocalRef(inputDeviceObj);
347         }
348         keyboardId++;
349     }
350 
351     if (bridge == nullptr) {
352         bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
353         bridge = MakeGlobalRefOrDie(env, bridge);
354     }
355     jmethodID setInputManager = GetStaticMethodIDOrDie(env, bridge, "setInputManager",
356                                                        "([Landroid/view/InputDevice;)V");
357     env->CallStaticVoidMethod(bridge, setInputManager, inputDevicesArray);
358     env->DeleteLocalRef(inputDevicesArray);
359 }
360 
361 } // namespace android
362 
363 using namespace android;
364 
JNI_OnLoad(JavaVM * vm,void *)365 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
366     javaVM = vm;
367     JNIEnv* env = nullptr;
368     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
369         return JNI_ERR;
370     }
371 
372     init_android_graphics();
373 
374     // Configuration is stored as java System properties.
375     // Get a reference to System.getProperty
376     jclass system = FindClassOrDie(env, "java/lang/System");
377     jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty",
378                                                          "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
379 
380     // Get the names of classes that need to register their native methods
381     auto nativesClassesJString =
382             (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
383                                                  env->NewStringUTF("core_native_classes"),
384                                                  env->NewStringUTF(""));
385     vector<string> classesToRegister = parseCsv(env, nativesClassesJString);
386 
387     jstring registerProperty =
388             (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
389                                                  env->NewStringUTF(
390                                                          "register_properties_during_load"),
391                                                  env->NewStringUTF(""));
392     const char* registerPropertyString = env->GetStringUTFChars(registerProperty, 0);
393     if (strcmp(registerPropertyString, "true") == 0) {
394         // Set the system properties first as they could be used in the static initialization of
395         // other classes
396         if (register_android_os_SystemProperties(env) < 0) {
397             return JNI_ERR;
398         }
399         classesToRegister.erase(find(classesToRegister.begin(), classesToRegister.end(),
400                                      "android.os.SystemProperties"));
401         bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
402         bridge = MakeGlobalRefOrDie(env, bridge);
403         jmethodID setSystemPropertiesMethod =
404                 GetStaticMethodIDOrDie(env, bridge, "setSystemProperties", "()V");
405         env->CallStaticVoidMethod(bridge, setSystemPropertiesMethod);
406         property_initialize_ro_cpu_abilist();
407     }
408     env->ReleaseStringUTFChars(registerProperty, registerPropertyString);
409 
410     if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
411         return JNI_ERR;
412     }
413 
414     // Set the location of ICU data
415     auto stringPath = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
416                                                            env->NewStringUTF("icu.data.path"),
417                                                            env->NewStringUTF(""));
418     const char* path = env->GetStringUTFChars(stringPath, 0);
419     bool icuInitialized = init_icu(path);
420     env->ReleaseStringUTFChars(stringPath, path);
421     if (!icuInitialized) {
422         return JNI_ERR;
423     }
424 
425     jstring useJniProperty =
426             (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
427                                                  env->NewStringUTF("use_bridge_for_logging"),
428                                                  env->NewStringUTF(""));
429     const char* useJniString = env->GetStringUTFChars(useJniProperty, 0);
430     if (strcmp(useJniString, "true") == 0) {
431         layoutLog = FindClassOrDie(env, "com/android/ide/common/rendering/api/ILayoutLog");
432         layoutLog = MakeGlobalRefOrDie(env, layoutLog);
433         logMethodId = GetMethodIDOrDie(env, layoutLog, "logAndroidFramework",
434                                        "(ILjava/lang/String;Ljava/lang/String;)V");
435         if (bridge == nullptr) {
436             bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
437             bridge = MakeGlobalRefOrDie(env, bridge);
438         }
439         getLogId = GetStaticMethodIDOrDie(env, bridge, "getLog",
440                                           "()Lcom/android/ide/common/rendering/api/ILayoutLog;");
441         android::base::SetLogger(LayoutlibLogger);
442         android::base::SetAborter(LayoutlibAborter);
443     } else {
444         // initialize logging, so ANDROD_LOG_TAGS env variable is respected
445         android::base::InitLogging(nullptr, android::base::StderrLogger);
446     }
447     env->ReleaseStringUTFChars(useJniProperty, useJniString);
448 
449     // Use English locale for number format to ensure correct parsing of floats when using strtof
450     setlocale(LC_NUMERIC, "en_US.UTF-8");
451 
452     auto keyboardPathsString =
453             (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
454                                                  env->NewStringUTF("keyboard_paths"),
455                                                  env->NewStringUTF(""));
456     vector<string> keyboardPaths = parseCsv(env, keyboardPathsString);
457     init_keyboard(env, keyboardPaths);
458 
459     return JNI_VERSION_1_6;
460 }
461 
JNI_OnUnload(JavaVM * vm,void *)462 JNIEXPORT void JNI_OnUnload(JavaVM* vm, void*) {
463     JNIEnv* env = nullptr;
464     vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
465     env->DeleteGlobalRef(bridge);
466     env->DeleteGlobalRef(layoutLog);
467 }
468