| Index: base/android/java/src/org/chromium/base/library_loader/Linker.java
|
| diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
|
| index 7e5099875a6d9be9b438c2e117e3ec7bdc2073b3..49acead1e0aca1676070eb598d6e78538075d4e9 100644
|
| --- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
|
| +++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
|
| @@ -106,16 +106,14 @@ import javax.annotation.Nullable;
|
| * running any native code from any of the libraries (except their static
|
| * constructors, which can't be avoided).
|
| *
|
| - * - A service process shall call either initServiceProcess() or
|
| - * disableSharedRelros() early (i.e. before any loadLibrary() call).
|
| - * Otherwise, the linker considers that it is running inside the browser
|
| - * process. This is because various Chromium projects have vastly
|
| - * different initialization paths.
|
| + * - A service process shall call initServiceProcess() early (i.e. before any
|
| + * loadLibrary() call). Otherwise, the linker considers that it is running
|
| + * inside the browser process. This is because various Chromium projects have
|
| + * vastly different initialization paths.
|
| *
|
| - * disableSharedRelros() completely disables shared RELROs, and loadLibrary()
|
| - * will behave exactly like System.loadLibrary().
|
| + * disableSharedRelros() completely disables shared RELROs.
|
| *
|
| - * initServiceProcess(baseLoadAddress) indicates that shared RELROs are to be
|
| + * enableSharedRelros(baseLoadAddress) indicates that shared RELROs are to be
|
| * used in this process.
|
| *
|
| * - The browser is in charge of deciding where in memory each library should
|
| @@ -140,18 +138,22 @@ import javax.annotation.Nullable;
|
| * fixed addresses too.
|
| *
|
| * - Once all libraries are loaded in the browser process, one can call
|
| - * getSharedRelros() which returns a Bundle instance containing a map that
|
| - * links each loaded library to its shared RELRO region.
|
| + * produceSharedStateBundle() which returns a Bundle instance of
|
| + * resources that a browser process can pass on to child processes. These resources
|
| + * include a map that links each loaded library to its shared RELRO region.
|
| + * TODO(oth): include fallback library descriptors.
|
| *
|
| * This Bundle must be passed to each service process, for example through
|
| * a Binder call (note that the Bundle includes file descriptors and cannot
|
| * be added as an Intent extra).
|
| *
|
| - * - In a service process, finishLibraryLoad() will block until the RELRO
|
| - * section Bundle is received. This is typically done by calling
|
| - * useSharedRelros() from another thread.
|
| + * - In a service process, finishLibraryLoad() will block until the Bundle is received.
|
| + * When the Bundle is received, the service process must call
|
| + * consumeSharedStateBundle() from the receiving thread. Typically this will
|
| + * be a different thread to the thread calling finishLibraryLoad() as it will block
|
| + * until consumeSharedStateBundle() is called.
|
| *
|
| - * This method also ensures the process uses the shared RELROs.
|
| + * consumeSharedStateBundle() also ensures the process uses the shared RELROs.
|
| */
|
| public class Linker {
|
|
|
| @@ -197,14 +199,8 @@ public class Linker {
|
| private static boolean sRelroSharingSupported = false;
|
|
|
| // Set to true if this runs in the browser process. Disabled by initServiceProcess().
|
| - // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in
|
| - // the browser process) on low-memory devices.
|
| private static boolean sInBrowserProcess = true;
|
|
|
| - // Becomes true to indicate this process needs to wait for a shared RELRO in
|
| - // finishLibraryLoad().
|
| - private static boolean sWaitForSharedRelros = false;
|
| -
|
| // Becomes true when initialization determines that the browser process can use the
|
| // shared RELRO.
|
| private static boolean sBrowserUsesSharedRelro = false;
|
| @@ -274,7 +270,6 @@ public class Linker {
|
| if (!sRelroSharingSupported) {
|
| // Sanity.
|
| sBrowserUsesSharedRelro = false;
|
| - sWaitForSharedRelros = false;
|
| }
|
|
|
| sInitialized = true;
|
| @@ -413,18 +408,18 @@ public class Linker {
|
| /**
|
| * Call this method just after loading all native shared libraries in this process.
|
| * Note that when in a service process, this will block until the RELRO bundle is
|
| - * received, i.e. when another thread calls useSharedRelros().
|
| + * received, i.e. when another thread calls consumeSharedStateBundle().
|
| */
|
| public static void finishLibraryLoad() {
|
| if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
|
| synchronized (Linker.class) {
|
| - if (DEBUG) Log.i(TAG, String.format(
|
| - Locale.US,
|
| - "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSharedRelros=%s",
|
| - sInBrowserProcess ? "true" : "false",
|
| - sBrowserUsesSharedRelro ? "true" : "false",
|
| - sWaitForSharedRelros ? "true" : "false"));
|
| -
|
| + if (DEBUG) {
|
| + Log.i(TAG,
|
| + String.format(Locale.US,
|
| + "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s",
|
| + sInBrowserProcess ? "true" : "false",
|
| + sBrowserUsesSharedRelro ? "true" : "false"));
|
| + }
|
| if (sLoadedLibraries == null) {
|
| if (DEBUG) Log.i(TAG, "No libraries loaded");
|
| } else {
|
| @@ -440,23 +435,13 @@ public class Linker {
|
| if (sBrowserUsesSharedRelro) {
|
| useSharedRelrosLocked(sSharedRelros);
|
| }
|
| - }
|
| -
|
| - if (sWaitForSharedRelros) {
|
| - assert !sInBrowserProcess;
|
| -
|
| - // Wait until the shared relro bundle is received from useSharedRelros().
|
| - while (sSharedRelros == null) {
|
| - try {
|
| - Linker.class.wait();
|
| - } catch (InterruptedException ie) {
|
| - // no-op
|
| - }
|
| + } else {
|
| + waitForSharedStateBundleLocked();
|
| + if (!sSharedRelros.isEmpty()) {
|
| + useSharedRelrosLocked(sSharedRelros);
|
| + // Clear the Bundle to ensure it can't be reused.
|
| + sSharedRelros.clear();
|
| }
|
| - useSharedRelrosLocked(sSharedRelros);
|
| - // Clear the Bundle to ensure its file descriptor references can't be reused.
|
| - sSharedRelros.clear();
|
| - sSharedRelros = null;
|
| }
|
| }
|
|
|
| @@ -487,14 +472,15 @@ public class Linker {
|
| }
|
|
|
| /**
|
| - * Call this to send a Bundle containing the shared RELRO sections to be
|
| - * used in this process. If initServiceProcess() was previously called,
|
| - * finishLibraryLoad() will not exit until this method is called in another
|
| + * Call this in service processes to consume shared linker resources in a Bundle from a browser
|
| + * (these will have been produced with produceSharedStateBundle). If enableSharedRelros() was
|
| + * previously called, finishLibraryLoad() will not exit until this method is called in another
|
| * thread with a non-null value.
|
| * @param bundle The Bundle instance containing a map of shared RELRO sections
|
| * to use in this process.
|
| */
|
| - public static void useSharedRelros(Bundle bundle) {
|
| + public static void consumeSharedStateBundle(Bundle bundle) {
|
| + assert !sInBrowserProcess : "Browser does not consume shared state bundle.";
|
| // Ensure the bundle uses the application's class loader, not the framework
|
| // one which doesn't know anything about LibInfo.
|
| // Also, hold a fresh copy of it so the caller can't recycle it.
|
| @@ -509,31 +495,43 @@ public class Linker {
|
| parcel.recycle();
|
| }
|
| if (DEBUG) {
|
| - Log.i(TAG, "useSharedRelros() called with " + bundle
|
| - + ", cloned " + clonedBundle);
|
| + Log.i(TAG, "consumeSharedStateBundle() called with " + bundle + ", cloned "
|
| + + clonedBundle);
|
| }
|
| synchronized (Linker.class) {
|
| // Note that in certain cases, this can be called before
|
| - // initServiceProcess() in service processes.
|
| + // enableSharedRelros() in service processes.
|
| sSharedRelros = clonedBundle;
|
| // Tell any listener blocked in finishLibraryLoad() about it.
|
| Linker.class.notifyAll();
|
| }
|
| }
|
|
|
| + private static void waitForSharedStateBundleLocked() {
|
| + assert Thread.holdsLock(Linker.class);
|
| +
|
| + while (sSharedRelros == null) {
|
| + try {
|
| + Linker.class.wait();
|
| + } catch (InterruptedException ie) {
|
| + // no-op
|
| + }
|
| + }
|
| + }
|
| +
|
| /**
|
| - * Call this to retrieve the shared RELRO sections created in this process,
|
| - * after loading all libraries.
|
| - * @return a new Bundle instance, or null if RELRO sharing is disabled on
|
| - * this system, or if initServiceProcess() was called previously.
|
| + * Call this to retrieve shared state between the browser process and it's
|
| + * children, e.g. the RELRO sections created in this process.
|
| + *
|
| + * Only valid for browser processes and after loading all libraries.
|
| + *
|
| + * @return Bundle instance for sharable linker state.
|
| */
|
| - public static Bundle getSharedRelros() {
|
| - if (DEBUG) Log.i(TAG, "getSharedRelros() called");
|
| + public static Bundle produceSharedStateBundle() {
|
| + if (DEBUG) Log.i(TAG, "getSharedStateBundle() called");
|
| synchronized (Linker.class) {
|
| - if (!sInBrowserProcess) {
|
| - if (DEBUG) Log.i(TAG, "... returning null Bundle");
|
| - return null;
|
| - }
|
| + assert sInBrowserProcess : "Non-browser does not share state bundle.";
|
| + assert sSharedRelros != null : "Bundle not ready.";
|
|
|
| // Return the Bundle created in finishLibraryLoad().
|
| if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
|
| @@ -541,16 +539,27 @@ public class Linker {
|
| }
|
| }
|
|
|
| + /**
|
| + * Call this method before enabling/disabling shared RELRO sections to
|
| + * indicate that this is a service process (i.e. not a browser process).
|
| + */
|
| + public static void initServiceProcess() {
|
| + if (DEBUG) Log.i(TAG, "initServiceProcess() called");
|
| + synchronized (Linker.class) {
|
| + assert sSharedRelros == null : "Bundle is initially empty for non-browser.";
|
| + sInBrowserProcess = false;
|
| + sBrowserUsesSharedRelro = false;
|
| + }
|
| + }
|
|
|
| /**
|
| * Call this method before loading any libraries to indicate that this
|
| - * process shall neither create or reuse shared RELRO sections.
|
| + * process shall neither create nor reuse shared RELRO sections.
|
| */
|
| public static void disableSharedRelros() {
|
| if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
|
| synchronized (Linker.class) {
|
| - sInBrowserProcess = false;
|
| - sWaitForSharedRelros = false;
|
| + sBaseLoadAddress = 0;
|
| sBrowserUsesSharedRelro = false;
|
| }
|
| }
|
| @@ -558,20 +567,20 @@ public class Linker {
|
| /**
|
| * Call this method before loading any libraries to indicate that this
|
| * process is ready to reuse shared RELRO sections from another one.
|
| - * Typically used when starting service processes.
|
| + * Typically used when starting service processes. Any calls to this method
|
| + * must be preceded by initServiceProcess().
|
| * @param baseLoadAddress the base library load address to use.
|
| */
|
| - public static void initServiceProcess(long baseLoadAddress) {
|
| + public static void enableSharedRelros(long baseLoadAddress) {
|
| if (DEBUG) {
|
| Log.i(TAG, String.format(
|
| - Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
|
| + Locale.US, "enableSharedRelros(0x%x) called", baseLoadAddress));
|
| }
|
| synchronized (Linker.class) {
|
| + assert !sInBrowserProcess;
|
| + assert !sBrowserUsesSharedRelro;
|
| ensureInitializedLocked();
|
| - sInBrowserProcess = false;
|
| - sBrowserUsesSharedRelro = false;
|
| if (sRelroSharingSupported) {
|
| - sWaitForSharedRelros = true;
|
| sBaseLoadAddress = baseLoadAddress;
|
| sCurrentLoadAddress = baseLoadAddress;
|
| }
|
| @@ -612,7 +621,6 @@ public class Linker {
|
| // free address space, so disable RELRO shared / fixed load addresses.
|
| Log.w(TAG, "Disabling shared RELROs due address space pressure");
|
| sBrowserUsesSharedRelro = false;
|
| - sWaitForSharedRelros = false;
|
| }
|
| }
|
| }
|
| @@ -730,7 +738,7 @@ public class Linker {
|
|
|
| LibInfo libInfo = new LibInfo();
|
| long loadAddress = 0;
|
| - if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) {
|
| + if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sBaseLoadAddress != 0) {
|
| // Load the library at a fixed address.
|
| loadAddress = sCurrentLoadAddress;
|
| }
|
| @@ -1137,7 +1145,7 @@ public class Linker {
|
| // The map of libraries that are currently loaded in this process.
|
| private static HashMap<String, LibInfo> sLoadedLibraries = null;
|
|
|
| - // Used to pass the shared RELRO Bundle through Binder.
|
| - public static final String EXTRA_LINKER_SHARED_RELROS =
|
| - "org.chromium.base.android.linker.shared_relros";
|
| + // Used to pass the shared linker state Bundle through the Binder.
|
| + public static final String EXTRA_LINKER_SHARED_STATE =
|
| + "org.chromium.base.android.linker.shared_state";
|
| }
|
|
|