Added CTS tests to check background network access while on power save mode.
BUG: 27127112
Change-Id: Ifa3019d7b94459d737a9dff80b4b36a2dd43aca5
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 59de759..3f80b5a 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -22,7 +22,6 @@
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
-import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -42,7 +41,8 @@
abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase {
protected static final String TAG = "RestrictBackgroundNetworkTests";
- private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
+ protected static final String TEST_PKG = "com.android.cts.net.hostside";
+ protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
private static final int SLEEP_TIME_SEC = 1;
private static final boolean DEBUG = true;
@@ -60,6 +60,10 @@
private static final String RESULT_SEPARATOR = ";";
private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:";
private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:";
+ private static final int NETWORK_TIMEOUT_MS = 15 * 1000;
+
+ // Must be higher than NETWORK_TIMEOUT_MS
+ private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4;
protected Context mContext;
protected Instrumentation mInstrumentation;
@@ -134,8 +138,7 @@
}
}, null, 0, null, null);
- final String resultData = result.poll(60, TimeUnit.SECONDS);
- assertNotNull("timeout waiting for ordered broadcast result", resultData);
+ final String resultData = result.poll(ORDERED_BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
Log.d(TAG, "Ordered broadcast response: " + resultData);
return resultData;
}
@@ -145,6 +148,7 @@
intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED);
intent.putExtra(EXTRA_RECEIVER_NAME, receiverName);
final String resultData = sendOrderedBroadcast(intent);
+ assertNotNull("timeout waiting for ordered broadcast result", resultData);
return Integer.valueOf(resultData);
}
@@ -153,25 +157,73 @@
final String resultData = sendOrderedBroadcast(intent);
final String[] resultItems = resultData.split(RESULT_SEPARATOR);
final String actualApiStatus = toString(Integer.parseInt(resultItems[0]));
- final String actualNetworkStatus = resultItems[1];
-
// First asserts the API returns the proper value...
assertEquals("wrong status", toString(expectedApiStatus), actualApiStatus);
//...then the actual network status in the background thread.
- final String expectedPrefix = expectedApiStatus == RESTRICT_BACKGROUND_STATUS_ENABLED ?
- STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX;
- assertTrue("Wrong network status for API status " + actualApiStatus + ": "
- + actualNetworkStatus, actualNetworkStatus.startsWith(expectedPrefix));
+ final String networkStatus = getNetworkStatus(resultItems);
+ assertNetworkStatus(expectedApiStatus != RESTRICT_BACKGROUND_STATUS_ENABLED, networkStatus);
}
- protected String executeShellCommand(String command) throws IOException {
+ protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception {
+ final Intent intent = new Intent(ACTION_CHECK_NETWORK);
+ final String resultData = sendOrderedBroadcast(intent);
+ final String[] resultItems = resultData.split(RESULT_SEPARATOR);
+ final String networkStatus = getNetworkStatus(resultItems);
+ assertNetworkStatus(expectAllowed, networkStatus);
+ }
+
+ private String getNetworkStatus(String[] resultItems) {
+ return resultItems.length < 2 ? null : resultItems[1];
+ }
+
+ private void assertNetworkStatus(boolean expectAvailable, String status) throws Exception {
+ if (status == null) {
+ Log.d(TAG, "timeout waiting for ordered broadcast");
+ if (expectAvailable) {
+ fail("did not get network status when access was allowed");
+ }
+ return;
+ }
+ final String expectedPrefix = expectAvailable ?
+ STATUS_NETWORK_AVAILABLE_PREFIX : STATUS_NETWORK_UNAVAILABLE_PREFIX;
+ assertTrue("Wrong network status (" + status + ") when expectedAvailable is "
+ + expectAvailable, status.startsWith(expectedPrefix));
+ }
+
+ protected String executeShellCommand(String command) throws Exception {
final String result = runShellCommand(mInstrumentation, command).trim();
if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'");
return result;
}
- protected void setMeteredNetwork() throws IOException {
+ /**
+ * Runs a Shell command which is not expected to generate output.
+ */
+ protected void executeSilentShellCommand(String command) throws Exception {
+ final String result = executeShellCommand(command);
+ assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty());
+ }
+
+ /**
+ * Asserts the result of a command, wait and re-running it a couple times if necessary.
+ */
+ protected void assertDelayedShellCommand(String command, String expectedResult)
+ throws Exception {
+ final int maxTries = 5;
+ for (int i = 1; i <= maxTries; i++) {
+ final String result = executeShellCommand(command).trim();
+ if (result.equals(expectedResult))
+ return;
+ Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
+ + expectedResult + "' on attempt #; sleeping 1s before polling again");
+ Thread.sleep(1000);
+ }
+ fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
+ + " attempts");
+ }
+
+ protected void setMeteredNetwork() throws Exception {
final NetworkInfo info = mCm.getActiveNetworkInfo();
final boolean metered = mCm.isActiveNetworkMetered();
if (metered) {
@@ -185,7 +237,7 @@
mResetMeteredWifi = true;
}
- protected String setWifiMeteredStatus(boolean metered) throws IOException {
+ protected String setWifiMeteredStatus(boolean metered) throws Exception {
mWfm.setWifiEnabled(true);
// TODO: if it's not guaranteed the device has wi-fi, we need to change the tests
// to make the actual verification of restrictions optional.
@@ -206,7 +258,7 @@
return netId;
}
- protected void setRestrictBackground(boolean enabled) throws IOException {
+ protected void setRestrictBackground(boolean enabled) throws Exception {
executeShellCommand("cmd netpolicy set restrict-background " + enabled);
final String output = executeShellCommand("cmd netpolicy get restrict-background ");
final String expectedSuffix = enabled ? "enabled" : "disabled";
@@ -242,6 +294,40 @@
fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual);
}
+ protected void assertPowerSaveModeWhitelist(String packageName, boolean expected)
+ throws Exception {
+ // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
+ // need to use netpolicy for whitelisting
+ assertDelayedShellCommand("dumpsys deviceidle whitelist =" + packageName,
+ Boolean.toString(expected));
+ }
+
+ protected void addPowerSaveModeWhitelist(String packageName) throws Exception {
+ Log.i(TAG, "Adding package " + packageName + " to power-save-mode whitelist");
+ // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
+ // need to use netpolicy for whitelisting
+ executeShellCommand("dumpsys deviceidle whitelist +" + packageName);
+ assertPowerSaveModeWhitelist(packageName, true); // Sanity check
+ }
+
+ protected void removePowerSaveModeWhitelist(String packageName) throws Exception {
+ Log.i(TAG, "Removing package " + packageName + " from power-save-mode whitelist");
+ // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
+ // need to use netpolicy for whitelisting
+ executeShellCommand("dumpsys deviceidle whitelist -" + packageName);
+ assertPowerSaveModeWhitelist(packageName, false); // Sanity check
+ }
+
+ protected void setPowerSaveMode(boolean enabled) throws Exception {
+ Log.i(TAG, "Setting power mode to " + enabled);
+ if (enabled) {
+ executeSilentShellCommand("cmd battery unplug");
+ executeSilentShellCommand("settings put global low_power 1");
+ } else {
+ executeSilentShellCommand("cmd battery reset");
+ }
+ }
+
/**
* Starts a service that will register a broadcast receiver to receive
* {@code RESTRICT_BACKGROUND_CHANGE} intents.
@@ -249,7 +335,7 @@
* The service must run in a separate app because otherwise it would be killed every time
* {@link #runDeviceTests(String, String)} is executed.
*/
- protected void registerApp2BroadcastReceiver() throws IOException {
+ protected void registerApp2BroadcastReceiver() throws Exception {
executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService");
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
new file mode 100644
index 0000000..29a0309
--- /dev/null
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.net.hostside;
+
+public class BatterySaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ setPowerSaveMode(false);
+ assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check
+ registerApp2BroadcastReceiver();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ setPowerSaveMode(false);
+ }
+
+ public void testBackgroundNetworkAccess_enabled() throws Exception {
+ setPowerSaveMode(true);
+ assertBackgroundNetworkAccess(false);
+ }
+
+ public void testBackgroundNetworkAccess_whitelisted() throws Exception {
+ setPowerSaveMode(true);
+ assertBackgroundNetworkAccess(false);
+ addPowerSaveModeWhitelist(TEST_APP2_PKG);
+ assertBackgroundNetworkAccess(true);
+ removePowerSaveModeWhitelist(TEST_APP2_PKG);
+ assertBackgroundNetworkAccess(false);
+ }
+
+ public void testBackgroundNetworkAccess_disabled() throws Exception {
+ setPowerSaveMode(false);
+ assertBackgroundNetworkAccess(true);
+ }
+}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index c62189e..ccb1fe9 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -30,6 +30,13 @@
registerApp2BroadcastReceiver();
}
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ setRestrictBackground(false);
+ }
+
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
removeRestrictBackgroundWhitelist(mUid);
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
index 65c7b60..f32bd44 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
@@ -110,7 +110,10 @@
setResultData(null);
return;
}
- data.append(apiStatus).append(RESULT_SEPARATOR).append(netStatus);
+ data.append(apiStatus).append(RESULT_SEPARATOR);
+ if (netStatus != null) {
+ data.append(netStatus);
+ }
Log.d(TAG, "checkNetwork: returning " + data);
setResultData(data.toString());
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index 21e5aa7..4786450 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -17,6 +17,7 @@
package com.android.cts.net;
import com.android.ddmlib.Log;
+import com.android.tradefed.device.DeviceNotAvailableException;
public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase {
@@ -39,24 +40,24 @@
uninstallPackage(TEST_APP2_PKG, true);
}
- public void testGetRestrictBackgroundStatus_disabled() throws Exception {
+ public void testDataSaverMode_disabled() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_disabled");
}
- public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
+ public void testDataSaverMode_whitelisted() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_whitelisted");
}
- public void testGetRestrictBackgroundStatus_enabled() throws Exception {
+ public void testDataSaverMode_enabled() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_enabled");
}
- public void testGetRestrictBackgroundStatus_uninstall() throws Exception {
+ public void testDataSaverMode_reinstall() throws Exception {
final int oldUid = getUid(TEST_PKG);
- testGetRestrictBackgroundStatus_whitelisted();
+ testDataSaverMode_whitelisted();
uninstallPackage(TEST_PKG, true);
assertPackageUninstalled(TEST_PKG);
@@ -68,6 +69,32 @@
assertRestrictBackgroundWhitelist(newUid, false);
}
+ public void testBatterySaverMode_disabled() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest",
+ "testBackgroundNetworkAccess_disabled");
+ }
+
+ public void testBatterySaverMode_whitelisted() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest",
+ "testBackgroundNetworkAccess_whitelisted");
+ }
+
+ public void testBatterySaverMode_enabled() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest",
+ "testBackgroundNetworkAccess_enabled");
+ }
+
+ public void testBatterySaverMode_reinstall() throws Exception {
+ testBatterySaverMode_whitelisted();
+
+ uninstallPackage(TEST_PKG, true);
+ assertPackageUninstalled(TEST_PKG);
+ assertPowerSaveModeWhitelist(TEST_PKG, false);
+
+ installPackage(TEST_APK);
+ assertPowerSaveModeWhitelist(TEST_PKG, false);
+ }
+
private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception {
final int max_tries = 5;
boolean actual = false;
@@ -84,4 +111,29 @@
fail("whitelist check for uid " + uid + " failed: expected "
+ expected + ", got " + actual);
}
+
+ private void assertPowerSaveModeWhitelist(String packageName, boolean expected)
+ throws Exception {
+ // TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
+ // need to use netpolicy for whitelisting
+ assertDelayedCommand("dumpsys deviceidle whitelist =" + packageName,
+ Boolean.toString(expected));
+ }
+
+ /**
+ * Asserts the result of a command, wait and re-running it a couple times if necessary.
+ */
+ private void assertDelayedCommand(String command, String expectedResult)
+ throws InterruptedException, DeviceNotAvailableException {
+ final int maxTries = 5;
+ for (int i = 1; i <= maxTries; i++) {
+ final String result = runCommand(command).trim();
+ if (result.equals(expectedResult)) return;
+ Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
+ + expectedResult + "' on attempt #; sleeping 1s before polling again");
+ Thread.sleep(1000);
+ }
+ fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
+ + " attempts");
+ }
}