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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 *field_id = env->GetFieldID(clazz, field_name, field_sig); | 133 *field_id = env->GetFieldID(clazz, field_name, field_sig); |
134 if (!*field_id) { | 134 if (!*field_id) { |
135 LOG_ERROR("Could not find ID for field '%s'", field_name); | 135 LOG_ERROR("Could not find ID for field '%s'", field_name); |
136 return false; | 136 return false; |
137 } | 137 } |
138 LOG_INFO( | 138 LOG_INFO( |
139 "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name); | 139 "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name); |
140 return true; | 140 return true; |
141 } | 141 } |
142 | 142 |
143 // Initialize a jmethodID corresponding to the static method of a given | |
144 // |clazz|, with name |method_name| and signature |method_sig|. | |
145 // |env| is the current JNI environment handle. | |
146 // On success, return true and set |*method_id|. | |
147 bool InitStaticMethodId(JNIEnv* env, | |
148 jclass clazz, | |
149 const char* method_name, | |
150 const char* method_sig, | |
151 jmethodID* method_id) { | |
152 *method_id = env->GetStaticMethodID(clazz, method_name, method_sig); | |
153 if (!*method_id) { | |
154 LOG_ERROR("Could not find ID for static method '%s'", method_name); | |
155 return false; | |
156 } | |
157 LOG_INFO("%s: Found ID %p for static method '%s'", | |
158 __FUNCTION__, *method_id, method_name); | |
159 return true; | |
160 } | |
161 | |
143 // A class used to model the field IDs of the org.chromium.base.Linker | 162 // 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 | 163 // LibInfo inner class, used to communicate data with the Java side |
145 // of the linker. | 164 // of the linker. |
146 struct LibInfo_class { | 165 struct LibInfo_class { |
147 jfieldID load_address_id; | 166 jfieldID load_address_id; |
148 jfieldID load_size_id; | 167 jfieldID load_size_id; |
149 jfieldID relro_start_id; | 168 jfieldID relro_start_id; |
150 jfieldID relro_size_id; | 169 jfieldID relro_size_id; |
151 jfieldID relro_fd_id; | 170 jfieldID relro_fd_id; |
152 | 171 |
(...skipping 122 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 to support simple callbacks from the Java side. Hold a pointer | |
305 // to a function taking a single void* argument, and an argument value. | |
306 struct callback_t { | |
307 public: | |
308 callback_t() : handler(NULL), opaque(NULL) { } | |
309 | |
310 void (*handler)(void*); | |
311 void* opaque; | |
312 }; | |
313 | |
314 // Designated receiver function for callbacks from Java. Its name is known | |
315 // to the Java side. | |
316 // |env| is the current JNI environment handle and is ignored here. | |
317 // |clazz| is the static class handle for org.chromium.base.Linker, | |
318 // and is ignored here. | |
319 // |arg| is a pointer to an allocated callback_t. | |
320 void ReceiveCallbackFromMainThread(JNIEnv* env, jclass clazz, jlong arg) { | |
321 callback_t* callback = reinterpret_cast<callback_t*>(arg); | |
322 | |
323 LOG_INFO("%s: Called back from java with handler %p, opaque %p", | |
324 __FUNCTION__, callback->handler, callback->opaque); | |
325 | |
326 (*callback->handler)(callback->opaque); | |
327 delete callback; | |
328 } | |
329 | |
330 // Class holding the Java class and method ID for the Java side Linker | |
331 // PostCallbackOnMainThread method. Like crazy_context_t, there is | |
332 // only one of these, requiring no locking. | |
333 struct callback_refs_t { | |
334 public: | |
335 callback_refs_t() : clazz(NULL), method_id(NULL) { } | |
336 | |
337 jclass clazz; | |
338 jmethodID method_id; | |
339 }; | |
340 | |
341 static callback_refs_t s_callback_refs; | |
342 | |
343 // Request a callback from Java. Constructs a new callback_t and calls | |
344 // the Java side's PostCallbackOnMainThread, which will some time later | |
345 // call back to our ReceiveCallbackFromMainThread. | |
346 // |handler| is a handler function, taking a single void* argument. | |
347 // |opaque| is the argument to supply to the handler when run in the callback. | |
348 // Returns true if the callback request succeeded. | |
349 static bool PostForLaterExecution(void (*handler)(void*), void *opaque) { | |
bulach
2014/04/15 13:58:14
nit: s/void *opaque/void* opaque/
simonb1
2014/04/17 14:45:43
Done.
| |
350 crazy_context_t* context = GetCrazyContext(); | |
351 | |
352 JavaVM* vm; | |
353 int minimum_jni_version; | |
354 crazy_context_get_java_vm(context, | |
355 reinterpret_cast<void**>(&vm), | |
356 &minimum_jni_version); | |
357 | |
358 // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own. | |
359 JNIEnv* env; | |
360 if (JNI_OK != vm->GetEnv( | |
361 reinterpret_cast<void**>(&env), minimum_jni_version)) { | |
362 LOG_ERROR("Could not create JNIEnv"); | |
363 return false; | |
364 } | |
365 | |
366 callback_t* callback = new callback_t(); | |
367 callback->handler = handler; | |
368 callback->opaque = opaque; | |
369 | |
370 LOG_INFO("%s: Calling back to java with handler %p, opaque %p", | |
371 __FUNCTION__, callback->handler, callback->opaque); | |
372 | |
373 jlong arg = static_cast<jlong>(reinterpret_cast<intptr_t>(callback)); | |
374 env->CallStaticVoidMethod( | |
375 s_callback_refs.clazz, s_callback_refs.method_id, arg); | |
bulach
2014/04/15 13:58:14
need to clear any java exception (assuming it's sa
simonb1
2014/04/17 14:45:43
Done.
| |
376 return true; | |
377 } | |
378 | |
285 jboolean CreateSharedRelro(JNIEnv* env, | 379 jboolean CreateSharedRelro(JNIEnv* env, |
286 jclass clazz, | 380 jclass clazz, |
287 jstring library_name, | 381 jstring library_name, |
288 jlong load_address, | 382 jlong load_address, |
289 jobject lib_info_obj) { | 383 jobject lib_info_obj) { |
290 String lib_name(env, library_name); | 384 String lib_name(env, library_name); |
291 | 385 |
292 LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str()); | 386 LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str()); |
293 | 387 |
294 if (!IsValidAddress(load_address)) { | 388 if (!IsValidAddress(load_address)) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
384 | 478 |
385 const JNINativeMethod kNativeMethods[] = { | 479 const JNINativeMethod kNativeMethods[] = { |
386 {"nativeLoadLibrary", | 480 {"nativeLoadLibrary", |
387 "(" | 481 "(" |
388 "Ljava/lang/String;" | 482 "Ljava/lang/String;" |
389 "J" | 483 "J" |
390 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 484 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
391 ")" | 485 ")" |
392 "Z", | 486 "Z", |
393 reinterpret_cast<void*>(&LoadLibrary)}, | 487 reinterpret_cast<void*>(&LoadLibrary)}, |
488 {"nativeReceiveCallbackFromMainThread", | |
489 "(" | |
490 "J" | |
491 ")" | |
492 "V", | |
493 reinterpret_cast<void*>(&ReceiveCallbackFromMainThread)}, | |
394 {"nativeCreateSharedRelro", | 494 {"nativeCreateSharedRelro", |
395 "(" | 495 "(" |
396 "Ljava/lang/String;" | 496 "Ljava/lang/String;" |
397 "J" | 497 "J" |
398 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 498 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
399 ")" | 499 ")" |
400 "Z", | 500 "Z", |
401 reinterpret_cast<void*>(&CreateSharedRelro)}, | 501 reinterpret_cast<void*>(&CreateSharedRelro)}, |
402 {"nativeUseSharedRelro", | 502 {"nativeUseSharedRelro", |
403 "(" | 503 "(" |
404 "Ljava/lang/String;" | 504 "Ljava/lang/String;" |
405 "Lorg/chromium/base/library_loader/Linker$LibInfo;" | 505 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
406 ")" | 506 ")" |
407 "Z", | 507 "Z", |
408 reinterpret_cast<void*>(&UseSharedRelro)}, | 508 reinterpret_cast<void*>(&UseSharedRelro)}, |
409 {"nativeCanUseSharedRelro", | 509 {"nativeCanUseSharedRelro", |
410 "(" | 510 "(" |
411 ")" | 511 ")" |
412 "Z", | 512 "Z", |
413 reinterpret_cast<void*>(&CanUseSharedRelro)}, | 513 reinterpret_cast<void*>(&CanUseSharedRelro)}, |
414 {"nativeGetPageSize", | 514 {"nativeGetPageSize", |
415 "(" | 515 "(" |
416 ")" | 516 ")" |
417 "J", | 517 "J", |
418 reinterpret_cast<void*>(&GetPageSize)}, }; | 518 reinterpret_cast<void*>(&GetPageSize)}, }; |
419 | |
420 } // namespace | 519 } // namespace |
421 | 520 |
422 // JNI_OnLoad() hook called when the linker library is loaded through | 521 // JNI_OnLoad() hook called when the linker library is loaded through |
423 // the regular System.LoadLibrary) API. This shall save the Java VM | 522 // the regular System.LoadLibrary) API. This shall save the Java VM |
424 // handle and initialize LibInfo fields. | 523 // handle and initialize LibInfo fields. |
425 jint JNI_OnLoad(JavaVM* vm, void* reserved) { | 524 jint JNI_OnLoad(JavaVM* vm, void* reserved) { |
426 LOG_INFO("%s: Entering", __FUNCTION__); | 525 LOG_INFO("%s: Entering", __FUNCTION__); |
427 // Get new JNIEnv | 526 // Get new JNIEnv |
428 JNIEnv* env; | 527 JNIEnv* env; |
429 if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) { | 528 if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) { |
430 LOG_ERROR("Could not create JNIEnv"); | 529 LOG_ERROR("Could not create JNIEnv"); |
431 return -1; | 530 return -1; |
432 } | 531 } |
433 | 532 |
434 // Register native methods. | 533 // Register native methods. |
435 jclass linker_class; | 534 jclass linker_class; |
436 if (!InitClassReference( | 535 if (!InitClassReference(env, |
437 env, "org/chromium/base/library_loader/Linker", &linker_class)) | 536 "org/chromium/base/library_loader/Linker", |
537 &linker_class)) | |
438 return -1; | 538 return -1; |
439 | 539 |
440 LOG_INFO("%s: Registering native methods", __FUNCTION__); | 540 LOG_INFO("%s: Registering native methods", __FUNCTION__); |
441 env->RegisterNatives(linker_class, | 541 env->RegisterNatives(linker_class, |
442 kNativeMethods, | 542 kNativeMethods, |
443 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); | 543 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); |
444 | 544 |
445 // Find LibInfo field ids. | 545 // Find LibInfo field ids. |
446 LOG_INFO("%s: Caching field IDs", __FUNCTION__); | 546 LOG_INFO("%s: Caching field IDs", __FUNCTION__); |
447 if (!s_lib_info_fields.Init(env)) { | 547 if (!s_lib_info_fields.Init(env)) { |
448 return -1; | 548 return -1; |
449 } | 549 } |
450 | 550 |
451 // Save JavaVM* handle into context. | 551 // Save JavaVM* handle into context. |
452 crazy_context_t* context = GetCrazyContext(); | 552 crazy_context_t* context = GetCrazyContext(); |
453 crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); | 553 crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); |
454 | 554 |
555 // Resolve the Java side Linker callback method. | |
556 jmethodID method_id; | |
557 if (!InitStaticMethodId(env, | |
558 linker_class, | |
559 "PostCallbackOnMainThread", | |
560 "(J)V", | |
561 &method_id)) | |
562 return -1; | |
563 | |
564 // Save the callback class and method, and register the function that | |
565 // the crazy linker can call to post code for later execution. | |
566 s_callback_refs.clazz = linker_class; | |
567 s_callback_refs.method_id = method_id; | |
568 crazy_context_set_post_for_later_execution(context, &PostForLaterExecution); | |
569 | |
455 LOG_INFO("%s: Done", __FUNCTION__); | 570 LOG_INFO("%s: Done", __FUNCTION__); |
456 return JNI_VERSION_1_4; | 571 return JNI_VERSION_1_4; |
457 } | 572 } |
OLD | NEW |