• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.cts;
18 
19 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
20 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
21 import static android.Manifest.permission.NETWORK_SETTINGS;
22 import static android.Manifest.permission.READ_DEVICE_CONFIG;
23 import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
24 import static android.content.pm.PackageManager.FEATURE_ETHERNET;
25 import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
26 import static android.content.pm.PackageManager.FEATURE_USB_HOST;
27 import static android.content.pm.PackageManager.FEATURE_WATCH;
28 import static android.content.pm.PackageManager.FEATURE_WIFI;
29 import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
30 import static android.content.pm.PackageManager.GET_PERMISSIONS;
31 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
32 import static android.net.ConnectivityManager.EXTRA_NETWORK;
33 import static android.net.ConnectivityManager.EXTRA_NETWORK_REQUEST;
34 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
35 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
36 import static android.net.ConnectivityManager.TYPE_ETHERNET;
37 import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
38 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
39 import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY;
40 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
41 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
42 import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
43 import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
44 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
45 import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
46 import static android.net.ConnectivityManager.TYPE_PROXY;
47 import static android.net.ConnectivityManager.TYPE_VPN;
48 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
49 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
50 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
51 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
52 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
53 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
54 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
55 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
56 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
57 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
58 import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
59 import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
60 import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
61 import static android.net.cts.util.CtsNetUtils.TEST_HOST;
62 import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
63 import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback;
64 import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL;
65 import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL;
66 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
67 import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
68 import static android.system.OsConstants.AF_INET;
69 import static android.system.OsConstants.AF_INET6;
70 import static android.system.OsConstants.AF_UNSPEC;
71 
72 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
73 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
74 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
75 import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
76 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
77 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
78 import static com.android.testutils.MiscAsserts.assertThrows;
79 import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
80 import static com.android.testutils.TestPermissionUtil.runAsShell;
81 
82 import static org.junit.Assert.assertArrayEquals;
83 import static org.junit.Assert.assertEquals;
84 import static org.junit.Assert.assertFalse;
85 import static org.junit.Assert.assertNotEquals;
86 import static org.junit.Assert.assertNotNull;
87 import static org.junit.Assert.assertNotSame;
88 import static org.junit.Assert.assertNull;
89 import static org.junit.Assert.assertTrue;
90 import static org.junit.Assert.fail;
91 import static org.junit.Assume.assumeTrue;
92 
93 import android.annotation.NonNull;
94 import android.app.Instrumentation;
95 import android.app.PendingIntent;
96 import android.app.UiAutomation;
97 import android.content.BroadcastReceiver;
98 import android.content.ContentResolver;
99 import android.content.Context;
100 import android.content.Intent;
101 import android.content.IntentFilter;
102 import android.content.pm.PackageInfo;
103 import android.content.pm.PackageManager;
104 import android.content.res.Resources;
105 import android.net.ConnectivityManager;
106 import android.net.ConnectivityManager.NetworkCallback;
107 import android.net.ConnectivitySettingsManager;
108 import android.net.InetAddresses;
109 import android.net.IpSecManager;
110 import android.net.IpSecManager.UdpEncapsulationSocket;
111 import android.net.LinkAddress;
112 import android.net.LinkProperties;
113 import android.net.Network;
114 import android.net.NetworkAgent;
115 import android.net.NetworkAgentConfig;
116 import android.net.NetworkCapabilities;
117 import android.net.NetworkInfo;
118 import android.net.NetworkInfo.DetailedState;
119 import android.net.NetworkInfo.State;
120 import android.net.NetworkProvider;
121 import android.net.NetworkRequest;
122 import android.net.NetworkScore;
123 import android.net.NetworkSpecifier;
124 import android.net.NetworkStateSnapshot;
125 import android.net.NetworkUtils;
126 import android.net.OemNetworkPreferences;
127 import android.net.ProxyInfo;
128 import android.net.SocketKeepalive;
129 import android.net.TelephonyNetworkSpecifier;
130 import android.net.TestNetworkInterface;
131 import android.net.TestNetworkManager;
132 import android.net.Uri;
133 import android.net.cts.util.CtsNetUtils;
134 import android.net.cts.util.CtsTetheringUtils;
135 import android.net.util.KeepaliveUtils;
136 import android.net.wifi.WifiManager;
137 import android.os.Binder;
138 import android.os.Build;
139 import android.os.Handler;
140 import android.os.Looper;
141 import android.os.MessageQueue;
142 import android.os.Process;
143 import android.os.SystemClock;
144 import android.os.SystemProperties;
145 import android.os.UserHandle;
146 import android.os.VintfRuntimeInfo;
147 import android.platform.test.annotations.AppModeFull;
148 import android.provider.DeviceConfig;
149 import android.provider.Settings;
150 import android.telephony.SubscriptionManager;
151 import android.telephony.TelephonyManager;
152 import android.text.TextUtils;
153 import android.util.ArraySet;
154 import android.util.Log;
155 import android.util.Pair;
156 import android.util.Range;
157 
158 import androidx.test.InstrumentationRegistry;
159 import androidx.test.runner.AndroidJUnit4;
160 
161 import com.android.internal.util.ArrayUtils;
162 import com.android.modules.utils.build.SdkLevel;
163 import com.android.networkstack.apishim.ConnectivityManagerShimImpl;
164 import com.android.networkstack.apishim.ConstantsShim;
165 import com.android.networkstack.apishim.NetworkInformationShimImpl;
166 import com.android.networkstack.apishim.common.ConnectivityManagerShim;
167 import com.android.testutils.CompatUtil;
168 import com.android.testutils.DevSdkIgnoreRule;
169 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
170 import com.android.testutils.DevSdkIgnoreRuleKt;
171 import com.android.testutils.RecorderCallback.CallbackEntry;
172 import com.android.testutils.SkipPresubmit;
173 import com.android.testutils.TestHttpServer;
174 import com.android.testutils.TestNetworkTracker;
175 import com.android.testutils.TestableNetworkCallback;
176 
177 import junit.framework.AssertionFailedError;
178 
179 import libcore.io.Streams;
180 
181 import org.junit.After;
182 import org.junit.Before;
183 import org.junit.Rule;
184 import org.junit.Test;
185 import org.junit.runner.RunWith;
186 
187 import java.io.FileDescriptor;
188 import java.io.IOException;
189 import java.io.InputStream;
190 import java.io.InputStreamReader;
191 import java.io.OutputStream;
192 import java.net.HttpURLConnection;
193 import java.net.Inet4Address;
194 import java.net.Inet6Address;
195 import java.net.InetAddress;
196 import java.net.InetSocketAddress;
197 import java.net.MalformedURLException;
198 import java.net.Socket;
199 import java.net.URL;
200 import java.net.UnknownHostException;
201 import java.nio.charset.StandardCharsets;
202 import java.util.ArrayList;
203 import java.util.Collection;
204 import java.util.List;
205 import java.util.Objects;
206 import java.util.Set;
207 import java.util.concurrent.CompletableFuture;
208 import java.util.concurrent.CountDownLatch;
209 import java.util.concurrent.Executor;
210 import java.util.concurrent.ExecutorService;
211 import java.util.concurrent.Executors;
212 import java.util.concurrent.LinkedBlockingQueue;
213 import java.util.concurrent.TimeUnit;
214 import java.util.concurrent.TimeoutException;
215 import java.util.concurrent.atomic.AtomicInteger;
216 import java.util.function.Supplier;
217 import java.util.regex.Matcher;
218 import java.util.regex.Pattern;
219 
220 import fi.iki.elonen.NanoHTTPD.Method;
221 import fi.iki.elonen.NanoHTTPD.Response.IStatus;
222 import fi.iki.elonen.NanoHTTPD.Response.Status;
223 
224 @RunWith(AndroidJUnit4.class)
225 public class ConnectivityManagerTest {
226     @Rule
227     public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
228 
229     private static final String TAG = ConnectivityManagerTest.class.getSimpleName();
230 
231     public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
232     public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
233 
234     private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
235     private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
236     private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500;
237     private static final int MAX_KEEPALIVE_RETRY_COUNT = 3;
238     private static final int MIN_KEEPALIVE_INTERVAL = 10;
239 
240     private static final int NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
241     private static final int NO_CALLBACK_TIMEOUT_MS = 100;
242     private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
243     private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
244     // device could have only one interface: data, wifi.
245     private static final int MIN_NUM_NETWORK_TYPES = 1;
246 
247     // Airplane Mode BroadcastReceiver Timeout
248     private static final long AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 10_000L;
249 
250     // Timeout for applying uids allowed on restricted networks
251     private static final long APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS = 3_000L;
252 
253     // Minimum supported keepalive counts for wifi and cellular.
254     public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1;
255     public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3;
256 
257     private static final String NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME =
258             "config_networkMeteredMultipathPreference";
259     private static final String KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME =
260             "config_allowedUnprivilegedKeepalivePerUid";
261     private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME =
262             "config_reservedPrivilegedKeepaliveSlots";
263 
264     private static final LinkAddress TEST_LINKADDR = new LinkAddress(
265             InetAddresses.parseNumericAddress("2001:db8::8"), 64);
266 
267     private static final int AIRPLANE_MODE_OFF = 0;
268     private static final int AIRPLANE_MODE_ON = 1;
269 
270     private static final String TEST_HTTPS_URL_PATH = "/https_path";
271     private static final String TEST_HTTP_URL_PATH = "/http_path";
272     private static final String LOCALHOST_HOSTNAME = "localhost";
273     // Re-connecting to the AP, obtaining an IP address, revalidating can take a long time
274     private static final long WIFI_CONNECT_TIMEOUT_MS = 60_000L;
275 
276     private Context mContext;
277     private Instrumentation mInstrumentation;
278     private ConnectivityManager mCm;
279     private ConnectivityManagerShim mCmShim;
280     private WifiManager mWifiManager;
281     private PackageManager mPackageManager;
282     private final ArraySet<Integer> mNetworkTypes = new ArraySet<>();
283     private UiAutomation mUiAutomation;
284     private CtsNetUtils mCtsNetUtils;
285 
286     // Used for cleanup purposes.
287     private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>();
288 
289     private final TestHttpServer mHttpServer = new TestHttpServer(LOCALHOST_HOSTNAME);
290 
291     @Before
setUp()292     public void setUp() throws Exception {
293         mInstrumentation = InstrumentationRegistry.getInstrumentation();
294         mContext = mInstrumentation.getContext();
295         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
296         mCmShim = ConnectivityManagerShimImpl.newInstance(mContext);
297         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
298         mPackageManager = mContext.getPackageManager();
299         mCtsNetUtils = new CtsNetUtils(mContext);
300 
301         if (DevSdkIgnoreRuleKt.isDevSdkInRange(null /* minExclusive */,
302                 Build.VERSION_CODES.R /* maxInclusive */)) {
303             addLegacySupportedNetworkTypes();
304         } else {
305             addSupportedNetworkTypes();
306         }
307 
308         mUiAutomation = mInstrumentation.getUiAutomation();
309 
310         assertNotNull("CTS requires a working Internet connection", mCm.getActiveNetwork());
311     }
312 
addLegacySupportedNetworkTypes()313     private void addLegacySupportedNetworkTypes() {
314         // Network type support as expected for android R-
315         // Get com.android.internal.R.array.networkAttributes
316         int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
317         String[] naStrings = mContext.getResources().getStringArray(resId);
318         boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
319         for (String naString : naStrings) {
320             try {
321                 final String[] splitConfig = naString.split(",");
322                 // Format was name,type,radio,priority,restoreTime,dependencyMet
323                 final int type = Integer.parseInt(splitConfig[1]);
324                 if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(type)) {
325                     continue;
326                 }
327                 mNetworkTypes.add(type);
328             } catch (Exception e) {}
329         }
330     }
331 
addSupportedNetworkTypes()332     private void addSupportedNetworkTypes() {
333         final PackageManager pm = mContext.getPackageManager();
334         if (pm.hasSystemFeature(FEATURE_WIFI)) {
335             mNetworkTypes.add(TYPE_WIFI);
336         }
337         if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) {
338             mNetworkTypes.add(TYPE_WIFI_P2P);
339         }
340         if (mContext.getSystemService(TelephonyManager.class).isDataCapable()) {
341             mNetworkTypes.add(TYPE_MOBILE);
342             mNetworkTypes.add(TYPE_MOBILE_MMS);
343             mNetworkTypes.add(TYPE_MOBILE_SUPL);
344             mNetworkTypes.add(TYPE_MOBILE_DUN);
345             mNetworkTypes.add(TYPE_MOBILE_HIPRI);
346             mNetworkTypes.add(TYPE_MOBILE_FOTA);
347             mNetworkTypes.add(TYPE_MOBILE_IMS);
348             mNetworkTypes.add(TYPE_MOBILE_CBS);
349             mNetworkTypes.add(TYPE_MOBILE_IA);
350             mNetworkTypes.add(TYPE_MOBILE_EMERGENCY);
351         }
352         if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) {
353             mNetworkTypes.add(TYPE_BLUETOOTH);
354         }
355         if (pm.hasSystemFeature(FEATURE_WATCH)) {
356             mNetworkTypes.add(TYPE_PROXY);
357         }
358         if (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) {
359             mNetworkTypes.add(TYPE_ETHERNET);
360         }
361         mNetworkTypes.add(TYPE_VPN);
362     }
363 
364     @After
tearDown()365     public void tearDown() throws Exception {
366         // Release any NetworkRequests filed to connect mobile data.
367         if (mCtsNetUtils.cellConnectAttempted()) {
368             mCtsNetUtils.disconnectFromCell();
369         }
370 
371         if (TestUtils.shouldTestSApis()) {
372             runWithShellPermissionIdentity(
373                     () -> mCmShim.setRequireVpnForUids(false, mVpnRequiredUidRanges),
374                     NETWORK_SETTINGS);
375         }
376 
377         // All tests in this class require a working Internet connection as they start. Make
378         // sure there is still one as they end that's ready to use for the next test to use.
379         final TestNetworkCallback callback = new TestNetworkCallback();
380         mCm.registerDefaultNetworkCallback(callback);
381         try {
382             assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable());
383         } finally {
384             mCm.unregisterNetworkCallback(callback);
385         }
386     }
387 
388     @Test
testIsNetworkTypeValid()389     public void testIsNetworkTypeValid() {
390         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE));
391         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI));
392         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS));
393         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL));
394         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN));
395         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI));
396         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX));
397         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH));
398         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY));
399         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET));
400         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA));
401         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS));
402         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS));
403         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P));
404         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA));
405         assertFalse(mCm.isNetworkTypeValid(-1));
406         assertTrue(mCm.isNetworkTypeValid(0));
407         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE));
408         assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1));
409 
410         NetworkInfo[] ni = mCm.getAllNetworkInfo();
411 
412         for (NetworkInfo n: ni) {
413             assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType()));
414         }
415 
416     }
417 
418     @Test
testSetNetworkPreference()419     public void testSetNetworkPreference() {
420         // getNetworkPreference() and setNetworkPreference() are both deprecated so they do
421         // not preform any action.  Verify they are at least still callable.
422         mCm.setNetworkPreference(mCm.getNetworkPreference());
423     }
424 
425     @Test
testGetActiveNetworkInfo()426     public void testGetActiveNetworkInfo() {
427         NetworkInfo ni = mCm.getActiveNetworkInfo();
428 
429         assertNotNull("You must have an active network connection to complete CTS", ni);
430         assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType()));
431         assertTrue(ni.getState() == State.CONNECTED);
432     }
433 
434     @Test
testGetActiveNetwork()435     public void testGetActiveNetwork() {
436         Network network = mCm.getActiveNetwork();
437         assertNotNull("You must have an active network connection to complete CTS", network);
438 
439         NetworkInfo ni = mCm.getNetworkInfo(network);
440         assertNotNull("Network returned from getActiveNetwork was invalid", ni);
441 
442         // Similar to testGetActiveNetworkInfo above.
443         assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType()));
444         assertTrue(ni.getState() == State.CONNECTED);
445     }
446 
447     @Test
testGetNetworkInfo()448     public void testGetNetworkInfo() {
449         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) {
450             if (shouldBeSupported(type)) {
451                 NetworkInfo ni = mCm.getNetworkInfo(type);
452                 assertTrue("Info shouldn't be null for " + type, ni != null);
453                 State state = ni.getState();
454                 assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal()
455                            && state.ordinal() >= State.CONNECTING.ordinal());
456                 DetailedState ds = ni.getDetailedState();
457                 assertTrue("Bad detailed state for " + type,
458                            DetailedState.FAILED.ordinal() >= ds.ordinal()
459                            && ds.ordinal() >= DetailedState.IDLE.ordinal());
460             } else {
461                 assertNull("Info should be null for " + type, mCm.getNetworkInfo(type));
462             }
463         }
464     }
465 
466     @Test
testGetAllNetworkInfo()467     public void testGetAllNetworkInfo() {
468         NetworkInfo[] ni = mCm.getAllNetworkInfo();
469         assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES);
470         for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
471             int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0);
472             int foundCount = 0;
473             for (NetworkInfo i : ni) {
474                 if (i.getType() == type) foundCount++;
475             }
476             if (foundCount != desiredFoundCount) {
477                 Log.e(TAG, "failure in testGetAllNetworkInfo.  Dump of returned NetworkInfos:");
478                 for (NetworkInfo networkInfo : ni) Log.e(TAG, "  " + networkInfo);
479             }
480             assertTrue("Unexpected foundCount of " + foundCount + " for type " + type,
481                     foundCount == desiredFoundCount);
482         }
483     }
484 
getSubscriberIdForCellNetwork(Network cellNetwork)485     private String getSubscriberIdForCellNetwork(Network cellNetwork) {
486         final NetworkCapabilities cellCaps = mCm.getNetworkCapabilities(cellNetwork);
487         final NetworkSpecifier specifier = cellCaps.getNetworkSpecifier();
488         assertTrue(specifier instanceof TelephonyNetworkSpecifier);
489         // Get subscription from Telephony network specifier.
490         final int subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
491         assertNotEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, subId);
492 
493         // Get subscriber Id from telephony manager.
494         final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
495         return runWithShellPermissionIdentity(() -> tm.getSubscriberId(subId),
496                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
497     }
498 
499     @AppModeFull(reason = "Cannot request network in instant app mode")
500     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
501     @Test
testGetAllNetworkStateSnapshots()502     public void testGetAllNetworkStateSnapshots()
503             throws InterruptedException {
504         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
505         // Make sure cell is active to retrieve IMSI for verification in later step.
506         final Network cellNetwork = mCtsNetUtils.connectToCell();
507         final String subscriberId = getSubscriberIdForCellNetwork(cellNetwork);
508         assertFalse(TextUtils.isEmpty(subscriberId));
509 
510         // Verify the API cannot be called without proper permission.
511         assertThrows(SecurityException.class, () -> mCm.getAllNetworkStateSnapshots());
512 
513         // Get all networks, verify the result of getAllNetworkStateSnapshots matches the result
514         // got from other APIs.
515         final Network[] networks = mCm.getAllNetworks();
516         assertGreaterOrEqual(networks.length, 1);
517         final List<NetworkStateSnapshot> snapshots = runWithShellPermissionIdentity(
518                 () -> mCm.getAllNetworkStateSnapshots(), NETWORK_SETTINGS);
519         assertEquals(networks.length, snapshots.size());
520         for (final Network network : networks) {
521             // Can't use a lambda because it will cause the test to crash on R with
522             // NoClassDefFoundError.
523             NetworkStateSnapshot snapshot = null;
524             for (NetworkStateSnapshot item : snapshots) {
525                 if (item.getNetwork().equals(network)) {
526                     snapshot = item;
527                     break;
528                 }
529             }
530             assertNotNull(snapshot);
531             final NetworkCapabilities caps =
532                     Objects.requireNonNull(mCm.getNetworkCapabilities(network));
533             // Redact specifier of the capabilities of the snapshot before comparing since
534             // the result returned from getNetworkCapabilities always get redacted.
535             final NetworkSpecifier snapshotCapSpecifier =
536                     snapshot.getNetworkCapabilities().getNetworkSpecifier();
537             final NetworkSpecifier redactedSnapshotCapSpecifier =
538                     snapshotCapSpecifier == null ? null : snapshotCapSpecifier.redact();
539             assertEquals("", caps.describeImmutableDifferences(
540                     snapshot.getNetworkCapabilities()
541                             .setNetworkSpecifier(redactedSnapshotCapSpecifier)));
542             assertEquals(mCm.getLinkProperties(network), snapshot.getLinkProperties());
543             assertEquals(mCm.getNetworkInfo(network).getType(), snapshot.getLegacyType());
544 
545             if (network.equals(cellNetwork)) {
546                 assertEquals(subscriberId, snapshot.getSubscriberId());
547             }
548         }
549     }
550 
551     /**
552      * Tests that connections can be opened on WiFi and cellphone networks,
553      * and that they are made from different IP addresses.
554      */
555     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
556     @Test
557     @SkipPresubmit(reason = "Virtual devices use a single internet connection for all networks")
testOpenConnection()558     public void testOpenConnection() throws Exception {
559         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
560         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
561 
562         Network wifiNetwork = mCtsNetUtils.connectToWifi();
563         Network cellNetwork = mCtsNetUtils.connectToCell();
564         // This server returns the requestor's IP address as the response body.
565         URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
566         String wifiAddressString = httpGet(wifiNetwork, url);
567         String cellAddressString = httpGet(cellNetwork, url);
568 
569         assertFalse(String.format("Same address '%s' on two different networks (%s, %s)",
570                 wifiAddressString, wifiNetwork, cellNetwork),
571                 wifiAddressString.equals(cellAddressString));
572 
573         // Verify that the IP addresses that the requests appeared to come from are actually on the
574         // respective networks.
575         assertOnNetwork(wifiAddressString, wifiNetwork);
576         assertOnNetwork(cellAddressString, cellNetwork);
577 
578         assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
579     }
580 
581     /**
582      * Performs a HTTP GET to the specified URL on the specified Network, and returns
583      * the response body decoded as UTF-8.
584      */
httpGet(Network network, URL httpUrl)585     private static String httpGet(Network network, URL httpUrl) throws IOException {
586         HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
587         try {
588             InputStream inputStream = connection.getInputStream();
589             return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
590         } finally {
591             connection.disconnect();
592         }
593     }
594 
assertOnNetwork(String adressString, Network network)595     private void assertOnNetwork(String adressString, Network network) throws UnknownHostException {
596         InetAddress address = InetAddress.getByName(adressString);
597         LinkProperties linkProperties = mCm.getLinkProperties(network);
598         // To make sure that the request went out on the right network, check that
599         // the IP address seen by the server is assigned to the expected network.
600         // We can only do this for IPv6 addresses, because in IPv4 we will likely
601         // have a private IPv4 address, and that won't match what the server sees.
602         if (address instanceof Inet6Address) {
603             assertContains(linkProperties.getAddresses(), address);
604         }
605     }
606 
assertContains(Collection<T> collection, T element)607     private static<T> void assertContains(Collection<T> collection, T element) {
608         assertTrue(element + " not found in " + collection, collection.contains(element));
609     }
610 
assertStartUsingNetworkFeatureUnsupported(int networkType, String feature)611     private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
612         try {
613             mCm.startUsingNetworkFeature(networkType, feature);
614             fail("startUsingNetworkFeature is no longer supported in the current API version");
615         } catch (UnsupportedOperationException expected) {}
616     }
617 
assertStopUsingNetworkFeatureUnsupported(int networkType, String feature)618     private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) {
619         try {
620             mCm.startUsingNetworkFeature(networkType, feature);
621             fail("stopUsingNetworkFeature is no longer supported in the current API version");
622         } catch (UnsupportedOperationException expected) {}
623     }
624 
assertRequestRouteToHostUnsupported(int networkType, int hostAddress)625     private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) {
626         try {
627             mCm.requestRouteToHost(networkType, hostAddress);
628             fail("requestRouteToHost is no longer supported in the current API version");
629         } catch (UnsupportedOperationException expected) {}
630     }
631 
632     @Test
testStartUsingNetworkFeature()633     public void testStartUsingNetworkFeature() {
634 
635         final String invalidateFeature = "invalidateFeature";
636         final String mmsFeature = "enableMMS";
637 
638         assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
639         assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
640         assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
641     }
642 
shouldEthernetBeSupported()643     private boolean shouldEthernetBeSupported() {
644         // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies.
645         // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on
646         // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or
647         // if the device can be a USB host and thus can use USB Ethernet adapters.
648         //
649         // Note that this test this will still fail in instant mode if a device supports Ethernet
650         // via other hardware means. We are not currently aware of any such device.
651         return (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) ||
652             mPackageManager.hasSystemFeature(FEATURE_ETHERNET) ||
653             mPackageManager.hasSystemFeature(FEATURE_USB_HOST);
654     }
655 
shouldBeSupported(int networkType)656     private boolean shouldBeSupported(int networkType) {
657         return mNetworkTypes.contains(networkType)
658             || (networkType == ConnectivityManager.TYPE_VPN)
659             || (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported());
660     }
661 
662     @Test
testIsNetworkSupported()663     public void testIsNetworkSupported() {
664         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
665             boolean supported = mCm.isNetworkSupported(type);
666             if (shouldBeSupported(type)) {
667                 assertTrue("Network type " + type + " should be supported", supported);
668             } else {
669                 assertFalse("Network type " + type + " should not be supported", supported);
670             }
671         }
672     }
673 
674     @Test
testRequestRouteToHost()675     public void testRequestRouteToHost() {
676         for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
677             assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
678         }
679     }
680 
681     @Test
testTest()682     public void testTest() {
683         mCm.getBackgroundDataSetting();
684     }
685 
makeDefaultRequest()686     private NetworkRequest makeDefaultRequest() {
687         // Make a request that is similar to the way framework tracks the system
688         // default network.
689         return new NetworkRequest.Builder()
690                 .clearCapabilities()
691                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
692                 .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
693                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
694                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
695                 .build();
696     }
697 
makeWifiNetworkRequest()698     private NetworkRequest makeWifiNetworkRequest() {
699         return new NetworkRequest.Builder()
700                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
701                 .addCapability(NET_CAPABILITY_INTERNET)
702                 .build();
703     }
704 
makeCellNetworkRequest()705     private NetworkRequest makeCellNetworkRequest() {
706         return new NetworkRequest.Builder()
707                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
708                 .addCapability(NET_CAPABILITY_INTERNET)
709                 .build();
710     }
711 
712     @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
713     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testIsPrivateDnsBroken()714     public void testIsPrivateDnsBroken() throws InterruptedException {
715         final String invalidPrivateDnsServer = "invalidhostname.example.com";
716         final String goodPrivateDnsServer = "dns.google";
717         mCtsNetUtils.storePrivateDnsSetting();
718         final TestableNetworkCallback cb = new TestableNetworkCallback();
719         mCm.registerNetworkCallback(makeWifiNetworkRequest(), cb);
720         try {
721             // Verifying the good private DNS sever
722             mCtsNetUtils.setPrivateDnsStrictMode(goodPrivateDnsServer);
723             final Network networkForPrivateDns =  mCtsNetUtils.ensureWifiConnected();
724             cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
725                     entry -> (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
726                     .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
727 
728             // Verifying the broken private DNS sever
729             mCtsNetUtils.setPrivateDnsStrictMode(invalidPrivateDnsServer);
730             cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
731                     entry -> (((CallbackEntry.CapabilitiesChanged) entry).getCaps()
732                     .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
733         } finally {
734             mCtsNetUtils.restorePrivateDnsSetting();
735             // Toggle wifi to make sure it is re-validated
736             reconnectWifi();
737         }
738     }
739 
740     /**
741      * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
742      * see if we get a callback for the TRANSPORT_WIFI transport type being available.
743      *
744      * <p>In order to test that a NetworkCallback occurs, we need some change in the network
745      * state (either a transport or capability is now available). The most straightforward is
746      * WiFi. We could add a version that uses the telephony data connection but it's not clear
747      * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?).
748      */
749     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
750     @Test
testRegisterNetworkCallback()751     public void testRegisterNetworkCallback() {
752         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
753 
754         // We will register for a WIFI network being available or lost.
755         final TestNetworkCallback callback = new TestNetworkCallback();
756         mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
757 
758         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
759         mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
760 
761         final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
762         final TestNetworkCallback perUidCallback = new TestNetworkCallback();
763         final TestNetworkCallback bestMatchingCallback = new TestNetworkCallback();
764         final Handler h = new Handler(Looper.getMainLooper());
765         if (TestUtils.shouldTestSApis()) {
766             runWithShellPermissionIdentity(() -> {
767                 mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
768                 mCmShim.registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h);
769             }, NETWORK_SETTINGS);
770             mCm.registerBestMatchingNetworkCallback(makeDefaultRequest(), bestMatchingCallback, h);
771         }
772 
773         Network wifiNetwork = null;
774 
775         try {
776             mCtsNetUtils.ensureWifiConnected();
777 
778             // Now we should expect to get a network callback about availability of the wifi
779             // network even if it was already connected as a state-based action when the callback
780             // is registered.
781             wifiNetwork = callback.waitForAvailable();
782             assertNotNull("Did not receive onAvailable for TRANSPORT_WIFI request",
783                     wifiNetwork);
784 
785             final Network defaultNetwork = defaultTrackingCallback.waitForAvailable();
786             assertNotNull("Did not receive onAvailable on default network callback",
787                     defaultNetwork);
788 
789             if (TestUtils.shouldTestSApis()) {
790                 assertNotNull("Did not receive onAvailable on system default network callback",
791                         systemDefaultCallback.waitForAvailable());
792                 final Network perUidNetwork = perUidCallback.waitForAvailable();
793                 assertNotNull("Did not receive onAvailable on per-UID default network callback",
794                         perUidNetwork);
795                 assertEquals(defaultNetwork, perUidNetwork);
796                 final Network bestMatchingNetwork = bestMatchingCallback.waitForAvailable();
797                 assertNotNull("Did not receive onAvailable on best matching network callback",
798                         bestMatchingNetwork);
799                 assertEquals(defaultNetwork, bestMatchingNetwork);
800             }
801 
802         } catch (InterruptedException e) {
803             fail("Broadcast receiver or NetworkCallback wait was interrupted.");
804         } finally {
805             mCm.unregisterNetworkCallback(callback);
806             mCm.unregisterNetworkCallback(defaultTrackingCallback);
807             if (TestUtils.shouldTestSApis()) {
808                 mCm.unregisterNetworkCallback(systemDefaultCallback);
809                 mCm.unregisterNetworkCallback(perUidCallback);
810                 mCm.unregisterNetworkCallback(bestMatchingCallback);
811             }
812         }
813     }
814 
815     /**
816      * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to
817      * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead
818      * of a {@code NetworkCallback}.
819      */
820     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
821     @Test
testRegisterNetworkCallback_withPendingIntent()822     public void testRegisterNetworkCallback_withPendingIntent() {
823         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
824 
825         // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
826         // action, NETWORK_CALLBACK_ACTION.
827         final IntentFilter filter = new IntentFilter();
828         filter.addAction(NETWORK_CALLBACK_ACTION);
829 
830         final ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
831                 mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
832         mContext.registerReceiver(receiver, filter);
833 
834         // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
835         final Intent intent = new Intent(NETWORK_CALLBACK_ACTION)
836                 .setPackage(mContext.getPackageName());
837         // While ConnectivityService would put extra info such as network or request id before
838         // broadcasting the inner intent. The MUTABLE flag needs to be added accordingly.
839         // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+ or
840         //  shims.
841         final int pendingIntentFlagMutable = 1 << 25;
842         final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0 /*requestCode*/,
843                 intent, PendingIntent.FLAG_CANCEL_CURRENT | pendingIntentFlagMutable);
844 
845         // We will register for a WIFI network being available or lost.
846         mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
847 
848         try {
849             mCtsNetUtils.ensureWifiConnected();
850 
851             // Now we expect to get the Intent delivered notifying of the availability of the wifi
852             // network even if it was already connected as a state-based action when the callback
853             // is registered.
854             assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI",
855                     receiver.waitForState());
856         } catch (InterruptedException e) {
857             fail("Broadcast receiver or NetworkCallback wait was interrupted.");
858         } finally {
859             mCm.unregisterNetworkCallback(pendingIntent);
860             pendingIntent.cancel();
861             mContext.unregisterReceiver(receiver);
862         }
863     }
864 
runIdenticalPendingIntentsRequestTest(boolean useListen)865     private void runIdenticalPendingIntentsRequestTest(boolean useListen) throws Exception {
866         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
867 
868         // Disconnect before registering callbacks, reconnect later to fire them
869         mCtsNetUtils.ensureWifiDisconnected(null);
870 
871         final NetworkRequest firstRequest = makeWifiNetworkRequest();
872         final NetworkRequest secondRequest = new NetworkRequest(firstRequest);
873         // Will match wifi or test, since transports are ORed; but there should only be wifi
874         secondRequest.networkCapabilities.addTransportType(TRANSPORT_TEST);
875 
876         PendingIntent firstIntent = null;
877         PendingIntent secondIntent = null;
878         BroadcastReceiver receiver = null;
879 
880         // Avoid receiving broadcasts from other runs by appending a timestamp
881         final String broadcastAction = NETWORK_CALLBACK_ACTION + System.currentTimeMillis();
882         try {
883             // TODO: replace with PendingIntent.FLAG_MUTABLE when this code compiles against S+
884             // Intent is mutable to receive EXTRA_NETWORK_REQUEST from ConnectivityService
885             final int pendingIntentFlagMutable = 1 << 25;
886             final String extraBoolKey = "extra_bool";
887             firstIntent = PendingIntent.getBroadcast(mContext,
888                     0 /* requestCode */,
889                     new Intent(broadcastAction).putExtra(extraBoolKey, false),
890                     PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable);
891 
892             if (useListen) {
893                 mCm.registerNetworkCallback(firstRequest, firstIntent);
894             } else {
895                 mCm.requestNetwork(firstRequest, firstIntent);
896             }
897 
898             // Second intent equals the first as per filterEquals (extras don't count), so first
899             // intent will be updated with the new extras
900             secondIntent = PendingIntent.getBroadcast(mContext,
901                     0 /* requestCode */,
902                     new Intent(broadcastAction).putExtra(extraBoolKey, true),
903                     PendingIntent.FLAG_UPDATE_CURRENT | pendingIntentFlagMutable);
904 
905             // Because secondIntent.intentFilterEquals the first, the request should be replaced
906             if (useListen) {
907                 mCm.registerNetworkCallback(secondRequest, secondIntent);
908             } else {
909                 mCm.requestNetwork(secondRequest, secondIntent);
910             }
911 
912             final IntentFilter filter = new IntentFilter();
913             filter.addAction(broadcastAction);
914 
915             final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
916             final AtomicInteger receivedCount = new AtomicInteger(0);
917             receiver = new BroadcastReceiver() {
918                 @Override
919                 public void onReceive(Context context, Intent intent) {
920                     final NetworkRequest request = intent.getParcelableExtra(EXTRA_NETWORK_REQUEST);
921                     assertPendingIntentRequestMatches(request, secondRequest, useListen);
922                     receivedCount.incrementAndGet();
923                     networkFuture.complete(intent.getParcelableExtra(EXTRA_NETWORK));
924                 }
925             };
926             mContext.registerReceiver(receiver, filter);
927 
928             final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
929             try {
930                 assertEquals(wifiNetwork, networkFuture.get(
931                         NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS));
932             } catch (TimeoutException e) {
933                 throw new AssertionError("PendingIntent not received for " + secondRequest, e);
934             }
935 
936             // Sleep for a small amount of time to try to check that only one callback is ever
937             // received (so the first callback was really unregistered). This does not guarantee
938             // that the test will fail if it runs very slowly, but it should at least be very
939             // noticeably flaky.
940             Thread.sleep(NO_CALLBACK_TIMEOUT_MS);
941 
942             // For R- frameworks, listens will receive duplicated callbacks. See b/189868426.
943             if (isAtLeastS() || !useListen) {
944                 assertEquals("PendingIntent should only be received once", 1, receivedCount.get());
945             }
946         } finally {
947             if (firstIntent != null) mCm.unregisterNetworkCallback(firstIntent);
948             if (secondIntent != null) mCm.unregisterNetworkCallback(secondIntent);
949             if (receiver != null) mContext.unregisterReceiver(receiver);
950             mCtsNetUtils.ensureWifiConnected();
951         }
952     }
953 
assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed, boolean useListen)954     private void assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed,
955             boolean useListen) {
956         assertArrayEquals(filed.networkCapabilities.getCapabilities(),
957                 broadcasted.networkCapabilities.getCapabilities());
958         // For R- frameworks, listens will receive duplicated callbacks. See b/189868426.
959         if (!isAtLeastS() && useListen) return;
960         assertArrayEquals(filed.networkCapabilities.getTransportTypes(),
961                 broadcasted.networkCapabilities.getTransportTypes());
962     }
963 
964     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
965     @Test
testRegisterNetworkRequest_identicalPendingIntents()966     public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception {
967         runIdenticalPendingIntentsRequestTest(false /* useListen */);
968     }
969 
970     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
971     @Test
testRegisterNetworkCallback_identicalPendingIntents()972     public void testRegisterNetworkCallback_identicalPendingIntents() throws Exception {
973         runIdenticalPendingIntentsRequestTest(true /* useListen */);
974     }
975 
976     /**
977      * Exercises the requestNetwork with NetworkCallback API. This checks to
978      * see if we get a callback for an INTERNET request.
979      */
980     @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
981     @Test
testRequestNetworkCallback()982     public void testRequestNetworkCallback() {
983         final TestNetworkCallback callback = new TestNetworkCallback();
984         mCm.requestNetwork(new NetworkRequest.Builder()
985                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
986                 .build(), callback);
987 
988         try {
989             // Wait to get callback for availability of internet
990             Network internetNetwork = callback.waitForAvailable();
991             assertNotNull("Did not receive NetworkCallback#onAvailable for INTERNET",
992                     internetNetwork);
993         } catch (InterruptedException e) {
994             fail("NetworkCallback wait was interrupted.");
995         } finally {
996             mCm.unregisterNetworkCallback(callback);
997         }
998     }
999 
1000     /**
1001      * Exercises the requestNetwork with NetworkCallback API with timeout - expected to
1002      * fail. Use WIFI and switch Wi-Fi off.
1003      */
1004     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1005     @Test
testRequestNetworkCallback_onUnavailable()1006     public void testRequestNetworkCallback_onUnavailable() {
1007         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
1008         if (previousWifiEnabledState) {
1009             mCtsNetUtils.ensureWifiDisconnected(null);
1010         }
1011 
1012         final TestNetworkCallback callback = new TestNetworkCallback();
1013         mCm.requestNetwork(new NetworkRequest.Builder()
1014                 .addTransportType(TRANSPORT_WIFI)
1015                 .build(), callback, 100);
1016 
1017         try {
1018             // Wait to get callback for unavailability of requested network
1019             assertTrue("Did not receive NetworkCallback#onUnavailable",
1020                     callback.waitForUnavailable());
1021         } catch (InterruptedException e) {
1022             fail("NetworkCallback wait was interrupted.");
1023         } finally {
1024             mCm.unregisterNetworkCallback(callback);
1025             if (previousWifiEnabledState) {
1026                 mCtsNetUtils.connectToWifi();
1027             }
1028         }
1029     }
1030 
getFirstV4Address(Network network)1031     private InetAddress getFirstV4Address(Network network) {
1032         LinkProperties linkProperties = mCm.getLinkProperties(network);
1033         for (InetAddress address : linkProperties.getAddresses()) {
1034             if (address instanceof Inet4Address) {
1035                 return address;
1036             }
1037         }
1038         return null;
1039     }
1040 
1041     /**
1042      * Checks that enabling/disabling wifi causes CONNECTIVITY_ACTION broadcasts.
1043      */
1044     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1045     @Test
testToggleWifiConnectivityAction()1046     public void testToggleWifiConnectivityAction() {
1047         // toggleWifi calls connectToWifi and disconnectFromWifi, which both wait for
1048         // CONNECTIVITY_ACTION broadcasts.
1049         mCtsNetUtils.toggleWifi();
1050     }
1051 
1052     /** Verify restricted networks cannot be requested. */
1053     @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
1054     @Test
testRestrictedNetworks()1055     public void testRestrictedNetworks() {
1056         // Verify we can request unrestricted networks:
1057         NetworkRequest request = new NetworkRequest.Builder()
1058                 .addCapability(NET_CAPABILITY_INTERNET).build();
1059         NetworkCallback callback = new NetworkCallback();
1060         mCm.requestNetwork(request, callback);
1061         mCm.unregisterNetworkCallback(callback);
1062         // Verify we cannot request restricted networks:
1063         request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build();
1064         callback = new NetworkCallback();
1065         try {
1066             mCm.requestNetwork(request, callback);
1067             fail("No exception thrown when restricted network requested.");
1068         } catch (SecurityException expected) {}
1069     }
1070 
1071     // Returns "true", "false" or "none"
getWifiMeteredStatus(String ssid)1072     private String getWifiMeteredStatus(String ssid) throws Exception {
1073         // Interestingly giving the SSID as an argument to list wifi-networks
1074         // only works iff the network in question has the "false" policy.
1075         // Also unfortunately runShellCommand does not pass the command to the interpreter
1076         // so it's not possible to | grep the ssid.
1077         final String command = "cmd netpolicy list wifi-networks";
1078         final String policyString = runShellCommand(mInstrumentation, command);
1079 
1080         final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
1081                 Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
1082         if (!m.find()) {
1083             fail("Unexpected format from cmd netpolicy, policyString = " + policyString);
1084         }
1085         return m.group(1);
1086     }
1087 
1088     // metered should be "true", "false" or "none"
setWifiMeteredStatus(String ssid, String metered)1089     private void setWifiMeteredStatus(String ssid, String metered) throws Exception {
1090         final String setCommand = "cmd netpolicy set metered-network " + ssid + " " + metered;
1091         runShellCommand(mInstrumentation, setCommand);
1092         assertEquals(getWifiMeteredStatus(ssid), metered);
1093     }
1094 
unquoteSSID(String ssid)1095     private String unquoteSSID(String ssid) {
1096         // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
1097         // Otherwise it's guaranteed not to start with a quote.
1098         if (ssid.charAt(0) == '"') {
1099             return ssid.substring(1, ssid.length() - 1);
1100         } else {
1101             return ssid;
1102         }
1103     }
1104 
waitForActiveNetworkMetered(final int targetTransportType, final boolean requestedMeteredness, final boolean useSystemDefault)1105     private void waitForActiveNetworkMetered(final int targetTransportType,
1106             final boolean requestedMeteredness, final boolean useSystemDefault)
1107             throws Exception {
1108         final CountDownLatch latch = new CountDownLatch(1);
1109         final NetworkCallback networkCallback = new NetworkCallback() {
1110             @Override
1111             public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
1112                 if (!nc.hasTransport(targetTransportType)) return;
1113 
1114                 final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
1115                 if (metered == requestedMeteredness) {
1116                     latch.countDown();
1117                 }
1118             }
1119         };
1120 
1121         try {
1122             // Registering a callback here guarantees onCapabilitiesChanged is called immediately
1123             // with the current setting. Therefore, if the setting has already been changed,
1124             // this method will return right away, and if not, it'll wait for the setting to change.
1125             if (useSystemDefault) {
1126                 runWithShellPermissionIdentity(() ->
1127                                 mCmShim.registerSystemDefaultNetworkCallback(networkCallback,
1128                                         new Handler(Looper.getMainLooper())),
1129                         NETWORK_SETTINGS);
1130             } else {
1131                 mCm.registerDefaultNetworkCallback(networkCallback);
1132             }
1133 
1134             // Changing meteredness on wifi involves reconnecting, which can take several seconds
1135             // (involves re-associating, DHCP...).
1136             if (!latch.await(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
1137                 fail("Timed out waiting for active network metered status to change to "
1138                         + requestedMeteredness + " ; network = " + mCm.getActiveNetwork());
1139             }
1140         } finally {
1141             mCm.unregisterNetworkCallback(networkCallback);
1142         }
1143     }
1144 
setWifiMeteredStatusAndWait(String ssid, boolean isMetered)1145     private void setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
1146         setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
1147         waitForActiveNetworkMetered(TRANSPORT_WIFI,
1148                 isMetered /* requestedMeteredness */,
1149                 true /* useSystemDefault */);
1150     }
1151 
assertMultipathPreferenceIsEventually(Network network, int oldValue, int expectedValue)1152     private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
1153             int expectedValue) {
1154         // Quick check : if oldValue == expectedValue, there is no way to guarantee the test
1155         // is not flaky.
1156         assertNotSame(oldValue, expectedValue);
1157 
1158         for (int i = 0; i < NUM_TRIES_MULTIPATH_PREF_CHECK; ++i) {
1159             final int actualValue = mCm.getMultipathPreference(network);
1160             if (actualValue == expectedValue) {
1161                 return;
1162             }
1163             if (actualValue != oldValue) {
1164                 fail("Multipath preference is neither previous (" + oldValue
1165                         + ") nor expected (" + expectedValue + ")");
1166             }
1167             SystemClock.sleep(INTERVAL_MULTIPATH_PREF_CHECK_MS);
1168         }
1169         fail("Timed out waiting for multipath preference to change. expected = "
1170                 + expectedValue + " ; actual = " + mCm.getMultipathPreference(network));
1171     }
1172 
getCurrentMeteredMultipathPreference(ContentResolver resolver)1173     private int getCurrentMeteredMultipathPreference(ContentResolver resolver) {
1174         final String rawMeteredPref = Settings.Global.getString(resolver,
1175                 NETWORK_METERED_MULTIPATH_PREFERENCE);
1176         return TextUtils.isEmpty(rawMeteredPref)
1177             ? getIntResourceForName(NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME)
1178             : Integer.parseInt(rawMeteredPref);
1179     }
1180 
findNextPrefValue(ContentResolver resolver)1181     private int findNextPrefValue(ContentResolver resolver) {
1182         // A bit of a nuclear hammer, but race conditions in CTS are bad. To be able to
1183         // detect a correct setting value without race conditions, the next pref must
1184         // be a valid value (range 0..3) that is different from the old setting of the
1185         // metered preference and from the unmetered preference.
1186         final int meteredPref = getCurrentMeteredMultipathPreference(resolver);
1187         final int unmeteredPref = ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
1188         if (0 != meteredPref && 0 != unmeteredPref) return 0;
1189         if (1 != meteredPref && 1 != unmeteredPref) return 1;
1190         return 2;
1191     }
1192 
1193     /**
1194      * Verify that getMultipathPreference does return appropriate values
1195      * for metered and unmetered networks.
1196      */
1197     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1198     @Test
testGetMultipathPreference()1199     public void testGetMultipathPreference() throws Exception {
1200         final ContentResolver resolver = mContext.getContentResolver();
1201         mCtsNetUtils.ensureWifiConnected();
1202         final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID());
1203         final String oldMeteredSetting = getWifiMeteredStatus(ssid);
1204         final String oldMeteredMultipathPreference = Settings.Global.getString(
1205                 resolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
1206         try {
1207             final int initialMeteredPreference = getCurrentMeteredMultipathPreference(resolver);
1208             int newMeteredPreference = findNextPrefValue(resolver);
1209             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
1210                     Integer.toString(newMeteredPreference));
1211             // Wifi meterness changes from unmetered to metered will disconnect and reconnect since
1212             // R.
1213             setWifiMeteredStatusAndWait(ssid, true);
1214             final Network network = mCtsNetUtils.ensureWifiConnected();
1215             assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
1216             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
1217                     NET_CAPABILITY_NOT_METERED), false);
1218             assertMultipathPreferenceIsEventually(network, initialMeteredPreference,
1219                     newMeteredPreference);
1220 
1221             final int oldMeteredPreference = newMeteredPreference;
1222             newMeteredPreference = findNextPrefValue(resolver);
1223             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
1224                     Integer.toString(newMeteredPreference));
1225             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
1226                     NET_CAPABILITY_NOT_METERED), false);
1227             assertMultipathPreferenceIsEventually(network,
1228                     oldMeteredPreference, newMeteredPreference);
1229 
1230             // No disconnect from unmetered to metered.
1231             setWifiMeteredStatusAndWait(ssid, false);
1232             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
1233                     NET_CAPABILITY_NOT_METERED), true);
1234             assertMultipathPreferenceIsEventually(network, newMeteredPreference,
1235                     ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED);
1236         } finally {
1237             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
1238                     oldMeteredMultipathPreference);
1239             setWifiMeteredStatus(ssid, oldMeteredSetting);
1240         }
1241     }
1242 
1243     // TODO: move the following socket keep alive test to dedicated test class.
1244     /**
1245      * Callback used in tcp keepalive offload that allows caller to wait callback fires.
1246      */
1247     private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
1248         public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
1249 
1250         public static class CallbackValue {
1251             public final CallbackType callbackType;
1252             public final int error;
1253 
CallbackValue(final CallbackType type, final int error)1254             private CallbackValue(final CallbackType type, final int error) {
1255                 this.callbackType = type;
1256                 this.error = error;
1257             }
1258 
1259             public static class OnStartedCallback extends CallbackValue {
OnStartedCallback()1260                 OnStartedCallback() { super(CallbackType.ON_STARTED, 0); }
1261             }
1262 
1263             public static class OnStoppedCallback extends CallbackValue {
OnStoppedCallback()1264                 OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); }
1265             }
1266 
1267             public static class OnErrorCallback extends CallbackValue {
OnErrorCallback(final int error)1268                 OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); }
1269             }
1270 
1271             @Override
equals(Object o)1272             public boolean equals(Object o) {
1273                 return o.getClass() == this.getClass()
1274                         && this.callbackType == ((CallbackValue) o).callbackType
1275                         && this.error == ((CallbackValue) o).error;
1276             }
1277 
1278             @Override
toString()1279             public String toString() {
1280                 return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
1281             }
1282         }
1283 
1284         private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
1285 
1286         @Override
onStarted()1287         public void onStarted() {
1288             mCallbacks.add(new CallbackValue.OnStartedCallback());
1289         }
1290 
1291         @Override
onStopped()1292         public void onStopped() {
1293             mCallbacks.add(new CallbackValue.OnStoppedCallback());
1294         }
1295 
1296         @Override
onError(final int error)1297         public void onError(final int error) {
1298             mCallbacks.add(new CallbackValue.OnErrorCallback(error));
1299         }
1300 
pollCallback()1301         public CallbackValue pollCallback() {
1302             try {
1303                 return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS,
1304                         TimeUnit.MILLISECONDS);
1305             } catch (InterruptedException e) {
1306                 fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms");
1307             }
1308             return null;
1309         }
expectCallback(CallbackValue expectedCallback)1310         private void expectCallback(CallbackValue expectedCallback) {
1311             final CallbackValue actualCallback = pollCallback();
1312             assertEquals(expectedCallback, actualCallback);
1313         }
1314 
expectStarted()1315         public void expectStarted() {
1316             expectCallback(new CallbackValue.OnStartedCallback());
1317         }
1318 
expectStopped()1319         public void expectStopped() {
1320             expectCallback(new CallbackValue.OnStoppedCallback());
1321         }
1322 
expectError(int error)1323         public void expectError(int error) {
1324             expectCallback(new CallbackValue.OnErrorCallback(error));
1325         }
1326     }
1327 
getAddrByName(final String hostname, final int family)1328     private InetAddress getAddrByName(final String hostname, final int family) throws Exception {
1329         final InetAddress[] allAddrs = InetAddress.getAllByName(hostname);
1330         for (InetAddress addr : allAddrs) {
1331             if (family == AF_INET && addr instanceof Inet4Address) return addr;
1332 
1333             if (family == AF_INET6 && addr instanceof Inet6Address) return addr;
1334 
1335             if (family == AF_UNSPEC) return addr;
1336         }
1337         return null;
1338     }
1339 
getConnectedSocket(final Network network, final String host, final int port, final int family)1340     private Socket getConnectedSocket(final Network network, final String host, final int port,
1341             final int family) throws Exception {
1342         final Socket s = network.getSocketFactory().createSocket();
1343         try {
1344             final InetAddress addr = getAddrByName(host, family);
1345             if (addr == null) fail("Fail to get destination address for " + family);
1346 
1347             final InetSocketAddress sockAddr = new InetSocketAddress(addr, port);
1348             s.connect(sockAddr);
1349         } catch (Exception e) {
1350             s.close();
1351             throw e;
1352         }
1353         return s;
1354     }
1355 
getSupportedKeepalivesForNet(@onNull Network network)1356     private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception {
1357         final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
1358 
1359         // Get number of supported concurrent keepalives for testing network.
1360         final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext);
1361         return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
1362                 keepalivesPerTransport, nc);
1363     }
1364 
isTcpKeepaliveSupportedByKernel()1365     private static boolean isTcpKeepaliveSupportedByKernel() {
1366         final String kVersionString = VintfRuntimeInfo.getKernelVersion();
1367         return compareMajorMinorVersion(kVersionString, "4.8") >= 0;
1368     }
1369 
getVersionFromString(String version)1370     private static Pair<Integer, Integer> getVersionFromString(String version) {
1371         // Only gets major and minor number of the version string.
1372         final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*");
1373         final Matcher m = versionPattern.matcher(version);
1374         if (m.matches()) {
1375             final int major = Integer.parseInt(m.group(1));
1376             final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3));
1377             return new Pair<>(major, minor);
1378         } else {
1379             return new Pair<>(0, 0);
1380         }
1381     }
1382 
1383     // TODO: Move to util class.
compareMajorMinorVersion(final String s1, final String s2)1384     private static int compareMajorMinorVersion(final String s1, final String s2) {
1385         final Pair<Integer, Integer> v1 = getVersionFromString(s1);
1386         final Pair<Integer, Integer> v2 = getVersionFromString(s2);
1387 
1388         if (v1.first == v2.first) {
1389             return Integer.compare(v1.second, v2.second);
1390         } else {
1391             return Integer.compare(v1.first, v2.first);
1392         }
1393     }
1394 
1395     /**
1396      * Verifies that version string compare logic returns expected result for various cases.
1397      * Note that only major and minor number are compared.
1398      */
1399     @Test
testMajorMinorVersionCompare()1400     public void testMajorMinorVersionCompare() {
1401         assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8"));
1402         assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1"));
1403         assertEquals(1, compareMajorMinorVersion("5.0", "4.8"));
1404         assertEquals(1, compareMajorMinorVersion("5", "4.8"));
1405         assertEquals(0, compareMajorMinorVersion("5", "5.0"));
1406         assertEquals(1, compareMajorMinorVersion("5-beta1", "4.8"));
1407         assertEquals(0, compareMajorMinorVersion("4.8.0.0", "4.8"));
1408         assertEquals(0, compareMajorMinorVersion("4.8-RC1", "4.8"));
1409         assertEquals(0, compareMajorMinorVersion("4.8", "4.8"));
1410         assertEquals(-1, compareMajorMinorVersion("3.10", "4.8.0"));
1411         assertEquals(-1, compareMajorMinorVersion("4.7.10.10", "4.8"));
1412     }
1413 
1414     /**
1415      * Verifies that the keepalive API cannot create any keepalive when the maximum number of
1416      * keepalives is set to 0.
1417      */
1418     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1419     @Test
testKeepaliveWifiUnsupported()1420     public void testKeepaliveWifiUnsupported() throws Exception {
1421         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1422 
1423         final Network network = mCtsNetUtils.ensureWifiConnected();
1424         if (getSupportedKeepalivesForNet(network) != 0) return;
1425         final InetAddress srcAddr = getFirstV4Address(network);
1426         assumeTrue("This test requires native IPv4", srcAddr != null);
1427 
1428         runWithShellPermissionIdentity(() -> {
1429             assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0));
1430             assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
1431         });
1432     }
1433 
1434     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1435     @Test
1436     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
testCreateTcpKeepalive()1437     public void testCreateTcpKeepalive() throws Exception {
1438         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1439 
1440         final Network network = mCtsNetUtils.ensureWifiConnected();
1441         if (getSupportedKeepalivesForNet(network) == 0) return;
1442         final InetAddress srcAddr = getFirstV4Address(network);
1443         assumeTrue("This test requires native IPv4", srcAddr != null);
1444 
1445         // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
1446         // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive
1447         // needs to be supported except if the kernel doesn't support it.
1448         if (!isTcpKeepaliveSupportedByKernel()) {
1449             // Verify that the callback result is expected.
1450             runWithShellPermissionIdentity(() -> {
1451                 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
1452             });
1453             Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel "
1454                     + VintfRuntimeInfo.getKernelVersion());
1455             return;
1456         }
1457 
1458         final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8");
1459         // So far only ipv4 tcp keepalive offload is supported.
1460         // TODO: add test case for ipv6 tcp keepalive offload when it is supported.
1461         try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, AF_INET)) {
1462 
1463             // Should able to start keep alive offload when socket is idle.
1464             final Executor executor = mContext.getMainExecutor();
1465             final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
1466 
1467             mUiAutomation.adoptShellPermissionIdentity();
1468             try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
1469                 sk.start(MIN_KEEPALIVE_INTERVAL);
1470                 callback.expectStarted();
1471 
1472                 // App should not able to write during keepalive offload.
1473                 final OutputStream out = s.getOutputStream();
1474                 try {
1475                     out.write(requestBytes);
1476                     fail("Should not able to write");
1477                 } catch (IOException e) { }
1478                 // App should not able to read during keepalive offload.
1479                 final InputStream in = s.getInputStream();
1480                 byte[] responseBytes = new byte[4096];
1481                 try {
1482                     in.read(responseBytes);
1483                     fail("Should not able to read");
1484                 } catch (IOException e) { }
1485 
1486                 // Stop.
1487                 sk.stop();
1488                 callback.expectStopped();
1489             } finally {
1490                 mUiAutomation.dropShellPermissionIdentity();
1491             }
1492 
1493             // Ensure socket is still connected.
1494             assertTrue(s.isConnected());
1495             assertFalse(s.isClosed());
1496 
1497             // Let socket be not idle.
1498             try {
1499                 final OutputStream out = s.getOutputStream();
1500                 out.write(requestBytes);
1501             } catch (IOException e) {
1502                 fail("Failed to write data " + e);
1503             }
1504             // Make sure response data arrives.
1505             final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue();
1506             final FileDescriptor fd = s.getFileDescriptor$();
1507             final CountDownLatch mOnReceiveLatch = new CountDownLatch(1);
1508             fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> {
1509                 mOnReceiveLatch.countDown();
1510                 return 0; // Unregister listener.
1511             });
1512             if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) {
1513                 fdHandlerQueue.removeOnFileDescriptorEventListener(fd);
1514                 fail("Timeout: no response data");
1515             }
1516 
1517             // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue
1518             // that has not been read.
1519             mUiAutomation.adoptShellPermissionIdentity();
1520             try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
1521                 sk.start(MIN_KEEPALIVE_INTERVAL);
1522                 callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE);
1523             } finally {
1524                 mUiAutomation.dropShellPermissionIdentity();
1525             }
1526         }
1527     }
1528 
createConcurrentKeepalivesOfType( int requestCount, @NonNull TestSocketKeepaliveCallback callback, Supplier<SocketKeepalive> kaFactory)1529     private ArrayList<SocketKeepalive> createConcurrentKeepalivesOfType(
1530             int requestCount, @NonNull TestSocketKeepaliveCallback callback,
1531             Supplier<SocketKeepalive> kaFactory) {
1532         final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
1533 
1534         int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT;
1535 
1536         // Test concurrent keepalives with the given supplier.
1537         while (kalist.size() < requestCount) {
1538             final SocketKeepalive ka = kaFactory.get();
1539             ka.start(MIN_KEEPALIVE_INTERVAL);
1540             TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback();
1541             assertNotNull(cv);
1542             if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) {
1543                 if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) {
1544                     // Unsupported.
1545                     break;
1546                 } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) {
1547                     // Limit reached or temporary unavailable due to stopped slot is not yet
1548                     // released.
1549                     if (remainingRetries > 0) {
1550                         SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS);
1551                         remainingRetries--;
1552                         continue;
1553                     }
1554                     break;
1555                 }
1556             }
1557             if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) {
1558                 kalist.add(ka);
1559             } else {
1560                 fail("Unexpected error when creating " + (kalist.size() + 1) + " "
1561                         + ka.getClass().getSimpleName() + ": " + cv);
1562             }
1563         }
1564 
1565         return kalist;
1566     }
1567 
createConcurrentNattSocketKeepalives( @onNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1568     private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives(
1569             @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount,
1570             @NonNull TestSocketKeepaliveCallback callback)  throws Exception {
1571 
1572         final Executor executor = mContext.getMainExecutor();
1573 
1574         // Initialize a real NaT-T socket.
1575         final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
1576         final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket();
1577         final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET);
1578         assertNotNull(srcAddr);
1579         assertNotNull(dstAddr);
1580 
1581         // Test concurrent Nat-T keepalives.
1582         final ArrayList<SocketKeepalive> result = createConcurrentKeepalivesOfType(requestCount,
1583                 callback, () -> mCm.createSocketKeepalive(network, nattSocket,
1584                         srcAddr, dstAddr, executor, callback));
1585 
1586         nattSocket.close();
1587         return result;
1588     }
1589 
createConcurrentTcpSocketKeepalives( @onNull Network network, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1590     private @NonNull ArrayList<SocketKeepalive> createConcurrentTcpSocketKeepalives(
1591             @NonNull Network network, int requestCount,
1592             @NonNull TestSocketKeepaliveCallback callback) {
1593         final Executor executor = mContext.getMainExecutor();
1594 
1595         // Create concurrent TCP keepalives.
1596         return createConcurrentKeepalivesOfType(requestCount, callback, () -> {
1597             // Assert that TCP connections can be established. The file descriptor of tcp
1598             // sockets will be duplicated and kept valid in service side if the keepalives are
1599             // successfully started.
1600             try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
1601                     AF_INET)) {
1602                 return mCm.createSocketKeepalive(network, tcpSocket, executor, callback);
1603             } catch (Exception e) {
1604                 fail("Unexpected error when creating TCP socket: " + e);
1605             }
1606             return null;
1607         });
1608     }
1609 
1610     /**
1611      * Creates concurrent keepalives until the specified counts of each type of keepalives are
1612      * reached or the expected error callbacks are received for each type of keepalives.
1613      *
1614      * @return the total number of keepalives created.
1615      */
1616     private int createConcurrentSocketKeepalives(
1617             @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount)
1618             throws Exception {
1619         final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
1620         final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
1621 
1622         kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback));
1623         kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback));
1624 
1625         final int ret = kalist.size();
1626 
1627         // Clean up.
1628         for (final SocketKeepalive ka : kalist) {
1629             ka.stop();
1630             callback.expectStopped();
1631         }
1632         kalist.clear();
1633 
1634         return ret;
1635     }
1636 
1637     /**
1638      * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't
1639      * get leaked after iterations.
1640      */
1641     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1642     @Test
1643     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
1644     public void testSocketKeepaliveLimitWifi() throws Exception {
1645         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1646 
1647         final Network network = mCtsNetUtils.ensureWifiConnected();
1648         final int supported = getSupportedKeepalivesForNet(network);
1649         if (supported == 0) {
1650             return;
1651         }
1652         final InetAddress srcAddr = getFirstV4Address(network);
1653         assumeTrue("This test requires native IPv4", srcAddr != null);
1654 
1655         runWithShellPermissionIdentity(() -> {
1656             // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT.
1657             assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT);
1658 
1659             // Verifies that Nat-T keepalives can be established.
1660             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1661                     supported + 1, 0));
1662             // Verifies that keepalives don't get leaked in second round.
1663             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported,
1664                     0));
1665         });
1666 
1667         // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
1668         // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel.
1669         if (!isTcpKeepaliveSupportedByKernel()) return;
1670 
1671         runWithShellPermissionIdentity(() -> {
1672             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
1673                     supported + 1));
1674 
1675             // Verifies that different types can be established at the same time.
1676             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1677                     supported / 2, supported - supported / 2));
1678 
1679             // Verifies that keepalives don't get leaked in second round.
1680             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
1681                     supported));
1682             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1683                     supported / 2, supported - supported / 2));
1684         });
1685     }
1686 
1687     /**
1688      * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and
1689      * don't get leaked after iterations.
1690      */
1691     @AppModeFull(reason = "Cannot request network in instant app mode")
1692     @Test
1693     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
1694     public void testSocketKeepaliveLimitTelephony() throws Exception {
1695         if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
1696             Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device"
1697                     + " supports telephony");
1698             return;
1699         }
1700 
1701         final int firstSdk = SdkLevel.isAtLeastS()
1702                 ? Build.VERSION.DEVICE_INITIAL_SDK_INT
1703                 // FIRST_SDK_INT was a @TestApi field renamed to DEVICE_INITIAL_SDK_INT in S
1704                 : Build.VERSION.class.getField("FIRST_SDK_INT").getInt(null);
1705         if (firstSdk < Build.VERSION_CODES.Q) {
1706             Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching"
1707                     + " before Q: " + firstSdk);
1708             return;
1709         }
1710 
1711         final Network network = mCtsNetUtils.connectToCell();
1712         final int supported = getSupportedKeepalivesForNet(network);
1713         final InetAddress srcAddr = getFirstV4Address(network);
1714         assumeTrue("This test requires native IPv4", srcAddr != null);
1715 
1716         runWithShellPermissionIdentity(() -> {
1717             // Verifies that the supported keepalive slots meet minimum requirement.
1718             assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT);
1719             // Verifies that Nat-T keepalives can be established.
1720             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1721                     supported + 1, 0));
1722             // Verifies that keepalives don't get leaked in second round.
1723             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported,
1724                     0));
1725         });
1726     }
1727 
1728     private int getIntResourceForName(@NonNull String resName) {
1729         final Resources r = mContext.getResources();
1730         final int resId = r.getIdentifier(resName, "integer", "android");
1731         return r.getInteger(resId);
1732     }
1733 
1734     /**
1735      * Verifies that the keepalive slots are limited as customized for unprivileged requests.
1736      */
1737     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1738     @Test
1739     @SkipPresubmit(reason = "Keepalive is not supported on virtual hardware")
1740     public void testSocketKeepaliveUnprivileged() throws Exception {
1741         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1742 
1743         final Network network = mCtsNetUtils.ensureWifiConnected();
1744         final int supported = getSupportedKeepalivesForNet(network);
1745         if (supported == 0) {
1746             return;
1747         }
1748         final InetAddress srcAddr = getFirstV4Address(network);
1749         assumeTrue("This test requires native IPv4", srcAddr != null);
1750 
1751         // Resource ID might be shifted on devices that compiled with different symbols.
1752         // Thus, resolve ID at runtime is needed.
1753         final int allowedUnprivilegedPerUid =
1754                 getIntResourceForName(KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME);
1755         final int reservedPrivilegedSlots =
1756                 getIntResourceForName(KEEPALIVE_RESERVED_PER_SLOT_RES_NAME);
1757         // Verifies that unprivileged request per uid cannot exceed the limit customized in the
1758         // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test
1759         // does not apply to TCP.
1760         assertGreaterOrEqual(supported, reservedPrivilegedSlots);
1761         assertGreaterOrEqual(supported, allowedUnprivilegedPerUid);
1762         final int expectedUnprivileged =
1763                 Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots);
1764         assertEquals(expectedUnprivileged,
1765                 createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0));
1766     }
1767 
1768     private static void assertGreaterOrEqual(long greater, long lesser) {
1769         assertTrue("" + greater + " expected to be greater than or equal to " + lesser,
1770                 greater >= lesser);
1771     }
1772 
1773     /**
1774      * Verifies that apps are not allowed to access restricted networks even if they declare the
1775      * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests.
1776      * See. b/144679405.
1777      */
1778     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1779     @Test
1780     public void testRestrictedNetworkPermission() throws Exception {
1781         // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package.
1782         final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(),
1783                 GET_PERMISSIONS);
1784         final int index = ArrayUtils.indexOf(
1785                 app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
1786         assertTrue(index >= 0);
1787         assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED);
1788 
1789         // Ensure that NetworkUtils.queryUserAccess always returns false since this package should
1790         // not have netd system permission to call this function.
1791         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
1792         assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId));
1793 
1794         // Ensure that this package cannot bind to any restricted network that's currently
1795         // connected.
1796         Network[] networks = mCm.getAllNetworks();
1797         for (Network network : networks) {
1798             NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
1799             if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
1800                 try {
1801                     network.bindSocket(new Socket());
1802                     fail("Bind to restricted network " + network + " unexpectedly succeeded");
1803                 } catch (IOException expected) {}
1804             }
1805         }
1806     }
1807 
1808     /**
1809      * Verifies that apps are allowed to call setAirplaneMode if they declare
1810      * NETWORK_AIRPLANE_MODE permission in their manifests.
1811      * See b/145164696.
1812      */
1813     @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps")
1814     @Test
1815     public void testSetAirplaneMode() throws Exception{
1816         final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI);
1817         final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
1818         // store the current state of airplane mode
1819         final boolean isAirplaneModeEnabled = isAirplaneModeEnabled();
1820         final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
1821         final TestableNetworkCallback telephonyCb = new TestableNetworkCallback();
1822         // disable airplane mode to reach a known state
1823         runShellCommand("cmd connectivity airplane-mode disable");
1824         // Verify that networks are available as expected if wifi or cell is supported. Continue the
1825         // test if none of them are supported since test should still able to verify the permission
1826         // mechanism.
1827         if (supportWifi) requestAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
1828         if (supportTelephony) requestAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb);
1829 
1830         try {
1831             // Verify we cannot set Airplane Mode without correct permission:
1832             try {
1833                 setAndVerifyAirplaneMode(true);
1834                 fail("SecurityException should have been thrown when setAirplaneMode was called"
1835                         + "without holding permission NETWORK_AIRPLANE_MODE.");
1836             } catch (SecurityException expected) {}
1837 
1838             // disable airplane mode again to reach a known state
1839             runShellCommand("cmd connectivity airplane-mode disable");
1840 
1841             // adopt shell permission which holds NETWORK_AIRPLANE_MODE
1842             mUiAutomation.adoptShellPermissionIdentity();
1843 
1844             // Verify we can enable Airplane Mode with correct permission:
1845             try {
1846                 setAndVerifyAirplaneMode(true);
1847             } catch (SecurityException e) {
1848                 fail("SecurityException should not have been thrown when setAirplaneMode(true) was"
1849                         + "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
1850             }
1851             // Verify that the enabling airplane mode takes effect as expected to prevent flakiness
1852             // caused by fast airplane mode switches. Ensure network lost before turning off
1853             // airplane mode.
1854             if (supportWifi) waitForLost(wifiCb);
1855             if (supportTelephony) waitForLost(telephonyCb);
1856 
1857             // Verify we can disable Airplane Mode with correct permission:
1858             try {
1859                 setAndVerifyAirplaneMode(false);
1860             } catch (SecurityException e) {
1861                 fail("SecurityException should not have been thrown when setAirplaneMode(false) was"
1862                         + "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
1863             }
1864             // Verify that turning airplane mode off takes effect as expected.
1865             if (supportWifi) waitForAvailable(wifiCb);
1866             if (supportTelephony) waitForAvailable(telephonyCb);
1867         } finally {
1868             if (supportWifi) mCm.unregisterNetworkCallback(wifiCb);
1869             if (supportTelephony) mCm.unregisterNetworkCallback(telephonyCb);
1870             // Restore the previous state of airplane mode and permissions:
1871             runShellCommand("cmd connectivity airplane-mode "
1872                     + (isAirplaneModeEnabled ? "enable" : "disable"));
1873             mUiAutomation.dropShellPermissionIdentity();
1874         }
1875     }
1876 
1877     private void requestAndWaitForAvailable(@NonNull final NetworkRequest request,
1878             @NonNull final TestableNetworkCallback cb) {
1879         mCm.registerNetworkCallback(request, cb);
1880         waitForAvailable(cb);
1881     }
1882 
1883     private void waitForAvailable(@NonNull final TestableNetworkCallback cb) {
1884         cb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
1885                 c -> c instanceof CallbackEntry.Available);
1886     }
1887 
1888     private void waitForAvailable(
1889             @NonNull final TestableNetworkCallback cb, final int expectedTransport) {
1890         cb.eventuallyExpect(
1891                 CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
1892                 entry -> {
1893                     final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork());
1894                     return nc.hasTransport(expectedTransport);
1895                 }
1896         );
1897     }
1898 
1899     private void waitForAvailable(
1900             @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) {
1901         cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */,
1902                 true /* validated */,
1903                 false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS);
1904     }
1905 
1906     private void waitForLost(@NonNull final TestableNetworkCallback cb) {
1907         cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
1908                 c -> c instanceof CallbackEntry.Lost);
1909     }
1910 
1911     private void setAndVerifyAirplaneMode(Boolean expectedResult)
1912             throws Exception {
1913         final CompletableFuture<Boolean> actualResult = new CompletableFuture();
1914         BroadcastReceiver receiver = new BroadcastReceiver() {
1915             @Override
1916             public void onReceive(Context context, Intent intent) {
1917                 // The defaultValue of getExtraBoolean should be the opposite of what is
1918                 // expected, thus ensuring a test failure if the extra is absent.
1919                 actualResult.complete(intent.getBooleanExtra("state", !expectedResult));
1920             }
1921         };
1922         try {
1923             mContext.registerReceiver(receiver,
1924                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
1925             mCm.setAirplaneMode(expectedResult);
1926             final String msg = "Setting Airplane Mode failed,";
1927             assertEquals(msg, expectedResult, actualResult.get(AIRPLANE_MODE_CHANGE_TIMEOUT_MS,
1928                     TimeUnit.MILLISECONDS));
1929         } finally {
1930             mContext.unregisterReceiver(receiver);
1931         }
1932     }
1933 
1934     private static boolean isAirplaneModeEnabled() {
1935         return runShellCommand("cmd connectivity airplane-mode")
1936                 .trim().equals("enabled");
1937     }
1938 
1939     @Test
1940     public void testGetCaptivePortalServerUrl() {
1941         final String permission = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q
1942                 ? CONNECTIVITY_INTERNAL
1943                 : NETWORK_SETTINGS;
1944         final String url = runAsShell(permission, mCm::getCaptivePortalServerUrl);
1945         assertNotNull("getCaptivePortalServerUrl must not be null", url);
1946         try {
1947             final URL parsedUrl = new URL(url);
1948             // As per the javadoc, the URL must be HTTP
1949             assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol());
1950         } catch (MalformedURLException e) {
1951             throw new AssertionFailedError("Captive portal server URL is invalid: " + e);
1952         }
1953     }
1954 
1955     /**
1956      * Verifies that apps are forbidden from getting ssid information from
1957      * {@Code NetworkCapabilities} if they do not hold NETWORK_SETTINGS permission.
1958      * See b/161370134.
1959      */
1960     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1961     @Test
1962     public void testSsidInNetworkCapabilities() throws Exception {
1963         assumeTrue("testSsidInNetworkCapabilities cannot execute unless device supports WiFi",
1964                 mPackageManager.hasSystemFeature(FEATURE_WIFI));
1965 
1966         final Network network = mCtsNetUtils.ensureWifiConnected();
1967         final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID());
1968         assertNotNull("Ssid getting from WifiManager is null", ssid);
1969         // This package should have no NETWORK_SETTINGS permission. Verify that no ssid is contained
1970         // in the NetworkCapabilities.
1971         verifySsidFromQueriedNetworkCapabilities(network, ssid, false /* hasSsid */);
1972         verifySsidFromCallbackNetworkCapabilities(ssid, false /* hasSsid */);
1973         // Adopt shell permission to allow to get ssid information.
1974         runWithShellPermissionIdentity(() -> {
1975             verifySsidFromQueriedNetworkCapabilities(network, ssid, true /* hasSsid */);
1976             verifySsidFromCallbackNetworkCapabilities(ssid, true /* hasSsid */);
1977         });
1978     }
1979 
1980     private void verifySsidFromQueriedNetworkCapabilities(@NonNull Network network,
1981             @NonNull String ssid, boolean hasSsid) throws Exception {
1982         // Verify if ssid is contained in NetworkCapabilities queried from ConnectivityManager.
1983         final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
1984         assertNotNull("NetworkCapabilities of the network is null", nc);
1985         assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find());
1986     }
1987 
1988     private void verifySsidFromCallbackNetworkCapabilities(@NonNull String ssid, boolean hasSsid)
1989             throws Exception {
1990         final CompletableFuture<NetworkCapabilities> foundNc = new CompletableFuture();
1991         final NetworkCallback callback = new NetworkCallback() {
1992             @Override
1993             public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
1994                 foundNc.complete(nc);
1995             }
1996         };
1997         try {
1998             mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
1999             // Registering a callback here guarantees onCapabilitiesChanged is called immediately
2000             // because WiFi network should be connected.
2001             final NetworkCapabilities nc =
2002                     foundNc.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2003             // Verify if ssid is contained in the NetworkCapabilities received from callback.
2004             assertNotNull("NetworkCapabilities of the network is null", nc);
2005             assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find());
2006         } finally {
2007             mCm.unregisterNetworkCallback(callback);
2008         }
2009     }
2010 
2011     /**
2012      * Verify background request can only be requested when acquiring
2013      * {@link android.Manifest.permission.NETWORK_SETTINGS}.
2014      */
2015     @AppModeFull(reason = "Instant apps cannot create test networks")
2016     @Test
2017     public void testRequestBackgroundNetwork() {
2018         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2019         // shims, and @IgnoreUpTo does not check that.
2020         assumeTrue(TestUtils.shouldTestSApis());
2021 
2022         // Create a tun interface. Use the returned interface name as the specifier to create
2023         // a test network request.
2024         final TestNetworkManager tnm = runWithShellPermissionIdentity(() ->
2025                 mContext.getSystemService(TestNetworkManager.class),
2026                 android.Manifest.permission.MANAGE_TEST_NETWORKS);
2027         final TestNetworkInterface testNetworkInterface = runWithShellPermissionIdentity(() ->
2028                     tnm.createTunInterface(new LinkAddress[]{TEST_LINKADDR}),
2029                 android.Manifest.permission.MANAGE_TEST_NETWORKS,
2030                 android.Manifest.permission.NETWORK_SETTINGS);
2031         assertNotNull(testNetworkInterface);
2032 
2033         final NetworkRequest testRequest = new NetworkRequest.Builder()
2034                 .addTransportType(TRANSPORT_TEST)
2035                 // Test networks do not have NOT_VPN or TRUSTED capabilities by default
2036                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
2037                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
2038                 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
2039                         testNetworkInterface.getInterfaceName()))
2040                 .build();
2041 
2042         // Verify background network cannot be requested without NETWORK_SETTINGS permission.
2043         final TestableNetworkCallback callback = new TestableNetworkCallback();
2044         final Handler handler = new Handler(Looper.getMainLooper());
2045         assertThrows(SecurityException.class,
2046                 () -> mCmShim.requestBackgroundNetwork(testRequest, callback, handler));
2047 
2048         Network testNetwork = null;
2049         try {
2050             // Request background test network via Shell identity which has NETWORK_SETTINGS
2051             // permission granted.
2052             runWithShellPermissionIdentity(
2053                     () -> mCmShim.requestBackgroundNetwork(testRequest, callback, handler),
2054                     new String[] { android.Manifest.permission.NETWORK_SETTINGS });
2055 
2056             // Register the test network agent which has no foreground request associated to it.
2057             // And verify it can satisfy the background network request just fired.
2058             final Binder binder = new Binder();
2059             runWithShellPermissionIdentity(() ->
2060                     tnm.setupTestNetwork(testNetworkInterface.getInterfaceName(), binder),
2061                     new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS,
2062                             android.Manifest.permission.NETWORK_SETTINGS });
2063             waitForAvailable(callback);
2064             testNetwork = callback.getLastAvailableNetwork();
2065             assertNotNull(testNetwork);
2066 
2067             // The test network that has just connected is a foreground network,
2068             // non-listen requests will get available callback before it can be put into
2069             // background if no foreground request can be satisfied. Thus, wait for a short
2070             // period is needed to let foreground capability go away.
2071             callback.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2072                     NETWORK_CALLBACK_TIMEOUT_MS,
2073                     c -> c instanceof CallbackEntry.CapabilitiesChanged
2074                             && !((CallbackEntry.CapabilitiesChanged) c).getCaps()
2075                             .hasCapability(NET_CAPABILITY_FOREGROUND));
2076             final NetworkCapabilities nc = mCm.getNetworkCapabilities(testNetwork);
2077             assertFalse("expected background network, but got " + nc,
2078                     nc.hasCapability(NET_CAPABILITY_FOREGROUND));
2079         } finally {
2080             final Network n = testNetwork;
2081             runWithShellPermissionIdentity(() -> {
2082                 if (null != n) {
2083                     tnm.teardownTestNetwork(n);
2084                     callback.eventuallyExpect(CallbackEntry.LOST,
2085                             NETWORK_CALLBACK_TIMEOUT_MS,
2086                             lost -> n.equals(lost.getNetwork()));
2087                 }
2088                 testNetworkInterface.getFileDescriptor().close();
2089             }, new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS });
2090             mCm.unregisterNetworkCallback(callback);
2091         }
2092     }
2093 
2094     private class DetailedBlockedStatusCallback extends TestableNetworkCallback {
2095         public void expectAvailableCallbacks(Network network) {
2096             super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */,
2097                     BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS);
2098         }
2099         public void expectBlockedStatusCallback(Network network, int blockedStatus) {
2100             super.expectBlockedStatusCallback(blockedStatus, network, NETWORK_CALLBACK_TIMEOUT_MS);
2101         }
2102         public void onBlockedStatusChanged(Network network, int blockedReasons) {
2103             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
2104         }
2105     }
2106 
2107     private void setRequireVpnForUids(boolean requireVpn, Collection<Range<Integer>> ranges)
2108             throws Exception {
2109         mCmShim.setRequireVpnForUids(requireVpn, ranges);
2110         for (Range<Integer> range : ranges) {
2111             if (requireVpn) {
2112                 mVpnRequiredUidRanges.add(range);
2113             } else {
2114                 assertTrue(mVpnRequiredUidRanges.remove(range));
2115             }
2116         }
2117     }
2118 
2119     private void doTestBlockedStatusCallback() throws Exception {
2120         final DetailedBlockedStatusCallback myUidCallback = new DetailedBlockedStatusCallback();
2121         final DetailedBlockedStatusCallback otherUidCallback = new DetailedBlockedStatusCallback();
2122 
2123         final int myUid = Process.myUid();
2124         final int otherUid = UserHandle.getUid(5, Process.FIRST_APPLICATION_UID);
2125         final Handler handler = new Handler(Looper.getMainLooper());
2126         mCm.registerDefaultNetworkCallback(myUidCallback, handler);
2127         mCmShim.registerDefaultNetworkCallbackForUid(otherUid, otherUidCallback, handler);
2128 
2129         final Network defaultNetwork = mCm.getActiveNetwork();
2130         final List<DetailedBlockedStatusCallback> allCallbacks =
2131                 List.of(myUidCallback, otherUidCallback);
2132         for (DetailedBlockedStatusCallback callback : allCallbacks) {
2133             callback.expectAvailableCallbacks(defaultNetwork);
2134         }
2135 
2136         final Range<Integer> myUidRange = new Range<>(myUid, myUid);
2137         final Range<Integer> otherUidRange = new Range<>(otherUid, otherUid);
2138 
2139         setRequireVpnForUids(true, List.of(myUidRange));
2140         myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN);
2141         otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
2142 
2143         setRequireVpnForUids(true, List.of(myUidRange, otherUidRange));
2144         myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
2145         otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN);
2146 
2147         // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not
2148         // unblock myUid because it was added to the blocked ranges twice.
2149         setRequireVpnForUids(false, List.of(myUidRange));
2150         myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
2151         otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
2152 
2153         setRequireVpnForUids(false, List.of(myUidRange, otherUidRange));
2154         myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
2155         otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
2156 
2157         myUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
2158         otherUidCallback.assertNoCallback(NO_CALLBACK_TIMEOUT_MS);
2159     }
2160 
2161     @Test
2162     public void testBlockedStatusCallback() {
2163         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2164         // shims, and @IgnoreUpTo does not check that.
2165         assumeTrue(TestUtils.shouldTestSApis());
2166         runWithShellPermissionIdentity(() -> doTestBlockedStatusCallback(), NETWORK_SETTINGS);
2167     }
2168 
2169     private void doTestLegacyLockdownEnabled() throws Exception {
2170         NetworkInfo info = mCm.getActiveNetworkInfo();
2171         assertNotNull(info);
2172         assertEquals(DetailedState.CONNECTED, info.getDetailedState());
2173 
2174         try {
2175             mCmShim.setLegacyLockdownVpnEnabled(true);
2176 
2177             // setLegacyLockdownVpnEnabled is asynchronous and only takes effect when the
2178             // ConnectivityService handler thread processes it. Ensure it has taken effect by doing
2179             // something that blocks until the handler thread is idle.
2180             final TestableNetworkCallback callback = new TestableNetworkCallback();
2181             mCm.registerDefaultNetworkCallback(callback);
2182             waitForAvailable(callback);
2183             mCm.unregisterNetworkCallback(callback);
2184 
2185             // Test one of the effects of setLegacyLockdownVpnEnabled: the fact that any NetworkInfo
2186             // in state CONNECTED is degraded to CONNECTING if the legacy VPN is not connected.
2187             info = mCm.getActiveNetworkInfo();
2188             assertNotNull(info);
2189             assertEquals(DetailedState.CONNECTING, info.getDetailedState());
2190         } finally {
2191             mCmShim.setLegacyLockdownVpnEnabled(false);
2192         }
2193     }
2194 
2195     @Test
2196     public void testLegacyLockdownEnabled() {
2197         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2198         // shims, and @IgnoreUpTo does not check that.
2199         assumeTrue(TestUtils.shouldTestSApis());
2200         runWithShellPermissionIdentity(() -> doTestLegacyLockdownEnabled(), NETWORK_SETTINGS);
2201     }
2202 
2203     @Test
2204     public void testGetCapabilityCarrierName() {
2205         assumeTrue(TestUtils.shouldTestSApis());
2206         assertEquals("ENTERPRISE", NetworkInformationShimImpl.newInstance()
2207                 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_ENTERPRISE));
2208         assertNull(NetworkInformationShimImpl.newInstance()
2209                 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_NOT_VCN_MANAGED));
2210     }
2211 
2212     @Test
2213     public void testSetGlobalProxy() {
2214         assumeTrue(TestUtils.shouldTestSApis());
2215         // Behavior is verified in gts. Verify exception thrown w/o permission.
2216         assertThrows(SecurityException.class, () -> mCm.setGlobalProxy(
2217                 ProxyInfo.buildDirectProxy("example.com" /* host */, 8080 /* port */)));
2218     }
2219 
2220     @Test
2221     public void testFactoryResetWithoutPermission() {
2222         assumeTrue(TestUtils.shouldTestSApis());
2223         assertThrows(SecurityException.class, () -> mCm.factoryReset());
2224     }
2225 
2226     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2227     @Test
2228     public void testFactoryReset() throws Exception {
2229         assumeTrue(TestUtils.shouldTestSApis());
2230 
2231         // Store current settings.
2232         final int curAvoidBadWifi =
2233                 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext);
2234         final int curPrivateDnsMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext);
2235 
2236         TestTetheringEventCallback tetherEventCallback = null;
2237         final CtsTetheringUtils tetherUtils = new CtsTetheringUtils(mContext);
2238         try {
2239             tetherEventCallback = tetherUtils.registerTetheringEventCallback();
2240             // Adopt for NETWORK_SETTINGS permission.
2241             mUiAutomation.adoptShellPermissionIdentity();
2242             // start tethering
2243             tetherEventCallback.assumeWifiTetheringSupported(mContext);
2244             tetherUtils.startWifiTethering(tetherEventCallback);
2245             // Update setting to verify the behavior.
2246             mCm.setAirplaneMode(true);
2247             ConnectivitySettingsManager.setPrivateDnsMode(mContext,
2248                     ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF);
2249             ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext,
2250                     ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE);
2251             assertEquals(AIRPLANE_MODE_ON, Settings.Global.getInt(
2252                     mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
2253             // Verify factoryReset
2254             mCm.factoryReset();
2255             verifySettings(AIRPLANE_MODE_OFF,
2256                     ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC,
2257                     ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT);
2258 
2259             tetherEventCallback.expectNoTetheringActive();
2260         } finally {
2261             // Restore settings.
2262             mCm.setAirplaneMode(false);
2263             ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, curAvoidBadWifi);
2264             ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode);
2265             if (tetherEventCallback != null) {
2266                 tetherUtils.unregisterTetheringEventCallback(tetherEventCallback);
2267             }
2268             tetherUtils.stopAllTethering();
2269             mUiAutomation.dropShellPermissionIdentity();
2270         }
2271     }
2272 
2273     /**
2274      * Verify that {@link ConnectivityManager#setProfileNetworkPreference} cannot be called
2275      * without required NETWORK_STACK permissions.
2276      */
2277     @Test
2278     public void testSetProfileNetworkPreference_NoPermission() {
2279         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2280         // shims, and @IgnoreUpTo does not check that.
2281         assumeTrue(TestUtils.shouldTestSApis());
2282         assertThrows(SecurityException.class, () -> mCm.setProfileNetworkPreference(
2283                 UserHandle.of(0), PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null /* executor */,
2284                 null /* listener */));
2285     }
2286 
2287     @Test
2288     public void testSystemReady() {
2289         assumeTrue(TestUtils.shouldTestSApis());
2290         assertThrows(SecurityException.class, () -> mCm.systemReady());
2291     }
2292 
2293     @Test
2294     public void testGetIpSecNetIdRange() {
2295         assumeTrue(TestUtils.shouldTestSApis());
2296         // The lower refers to ConnectivityManager.TUN_INTF_NETID_START.
2297         final long lower = 64512;
2298         // The upper refers to ConnectivityManager.TUN_INTF_NETID_START
2299         // + ConnectivityManager.TUN_INTF_NETID_RANGE - 1
2300         final long upper = 65535;
2301         assertEquals(lower, (long) ConnectivityManager.getIpSecNetIdRange().getLower());
2302         assertEquals(upper, (long) ConnectivityManager.getIpSecNetIdRange().getUpper());
2303     }
2304 
2305     private void verifySettings(int expectedAirplaneMode, int expectedPrivateDnsMode,
2306             int expectedAvoidBadWifi) throws Exception {
2307         assertEquals(expectedAirplaneMode, Settings.Global.getInt(
2308                 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
2309         assertEquals(expectedPrivateDnsMode,
2310                 ConnectivitySettingsManager.getPrivateDnsMode(mContext));
2311         assertEquals(expectedAvoidBadWifi,
2312                 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext));
2313     }
2314 
2315     /**
2316      * Verify that per-app OEM network preference functions as expected for network preference TEST.
2317      * For specified apps, validate networks are prioritized in order: unmetered, TEST transport,
2318      * default network.
2319      */
2320     @AppModeFull(reason = "Instant apps cannot create test networks")
2321     @Test
2322     public void testSetOemNetworkPreferenceForTestPref() throws Exception {
2323         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2324         // shims, and @IgnoreUpTo does not check that.
2325         assumeTrue(TestUtils.shouldTestSApis());
2326         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
2327 
2328         final TestNetworkTracker tnt = callWithShellPermissionIdentity(
2329                 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
2330         final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
2331         final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
2332 
2333         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2334         final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity(
2335                 () -> mCm.getNetworkCapabilities(wifiNetwork));
2336         final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid());
2337         final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
2338 
2339         try {
2340             // This network will be used for unmetered.
2341             setWifiMeteredStatusAndWait(ssid, false /* isMetered */);
2342 
2343             setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
2344             registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
2345 
2346             // Validate that an unmetered network is used over other networks.
2347             waitForAvailable(defaultCallback, wifiNetwork);
2348             waitForAvailable(systemDefaultCallback, wifiNetwork);
2349 
2350             // Validate when setting unmetered to metered, unmetered is lost and replaced by the
2351             // network with the TEST transport.
2352             setWifiMeteredStatusAndWait(ssid, true /* isMetered */);
2353             defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork,
2354                     NETWORK_CALLBACK_TIMEOUT_MS);
2355             waitForAvailable(defaultCallback, tnt.getNetwork());
2356             // Depending on if this device has cellular connectivity or not, multiple available
2357             // callbacks may be received. Eventually, metered Wi-Fi should be the final available
2358             // callback in any case therefore confirm its receipt before continuing to assure the
2359             // system is in the expected state.
2360             waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI);
2361         } finally {
2362             // Validate that removing the test network will fallback to the default network.
2363             runWithShellPermissionIdentity(tnt::teardown);
2364             defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork(),
2365                     NETWORK_CALLBACK_TIMEOUT_MS);
2366             waitForAvailable(defaultCallback);
2367 
2368             setWifiMeteredStatusAndWait(ssid, oldMeteredValue);
2369 
2370             // Cleanup any prior test state from setOemNetworkPreference
2371             clearOemNetworkPreference();
2372             unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
2373         }
2374     }
2375 
2376     /**
2377      * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY.
2378      * For specified apps, validate that only TEST transport type networks are used.
2379      */
2380     @AppModeFull(reason = "Instant apps cannot create test networks")
2381     @Test
2382     public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
2383         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2384         // shims, and @IgnoreUpTo does not check that.
2385         assumeTrue(TestUtils.shouldTestSApis());
2386 
2387         final TestNetworkTracker tnt = callWithShellPermissionIdentity(
2388                 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
2389         final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
2390         final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
2391 
2392         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2393 
2394         try {
2395             setOemNetworkPreferenceForMyPackage(
2396                     OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY);
2397             registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
2398             waitForAvailable(defaultCallback, tnt.getNetwork());
2399             waitForAvailable(systemDefaultCallback, wifiNetwork);
2400         } finally {
2401             runWithShellPermissionIdentity(tnt::teardown);
2402             defaultCallback.expectCallback(CallbackEntry.LOST, tnt.getNetwork(),
2403                     NETWORK_CALLBACK_TIMEOUT_MS);
2404 
2405             // This network preference should only ever use the test network therefore available
2406             // should not trigger when the test network goes down (e.g. switch to cellular).
2407             defaultCallback.assertNoCallback();
2408             // The system default should still be connected to Wi-fi
2409             assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork());
2410 
2411             // Cleanup any prior test state from setOemNetworkPreference
2412             clearOemNetworkPreference();
2413 
2414             // The default (non-test) network should be available as the network pref was cleared.
2415             waitForAvailable(defaultCallback);
2416             unregisterTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
2417         }
2418     }
2419 
2420     private void unregisterTestOemNetworkPreferenceCallbacks(
2421             @NonNull final TestableNetworkCallback defaultCallback,
2422             @NonNull final TestableNetworkCallback systemDefaultCallback) {
2423         mCm.unregisterNetworkCallback(defaultCallback);
2424         mCm.unregisterNetworkCallback(systemDefaultCallback);
2425     }
2426 
2427     private void registerTestOemNetworkPreferenceCallbacks(
2428             @NonNull final TestableNetworkCallback defaultCallback,
2429             @NonNull final TestableNetworkCallback systemDefaultCallback) {
2430         mCm.registerDefaultNetworkCallback(defaultCallback);
2431         runWithShellPermissionIdentity(() ->
2432                 mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback,
2433                         new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
2434     }
2435 
2436     private static final class OnCompleteListenerCallback {
2437         final CompletableFuture<Object> mDone = new CompletableFuture<>();
2438 
2439         public void onComplete() {
2440             mDone.complete(new Object());
2441         }
2442 
2443         void expectOnComplete() throws Exception {
2444             try {
2445                 mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2446             } catch (TimeoutException e) {
2447                 fail("Expected onComplete() not received after "
2448                         + NETWORK_CALLBACK_TIMEOUT_MS + " ms");
2449             }
2450         }
2451     }
2452 
2453     private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception {
2454         final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
2455                 .addNetworkPreference(mContext.getPackageName(), networkPref)
2456                 .build();
2457         final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
2458         mUiAutomation.adoptShellPermissionIdentity();
2459         try {
2460             mCm.setOemNetworkPreference(
2461                     pref, mContext.getMainExecutor(), oemPrefListener::onComplete);
2462         } finally {
2463             mUiAutomation.dropShellPermissionIdentity();
2464         }
2465         oemPrefListener.expectOnComplete();
2466     }
2467 
2468     /**
2469      * This will clear the OEM network preference on the device. As there is currently no way of
2470      * getting the existing preference, if this is executed while an existing preference is in
2471      * place, that preference will need to be reapplied after executing this test.
2472      * @throws Exception
2473      */
2474     private void clearOemNetworkPreference() throws Exception {
2475         final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build();
2476         final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
2477         mUiAutomation.adoptShellPermissionIdentity();
2478         try {
2479             mCm.setOemNetworkPreference(
2480                     clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete);
2481         } finally {
2482             mUiAutomation.dropShellPermissionIdentity();
2483         }
2484         oemPrefListener.expectOnComplete();
2485     }
2486 
2487     @Test
2488     public void testSetAcceptPartialConnectivity_NoPermission_GetException() {
2489         assumeTrue(TestUtils.shouldTestSApis());
2490         assertThrows(SecurityException.class, () -> mCm.setAcceptPartialConnectivity(
2491                 mCm.getActiveNetwork(), false /* accept */ , false /* always */));
2492     }
2493 
2494     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2495     @Test
2496     public void testAcceptPartialConnectivity_validatedNetwork() throws Exception {
2497         assumeTrue(TestUtils.shouldTestSApis());
2498         assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
2499                         + " unless device supports WiFi",
2500                 mPackageManager.hasSystemFeature(FEATURE_WIFI));
2501 
2502         try {
2503             // Wait for partial connectivity to be detected on the network
2504             final Network network = preparePartialConnectivity();
2505 
2506             runAsShell(NETWORK_SETTINGS, () -> {
2507                 // The always bit is verified in NetworkAgentTest
2508                 mCm.setAcceptPartialConnectivity(network, true /* accept */, false /* always */);
2509             });
2510 
2511             // Accept partial connectivity network should result in a validated network
2512             expectNetworkHasCapability(network, NET_CAPABILITY_VALIDATED, WIFI_CONNECT_TIMEOUT_MS);
2513         } finally {
2514             resetValidationConfig();
2515             // Reconnect wifi to reset the wifi status
2516             reconnectWifi();
2517         }
2518     }
2519 
2520     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2521     @Test
2522     public void testRejectPartialConnectivity_TearDownNetwork() throws Exception {
2523         assumeTrue(TestUtils.shouldTestSApis());
2524         assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
2525                         + " unless device supports WiFi",
2526                 mPackageManager.hasSystemFeature(FEATURE_WIFI));
2527 
2528         final TestNetworkCallback cb = new TestNetworkCallback();
2529         try {
2530             // Wait for partial connectivity to be detected on the network
2531             final Network network = preparePartialConnectivity();
2532 
2533             mCm.requestNetwork(makeWifiNetworkRequest(), cb);
2534             runAsShell(NETWORK_SETTINGS, () -> {
2535                 // The always bit is verified in NetworkAgentTest
2536                 mCm.setAcceptPartialConnectivity(network, false /* accept */, false /* always */);
2537             });
2538             // Reject partial connectivity network should cause the network being torn down
2539             assertEquals(network, cb.waitForLost());
2540         } finally {
2541             mCm.unregisterNetworkCallback(cb);
2542             resetValidationConfig();
2543             // Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot
2544             // apply here. Thus, turn off wifi first and restart to restore.
2545             runShellCommand("svc wifi disable");
2546             mCtsNetUtils.ensureWifiConnected();
2547         }
2548     }
2549 
2550     @Test
2551     public void testSetAcceptUnvalidated_NoPermission_GetException() {
2552         assumeTrue(TestUtils.shouldTestSApis());
2553         assertThrows(SecurityException.class, () -> mCm.setAcceptUnvalidated(
2554                 mCm.getActiveNetwork(), false /* accept */ , false /* always */));
2555     }
2556 
2557     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2558     @Test
2559     public void testRejectUnvalidated_TearDownNetwork() throws Exception {
2560         assumeTrue(TestUtils.shouldTestSApis());
2561         final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
2562                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
2563         assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
2564                         + " unless device supports WiFi and telephony", canRunTest);
2565 
2566         final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
2567         try {
2568             // Ensure at least one default network candidate connected.
2569             mCtsNetUtils.connectToCell();
2570 
2571             final Network wifiNetwork = prepareUnvalidatedNetwork();
2572             // Default network should not be wifi ,but checking that wifi is not the default doesn't
2573             // guarantee that it won't become the default in the future.
2574             assertNotEquals(wifiNetwork, mCm.getActiveNetwork());
2575 
2576             mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb);
2577             runAsShell(NETWORK_SETTINGS, () -> {
2578                 mCm.setAcceptUnvalidated(wifiNetwork, false /* accept */, false /* always */);
2579             });
2580             waitForLost(wifiCb);
2581         } finally {
2582             mCm.unregisterNetworkCallback(wifiCb);
2583             resetValidationConfig();
2584             /// Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot
2585             // apply here. Thus, turn off wifi first and restart to restore.
2586             runShellCommand("svc wifi disable");
2587             mCtsNetUtils.ensureWifiConnected();
2588         }
2589     }
2590 
2591     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2592     @Test
2593     public void testSetAvoidUnvalidated() throws Exception {
2594         assumeTrue(TestUtils.shouldTestSApis());
2595         // TODO: Allow in debuggable ROM only. To be replaced by FabricatedOverlay
2596         assumeTrue(Build.isDebuggable());
2597         final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
2598                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
2599         assumeTrue("testSetAvoidUnvalidated cannot execute"
2600                 + " unless device supports WiFi and telephony", canRunTest);
2601 
2602         final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
2603         final TestableNetworkCallback defaultCb = new TestableNetworkCallback();
2604         final int previousAvoidBadWifi =
2605                 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext);
2606 
2607         allowBadWifi();
2608 
2609         final Network cellNetwork = mCtsNetUtils.connectToCell();
2610         final Network wifiNetwork = prepareValidatedNetwork();
2611 
2612         mCm.registerDefaultNetworkCallback(defaultCb);
2613         mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb);
2614 
2615         try {
2616             // Verify wifi is the default network.
2617             defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2618                     entry -> wifiNetwork.equals(entry.getNetwork()));
2619             wifiCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2620                     entry -> wifiNetwork.equals(entry.getNetwork()));
2621             assertTrue(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
2622                     NET_CAPABILITY_VALIDATED));
2623 
2624             // Configure response code for unvalidated network
2625             configTestServer(Status.INTERNAL_ERROR, Status.INTERNAL_ERROR);
2626             mCm.reportNetworkConnectivity(wifiNetwork, false);
2627             // Default network should stay on unvalidated wifi because avoid bad wifi is disabled.
2628             defaultCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2629                     NETWORK_CALLBACK_TIMEOUT_MS,
2630                     entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps()
2631                             .hasCapability(NET_CAPABILITY_VALIDATED));
2632             wifiCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2633                     NETWORK_CALLBACK_TIMEOUT_MS,
2634                     entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps()
2635                             .hasCapability(NET_CAPABILITY_VALIDATED));
2636 
2637             runAsShell(NETWORK_SETTINGS, () -> {
2638                 mCm.setAvoidUnvalidated(wifiNetwork);
2639             });
2640             // Default network should be updated to validated cellular network.
2641             defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2642                     entry -> cellNetwork.equals(entry.getNetwork()));
2643             // No update on wifi callback.
2644             wifiCb.assertNoCallback();
2645         } finally {
2646             mCm.unregisterNetworkCallback(wifiCb);
2647             mCm.unregisterNetworkCallback(defaultCb);
2648             resetAvoidBadWifi(previousAvoidBadWifi);
2649             resetValidationConfig();
2650             // Reconnect wifi to reset the wifi status
2651             reconnectWifi();
2652         }
2653     }
2654 
2655     private void resetAvoidBadWifi(int settingValue) {
2656         setTestAllowBadWifiResource(0 /* timeMs */);
2657         ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, settingValue);
2658     }
2659 
2660     private void allowBadWifi() {
2661         setTestAllowBadWifiResource(
2662                 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS /* timeMs */);
2663         ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext,
2664                 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE);
2665     }
2666 
2667     private void setTestAllowBadWifiResource(long timeMs) {
2668         runAsShell(NETWORK_SETTINGS, () -> {
2669             mCm.setTestAllowBadWifiUntil(timeMs);
2670         });
2671     }
2672 
2673     private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout)
2674             throws Exception {
2675         final CompletableFuture<Network> future = new CompletableFuture();
2676         final NetworkCallback cb = new NetworkCallback() {
2677             @Override
2678             public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) {
2679                 if (n.equals(network) && nc.hasCapability(expectedNetCap)) {
2680                     future.complete(network);
2681                 }
2682             }
2683         };
2684 
2685         try {
2686             mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), cb);
2687             return future.get(timeout, TimeUnit.MILLISECONDS);
2688         } finally {
2689             mCm.unregisterNetworkCallback(cb);
2690         }
2691     }
2692 
2693     private void resetValidationConfig() {
2694         NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig();
2695         mHttpServer.stop();
2696     }
2697 
2698     private void prepareHttpServer() throws Exception {
2699         runAsShell(READ_DEVICE_CONFIG, () -> {
2700             // Verify that the test URLs are not normally set on the device, but do not fail if the
2701             // test URLs are set to what this test uses (URLs on localhost), in case the test was
2702             // interrupted manually and rerun.
2703             assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL);
2704             assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL);
2705         });
2706 
2707         NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig();
2708 
2709         mHttpServer.start();
2710     }
2711 
2712     private Network reconnectWifi() {
2713         mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
2714         return mCtsNetUtils.ensureWifiConnected();
2715     }
2716 
2717     private Network prepareValidatedNetwork() throws Exception {
2718         prepareHttpServer();
2719         configTestServer(Status.NO_CONTENT, Status.NO_CONTENT);
2720         // Disconnect wifi first then start wifi network with configuration.
2721         final Network wifiNetwork = reconnectWifi();
2722 
2723         return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_VALIDATED,
2724                 WIFI_CONNECT_TIMEOUT_MS);
2725     }
2726 
2727     private Network preparePartialConnectivity() throws Exception {
2728         prepareHttpServer();
2729         // Configure response code for partial connectivity
2730         configTestServer(Status.INTERNAL_ERROR  /* httpsStatusCode */,
2731                 Status.NO_CONTENT  /* httpStatusCode */);
2732         // Disconnect wifi first then start wifi network with configuration.
2733         mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
2734         final Network network = mCtsNetUtils.ensureWifiConnected();
2735 
2736         return expectNetworkHasCapability(network, NET_CAPABILITY_PARTIAL_CONNECTIVITY,
2737                 WIFI_CONNECT_TIMEOUT_MS);
2738     }
2739 
2740     private Network prepareUnvalidatedNetwork() throws Exception {
2741         prepareHttpServer();
2742         // Configure response code for unvalidated network
2743         configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */,
2744                 Status.INTERNAL_ERROR /* httpStatusCode */);
2745 
2746         // Disconnect wifi first then start wifi network with configuration.
2747         mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
2748         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2749         return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_INTERNET,
2750                 WIFI_CONNECT_TIMEOUT_MS);
2751     }
2752 
2753     private String makeUrl(String path) {
2754         return "http://localhost:" + mHttpServer.getListeningPort() + path;
2755     }
2756 
2757     private void assertEmptyOrLocalhostUrl(String urlKey) {
2758         final String url = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, urlKey);
2759         assertTrue(urlKey + " must not be set in production scenarios, current value= " + url,
2760                 TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME.equals(Uri.parse(url).getHost()));
2761     }
2762 
2763     private void configTestServer(IStatus httpsStatusCode, IStatus httpStatusCode) {
2764         mHttpServer.addResponse(new TestHttpServer.Request(
2765                 TEST_HTTPS_URL_PATH, Method.GET, "" /* queryParameters */),
2766                 httpsStatusCode, null /* locationHeader */, "" /* content */);
2767         mHttpServer.addResponse(new TestHttpServer.Request(
2768                 TEST_HTTP_URL_PATH, Method.GET, "" /* queryParameters */),
2769                 httpStatusCode, null /* locationHeader */, "" /* content */);
2770         NetworkValidationTestUtil.setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH));
2771         NetworkValidationTestUtil.setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH));
2772         NetworkValidationTestUtil.setUrlExpirationDeviceConfig(
2773                 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS);
2774     }
2775 
2776     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2777     @Test
2778     public void testMobileDataPreferredUids() throws Exception {
2779         assumeTrue(TestUtils.shouldTestSApis());
2780         final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
2781                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
2782         assumeTrue("testMobileDataPreferredUidsWithCallback cannot execute"
2783                 + " unless device supports both WiFi and telephony", canRunTest);
2784 
2785         final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */);
2786         final Set<Integer> mobileDataPreferredUids =
2787                 ConnectivitySettingsManager.getMobileDataPreferredUids(mContext);
2788         // CtsNetTestCases uid should not list in MOBILE_DATA_PREFERRED_UIDS setting because it just
2789         // installs to device. In case the uid is existed in setting mistakenly, try to remove the
2790         // uid and set correct uids to setting.
2791         mobileDataPreferredUids.remove(uid);
2792         ConnectivitySettingsManager.setMobileDataPreferredUids(mContext, mobileDataPreferredUids);
2793 
2794         // For testing mobile data preferred uids feature, it needs both wifi and cell network.
2795         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2796         final Network cellNetwork = mCtsNetUtils.connectToCell();
2797         final TestableNetworkCallback defaultTrackingCb = new TestableNetworkCallback();
2798         final TestableNetworkCallback systemDefaultCb = new TestableNetworkCallback();
2799         final Handler h = new Handler(Looper.getMainLooper());
2800         runWithShellPermissionIdentity(() -> mCm.registerSystemDefaultNetworkCallback(
2801                 systemDefaultCb, h), NETWORK_SETTINGS);
2802         mCm.registerDefaultNetworkCallback(defaultTrackingCb);
2803 
2804         try {
2805             // CtsNetTestCases uid is not listed in MOBILE_DATA_PREFERRED_UIDS setting, so the
2806             // per-app default network should be same as system default network.
2807             waitForAvailable(systemDefaultCb, wifiNetwork);
2808             defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2809                     entry -> wifiNetwork.equals(entry.getNetwork()));
2810             // Active network for CtsNetTestCases uid should be wifi now.
2811             assertEquals(wifiNetwork, mCm.getActiveNetwork());
2812 
2813             // Add CtsNetTestCases uid to MOBILE_DATA_PREFERRED_UIDS setting, then available per-app
2814             // default network callback should be received with cell network.
2815             final Set<Integer> newMobileDataPreferredUids = new ArraySet<>(mobileDataPreferredUids);
2816             newMobileDataPreferredUids.add(uid);
2817             ConnectivitySettingsManager.setMobileDataPreferredUids(
2818                     mContext, newMobileDataPreferredUids);
2819             defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2820                     entry -> cellNetwork.equals(entry.getNetwork()));
2821             // System default network doesn't change.
2822             systemDefaultCb.assertNoCallback();
2823             // Active network for CtsNetTestCases uid should change to cell, too.
2824             assertEquals(cellNetwork, mCm.getActiveNetwork());
2825 
2826             // Remove CtsNetTestCases uid from MOBILE_DATA_PREFERRED_UIDS setting, then available
2827             // per-app default network callback should be received again with system default network
2828             newMobileDataPreferredUids.remove(uid);
2829             ConnectivitySettingsManager.setMobileDataPreferredUids(
2830                     mContext, newMobileDataPreferredUids);
2831             defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2832                     entry -> wifiNetwork.equals(entry.getNetwork()));
2833             // System default network still doesn't change.
2834             systemDefaultCb.assertNoCallback();
2835             // Active network for CtsNetTestCases uid should change back to wifi.
2836             assertEquals(wifiNetwork, mCm.getActiveNetwork());
2837         } finally {
2838             mCm.unregisterNetworkCallback(systemDefaultCb);
2839             mCm.unregisterNetworkCallback(defaultTrackingCb);
2840 
2841             // Restore setting.
2842             ConnectivitySettingsManager.setMobileDataPreferredUids(
2843                     mContext, mobileDataPreferredUids);
2844         }
2845     }
2846 
2847     /** Wait for assigned time. */
2848     private void waitForMs(long ms) {
2849         try {
2850             Thread.sleep(ms);
2851         } catch (InterruptedException e) {
2852             fail("Thread was interrupted");
2853         }
2854     }
2855 
2856     private void assertBindSocketToNetworkSuccess(final Network network) throws Exception {
2857         final CompletableFuture<Boolean> future = new CompletableFuture<>();
2858         final ExecutorService executor = Executors.newSingleThreadExecutor();
2859         try {
2860             executor.execute(() -> {
2861                 for (int i = 0; i < 30; i++) {
2862                     waitForMs(100);
2863 
2864                     try (Socket socket = new Socket()) {
2865                         network.bindSocket(socket);
2866                         future.complete(true);
2867                         return;
2868                     } catch (IOException e) { }
2869                 }
2870             });
2871             assertTrue(future.get(APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS,
2872                     TimeUnit.MILLISECONDS));
2873         } finally {
2874             executor.shutdown();
2875         }
2876     }
2877 
2878     @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
2879     @Test
2880     public void testUidsAllowedOnRestrictedNetworks() throws Exception {
2881         assumeTrue(TestUtils.shouldTestSApis());
2882 
2883         // TODO (b/175199465): figure out a reasonable permission check for
2884         //  setUidsAllowedOnRestrictedNetworks that allows tests but not system-external callers.
2885         assumeTrue(Build.isDebuggable());
2886 
2887         final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */);
2888         final Set<Integer> originalUidsAllowedOnRestrictedNetworks =
2889                 ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext);
2890         // CtsNetTestCases uid should not list in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting
2891         // because it has been just installed to device. In case the uid is existed in setting
2892         // mistakenly, try to remove the uid and set correct uids to setting.
2893         originalUidsAllowedOnRestrictedNetworks.remove(uid);
2894         runWithShellPermissionIdentity(() ->
2895                 ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
2896                         mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
2897 
2898         final Handler h = new Handler(Looper.getMainLooper());
2899         final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
2900         mCm.registerBestMatchingNetworkCallback(new NetworkRequest.Builder().clearCapabilities()
2901                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), testNetworkCb, h);
2902 
2903         // Create test network agent with restricted network.
2904         final NetworkCapabilities nc = new NetworkCapabilities.Builder()
2905                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
2906                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
2907                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
2908                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
2909                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
2910                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
2911                 .build();
2912         final NetworkScore score = new NetworkScore.Builder()
2913                 .setExiting(false)
2914                 .setTransportPrimary(false)
2915                 .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER)
2916                 .build();
2917         final NetworkAgent agent = new NetworkAgent(mContext, Looper.getMainLooper(),
2918                 TAG, nc, new LinkProperties(), score, new NetworkAgentConfig.Builder().build(),
2919                 new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {};
2920         runWithShellPermissionIdentity(() -> agent.register(),
2921                 android.Manifest.permission.MANAGE_TEST_NETWORKS);
2922         agent.markConnected();
2923 
2924         final Network network = agent.getNetwork();
2925 
2926         try (Socket socket = new Socket()) {
2927             testNetworkCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2928                     entry -> network.equals(entry.getNetwork()));
2929             // Verify that the network is restricted.
2930             final NetworkCapabilities testNetworkNc = mCm.getNetworkCapabilities(network);
2931             assertNotNull(testNetworkNc);
2932             assertFalse(testNetworkNc.hasCapability(
2933                     NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
2934             // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
2935             // does not allow to bind socket to restricted network.
2936             assertThrows(IOException.class, () -> network.bindSocket(socket));
2937 
2938             // Add CtsNetTestCases uid to UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting, then it can
2939             // bind socket to restricted network normally.
2940             final Set<Integer> newUidsAllowedOnRestrictedNetworks =
2941                     new ArraySet<>(originalUidsAllowedOnRestrictedNetworks);
2942             newUidsAllowedOnRestrictedNetworks.add(uid);
2943             runWithShellPermissionIdentity(() ->
2944                     ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
2945                             mContext, newUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
2946             // Wait a while for sending allowed uids on the restricted network to netd.
2947             // TODD: Have a significant signal to know the uids has been send to netd.
2948             assertBindSocketToNetworkSuccess(network);
2949         } finally {
2950             mCm.unregisterNetworkCallback(testNetworkCb);
2951             agent.unregister();
2952 
2953             // Restore setting.
2954             runWithShellPermissionIdentity(() ->
2955                     ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
2956                             mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
2957         }
2958     }
2959 }
2960