Chromium Code Reviews| 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 602358b8e4145dbfac210f73623b12f07e36235b..0a2fea265b99272a39df6e1e3925d4f079e7255f 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; |
| @@ -31,7 +32,7 @@ import javax.annotation.Nullable; |
| * the native counterpart to this class. |
| */ |
| @JNINamespace("base::android") |
| -public class LibraryLoader { |
| +public class LibraryLoader extends LibraryProcessType { |
|
Ted C
2015/02/06 01:37:43
having this extend the generated constants file is
michaelbai
2015/02/10 05:17:31
Done.
|
| private static final String TAG = "LibraryLoader"; |
| // Set to true to enable debug logs. |
| @@ -40,41 +41,67 @@ public class LibraryLoader { |
| // Guards all access to the libraries |
| private static final Object sLock = new Object(); |
| + private static LibraryLoader sInstance; |
| + |
| // One-way switch becomes true when the libraries are loaded. |
| - private static boolean sLoaded = false; |
| + private boolean mLoaded = false; |
| // One-way switch becomes true when the Java command line is switched to |
| // native. |
| - private static boolean sCommandLineSwitched = false; |
| + private boolean mCommandLineSwitched = false; |
| // 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 = false; |
| // 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 = false; |
| + private boolean mLoadAtFixedAddressFailed = false; |
| // 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 = false; |
| // 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 = false; |
| // 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 +109,7 @@ public class LibraryLoader { |
| * |
| * @throws ProcessInitException |
| */ |
| - public static void ensureInitialized() throws ProcessInitException { |
| + public void ensureInitialized() throws ProcessInitException { |
| ensureInitialized(null, false); |
| } |
| @@ -96,11 +123,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 +141,7 @@ public class LibraryLoader { |
| */ |
| public static boolean isInitialized() { |
| synchronized (sLock) { |
| - return sInitialized; |
| + return sInstance != null && sInstance.mInitialized; |
| } |
| } |
| @@ -124,7 +151,7 @@ public class LibraryLoader { |
| * |
| * @throws ProcessInitException |
| */ |
| - public static void loadNow() throws ProcessInitException { |
| + public void loadNow() throws ProcessInitException { |
| loadNow(null, false); |
| } |
| @@ -141,7 +168,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 +180,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(); |
| @@ -189,17 +216,17 @@ public class LibraryLoader { |
| && version < android.os.Build.VERSION_CODES.KITKAT |
| && 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"); |
| @@ -228,9 +255,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; |
| @@ -257,7 +284,7 @@ public class LibraryLoader { |
| // Load the library. |
| boolean isLoaded = false; |
| if (Linker.isUsingBrowserSharedRelros()) { |
| - sIsUsingBrowserSharedRelros = true; |
| + mIsUsingBrowserSharedRelros = true; |
| try { |
| loadLibrary(zipFilePath, libFilePath); |
| isLoaded = true; |
| @@ -265,7 +292,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) { |
| @@ -293,7 +320,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); |
| @@ -311,17 +338,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(); |
| } |
| @@ -330,24 +357,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()); |
| } |
| @@ -358,13 +385,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. |
| @@ -372,32 +399,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; |
| } |
| @@ -406,11 +433,11 @@ public class LibraryLoader { |
| return LibraryLoadFromApkStatusCodes.UNKNOWN; |
| } |
| - if (!sProbeMapApkWithExecPermission) { |
| + if (!mProbeMapApkWithExecPermission) { |
| return LibraryLoadFromApkStatusCodes.UNKNOWN; |
| } |
| - return sMapApkWithExecPermission |
| + return mMapApkWithExecPermission |
| ? LibraryLoadFromApkStatusCodes.SUPPORTED |
| : LibraryLoadFromApkStatusCodes.NOT_SUPPORTED; |
| } |
| @@ -419,15 +446,23 @@ 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); |
| + @CalledByNative |
| + public static int getLibraryProcessType() { |
|
Ted C
2015/02/06 01:37:43
javadoc for this as well.
michaelbai
2015/02/10 05:17:31
Done.
|
| + synchronized (sLock) { |
| + if (sInstance == null) return 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 |
| @@ -435,13 +470,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); |
| @@ -449,11 +484,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(); |
| } |