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
3 // found in the LICENSE file.
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
7 // real Chromium libraries (e.g. libcontentshell.so).
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
13 // This source code *cannot* depend on anything from base/ or the C++
14 // STL, to keep the final library small, and avoid ugly dependency issues.
16 #include <android/log.h>
17 #include <crazy_linker.h>
25 // Set this to 1 to enable debug traces to the Android log.
26 // Note that LOG() from "base/logging.h" cannot be used, since it is
27 // in base/ which hasn't been loaded yet.
30 #define TAG "chromium_android_linker"
33 #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
35 #define LOG_INFO(...) ((void)0)
37 #define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
39 #define UNUSED __attribute__((unused))
43 // A simply scoped UTF String class that can be initialized from
44 // a Java jstring handle. Modeled like std::string, which cannot
48 String(JNIEnv
* env
, jstring str
);
55 const char* c_str() const { return ptr_
? ptr_
: ""; }
56 size_t size() const { return size_
; }
63 String::String(JNIEnv
* env
, jstring str
) {
64 size_
= env
->GetStringUTFLength(str
);
65 ptr_
= static_cast<char*>(::malloc(size_
+ 1));
67 // Note: the result contains Java "modified UTF-8" bytes.
68 // Good enough for the linker though.
69 const char* bytes
= env
->GetStringUTFChars(str
, NULL
);
70 ::memcpy(ptr_
, bytes
, size_
);
73 env
->ReleaseStringUTFChars(str
, bytes
);
76 // Return true iff |address| is a valid address for the target CPU.
77 bool IsValidAddress(jlong address
) {
78 return static_cast<jlong
>(static_cast<size_t>(address
)) == address
;
81 // Find the jclass JNI reference corresponding to a given |class_name|.
82 // |env| is the current JNI environment handle.
83 // On success, return true and set |*clazz|.
84 bool InitClassReference(JNIEnv
* env
, const char* class_name
, jclass
* clazz
) {
85 *clazz
= env
->FindClass(class_name
);
87 LOG_ERROR("Could not find class for %s", class_name
);
93 // Initialize a jfieldID corresponding to the field of a given |clazz|,
94 // with name |field_name| and signature |field_sig|.
95 // |env| is the current JNI environment handle.
96 // On success, return true and set |*field_id|.
97 bool InitFieldId(JNIEnv
* env
,
99 const char* field_name
,
100 const char* field_sig
,
101 jfieldID
* field_id
) {
102 *field_id
= env
->GetFieldID(clazz
, field_name
, field_sig
);
104 LOG_ERROR("Could not find ID for field '%s'", field_name
);
108 "%s: Found ID %p for field '%s'", __FUNCTION__
, *field_id
, field_name
);
112 // Initialize a jmethodID corresponding to the static method of a given
113 // |clazz|, with name |method_name| and signature |method_sig|.
114 // |env| is the current JNI environment handle.
115 // On success, return true and set |*method_id|.
116 bool InitStaticMethodId(JNIEnv
* env
,
118 const char* method_name
,
119 const char* method_sig
,
120 jmethodID
* method_id
) {
121 *method_id
= env
->GetStaticMethodID(clazz
, method_name
, method_sig
);
123 LOG_ERROR("Could not find ID for static method '%s'", method_name
);
126 LOG_INFO("%s: Found ID %p for static method '%s'",
127 __FUNCTION__
, *method_id
, method_name
);
131 // Initialize a jfieldID corresponding to the static field of a given |clazz|,
132 // with name |field_name| and signature |field_sig|.
133 // |env| is the current JNI environment handle.
134 // On success, return true and set |*field_id|.
135 bool InitStaticFieldId(JNIEnv
* env
,
137 const char* field_name
,
138 const char* field_sig
,
139 jfieldID
* field_id
) {
140 *field_id
= env
->GetStaticFieldID(clazz
, field_name
, field_sig
);
142 LOG_ERROR("Could not find ID for static field '%s'", field_name
);
146 "%s: Found ID %p for static field '%s'",
147 __FUNCTION__
, *field_id
, field_name
);
151 // Initialize a jint corresponding to the static integer field of a class
152 // with class name |class_name| and field name |field_name|.
153 // |env| is the current JNI environment handle.
154 // On success, return true and set |*value|.
155 bool InitStaticInt(JNIEnv
* env
,
156 const char* class_name
,
157 const char* field_name
,
160 if (!InitClassReference(env
, class_name
, &clazz
))
164 if (!InitStaticFieldId(env
, clazz
, field_name
, "I", &field_id
))
167 *value
= env
->GetStaticIntField(clazz
, field_id
);
169 "%s: Found value %d for class '%s', static field '%s'",
170 __FUNCTION__
, *value
, class_name
, field_name
);
175 // A class used to model the field IDs of the org.chromium.base.Linker
176 // LibInfo inner class, used to communicate data with the Java side
178 struct LibInfo_class
{
179 jfieldID load_address_id
;
180 jfieldID load_size_id
;
181 jfieldID relro_start_id
;
182 jfieldID relro_size_id
;
183 jfieldID relro_fd_id
;
185 // Initialize an instance.
186 bool Init(JNIEnv
* env
) {
188 if (!InitClassReference(
189 env
, "org/chromium/base/library_loader/Linker$LibInfo", &clazz
)) {
193 return InitFieldId(env
, clazz
, "mLoadAddress", "J", &load_address_id
) &&
194 InitFieldId(env
, clazz
, "mLoadSize", "J", &load_size_id
) &&
195 InitFieldId(env
, clazz
, "mRelroStart", "J", &relro_start_id
) &&
196 InitFieldId(env
, clazz
, "mRelroSize", "J", &relro_size_id
) &&
197 InitFieldId(env
, clazz
, "mRelroFd", "I", &relro_fd_id
);
200 void SetLoadInfo(JNIEnv
* env
,
201 jobject library_info_obj
,
204 env
->SetLongField(library_info_obj
, load_address_id
, load_address
);
205 env
->SetLongField(library_info_obj
, load_size_id
, load_size
);
208 // Use this instance to convert a RelroInfo reference into
209 // a crazy_library_info_t.
210 void GetRelroInfo(JNIEnv
* env
,
211 jobject library_info_obj
,
215 *relro_start
= static_cast<size_t>(
216 env
->GetLongField(library_info_obj
, relro_start_id
));
219 static_cast<size_t>(env
->GetLongField(library_info_obj
, relro_size_id
));
221 *relro_fd
= env
->GetIntField(library_info_obj
, relro_fd_id
);
224 void SetRelroInfo(JNIEnv
* env
,
225 jobject library_info_obj
,
229 env
->SetLongField(library_info_obj
, relro_start_id
, relro_start
);
230 env
->SetLongField(library_info_obj
, relro_size_id
, relro_size
);
231 env
->SetIntField(library_info_obj
, relro_fd_id
, relro_fd
);
235 static LibInfo_class s_lib_info_fields
;
237 // Retrieve the SDK build version and pass it into the crazy linker. This
238 // needs to be done early in initialization, before any other crazy linker
240 // |env| is the current JNI environment handle.
241 // On success, return true.
242 bool InitSDKVersionInfo(JNIEnv
* env
) {
244 if (!InitStaticInt(env
, "android/os/Build$VERSION", "SDK_INT", &value
))
247 crazy_set_sdk_build_version(static_cast<int>(value
));
248 LOG_INFO("%s: Set SDK build version to %d",
249 __FUNCTION__
, static_cast<int>(value
));
254 // The linker uses a single crazy_context_t object created on demand.
255 // There is no need to protect this against concurrent access, locking
256 // is already handled on the Java side.
257 static crazy_context_t
* s_crazy_context
;
259 crazy_context_t
* GetCrazyContext() {
260 if (!s_crazy_context
) {
261 // Create new context.
262 s_crazy_context
= crazy_context_create();
264 // Ensure libraries located in the same directory as the linker
265 // can be loaded before system ones.
266 crazy_context_add_search_path_for_address(
267 s_crazy_context
, reinterpret_cast<void*>(&s_crazy_context
));
270 return s_crazy_context
;
273 // A scoped crazy_library_t that automatically closes the handle
274 // on scope exit, unless Release() has been called.
275 class ScopedLibrary
{
277 ScopedLibrary() : lib_(NULL
) {}
281 crazy_library_close_with_context(lib_
, GetCrazyContext());
284 crazy_library_t
* Get() { return lib_
; }
286 crazy_library_t
** GetPtr() { return &lib_
; }
288 crazy_library_t
* Release() {
289 crazy_library_t
* ret
= lib_
;
295 crazy_library_t
* lib_
;
300 template <class LibraryOpener
>
301 bool GenericLoadLibrary(
303 const char* library_name
, jlong load_address
, jobject lib_info_obj
,
304 const LibraryOpener
& opener
) {
305 crazy_context_t
* context
= GetCrazyContext();
307 if (!IsValidAddress(load_address
)) {
308 LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__
, load_address
);
312 // Set the desired load address (0 means randomize it).
313 crazy_context_set_load_address(context
, static_cast<size_t>(load_address
));
315 ScopedLibrary library
;
316 if (!opener
.Open(library
.GetPtr(), library_name
, context
)) {
320 crazy_library_info_t info
;
321 if (!crazy_library_get_info(library
.Get(), context
, &info
)) {
322 LOG_ERROR("%s: Could not get library information for %s: %s",
325 crazy_context_get_error(context
));
329 // Release library object to keep it alive after the function returns.
332 s_lib_info_fields
.SetLoadInfo(
333 env
, lib_info_obj
, info
.load_address
, info
.load_size
);
334 LOG_INFO("%s: Success loading library %s", __FUNCTION__
, library_name
);
338 // Used for opening the library in a regular file.
339 class FileLibraryOpener
{
342 crazy_library_t
** library
,
343 const char* library_name
,
344 crazy_context_t
* context
) const;
347 bool FileLibraryOpener::Open(
348 crazy_library_t
** library
,
349 const char* library_name
,
350 crazy_context_t
* context
) const {
351 if (!crazy_library_open(library
, library_name
, context
)) {
352 LOG_ERROR("%s: Could not open %s: %s",
355 crazy_context_get_error(context
));
361 // Used for opening the library in a zip file.
362 class ZipLibraryOpener
{
364 explicit ZipLibraryOpener(const char* zip_file
) : zip_file_(zip_file
) {}
366 crazy_library_t
** library
,
367 const char* library_name
,
368 crazy_context_t
* context
) const;
370 const char* zip_file_
;
373 bool ZipLibraryOpener::Open(
374 crazy_library_t
** library
,
375 const char* library_name
,
376 crazy_context_t
* context
) const {
377 if (!crazy_library_open_in_zip_file(
378 library
, zip_file_
, library_name
, context
)) {
379 LOG_ERROR("%s: Could not open %s in zip file %s: %s",
380 __FUNCTION__
, library_name
, zip_file_
,
381 crazy_context_get_error(context
));
387 } // unnamed namespace
389 // Load a library with the chromium linker. This will also call its
390 // JNI_OnLoad() method, which shall register its methods. Note that
391 // lazy native method resolution will _not_ work after this, because
392 // Dalvik uses the system's dlsym() which won't see the new library,
393 // so explicit registration is mandatory.
394 // |env| is the current JNI environment handle.
395 // |clazz| is the static class handle for org.chromium.base.Linker,
396 // and is ignored here.
397 // |library_name| is the library name (e.g. libfoo.so).
398 // |load_address| is an explicit load address.
399 // |library_info| is a LibInfo handle used to communicate information
400 // with the Java side.
401 // Return true on success.
402 jboolean
LoadLibrary(JNIEnv
* env
,
404 jstring library_name
,
406 jobject lib_info_obj
) {
407 String
lib_name(env
, library_name
);
408 FileLibraryOpener opener
;
409 return GenericLoadLibrary(
410 env
, lib_name
.c_str(),
411 static_cast<size_t>(load_address
), lib_info_obj
, opener
);
414 // Load a library from a zipfile with the chromium linker. The
415 // library in the zipfile must be uncompressed and page aligned.
416 // The basename of the library is given. The library is expected
417 // to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the
418 // same as the abi for this linker. The "crazy." prefix is included
419 // so that the Android Package Manager doesn't extract the library into
422 // Loading the library will also call its JNI_OnLoad() method, which
423 // shall register its methods. Note that lazy native method resolution
424 // will _not_ work after this, because Dalvik uses the system's dlsym()
425 // which won't see the new library, so explicit registration is mandatory.
427 // |env| is the current JNI environment handle.
428 // |clazz| is the static class handle for org.chromium.base.Linker,
429 // and is ignored here.
430 // |zipfile_name| is the filename of the zipfile containing the library.
431 // |library_name| is the library base name (e.g. libfoo.so).
432 // |load_address| is an explicit load address.
433 // |library_info| is a LibInfo handle used to communicate information
434 // with the Java side.
435 // Returns true on success.
436 jboolean
LoadLibraryInZipFile(JNIEnv
* env
,
438 jstring zipfile_name
,
439 jstring library_name
,
441 jobject lib_info_obj
) {
442 String
zipfile_name_str(env
, zipfile_name
);
443 String
lib_name(env
, library_name
);
444 ZipLibraryOpener
opener(zipfile_name_str
.c_str());
445 return GenericLoadLibrary(
446 env
, lib_name
.c_str(),
447 static_cast<size_t>(load_address
), lib_info_obj
, opener
);
450 // Enable the fallback due to lack of support for mapping the APK file with
451 // executable permission in the crazy linker.
453 // |env| is the current JNI environment handle and is ignored here.
454 // |clazz| is the static class handle for org.chromium.base.Linker,
455 // and is ignored here.
456 void EnableNoMapExecSupportFallback(JNIEnv
* env
, jclass clazz
) {
457 crazy_context_t
* context
= GetCrazyContext();
458 crazy_context_set_no_map_exec_support_fallback_enabled(context
, true);
461 // Class holding the Java class and method ID for the Java side Linker
462 // postCallbackOnMainThread method.
463 struct JavaCallbackBindings_class
{
467 // Initialize an instance.
468 bool Init(JNIEnv
* env
, jclass linker_class
) {
469 clazz
= reinterpret_cast<jclass
>(env
->NewGlobalRef(linker_class
));
470 return InitStaticMethodId(env
,
472 "postCallbackOnMainThread",
478 static JavaCallbackBindings_class s_java_callback_bindings
;
480 // Designated receiver function for callbacks from Java. Its name is known
482 // |env| is the current JNI environment handle and is ignored here.
483 // |clazz| is the static class handle for org.chromium.base.Linker,
484 // and is ignored here.
485 // |arg| is a pointer to an allocated crazy_callback_t, deleted after use.
486 void RunCallbackOnUiThread(JNIEnv
* env
, jclass clazz
, jlong arg
) {
487 crazy_callback_t
* callback
= reinterpret_cast<crazy_callback_t
*>(arg
);
489 LOG_INFO("%s: Called back from java with handler %p, opaque %p",
490 __FUNCTION__
, callback
->handler
, callback
->opaque
);
492 crazy_callback_run(callback
);
496 // Request a callback from Java. The supplied crazy_callback_t is valid only
497 // for the duration of this call, so we copy it to a newly allocated
498 // crazy_callback_t and then call the Java side's postCallbackOnMainThread.
499 // This will call back to to our RunCallbackOnUiThread some time
500 // later on the UI thread.
501 // |callback_request| is a crazy_callback_t.
502 // |poster_opaque| is unused.
503 // Returns true if the callback request succeeds.
504 static bool PostForLaterExecution(crazy_callback_t
* callback_request
,
505 void* poster_opaque UNUSED
) {
506 crazy_context_t
* context
= GetCrazyContext();
509 int minimum_jni_version
;
510 crazy_context_get_java_vm(context
,
511 reinterpret_cast<void**>(&vm
),
512 &minimum_jni_version
);
514 // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own.
516 if (JNI_OK
!= vm
->GetEnv(
517 reinterpret_cast<void**>(&env
), minimum_jni_version
)) {
518 LOG_ERROR("Could not create JNIEnv");
522 // Copy the callback; the one passed as an argument may be temporary.
523 crazy_callback_t
* callback
= new crazy_callback_t();
524 *callback
= *callback_request
;
526 LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
527 __FUNCTION__
, callback
->handler
, callback
->opaque
);
529 jlong arg
= static_cast<jlong
>(reinterpret_cast<uintptr_t>(callback
));
531 env
->CallStaticVoidMethod(
532 s_java_callback_bindings
.clazz
, s_java_callback_bindings
.method_id
, arg
);
534 // Back out and return false if we encounter a JNI exception.
535 if (env
->ExceptionCheck() == JNI_TRUE
) {
536 env
->ExceptionDescribe();
537 env
->ExceptionClear();
545 jboolean
CreateSharedRelro(JNIEnv
* env
,
547 jstring library_name
,
549 jobject lib_info_obj
) {
550 String
lib_name(env
, library_name
);
552 LOG_INFO("%s: Called for %s", __FUNCTION__
, lib_name
.c_str());
554 if (!IsValidAddress(load_address
)) {
555 LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__
, load_address
);
559 ScopedLibrary library
;
560 if (!crazy_library_find_by_name(lib_name
.c_str(), library
.GetPtr())) {
561 LOG_ERROR("%s: Could not find %s", __FUNCTION__
, lib_name
.c_str());
565 crazy_context_t
* context
= GetCrazyContext();
566 size_t relro_start
= 0;
567 size_t relro_size
= 0;
570 if (!crazy_library_create_shared_relro(library
.Get(),
572 static_cast<size_t>(load_address
),
576 LOG_ERROR("%s: Could not create shared RELRO sharing for %s: %s\n",
579 crazy_context_get_error(context
));
583 s_lib_info_fields
.SetRelroInfo(
584 env
, lib_info_obj
, relro_start
, relro_size
, relro_fd
);
588 jboolean
UseSharedRelro(JNIEnv
* env
,
590 jstring library_name
,
591 jobject lib_info_obj
) {
592 String
lib_name(env
, library_name
);
594 LOG_INFO("%s: called for %s, lib_info_ref=%p",
599 ScopedLibrary library
;
600 if (!crazy_library_find_by_name(lib_name
.c_str(), library
.GetPtr())) {
601 LOG_ERROR("%s: Could not find %s", __FUNCTION__
, lib_name
.c_str());
605 crazy_context_t
* context
= GetCrazyContext();
606 size_t relro_start
= 0;
607 size_t relro_size
= 0;
609 s_lib_info_fields
.GetRelroInfo(
610 env
, lib_info_obj
, &relro_start
, &relro_size
, &relro_fd
);
612 LOG_INFO("%s: library=%s relro start=%p size=%p fd=%d",
619 if (!crazy_library_use_shared_relro(
620 library
.Get(), context
, relro_start
, relro_size
, relro_fd
)) {
621 LOG_ERROR("%s: Could not use shared RELRO for %s: %s",
624 crazy_context_get_error(context
));
628 LOG_INFO("%s: Library %s using shared RELRO section!",
635 jboolean
CanUseSharedRelro(JNIEnv
* env
, jclass clazz
) {
636 return crazy_system_can_share_relro();
639 jlong
GetRandomBaseLoadAddress(JNIEnv
* env
, jclass clazz
, jlong bytes
) {
641 mmap(NULL
, bytes
, PROT_NONE
, MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
642 if (address
== MAP_FAILED
) {
643 LOG_INFO("%s: Random base load address not determinable\n", __FUNCTION__
);
646 munmap(address
, bytes
);
647 LOG_INFO("%s: Random base load address is %p\n", __FUNCTION__
, address
);
648 return static_cast<jlong
>(reinterpret_cast<uintptr_t>(address
));
651 // Get the full path of a library in the zip file
652 // (lib/<abi>/crazy.<lib_name>).
654 // |env| is the current JNI environment handle.
655 // |clazz| is the static class handle which is not used here.
656 // |lib_name| is the library base name.
657 // Returns the full path (or empty string on failure).
658 jstring
GetLibraryFilePathInZipFile(JNIEnv
* env
,
661 String
lib_name_str(env
, lib_name
);
662 const char* lib_name_c_str
= lib_name_str
.c_str();
663 char buffer
[kMaxFilePathLengthInZip
+ 1];
664 if (crazy_library_file_path_in_zip_file(
665 lib_name_c_str
, buffer
, sizeof(buffer
)) == CRAZY_STATUS_FAILURE
) {
666 LOG_ERROR("%s: Failed to get full filename for library '%s'",
667 __FUNCTION__
, lib_name_c_str
);
670 return env
->NewStringUTF(buffer
);
673 // Check whether the device supports mapping the APK file with executable
676 // |env| is the current JNI environment handle.
677 // |clazz| is the static class handle which is not used here.
678 // |apkfile_name| is the filename of the APK.
679 // Returns true if supported.
680 jboolean
CheckMapExecSupport(JNIEnv
* env
, jclass clazz
, jstring apkfile_name
) {
681 String
apkfile_name_str(env
, apkfile_name
);
682 const char* apkfile_name_c_str
= apkfile_name_str
.c_str();
684 int fd
= open(apkfile_name_c_str
, O_RDONLY
);
686 LOG_ERROR("%s: Failed to open %s\n", __FUNCTION__
, apkfile_name_c_str
);
691 "%s: Memory mapping the first page of %s with executable permissions\n",
692 __FUNCTION__
, apkfile_name_c_str
);
693 void* address
= mmap(NULL
, PAGE_SIZE
, PROT_EXEC
, MAP_PRIVATE
, fd
, 0);
696 if (address
== MAP_FAILED
) {
700 munmap(address
, PAGE_SIZE
);
705 LOG_INFO("%s: %s\n", __FUNCTION__
, status
? "Supported" : "NOT supported");
709 // Check whether a library is page aligned and uncompressed in the APK file.
711 // |env| is the current JNI environment handle.
712 // |clazz| is the static class handle which is not used here.
713 // |apkfile_name| is the filename of the APK.
714 // |library_name| is the library base name.
715 // Returns true if page aligned and uncompressed.
716 jboolean
CheckLibraryIsMappableInApk(JNIEnv
* env
, jclass clazz
,
717 jstring apkfile_name
,
718 jstring library_name
) {
719 String
apkfile_name_str(env
, apkfile_name
);
720 const char* apkfile_name_c_str
= apkfile_name_str
.c_str();
721 String
library_name_str(env
, library_name
);
722 const char* library_name_c_str
= library_name_str
.c_str();
724 LOG_INFO("%s: Checking if %s is page-aligned and uncompressed in %s\n",
725 __FUNCTION__
, library_name_c_str
, apkfile_name_c_str
);
726 jboolean mappable
= crazy_linker_check_library_is_mappable_in_zip_file(
727 apkfile_name_c_str
, library_name_c_str
) == CRAZY_STATUS_SUCCESS
;
728 LOG_INFO("%s: %s\n", __FUNCTION__
, mappable
? "Mappable" : "NOT mappable");
733 const JNINativeMethod kNativeMethods
[] = {
734 {"nativeLoadLibrary",
738 "Lorg/chromium/base/library_loader/Linker$LibInfo;"
741 reinterpret_cast<void*>(&LoadLibrary
)},
742 {"nativeLoadLibraryInZipFile",
747 "Lorg/chromium/base/library_loader/Linker$LibInfo;"
750 reinterpret_cast<void*>(&LoadLibraryInZipFile
)},
751 {"nativeEnableNoMapExecSupportFallback",
755 reinterpret_cast<void*>(&EnableNoMapExecSupportFallback
)},
756 {"nativeRunCallbackOnUiThread",
761 reinterpret_cast<void*>(&RunCallbackOnUiThread
)},
762 {"nativeCreateSharedRelro",
766 "Lorg/chromium/base/library_loader/Linker$LibInfo;"
769 reinterpret_cast<void*>(&CreateSharedRelro
)},
770 {"nativeUseSharedRelro",
773 "Lorg/chromium/base/library_loader/Linker$LibInfo;"
776 reinterpret_cast<void*>(&UseSharedRelro
)},
777 {"nativeCanUseSharedRelro",
781 reinterpret_cast<void*>(&CanUseSharedRelro
)},
782 {"nativeGetRandomBaseLoadAddress",
787 reinterpret_cast<void*>(&GetRandomBaseLoadAddress
)},
788 {"nativeGetLibraryFilePathInZipFile",
792 "Ljava/lang/String;",
793 reinterpret_cast<void*>(&GetLibraryFilePathInZipFile
)},
794 {"nativeCheckMapExecSupport",
799 reinterpret_cast<void*>(&CheckMapExecSupport
)},
800 {"nativeCheckLibraryIsMappableInApk",
806 reinterpret_cast<void*>(&CheckLibraryIsMappableInApk
)}, };
810 // JNI_OnLoad() hook called when the linker library is loaded through
811 // the regular System.LoadLibrary) API. This shall save the Java VM
812 // handle and initialize LibInfo fields.
813 jint
JNI_OnLoad(JavaVM
* vm
, void* reserved
) {
814 LOG_INFO("%s: Entering", __FUNCTION__
);
817 if (JNI_OK
!= vm
->GetEnv(reinterpret_cast<void**>(&env
), JNI_VERSION_1_4
)) {
818 LOG_ERROR("Could not create JNIEnv");
822 // Initialize SDK version info.
823 LOG_INFO("%s: Retrieving SDK version info", __FUNCTION__
);
824 if (!InitSDKVersionInfo(env
))
827 // Register native methods.
829 if (!InitClassReference(env
,
830 "org/chromium/base/library_loader/Linker",
834 LOG_INFO("%s: Registering native methods", __FUNCTION__
);
835 env
->RegisterNatives(linker_class
,
837 sizeof(kNativeMethods
) / sizeof(kNativeMethods
[0]));
839 // Find LibInfo field ids.
840 LOG_INFO("%s: Caching field IDs", __FUNCTION__
);
841 if (!s_lib_info_fields
.Init(env
)) {
845 // Resolve and save the Java side Linker callback class and method.
846 LOG_INFO("%s: Resolving callback bindings", __FUNCTION__
);
847 if (!s_java_callback_bindings
.Init(env
, linker_class
)) {
851 // Save JavaVM* handle into context.
852 crazy_context_t
* context
= GetCrazyContext();
853 crazy_context_set_java_vm(context
, vm
, JNI_VERSION_1_4
);
855 // Register the function that the crazy linker can call to post code
856 // for later execution.
857 crazy_context_set_callback_poster(context
, &PostForLaterExecution
, NULL
);
859 LOG_INFO("%s: Done", __FUNCTION__
);
860 return JNI_VERSION_1_4
;