Index: base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java |
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java |
index 2168c21827fddcd17c1d7d2f5de4d0dd17155a62..d68fb4a814a19f1e187fd0afe77a2227b5df40e4 100644 |
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java |
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java |
@@ -8,6 +8,7 @@ import android.content.Context; |
import android.os.SystemClock; |
import android.util.Log; |
+import org.chromium.base.CalledByNative; |
import org.chromium.base.CommandLine; |
import org.chromium.base.JNINamespace; |
import org.chromium.base.TraceEvent; |
@@ -40,41 +41,68 @@ public class LibraryLoader { |
// Guards all access to the libraries |
private static final Object sLock = new Object(); |
+ // The singleton instance of LibraryLoader. |
+ private static LibraryLoader sInstance; |
+ |
// One-way switch becomes true when the libraries are loaded. |
- private static boolean sLoaded = false; |
+ private boolean mLoaded; |
// One-way switch becomes true when the Java command line is switched to |
// native. |
- private static boolean sCommandLineSwitched = false; |
+ private boolean mCommandLineSwitched; |
// 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; |
+ private boolean mInitialized; |
// One-way switches recording attempts to use Relro sharing in the browser. |
// The flags are used to report UMA stats later. |
- private static boolean sIsUsingBrowserSharedRelros = false; |
- private static boolean sLoadAtFixedAddressFailed = false; |
+ private boolean mIsUsingBrowserSharedRelros; |
+ private boolean mLoadAtFixedAddressFailed; |
// One-way switch becomes true if the device supports memory mapping the |
// APK file with executable permissions. |
- private static boolean sMapApkWithExecPermission = false; |
+ private boolean mMapApkWithExecPermission; |
// One-way switch to indicate whether we probe for memory mapping the APK |
// file with executable permissions. We suppress the probe under some |
// conditions. |
// For more, see: |
// https://code.google.com/p/chromium/issues/detail?id=448084 |
- private static boolean sProbeMapApkWithExecPermission = true; |
+ private boolean mProbeMapApkWithExecPermission = true; |
// One-way switch becomes true if the Chromium library was loaded from the |
// APK file directly. |
- private static boolean sLibraryWasLoadedFromApk = false; |
+ private boolean mLibraryWasLoadedFromApk; |
// One-way switch becomes false if the Chromium library should be loaded |
// directly from the APK file but it was compressed or not aligned. |
- private static boolean sLibraryIsMappableInApk = true; |
+ private boolean mLibraryIsMappableInApk = true; |
+ |
+ // The type of process the shared library is loaded in. |
+ private int mLibraryProcessType; |
+ |
+ /** |
+ * @param libraryProcessType the process the shared library is loaded in. refer to |
+ * LibraryProcessType for possible values. |
+ * @return LibraryLoader if existing, otherwise create a new one. |
+ */ |
+ public static LibraryLoader get(int libraryProcessType) throws ProcessInitException { |
+ synchronized (sLock) { |
+ if (sInstance != null) { |
+ if (sInstance.mLibraryProcessType == libraryProcessType) return sInstance; |
+ throw new ProcessInitException( |
+ LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED); |
+ } |
+ sInstance = new LibraryLoader(libraryProcessType); |
+ return sInstance; |
+ } |
+ } |
+ |
+ private LibraryLoader(int libraryProcessType) { |
+ mLibraryProcessType = libraryProcessType; |
+ } |
/** |
* The same as ensureInitialized(null, false), should only be called |
@@ -82,7 +110,7 @@ public class LibraryLoader { |
* |
* @throws ProcessInitException |
*/ |
- public static void ensureInitialized() throws ProcessInitException { |
+ public void ensureInitialized() throws ProcessInitException { |
ensureInitialized(null, false); |
} |
@@ -96,11 +124,11 @@ public class LibraryLoader { |
* @param shouldDeleteFallbackLibraries The flag tells whether the method |
* should delete the fallback libraries or not. |
*/ |
- public static void ensureInitialized( |
+ public void ensureInitialized( |
Context context, boolean shouldDeleteFallbackLibraries) |
throws ProcessInitException { |
synchronized (sLock) { |
- if (sInitialized) { |
+ if (mInitialized) { |
// Already initialized, nothing to do. |
return; |
} |
@@ -114,7 +142,7 @@ public class LibraryLoader { |
*/ |
public static boolean isInitialized() { |
synchronized (sLock) { |
- return sInitialized; |
+ return sInstance != null && sInstance.mInitialized; |
} |
} |
@@ -124,7 +152,7 @@ public class LibraryLoader { |
* |
* @throws ProcessInitException |
*/ |
- public static void loadNow() throws ProcessInitException { |
+ public void loadNow() throws ProcessInitException { |
loadNow(null, false); |
} |
@@ -141,7 +169,7 @@ public class LibraryLoader { |
* |
* @throws ProcessInitException if the native library failed to load. |
*/ |
- public static void loadNow(Context context, boolean shouldDeleteFallbackLibraries) |
+ public void loadNow(Context context, boolean shouldDeleteFallbackLibraries) |
throws ProcessInitException { |
synchronized (sLock) { |
loadAlreadyLocked(context, shouldDeleteFallbackLibraries); |
@@ -153,19 +181,19 @@ public class LibraryLoader { |
* native will call its "main" thread. The library must have previously been |
* loaded with loadNow. |
*/ |
- public static void initialize() throws ProcessInitException { |
+ public void initialize() throws ProcessInitException { |
synchronized (sLock) { |
initializeAlreadyLocked(); |
} |
} |
// Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code |
- private static void loadAlreadyLocked( |
+ private void loadAlreadyLocked( |
Context context, boolean shouldDeleteFallbackLibraries) |
throws ProcessInitException { |
try { |
- if (!sLoaded) { |
- assert !sInitialized; |
+ if (!mLoaded) { |
+ assert !mInitialized; |
long startTime = SystemClock.uptimeMillis(); |
boolean useChromiumLinker = Linker.isUsed(); |
@@ -183,17 +211,17 @@ public class LibraryLoader { |
if (manufacturer != null |
&& manufacturer.toLowerCase(Locale.ENGLISH).contains("samsung")) { |
Log.w(TAG, "Suppressed load from APK support check on this device"); |
- sProbeMapApkWithExecPermission = false; |
+ mProbeMapApkWithExecPermission = false; |
} |
// Check if the device supports memory mapping the APK file |
// with executable permissions. |
if (context != null) { |
apkFilePath = context.getApplicationInfo().sourceDir; |
- if (sProbeMapApkWithExecPermission) { |
- sMapApkWithExecPermission = Linker.checkMapExecSupport(apkFilePath); |
+ if (mProbeMapApkWithExecPermission) { |
+ mMapApkWithExecPermission = Linker.checkMapExecSupport(apkFilePath); |
} |
- if (!sMapApkWithExecPermission && Linker.isInZipFile()) { |
+ if (!mMapApkWithExecPermission && Linker.isInZipFile()) { |
Log.w(TAG, "the no map executable support fallback will be used because" |
+ " memory mapping the APK file with executable permissions is" |
+ " not supported"); |
@@ -222,9 +250,9 @@ public class LibraryLoader { |
if (apkFilePath != null && Linker.isInZipFile()) { |
// The library is in the APK file. |
if (!Linker.checkLibraryIsMappableInApk(apkFilePath, libFilePath)) { |
- sLibraryIsMappableInApk = false; |
+ mLibraryIsMappableInApk = false; |
} |
- if (sLibraryIsMappableInApk || useMapExecSupportFallback) { |
+ if (mLibraryIsMappableInApk || useMapExecSupportFallback) { |
// Load directly from the APK (or use the no map executable |
// support fallback, see crazy_linker_elf_loader.cpp). |
zipFilePath = apkFilePath; |
@@ -251,7 +279,7 @@ public class LibraryLoader { |
// Load the library. |
boolean isLoaded = false; |
if (Linker.isUsingBrowserSharedRelros()) { |
- sIsUsingBrowserSharedRelros = true; |
+ mIsUsingBrowserSharedRelros = true; |
try { |
loadLibrary(zipFilePath, libFilePath); |
isLoaded = true; |
@@ -259,7 +287,7 @@ public class LibraryLoader { |
Log.w(TAG, "Failed to load native library with shared RELRO, " |
+ "retrying without"); |
Linker.disableSharedRelros(); |
- sLoadAtFixedAddressFailed = true; |
+ mLoadAtFixedAddressFailed = true; |
} |
} |
if (!isLoaded) { |
@@ -287,7 +315,7 @@ public class LibraryLoader { |
startTime % 10000, |
stopTime % 10000)); |
- sLoaded = true; |
+ mLoaded = true; |
} |
} catch (UnsatisfiedLinkError e) { |
throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED, e); |
@@ -305,17 +333,17 @@ public class LibraryLoader { |
// Load a native shared library with the Chromium linker. If the zip file |
// path is not null, the library is loaded directly from the zip file. |
- private static void loadLibrary(@Nullable String zipFilePath, String libFilePath) { |
+ private void loadLibrary(@Nullable String zipFilePath, String libFilePath) { |
Linker.loadLibrary(zipFilePath, libFilePath); |
if (zipFilePath != null) { |
- sLibraryWasLoadedFromApk = true; |
+ mLibraryWasLoadedFromApk = true; |
} |
} |
// The WebView requires the Command Line to be switched over before |
// initialization is done. This is okay in the WebView's case since the |
// JNI is already loaded by this point. |
- public static void switchCommandLineForWebView() { |
+ public void switchCommandLineForWebView() { |
synchronized (sLock) { |
ensureCommandLineSwitchedAlreadyLocked(); |
} |
@@ -324,24 +352,24 @@ public class LibraryLoader { |
// Switch the CommandLine over from Java to native if it hasn't already been done. |
// This must happen after the code is loaded and after JNI is ready (since after the |
// switch the Java CommandLine will delegate all calls the native CommandLine). |
- private static void ensureCommandLineSwitchedAlreadyLocked() { |
- assert sLoaded; |
- if (sCommandLineSwitched) { |
+ private void ensureCommandLineSwitchedAlreadyLocked() { |
+ assert mLoaded; |
+ if (mCommandLineSwitched) { |
return; |
} |
nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull()); |
CommandLine.enableNativeProxy(); |
- sCommandLineSwitched = true; |
+ mCommandLineSwitched = true; |
} |
// Invoke base::android::LibraryLoaded in library_loader_hooks.cc |
- private static void initializeAlreadyLocked() throws ProcessInitException { |
- if (sInitialized) { |
+ private void initializeAlreadyLocked() throws ProcessInitException { |
+ if (mInitialized) { |
return; |
} |
// Setup the native command line if necessary. |
- if (!sCommandLineSwitched) { |
+ if (!mCommandLineSwitched) { |
nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull()); |
} |
@@ -352,13 +380,13 @@ public class LibraryLoader { |
// 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; |
+ mInitialized = true; |
// The Chrome JNI is registered by now so we can switch the Java |
// command line over to delegating to native if it's necessary. |
- if (!sCommandLineSwitched) { |
+ if (!mCommandLineSwitched) { |
CommandLine.enableNativeProxy(); |
- sCommandLineSwitched = true; |
+ mCommandLineSwitched = true; |
} |
// From now on, keep tracing in sync with native. |
@@ -366,32 +394,32 @@ public class LibraryLoader { |
} |
// Called after all native initializations are complete. |
- public static void onNativeInitializationComplete(Context context) { |
+ public void onNativeInitializationComplete(Context context) { |
recordBrowserProcessHistogram(context); |
} |
// Record Chromium linker histogram state for the main browser process. Called from |
// onNativeInitializationComplete(). |
- private static void recordBrowserProcessHistogram(Context context) { |
+ private void recordBrowserProcessHistogram(Context context) { |
if (Linker.isUsed()) { |
- nativeRecordChromiumAndroidLinkerBrowserHistogram(sIsUsingBrowserSharedRelros, |
- sLoadAtFixedAddressFailed, |
+ nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros, |
+ mLoadAtFixedAddressFailed, |
getLibraryLoadFromApkStatus(context)); |
} |
} |
// Returns the device's status for loading a library directly from the APK file. |
// This method can only be called when the Chromium linker is used. |
- private static int getLibraryLoadFromApkStatus(Context context) { |
+ private int getLibraryLoadFromApkStatus(Context context) { |
assert Linker.isUsed(); |
- if (sLibraryWasLoadedFromApk) { |
- return sMapApkWithExecPermission |
+ if (mLibraryWasLoadedFromApk) { |
+ return mMapApkWithExecPermission |
? LibraryLoadFromApkStatusCodes.SUCCESSFUL |
: LibraryLoadFromApkStatusCodes.USED_NO_MAP_EXEC_SUPPORT_FALLBACK; |
} |
- if (!sLibraryIsMappableInApk) { |
+ if (!mLibraryIsMappableInApk) { |
return LibraryLoadFromApkStatusCodes.USED_UNPACK_LIBRARY_FALLBACK; |
} |
@@ -400,11 +428,11 @@ public class LibraryLoader { |
return LibraryLoadFromApkStatusCodes.UNKNOWN; |
} |
- if (!sProbeMapApkWithExecPermission) { |
+ if (!mProbeMapApkWithExecPermission) { |
return LibraryLoadFromApkStatusCodes.UNKNOWN; |
} |
- return sMapApkWithExecPermission |
+ return mMapApkWithExecPermission |
? LibraryLoadFromApkStatusCodes.SUPPORTED |
: LibraryLoadFromApkStatusCodes.NOT_SUPPORTED; |
} |
@@ -413,15 +441,27 @@ public class LibraryLoader { |
// recorded as a histogram immediately because histograms and IPC are not ready at the |
// time it are captured. This function stores a pending value, so that a later call to |
// RecordChromiumAndroidLinkerRendererHistogram() will record it correctly. |
- public static void registerRendererProcessHistogram(boolean requestedSharedRelro, |
- boolean loadAtFixedAddressFailed) { |
+ public void registerRendererProcessHistogram(boolean requestedSharedRelro, |
+ boolean loadAtFixedAddressFailed) { |
if (Linker.isUsed()) { |
nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedSharedRelro, |
loadAtFixedAddressFailed); |
} |
} |
- private static native void nativeInitCommandLine(String[] initCommandLine); |
+ /** |
+ * @return the process the shared library is loaded in, see the LibraryProcessType |
+ * for possible values. |
+ */ |
+ @CalledByNative |
+ public static int getLibraryProcessType() { |
+ synchronized (sLock) { |
+ if (sInstance == null) return LibraryProcessType.PROCESS_UNINITIALIZED; |
+ return sInstance.mLibraryProcessType; |
+ } |
+ } |
+ |
+ private native void nativeInitCommandLine(String[] initCommandLine); |
// Only methods needed before or during normal JNI registration are during System.OnLoad. |
// nativeLibraryLoaded is then called to register everything else. This process is called |
@@ -429,13 +469,13 @@ public class LibraryLoader { |
// definition in base/android/library_loader/library_loader_hooks.cc. |
// |
// Return true on success and false on failure. |
- private static native boolean nativeLibraryLoaded(); |
+ private native boolean nativeLibraryLoaded(); |
// Method called to record statistics about the Chromium linker operation for the main |
// browser process. Indicates whether the linker attempted relro sharing for the browser, |
// and if it did, whether the library failed to load at a fixed address. Also records |
// support for loading a library directly from the APK file. |
- private static native void nativeRecordChromiumAndroidLinkerBrowserHistogram( |
+ private native void nativeRecordChromiumAndroidLinkerBrowserHistogram( |
boolean isUsingBrowserSharedRelros, |
boolean loadAtFixedAddressFailed, |
int libraryLoadFromApkStatus); |
@@ -443,11 +483,11 @@ public class LibraryLoader { |
// Method called to register (for later recording) statistics about the Chromium linker |
// operation for a renderer process. Indicates whether the linker attempted relro sharing, |
// and if it did, whether the library failed to load at a fixed address. |
- private static native void nativeRegisterChromiumAndroidLinkerRendererHistogram( |
+ private native void nativeRegisterChromiumAndroidLinkerRendererHistogram( |
boolean requestedSharedRelro, |
boolean loadAtFixedAddressFailed); |
// Get the version of the native library. This is needed so that we can check we |
// have the right version before initializing the (rest of the) JNI. |
- private static native String nativeGetVersionNumber(); |
+ private native String nativeGetVersionNumber(); |
} |