From 31c9ec9cb4d42cb5bd7bbd7d0a287d9d8e35f481 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 23 Feb 2016 11:24:54 -0800 Subject: [PATCH] Added CTS tests to check background network access while on power save mode. BUG: 27127112 Change-Id: Ifa3019d7b94459d737a9dff80b4b36a2dd43aca5 --- ...ractRestrictBackgroundNetworkTestCase.java | 116 +++++++++++++++--- .../net/hostside/BatterySaverModeTest.java | 55 +++++++++ .../cts/net/hostside/DataSaverModeTest.java | 7 ++ .../hostside/app2/MyBroadcastReceiver.java | 5 +- ...ostsideRestrictBackgroundNetworkTests.java | 62 +++++++++- 5 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java 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 59de7593b2..3f80b5a406 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_DISABLE 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 @@ import android.util.Log; 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation } }, 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation * 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 0000000000..29a0309bd1 --- /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 c62189ed23..ccb1fe9600 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 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase 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 65c7b6009d..f32bd44d79 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 @@ public class MyBroadcastReceiver extends BroadcastReceiver { 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 21e5aa7f48..4786450c42 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 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC 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 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC 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 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC 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"); + } }