From 3953e40365470b468db1e95e3a47ed627a5cae39 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 14 Mar 2019 10:30:06 +0800 Subject: [PATCH 1/6] Fix API Review issues. Modify the method name in LinkProperties. Bug: 126699682 Test: make cts passed. Change-Id: I3729e8915a8eff36e8de9035b5bf1571f8609e42 --- tests/cts/net/src/android/net/cts/DnsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/DnsTest.java b/tests/cts/net/src/android/net/cts/DnsTest.java index 84231c25a8..746dcb0a1c 100644 --- a/tests/cts/net/src/android/net/cts/DnsTest.java +++ b/tests/cts/net/src/android/net/cts/DnsTest.java @@ -287,7 +287,7 @@ public class DnsTest extends AndroidTestCase { final NetworkCallback callback = new NetworkCallback() { @Override public void onLinkPropertiesChanged(Network network, LinkProperties lp) { - if (lp.hasGlobalIPv6Address()) { + if (lp.hasGlobalIpv6Address()) { latch.countDown(); } } From e16d426550b6683e4abf9dc70004d00bad548804 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 14 Mar 2019 14:31:28 -0700 Subject: [PATCH 2/6] Wifi: Rename class name WifiManager_WifiLockTest This commit renames both the class name and the file name from WifiManager_WifiLockTest into WifiLockTest since WifiManager is implied from the package and directory hierarchy. Bug: 34905427 Test: atest android.net.wifi.cts Change-Id: Iaade2ba98cb1608384c2527eddb29bb6d020bf78 --- .../{WifiManager_WifiLockTest.java => WifiLockTest.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/cts/net/src/android/net/wifi/cts/{WifiManager_WifiLockTest.java => WifiLockTest.java} (93%) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java similarity index 93% rename from tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java rename to tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java index e08a972bd0..0703e6096b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java @@ -21,9 +21,9 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -public class WifiManager_WifiLockTest extends AndroidTestCase { +public class WifiLockTest extends AndroidTestCase { - private static final String WIFI_TAG = "WifiManager_WifiLockTest"; + private static final String WIFI_TAG = "WifiLockTest"; /** * Verify acquire and release of High Performance wifi locks @@ -82,7 +82,7 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { wl.release(); assertFalse(wl.isHeld()); assertNotNull(wl.toString()); - // should be ignored + // releasing again after release: but ignored for non-referenced locks wl.release(); } } From 361584140b7d6c7ab117a4181045c57e551e5dbc Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 8 Mar 2019 16:41:03 +0800 Subject: [PATCH 3/6] Add cancel test cases for async DNS API Bug: 124882626 Test: built, flashed, booted atest DnsResolverTest Change-Id: I9b496821e422f71009319eeefc6f3c6c1e249111 --- .../src/android/net/cts/DnsResolverTest.java | 162 +++++++++++++++++- 1 file changed, 155 insertions(+), 7 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 6fbe586bb4..f6cc76852b 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -17,9 +17,11 @@ package android.net.cts; import static android.net.DnsResolver.CLASS_IN; +import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; +import static android.system.OsConstants.EBADF; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,6 +32,7 @@ import android.net.DnsResolver; import android.net.Network; import android.net.NetworkCapabilities; import android.net.ParseException; +import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; import android.system.ErrnoException; @@ -50,6 +53,7 @@ public class DnsResolverTest extends AndroidTestCase { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static final int TIMEOUT_MS = 12_000; + static final int CANCEL_RETRY_TIMES = 5; private ConnectivityManager mCM; private Executor mExecutor; @@ -118,7 +122,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -174,12 +178,19 @@ public class DnsResolverTest extends AndroidTestCase { class RawAnswerCallbackImpl extends DnsResolver.RawAnswerCallback { private final CountDownLatch mLatch = new CountDownLatch(1); private final String mMsg; - RawAnswerCallbackImpl(String msg) { + private final int mTimeout; + + RawAnswerCallbackImpl(@NonNull String msg, int timeout) { this.mMsg = msg; + this.mTimeout = timeout; + } + + RawAnswerCallbackImpl(@NonNull String msg) { + this(msg, TIMEOUT_MS); } public boolean waitForAnswer() throws InterruptedException { - return mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + return mLatch.await(mTimeout, TimeUnit.MILLISECONDS); } @Override @@ -210,7 +221,7 @@ public class DnsResolverTest extends AndroidTestCase { for (Network network : getTestableNetworks()) { final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -238,7 +249,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "Query with RawAnswerCallback " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, callback); + mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -276,7 +287,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + "but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -313,7 +324,7 @@ public class DnsResolverTest extends AndroidTestCase { } }; mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, callback); + mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); @@ -322,4 +333,141 @@ public class DnsResolverTest extends AndroidTestCase { } } } + + /** + * A query callback that ensures that the query is cancelled and that onAnswer is never + * called. If the query succeeds before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelCallback extends DnsResolver.RawAnswerCallback { + private static final int CANCEL_TIMEOUT = 3_000; + + private final CountDownLatch mLatch = new CountDownLatch(1); + private final String mMsg; + private final CancellationSignal mCancelSignal; + + VerifyCancelCallback(@NonNull String msg, @NonNull CancellationSignal cancelSignal) { + this.mMsg = msg; + this.mCancelSignal = cancelSignal; + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); + } + + @Override + public void onAnswer(@NonNull byte[] answer) { + if (mCancelSignal.isCanceled()) { + fail(mMsg + " should not have returned any answers"); + } + mLatch.countDown(); + } + + @Override + public void onParseException(@NonNull ParseException e) { + fail(mMsg + e.getMessage()); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + if (mCancelSignal.isCanceled() && e.errno == EBADF) return; + fail(mMsg + e.getMessage()); + } + } + + public void testQueryCancel() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "Test cancel query " + dname; + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + try { + retry = callback.needRetry(); + assertTrue(msg + " query was not cancelled", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(msg + "Waiting for DNS lookup was interrupted"); + } + } while (retry); + } + } + + public void testQueryBlobCancel() throws ErrnoException { + final byte[] blob = new byte[]{ + /* Header */ + 0x55, 0x66, /* Transaction ID */ + 0x01, 0x00, /* Flags */ + 0x00, 0x01, /* Questions */ + 0x00, 0x00, /* Answer RRs */ + 0x00, 0x00, /* Authority RRs */ + 0x00, 0x00, /* Additional RRs */ + /* Queries */ + 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */ + 0x00, 0x01, /* Type */ + 0x00, 0x01 /* Class */ + }; + final String msg = "Test cancel raw Query " + byteArrayToHexString(blob); + // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect + // that the query is cancelled before it succeeds. If it is not cancelled before it + // succeeds, retry the until it is. + for (Network network : getTestableNetworks()) { + boolean retry = false; + int round = 0; + do { + if (++round > CANCEL_RETRY_TIMES) { + fail(msg + " cancel failed " + CANCEL_RETRY_TIMES + " times"); + } + final CountDownLatch latch = new CountDownLatch(1); + final CancellationSignal cancelSignal = new CancellationSignal(); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); + mDns.query(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mExecutor.execute(() -> { + cancelSignal.cancel(); + latch.countDown(); + }); + try { + retry = callback.needRetry(); + assertTrue(msg + " cancel is not done", + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } while (retry); + } + } + + public void testCancelBeforeQuery() throws ErrnoException { + final String dname = "www.google.com"; + final String msg = "Test cancelled query " + dname; + for (Network network : getTestableNetworks()) { + final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg, 3_000); + final CancellationSignal cancelSignal = new CancellationSignal(); + cancelSignal.cancel(); + mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mExecutor, cancelSignal, callback); + try { + assertTrue(msg + " should not return any answers", + !callback.waitForAnswer()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } } From d05db41eb7a413339d25f8bd37f44b229980a1a5 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 19 Mar 2019 21:34:38 +0800 Subject: [PATCH 4/6] Export API of listening for network change events in app2 Currently, due to foreground app will never get blocked by NetworkPolicyManagerService, so onBlockedStatusChanged cannot be tested under cts net app. Thus, listen for network change events in app2 allows subsequent tests on NetworkCallbacks. Bug: 118862340 Test: m -j cts Change-Id: I26ca370fc6ae4dd3f32ce6cf448bae83f3fbfbcc --- tests/cts/hostside/aidl/Android.mk | 1 + .../android/cts/net/hostside/IMyService.aidl | 3 + .../cts/net/hostside/INetworkCallback.aidl | 25 +++++++ ...ractRestrictBackgroundNetworkTestCase.java | 4 + .../cts/net/hostside/MyServiceClient.java | 6 +- .../cts/net/hostside/app2/MyService.java | 74 ++++++++++++++++++- 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl diff --git a/tests/cts/hostside/aidl/Android.mk b/tests/cts/hostside/aidl/Android.mk index 85f71c3726..20dabc15b2 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/INetworkCallback.aidl \ com/android/cts/net/hostside/INetworkStateObserver.aidl \ com/android/cts/net/hostside/IRemoteSocketFactory.aidl LOCAL_MODULE := CtsHostsideNetworkTestsAidl diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl index 72d105990e..a820ae581f 100644 --- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl @@ -16,10 +16,13 @@ package com.android.cts.net.hostside; +import com.android.cts.net.hostside.INetworkCallback; + interface IMyService { void registerBroadcastReceiver(); int getCounters(String receiverName, String action); String checkNetworkStatus(); String getRestrictBackgroundStatus(); void sendNotification(int notificationId, String notificationType); + void registerNetworkCallback(in INetworkCallback cb); } diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl new file mode 100644 index 0000000000..740ec26ee2 --- /dev/null +++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkCallback.aidl @@ -0,0 +1,25 @@ +/* + * 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 android.net.Network; + +interface INetworkCallback { + void onBlockedStatusChanged(in Network network, boolean blocked); + void onAvailable(in Network network); + void onLost(in Network network); +} 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 5232372047..d15913d85c 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 @@ -962,6 +962,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation fail("app2 receiver is not ready"); } + protected void registerNetworkCallback(INetworkCallback cb) throws Exception { + mServiceClient.registerNetworkCallback(cb); + } + /** * Registers a {@link NotificationListenerService} implementation that will execute the * notification actions right after the notification is sent. diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java index e2976c2150..3ee7b99c35 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java @@ -26,8 +26,6 @@ import android.os.RemoteException; import com.android.cts.net.hostside.IMyService; -import java.io.FileDescriptor; - public class MyServiceClient { private static final int TIMEOUT_MS = 5000; private static final String PACKAGE = MyServiceClient.class.getPackage().getName(); @@ -98,4 +96,8 @@ public class MyServiceClient { public void sendNotification(int notificationId, String notificationType) throws RemoteException { mService.sendNotification(notificationId, notificationType); } + + public void registerNetworkCallback(INetworkCallback cb) throws RemoteException { + mService.registerNetworkCallback(cb); + } } diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java index 2496c4ac7d..ec536aff68 100644 --- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java +++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java @@ -16,6 +16,7 @@ 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_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; import static com.android.cts.net.hostside.app2.Common.TAG; @@ -26,13 +27,16 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.os.IBinder; -import android.os.Looper; +import android.os.RemoteException; import android.util.Log; -import android.widget.Toast; import com.android.cts.net.hostside.IMyService; +import com.android.cts.net.hostside.INetworkCallback; /** * Service used to dynamically register a broadcast receiver. @@ -40,7 +44,10 @@ import com.android.cts.net.hostside.IMyService; public class MyService extends Service { private static final String NOTIFICATION_CHANNEL_ID = "MyService"; + ConnectivityManager mCm; + private MyBroadcastReceiver mReceiver; + private ConnectivityManager.NetworkCallback mNetworkCallback; // TODO: move MyBroadcast static functions here - they were kept there to make git diff easier. @@ -81,8 +88,67 @@ public class MyService extends Service { MyBroadcastReceiver .sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID, notificationId, notificationType); } + + @Override + public void registerNetworkCallback(INetworkCallback cb) { + if (mNetworkCallback != null) { + Log.d(TAG, "unregister previous network callback: " + mNetworkCallback); + unregisterNetworkCallback(); + } + Log.d(TAG, "registering network callback"); + + mNetworkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + try { + cb.onBlockedStatusChanged(network, blocked); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onBlockedStatusChanged: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onAvailable(Network network) { + try { + cb.onAvailable(network); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onAvailable: " + e); + unregisterNetworkCallback(); + } + } + + @Override + public void onLost(Network network) { + try { + cb.onLost(network); + } catch (RemoteException e) { + Log.d(TAG, "Cannot send onLost: " + e); + unregisterNetworkCallback(); + } + } + }; + mCm.registerNetworkCallback(makeWifiNetworkRequest(), mNetworkCallback); + try { + cb.asBinder().linkToDeath(() -> unregisterNetworkCallback(), 0); + } catch (RemoteException e) { + unregisterNetworkCallback(); + } + } }; + private void unregisterNetworkCallback() { + Log.d(TAG, "unregistering network callback"); + mCm.unregisterNetworkCallback(mNetworkCallback); + mNetworkCallback = null; + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + @Override public IBinder onBind(Intent intent) { return mBinder; @@ -94,6 +160,8 @@ public class MyService extends Service { ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) .createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT)); + mCm = (ConnectivityManager) getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); } @Override From 27e1316c337fe96920061ebe2ac0120b1de50536 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 20 Mar 2019 14:45:10 +0800 Subject: [PATCH 5/6] Add cts test cases for NetworkCallback.onBlockedStatusChanged Bug: 118862340 Test: atest HostsideNetworkCallbackTests Change-Id: Ic19b3b648a94adf4449393beb9b30ad7a7dc2283 --- ...ractRestrictBackgroundNetworkTestCase.java | 17 ++ .../cts/net/hostside/DataSaverModeTest.java | 17 -- .../cts/net/hostside/NetworkCallbackTest.java | 241 ++++++++++++++++++ .../cts/net/HostsideNetworkCallbackTests.java | 42 +++ 4 files changed, 300 insertions(+), 17 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java 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 d15913d85c..bbc0354e2f 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 @@ -369,6 +369,23 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation 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. */ 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 599a31ce1c..72563d499e 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 @@ -73,23 +73,6 @@ public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase return mIsDataSaverSupported && super.isSupported(); } - /** - * 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. - */ - private boolean isDataSaverSupported() throws Exception { - assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - try { - setRestrictBackground(true); - return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED); - } finally { - setRestrictBackground(false); - } - } - public void testGetRestrictBackgroundStatus_disabled() throws Exception { if (!isSupported()) return; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java new file mode 100644 index 0000000000..24dde9d356 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java @@ -0,0 +1,241 @@ +/* + * 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 android.net.Network; + +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase { + + private boolean mIsDataSaverSupported; + private Network mNetwork; + private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback(); + + enum CallbackState { + NONE, + AVAILABLE, + LOST, + BLOCKED_STATUS + } + + private static class CallbackInfo { + public final CallbackState state; + public final Network network; + public final Object arg; + + CallbackInfo(CallbackState s, Network n, Object o) { + state = s; network = n; arg = o; + } + + public String toString() { + return String.format("%s (%s) (%s)", state, network, arg); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CallbackInfo)) return false; + // Ignore timeMs, since it's unpredictable. + final CallbackInfo other = (CallbackInfo) o; + return (state == other.state) && Objects.equals(network, other.network) + && Objects.equals(arg, other.arg); + } + + @Override + public int hashCode() { + return Objects.hash(state, network, arg); + } + } + + private class TestNetworkCallback extends INetworkCallback.Stub { + private static final int TEST_CALLBACK_TIMEOUT_MS = 200; + + private final LinkedBlockingQueue mCallbacks = new LinkedBlockingQueue<>(); + + protected void setLastCallback(CallbackState state, Network network, Object o) { + mCallbacks.offer(new CallbackInfo(state, network, o)); + } + + CallbackInfo nextCallback(int timeoutMs) { + CallbackInfo cb = null; + try { + cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } + if (cb == null) { + fail("Did not receive callback after " + timeoutMs + "ms"); + } + return cb; + } + + CallbackInfo expectCallback(CallbackState state, Network expectedNetwork, Object o) { + final CallbackInfo expected = new CallbackInfo(state, expectedNetwork, o); + final CallbackInfo actual = nextCallback(TEST_CALLBACK_TIMEOUT_MS); + assertEquals("Unexpected callback:", expected, actual); + return actual; + } + + @Override + public void onAvailable(Network network) { + setLastCallback(CallbackState.AVAILABLE, network, null); + } + + @Override + public void onLost(Network network) { + setLastCallback(CallbackState.LOST, network, null); + } + + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked); + } + + public void expectLostCallback(Network expectedNetwork) { + expectCallback(CallbackState.LOST, expectedNetwork, null); + } + + public void expectAvailableCallback(Network expectedNetwork) { + expectCallback(CallbackState.AVAILABLE, expectedNetwork, null); + } + + public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) { + expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, + expectBlocked); + } + + void assertNoCallback() { + CallbackInfo cb = null; + try { + cb = mCallbacks.poll(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // Expected. + } + if (cb != null) { + assertNull("Unexpected callback: " + cb, cb); + } + } + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + mIsDataSaverSupported = isDataSaverSupported(); + + mNetwork = mCm.getActiveNetwork(); + + // Set initial state. + setBatterySaverMode(false); + registerBroadcastReceiver(); + + if (!mIsDataSaverSupported) return; + setRestrictBackground(false); + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(0); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + if (!mIsDataSaverSupported) return; + + try { + resetMeteredNetwork(); + } finally { + setRestrictBackground(false); + } + } + + public void testOnBlockedStatusChanged_data_saver() throws Exception { + if (!mIsDataSaverSupported) return; + + // Prepare metered wifi + if (!setMeteredNetwork()) return; + + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable restrict background + setRestrictBackground(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Add to whitelist + addRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Remove from whitelist + removeRestrictBackgroundWhitelist(mUid); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Set to non-metered network + setUnmeteredNetwork(); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Disable restrict background, should not trigger callback + setRestrictBackground(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.assertNoCallback(); + } + + + public void testOnBlockedStatusChanged_power_saver() throws Exception { + // Prepare metered wifi + if (!setMeteredNetwork()) return; + + // Register callback + registerNetworkCallback((INetworkCallback.Stub) mTestNetworkCallback); + mTestNetworkCallback.expectAvailableCallback(mNetwork); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + + // Set to non-metered network + setUnmeteredNetwork(); + mTestNetworkCallback.assertNoCallback(); + + // Enable Power Saver + setBatterySaverMode(true); + assertBackgroundNetworkAccess(false); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, true); + + // Disable Power Saver + setBatterySaverMode(false); + assertBackgroundNetworkAccess(true); + mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false); + } + + // TODO: 1. test against VPN lockdown. + // 2. test against multiple networks. +} diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java new file mode 100644 index 0000000000..8d6c4acd7d --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java @@ -0,0 +1,42 @@ +/* + * 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; +public class HostsideNetworkCallbackTests extends HostsideNetworkTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + uninstallPackage(TEST_APP2_PKG, true); + } + + public void testOnBlockedStatusChanged_data_saver() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_data_saver"); + } + + public void testOnBlockedStatusChanged_power_saver() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_power_saver"); + } +} + From f011d5f95bf73c8f0a64fe15ddd0ef29ca253863 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 25 Mar 2019 13:40:16 +0900 Subject: [PATCH 6/6] Enable instant and ABI XML tags for native networking tests. These tests include native code so mark them as multi_abi. They also pass in instant mode so mark them instant_app. Fix: 123367032 Fix: 123367595 Test: atest CtsNativeNetDnsTestCases CtsNativeNetTestCases Test: cts-tradefed run commandAndExit cts --enable-parameterized-modules --module-parameter instant_app -m CtsNativeNetDnsTestCases Test: cts-tradefed run commandAndExit cts --enable-parameterized-modules --module-parameter instant_app -m CtsNativeNetTestCases Change-Id: Id66705ecb012a07aa34318f41afb1840dd25b9e3 --- tests/cts/net/native/dns/AndroidTest.xml | 2 ++ tests/cts/net/native/qtaguid/AndroidTest.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/cts/net/native/dns/AndroidTest.xml b/tests/cts/net/native/dns/AndroidTest.xml index e63c6789a5..fe88cdaffe 100644 --- a/tests/cts/net/native/dns/AndroidTest.xml +++ b/tests/cts/net/native/dns/AndroidTest.xml @@ -16,6 +16,8 @@