| Index: content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java b/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
|
| index 0facd0b31ebae5194207e36db3a03283334bb954..5791d56bbcc8dc51a5b44f6f053e499d863e1426 100644
|
| --- a/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
|
| +++ b/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
|
| @@ -15,13 +15,14 @@ import org.chromium.content.common.TraceEvent;
|
|
|
| /**
|
| * This class provides functionality to load and register the native library.
|
| - * In most cases, users will call ensureInitialized() from their main thread
|
| - * (only) which ensures a post condition that the library is loaded,
|
| - * initialized, and ready to use.
|
| - * Optionally, an application may optimize startup be calling loadNow early on,
|
| - * from a background thread, and then on completion of that method it must call
|
| - * ensureInitialized() on the main thread before it tries to access any native
|
| - * code.
|
| + * Callers are allowed to separate loading the library from initializing it.
|
| + * This may be an advantage for Android Webview, where the library can be loaded
|
| + * by the zygote process, but then needs per process initialization after the
|
| + * application processes are forked from the zygote process.
|
| + *
|
| + * The library may be loaded and initialized from any thread. Synchronization
|
| + * primitives are used to ensure that overlapping requests from different
|
| + * threads are handled sequentially.
|
| */
|
| @JNINamespace("content")
|
| public class LibraryLoader {
|
| @@ -30,7 +31,7 @@ public class LibraryLoader {
|
| private static String sLibrary = null;
|
|
|
| // This object's lock guards sLoaded assignment and also the library load.
|
| - private static Object sLoadedLock = new Object();
|
| + private static Object sLoadLock = new Object();
|
| private static Boolean sLoaded = false;
|
|
|
| private static boolean sInitialized = false;
|
| @@ -57,19 +58,20 @@ public class LibraryLoader {
|
| }
|
|
|
| /**
|
| - * This method blocks until the library is fully loaded and initialized;
|
| - * must be called on the thread that the native will call its "main" thread.
|
| + * This method blocks until the library is fully loaded and initialized.
|
| */
|
| public static void ensureInitialized() throws ProcessInitException {
|
| - checkThreadUsage();
|
| - if (sInitialized) {
|
| - // Already initialized, nothing to do.
|
| - return;
|
| + synchronized (sLoadLock) {
|
| + if (sInitialized) {
|
| + // Already initialized, nothing to do.
|
| + return;
|
| + }
|
| + loadAlreadyLocked();
|
| + initializeAlreadyLocked(CommandLine.getJavaSwitchesOrNull());
|
| }
|
| - loadNow();
|
| - initializeOnMainThread();
|
| }
|
|
|
| +
|
| /**
|
| * Loads the library and blocks until the load completes. The caller is responsible
|
| * for subsequently calling ensureInitialized().
|
| @@ -80,24 +82,12 @@ public class LibraryLoader {
|
| * @throws ProcessInitException if the native library failed to load.
|
| */
|
| public static void loadNow() throws ProcessInitException {
|
| - if (sLibrary == null) {
|
| - assert false : "No library specified to load. Call setLibraryToLoad before first.";
|
| - }
|
| - try {
|
| - synchronized (sLoadedLock) {
|
| - if (!sLoaded) {
|
| - assert !sInitialized;
|
| - 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);
|
| + synchronized (sLoadLock) {
|
| + 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
|
| @@ -105,12 +95,37 @@ public class LibraryLoader {
|
| * @param initCommandLine The command line arguments that native command line will
|
| * be initialized with.
|
| */
|
| - static void initializeOnMainThread(String[] initCommandLine) throws ProcessInitException {
|
| - checkThreadUsage();
|
| + static void initialize(String[] initCommandLine) throws ProcessInitException {
|
| + synchronized (sLoadLock) {
|
| + initializeAlreadyLocked(initCommandLine);
|
| + }
|
| + }
|
| +
|
| +
|
| + private static void loadAlreadyLocked() throws ProcessInitException {
|
| + if (sLibrary == null) {
|
| + assert false : "No library specified to load. Call setLibraryToLoad before first.";
|
| + }
|
| + try {
|
| + if (!sLoaded) {
|
| + assert !sInitialized;
|
| + 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);
|
| + }
|
| + }
|
| +
|
| +
|
| + private static void initializeAlreadyLocked(String[] initCommandLine)
|
| + throws ProcessInitException {
|
| if (sInitialized) {
|
| return;
|
| }
|
| - int resultCode = nativeLibraryLoadedOnMainThread(initCommandLine);
|
| + int resultCode = nativeLibraryLoaded(initCommandLine);
|
| if (resultCode != 0) {
|
| Log.e(TAG, "error calling nativeLibraryLoadedOnMainThread");
|
| throw new ProcessInitException(resultCode);
|
| @@ -123,40 +138,9 @@ public class LibraryLoader {
|
| TraceEvent.setEnabledToMatchNative();
|
| }
|
|
|
| - static private void initializeOnMainThread() throws ProcessInitException {
|
| - checkThreadUsage();
|
| - if (!sInitialized) {
|
| - initializeOnMainThread(CommandLine.getJavaSwitchesOrNull());
|
| - }
|
| - }
|
| -
|
| - private LibraryLoader() {
|
| - }
|
| -
|
| - // This asserts that calls to ensureInitialized() will happen from the
|
| - // same thread.
|
| - private static Object sCheckThreadLock = new Object();
|
| - private static Thread sMyThread;
|
| - private static void checkThreadUsage() {
|
| - Thread currentThread = Thread.currentThread();
|
| - synchronized (sCheckThreadLock) {
|
| - if (sMyThread == null) {
|
| - sMyThread = currentThread;
|
| - } else {
|
| - if (sMyThread != currentThread) {
|
| - Log.e(TAG, "Threading violation detected. My thread=" + sMyThread + " id=" +
|
| - sMyThread.getId() + " but I'm being accessed from thread=" +
|
| - currentThread + " id=" + currentThread.getId());
|
| - assert false;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - // This is the only method that is registered during System.loadLibrary, as it
|
| - // may happen on a different thread. We then call it on the main thread to register
|
| - // everything else.
|
| + // This is the only method that is registered during System.loadLibrary. We then call it
|
| + // to register everything else.
|
| // Return 0 on success, otherwise return the error code from
|
| // content/public/common/result_codes.h.
|
| - private static native int nativeLibraryLoadedOnMainThread(String[] initCommandLine);
|
| + private static native int nativeLibraryLoaded(String[] initCommandLine);
|
| }
|
|
|