Chromium Code Reviews| 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 |