Update network tests to make sure app has connectivity on start.
In the tests, we check the ouput from "am get-uid-state" command to see
if the app is coming to foreground and check for network access. But the
command gives internal uid state info in AMS and it's possible that the
activity/service is not started yet. Update this behavior so that we check
for network access only after the activity/service is started.
Bug: 27803922
Test: cts-tradefed run singleCommand cts-dev --module CtsHostsideNetworkTests
Change-Id: Ic0d94a585439c1d8629a897a8b56bcbf178a4371
diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk
index 58be21f..85f71c3 100644
--- a/tests/cts/hostside/aidl/Android.mk
+++ b/tests/cts/hostside/aidl/Android.mk
@@ -19,6 +19,7 @@
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := \
com/android/cts/net/hostside/IMyService.aidl \
+ com/android/cts/net/hostside/INetworkStateObserver.aidl \
com/android/cts/net/hostside/IRemoteSocketFactory.aidl
LOCAL_MODULE := CtsHostsideNetworkTestsAidl
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
new file mode 100644
index 0000000..09f3120
--- /dev/null
+++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+oneway interface INetworkStateObserver {
+ void onNetworkStateChecked(String resultData);
+}
\ No newline at end of file
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index 78ba4b9..0e35b1b 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -91,9 +91,7 @@
// Make sure foreground app doesn't lose access upon enabling it.
setAppIdle(true);
- launchActivity();
- assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched...
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
finishActivity();
assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched...
assertBackgroundNetworkAccess(true);
@@ -102,9 +100,7 @@
// Same for foreground service.
setAppIdle(true);
- startForegroundService();
- assertAppIdle(true); // Sanity check - still idle
- assertForegroundServiceNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
stopForegroundService();
assertAppIdle(true);
assertBackgroundNetworkAccess(false);
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
index 50bcc60..546a550 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java
@@ -87,8 +87,7 @@
// Make sure foreground app doesn't lose access upon Battery Saver.
setBatterySaverMode(false);
- launchActivity();
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
setBatterySaverMode(true);
assertForegroundNetworkAccess();
@@ -104,8 +103,7 @@
// Make sure foreground service doesn't lose access upon enabling Battery Saver.
setBatterySaverMode(false);
- startForegroundService();
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
setBatterySaverMode(true);
assertForegroundNetworkAccess();
stopForegroundService();
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 6669af5..68f6e74 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
@@ -88,8 +88,7 @@
// Make sure foreground service doesn't lose network access upon enabling doze.
setDozeMode(false);
- startForegroundService();
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
setDozeMode(true);
assertForegroundNetworkAccess();
stopForegroundService();
@@ -159,8 +158,7 @@
// leaves Doze Mode.
@Override
protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception {
- startForegroundService();
- assertForegroundServiceNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
stopForegroundService();
assertBackgroundState();
}
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 014d7ae..3374378 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,11 +22,13 @@
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -35,11 +37,15 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiManager;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.test.InstrumentationTestCase;
import android.util.Log;
+import com.android.cts.net.hostside.INetworkStateObserver;
+
/**
* Superclass for tests related to background network restrictions.
*/
@@ -49,6 +55,9 @@
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 String TEST_APP2_ACTIVITY_CLASS = TEST_APP2_PKG + ".MyActivity";
+ private static final String TEST_APP2_SERVICE_CLASS = TEST_APP2_PKG + ".MyForegroundService";
+
private static final int SLEEP_TIME_SEC = 1;
private static final boolean DEBUG = true;
@@ -76,6 +85,12 @@
private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
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;
+ protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
+
+ private static final int FOREGROUND_PROC_NETWORK_TIMEOUT_MS = 6000;
// Must be higher than NETWORK_TIMEOUT_MS
private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4;
@@ -225,13 +240,11 @@
*/
protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception{
// Checks foreground first.
- launchActivity();
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
finishActivity();
// Then foreground service
- startForegroundService();
- assertForegroundServiceNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
stopForegroundService();
}
@@ -329,14 +342,19 @@
*/
private String checkNetworkAccess(boolean expectAvailable) throws Exception {
final String resultData = mServiceClient.checkNetworkStatus();
+ return checkForAvailabilityInResultData(resultData, expectAvailable);
+ }
+
+ private String checkForAvailabilityInResultData(String resultData, boolean expectAvailable) {
if (resultData == null) {
- return "did not get network status from app2";
+ assertNotNull("Network status from app2 is null", resultData);
}
// Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check
final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]);
- final DetailedState detailedState = parts[1].equals("null") ? null : DetailedState.valueOf(parts[1]);
+ final DetailedState detailedState = parts[1].equals("null")
+ ? null : DetailedState.valueOf(parts[1]);
final boolean connected = Boolean.valueOf(parts[2]);
final String connectionCheckDetails = parts[3];
final String networkInfo = parts[4];
@@ -641,7 +659,6 @@
Log.i(TAG, "Setting Battery Saver Mode to " + enabled);
if (enabled) {
turnBatteryOff();
- executeSilentShellCommand("cmd battery unplug");
executeSilentShellCommand("settings put global low_power 1");
} else {
executeSilentShellCommand("settings put global low_power 0");
@@ -742,35 +759,58 @@
mDeviceIdleConstantsSetting));
}
- protected void startForegroundService() throws Exception {
- executeShellCommand(
- "am startservice -f 1 com.android.cts.net.hostside.app2/.MyForegroundService");
- assertForegroundServiceState();
+ protected void launchComponentAndAssertNetworkAccess(int type) throws Exception {
+ if (type == TYPE_COMPONENT_ACTIVTIY) {
+ turnScreenOn();
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Intent launchIntent = getIntentForComponent(type);
+ final Bundle extras = new Bundle();
+ final String[] errors = new String[] {null};
+ extras.putBinder(KEY_NETWORK_STATE_OBSERVER, getNewNetworkStateObserver(latch, errors));
+ launchIntent.putExtras(extras);
+ if (type == TYPE_COMPONENT_ACTIVTIY) {
+ mContext.startActivity(launchIntent);
+ } else if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) {
+ mContext.startService(launchIntent);
+ }
+ if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ if (!errors[0].isEmpty()) {
+ fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
+ }
+ } else {
+ fail("Timed out waiting for network availability status from app2 (" + mUid + ")");
+ }
+ }
+
+ private Intent getIntentForComponent(int type) {
+ final Intent intent = new Intent();
+ if (type == TYPE_COMPONENT_ACTIVTIY) {
+ intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_ACTIVITY_CLASS));
+ } else if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) {
+ intent.setComponent(new ComponentName(TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS))
+ .setFlags(1);
+ } else {
+ fail("Unknown type: " + type);
+ }
+ return intent;
}
protected void stopForegroundService() throws Exception {
- executeShellCommand(
- "am startservice -f 2 com.android.cts.net.hostside.app2/.MyForegroundService");
+ executeShellCommand(String.format("am startservice -f 2 %s/%s",
+ TEST_APP2_PKG, TEST_APP2_SERVICE_CLASS));
// NOTE: cannot assert state because it depends on whether activity was on top before.
}
- /**
- * Launches an activity on app2 so its process is elevated to foreground status.
- */
- protected void launchActivity() throws Exception {
- turnScreenOn();
- executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity");
- final int maxTries = 30;
- ProcessState state = null;
- for (int i = 1; i <= maxTries; i++) {
- state = getProcessStateByUid(mUid);
- if (state.state == PROCESS_STATE_TOP) return;
- Log.w(TAG, "launchActivity(): uid " + mUid + " not on TOP state on attempt #" + i
- + "; turning screen on and sleeping 1s before checking again");
- turnScreenOn();
- SystemClock.sleep(SECOND_IN_MS);
- }
- fail("App2 is not on foreground state after " + maxTries + " attempts: " + state);
+ private Binder getNewNetworkStateObserver(final CountDownLatch latch,
+ final String[] errors) {
+ return new INetworkStateObserver.Stub() {
+ @Override
+ public void onNetworkStateChecked(String resultData) {
+ errors[0] = checkForAvailabilityInResultData(resultData, true);
+ latch.countDown();
+ }
+ };
}
/**
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 7ca302f..4c907ff 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
@@ -100,8 +100,7 @@
// Make sure foreground app doesn't lose access upon enabling Data Saver.
setRestrictBackground(false);
- launchActivity();
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
setRestrictBackground(true);
assertForegroundNetworkAccess();
@@ -117,8 +116,7 @@
// Make sure foreground service doesn't lose access upon enabling Data Saver.
setRestrictBackground(false);
- startForegroundService();
- assertForegroundNetworkAccess();
+ launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
setRestrictBackground(true);
assertForegroundNetworkAccess();
stopForegroundService();
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 dc9a630..20bbd5a 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
@@ -16,7 +16,14 @@
package com.android.cts.net.hostside.app2;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.cts.net.hostside.INetworkStateObserver;
public final class Common {
@@ -42,6 +49,9 @@
static final String NOTIFICATION_TYPE_ACTION_BUNDLE = "ACTION_BUNDLE";
static final String NOTIFICATION_TYPE_ACTION_REMOTE_INPUT = "ACTION_REMOTE_INPUT";
+ static final String TEST_PKG = "com.android.cts.net.hostside";
+ static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+
static int getUid(Context context) {
final String packageName = context.getPackageName();
try {
@@ -50,4 +60,26 @@
throw new IllegalStateException("Could not get UID for " + packageName, e);
}
}
+
+ static void notifyNetworkStateObserver(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ final Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return;
+ }
+ final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
+ extras.getBinder(KEY_NETWORK_STATE_OBSERVER));
+ if (observer != null) {
+ AsyncTask.execute(() -> {
+ try {
+ observer.onNetworkStateChecked(
+ MyBroadcastReceiver.checkNetworkStatus(context));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error occured while notifying the observer: " + e);
+ }
+ });
+ }
+ }
}
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index 444b696..da7e704 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -17,30 +17,47 @@
import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY;
import static com.android.cts.net.hostside.app2.Common.TAG;
+import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.RemoteException;
import android.util.Log;
+import com.android.cts.net.hostside.INetworkStateObserver;
+
/**
* Activity used to bring process to foreground.
*/
public class MyActivity extends Activity {
+ private BroadcastReceiver finishCommandReceiver = null;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- registerReceiver(new BroadcastReceiver() {
-
+ Common.notifyNetworkStateObserver(this, getIntent());
+ finishCommandReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Finishing MyActivity");
MyActivity.this.finish();
- }}, new IntentFilter(ACTION_FINISH_ACTIVITY));
+ }
+ };
+ registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
+ }
+
+ @Override
+ public void finish() {
+ if (finishCommandReceiver != null) {
+ unregisterReceiver(finishCommandReceiver);
+ }
+ super.finish();
}
@Override
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
index fa3fdd1..ff4ba65 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
@@ -16,15 +16,22 @@
package com.android.cts.net.hostside.app2;
import static com.android.cts.net.hostside.app2.Common.TAG;
+import static com.android.cts.net.hostside.app2.Common.TEST_PKG;
+
import android.R;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
import android.util.Log;
+import com.android.cts.net.hostside.INetworkStateObserver;
+
/**
* Service used to change app state to FOREGROUND_SERVICE.
*/
@@ -51,6 +58,7 @@
startForeground(42, new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine
.build());
+ Common.notifyNetworkStateObserver(this, intent);
break;
case FLAG_STOP_FOREGROUND:
Log.d(TAG, "Stopping foreground");