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