| 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();
|
| }
|
|
|