Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(299)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java

Issue 2845243002: Moving BindingManager and ChildProcessConnection to base/.
Patch Set: Moving BindingManager and ChildProcessConnection to base/. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
deleted file mode 100644
index 583a76c8a508f442f3553b04748dc1e8b4b23016..0000000000000000000000000000000000000000
--- a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
+++ /dev/null
@@ -1,465 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser;
-
-import android.annotation.TargetApi;
-import android.content.ComponentCallbacks2;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.util.LruCache;
-import android.util.SparseArray;
-
-import org.chromium.base.Log;
-import org.chromium.base.SysUtils;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.metrics.RecordHistogram;
-
-import java.util.Map;
-
-/**
- * Manages oom bindings used to bound child services.
- * This object must only be accessed from the launcher thread.
- */
-class BindingManagerImpl implements BindingManager {
- private static final String TAG = "cr.BindingManager";
-
- // Low reduce ratio of moderate binding.
- private static final float MODERATE_BINDING_LOW_REDUCE_RATIO = 0.25f;
- // High reduce ratio of moderate binding.
- private static final float MODERATE_BINDING_HIGH_REDUCE_RATIO = 0.5f;
-
- // Delay of 1 second used when removing temporary strong binding of a process (only on
- // non-low-memory devices).
- private static final long DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS = 1 * 1000;
-
- // Delays used when clearing moderate binding pool when onSentToBackground happens.
- private static final long MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS = 10 * 1000;
-
- // These fields allow to override the parameters for testing - see
- // createBindingManagerForTesting().
- private final boolean mIsLowMemoryDevice;
-
- private static class ModerateBindingPool
- extends LruCache<Integer, ManagedConnection> implements ComponentCallbacks2 {
- private Runnable mDelayedClearer;
-
- public ModerateBindingPool(int maxSize) {
- super(maxSize);
- }
-
- @Override
- public void onTrimMemory(final int level) {
- ThreadUtils.assertOnUiThread();
- LauncherThread.post(new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, size());
- if (size() <= 0) {
- return;
- }
- if (level <= TRIM_MEMORY_RUNNING_MODERATE) {
- reduce(MODERATE_BINDING_LOW_REDUCE_RATIO);
- } else if (level <= TRIM_MEMORY_RUNNING_LOW) {
- reduce(MODERATE_BINDING_HIGH_REDUCE_RATIO);
- } else if (level == TRIM_MEMORY_UI_HIDDEN) {
- // This will be handled by |mDelayedClearer|.
- return;
- } else {
- evictAll();
- }
- }
- });
- }
-
- @Override
- public void onLowMemory() {
- ThreadUtils.assertOnUiThread();
- LauncherThread.post(new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "onLowMemory: evict %d bindings", size());
- evictAll();
- }
- });
- }
-
- @Override
- public void onConfigurationChanged(Configuration configuration) {}
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- private void reduce(float reduceRatio) {
- int oldSize = size();
- int newSize = (int) (oldSize * (1f - reduceRatio));
- Log.i(TAG, "Reduce connections from %d to %d", oldSize, newSize);
- if (newSize == 0) {
- evictAll();
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- trimToSize(newSize);
- } else {
- // Entries will be removed from the front because snapshot() returns ones ordered
- // from least recently accessed to most recently accessed.
- int count = 0;
- for (Map.Entry<Integer, ManagedConnection> entry : snapshot().entrySet()) {
- remove(entry.getKey());
- ++count;
- if (count == oldSize - newSize) break;
- }
- }
- }
-
- void addConnection(ManagedConnection managedConnection) {
- ManagedChildProcessConnection connection = managedConnection.mConnection;
- if (connection != null && connection.isSandboxed()) {
- managedConnection.addModerateBinding();
- if (connection.isModerateBindingBound()) {
- put(connection.getServiceNumber(), managedConnection);
- } else {
- remove(connection.getServiceNumber());
- }
- }
- }
-
- void removeConnection(ManagedConnection managedConnection) {
- ManagedChildProcessConnection connection = managedConnection.mConnection;
- if (connection != null && connection.isSandboxed()) {
- remove(connection.getServiceNumber());
- }
- }
-
- @Override
- protected void entryRemoved(boolean evicted, Integer key, ManagedConnection oldValue,
- ManagedConnection newValue) {
- if (oldValue != newValue) {
- oldValue.removeModerateBinding();
- }
- }
-
- void onSentToBackground(final boolean onTesting) {
- if (size() == 0) return;
- mDelayedClearer = new Runnable() {
- @Override
- public void run() {
- if (mDelayedClearer == null) return;
- mDelayedClearer = null;
- Log.i(TAG, "Release moderate connections: %d", size());
- if (!onTesting) {
- RecordHistogram.recordCountHistogram(
- "Android.ModerateBindingCount", size());
- }
- evictAll();
- }
- };
- LauncherThread.postDelayed(mDelayedClearer, MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS);
- }
-
- void onBroughtToForeground() {
- if (mDelayedClearer != null) {
- LauncherThread.removeCallbacks(mDelayedClearer);
- mDelayedClearer = null;
- }
- }
- }
-
- private ModerateBindingPool mModerateBindingPool;
-
- /**
- * Wraps ManagedChildProcessConnection keeping track of additional information needed to manage
- * the bindings of the connection. The reference to ManagedChildProcessConnection is cleared
- * when the connection goes away, but ManagedConnection itself is kept (until overwritten by a
- * new entry for the same pid).
- */
- private class ManagedConnection {
- // Set in constructor, cleared in clearConnection() (on a separate thread).
- // Need to keep a local reference to avoid it being cleared while using it.
- private ManagedChildProcessConnection mConnection;
-
- // True iff there is a strong binding kept on the service because it is working in
- // foreground.
- private boolean mInForeground;
-
- // True iff there is a strong binding kept on the service because it was bound for the
- // application background period.
- private boolean mBoundForBackgroundPeriod;
-
- /**
- * Removes the initial service binding.
- * @return true if the binding was removed.
- */
- private boolean removeInitialBinding() {
- ManagedChildProcessConnection connection = mConnection;
- if (connection == null || !connection.isInitialBindingBound()) return false;
-
- connection.removeInitialBinding();
- return true;
- }
-
- /** Adds a strong service binding. */
- private void addStrongBinding() {
- ManagedChildProcessConnection connection = mConnection;
- if (connection == null) return;
-
- connection.addStrongBinding();
- if (mModerateBindingPool != null) mModerateBindingPool.removeConnection(this);
- }
-
- /** Removes a strong service binding. */
- private void removeStrongBinding(final boolean keepAsModerate) {
- final ManagedChildProcessConnection connection = mConnection;
- // We have to fail gracefully if the strong binding is not present, as on low-end the
- // binding could have been removed by dropOomBindings() when a new service was started.
- if (connection == null || !connection.isStrongBindingBound()) return;
-
- // This runnable performs the actual unbinding. It will be executed synchronously when
- // on low-end devices and posted with a delay otherwise.
- Runnable doUnbind = new Runnable() {
- @Override
- public void run() {
- if (connection.isStrongBindingBound()) {
- connection.removeStrongBinding();
- if (keepAsModerate) {
- addConnectionToModerateBindingPool(connection);
- }
- }
- }
- };
-
- if (mIsLowMemoryDevice) {
- doUnbind.run();
- } else {
- LauncherThread.postDelayed(doUnbind, DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS);
- }
- }
-
- /**
- * Adds connection to the moderate binding pool. No-op if the connection has a strong
- * binding.
- * @param connection The ChildProcessConnection to add to the moderate binding pool.
- */
- private void addConnectionToModerateBindingPool(ManagedChildProcessConnection connection) {
- if (mModerateBindingPool != null && !connection.isStrongBindingBound()) {
- mModerateBindingPool.addConnection(ManagedConnection.this);
- }
- }
-
- /** Removes the moderate service binding. */
- private void removeModerateBinding() {
- ManagedChildProcessConnection connection = mConnection;
- if (connection == null || !connection.isModerateBindingBound()) return;
- connection.removeModerateBinding();
- }
-
- /** Adds the moderate service binding. */
- private void addModerateBinding() {
- ManagedChildProcessConnection connection = mConnection;
- if (connection == null) return;
-
- connection.addModerateBinding();
- }
-
- /**
- * Drops the service bindings. This is used on low-end to drop bindings of the current
- * service when a new one is used in foreground.
- */
- private void dropBindings() {
- assert mIsLowMemoryDevice;
- ManagedChildProcessConnection connection = mConnection;
- if (connection == null) return;
-
- connection.dropOomBindings();
- }
-
- ManagedConnection(ManagedChildProcessConnection connection) {
- mConnection = connection;
- }
-
- /**
- * Sets the visibility of the service, adding or removing the strong binding as needed.
- */
- void setInForeground(boolean nextInForeground) {
- if (!mInForeground && nextInForeground) {
- addStrongBinding();
- } else if (mInForeground && !nextInForeground) {
- removeStrongBinding(true);
- }
-
- mInForeground = nextInForeground;
- }
-
- /**
- * Called when it is safe to rely on setInForeground() for binding management.
- */
- void onDeterminedVisibility() {
- if (!removeInitialBinding()) return;
- // Decrease the likelihood of a recently created background tab getting evicted by
- // immediately adding moderate binding.
- addConnectionToModerateBindingPool(mConnection);
- }
-
- /**
- * Sets or removes additional binding when the service is main service during the embedder
- * background period.
- */
- void setBoundForBackgroundPeriod(boolean nextBound) {
- if (!mBoundForBackgroundPeriod && nextBound) {
- addStrongBinding();
- } else if (mBoundForBackgroundPeriod && !nextBound) {
- removeStrongBinding(false);
- }
-
- mBoundForBackgroundPeriod = nextBound;
- }
-
- void clearConnection() {
- if (mModerateBindingPool != null) mModerateBindingPool.removeConnection(this);
- mConnection = null;
- }
- }
-
- private final SparseArray<ManagedConnection> mManagedConnections =
- new SparseArray<ManagedConnection>();
-
- // The connection that was most recently set as foreground (using setInForeground()). This is
- // used to add additional binding on it when the embedder goes to background. On low-end, this
- // is also used to drop process bindings when a new one is created, making sure that only one
- // renderer process at a time is protected from oom killing.
- private ManagedConnection mLastInForeground;
-
- // The connection bound with additional binding in onSentToBackground().
- private ManagedConnection mBoundForBackgroundPeriod;
-
- // Whether this instance is used on testing.
- private final boolean mOnTesting;
-
- /**
- * The constructor is private to hide parameters exposed for testing from the regular consumer.
- * Use factory methods to create an instance.
- */
- private BindingManagerImpl(boolean isLowMemoryDevice, boolean onTesting) {
- assert LauncherThread.runningOnLauncherThread();
- mIsLowMemoryDevice = isLowMemoryDevice;
- mOnTesting = onTesting;
- }
-
- public static BindingManagerImpl createBindingManager() {
- assert LauncherThread.runningOnLauncherThread();
- return new BindingManagerImpl(SysUtils.isLowEndDevice(), false);
- }
-
- /**
- * Creates a testing instance of BindingManager. Testing instance will have the unbinding delays
- * set to 0, so that the tests don't need to deal with actual waiting.
- * @param isLowEndDevice true iff the created instance should apply low-end binding policies
- */
- public static BindingManagerImpl createBindingManagerForTesting(boolean isLowEndDevice) {
- assert LauncherThread.runningOnLauncherThread();
- return new BindingManagerImpl(isLowEndDevice, true);
- }
-
- @Override
- public void addNewConnection(int pid, ManagedChildProcessConnection connection) {
- assert LauncherThread.runningOnLauncherThread();
- // This will reset the previous entry for the pid in the unlikely event of the OS
- // reusing renderer pids.
- mManagedConnections.put(pid, new ManagedConnection(connection));
- }
-
- @Override
- public void setInForeground(int pid, boolean inForeground) {
- assert LauncherThread.runningOnLauncherThread();
- ManagedConnection managedConnection = mManagedConnections.get(pid);
- if (managedConnection == null) {
- Log.w(TAG, "Cannot setInForeground() - never saw a connection for the pid: %d", pid);
- return;
- }
-
- if (inForeground && mIsLowMemoryDevice && mLastInForeground != null
- && mLastInForeground != managedConnection) {
- mLastInForeground.dropBindings();
- }
-
- managedConnection.setInForeground(inForeground);
- if (inForeground) mLastInForeground = managedConnection;
- }
-
- @Override
- public void onDeterminedVisibility(int pid) {
- assert LauncherThread.runningOnLauncherThread();
- ManagedConnection managedConnection = mManagedConnections.get(pid);
- if (managedConnection == null) {
- Log.w(TAG, "Cannot call determinedVisibility() - never saw a connection for the pid: "
- + "%d", pid);
- return;
- }
-
- managedConnection.onDeterminedVisibility();
- }
-
- @Override
- public void onSentToBackground() {
- assert LauncherThread.runningOnLauncherThread();
- assert mBoundForBackgroundPeriod == null;
- // mLastInForeground can be null at this point as the embedding application could be
- // used in foreground without spawning any renderers.
- if (mLastInForeground != null) {
- mLastInForeground.setBoundForBackgroundPeriod(true);
- mBoundForBackgroundPeriod = mLastInForeground;
- }
- if (mModerateBindingPool != null) mModerateBindingPool.onSentToBackground(mOnTesting);
- }
-
- @Override
- public void onBroughtToForeground() {
- assert LauncherThread.runningOnLauncherThread();
- if (mBoundForBackgroundPeriod != null) {
- mBoundForBackgroundPeriod.setBoundForBackgroundPeriod(false);
- mBoundForBackgroundPeriod = null;
- }
- if (mModerateBindingPool != null) mModerateBindingPool.onBroughtToForeground();
- }
-
- @Override
- public void removeConnection(int pid) {
- assert LauncherThread.runningOnLauncherThread();
- ManagedConnection managedConnection = mManagedConnections.get(pid);
- if (managedConnection != null) {
- mManagedConnections.remove(pid);
- managedConnection.clearConnection();
- }
- }
-
- /** @return true iff the connection reference is no longer held */
- @VisibleForTesting
- public boolean isConnectionCleared(int pid) {
- assert LauncherThread.runningOnLauncherThread();
- return mManagedConnections.get(pid) == null;
- }
-
- @Override
- public void startModerateBindingManagement(Context context, int maxSize) {
- assert LauncherThread.runningOnLauncherThread();
- if (mIsLowMemoryDevice) return;
-
- if (mModerateBindingPool == null) {
- Log.i(TAG, "Moderate binding enabled: maxSize=%d", maxSize);
- mModerateBindingPool = new ModerateBindingPool(maxSize);
- if (context != null) {
- // Note that it is safe to call Context.registerComponentCallbacks from a background
- // thread.
- context.registerComponentCallbacks(mModerateBindingPool);
- }
- }
- }
-
- @Override
- public void releaseAllModerateBindings() {
- assert LauncherThread.runningOnLauncherThread();
- if (mModerateBindingPool != null) {
- Log.i(TAG, "Release all moderate bindings: %d", mModerateBindingPool.size());
- mModerateBindingPool.evictAll();
- }
- }
-}

Powered by Google App Engine
This is Rietveld 408576698