OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This is the Android-specific Chromium linker, a tiny shared library | 5 // This is the Android-specific Chromium linker, a tiny shared library |
6 // implementing a custom dynamic linker that can be used to load the | 6 // implementing a custom dynamic linker that can be used to load the |
7 // real Chromium libraries (e.g. libcontentshell.so). | 7 // real Chromium libraries (e.g. libcontentshell.so). |
8 | 8 |
9 // The main point of this linker is to be able to share the RELRO | 9 // The main point of this linker is to be able to share the RELRO |
10 // section of libcontentshell.so (or equivalent) between the browser and | 10 // section of libcontentshell.so (or equivalent) between the browser and |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 | 64 |
65 // Note: the result contains Java "modified UTF-8" bytes. | 65 // Note: the result contains Java "modified UTF-8" bytes. |
66 // Good enough for the linker though. | 66 // Good enough for the linker though. |
67 const char* bytes = env->GetStringUTFChars(str, NULL); | 67 const char* bytes = env->GetStringUTFChars(str, NULL); |
68 ::memcpy(ptr_, bytes, size_); | 68 ::memcpy(ptr_, bytes, size_); |
69 ptr_[size_] = '\0'; | 69 ptr_[size_] = '\0'; |
70 | 70 |
71 env->ReleaseStringUTFChars(str, bytes); | 71 env->ReleaseStringUTFChars(str, bytes); |
72 } | 72 } |
73 | 73 |
74 // A scoped crazy_library_t that automatically closes the handle | |
75 // on scope exit, unless Release() has been called. | |
76 class ScopedLibrary { | |
77 public: | |
78 ScopedLibrary() : lib_(NULL) {} | |
79 | |
80 ~ScopedLibrary() { | |
81 if (lib_) | |
82 crazy_library_close(lib_); | |
83 } | |
84 | |
85 crazy_library_t* Get() { return lib_; } | |
86 | |
87 crazy_library_t** GetPtr() { return &lib_; } | |
88 | |
89 crazy_library_t* Release() { | |
90 crazy_library_t* ret = lib_; | |
91 lib_ = NULL; | |
92 return ret; | |
93 } | |
94 | |
95 private: | |
96 crazy_library_t* lib_; | |
97 }; | |
98 | |
99 // Return a pointer to the base name from an input |path| string. | 74 // Return a pointer to the base name from an input |path| string. |
100 const char* GetBaseNamePtr(const char* path) { | 75 const char* GetBaseNamePtr(const char* path) { |
101 const char* p = strrchr(path, '/'); | 76 const char* p = strrchr(path, '/'); |
102 if (p) | 77 if (p) |
103 return p + 1; | 78 return p + 1; |
104 return path; | 79 return path; |
105 } | 80 } |
106 | 81 |
107 // Return true iff |address| is a valid address for the target CPU. | 82 // Return true iff |address| is a valid address for the target CPU. |
108 bool IsValidAddress(jlong address) { | 83 bool IsValidAddress(jlong address) { |
(...skipping 24 matching lines...) Expand all Loading... | |
133 *field_id = env->GetFieldID(clazz, field_name, field_sig); | 108 *field_id = env->GetFieldID(clazz, field_name, field_sig); |
134 if (!*field_id) { | 109 if (!*field_id) { |
135 LOG_ERROR("Could not find ID for field '%s'", field_name); | 110 LOG_ERROR("Could not find ID for field '%s'", field_name); |
136 return false; | 111 return false; |
137 } | 112 } |
138 LOG_INFO( | 113 LOG_INFO( |
139 "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name); | 114 "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name); |
140 return true; | 115 return true; |
141 } | 116 } |
142 | 117 |
118 // Initialize a jmethodID corresponding to the static method of a given | |
119 // |clazz|, with name |method_name| and signature |method_sig|. | |
120 // |env| is the current JNI environment handle. | |
121 // On success, return true and set |*method_id|. | |
122 bool InitStaticMethodId(JNIEnv* env, | |
123 jclass clazz, | |
124 const char* method_name, | |
125 const char* method_sig, | |
126 jmethodID* method_id) { | |
127 *method_id = env->GetStaticMethodID(clazz, method_name, method_sig); | |
128 if (!*method_id) { | |
129 LOG_ERROR("Could not find ID for static method '%s'", method_name); | |
130 return false; | |
131 } | |
132 LOG_INFO("%s: Found ID %p for static method '%s'", | |
133 __FUNCTION__, *method_id, method_name); | |
134 return true; | |
135 } | |
136 | |
143 // A class used to model the field IDs of the org.chromium.base.Linker | 137 // A class used to model the field IDs of the org.chromium.base.Linker |
144 // LibInfo inner class, used to communicate data with the Java side | 138 // LibInfo inner class, used to communicate data with the Java side |
145 // of the linker. | 139 // of the linker. |
146 struct LibInfo_class { | 140 struct LibInfo_class { |
147 jfieldID load_address_id; | 141 jfieldID load_address_id; |
148 jfieldID load_size_id; | 142 jfieldID load_size_id; |
149 jfieldID relro_start_id; | 143 jfieldID relro_start_id; |
150 jfieldID relro_size_id; | 144 jfieldID relro_size_id; |
151 jfieldID relro_fd_id; | 145 jfieldID relro_fd_id; |
152 | 146 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
214 | 208 |
215 // Ensure libraries located in the same directory as the linker | 209 // Ensure libraries located in the same directory as the linker |
216 // can be loaded before system ones. | 210 // can be loaded before system ones. |
217 crazy_context_add_search_path_for_address( | 211 crazy_context_add_search_path_for_address( |
218 s_crazy_context, reinterpret_cast<void*>(&s_crazy_context)); | 212 s_crazy_context, reinterpret_cast<void*>(&s_crazy_context)); |
219 } | 213 } |
220 | 214 |
221 return s_crazy_context; | 215 return s_crazy_context; |
222 } | 216 } |
223 | 217 |
218 // A scoped crazy_library_t that automatically closes the handle | |
219 // on scope exit, unless Release() has been called. | |
220 class ScopedLibrary { | |
221 public: | |
222 ScopedLibrary() : lib_(NULL) {} | |
223 | |
224 ~ScopedLibrary() { | |
225 if (lib_) | |
226 crazy_library_close_with_context(lib_, GetCrazyContext()); | |
227 } | |
228 | |
229 crazy_library_t* Get() { return lib_; } | |
230 | |
231 crazy_library_t** GetPtr() { return &lib_; } | |
232 | |
233 crazy_library_t* Release() { | |
234 crazy_library_t* ret = lib_; | |
235 lib_ = NULL; | |
236 return ret; | |
237 } | |
238 | |
239 private: | |
240 crazy_library_t* lib_; | |
241 }; | |
242 | |
224 // Load a library with the chromium linker. This will also call its | 243 // Load a library with the chromium linker. This will also call its |
225 // JNI_OnLoad() method, which shall register its methods. Note that | 244 // JNI_OnLoad() method, which shall register its methods. Note that |
226 // lazy native method resolution will _not_ work after this, because | 245 // lazy native method resolution will _not_ work after this, because |
227 // Dalvik uses the system's dlsym() which won't see the new library, | 246 // Dalvik uses the system's dlsym() which won't see the new library, |
228 // so explicit registration is mandatory. | 247 // so explicit registration is mandatory. |
229 // |env| is the current JNI environment handle. | 248 // |env| is the current JNI environment handle. |
230 // |clazz| is the static class handle for org.chromium.base.Linker, | 249 // |clazz| is the static class handle for org.chromium.base.Linker, |
231 // and is ignored here. | 250 // and is ignored here. |
232 // |library_name| is the library name (e.g. libfoo.so). | 251 // |library_name| is the library name (e.g. libfoo.so). |
233 // |load_address| is an explicit load address. | 252 // |load_address| is an explicit load address. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 | 294 |
276 // Release library object to keep it alive after the function returns. | 295 // Release library object to keep it alive after the function returns. |
277 library.Release(); | 296 library.Release(); |
278 | 297 |
279 s_lib_info_fields.SetLoadInfo( | 298 s_lib_info_fields.SetLoadInfo( |
280 env, lib_info_obj, info.load_address, info.load_size); | 299 env, lib_info_obj, info.load_address, info.load_size); |
281 LOG_INFO("%s: Success loading library %s", __FUNCTION__, lib_basename); | 300 LOG_INFO("%s: Success loading library %s", __FUNCTION__, lib_basename); |
282 return true; | 301 return true; |
283 } | 302 } |
284 | 303 |
304 // Class holding the Java class and method ID for the Java side Linker | |
305 // postCallbackOnMainThread method. | |
306 struct CallbackRefs_class { | |
bulach
2014/05/07 16:10:53
nit: the name should be CallbackRefsClass. however
simonb1
2014/05/07 17:25:24
Done.
| |
307 jclass clazz; | |
308 jmethodID method_id; | |
309 | |
310 // Initialize an instance. | |
311 bool Init(JNIEnv* env, jclass linker_class) { | |
312 clazz = linker_class; | |
bulach
2014/05/07 16:10:53
nit: theoretically linker_class is a "localref" th
simonb1
2014/05/07 17:25:24
Done.
| |
313 return InitStaticMethodId(env, | |
314 linker_class, | |
315 "postCallbackOnMainThread", | |
316 "(J)V", | |
317 &method_id); | |
318 } | |
319 }; | |
320 | |
321 static CallbackRefs_class s_callback_refs; | |
322 | |
323 // Designated receiver function for callbacks from Java. Its name is known | |
324 // to the Java side. | |
325 // |env| is the current JNI environment handle and is ignored here. | |
326 // |clazz| is the static class handle for org.chromium.base.Linker, | |
327 // and is ignored here. | |
328 // |arg| is a pointer to an allocated crazy_callback_t, deleted after use. | |
329 void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) { | |
330 crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg); | |
331 | |
332 LOG_INFO("%s: Called back from java with handler %p, opaque %p", | |
333 __FUNCTION__, callback->handler, callback->opaque); | |
334 | |
335 crazy_callback_run(callback); | |
336 delete callback; | |
337 } | |
338 | |
339 // Request a callback from Java. The supplied crazy_callback_t is valid only | |
340 // for the duration of this call, so we copy it to a newly allocated | |
341 // crazy_callback_t and then call the Java side's postCallbackOnMainThread. | |
342 // This will call back to to our RunCallbackOnUiThread some time | |
343 // later on the UI thread. | |
344 // |callback_request| is a crazy_callback_t. | |
345 // |poster_opaque| is unused. | |
346 // Returns true if the callback request succeeds. | |
347 static bool PostForLaterExecution(crazy_callback_t* callback_request, | |
348 void* poster_opaque UNUSED) { | |
349 crazy_context_t* context = GetCrazyContext(); | |
350 | |
351 JavaVM* vm; | |
352 int minimum_jni_version; | |
353 crazy_context_get_java_vm(context, | |
354 reinterpret_cast<void**>(&vm), | |
355 &minimum_jni_version); | |
356 | |
357 // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own. | |
358 JNIEnv* env; | |
359 if (JNI_OK != vm->GetEnv( | |
360 reinterpret_cast<void**>(&env), minimum_jni_version)) { | |
361 LOG_ERROR("Could not create JNIEnv"); | |
362 return false; | |
363 } | |
364 | |
365 // Copy the callback; the one passed as an argument may be temporary. | |
366 crazy_callback_t* callback = new crazy_callback_t(); | |
367 *callback = *callback_request; | |
368 | |
369 LOG_INFO("%s: Calling back to java with handler %p, opaque %p", | |
370 __FUNCTION__, callback->handler, callback->opaque); | |
371 | |
372 jlong arg = static_cast<jlong>(reinterpret_cast<intptr_t>(callback)); | |
373 env->CallStaticVoidMethod( | |
374 s_callback_refs.clazz, s_callback_refs.method_id, arg); | |
375 | |
376 // Back out and return false if we encounter a JNI exception. | |
377 if (env->ExceptionCheck() == JNI_TRUE) { | |
378 env->ExceptionDescribe(); | |
379 env->ExceptionClear(); | |
380 delete callback; | |
381 return false; | |
382 } | |
383 | |
384 return true; | |
385 } | |
386 | |
285 jboolean CreateSharedRelro(JNIEnv* env, | 387 jboolean CreateSharedRelro(JNIEnv* env, |
286 jclass clazz, | 388 jclass clazz, |
287 jstring library_name, | 389 jstring library_name, |
288 jlong load_address, | 390 jlong load_address, |
289 jobject lib_info_obj) { | 391 jobject lib_info_obj) { |
290 String lib_name(env, library_name); | 392 String lib_name(env, library_name); |
291 | 393 |
292 LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str()); | 394 LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str()); |
293 | 395 |
294 if (!IsValidAddress(load_address)) { | 396 if (!IsValidAddress(load_address)) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
384 | 486 |
385 const JNINativeMethod kNativeMethods[] = { | 487 const JNINativeMethod kNativeMethods[] = { |
386 {"nativeLoadLibrary", | 488 {"nativeLoadLibrary", |
387 "(" | 489 "(" |
388 "Ljava/lang/String;" | 490 "Ljava/lang/String;" |
389 "J" | 491 "J" |
390 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 492 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
391 ")" | 493 ")" |
392 "Z", | 494 "Z", |
393 reinterpret_cast<void*>(&LoadLibrary)}, | 495 reinterpret_cast<void*>(&LoadLibrary)}, |
496 {"nativeRunCallbackOnUiThread", | |
497 "(" | |
498 "J" | |
499 ")" | |
500 "V", | |
501 reinterpret_cast<void*>(&RunCallbackOnUiThread)}, | |
394 {"nativeCreateSharedRelro", | 502 {"nativeCreateSharedRelro", |
395 "(" | 503 "(" |
396 "Ljava/lang/String;" | 504 "Ljava/lang/String;" |
397 "J" | 505 "J" |
398 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 506 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
399 ")" | 507 ")" |
400 "Z", | 508 "Z", |
401 reinterpret_cast<void*>(&CreateSharedRelro)}, | 509 reinterpret_cast<void*>(&CreateSharedRelro)}, |
402 {"nativeUseSharedRelro", | 510 {"nativeUseSharedRelro", |
403 "(" | 511 "(" |
(...skipping 22 matching lines...) Expand all Loading... | |
426 LOG_INFO("%s: Entering", __FUNCTION__); | 534 LOG_INFO("%s: Entering", __FUNCTION__); |
427 // Get new JNIEnv | 535 // Get new JNIEnv |
428 JNIEnv* env; | 536 JNIEnv* env; |
429 if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) { | 537 if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) { |
430 LOG_ERROR("Could not create JNIEnv"); | 538 LOG_ERROR("Could not create JNIEnv"); |
431 return -1; | 539 return -1; |
432 } | 540 } |
433 | 541 |
434 // Register native methods. | 542 // Register native methods. |
435 jclass linker_class; | 543 jclass linker_class; |
436 if (!InitClassReference( | 544 if (!InitClassReference(env, |
437 env, "org/chromium/base/library_loader/Linker", &linker_class)) | 545 "org/chromium/base/library_loader/Linker", |
546 &linker_class)) | |
438 return -1; | 547 return -1; |
439 | 548 |
440 LOG_INFO("%s: Registering native methods", __FUNCTION__); | 549 LOG_INFO("%s: Registering native methods", __FUNCTION__); |
441 env->RegisterNatives(linker_class, | 550 env->RegisterNatives(linker_class, |
442 kNativeMethods, | 551 kNativeMethods, |
443 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); | 552 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); |
444 | 553 |
445 // Find LibInfo field ids. | 554 // Find LibInfo field ids. |
446 LOG_INFO("%s: Caching field IDs", __FUNCTION__); | 555 LOG_INFO("%s: Caching field IDs", __FUNCTION__); |
447 if (!s_lib_info_fields.Init(env)) { | 556 if (!s_lib_info_fields.Init(env)) { |
448 return -1; | 557 return -1; |
449 } | 558 } |
450 | 559 |
560 // Resolve and save the Java side Linker callback class and method. | |
561 LOG_INFO("%s: Resolving callback references", __FUNCTION__); | |
562 if (!s_callback_refs.Init(env, linker_class)) { | |
563 return -1; | |
564 } | |
565 | |
451 // Save JavaVM* handle into context. | 566 // Save JavaVM* handle into context. |
452 crazy_context_t* context = GetCrazyContext(); | 567 crazy_context_t* context = GetCrazyContext(); |
453 crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); | 568 crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); |
454 | 569 |
570 // Register the function that the crazy linker can call to post code | |
571 // for later execution. | |
572 crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL); | |
573 | |
455 LOG_INFO("%s: Done", __FUNCTION__); | 574 LOG_INFO("%s: Done", __FUNCTION__); |
456 return JNI_VERSION_1_4; | 575 return JNI_VERSION_1_4; |
457 } | 576 } |
OLD | NEW |