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
This commit is contained in:
Sudheer Shanka
2017-01-09 16:02:02 -08:00
parent 51d07a361b
commit e66cee4861
10 changed files with 160 additions and 51 deletions

View File

@@ -19,6 +19,7 @@ LOCAL_MODULE_TAGS := tests
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)

View File

@@ -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);
}

View File

@@ -91,9 +91,7 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork
// 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 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork
// Same for foreground service.
setAppIdle(true);
startForegroundService();
assertAppIdle(true); // Sanity check - still idle
assertForegroundServiceNetworkAccess();
launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
stopForegroundService();
assertAppIdle(true);
assertBackgroundNetworkAccess(false);

View File

@@ -87,8 +87,7 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou
// 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 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou
// 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();

View File

@@ -88,8 +88,7 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor
// 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 @@ abstract class AbstractDozeModeTestCase extends AbstractRestrictBackgroundNetwor
// leaves Doze Mode.
@Override
protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception {
startForegroundService();
assertForegroundServiceNetworkAccess();
launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_FOREGROUND_SERVICE);
stopForegroundService();
assertBackgroundState();
}

View File

@@ -22,11 +22,13 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
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;
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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
*/
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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
*/
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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
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 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
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();
}
};
}
/**

View File

@@ -100,8 +100,7 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
// 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 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase
// 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();

View File

@@ -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 @@ public final class Common {
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 @@ public final class Common {
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);
}
});
}
}
}

View File

@@ -17,30 +17,47 @@ package com.android.cts.net.hostside.app2;
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

View File

@@ -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 @@ public class MyForegroundService extends Service {
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");