By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *
By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { } - @Test public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -80,8 +118,9 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setBatterySaverMode(true); assertBackgroundNetworkAccess(false); @@ -101,8 +140,9 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java index 6f32c563c1..f20f1d1c4d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractDozeModeTestCase.java @@ -16,25 +16,20 @@ package com.android.cts.net.hostside; -import static com.android.cts.net.hostside.Property.DOZE_MODE; -import static com.android.cts.net.hostside.Property.NOT_LOW_RAM_DEVICE; - import android.os.SystemClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import android.util.Log; /** * Base class for metered and non-metered Doze Mode tests. */ -@RequiredProperties({DOZE_MODE}) abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetworkTestCase { - @Before - public final void setUp() throws Exception { + @Override + protected final void setUp() throws Exception { super.setUp(); + if (!isSupported()) return; + // Set initial state. removePowerSaveModeWhitelist(TEST_APP2_PKG); removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG); @@ -43,15 +38,48 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor registerBroadcastReceiver(); } - @After - public final void tearDown() throws Exception { + @Override + protected final void tearDown() throws Exception { super.tearDown(); - setDozeMode(false); + if (!isSupported()) return; + + try { + tearDownMeteredNetwork(); + } finally { + setDozeMode(false); + } + } + + @Override + protected boolean isSupported() throws Exception { + boolean supported = isDozeModeEnabled(); + if (!supported) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Doze Mode"); + } + return supported; + } + + /** + * Sets the initial (non) metered network state. + * + *
By default is empty - it's up to subclasses to override. + */ + protected void setUpMeteredNetwork() throws Exception { + } + + /** + * Resets the (non) metered network state. + * + *
By default is empty - it's up to subclasses to override. + */ + protected void tearDownMeteredNetwork() throws Exception { } - @Test public void testBackgroundNetworkAccess_enabled() throws Exception { + if (!isSupported()) return; + setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -68,8 +96,9 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_whitelisted() throws Exception { + if (!isSupported()) return; + setDozeMode(true); assertBackgroundNetworkAccess(false); @@ -89,18 +118,19 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor assertBackgroundNetworkAccess(false); } - @Test public void testBackgroundNetworkAccess_disabled() throws Exception { + if (!isSupported()) return; + assertBackgroundNetworkAccess(true); assertsForegroundAlwaysHasNetworkAccess(); assertBackgroundNetworkAccess(true); } - @RequiredProperties({NOT_LOW_RAM_DEVICE}) - @Test public void testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction() throws Exception { + if (!isSupported() || isLowRamDevice()) return; + setPendingIntentWhitelistDuration(NETWORK_TIMEOUT_MS); try { registerNotificationListenerService(); 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 57b7bb4f8d..40d7e34fcc 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 @@ -17,22 +17,14 @@ package com.android.cts.net.hostside; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.os.BatteryManager.BATTERY_PLUGGED_AC; import static android.os.BatteryManager.BATTERY_PLUGGED_USB; import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getConnectivityManager; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getContext; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getInstrumentation; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getWifiManager; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported; -import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.ActivityManager; import android.app.Instrumentation; @@ -42,7 +34,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.wifi.WifiManager; @@ -50,27 +44,24 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; +import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; +import android.test.InstrumentationTestCase; +import android.text.TextUtils; import android.util.Log; -import org.junit.Rule; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; +import com.android.compatibility.common.util.BatteryUtils; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - /** * Superclass for tests related to background network restrictions. */ -@RunWith(AndroidJUnit4.class) -public abstract class AbstractRestrictBackgroundNetworkTestCase { - public static final String TAG = "RestrictBackgroundNetworkTests"; +abstract class AbstractRestrictBackgroundNetworkTestCase extends InstrumentationTestCase { + protected static final String TAG = "RestrictBackgroundNetworkTests"; protected static final String TEST_PKG = "com.android.cts.net.hostside"; protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2"; @@ -107,6 +98,8 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS; private static int PROCESS_STATE_FOREGROUND_SERVICE; + private static final int PROCESS_STATE_TOP = 2; + private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer"; protected static final int TYPE_COMPONENT_ACTIVTIY = 0; @@ -133,23 +126,22 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected WifiManager mWfm; protected int mUid; private int mMyUid; + private String mMeteredWifi; private MyServiceClient mServiceClient; private String mDeviceIdleConstantsSetting; + private boolean mSupported; private boolean mIsLocationOn; - @Rule - public final RuleChain mRuleChain = RuleChain.outerRule(new DumpOnFailureRule()) - .around(new RequiredPropertiesRule()) - .around(new MeterednessConfigurationRule()); - + @Override protected void setUp() throws Exception { + super.setUp(); PROCESS_STATE_FOREGROUND_SERVICE = (Integer) ActivityManager.class .getDeclaredField("PROCESS_STATE_FOREGROUND_SERVICE").get(null); mInstrumentation = getInstrumentation(); - mContext = getContext(); - mCm = getConnectivityManager(); - mWfm = getWifiManager(); + mContext = mInstrumentation.getContext(); + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mUid = getUid(TEST_APP2_PKG); mMyUid = getUid(mContext.getPackageName()); mServiceClient = new MyServiceClient(mContext); @@ -159,9 +151,10 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { if (!mIsLocationOn) { enableLocation(); } + mSupported = setUpActiveNetworkMeteringState(); setAppIdle(false); - Log.i(TAG, "Apps status:\n" + Log.i(TAG, "Apps status on " + getName() + ":\n" + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n" + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid)); @@ -172,13 +165,16 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { final String currentConstants = executeShellCommand("settings get global app_idle_constants"); assertEquals(appIdleConstants, currentConstants); - } + } + @Override protected void tearDown() throws Exception { if (!mIsLocationOn) { disableLocation(); } mServiceClient.unbind(); + + super.tearDown(); } private void enableLocation() throws Exception { @@ -263,8 +259,23 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception { final String status = mServiceClient.getRestrictBackgroundStatus(); assertNotNull("didn't get API status from app2", status); - assertEquals(restrictBackgroundValueToString(expectedStatus), - restrictBackgroundValueToString(Integer.parseInt(status))); + final String actualStatus = toString(Integer.parseInt(status)); + assertEquals("wrong status", toString(expectedStatus), actualStatus); + } + + protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus)); + } + + protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception { + final int actualStatus = mCm.getRestrictBackgroundStatus(); + if (expectedStatus != actualStatus) { + Log.d(TAG, "Expected: " + toString(expectedStatus) + + " but actual: " + toString(actualStatus)); + return false; + } + return true; } protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception { @@ -286,6 +297,28 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */); } + /** + * Whether this device suport this type of test. + * + *
Should be overridden when necessary (but always calling + * {@code super.isSupported()} first), and explicitly used before each test + * Example: + * + *
+ * public void testSomething() {
+ * if (!isSupported()) return;
+ *
+ *
+ * @return {@code true} by default.
+ */
+ protected boolean isSupported() throws Exception {
+ return mSupported;
+ }
+
+ protected boolean isBatterySaverSupported() {
+ return BatteryUtils.isBatterySaverSupported();
+ }
+
/**
* Asserts that an app always have access while on foreground or running a foreground service.
*
@@ -354,6 +387,23 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state );
}
+ /**
+ * As per CDD requirements, if the device doesn't support data saver mode then
+ * ConnectivityManager.getRestrictBackgroundStatus() will always return
+ * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if
+ * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns
+ * RESTRICT_BACKGROUND_STATUS_DISABLED or not.
+ */
+ protected boolean isDataSaverSupported() throws Exception {
+ assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+ try {
+ setRestrictBackground(true);
+ return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+ } finally {
+ setRestrictBackground(false);
+ }
+ }
+
/**
* Returns whether an app state should be considered "background" for restriction purposes.
*/
@@ -393,10 +443,40 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
// Exponential back-off.
timeoutMs = Math.min(timeoutMs*2, NETWORK_TIMEOUT_MS);
}
+ dumpOnFailure();
fail("Invalid state for expectAvailable=" + expectAvailable + " after " + maxTries
+ " attempts.\nLast error: " + error);
}
+ private void dumpOnFailure() throws Exception {
+ dumpAllNetworkRules();
+ Log.d(TAG, "Usagestats dump: " + getUsageStatsDump());
+ executeShellCommand("settings get global app_idle_constants");
+ }
+
+ private void dumpAllNetworkRules() throws Exception {
+ final String networkManagementDump = runShellCommand(mInstrumentation,
+ "dumpsys network_management").trim();
+ final String networkPolicyDump = runShellCommand(mInstrumentation,
+ "dumpsys netpolicy").trim();
+ TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n');
+ splitter.setString(networkManagementDump);
+ String next;
+ Log.d(TAG, ">>> Begin network_management dump");
+ while (splitter.hasNext()) {
+ next = splitter.next();
+ Log.d(TAG, next);
+ }
+ Log.d(TAG, "<<< End network_management dump");
+ splitter.setString(networkPolicyDump);
+ Log.d(TAG, ">>> Begin netpolicy dump");
+ while (splitter.hasNext()) {
+ next = splitter.next();
+ Log.d(TAG, next);
+ }
+ Log.d(TAG, "<<< End netpolicy dump");
+ }
+
/**
* Checks whether the network is available as expected.
*
@@ -448,10 +528,22 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
return errors.toString();
}
+ protected boolean isLowRamDevice() {
+ final ActivityManager am = (ActivityManager) mContext.getSystemService(
+ Context.ACTIVITY_SERVICE);
+ return am.isLowRamDevice();
+ }
+
+ 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;
+ }
+
/**
* Runs a Shell command which is not expected to generate output.
*/
- protected void executeSilentShellCommand(String command) {
+ protected void executeSilentShellCommand(String command) throws Exception {
final String result = executeShellCommand(command);
assertTrue("Command '" + command + "' failed: " + result, result.trim().isEmpty());
}
@@ -480,6 +572,10 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
});
}
+ protected void assertDelayedShellCommand(String command, ExpectResultChecker checker)
+ throws Exception {
+ assertDelayedShellCommand(command, 5, 1, checker);
+ }
protected void assertDelayedShellCommand(String command, int maxTries, int napTimeSeconds,
ExpectResultChecker checker) throws Exception {
String result = "";
@@ -496,6 +592,159 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
+ " attempts. Last result: '" + result + "'");
}
+ /**
+ * Sets the initial metering state for the active network.
+ *
+ * It's called on setup and by default does nothing - it's up to the + * subclasses to override. + * + * @return whether the tests in the subclass are supported on this device. + */ + protected boolean setUpActiveNetworkMeteringState() throws Exception { + return true; + } + + /** + * Makes sure the active network is not metered. + * + *
If the device does not supoprt un-metered networks (for example if it + * only has cellular data but not wi-fi), it should return {@code false}; + * otherwise, it should return {@code true} (or fail if the un-metered + * network could not be set). + * + * @return {@code true} if the network is now unmetered. + */ + protected boolean setUnmeteredNetwork() throws Exception { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + assertNotNull("Could not get active network", info); + if (!mCm.isActiveNetworkMetered()) { + Log.d(TAG, "Active network is not metered: " + info); + } else if (info.getType() == ConnectivityManager.TYPE_WIFI) { + Log.i(TAG, "Setting active WI-FI network as not metered: " + info ); + setWifiMeteredStatus(false); + } else { + Log.d(TAG, "Active network cannot be set to un-metered: " + info); + return false; + } + assertActiveNetworkMetered(false); // Sanity check. + return true; + } + + /** + * Enables metering on the active network if supported. + * + *
If the device does not support metered networks it should return + * {@code false}; otherwise, it should return {@code true} (or fail if the + * metered network could not be set). + * + * @return {@code true} if the network is now metered. + */ + protected boolean setMeteredNetwork() throws Exception { + final NetworkInfo info = mCm.getActiveNetworkInfo(); + final boolean metered = mCm.isActiveNetworkMetered(); + if (metered) { + Log.d(TAG, "Active network already metered: " + info); + return true; + } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { + Log.w(TAG, "Active network does not support metering: " + info); + return false; + } else { + Log.w(TAG, "Active network not metered: " + info); + } + final String netId = setWifiMeteredStatus(true); + + // Set flag so status is reverted on resetMeteredNetwork(); + mMeteredWifi = netId; + // Sanity check. + assertWifiMeteredStatus(netId, true); + assertActiveNetworkMetered(true); + return true; + } + + /** + * Resets the device metering state to what it was before the test started. + * + *
This reverts any metering changes made by {@code setMeteredNetwork}.
+ */
+ protected void resetMeteredNetwork() throws Exception {
+ if (mMeteredWifi != null) {
+ Log.i(TAG, "resetMeteredNetwork(): SID '" + mMeteredWifi
+ + "' was set as metered by test case; resetting it");
+ setWifiMeteredStatus(mMeteredWifi, false);
+ assertActiveNetworkMetered(false); // Sanity check.
+ }
+ }
+
+ private void assertActiveNetworkMetered(boolean expected) throws Exception {
+ final int maxTries = 5;
+ NetworkInfo info = null;
+ for (int i = 1; i <= maxTries; i++) {
+ info = mCm.getActiveNetworkInfo();
+ if (info == null) {
+ Log.v(TAG, "No active network info on attempt #" + i
+ + "; sleeping 1s before polling again");
+ } else if (mCm.isActiveNetworkMetered() != expected) {
+ Log.v(TAG, "Wrong metered status for active network " + info + "; expected="
+ + expected + "; sleeping 1s before polling again");
+ } else {
+ break;
+ }
+ Thread.sleep(SECOND_IN_MS);
+ }
+ assertNotNull("No active network after " + maxTries + " attempts", info);
+ assertEquals("Wrong metered status for active network " + info, expected,
+ mCm.isActiveNetworkMetered());
+ }
+
+ private String setWifiMeteredStatus(boolean metered) throws Exception {
+ // We could call setWifiEnabled() here, but it might take sometime to be in a consistent
+ // state (for example, if one of the saved network is not properly authenticated), so it's
+ // better to let the hostside test take care of that.
+ assertTrue("wi-fi is disabled", mWfm.isWifiEnabled());
+ // 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.
+ final String ssid = mWfm.getConnectionInfo().getSSID();
+ return setWifiMeteredStatus(ssid, metered);
+ }
+
+ private String setWifiMeteredStatus(String ssid, boolean metered) throws Exception {
+ assertNotNull("null SSID", ssid);
+ final String netId = ssid.trim().replaceAll("\"", ""); // remove quotes, if any.
+ assertFalse("empty SSID", ssid.isEmpty());
+
+ Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered);
+ final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered;
+ assertDelayedShellCommand(setCommand, "");
+
+ return netId;
+ }
+
+ private void assertWifiMeteredStatus(String netId, boolean status) throws Exception {
+ final String command = "cmd netpolicy list wifi-networks";
+ final String expectedLine = netId + ";" + status;
+ assertDelayedShellCommand(command, new ExpectResultChecker() {
+
+ @Override
+ public boolean isExpected(String result) {
+ return result.contains(expectedLine);
+ }
+
+ @Override
+ public String getExpected() {
+ return "line containing " + expectedLine;
+ }
+ });
+ }
+
+ 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";
+ // TODO: use MoreAsserts?
+ assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
+ output.endsWith(expectedSuffix));
+ }
+
protected void addRestrictBackgroundWhitelist(int uid) throws Exception {
executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid);
assertRestrictBackgroundWhitelist(uid, true);
@@ -675,7 +924,7 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
protected void setDozeMode(boolean enabled) throws Exception {
// Sanity check, since tests should check beforehand....
- assertTrue("Device does not support Doze Mode", isDozeModeSupported());
+ assertTrue("Device does not support Doze Mode", isDozeModeEnabled());
Log.i(TAG, "Setting Doze Mode to " + enabled);
if (enabled) {
@@ -695,16 +944,43 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
assertDelayedShellCommand("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE");
}
+ protected boolean isDozeModeEnabled() throws Exception {
+ final String result = executeShellCommand("cmd deviceidle enabled deep").trim();
+ return result.equals("1");
+ }
+
protected void setAppIdle(boolean enabled) throws Exception {
Log.i(TAG, "Setting app idle to " + enabled);
executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled );
assertAppIdle(enabled); // Sanity check
}
+ private String getUsageStatsDump() throws Exception {
+ final String output = runShellCommand(mInstrumentation, "dumpsys usagestats").trim();
+ final StringBuilder sb = new StringBuilder();
+ final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n');
+ splitter.setString(output);
+ String str;
+ while (splitter.hasNext()) {
+ str = splitter.next();
+ if (str.contains("package=")
+ && !str.contains(TEST_PKG) && !str.contains(TEST_APP2_PKG)) {
+ continue;
+ }
+ if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) {
+ continue;
+ }
+ sb.append(str).append('\n');
+ }
+ return sb.toString();
+ }
+
protected void assertAppIdle(boolean enabled) throws Exception {
try {
assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled);
} catch (Throwable e) {
+ Log.d(TAG, "UsageStats dump:\n" + getUsageStatsDump());
+ executeShellCommand("settings get global app_idle_constants");
throw e;
}
}
@@ -785,10 +1061,12 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
// App didn't come to foreground when the activity is started, so try again.
assertForegroundNetworkAccess();
} else {
+ dumpOnFailure();
fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
}
}
} else {
+ dumpOnFailure();
fail("Timed out waiting for network availability status from app2 (" + mUid + ")");
}
} else {
@@ -872,6 +1150,19 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
}
}
+ private String toString(int status) {
+ switch (status) {
+ case RESTRICT_BACKGROUND_STATUS_DISABLED:
+ return "DISABLED";
+ case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
+ return "WHITELISTED";
+ case RESTRICT_BACKGROUND_STATUS_ENABLED:
+ return "ENABLED";
+ default:
+ return "UNKNOWN_STATUS_" + status;
+ }
+ }
+
private ProcessState getProcessStateByUid(int uid) throws Exception {
return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid));
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
index f1858d65a5..622d99361f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleMeteredTest.java
@@ -16,8 +16,15 @@
package com.android.cts.net.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-
-@RequiredProperties({METERED_NETWORK})
public class AppIdleMeteredTest extends AbstractAppIdleTestCase {
+
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setMeteredNetwork();
+ }
+
+ @Override
+ protected void tearDownMeteredNetwork() throws Exception {
+ resetMeteredNetwork();
+ }
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
index e737a6dabe..bde71f9100 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AppIdleNonMeteredTest.java
@@ -16,8 +16,9 @@
package com.android.cts.net.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-@RequiredProperties({NON_METERED_NETWORK})
public class AppIdleNonMeteredTest extends AbstractAppIdleTestCase {
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setUnmeteredNetwork();
+ }
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
index c78ca2ec77..3071cfe3f1 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeMeteredTest.java
@@ -16,8 +16,15 @@
package com.android.cts.net.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-
-@RequiredProperties({METERED_NETWORK})
public class BatterySaverModeMeteredTest extends AbstractBatterySaverModeTestCase {
+
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setMeteredNetwork();
+ }
+
+ @Override
+ protected void tearDownMeteredNetwork() throws Exception {
+ resetMeteredNetwork();
+ }
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
index fb52a540d8..6d3076fe0e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
@@ -16,9 +16,10 @@
package com.android.cts.net.hostside;
-
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-@RequiredProperties({NON_METERED_NETWORK})
public class BatterySaverModeNonMeteredTest extends AbstractBatterySaverModeTestCase {
+
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setUnmeteredNetwork();
+ }
}
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 aa2c914e02..cfe6a73a0f 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
@@ -20,33 +20,24 @@ 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 static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
-import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NO_DATA_SAVER_MODE;
-
-import static org.junit.Assert.fail;
+import android.util.Log;
import com.android.compatibility.common.util.CddTest;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import androidx.test.filters.LargeTest;
-
-@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK})
-@LargeTest
public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
private static final String[] REQUIRED_WHITELISTED_PACKAGES = {
"com.android.providers.downloads"
};
- @Before
+ private boolean mIsDataSaverSupported;
+
+ @Override
public void setUp() throws Exception {
super.setUp();
+ mIsDataSaverSupported = isDataSaverSupported();
+
// Set initial state.
setRestrictBackground(false);
removeRestrictBackgroundWhitelist(mUid);
@@ -56,15 +47,36 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
assertRestrictBackgroundChangedReceived(0);
}
- @After
- public void tearDown() throws Exception {
+ @Override
+ protected void tearDown() throws Exception {
super.tearDown();
- setRestrictBackground(false);
+ if (!isSupported()) return;
+
+ try {
+ resetMeteredNetwork();
+ } finally {
+ setRestrictBackground(false);
+ }
+ }
+
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setMeteredNetwork();
+ }
+
+ @Override
+ protected boolean isSupported() throws Exception {
+ if (!mIsDataSaverSupported) {
+ Log.i(TAG, "Skipping " + getClass() + "." + getName()
+ + "() because device does not support Data Saver Mode");
+ }
+ return mIsDataSaverSupported && super.isSupported();
}
- @Test
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
+ if (!isSupported()) return;
+
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
// Sanity check: make sure status is always disabled, never whitelisted
@@ -76,8 +88,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
}
- @Test
public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
+ if (!isSupported()) return;
+
setRestrictBackground(true);
assertRestrictBackgroundChangedReceived(1);
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
@@ -94,8 +107,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
}
- @Test
public void testGetRestrictBackgroundStatus_enabled() throws Exception {
+ if (!isSupported()) return;
+
setRestrictBackground(true);
assertRestrictBackgroundChangedReceived(1);
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
@@ -128,8 +142,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
assertBackgroundNetworkAccess(false);
}
- @Test
public void testGetRestrictBackgroundStatus_blacklisted() throws Exception {
+ if (!isSupported()) return;
+
addRestrictBackgroundBlacklist(mUid);
assertRestrictBackgroundChangedReceived(1);
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
@@ -165,8 +180,9 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
assertsForegroundAlwaysHasNetworkAccess();
}
- @Test
public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception {
+ if (!isSupported()) return;
+
final StringBuilder error = new StringBuilder();
for (String packageName : REQUIRED_WHITELISTED_PACKAGES) {
int uid = -1;
@@ -186,10 +202,10 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
}
}
- @RequiredProperties({NO_DATA_SAVER_MODE})
@CddTest(requirement="7.4.7/C-2-2")
- @Test
public void testBroadcastNotSentOnUnsupportedDevices() throws Exception {
+ if (isSupported()) return;
+
setRestrictBackground(true);
assertRestrictBackgroundChangedReceived(0);
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
index 4306c991c2..e4189af587 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeMeteredTest.java
@@ -16,8 +16,15 @@
package com.android.cts.net.hostside;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-
-@RequiredProperties({METERED_NETWORK})
public class DozeModeMeteredTest extends AbstractDozeModeTestCase {
+
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setMeteredNetwork();
+ }
+
+ @Override
+ protected void tearDownMeteredNetwork() throws Exception {
+ resetMeteredNetwork();
+ }
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
index 1e89f158a3..edbbb9e1ce 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DozeModeNonMeteredTest.java
@@ -16,8 +16,10 @@
package com.android.cts.net.hostside;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-@RequiredProperties({NON_METERED_NETWORK})
public class DozeModeNonMeteredTest extends AbstractDozeModeTestCase {
+
+ @Override
+ protected boolean setUpActiveNetworkMeteringState() throws Exception {
+ return setUnmeteredNetwork();
+ }
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
deleted file mode 100644
index cedd62a0bc..0000000000
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
-import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG;
-
-import android.os.Environment;
-import android.os.FileUtils;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import com.android.compatibility.common.util.OnFailureRule;
-
-import org.junit.AssumptionViolatedException;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-public class DumpOnFailureRule extends OnFailureRule {
- private File mDumpDir = new File(Environment.getExternalStorageDirectory(),
- "CtsHostsideNetworkTests");
-
- @Override
- public void onTestFailure(Statement base, Description description, Throwable throwable) {
- final String testName = description.getClassName() + "_" + description.getMethodName();
-
- if (throwable instanceof AssumptionViolatedException) {
- Log.d(TAG, "Skipping test " + testName + ": " + throwable);
- return;
- }
-
- prepareDumpRootDir();
- final File dumpFile = new File(mDumpDir, "dump-" + testName);
- Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath());
- try (FileOutputStream out = new FileOutputStream(dumpFile)) {
- for (String cmd : new String[] {
- "dumpsys netpolicy",
- "dumpsys network_management",
- "dumpsys usagestats " + TEST_PKG,
- "dumpsys usagestats appstandby",
- }) {
- dumpCommandOutput(out, cmd);
- }
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Error opening file: " + dumpFile, e);
- } catch (IOException e) {
- Log.e(TAG, "Error closing file: " + dumpFile, e);
- }
- }
-
- void dumpCommandOutput(FileOutputStream out, String cmd) {
- final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation()
- .getUiAutomation().executeShellCommand(cmd);
- try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
- out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8));
- FileUtils.copy(in, out);
- out.write("\n\n=================================================================\n\n"
- .getBytes(StandardCharsets.UTF_8));
- } catch (IOException e) {
- Log.e(TAG, "Error dumping '" + cmd + "'", e);
- }
- }
-
- void prepareDumpRootDir() {
- if (!mDumpDir.exists() && !mDumpDir.mkdir()) {
- Log.e(TAG, "Error creating " + mDumpDir);
- }
- }
-}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java
deleted file mode 100644
index 8fadf9e295..0000000000
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MeterednessConfigurationRule.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.resetMeteredNetwork;
-import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setupMeteredNetwork;
-import static com.android.cts.net.hostside.Property.METERED_NETWORK;
-import static com.android.cts.net.hostside.Property.NON_METERED_NETWORK;
-
-import android.util.ArraySet;
-import android.util.Pair;
-
-import com.android.compatibility.common.util.BeforeAfterRule;
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-public class MeterednessConfigurationRule extends BeforeAfterRule {
- private Pair