// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.content.app;
import android.text.TextUtils;
import android.util.Log;
import org.chromium.base.JNINamespace;
import org.chromium.content.common.CommandLine;
import org.chromium.content.common.ProcessInitException;
import org.chromium.content.common.ResultCodes;
import org.chromium.content.common.TraceEvent;
/**
* This class provides functionality to load and register the native libraries.
* Callers are allowed to separate loading the libraries from initializing them.
* This may be an advantage for Android Webview, where the libraries can be loaded
* by the zygote process, but then needs per process initialization after the
* application processes are forked from the zygote process.
*
* The libraries may be loaded and initialized from any thread. Synchronization
* primitives are used to ensure that overlapping requests from different
* threads are handled sequentially.
*
* See also content/app/android/library_loader_hooks.cc, which contains
* the native counterpart to this class.
*/
@JNINamespace("content")
public class LibraryLoader {
private static final String TAG = "LibraryLoader";
// Guards all access to the libraries
private static final Object sLock = new Object();
// One-way switch becomes true when the libraries are loaded.
private static boolean sLoaded = false;
// One-way switch becomes true when the libraries are initialized (
// by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
// library_loader_hooks.cc).
private static boolean sInitialized = false;
// TODO(cjhopman): Remove this once it's unused.
/**
* Doesn't do anything.
*/
@Deprecated
public static void setLibraryToLoad(String library) {
}
/**
* This method blocks until the library is fully loaded and initialized.
*/
public static void ensureInitialized() throws ProcessInitException {
synchronized (sLock) {
if (sInitialized) {
// Already initialized, nothing to do.
return;
}
loadAlreadyLocked();
initializeAlreadyLocked(CommandLine.getJavaSwitchesOrNull());
}
}
/**
* Loads the library and blocks until the load completes. The caller is responsible
* for subsequently calling ensureInitialized().
* May be called on any thread, but should only be called once. Note the thread
* this is called on will be the thread that runs the native code's static initializers.
* See the comment in doInBackground() for more considerations on this.
*
* @throws ProcessInitException if the native library failed to load.
*/
public static void loadNow() throws ProcessInitException {
synchronized (sLock) {
loadAlreadyLocked();
}
}
/**
* initializes the library here and now: must be called on the thread that the
* native will call its "main" thread. The library must have previously been
* loaded with loadNow.
* @param initCommandLine The command line arguments that native command line will
* be initialized with.
*/
static void initialize(String[] initCommandLine) throws ProcessInitException {
synchronized (sLock) {
initializeAlreadyLocked(initCommandLine);
}
}
// Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
private static void loadAlreadyLocked() throws ProcessInitException {
try {
if (!sLoaded) {
assert !sInitialized;
for (String sLibrary : NativeLibraries.libraries) {
Log.i(TAG, "loading: " + sLibrary);
System.loadLibrary(sLibrary);
Log.i(TAG, "loaded: " + sLibrary);
}
sLoaded = true;
}
} catch (UnsatisfiedLinkError e) {
throw new ProcessInitException(ResultCodes.RESULT_CODE_NATIVE_LIBRARY_LOAD_FAILED, e);
}
}
// Invoke content::LibraryLoaded in library_loader_hooks.cc
private static void initializeAlreadyLocked(String[] initCommandLine)
throws ProcessInitException {
if (sInitialized) {
return;
}
int resultCode = nativeLibraryLoaded(initCommandLine);
if (resultCode != 0) {
Log.e(TAG, "error calling nativeLibraryLoaded");
throw new ProcessInitException(resultCode);
}
// From this point on, native code is ready to use and checkIsReady()
// shouldn't complain from now on (and in fact, it's used by the
// following calls).
sInitialized = true;
CommandLine.enableNativeProxy();
TraceEvent.setEnabledToMatchNative();
}
// This is the only method that is registered during System.loadLibrary. We then call it
// to register everything else. This process is called "initialization".
// This method will be mapped (by generated code) to the LibraryLoaded
// definition in content/app/android/library_loader_hooks.cc.
//
// Return 0 on success, otherwise return the error code from
// content/public/common/result_codes.h.
private static native int nativeLibraryLoaded(String[] initCommandLine);
}