Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / base / android / linker / linker_jni.cc
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.
4
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).
8
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
11 // renderer process.
12
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.
15
16 #include <android/log.h>
17 #include <crazy_linker.h>
18 #include <fcntl.h>
19 #include <jni.h>
20 #include <limits.h>
21 #include <stdlib.h>
22 #include <sys/mman.h>
23 #include <unistd.h>
24
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.
28 #define DEBUG 0
29
30 #define TAG "chromium_android_linker"
31
32 #if DEBUG
33 #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
34 #else
35 #define LOG_INFO(...) ((void)0)
36 #endif
37 #define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
38
39 #define UNUSED __attribute__((unused))
40
41 namespace {
42
43 // A simply scoped UTF String class that can be initialized from
44 // a Java jstring handle. Modeled like std::string, which cannot
45 // be used here.
46 class String {
47  public:
48   String(JNIEnv* env, jstring str);
49
50   ~String() {
51     if (ptr_)
52       ::free(ptr_);
53   }
54
55   const char* c_str() const { return ptr_ ? ptr_ : ""; }
56   size_t size() const { return size_; }
57
58  private:
59   char* ptr_;
60   size_t size_;
61 };
62
63 String::String(JNIEnv* env, jstring str) {
64   size_ = env->GetStringUTFLength(str);
65   ptr_ = static_cast<char*>(::malloc(size_ + 1));
66
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_);
71   ptr_[size_] = '\0';
72
73   env->ReleaseStringUTFChars(str, bytes);
74 }
75
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;
79 }
80
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);
86   if (!*clazz) {
87     LOG_ERROR("Could not find class for %s", class_name);
88     return false;
89   }
90   return true;
91 }
92
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,
98                  jclass clazz,
99                  const char* field_name,
100                  const char* field_sig,
101                  jfieldID* field_id) {
102   *field_id = env->GetFieldID(clazz, field_name, field_sig);
103   if (!*field_id) {
104     LOG_ERROR("Could not find ID for field '%s'", field_name);
105     return false;
106   }
107   LOG_INFO(
108       "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name);
109   return true;
110 }
111
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,
117                         jclass clazz,
118                         const char* method_name,
119                         const char* method_sig,
120                         jmethodID* method_id) {
121   *method_id = env->GetStaticMethodID(clazz, method_name, method_sig);
122   if (!*method_id) {
123     LOG_ERROR("Could not find ID for static method '%s'", method_name);
124     return false;
125   }
126   LOG_INFO("%s: Found ID %p for static method '%s'",
127            __FUNCTION__, *method_id, method_name);
128   return true;
129 }
130
131 // A class used to model the field IDs of the org.chromium.base.Linker
132 // LibInfo inner class, used to communicate data with the Java side
133 // of the linker.
134 struct LibInfo_class {
135   jfieldID load_address_id;
136   jfieldID load_size_id;
137   jfieldID relro_start_id;
138   jfieldID relro_size_id;
139   jfieldID relro_fd_id;
140
141   // Initialize an instance.
142   bool Init(JNIEnv* env) {
143     jclass clazz;
144     if (!InitClassReference(
145              env, "org/chromium/base/library_loader/Linker$LibInfo", &clazz)) {
146       return false;
147     }
148
149     return InitFieldId(env, clazz, "mLoadAddress", "J", &load_address_id) &&
150            InitFieldId(env, clazz, "mLoadSize", "J", &load_size_id) &&
151            InitFieldId(env, clazz, "mRelroStart", "J", &relro_start_id) &&
152            InitFieldId(env, clazz, "mRelroSize", "J", &relro_size_id) &&
153            InitFieldId(env, clazz, "mRelroFd", "I", &relro_fd_id);
154   }
155
156   void SetLoadInfo(JNIEnv* env,
157                    jobject library_info_obj,
158                    size_t load_address,
159                    size_t load_size) {
160     env->SetLongField(library_info_obj, load_address_id, load_address);
161     env->SetLongField(library_info_obj, load_size_id, load_size);
162   }
163
164   // Use this instance to convert a RelroInfo reference into
165   // a crazy_library_info_t.
166   void GetRelroInfo(JNIEnv* env,
167                     jobject library_info_obj,
168                     size_t* relro_start,
169                     size_t* relro_size,
170                     int* relro_fd) {
171     *relro_start = static_cast<size_t>(
172         env->GetLongField(library_info_obj, relro_start_id));
173
174     *relro_size =
175         static_cast<size_t>(env->GetLongField(library_info_obj, relro_size_id));
176
177     *relro_fd = env->GetIntField(library_info_obj, relro_fd_id);
178   }
179
180   void SetRelroInfo(JNIEnv* env,
181                     jobject library_info_obj,
182                     size_t relro_start,
183                     size_t relro_size,
184                     int relro_fd) {
185     env->SetLongField(library_info_obj, relro_start_id, relro_start);
186     env->SetLongField(library_info_obj, relro_size_id, relro_size);
187     env->SetIntField(library_info_obj, relro_fd_id, relro_fd);
188   }
189 };
190
191 static LibInfo_class s_lib_info_fields;
192
193 // The linker uses a single crazy_context_t object created on demand.
194 // There is no need to protect this against concurrent access, locking
195 // is already handled on the Java side.
196 static crazy_context_t* s_crazy_context;
197
198 crazy_context_t* GetCrazyContext() {
199   if (!s_crazy_context) {
200     // Create new context.
201     s_crazy_context = crazy_context_create();
202
203     // Ensure libraries located in the same directory as the linker
204     // can be loaded before system ones.
205     crazy_context_add_search_path_for_address(
206         s_crazy_context, reinterpret_cast<void*>(&s_crazy_context));
207   }
208
209   return s_crazy_context;
210 }
211
212 // A scoped crazy_library_t that automatically closes the handle
213 // on scope exit, unless Release() has been called.
214 class ScopedLibrary {
215  public:
216   ScopedLibrary() : lib_(NULL) {}
217
218   ~ScopedLibrary() {
219     if (lib_)
220       crazy_library_close_with_context(lib_, GetCrazyContext());
221   }
222
223   crazy_library_t* Get() { return lib_; }
224
225   crazy_library_t** GetPtr() { return &lib_; }
226
227   crazy_library_t* Release() {
228     crazy_library_t* ret = lib_;
229     lib_ = NULL;
230     return ret;
231   }
232
233  private:
234   crazy_library_t* lib_;
235 };
236
237 namespace {
238
239 template <class LibraryOpener>
240 bool GenericLoadLibrary(
241     JNIEnv* env,
242     const char* library_name, jlong load_address, jobject lib_info_obj,
243     const LibraryOpener& opener) {
244   crazy_context_t* context = GetCrazyContext();
245
246   if (!IsValidAddress(load_address)) {
247     LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__, load_address);
248     return false;
249   }
250
251   // Set the desired load address (0 means randomize it).
252   crazy_context_set_load_address(context, static_cast<size_t>(load_address));
253
254   ScopedLibrary library;
255   if (!opener.Open(library.GetPtr(), library_name, context)) {
256     return false;
257   }
258
259   crazy_library_info_t info;
260   if (!crazy_library_get_info(library.Get(), context, &info)) {
261     LOG_ERROR("%s: Could not get library information for %s: %s",
262               __FUNCTION__,
263               library_name,
264               crazy_context_get_error(context));
265     return false;
266   }
267
268   // Release library object to keep it alive after the function returns.
269   library.Release();
270
271   s_lib_info_fields.SetLoadInfo(
272       env, lib_info_obj, info.load_address, info.load_size);
273   LOG_INFO("%s: Success loading library %s", __FUNCTION__, library_name);
274   return true;
275 }
276
277 // Used for opening the library in a regular file.
278 class FileLibraryOpener {
279  public:
280   bool Open(
281       crazy_library_t** library,
282       const char* library_name,
283       crazy_context_t* context) const;
284 };
285
286 bool FileLibraryOpener::Open(
287     crazy_library_t** library,
288     const char* library_name,
289     crazy_context_t* context) const {
290   if (!crazy_library_open(library, library_name, context)) {
291     LOG_ERROR("%s: Could not open %s: %s",
292               __FUNCTION__,
293               library_name,
294               crazy_context_get_error(context));
295     return false;
296   }
297   return true;
298 }
299
300 // Used for opening the library in a zip file.
301 class ZipLibraryOpener {
302  public:
303   explicit ZipLibraryOpener(const char* zip_file) : zip_file_(zip_file) {}
304   bool Open(
305       crazy_library_t** library,
306       const char* library_name,
307       crazy_context_t* context) const;
308  private:
309   const char* zip_file_;
310 };
311
312 bool ZipLibraryOpener::Open(
313     crazy_library_t** library,
314     const char* library_name,
315     crazy_context_t* context) const {
316   if (!crazy_library_open_in_zip_file(
317           library, zip_file_, library_name, context)) {
318      LOG_ERROR("%s: Could not open %s in zip file %s: %s",
319                __FUNCTION__, library_name, zip_file_,
320                crazy_context_get_error(context));
321      return false;
322   }
323   return true;
324 }
325
326 }  // unnamed namespace
327
328 // Load a library with the chromium linker. This will also call its
329 // JNI_OnLoad() method, which shall register its methods. Note that
330 // lazy native method resolution will _not_ work after this, because
331 // Dalvik uses the system's dlsym() which won't see the new library,
332 // so explicit registration is mandatory.
333 // |env| is the current JNI environment handle.
334 // |clazz| is the static class handle for org.chromium.base.Linker,
335 // and is ignored here.
336 // |library_name| is the library name (e.g. libfoo.so).
337 // |load_address| is an explicit load address.
338 // |library_info| is a LibInfo handle used to communicate information
339 // with the Java side.
340 // Return true on success.
341 jboolean LoadLibrary(JNIEnv* env,
342                      jclass clazz,
343                      jstring library_name,
344                      jlong load_address,
345                      jobject lib_info_obj) {
346   String lib_name(env, library_name);
347   FileLibraryOpener opener;
348   return GenericLoadLibrary(
349       env, lib_name.c_str(),
350       static_cast<size_t>(load_address), lib_info_obj, opener);
351 }
352
353 // Load a library from a zipfile with the chromium linker. The
354 // library in the zipfile must be uncompressed and page aligned.
355 // The basename of the library is given. The library is expected
356 // to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the
357 // same as the abi for this linker. The "crazy." prefix is included
358 // so that the Android Package Manager doesn't extract the library into
359 // /data/app-lib.
360 //
361 // Loading the library will also call its JNI_OnLoad() method, which
362 // shall register its methods. Note that lazy native method resolution
363 // will _not_ work after this, because Dalvik uses the system's dlsym()
364 // which won't see the new library, so explicit registration is mandatory.
365 //
366 // |env| is the current JNI environment handle.
367 // |clazz| is the static class handle for org.chromium.base.Linker,
368 // and is ignored here.
369 // |zipfile_name| is the filename of the zipfile containing the library.
370 // |library_name| is the library base name (e.g. libfoo.so).
371 // |load_address| is an explicit load address.
372 // |library_info| is a LibInfo handle used to communicate information
373 // with the Java side.
374 // Returns true on success.
375 jboolean LoadLibraryInZipFile(JNIEnv* env,
376                               jclass clazz,
377                               jstring zipfile_name,
378                               jstring library_name,
379                               jlong load_address,
380                               jobject lib_info_obj) {
381   String zipfile_name_str(env, zipfile_name);
382   String lib_name(env, library_name);
383   ZipLibraryOpener opener(zipfile_name_str.c_str());
384   return GenericLoadLibrary(
385       env, lib_name.c_str(),
386       static_cast<size_t>(load_address), lib_info_obj, opener);
387 }
388
389 // Enable the fallback due to lack of support for mapping the APK file with
390 // executable permission in the crazy linker.
391 //
392 // |env| is the current JNI environment handle and is ignored here.
393 // |clazz| is the static class handle for org.chromium.base.Linker,
394 // and is ignored here.
395 void EnableNoMapExecSupportFallback(JNIEnv* env, jclass clazz) {
396   crazy_context_t* context = GetCrazyContext();
397   crazy_context_set_no_map_exec_support_fallback_enabled(context, true);
398 }
399
400 // Class holding the Java class and method ID for the Java side Linker
401 // postCallbackOnMainThread method.
402 struct JavaCallbackBindings_class {
403   jclass clazz;
404   jmethodID method_id;
405
406   // Initialize an instance.
407   bool Init(JNIEnv* env, jclass linker_class) {
408     clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class));
409     return InitStaticMethodId(env,
410                               linker_class,
411                               "postCallbackOnMainThread",
412                               "(J)V",
413                               &method_id);
414   }
415 };
416
417 static JavaCallbackBindings_class s_java_callback_bindings;
418
419 // Designated receiver function for callbacks from Java. Its name is known
420 // to the Java side.
421 // |env| is the current JNI environment handle and is ignored here.
422 // |clazz| is the static class handle for org.chromium.base.Linker,
423 // and is ignored here.
424 // |arg| is a pointer to an allocated crazy_callback_t, deleted after use.
425 void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) {
426   crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg);
427
428   LOG_INFO("%s: Called back from java with handler %p, opaque %p",
429            __FUNCTION__, callback->handler, callback->opaque);
430
431   crazy_callback_run(callback);
432   delete callback;
433 }
434
435 // Request a callback from Java. The supplied crazy_callback_t is valid only
436 // for the duration of this call, so we copy it to a newly allocated
437 // crazy_callback_t and then call the Java side's postCallbackOnMainThread.
438 // This will call back to to our RunCallbackOnUiThread some time
439 // later on the UI thread.
440 // |callback_request| is a crazy_callback_t.
441 // |poster_opaque| is unused.
442 // Returns true if the callback request succeeds.
443 static bool PostForLaterExecution(crazy_callback_t* callback_request,
444                                   void* poster_opaque UNUSED) {
445   crazy_context_t* context = GetCrazyContext();
446
447   JavaVM* vm;
448   int minimum_jni_version;
449   crazy_context_get_java_vm(context,
450                             reinterpret_cast<void**>(&vm),
451                             &minimum_jni_version);
452
453   // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own.
454   JNIEnv* env;
455   if (JNI_OK != vm->GetEnv(
456       reinterpret_cast<void**>(&env), minimum_jni_version)) {
457     LOG_ERROR("Could not create JNIEnv");
458     return false;
459   }
460
461   // Copy the callback; the one passed as an argument may be temporary.
462   crazy_callback_t* callback = new crazy_callback_t();
463   *callback = *callback_request;
464
465   LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
466            __FUNCTION__, callback->handler, callback->opaque);
467
468   jlong arg = static_cast<jlong>(reinterpret_cast<uintptr_t>(callback));
469
470   env->CallStaticVoidMethod(
471       s_java_callback_bindings.clazz, s_java_callback_bindings.method_id, arg);
472
473   // Back out and return false if we encounter a JNI exception.
474   if (env->ExceptionCheck() == JNI_TRUE) {
475     env->ExceptionDescribe();
476     env->ExceptionClear();
477     delete callback;
478     return false;
479   }
480
481   return true;
482 }
483
484 jboolean CreateSharedRelro(JNIEnv* env,
485                            jclass clazz,
486                            jstring library_name,
487                            jlong load_address,
488                            jobject lib_info_obj) {
489   String lib_name(env, library_name);
490
491   LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str());
492
493   if (!IsValidAddress(load_address)) {
494     LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__, load_address);
495     return false;
496   }
497
498   ScopedLibrary library;
499   if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
500     LOG_ERROR("%s: Could not find %s", __FUNCTION__, lib_name.c_str());
501     return false;
502   }
503
504   crazy_context_t* context = GetCrazyContext();
505   size_t relro_start = 0;
506   size_t relro_size = 0;
507   int relro_fd = -1;
508
509   if (!crazy_library_create_shared_relro(library.Get(),
510                                          context,
511                                          static_cast<size_t>(load_address),
512                                          &relro_start,
513                                          &relro_size,
514                                          &relro_fd)) {
515     LOG_ERROR("%s: Could not create shared RELRO sharing for %s: %s\n",
516               __FUNCTION__,
517               lib_name.c_str(),
518               crazy_context_get_error(context));
519     return false;
520   }
521
522   s_lib_info_fields.SetRelroInfo(
523       env, lib_info_obj, relro_start, relro_size, relro_fd);
524   return true;
525 }
526
527 jboolean UseSharedRelro(JNIEnv* env,
528                         jclass clazz,
529                         jstring library_name,
530                         jobject lib_info_obj) {
531   String lib_name(env, library_name);
532
533   LOG_INFO("%s: called for %s, lib_info_ref=%p",
534            __FUNCTION__,
535            lib_name.c_str(),
536            lib_info_obj);
537
538   ScopedLibrary library;
539   if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
540     LOG_ERROR("%s: Could not find %s", __FUNCTION__, lib_name.c_str());
541     return false;
542   }
543
544   crazy_context_t* context = GetCrazyContext();
545   size_t relro_start = 0;
546   size_t relro_size = 0;
547   int relro_fd = -1;
548   s_lib_info_fields.GetRelroInfo(
549       env, lib_info_obj, &relro_start, &relro_size, &relro_fd);
550
551   LOG_INFO("%s: library=%s relro start=%p size=%p fd=%d",
552            __FUNCTION__,
553            lib_name.c_str(),
554            (void*)relro_start,
555            (void*)relro_size,
556            relro_fd);
557
558   if (!crazy_library_use_shared_relro(
559            library.Get(), context, relro_start, relro_size, relro_fd)) {
560     LOG_ERROR("%s: Could not use shared RELRO for %s: %s",
561               __FUNCTION__,
562               lib_name.c_str(),
563               crazy_context_get_error(context));
564     return false;
565   }
566
567   LOG_INFO("%s: Library %s using shared RELRO section!",
568            __FUNCTION__,
569            lib_name.c_str());
570
571   return true;
572 }
573
574 jboolean CanUseSharedRelro(JNIEnv* env, jclass clazz) {
575   return crazy_system_can_share_relro();
576 }
577
578 jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) {
579   void* address =
580       mmap(NULL, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
581   if (address == MAP_FAILED) {
582     LOG_INFO("%s: Random base load address not determinable\n", __FUNCTION__);
583     return 0;
584   }
585   munmap(address, bytes);
586   LOG_INFO("%s: Random base load address is %p\n", __FUNCTION__, address);
587   return static_cast<jlong>(reinterpret_cast<uintptr_t>(address));
588 }
589
590 // Get the full path of a library in the zip file
591 // (lib/<abi>/crazy.<lib_name>).
592 //
593 // |env| is the current JNI environment handle.
594 // |clazz| is the static class handle which is not used here.
595 // |lib_name| is the library base name.
596 // Returns the full path (or empty string on failure).
597 jstring GetLibraryFilePathInZipFile(JNIEnv* env,
598                                     jclass clazz,
599                                     jstring lib_name) {
600   String lib_name_str(env, lib_name);
601   const char* lib_name_c_str = lib_name_str.c_str();
602   char buffer[kMaxFilePathLengthInZip + 1];
603   if (crazy_library_file_path_in_zip_file(
604           lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) {
605     LOG_ERROR("%s: Failed to get full filename for library '%s'",
606               __FUNCTION__, lib_name_c_str);
607     buffer[0] = '\0';
608   }
609   return env->NewStringUTF(buffer);
610 }
611
612 // Check whether the device supports mapping the APK file with executable
613 // permission.
614 //
615 // |env| is the current JNI environment handle.
616 // |clazz| is the static class handle which is not used here.
617 // |apkfile_name| is the filename of the APK.
618 // Returns true if supported.
619 jboolean CheckMapExecSupport(JNIEnv* env, jclass clazz, jstring apkfile_name) {
620   String apkfile_name_str(env, apkfile_name);
621   const char* apkfile_name_c_str = apkfile_name_str.c_str();
622
623   int fd = open(apkfile_name_c_str, O_RDONLY);
624   if (fd == -1) {
625     LOG_ERROR("%s: Failed to open %s\n", __FUNCTION__, apkfile_name_c_str);
626     return false;
627   }
628
629   LOG_INFO(
630       "%s: Memory mapping the first page of %s with executable permissions\n",
631       __FUNCTION__, apkfile_name_c_str);
632   void* address = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_PRIVATE, fd, 0);
633
634   jboolean status;
635   if (address == MAP_FAILED) {
636     status = false;
637   } else {
638     status = true;
639     munmap(address, PAGE_SIZE);
640   }
641
642   close(fd);
643
644   LOG_INFO("%s: %s\n", __FUNCTION__, status ? "Supported" : "NOT supported");
645   return status;
646 }
647
648 // Check whether a library is page aligned and uncompressed in the APK file.
649 //
650 // |env| is the current JNI environment handle.
651 // |clazz| is the static class handle which is not used here.
652 // |apkfile_name| is the filename of the APK.
653 // |library_name| is the library base name.
654 // Returns true if page aligned and uncompressed.
655 jboolean CheckLibraryIsMappableInApk(JNIEnv* env, jclass clazz,
656                                      jstring apkfile_name,
657                                      jstring library_name) {
658   String apkfile_name_str(env, apkfile_name);
659   const char* apkfile_name_c_str = apkfile_name_str.c_str();
660   String library_name_str(env, library_name);
661   const char* library_name_c_str = library_name_str.c_str();
662
663   LOG_INFO("%s: Checking if %s is page-aligned and uncompressed in %s\n",
664            __FUNCTION__, library_name_c_str, apkfile_name_c_str);
665   jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file(
666       apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS;
667   LOG_INFO("%s: %s\n", __FUNCTION__, aligned ? "Aligned" : "NOT aligned");
668
669   return mappable;
670 }
671
672 const JNINativeMethod kNativeMethods[] = {
673     {"nativeLoadLibrary",
674      "("
675      "Ljava/lang/String;"
676      "J"
677      "Lorg/chromium/base/library_loader/Linker$LibInfo;"
678      ")"
679      "Z",
680      reinterpret_cast<void*>(&LoadLibrary)},
681     {"nativeLoadLibraryInZipFile",
682      "("
683      "Ljava/lang/String;"
684      "Ljava/lang/String;"
685      "J"
686      "Lorg/chromium/base/library_loader/Linker$LibInfo;"
687      ")"
688      "Z",
689      reinterpret_cast<void*>(&LoadLibraryInZipFile)},
690     {"nativeEnableNoMapExecSupportFallback",
691      "("
692      ")"
693      "V",
694      reinterpret_cast<void*>(&EnableNoMapExecSupportFallback)},
695     {"nativeRunCallbackOnUiThread",
696      "("
697      "J"
698      ")"
699      "V",
700      reinterpret_cast<void*>(&RunCallbackOnUiThread)},
701     {"nativeCreateSharedRelro",
702      "("
703      "Ljava/lang/String;"
704      "J"
705      "Lorg/chromium/base/library_loader/Linker$LibInfo;"
706      ")"
707      "Z",
708      reinterpret_cast<void*>(&CreateSharedRelro)},
709     {"nativeUseSharedRelro",
710      "("
711      "Ljava/lang/String;"
712      "Lorg/chromium/base/library_loader/Linker$LibInfo;"
713      ")"
714      "Z",
715      reinterpret_cast<void*>(&UseSharedRelro)},
716     {"nativeCanUseSharedRelro",
717      "("
718      ")"
719      "Z",
720      reinterpret_cast<void*>(&CanUseSharedRelro)},
721     {"nativeGetRandomBaseLoadAddress",
722      "("
723      "J"
724      ")"
725      "J",
726      reinterpret_cast<void*>(&GetRandomBaseLoadAddress)},
727     {"nativeGetLibraryFilePathInZipFile",
728      "("
729      "Ljava/lang/String;"
730      ")"
731      "Ljava/lang/String;",
732      reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)},
733     {"nativeCheckMapExecSupport",
734      "("
735      "Ljava/lang/String;"
736      ")"
737      "Z",
738      reinterpret_cast<void*>(&CheckMapExecSupport)},
739     {"nativeCheckLibraryIsMappableInApk",
740      "("
741      "Ljava/lang/String;"
742      "Ljava/lang/String;"
743      ")"
744      "Z",
745      reinterpret_cast<void*>(&CheckLibraryIsMappableInApk)}, };
746
747 }  // namespace
748
749 // JNI_OnLoad() hook called when the linker library is loaded through
750 // the regular System.LoadLibrary) API. This shall save the Java VM
751 // handle and initialize LibInfo fields.
752 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
753   LOG_INFO("%s: Entering", __FUNCTION__);
754   // Get new JNIEnv
755   JNIEnv* env;
756   if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) {
757     LOG_ERROR("Could not create JNIEnv");
758     return -1;
759   }
760
761   // Register native methods.
762   jclass linker_class;
763   if (!InitClassReference(env,
764                           "org/chromium/base/library_loader/Linker",
765                           &linker_class))
766     return -1;
767
768   LOG_INFO("%s: Registering native methods", __FUNCTION__);
769   env->RegisterNatives(linker_class,
770                        kNativeMethods,
771                        sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
772
773   // Find LibInfo field ids.
774   LOG_INFO("%s: Caching field IDs", __FUNCTION__);
775   if (!s_lib_info_fields.Init(env)) {
776     return -1;
777   }
778
779   // Resolve and save the Java side Linker callback class and method.
780   LOG_INFO("%s: Resolving callback bindings", __FUNCTION__);
781   if (!s_java_callback_bindings.Init(env, linker_class)) {
782     return -1;
783   }
784
785   // Save JavaVM* handle into context.
786   crazy_context_t* context = GetCrazyContext();
787   crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4);
788
789   // Register the function that the crazy linker can call to post code
790   // for later execution.
791   crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL);
792
793   LOG_INFO("%s: Done", __FUNCTION__);
794   return JNI_VERSION_1_4;
795 }