| 1 | // Copyright (c) 2012 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 | package org.chromium.content.app; |
| 6 | |
| 7 | import android.text.TextUtils; |
| 8 | import android.util.Log; |
| 9 | |
| 10 | import org.chromium.base.JNINamespace; |
| 11 | import org.chromium.content.common.CommandLine; |
| 12 | import org.chromium.content.common.ProcessInitException; |
| 13 | import org.chromium.content.common.ResultCodes; |
| 14 | import org.chromium.content.common.TraceEvent; |
| 15 | |
| 16 | /** |
| 17 | * This class provides functionality to load and register the native libraries. |
| 18 | * Callers are allowed to separate loading the libraries from initializing them. |
| 19 | * This may be an advantage for Android Webview, where the libraries can be loaded |
| 20 | * by the zygote process, but then needs per process initialization after the |
| 21 | * application processes are forked from the zygote process. |
| 22 | * |
| 23 | * The libraries may be loaded and initialized from any thread. Synchronization |
| 24 | * primitives are used to ensure that overlapping requests from different |
| 25 | * threads are handled sequentially. |
| 26 | * |
| 27 | * See also content/app/android/library_loader_hooks.cc, which contains |
| 28 | * the native counterpart to this class. |
| 29 | */ |
| 30 | @JNINamespace("content") |
| 31 | public class LibraryLoader { |
| 32 | private static final String TAG = "LibraryLoader"; |
| 33 | |
| 34 | // Guards all access to the libraries |
| 35 | private static final Object sLock = new Object(); |
| 36 | |
| 37 | // One-way switch becomes true when the libraries are loaded. |
| 38 | private static boolean sLoaded = false; |
| 39 | |
| 40 | // One-way switch becomes true when the libraries are initialized ( |
| 41 | // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in |
| 42 | // library_loader_hooks.cc). |
| 43 | private static boolean sInitialized = false; |
| 44 | |
| 45 | // TODO(cjhopman): Remove this once it's unused. |
| 46 | /** |
| 47 | * Doesn't do anything. |
| 48 | */ |
| 49 | @Deprecated |
| 50 | public static void setLibraryToLoad(String library) { |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * This method blocks until the library is fully loaded and initialized. |
| 55 | */ |
| 56 | public static void ensureInitialized() throws ProcessInitException { |
| 57 | synchronized (sLock) { |
| 58 | if (sInitialized) { |
| 59 | // Already initialized, nothing to do. |
| 60 | return; |
| 61 | } |
| 62 | loadAlreadyLocked(); |
| 63 | initializeAlreadyLocked(CommandLine.getJavaSwitchesOrNull()); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | /** |
| 68 | * Checks if library is fully loaded and initialized. |
| 69 | */ |
| 70 | public static boolean isInitialized() { |
| 71 | synchronized (sLock) { |
| 72 | return sInitialized; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | /** |
| 77 | * Loads the library and blocks until the load completes. The caller is responsible |
| 78 | * for subsequently calling ensureInitialized(). |
| 79 | * May be called on any thread, but should only be called once. Note the thread |
| 80 | * this is called on will be the thread that runs the native code's static initializers. |
| 81 | * See the comment in doInBackground() for more considerations on this. |
| 82 | * |
| 83 | * @throws ProcessInitException if the native library failed to load. |
| 84 | */ |
| 85 | public static void loadNow() throws ProcessInitException { |
| 86 | synchronized (sLock) { |
| 87 | loadAlreadyLocked(); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | |
| 92 | /** |
| 93 | * initializes the library here and now: must be called on the thread that the |
| 94 | * native will call its "main" thread. The library must have previously been |
| 95 | * loaded with loadNow. |
| 96 | * @param initCommandLine The command line arguments that native command line will |
| 97 | * be initialized with. |
| 98 | */ |
| 99 | static void initialize(String[] initCommandLine) throws ProcessInitException { |
| 100 | synchronized (sLock) { |
| 101 | initializeAlreadyLocked(initCommandLine); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | |
| 106 | // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code |
| 107 | private static void loadAlreadyLocked() throws ProcessInitException { |
| 108 | try { |
| 109 | if (!sLoaded) { |
| 110 | assert !sInitialized; |
| 111 | for (String sLibrary : NativeLibraries.libraries) { |
| 112 | Log.i(TAG, "loading: " + sLibrary); |
| 113 | System.loadLibrary(sLibrary); |
| 114 | Log.i(TAG, "loaded: " + sLibrary); |
| 115 | } |
| 116 | sLoaded = true; |
| 117 | } |
| 118 | } catch (UnsatisfiedLinkError e) { |
| 119 | throw new ProcessInitException(ResultCodes.RESULT_CODE_NATIVE_LIBRARY_LOAD_FAILED, e); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | |
| 124 | // Invoke content::LibraryLoaded in library_loader_hooks.cc |
| 125 | private static void initializeAlreadyLocked(String[] initCommandLine) |
| 126 | throws ProcessInitException { |
| 127 | if (sInitialized) { |
| 128 | return; |
| 129 | } |
| 130 | int resultCode = nativeLibraryLoaded(initCommandLine); |
| 131 | if (resultCode != 0) { |
| 132 | Log.e(TAG, "error calling nativeLibraryLoaded"); |
| 133 | throw new ProcessInitException(resultCode); |
| 134 | } |
| 135 | // From this point on, native code is ready to use and checkIsReady() |
| 136 | // shouldn't complain from now on (and in fact, it's used by the |
| 137 | // following calls). |
| 138 | sInitialized = true; |
| 139 | CommandLine.enableNativeProxy(); |
| 140 | TraceEvent.setEnabledToMatchNative(); |
| 141 | } |
| 142 | |
| 143 | // This is the only method that is registered during System.loadLibrary. We then call it |
| 144 | // to register everything else. This process is called "initialization". |
| 145 | // This method will be mapped (by generated code) to the LibraryLoaded |
| 146 | // definition in content/app/android/library_loader_hooks.cc. |
| 147 | // |
| 148 | // Return 0 on success, otherwise return the error code from |
| 149 | // content/public/common/result_codes.h. |
| 150 | private static native int nativeLibraryLoaded(String[] initCommandLine); |
| 151 | } |