summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraberent@chromium.org <aberent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-19 20:43:55 +0000
committeraberent@chromium.org <aberent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-19 20:43:55 +0000
commitf4da17db5acfcc233fcd8b5917ed213f4e571477 (patch)
tree2f8c7e91bcddce502ce4307dc4cad3bd3b1c58d2
parent3263a9f3effa35ca44d7d820154b7f871cab77c8 (diff)
downloadchromium_src-f4da17db5acfcc233fcd8b5917ed213f4e571477.zip
chromium_src-f4da17db5acfcc233fcd8b5917ed213f4e571477.tar.gz
chromium_src-f4da17db5acfcc233fcd8b5917ed213f4e571477.tar.bz2
[Android] Allow JNI initialization on background thread
The code used to insist that JNI initialization only happened on the main (UI) thread. This was because it was believed that the static initialization of the Java classes initialized as a result of JNI calls might only work on the UI thread. In practice it seems that none of these Java classes have this requirement, so this seems to have been an unnecessary restriction, and slowed up startup on Chrome for Android. Remove this restriction, but add locks to ensure that only one thread is trying to initialize the JNI at a time. Also change some function names to reflect this change. BUG=214560 Review URL: https://chromiumcodereview.appspot.com/12700011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@189093 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/app/android/library_loader_hooks.cc4
-rw-r--r--content/public/android/java/src/org/chromium/content/app/ChildProcessService.java2
-rw-r--r--content/public/android/java/src/org/chromium/content/app/LibraryLoader.java120
3 files changed, 55 insertions, 71 deletions
diff --git a/content/app/android/library_loader_hooks.cc b/content/app/android/library_loader_hooks.cc
index 213f65e..93a9d07 100644
--- a/content/app/android/library_loader_hooks.cc
+++ b/content/app/android/library_loader_hooks.cc
@@ -35,8 +35,8 @@ base::AtExitManager* g_at_exit_manager = NULL;
namespace content {
-static jint LibraryLoadedOnMainThread(JNIEnv* env, jclass clazz,
- jobjectArray init_command_line) {
+static jint LibraryLoaded(JNIEnv* env, jclass clazz,
+ jobjectArray init_command_line) {
InitNativeCommandLineFromJavaArray(env, init_command_line);
CommandLine* command_line = CommandLine::ForCurrentProcess();
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
index 4729bb7..240cf5b 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java
@@ -130,7 +130,7 @@ public class ChildProcessService extends Service {
mMainThread.wait();
}
}
- LibraryLoader.initializeOnMainThread(mCommandLineParams);
+ LibraryLoader.initialize(mCommandLineParams);
synchronized (mMainThread) {
mLibraryInitialized = true;
mMainThread.notifyAll();
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 0facd0b..5791d56 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);
}