 Chromium Code Reviews
 Chromium Code Reviews Issue 1146813010:
  Introduce moderate binding  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1146813010:
  Introduce moderate binding  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| Index: content/public/android/javatests/src/org/chromium/content/browser/BindingManagerImplTest.java | 
| diff --git a/content/public/android/javatests/src/org/chromium/content/browser/BindingManagerImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/BindingManagerImplTest.java | 
| index 08cdbfd29bc3cf4ec3f7e2d1c6436f764acf7fbc..968f774083ca1ea36f3233bd4a3d823615dad4aa 100644 | 
| --- a/content/public/android/javatests/src/org/chromium/content/browser/BindingManagerImplTest.java | 
| +++ b/content/public/android/javatests/src/org/chromium/content/browser/BindingManagerImplTest.java | 
| @@ -4,14 +4,22 @@ | 
| package org.chromium.content.browser; | 
| +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; | 
| +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; | 
| +import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; | 
| + | 
| +import android.app.Application; | 
| import android.os.Bundle; | 
| import android.test.InstrumentationTestCase; | 
| import android.test.suitebuilder.annotation.SmallTest; | 
| +import android.util.Pair; | 
| import org.chromium.base.test.util.Feature; | 
| import org.chromium.content.common.IChildProcessCallback; | 
| import org.chromium.content.common.IChildProcessService; | 
| +import java.util.ArrayList; | 
| + | 
| /** | 
| * Unit tests for BindingManagerImpl. The tests run agains mock ChildProcessConnection | 
| * implementation, thus testing only the BindingManagerImpl itself. | 
| @@ -23,6 +31,7 @@ import org.chromium.content.common.IChildProcessService; | 
| public class BindingManagerImplTest extends InstrumentationTestCase { | 
| private static class MockChildProcessConnection implements ChildProcessConnection { | 
| boolean mInitialBindingBound; | 
| + boolean mModerateBindingBound; | 
| int mStrongBindingCount; | 
| final int mPid; | 
| @@ -86,12 +95,12 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| @Override | 
| public int getServiceNumber() { | 
| - throw new UnsupportedOperationException(); | 
| + return mPid; | 
| } | 
| @Override | 
| public boolean isInSandbox() { | 
| - throw new UnsupportedOperationException(); | 
| + return true; | 
| } | 
| @Override | 
| @@ -110,6 +119,21 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| Bundle sharedRelros) { | 
| throw new UnsupportedOperationException(); | 
| } | 
| + | 
| + @Override | 
| + public void addModerateBinding() { | 
| + mModerateBindingBound = true; | 
| + } | 
| + | 
| + @Override | 
| + public void removeModerateBinding() { | 
| + mModerateBindingBound = false; | 
| + } | 
| + | 
| + @Override | 
| + public boolean isModerateBindingBound() { | 
| + return mModerateBindingBound; | 
| + } | 
| } | 
| /** | 
| @@ -134,15 +158,20 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| // The managers are created in setUp() for convenience. | 
| BindingManagerImpl mLowEndManager; | 
| BindingManagerImpl mHighEndManager; | 
| + BindingManagerImpl mModerateBindingManager; | 
| ManagerEntry[] mAllManagers; | 
| @Override | 
| protected void setUp() { | 
| mLowEndManager = BindingManagerImpl.createBindingManagerForTesting(true); | 
| mHighEndManager = BindingManagerImpl.createBindingManagerForTesting(false); | 
| + mModerateBindingManager = BindingManagerImpl.createBindingManagerForTesting(false); | 
| + mModerateBindingManager.startModerateBindingManagement( | 
| + getInstrumentation().getTargetContext(), 4, 0.25f, 0.5f); | 
| mAllManagers = new ManagerEntry[] { | 
| - new ManagerEntry(mLowEndManager, "low-end"), | 
| - new ManagerEntry(mHighEndManager, "high-end")}; | 
| + new ManagerEntry(mLowEndManager, "low-end"), | 
| + new ManagerEntry(mHighEndManager, "high-end"), | 
| + new ManagerEntry(mModerateBindingManager, "moderate-binding")}; | 
| } | 
| /** | 
| @@ -254,12 +283,56 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| } | 
| /** | 
| + * Verifies the strong binding removal policies with moderate binding management, where the | 
| + * moderate binding should be bound. | 
| + */ | 
| + @SmallTest | 
| + @Feature({"ProcessManagement"}) | 
| + public void testStrongBindingRemovalWithModerateBinding() throws Throwable { | 
| + // This test applies only to the moderate-binding manager. | 
| + final BindingManagerImpl manager = mModerateBindingManager; | 
| + | 
| + // Add a connection to the manager. | 
| + final MockChildProcessConnection connection = new MockChildProcessConnection(1); | 
| + manager.addNewConnection(connection.getPid(), connection); | 
| + assertTrue(connection.isInitialBindingBound()); | 
| + assertFalse(connection.isStrongBindingBound()); | 
| + assertFalse(connection.isModerateBindingBound()); | 
| + // This has to happen on the UI thread, so that we can check the binding status right after | 
| + // the call to remove it, before the any other task is executed on the main thread. | 
| + runTestOnUiThread(new Runnable() { | 
| + @Override | 
| + public void run() { | 
| + // Add a strong binding, verify that the initial binding is not removed. | 
| + manager.setInForeground(connection.getPid(), true); | 
| + assertTrue(connection.isStrongBindingBound()); | 
| + assertTrue(connection.isInitialBindingBound()); | 
| + assertFalse(connection.isModerateBindingBound()); | 
| + | 
| + // Remove the strong binding, verify that the strong binding is not removed | 
| + // immediately. | 
| + manager.setInForeground(connection.getPid(), false); | 
| + assertTrue(connection.isStrongBindingBound()); | 
| + assertTrue(connection.isInitialBindingBound()); | 
| + assertFalse(connection.isModerateBindingBound()); | 
| + } | 
| + }); | 
| + | 
| + // Wait until the posted unbinding tasks get executed and verify that the strong binding was | 
| + // removed while the initial binding is not affected, and the moderate binding is bound. | 
| + getInstrumentation().waitForIdleSync(); | 
| + assertFalse(connection.isStrongBindingBound()); | 
| + assertTrue(connection.isInitialBindingBound()); | 
| + assertTrue(connection.isModerateBindingBound()); | 
| + } | 
| + | 
| + /** | 
| * Verifies that the initial binding is removed after determinedVisibility() is called. | 
| */ | 
| @SmallTest | 
| @Feature({"ProcessManagement"}) | 
| public void testInitialBindingRemoval() { | 
| - // This test applies to both low-end and high-end policies. | 
| + // This test applies to low-end, high-end and moderate-binding policies. | 
| for (ManagerEntry managerEntry : mAllManagers) { | 
| BindingManagerImpl manager = managerEntry.mManager; | 
| String message = managerEntry.getErrorMessage(); | 
| @@ -289,7 +362,7 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| @SmallTest | 
| @Feature({"ProcessManagement"}) | 
| public void testIsOomProtected() { | 
| - // This test applies to both low-end and high-end policies. | 
| + // This test applies to low-end, high-end and moderate-binding policies. | 
| for (ManagerEntry managerEntry : mAllManagers) { | 
| BindingManagerImpl manager = managerEntry.mManager; | 
| String message = managerEntry.getErrorMessage(); | 
| @@ -339,7 +412,7 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| @SmallTest | 
| @Feature({"ProcessManagement"}) | 
| public void testBackgroundPeriodBinding() { | 
| - // This test applies to both low-end and high-end policies. | 
| + // This test applies to low-end, high-end and moderate-binding policies. | 
| for (ManagerEntry managerEntry : mAllManagers) { | 
| BindingManagerImpl manager = managerEntry.mManager; | 
| String message = managerEntry.getErrorMessage(); | 
| @@ -383,4 +456,122 @@ public class BindingManagerImplTest extends InstrumentationTestCase { | 
| assertFalse(message, thirdConnection.isStrongBindingBound()); | 
| } | 
| } | 
| + | 
| + /** | 
| + * Verifies that onSentToBackground() drops all the moderate bindings, and | 
| + * onBroughtToForeground() doesn't recover them. | 
| + */ | 
| + @SmallTest | 
| + @Feature({"ProcessManagement"}) | 
| + public void testModerateBindingDropOnBackground() { | 
| + // This test applies only to the moderate-binding manager. | 
| + final BindingManagerImpl manager = mModerateBindingManager; | 
| + | 
| + MockChildProcessConnection[] connections = new MockChildProcessConnection[4]; | 
| + int i; | 
| + for (i = 0; i < connections.length; i++) { | 
| + connections[i] = new MockChildProcessConnection(i + 1); | 
| + manager.addNewConnection(connections[i].getPid(), connections[i]); | 
| + } | 
| + | 
| + // Verify that each connection has a moderate binding after binding and releasing a strong | 
| + // binding. | 
| + for (MockChildProcessConnection connection : connections) { | 
| + manager.setInForeground(connection.getPid(), true); | 
| + manager.setInForeground(connection.getPid(), false); | 
| + getInstrumentation().waitForIdleSync(); | 
| + assertTrue(connection.isModerateBindingBound()); | 
| + } | 
| + | 
| + // Call onSentToBackground() and verify that all the moderate bindings drop. | 
| + manager.onSentToBackground(); | 
| + for (MockChildProcessConnection connection : connections) { | 
| + assertFalse(connection.isModerateBindingBound()); | 
| + } | 
| + | 
| + // Call onBroughtToForeground() and verify that the previous moderate bindings aren't | 
| + // recovered. | 
| + manager.onBroughtToForeground(); | 
| + for (MockChildProcessConnection connection : connections) { | 
| + assertFalse(connection.isModerateBindingBound()); | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * Verifies that onLowMemory() drops all the moderate bindings. | 
| + */ | 
| + @SmallTest | 
| + @Feature({"ProcessManagement"}) | 
| + public void testModerateBindingDropOnLowMemory() { | 
| + final Application app = | 
| + (Application) getInstrumentation().getTargetContext().getApplicationContext(); | 
| + // This test applies only to the moderate-binding manager. | 
| + final BindingManagerImpl manager = mModerateBindingManager; | 
| + | 
| + MockChildProcessConnection[] connections = new MockChildProcessConnection[4]; | 
| + int i; | 
| + for (i = 0; i < connections.length; i++) { | 
| + connections[i] = new MockChildProcessConnection(i + 1); | 
| + manager.addNewConnection(connections[i].getPid(), connections[i]); | 
| + } | 
| + | 
| + // Verify that each connection has a moderate binding after binding and releasing a strong | 
| + // binding. | 
| + for (MockChildProcessConnection connection : connections) { | 
| + manager.setInForeground(connection.getPid(), true); | 
| + manager.setInForeground(connection.getPid(), false); | 
| + getInstrumentation().waitForIdleSync(); | 
| + assertTrue(connection.isModerateBindingBound()); | 
| + } | 
| + | 
| + // Call onLowMemory() and verify that all the moderate bindings drop. | 
| + app.onLowMemory(); | 
| + for (MockChildProcessConnection connection : connections) { | 
| + assertFalse(connection.isModerateBindingBound()); | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * Verifies that onTrimMemory() drops moderate bindings properly. | 
| + */ | 
| + @SmallTest | 
| + @Feature({"ProcessManagement"}) | 
| + public void testModerateBindingDropOnTrimMemory() { | 
| + final Application app = | 
| + (Application) getInstrumentation().getTargetContext().getApplicationContext(); | 
| + // This test applies only to the moderate-binding manager. | 
| + final BindingManagerImpl manager = mModerateBindingManager; | 
| + | 
| + ArrayList<Pair<Integer, Integer>> levelAndExpectedVictimCountList = | 
| + new ArrayList<Pair<Integer, Integer>>(); | 
| + levelAndExpectedVictimCountList.add( | 
| + new Pair<Integer, Integer>(TRIM_MEMORY_RUNNING_MODERATE, 1)); | 
| + levelAndExpectedVictimCountList.add(new Pair<Integer, Integer>(TRIM_MEMORY_RUNNING_LOW, 2)); | 
| + levelAndExpectedVictimCountList.add( | 
| + new Pair<Integer, Integer>(TRIM_MEMORY_RUNNING_CRITICAL, 4)); | 
| + | 
| + MockChildProcessConnection[] connections = new MockChildProcessConnection[4]; | 
| + int i; | 
| 
Yaron
2015/06/17 02:56:12
inline in for-loop's initializer
 
Jaekyun Seok (inactive)
2015/06/17 04:35:46
Done.
 | 
| + for (i = 0; i < connections.length; i++) { | 
| + connections[i] = new MockChildProcessConnection(i + 1); | 
| + manager.addNewConnection(connections[i].getPid(), connections[i]); | 
| + } | 
| + | 
| + for (Pair<Integer, Integer> pair : levelAndExpectedVictimCountList) { | 
| + // Verify that each connection has a moderate binding after binding and releasing a | 
| + // strong binding. | 
| + for (MockChildProcessConnection connection : connections) { | 
| + manager.setInForeground(connection.getPid(), true); | 
| + manager.setInForeground(connection.getPid(), false); | 
| + getInstrumentation().waitForIdleSync(); | 
| + assertTrue(connection.isModerateBindingBound()); | 
| + } | 
| + | 
| + app.onTrimMemory(pair.first); | 
| + // Verify that some of moderate bindings drop. | 
| + for (i = 0; i < connections.length; i++) { | 
| + assertEquals(i >= pair.second, connections[i].isModerateBindingBound()); | 
| 
Yaron
2015/06/17 02:56:12
You should add a meaningful error message (i.e. wh
 
Jaekyun Seok (inactive)
2015/06/17 04:35:46
Done.
 | 
| + } | 
| + } | 
| + } | 
| } |