From e7636e47504034c048872f251a0a7cb240017b31 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 21 Feb 2016 01:04:13 +0900 Subject: [PATCH 1/2] Make it easier to test code that uses WakeupMessage. Code that uses WakeupMessage uses the AlarmManager. Testing such code is slow because AlarmManager.MIN_FUTURITY ensures that alarms must wait at least 5 seconds before firing. This change makes WakeupMessage's fields protected so that test code can subclass from it and override schedule() and cancel() with implementations that do not use AlarmManager, for example by making schedule() call sendEmptyMessageDelayed and making cancel() call removeMessages. Change-Id: I51096b182d9eb87cc7bd46c3c91906f18356b354 --- .../com/android/internal/util/WakeupMessage.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java index 451078b1b0476..26537451992c6 100644 --- a/core/java/com/android/internal/util/WakeupMessage.java +++ b/core/java/com/android/internal/util/WakeupMessage.java @@ -21,7 +21,9 @@ import android.content.Context; import android.os.Handler; import android.os.Message; -/** +import com.android.internal.annotations.VisibleForTesting; + + /** * An AlarmListener that sends the specified message to a Handler and keeps the system awake until * the message is processed. * @@ -36,9 +38,13 @@ import android.os.Message; */ public class WakeupMessage implements AlarmManager.OnAlarmListener { private final AlarmManager mAlarmManager; - private final Handler mHandler; - private final String mCmdName; - private final int mCmd, mArg1, mArg2; + + @VisibleForTesting + protected final Handler mHandler; + @VisibleForTesting + protected final String mCmdName; + @VisibleForTesting + protected final int mCmd, mArg1, mArg2; private boolean mScheduled; public WakeupMessage(Context context, Handler handler, From bfecba2938bd01299c74bc7d7cf0191c1908776a Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 21 Feb 2016 01:09:26 +0900 Subject: [PATCH 2/2] Speed up ConnectivityServiceTest. 1. Override WakeupMessage with an implementation that uses sendEmptyMessageDelayed. This allows us to replace a 6-second sleep with a 150ms wait. 2. Change waitFor()'s polling interval from 100ms to 50ms. With these changes ConnectivityServiceTest goes from ~9s to ~3s. Change-Id: Id78aab9cded90a5b17f09d7f437904e179808dd2 --- .../server/connectivity/NetworkMonitor.java | 7 ++- .../server/ConnectivityServiceTest.java | 51 ++++++++++++++++--- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 4504bdb08945c..fb8b110fbcab9 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -566,7 +566,7 @@ public class NetworkMonitor extends StateMachine { @Override public void enter() { final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId; - mWakeupMessage = new WakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED); + mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED); long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs; mWakeupMessage.schedule(wakeupTime); } @@ -823,4 +823,9 @@ public class NetworkMonitor extends StateMachine { } DEFAULT_LINGER_DELAY_MS = time_ms; } + + @VisibleForTesting + protected WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int i) { + return new WakeupMessage(c, h, s, i); + } } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 20a0131dd70d4..69f12eb5b08cd 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -59,12 +59,14 @@ import android.os.Message; import android.os.MessageQueue; import android.os.Messenger; import android.os.MessageQueue.IdleHandler; +import android.os.SystemClock; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import android.util.LogPrinter; +import com.android.internal.util.WakeupMessage; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.net.NetworkPinner; @@ -505,6 +507,35 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } + private class FakeWakeupMessage extends WakeupMessage { + private static final int UNREASONABLY_LONG_WAIT = 1000; + + public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) { + super(context, handler, cmdName, cmd); + } + + @Override + public void schedule(long when) { + long delayMs = when - SystemClock.elapsedRealtime(); + if (delayMs < 0) delayMs = 0; + if (delayMs > UNREASONABLY_LONG_WAIT) { + fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT + + "ms into the future: " + delayMs); + } + mHandler.sendEmptyMessageDelayed(mCmd, delayMs); + } + + @Override + public void cancel() { + mHandler.removeMessages(mCmd); + } + + @Override + public void onAlarm() { + throw new AssertionError("Should never happen. Update this fake."); + } + } + // NetworkMonitor implementation allowing overriding of Internet connectivity probe result. private class WrappedNetworkMonitor extends NetworkMonitor { // HTTP response code fed back to NetworkMonitor for Internet connectivity probe. @@ -519,6 +550,12 @@ public class ConnectivityServiceTest extends AndroidTestCase { protected int isCaptivePortal() { return gen204ProbeResult; } + + @Override + protected WakeupMessage makeWakeupMessage( + Context context, Handler handler, String cmdName, int cmd) { + return new FakeWakeupMessage(context, handler, cmdName, cmd); + } } private class WrappedConnectivityService extends ConnectivityService { @@ -596,10 +633,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { int delays = 0; while (!criteria.get()) { try { - Thread.sleep(100); + Thread.sleep(50); } catch (InterruptedException e) { } - if (++delays == 5) fail(); + if (++delays == 10) fail(); } } @@ -615,6 +652,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { public void setUp() throws Exception { super.setUp(); + NetworkMonitor.SetDefaultLingerTime(120); + // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . if (Looper.myLooper() == null) { @@ -696,8 +735,6 @@ public class ConnectivityServiceTest extends AndroidTestCase { @LargeTest public void testLingering() throws Exception { - // Decrease linger timeout to the minimum allowed by AlarmManagerService. - NetworkMonitor.SetDefaultLingerTime(5000); verifyNoNetwork(); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); @@ -724,10 +761,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) || mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork())); // Test cellular linger timeout. - try { - Thread.sleep(6000); - } catch (InterruptedException e) { - } + waitFor(new Criteria() { + public boolean get() { return mCm.getAllNetworks().length == 1; } }); verifyActiveNetwork(TRANSPORT_WIFI); assertEquals(1, mCm.getAllNetworks().length); assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());