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.
5 package org.chromium.content.app;
7 import android.text.TextUtils;
8 import android.util.Log;
10 import org.chromium.base.JNINamespace;
11 import org.chromium.base.SysUtils;
12 import org.chromium.content.common.CommandLine;
13 import org.chromium.content.common.ProcessInitException;
14 import org.chromium.content.common.ResultCodes;
15 import org.chromium.content.common.TraceEvent;
18 * This class provides functionality to load and register the native libraries.
19 * Callers are allowed to separate loading the libraries from initializing them.
20 * This may be an advantage for Android Webview, where the libraries can be loaded
21 * by the zygote process, but then needs per process initialization after the
22 * application processes are forked from the zygote process.
24 * The libraries may be loaded and initialized from any thread. Synchronization
25 * primitives are used to ensure that overlapping requests from different
26 * threads are handled sequentially.
28 * See also content/app/android/library_loader_hooks.cc, which contains
29 * the native counterpart to this class.
31 @JNINamespace("content")
32 public class LibraryLoader {
33 private static final String TAG = "LibraryLoader";
35 // Guards all access to the libraries
36 private static final Object sLock = new Object();
38 // One-way switch becomes true when the libraries are loaded.
39 private static boolean sLoaded = false;
41 // One-way switch becomes true when the libraries are initialized (
42 // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
43 // library_loader_hooks.cc).
44 private static boolean sInitialized = false;
46 // TODO(cjhopman): Remove this once it's unused.
48 * Doesn't do anything.
51 public static void setLibraryToLoad(String library) {
55 * This method blocks until the library is fully loaded and initialized.
57 public static void ensureInitialized() throws ProcessInitException {
58 synchronized (sLock) {
60 // Already initialized, nothing to do.
64 initializeAlreadyLocked(CommandLine.getJavaSwitchesOrNull());
69 * Checks if library is fully loaded and initialized.
71 public static boolean isInitialized() {
72 synchronized (sLock) {
78 * Loads the library and blocks until the load completes. The caller is responsible
79 * for subsequently calling ensureInitialized().
80 * May be called on any thread, but should only be called once. Note the thread
81 * this is called on will be the thread that runs the native code's static initializers.
82 * See the comment in doInBackground() for more considerations on this.
84 * @throws ProcessInitException if the native library failed to load.
86 public static void loadNow() throws ProcessInitException {
87 synchronized (sLock) {
94 * initializes the library here and now: must be called on the thread that the
95 * native will call its "main" thread. The library must have previously been
96 * loaded with loadNow.
97 * @param initCommandLine The command line arguments that native command line will
98 * be initialized with.
100 static void initialize(String[] initCommandLine) throws ProcessInitException {
101 synchronized (sLock) {
102 initializeAlreadyLocked(initCommandLine);
107 // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
108 private static void loadAlreadyLocked() throws ProcessInitException {
111 assert !sInitialized;
113 long startTime = System.currentTimeMillis();
114 boolean useContentLinker = Linker.isUsed();
116 if (useContentLinker)
117 Linker.prepareLibraryLoad();
119 for (String library : NativeLibraries.libraries) {
120 Log.i(TAG, "Loading: " + library);
121 if (useContentLinker)
122 Linker.loadLibrary(library);
124 System.loadLibrary(library);
126 if (useContentLinker)
127 Linker.finishLibraryLoad();
128 long stopTime = System.currentTimeMillis();
129 Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
130 stopTime - startTime,
135 } catch (UnsatisfiedLinkError e) {
136 throw new ProcessInitException(ResultCodes.RESULT_CODE_NATIVE_LIBRARY_LOAD_FAILED, e);
141 // Invoke content::LibraryLoaded in library_loader_hooks.cc
142 private static void initializeAlreadyLocked(String[] initCommandLine)
143 throws ProcessInitException {
147 int resultCode = nativeLibraryLoaded(initCommandLine);
148 if (resultCode != 0) {
149 Log.e(TAG, "error calling nativeLibraryLoaded");
150 throw new ProcessInitException(resultCode);
152 // From this point on, native code is ready to use and checkIsReady()
153 // shouldn't complain from now on (and in fact, it's used by the
156 CommandLine.enableNativeProxy();
157 TraceEvent.setEnabledToMatchNative();
158 // Record histogram for the content linker.
160 nativeRecordContentAndroidLinkerHistogram(Linker.loadAtFixedAddressFailed(),
161 SysUtils.isLowEndDevice());
164 // This is the only method that is registered during System.loadLibrary. We then call it
165 // to register everything else. This process is called "initialization".
166 // This method will be mapped (by generated code) to the LibraryLoaded
167 // definition in content/app/android/library_loader_hooks.cc.
169 // Return 0 on success, otherwise return the error code from
170 // content/public/common/result_codes.h.
171 private static native int nativeLibraryLoaded(String[] initCommandLine);
173 // Method called to record statistics about the content linker operation,
174 // i.e. whether the library failed to be loaded at a fixed address, and
175 // whether the device is 'low-memory'.
176 private static native void nativeRecordContentAndroidLinkerHistogram(
177 boolean loadedAtFixedAddressFailed,
178 boolean isLowMemoryDevice);