diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk index 58be21f608..85f71c3726 100644 --- a/tests/cts/hostside/aidl/Android.mk +++ b/tests/cts/hostside/aidl/Android.mk @@ -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) 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 0000000000..09f3120ba9 --- /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 78ba4b9514..0e35b1b8ed 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 @@ 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); 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 50bcc6058e..546a550d5c 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 @@ 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(); 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 6669af5edd..68f6e7439d 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 @@ 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(); } 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 014d7ae6e2..3374378605 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_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(); + } + }; } /** 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 7ca302f52a..4c907fff55 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 @@ 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(); 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 dc9a63036a..20bbd5a75c 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 @@ 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); + } + }); + } + } } 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 444b696962..da7e704e8b 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 @@ 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 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 fa3fdd148c..ff4ba656b1 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 @@ 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");