| 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
|
| index 583a76c8a508f442f3553b04748dc1e8b4b23016..a6bd65971fcb7389b46f77c63f5a46cbc83f5d4c 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
|
| @@ -4,12 +4,9 @@
|
|
|
| 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;
|
| @@ -18,14 +15,14 @@ import org.chromium.base.ThreadUtils;
|
| import org.chromium.base.VisibleForTesting;
|
| import org.chromium.base.metrics.RecordHistogram;
|
|
|
| -import java.util.Map;
|
| +import java.util.LinkedList;
|
|
|
| /**
|
| * 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";
|
| + private static final String TAG = "cr_BindingManager";
|
|
|
| // Low reduce ratio of moderate binding.
|
| private static final float MODERATE_BINDING_LOW_REDUCE_RATIO = 0.25f;
|
| @@ -43,12 +40,15 @@ class BindingManagerImpl implements BindingManager {
|
| // createBindingManagerForTesting().
|
| private final boolean mIsLowMemoryDevice;
|
|
|
| - private static class ModerateBindingPool
|
| - extends LruCache<Integer, ManagedConnection> implements ComponentCallbacks2 {
|
| + private static class ModerateBindingPool implements ComponentCallbacks2 {
|
| + // Stores the connections in MRU order.
|
| + private final LinkedList<ManagedConnection> mConnections = new LinkedList<>();
|
| + private final int mMaxSize;
|
| +
|
| private Runnable mDelayedClearer;
|
|
|
| public ModerateBindingPool(int maxSize) {
|
| - super(maxSize);
|
| + mMaxSize = maxSize;
|
| }
|
|
|
| @Override
|
| @@ -57,8 +57,8 @@ class BindingManagerImpl implements BindingManager {
|
| LauncherThread.post(new Runnable() {
|
| @Override
|
| public void run() {
|
| - Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, size());
|
| - if (size() <= 0) {
|
| + Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, mConnections.size());
|
| + if (mConnections.isEmpty()) {
|
| return;
|
| }
|
| if (level <= TRIM_MEMORY_RUNNING_MODERATE) {
|
| @@ -69,7 +69,7 @@ class BindingManagerImpl implements BindingManager {
|
| // This will be handled by |mDelayedClearer|.
|
| return;
|
| } else {
|
| - evictAll();
|
| + removeAllConnections();
|
| }
|
| }
|
| });
|
| @@ -81,8 +81,8 @@ class BindingManagerImpl implements BindingManager {
|
| LauncherThread.post(new Runnable() {
|
| @Override
|
| public void run() {
|
| - Log.i(TAG, "onLowMemory: evict %d bindings", size());
|
| - evictAll();
|
| + Log.i(TAG, "onLowMemory: evict %d bindings", mConnections.size());
|
| + removeAllConnections();
|
| }
|
| });
|
| }
|
| @@ -90,25 +90,12 @@ class BindingManagerImpl implements BindingManager {
|
| @Override
|
| public void onConfigurationChanged(Configuration configuration) {}
|
|
|
| - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
| private void reduce(float reduceRatio) {
|
| - int oldSize = size();
|
| + int oldSize = mConnections.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;
|
| - }
|
| - }
|
| + removeOldConnections(oldSize - newSize);
|
| + assert mConnections.size() == newSize;
|
| }
|
|
|
| void addConnection(ManagedConnection managedConnection) {
|
| @@ -116,9 +103,9 @@ class BindingManagerImpl implements BindingManager {
|
| if (connection != null && connection.isSandboxed()) {
|
| managedConnection.addModerateBinding();
|
| if (connection.isModerateBindingBound()) {
|
| - put(connection.getServiceNumber(), managedConnection);
|
| + addConnectionImpl(managedConnection);
|
| } else {
|
| - remove(connection.getServiceNumber());
|
| + removeConnectionImpl(managedConnection);
|
| }
|
| }
|
| }
|
| @@ -126,31 +113,60 @@ class BindingManagerImpl implements BindingManager {
|
| void removeConnection(ManagedConnection managedConnection) {
|
| ManagedChildProcessConnection connection = managedConnection.mConnection;
|
| if (connection != null && connection.isSandboxed()) {
|
| - remove(connection.getServiceNumber());
|
| + removeConnectionImpl(managedConnection);
|
| }
|
| }
|
|
|
| - @Override
|
| - protected void entryRemoved(boolean evicted, Integer key, ManagedConnection oldValue,
|
| - ManagedConnection newValue) {
|
| - if (oldValue != newValue) {
|
| - oldValue.removeModerateBinding();
|
| + void removeAllConnections() {
|
| + removeOldConnections(mConnections.size());
|
| + }
|
| +
|
| + int size() {
|
| + return mConnections.size();
|
| + }
|
| +
|
| + private void addConnectionImpl(ManagedConnection managedConnection) {
|
| + // Note that the size of connections is currently fairly small (20).
|
| + // If it became bigger we should consider using an alternate data structure so we don't
|
| + // have to traverse the list every time.
|
| +
|
| + // Remove the connection if it's already in the list, we'll add it at the head.
|
| + mConnections.removeFirstOccurrence(managedConnection);
|
| + if (mConnections.size() == mMaxSize) {
|
| + // Make room for the connection we are about to add.
|
| + removeOldConnections(1);
|
| + }
|
| + mConnections.add(0, managedConnection);
|
| + assert mConnections.size() <= mMaxSize;
|
| + }
|
| +
|
| + private void removeConnectionImpl(ManagedConnection managedConnection) {
|
| + int index = mConnections.indexOf(managedConnection);
|
| + if (index != -1) {
|
| + ManagedConnection connection = mConnections.remove(index);
|
| + connection.mConnection.removeModerateBinding();
|
| + }
|
| + }
|
| +
|
| + private void removeOldConnections(int numberOfConnections) {
|
| + assert numberOfConnections <= mConnections.size();
|
| + for (int i = 0; i < numberOfConnections; i++) {
|
| + ManagedConnection connection = mConnections.removeLast();
|
| + connection.mConnection.removeModerateBinding();
|
| }
|
| }
|
|
|
| void onSentToBackground(final boolean onTesting) {
|
| - if (size() == 0) return;
|
| + if (mConnections.isEmpty()) return;
|
| mDelayedClearer = new Runnable() {
|
| @Override
|
| public void run() {
|
| - if (mDelayedClearer == null) return;
|
| - mDelayedClearer = null;
|
| - Log.i(TAG, "Release moderate connections: %d", size());
|
| + Log.i(TAG, "Release moderate connections: %d", mConnections.size());
|
| if (!onTesting) {
|
| RecordHistogram.recordCountHistogram(
|
| - "Android.ModerateBindingCount", size());
|
| + "Android.ModerateBindingCount", mConnections.size());
|
| }
|
| - evictAll();
|
| + removeAllConnections();
|
| }
|
| };
|
| LauncherThread.postDelayed(mDelayedClearer, MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS);
|
| @@ -459,7 +475,7 @@ class BindingManagerImpl implements BindingManager {
|
| assert LauncherThread.runningOnLauncherThread();
|
| if (mModerateBindingPool != null) {
|
| Log.i(TAG, "Release all moderate bindings: %d", mModerateBindingPool.size());
|
| - mModerateBindingPool.evictAll();
|
| + mModerateBindingPool.removeAllConnections();
|
| }
|
| }
|
| }
|
|
|