Chromium Code Reviews| 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 728699e38e7192555aeca66f39eaa39dfa456517..f080e2e79f76d386928645d0e868e8047e107ecf 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,18 @@ |
| package org.chromium.content.browser; |
| -import android.util.Log; |
| +import android.content.ComponentCallbacks2; |
| +import android.content.Context; |
| +import android.content.res.Configuration; |
| +import android.util.LruCache; |
| import android.util.SparseArray; |
| +import org.chromium.base.ApplicationStatus; |
| +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; |
| /** |
| * Manages oom bindings used to bound child services. |
| @@ -26,6 +32,77 @@ class BindingManagerImpl implements BindingManager { |
| private final long mRemoveStrongBindingDelay; |
| private final boolean mIsLowMemoryDevice; |
| + private class ModerateBindingPool extends LruCache<Integer, ManagedConnection> { |
|
Yaron
2015/06/11 16:54:34
Can this be static?
Jaekyun Seok (inactive)
2015/06/12 06:50:20
Done.
|
| + public ModerateBindingPool( |
| + Context context, final float lowReduceRatio, final float highReduceRatio) { |
| + super(ChildProcessLauncher.getNumberOfServices(context, true)); |
| + |
| + context.registerComponentCallbacks(new ComponentCallbacks2() { |
| + @Override |
| + public void onTrimMemory(int level) { |
| + Log.i(TAG, "onTrimMemory: level=" + level + ", size=" + size()); |
| + if (size() > 0) { |
| + if (level <= TRIM_MEMORY_RUNNING_MODERATE) { |
| + reduce(lowReduceRatio); |
| + } else if (level <= TRIM_MEMORY_RUNNING_LOW) { |
| + reduce(highReduceRatio); |
| + } else { |
| + evictAll(); |
| + } |
| + } |
| + } |
| + |
| + @Override |
| + public void onLowMemory() { |
| + Log.i(TAG, "onLowMemory: evict " + size() + " bindings"); |
| + evictAll(); |
| + } |
| + |
| + @Override |
| + public void onConfigurationChanged(Configuration configuration) {} |
| + }); |
| + } |
| + |
| + private void reduce(float reduceRatio) { |
| + int newSize = (int) (size() * (1f - reduceRatio)); |
| + Log.i(TAG, "Reduce connections from " + size() + " to " + newSize); |
| + if (newSize == 0) { |
| + evictAll(); |
| + } else { |
| + trimToSize(newSize); |
| + } |
| + } |
| + |
| + void addConnection(ManagedConnection managedConnection) { |
| + ChildProcessConnection connection = managedConnection.mConnection; |
| + if (connection != null && connection.isInSandbox()) { |
| + managedConnection.addModerateBinding(); |
| + if (connection.isModerateBindingBound()) { |
| + put(connection.getServiceNumber(), managedConnection); |
| + } else { |
| + remove(connection.getServiceNumber()); |
| + } |
| + } |
| + } |
| + |
| + void removeConnection(ManagedConnection managedConnection) { |
| + ChildProcessConnection connection = managedConnection.mConnection; |
| + if (connection != null && connection.isInSandbox()) { |
| + remove(connection.getServiceNumber()); |
| + } |
| + } |
| + |
| + @Override |
| + protected void entryRemoved(boolean evicted, Integer key, ManagedConnection oldValue, |
| + ManagedConnection newValue) { |
| + if (oldValue != newValue) { |
| + oldValue.removeModerateBinding(); |
| + } |
| + } |
| + } |
| + |
| + private ModerateBindingPool mModerateBindingPool; |
| + |
| /** |
| * Wraps ChildProcessConnection keeping track of additional information needed to manage the |
| * bindings of the connection. The reference to ChildProcessConnection is cleared when the |
| @@ -59,10 +136,13 @@ class BindingManagerImpl implements BindingManager { |
| if (connection == null) return; |
| connection.addStrongBinding(); |
| + if (mModerateBindingPool != null) { |
| + mModerateBindingPool.removeConnection(this); |
| + } |
| } |
| /** Removes a strong service binding. */ |
| - private void removeStrongBinding() { |
| + private void removeStrongBinding(final boolean keepsAsModerate) { |
| final ChildProcessConnection 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. |
| @@ -75,6 +155,10 @@ class BindingManagerImpl implements BindingManager { |
| public void run() { |
| if (connection.isStrongBindingBound()) { |
| connection.removeStrongBinding(); |
| + if (mModerateBindingPool != null && !connection.isStrongBindingBound() |
|
Yaron
2015/06/11 16:54:34
Shouldn't this be !connection.isModerateBindingBou
Jaekyun Seok (inactive)
2015/06/12 06:50:20
This is to confirm whether a strong binding is act
|
| + && keepsAsModerate) { |
| + mModerateBindingPool.addConnection(ManagedConnection.this); |
| + } |
| } |
| } |
| }; |
| @@ -86,6 +170,20 @@ class BindingManagerImpl implements BindingManager { |
| } |
| } |
| + /** Removes the moderate service binding. */ |
| + private void removeModerateBinding() { |
| + if (mConnection == null || !mConnection.isModerateBindingBound()) return; |
| + mConnection.removeModerateBinding(); |
| + } |
| + |
| + /** Adds the moderate service binding. */ |
| + private void addModerateBinding() { |
| + ChildProcessConnection 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. |
| @@ -109,7 +207,7 @@ class BindingManagerImpl implements BindingManager { |
| if (!mInForeground && nextInForeground) { |
| addStrongBinding(); |
| } else if (mInForeground && !nextInForeground) { |
| - removeStrongBinding(); |
| + removeStrongBinding(true); |
| } |
| mInForeground = nextInForeground; |
| @@ -130,7 +228,7 @@ class BindingManagerImpl implements BindingManager { |
| if (!mBoundForBackgroundPeriod && nextBound) { |
| addStrongBinding(); |
| } else if (mBoundForBackgroundPeriod && !nextBound) { |
| - removeStrongBinding(); |
| + removeStrongBinding(false); |
| } |
| mBoundForBackgroundPeriod = nextBound; |
| @@ -146,6 +244,9 @@ class BindingManagerImpl implements BindingManager { |
| void clearConnection() { |
| mWasOomProtected = mConnection.isOomProtectedOrWasWhenDied(); |
| + if (mModerateBindingPool != null) { |
| + mModerateBindingPool.removeConnection(this); |
| + } |
| mConnection = null; |
| } |
| @@ -256,6 +357,12 @@ class BindingManagerImpl implements BindingManager { |
| mBoundForBackgroundPeriod = mLastInForeground; |
| } |
| } |
| + if (mModerateBindingPool != null) { |
| + Log.i(TAG, "Release moderate connections: " + mModerateBindingPool.size()); |
| + RecordHistogram.recordCountHistogram( |
| + "MobileBindingManager.ModerateBindingCount", mModerateBindingPool.size()); |
| + mModerateBindingPool.evictAll(); |
| + } |
| } |
| @Override |
| @@ -294,4 +401,13 @@ class BindingManagerImpl implements BindingManager { |
| return mManagedConnections.get(pid).isConnectionCleared(); |
| } |
| } |
| + |
| + @Override |
| + public void startModerateBinding(float lowReduceRatio, float highReduceRatio) { |
| + if (mIsLowMemoryDevice || mModerateBindingPool != null) return; |
| + |
| + Log.i(TAG, "Moderate binding enabled: " + lowReduceRatio + " " + highReduceRatio); |
| + mModerateBindingPool = new ModerateBindingPool( |
| + ApplicationStatus.getApplicationContext(), lowReduceRatio, highReduceRatio); |
| + } |
| } |