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