Refactored how data is shared between test apps.
When running the device-site tests, it's necessary to share state
between a second app and the main test app. Currently that's achieved
through a shared preference file that is accessed by both apps (since
they use a shared id), but this approach will not work on power save
mode tests (because the test app will be in foreground and the
background restrictions won't be applied in the second app).
This change refactors the data sharing mechanism by:
- Using an ordered broadcast that is sent from the test app to the
secondary app.
- Checking for the network status in the secondary app.
- Moving the test logic to the client-side tests.
BUG: 27127112
Change-Id: I44987701b908b329fdf40e3a7a97e9f30cfadecb
diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml
index f44fdd1..c7978f8 100644
--- a/tests/cts/hostside/app/AndroidManifest.xml
+++ b/tests/cts/hostside/app/AndroidManifest.xml
@@ -15,11 +15,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.net.hostside"
- android:sharedUserId="com.android.cts.net.hostside.apps">
+ package="com.android.cts.net.hostside">
- <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java
index 8975dab..9a4f318 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java
@@ -16,24 +16,26 @@
package com.android.cts.net.hostside;
+import static android.cts.util.SystemUtil.runShellCommand;
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 android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.test.InstrumentationTestCase;
-import android.util.Log;
-
-import java.net.HttpURLConnection;
-import java.net.URL;
+import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import android.app.Instrumentation;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
/**
* Tests for the {@link ConnectivityManager} API.
*
@@ -44,54 +46,91 @@
public class ConnectivityManagerTest extends InstrumentationTestCase {
private static final String TAG = "ConnectivityManagerTest";
+ private 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;
+
+ // Constants below must match values defined on app2's Common.java
private static final String MANIFEST_RECEIVER = "ManifestReceiver";
private static final String DYNAMIC_RECEIVER = "DynamicReceiver";
-
+ private static final String ACTION_GET_COUNTERS =
+ "com.android.cts.net.hostside.app2.action.GET_COUNTERS";
+ private static final String ACTION_CHECK_NETWORK =
+ "com.android.cts.net.hostside.app2.action.CHECK_NETWORK";
+ private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION";
+ private static final String EXTRA_RECEIVER_NAME =
+ "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
+ 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 = 15000;
- private static final int SLEEP_TIME_SEC = 1;
-
+ private Context mContext;
+ private Instrumentation mInstrumentation;
private ConnectivityManager mCm;
+ private WifiManager mWfm;
private int mUid;
+ private boolean mResetMeteredWifi = false;
@Override
public void setUp() throws Exception {
super.setUp();
- final Context context = getInstrumentation().getContext();
- mCm = (ConnectivityManager) context.getSystemService(Activity.CONNECTIVITY_SERVICE);
- mUid = context.getPackageManager()
- .getPackageInfo(context.getPackageName(), 0).applicationInfo.uid;
- final boolean metered = mCm.isActiveNetworkMetered();
- Log.i(TAG, getName() + ": uid=" + mUid + ", metered=" + metered);
- assertTrue("Active network is not metered", metered);
+ mInstrumentation = getInstrumentation();
+ mContext = mInstrumentation.getContext();
+ mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ mUid = mContext.getPackageManager().getPackageInfo(TEST_APP2_PKG, 0).applicationInfo.uid;
+ final int myUid = mContext.getPackageManager()
+ .getPackageInfo(mContext.getPackageName(), 0).applicationInfo.uid;
+
+ Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid);
+
+ setRestrictBackground(false);
+ setMeteredNetwork();
+
+ registerApp2BroadcastReceiver();
}
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ if (mResetMeteredWifi) {
+ setWifiMeteredStatus(false);
+ }
+ }
+
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
+ removeRestrictBackgroundWhitelist(mUid);
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+ assertRestrictBackgroundChangedReceived(0);
+
+ // Sanity check: make sure status is always disabled, never whitelisted
+ addRestrictBackgroundWhitelist(mUid);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+ assertRestrictBackgroundChangedReceived(0);
}
public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
+ setRestrictBackground(true);
+ assertRestrictBackgroundChangedReceived(1);
+
+ addRestrictBackgroundWhitelist(mUid);
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
+ assertRestrictBackgroundChangedReceived(2);
}
public void testGetRestrictBackgroundStatus_enabled() throws Exception {
+ setRestrictBackground(true);
+ assertRestrictBackgroundChangedReceived(1);
+
+ removeRestrictBackgroundWhitelist(mUid);
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
+ assertRestrictBackgroundChangedReceived(1);
}
- public void testRestrictBackgroundChangedNotReceived() throws Exception {
- assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 0);
- assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0);
- }
-
- public void testRestrictBackgroundChangedReceivedOnce() throws Exception {
- assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 1);
- assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0);
- }
-
- public void testRestrictBackgroundChangedReceivedTwice() throws Exception {
- assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, 2);
+ public void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception {
+ assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount);
assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0);
}
@@ -102,12 +141,12 @@
final int maxAttempts = 5;
do {
attempts++;
- count = getNumberBroadcastsReceived(getInstrumentation().getContext(), receiverName,
- ACTION_RESTRICT_BACKGROUND_CHANGED);
+ count = getNumberBroadcastsReceived(receiverName, ACTION_RESTRICT_BACKGROUND_CHANGED);
if (count == expectedCount) {
break;
}
- Log.d(TAG, "Count is " + count + " after " + attempts + " attempts; sleeping "
+ Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after "
+ + attempts + " attempts; sleeping "
+ SLEEP_TIME_SEC + " seconds before trying again");
Thread.sleep(SLEEP_TIME_SEC * 1000);
} while (attempts <= maxAttempts);
@@ -115,62 +154,139 @@
+ maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count);
}
+ private String sendOrderedBroadcast(Intent intent) throws Exception {
+ final LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
+ Log.d(TAG, "Sending ordered broadcast: " + intent);
+ mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
- static int getNumberBroadcastsReceived(Context context, String receiverName, String action)
- throws Exception {
- final Context sharedContext = context.createPackageContext(
- "com.android.cts.net.hostside.app2", Context.CONTEXT_IGNORE_SECURITY);
- final SharedPreferences prefs = sharedContext.getSharedPreferences(receiverName,
- Context.MODE_PRIVATE);
- return prefs.getInt(action, 0);
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String resultData = getResultData();
+ if (resultData == null) {
+ Log.e(TAG, "Received null data from ordered intent");
+ return;
+ }
+ result.offer(resultData);
+ }
+ }, null, 0, null, null);
+
+ final String resultData = result.poll(60, TimeUnit.SECONDS);
+ assertNotNull("timeout waiting for ordered broadcast result", resultData);
+ Log.d(TAG, "Ordered broadcast response: " + resultData);
+ return resultData;
}
- private void assertRestrictBackgroundStatus(int expectedApiStatus) throws InterruptedException {
- // First asserts the API returns the proper value...
- final String expected = toString(expectedApiStatus);
- Log.d(TAG, getName() + " (expecting " + expected + ")");
- final int apiStatus = mCm.getRestrictBackgroundStatus();
- String actualApiStatus = toString(apiStatus);
- assertEquals("wrong status", expected, actualApiStatus);
+ private int getNumberBroadcastsReceived(String receiverName, String action) throws Exception {
+ final Intent intent = new Intent(ACTION_GET_COUNTERS);
+ intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED);
+ intent.putExtra(EXTRA_RECEIVER_NAME, receiverName);
+ final String resultData = sendOrderedBroadcast(intent);
+ return Integer.valueOf(resultData);
+ }
- //...then use a background thread to verify the actual network status.
- final LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
- new Thread(new Runnable() {
- @Override
- public void run() {
- result.offer(checkNetworkStatus());
- }
- }, "CheckNetworkThread").start();
- final String actualNetworkStatus = result.poll(10, TimeUnit.SECONDS);
- assertNotNull("timeout waiting for background thread", actualNetworkStatus);
- final String expectedPrefix = apiStatus == RESTRICT_BACKGROUND_STATUS_ENABLED ?
- STATUS_NETWORK_UNAVAILABLE_PREFIX : STATUS_NETWORK_AVAILABLE_PREFIX;
+ private void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception {
+ final Intent intent = new Intent(ACTION_CHECK_NETWORK);
+ 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));
}
- protected String checkNetworkStatus() {
- // TODO: connect to a hostside server instead
- final String address = "http://example.com";
- final NetworkInfo networkInfo = mCm.getActiveNetworkInfo();
- Log.d(TAG, "Running checkNetworkStatus() on thread " + Thread.currentThread().getName()
- + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
- String prefix = STATUS_NETWORK_AVAILABLE_PREFIX;
- try {
- final URL url = new URL(address);
- final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(NETWORK_TIMEOUT_MS);
- conn.setConnectTimeout(NETWORK_TIMEOUT_MS);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- conn.connect();
- final int response = conn.getResponseCode();
- Log.d(TAG, "HTTP response for " + address + ": " + response);
- } catch (Exception e) {
- Log.d(TAG, "Exception getting " + address + ": " + e);
- prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX;
+ private String executeShellCommand(String command) throws IOException {
+ final String result = runShellCommand(mInstrumentation, command).trim();
+ if (DEBUG) Log.d(TAG, "Command '" + command + "' returned '" + result + "'");
+ return result;
+ }
+
+ private void setMeteredNetwork() throws IOException {
+ final NetworkInfo info = mCm.getActiveNetworkInfo();
+ final boolean metered = mCm.isActiveNetworkMetered();
+ if (metered) {
+ Log.d(TAG, "Active network already metered: " + info);
+ return;
}
- return prefix + networkInfo;
+ final String netId = setWifiMeteredStatus(true);
+ assertTrue("Could not set wifi '" + netId + "' as metered ("
+ + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered());
+ // Set flag so status is reverted on teardown.
+ mResetMeteredWifi = true;
+ }
+
+ private String setWifiMeteredStatus(boolean metered) throws IOException {
+ 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.
+ final String ssid = mWfm.getConnectionInfo().getSSID();
+ 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;
+ final String result = executeShellCommand(setCommand);
+ assertTrue("Command '" + setCommand + "' failed: " + result, result.isEmpty());
+
+ // Sanity check.
+ final String newStatus = executeShellCommand("cmd netpolicy get metered-network " + netId);
+ assertEquals("Metered status of wi-fi network " + netId + " not set properly",
+ newStatus.trim(), Boolean.toString(metered));
+ return netId;
+ }
+
+ private void setRestrictBackground(boolean enabled) throws IOException {
+ 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));
+ }
+
+ private void addRestrictBackgroundWhitelist(int uid) throws Exception {
+ executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid);
+ assertRestrictBackgroundWhitelist(uid, true);
+ }
+
+ private void removeRestrictBackgroundWhitelist(int uid) throws Exception {
+ executeShellCommand("cmd netpolicy remove restrict-background-whitelist " + uid);
+ assertRestrictBackgroundWhitelist(uid, false);
+ }
+
+ private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception {
+ final int maxTries = 5;
+ boolean actual = false;
+ for (int i = 1; i <= maxTries; i++) {
+ final String output =
+ executeShellCommand("cmd netpolicy list restrict-background-whitelist ");
+ actual = output.contains(Integer.toString(uid));
+ if (expected == actual) {
+ return;
+ }
+ Log.v(TAG, "whitelist check for uid " + uid + " doesn't match yet (expected "
+ + expected + ", got " + actual + "); sleeping 1s before polling again");
+ Thread.sleep(1000);
+ }
+ fail("whitelist check for uid " + uid + " failed: expected " + expected + ", got " + actual);
+ }
+
+ /**
+ * Starts a service that will register a broadcast receiver to receive
+ * {@code RESTRICT_BACKGROUND_CHANGE} intents.
+ * <p>
+ * The service must run in a separate app because otherwise it would be killed every time
+ * {@link #runDeviceTests(String, String)} is executed.
+ */
+ private void registerApp2BroadcastReceiver() throws IOException {
+ executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService");
}
private String toString(int status) {
diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml
index d69bf56..fa4cb43 100644
--- a/tests/cts/hostside/app2/AndroidManifest.xml
+++ b/tests/cts/hostside/app2/AndroidManifest.xml
@@ -16,20 +16,28 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.net.hostside.app2"
- android:sharedUserId="com.android.cts.net.hostside.apps" >
+ package="com.android.cts.net.hostside.app2" >
- <!-- This application is used to listen to RESTRICT_BACKGROUND_CHANGED intents and store
- them in a shared preferences which is then read by the test app.
- It defines 2 listeners, one in the manifest and another dynamically registered by
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <!--
+ This application is used to listen to RESTRICT_BACKGROUND_CHANGED intents and store
+ them in a shared preferences which is then read by the test app. These broadcasts are
+ handled by 2 listeners, one defined the manifest and another dynamically registered by
a service.
+
+ The manifest-defined listener also handles ordered broadcasts used to share data with the
+ test app.
-->
<application>
- <service android:name=".MyService" />
+ <service android:name=".MyService" android:exported="true"/>
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
<action android:name="android.net.conn.RESTRICT_BACKGROUND_CHANGED" />
+ <action android:name="com.android.cts.net.hostside.app2.action.GET_COUNTERS" />
+ <action android:name="com.android.cts.net.hostside.app2.action.CHECK_NETWORK" />
</intent-filter>
</receiver>
</application>
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
index 91caeda..3be4261 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -18,6 +18,18 @@
public final class Common {
static final String TAG = "CtsNetApp2";
+
+ // Constants below must match values defined on app's ConnectivityManagerTest.java
static final String MANIFEST_RECEIVER = "ManifestReceiver";
static final String DYNAMIC_RECEIVER = "DynamicReceiver";
+ static final String ACTION_GET_COUNTERS =
+ "com.android.cts.net.hostside.app2.action.GET_COUNTERS";
+ static final String ACTION_CHECK_NETWORK =
+ "com.android.cts.net.hostside.app2.action.CHECK_NETWORK";
+ static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION";
+ static final String EXTRA_RECEIVER_NAME =
+ "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
+ static final char RESULT_SEPARATOR = ';';
+ static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:";
+ static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:";
}
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 0cbf360..65c7b60 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
@@ -13,21 +13,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.cts.net.hostside.app2;
+import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
+import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK;
+import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS;
+import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION;
+import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME;
import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
+import static com.android.cts.net.hostside.app2.Common.RESULT_SEPARATOR;
+import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_AVAILABLE_PREFIX;
+import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_UNAVAILABLE_PREFIX;
import static com.android.cts.net.hostside.app2.Common.TAG;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.util.Log;
/**
- * Receiver that stores received broadcasts in a shared preference.
+ * Receiver used to:
+ * <ol>
+ * <li>Stored received RESTRICT_BACKGROUND_CHANGED broadcasts in a shared preference.
+ * <li>Returned the number of RESTRICT_BACKGROUND_CHANGED broadcasts in an ordered broadcast.
+ * </ol>
*/
public class MyBroadcastReceiver extends BroadcastReceiver {
+ private static final int NETWORK_TIMEOUT_MS = 15 * 1000;
+
private final String mName;
public MyBroadcastReceiver() {
@@ -37,15 +60,106 @@
MyBroadcastReceiver(String name) {
Log.d(TAG, "Constructing MyBroadcastReceiver named " + name);
mName = name;
- }
+ }
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive() for " + mName + ": " + intent);
+ final String action = intent.getAction();
+ switch (action) {
+ case ACTION_RESTRICT_BACKGROUND_CHANGED:
+ increaseCounter(context, action);
+ break;
+ case ACTION_GET_COUNTERS:
+ setResultDataFromCounter(context, intent);
+ break;
+ case ACTION_CHECK_NETWORK:
+ checkNetwork(context, intent);
+ break;
+ default:
+ Log.e(TAG, "received unexpected action: " + action);
+ }
+ }
+
+ private void increaseCounter(Context context, String action) {
final SharedPreferences prefs = context.getSharedPreferences(mName, Context.MODE_PRIVATE);
- final String pref = intent.getAction();
- final int value = prefs.getInt(pref, 0) + 1;
- Log.d(TAG, "Setting " + pref + " = " + value);
- prefs.edit().putInt(pref, value).apply();
+ final int value = prefs.getInt(action, 0) + 1;
+ Log.d(TAG, "increaseCounter('" + action + "'): setting '" + mName + "' to " + value);
+ prefs.edit().putInt(action, value).apply();
+ }
+
+ private int getCounter(Context context, String action, String receiverName) {
+ final SharedPreferences prefs = context.getSharedPreferences(receiverName,
+ Context.MODE_PRIVATE);
+ final int value = prefs.getInt(action, 0);
+ Log.d(TAG, "getCounter('" + action + "', '" + receiverName + "'): " + value);
+ return value;
+ }
+
+ private void checkNetwork(final Context context, Intent intent) {
+ final ConnectivityManager cm = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ final StringBuilder data = new StringBuilder();
+ final int apiStatus = cm.getRestrictBackgroundStatus();
+ String netStatus;
+ try {
+ netStatus = checkNetworkStatus(cm);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Timeout checking network status");
+ setResultData(null);
+ return;
+ }
+ data.append(apiStatus).append(RESULT_SEPARATOR).append(netStatus);
+ Log.d(TAG, "checkNetwork: returning " + data);
+ setResultData(data.toString());
+ }
+
+ private String checkNetworkStatus(final ConnectivityManager cm) throws InterruptedException {
+ final LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ // TODO: connect to a hostside server instead
+ final String address = "http://example.com";
+ final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ Log.d(TAG, "Running checkNetworkStatus() on thread "
+ + Thread.currentThread().getName()
+ + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
+ String prefix = STATUS_NETWORK_AVAILABLE_PREFIX;
+ try {
+ final URL url = new URL(address);
+ final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setReadTimeout(NETWORK_TIMEOUT_MS);
+ conn.setConnectTimeout(NETWORK_TIMEOUT_MS);
+ conn.setRequestMethod("GET");
+ conn.setDoInput(true);
+ conn.connect();
+ final int response = conn.getResponseCode();
+ Log.d(TAG, "HTTP response for " + address + ": " + response);
+ } catch (Exception e) {
+ Log.d(TAG, "Exception getting " + address + ": " + e);
+ prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX + "Exception " + e + ":";
+ }
+ result.offer(prefix + networkInfo);
+ }
+ }, mName).start();
+ return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS);
+ }
+
+ private void setResultDataFromCounter(Context context, Intent intent) {
+ final String action = intent.getStringExtra(EXTRA_ACTION);
+ if (action == null) {
+ Log.e(TAG, "Missing extra '" + EXTRA_ACTION + "' on " + intent);
+ return;
+ }
+ final String receiverName = intent.getStringExtra(EXTRA_RECEIVER_NAME);
+ if (receiverName == null) {
+ Log.e(TAG, "Missing extra '" + EXTRA_RECEIVER_NAME + "' on " + intent);
+ return;
+ }
+ final int counter = getCounter(context, action, receiverName);
+ setResultData(String.valueOf(counter));
}
}
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 1804740..f2c3b1f 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -17,30 +17,19 @@
package com.android.cts.net;
import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.WifiHelper;
public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestCase {
+
private static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
private static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk";
- private int mUid;
- private WifiHelper mWifiHelper;
-
@Override
protected void setUp() throws Exception {
super.setUp();
- mUid = getUid(TEST_PKG);
- mWifiHelper = new WifiHelper(getDevice());
-
- setWifiMeteredStatus(true);
- setRestrictBackground(false);
-
uninstallPackage(TEST_APP2_PKG, false);
installPackage(TEST_APP2_APK);
- startBroadcastReceiverService();
}
@Override
@@ -48,103 +37,35 @@
super.tearDown();
uninstallPackage(TEST_APP2_PKG, true);
- setRestrictBackground(false);
- setWifiMeteredStatus(false);
}
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
- removeRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatusDisabled();
- // From the app's point of view, nothing changed, it still have access
- assertRestrictBackgroundChangedNotReceived();
-
- // Sanity check: make sure status is always disabled, never whitelisted
- addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatusDisabled();
- assertRestrictBackgroundChangedNotReceived();
- }
-
- public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceivedOnce();
-
- addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatusWhitelisted();
- assertRestrictBackgroundChangedReceivedTwice();
- }
-
- public void testGetRestrictBackgroundStatus_enabled() throws Exception {
- setRestrictBackground(true);
- assertRestrictBackgroundChangedReceivedOnce();
-
- removeRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatusEnabled();
- assertRestrictBackgroundChangedReceivedOnce();
- }
-
- public void testGetRestrictBackgroundStatus_uninstall() throws Exception {
- addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundWhitelist(mUid, true);
-
- uninstallPackage(TEST_PKG, true);
- assertPackageUninstalled(TEST_PKG);
- assertRestrictBackgroundWhitelist(mUid, false);
-
- installPackage(TEST_APK);
- final int newUid = getUid(TEST_PKG);
- assertRestrictBackgroundWhitelist(mUid, false);
- assertRestrictBackgroundWhitelist(newUid, false);
- }
-
- /**
- * Starts a service that will register a broadcast receiver to receive
- * {@code RESTRICT_BACKGROUND_CHANGE} intents.
- * <p>
- * The service must run in a separate app because otherwise it would be killed every time
- * {@link #runDeviceTests(String, String)} is executed.
- */
- private void startBroadcastReceiverService() throws DeviceNotAvailableException {
- runCommand("am startservice " + TEST_APP2_PKG + "/.MyService");
- }
-
- private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException {
runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
"testGetRestrictBackgroundStatus_disabled");
}
- private void assertRestrictBackgroundStatusWhitelisted() throws DeviceNotAvailableException {
+ public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
"testGetRestrictBackgroundStatus_whitelisted");
}
- private void assertRestrictBackgroundStatusEnabled() throws DeviceNotAvailableException {
+ public void testGetRestrictBackgroundStatus_enabled() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
"testGetRestrictBackgroundStatus_enabled");
}
- private void assertRestrictBackgroundChangedNotReceived() throws DeviceNotAvailableException {
- runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
- "testRestrictBackgroundChangedNotReceived");
- }
+ public void testGetRestrictBackgroundStatus_uninstall() throws Exception {
+ final int oldUid = getUid(TEST_PKG);
+ testGetRestrictBackgroundStatus_whitelisted();
- private void assertRestrictBackgroundChangedReceivedOnce() throws DeviceNotAvailableException {
- runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
- "testRestrictBackgroundChangedReceivedOnce");
- }
+ uninstallPackage(TEST_PKG, true);
+ assertPackageUninstalled(TEST_PKG);
+ assertRestrictBackgroundWhitelist(oldUid, false);
- private void assertRestrictBackgroundChangedReceivedTwice() throws DeviceNotAvailableException {
- runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
- "testRestrictBackgroundChangedReceivedTwice");
- }
-
- private void addRestrictBackgroundWhitelist(int uid) throws Exception {
- runCommand("cmd netpolicy add restrict-background-whitelist " + uid);
- assertRestrictBackgroundWhitelist(uid, true);
- }
-
- private void removeRestrictBackgroundWhitelist(int uid) throws Exception {
- runCommand("cmd netpolicy remove restrict-background-whitelist " + uid);
- assertRestrictBackgroundWhitelist(uid, false);
+ installPackage(TEST_APK);
+ final int newUid = getUid(TEST_PKG);
+ assertRestrictBackgroundWhitelist(oldUid, false);
+ assertRestrictBackgroundWhitelist(newUid, false);
}
private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception {
@@ -163,32 +84,4 @@
fail("whitelist check for uid " + uid + " failed: expected "
+ expected + ", got " + actual);
}
-
- private void setWifiMeteredStatus(boolean metered) throws DeviceNotAvailableException {
- mWifiHelper.enableWifi();
- // 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 netId = mWifiHelper.getSSID();
- assertNotNull("null SSID", netId);
- assertFalse("empty SSID", netId.trim().isEmpty());
-
- Log.i(TAG, "Setting wi-fi network " + netId + " metered status to " + metered);
- final String setCommand = "cmd netpolicy set metered-network " + netId + " "+ metered;
- final String result = runCommand(setCommand);
- assertTrue("Command '" + setCommand + "' failed: " + result, result.trim().isEmpty());
-
- // Sanity check.
- final String newStatus = runCommand("cmd netpolicy get metered-network " + netId);
- assertEquals("Metered status of wi-fi network " + netId + " not set properly",
- newStatus.trim(), Boolean.toString(metered));
- }
-
- private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException {
- runCommand("cmd netpolicy set restrict-background " + enabled);
- final String output = runCommand("cmd netpolicy get restrict-background ").trim();
- final String expectedSuffix = enabled ? "enabled" : "disabled";
- // TODO: use MoreAsserts?
- assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
- output.endsWith(expectedSuffix));
- }
}