• 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.ACCESS_COARSE_LOCATION;
20 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
21 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
22 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
23 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
24 import static android.Manifest.permission.NETWORK_FACTORY;
25 import static android.Manifest.permission.NETWORK_SETTINGS;
26 import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
27 import static android.Manifest.permission.NETWORK_STACK;
28 import static android.Manifest.permission.READ_DEVICE_CONFIG;
29 import static android.Manifest.permission.TETHER_PRIVILEGED;
30 import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
31 import static android.content.pm.PackageManager.FEATURE_ETHERNET;
32 import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
33 import static android.content.pm.PackageManager.FEATURE_USB_HOST;
34 import static android.content.pm.PackageManager.FEATURE_WATCH;
35 import static android.content.pm.PackageManager.FEATURE_WIFI;
36 import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
37 import static android.content.pm.PackageManager.GET_PERMISSIONS;
38 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
39 import static android.net.ConnectivityManager.EXTRA_NETWORK;
40 import static android.net.ConnectivityManager.EXTRA_NETWORK_REQUEST;
41 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
42 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
43 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
44 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
45 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
46 import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
47 import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
48 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
49 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
50 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
51 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
52 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
53 import static android.net.ConnectivityManager.TYPE_ETHERNET;
54 import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
55 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
56 import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY;
57 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
58 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
59 import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
60 import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
61 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
62 import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
63 import static android.net.ConnectivityManager.TYPE_PROXY;
64 import static android.net.ConnectivityManager.TYPE_VPN;
65 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
66 import static android.net.ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks;
67 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
68 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
69 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
70 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
71 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
72 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
73 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
74 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
75 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
76 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
77 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
78 import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
79 import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
80 import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
81 import static android.net.cts.util.CtsNetUtils.TEST_HOST;
82 import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
83 import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback;
84 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
85 import static android.os.Process.INVALID_UID;
86 import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
87 import static android.system.OsConstants.AF_INET;
88 import static android.system.OsConstants.AF_INET6;
89 import static android.system.OsConstants.AF_UNSPEC;
90 
91 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
92 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
93 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
94 import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
95 import static com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTPS_URL;
96 import static com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL;
97 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
98 import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
99 import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
100 import static com.android.testutils.Cleanup.testAndCleanup;
101 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
102 import static com.android.testutils.MiscAsserts.assertThrows;
103 import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
104 import static com.android.testutils.TestPermissionUtil.runAsShell;
105 
106 import static org.junit.Assert.assertArrayEquals;
107 import static org.junit.Assert.assertEquals;
108 import static org.junit.Assert.assertFalse;
109 import static org.junit.Assert.assertNotEquals;
110 import static org.junit.Assert.assertNotNull;
111 import static org.junit.Assert.assertNotSame;
112 import static org.junit.Assert.assertNull;
113 import static org.junit.Assert.assertTrue;
114 import static org.junit.Assert.fail;
115 import static org.junit.Assume.assumeTrue;
116 
117 import android.annotation.NonNull;
118 import android.app.Instrumentation;
119 import android.app.PendingIntent;
120 import android.app.UiAutomation;
121 import android.content.BroadcastReceiver;
122 import android.content.ContentResolver;
123 import android.content.Context;
124 import android.content.Intent;
125 import android.content.IntentFilter;
126 import android.content.pm.PackageInfo;
127 import android.content.pm.PackageManager;
128 import android.content.res.Resources;
129 import android.net.CaptivePortalData;
130 import android.net.ConnectivityManager;
131 import android.net.ConnectivityManager.NetworkCallback;
132 import android.net.ConnectivitySettingsManager;
133 import android.net.InetAddresses;
134 import android.net.IpSecManager;
135 import android.net.IpSecManager.UdpEncapsulationSocket;
136 import android.net.LinkAddress;
137 import android.net.LinkProperties;
138 import android.net.Network;
139 import android.net.NetworkAgent;
140 import android.net.NetworkAgentConfig;
141 import android.net.NetworkCapabilities;
142 import android.net.NetworkInfo;
143 import android.net.NetworkInfo.DetailedState;
144 import android.net.NetworkInfo.State;
145 import android.net.NetworkProvider;
146 import android.net.NetworkRequest;
147 import android.net.NetworkSpecifier;
148 import android.net.NetworkStateSnapshot;
149 import android.net.OemNetworkPreferences;
150 import android.net.ProxyInfo;
151 import android.net.SocketKeepalive;
152 import android.net.TelephonyNetworkSpecifier;
153 import android.net.TestNetworkInterface;
154 import android.net.TestNetworkManager;
155 import android.net.Uri;
156 import android.net.cts.util.CtsNetUtils;
157 import android.net.cts.util.CtsTetheringUtils;
158 import android.net.util.KeepaliveUtils;
159 import android.net.wifi.WifiInfo;
160 import android.net.wifi.WifiManager;
161 import android.os.Binder;
162 import android.os.Build;
163 import android.os.Handler;
164 import android.os.Looper;
165 import android.os.MessageQueue;
166 import android.os.Process;
167 import android.os.ServiceManager;
168 import android.os.SystemClock;
169 import android.os.UserHandle;
170 import android.os.VintfRuntimeInfo;
171 import android.platform.test.annotations.AppModeFull;
172 import android.provider.DeviceConfig;
173 import android.provider.Settings;
174 import android.telephony.SubscriptionManager;
175 import android.telephony.TelephonyManager;
176 import android.text.TextUtils;
177 import android.util.ArraySet;
178 import android.util.Log;
179 import android.util.Range;
180 
181 import androidx.test.InstrumentationRegistry;
182 import androidx.test.filters.RequiresDevice;
183 import androidx.test.runner.AndroidJUnit4;
184 
185 import com.android.internal.util.ArrayUtils;
186 import com.android.modules.utils.build.SdkLevel;
187 import com.android.net.module.util.CollectionUtils;
188 import com.android.networkstack.apishim.ConnectivityManagerShimImpl;
189 import com.android.networkstack.apishim.ConstantsShim;
190 import com.android.networkstack.apishim.NetworkInformationShimImpl;
191 import com.android.networkstack.apishim.common.ConnectivityManagerShim;
192 import com.android.testutils.CompatUtil;
193 import com.android.testutils.ConnectivityModuleTest;
194 import com.android.testutils.DevSdkIgnoreRule;
195 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
196 import com.android.testutils.DeviceConfigRule;
197 import com.android.testutils.DeviceInfoUtils;
198 import com.android.testutils.DumpTestUtils;
199 import com.android.testutils.RecorderCallback.CallbackEntry;
200 import com.android.testutils.TestHttpServer;
201 import com.android.testutils.TestNetworkTracker;
202 import com.android.testutils.TestableNetworkCallback;
203 
204 import junit.framework.AssertionFailedError;
205 
206 import libcore.io.Streams;
207 
208 import org.junit.After;
209 import org.junit.Before;
210 import org.junit.Rule;
211 import org.junit.Test;
212 import org.junit.runner.RunWith;
213 
214 import java.io.FileDescriptor;
215 import java.io.IOException;
216 import java.io.InputStream;
217 import java.io.InputStreamReader;
218 import java.io.OutputStream;
219 import java.net.DatagramPacket;
220 import java.net.DatagramSocket;
221 import java.net.HttpURLConnection;
222 import java.net.Inet4Address;
223 import java.net.Inet6Address;
224 import java.net.InetAddress;
225 import java.net.InetSocketAddress;
226 import java.net.MalformedURLException;
227 import java.net.Socket;
228 import java.net.SocketException;
229 import java.net.URL;
230 import java.net.UnknownHostException;
231 import java.nio.charset.StandardCharsets;
232 import java.util.ArrayList;
233 import java.util.Collection;
234 import java.util.List;
235 import java.util.Objects;
236 import java.util.Random;
237 import java.util.Set;
238 import java.util.UUID;
239 import java.util.concurrent.CompletableFuture;
240 import java.util.concurrent.CountDownLatch;
241 import java.util.concurrent.Executor;
242 import java.util.concurrent.ExecutorService;
243 import java.util.concurrent.Executors;
244 import java.util.concurrent.LinkedBlockingQueue;
245 import java.util.concurrent.TimeUnit;
246 import java.util.concurrent.TimeoutException;
247 import java.util.concurrent.atomic.AtomicInteger;
248 import java.util.function.Supplier;
249 import java.util.regex.Matcher;
250 import java.util.regex.Pattern;
251 
252 import fi.iki.elonen.NanoHTTPD.Method;
253 import fi.iki.elonen.NanoHTTPD.Response.IStatus;
254 import fi.iki.elonen.NanoHTTPD.Response.Status;
255 
256 @RunWith(AndroidJUnit4.class)
257 public class ConnectivityManagerTest {
258     @Rule
259     public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
260 
261     @Rule
262     public final DeviceConfigRule mTestValidationConfigRule = new DeviceConfigRule(
263             5 /* retryCountBeforeSIfConfigChanged */);
264 
265     private static final String TAG = ConnectivityManagerTest.class.getSimpleName();
266 
267     public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
268     public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
269 
270     private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
271     private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
272     private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500;
273     private static final int MAX_KEEPALIVE_RETRY_COUNT = 3;
274     private static final int MIN_KEEPALIVE_INTERVAL = 10;
275 
276     private static final int NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
277     // Timeout for waiting network to be validated. Set the timeout to 30s, which is more than
278     // DNS timeout.
279     // TODO(b/252972908): reset the original timer when aosp/2188755 is ramped up.
280     private static final int LISTEN_ACTIVITY_TIMEOUT_MS = 30_000;
281     private static final int NO_CALLBACK_TIMEOUT_MS = 100;
282     private static final int NETWORK_REQUEST_TIMEOUT_MS = 3000;
283     private static final int SOCKET_TIMEOUT_MS = 100;
284     private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
285     private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
286     // device could have only one interface: data, wifi.
287     private static final int MIN_NUM_NETWORK_TYPES = 1;
288 
289     // Airplane Mode BroadcastReceiver Timeout
290     private static final long AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 10_000L;
291 
292     // Timeout for applying uids allowed on restricted networks
293     private static final long APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS = 3_000L;
294 
295     // Minimum supported keepalive counts for wifi and cellular.
296     public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1;
297     public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3;
298 
299     private static final String NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME =
300             "config_networkMeteredMultipathPreference";
301     private static final String KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME =
302             "config_allowedUnprivilegedKeepalivePerUid";
303     private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME =
304             "config_reservedPrivilegedKeepaliveSlots";
305     private static final String TEST_RESTRICTED_NW_IFACE_NAME = "test-restricted-nw";
306 
307     private static final LinkAddress TEST_LINKADDR = new LinkAddress(
308             InetAddresses.parseNumericAddress("2001:db8::8"), 64);
309 
310     private static final int AIRPLANE_MODE_OFF = 0;
311     private static final int AIRPLANE_MODE_ON = 1;
312 
313     private static final String TEST_HTTPS_URL_PATH = "/https_path";
314     private static final String TEST_HTTP_URL_PATH = "/http_path";
315     private static final String LOCALHOST_HOSTNAME = "localhost";
316     // Re-connecting to the AP, obtaining an IP address, revalidating can take a long time
317     private static final long WIFI_CONNECT_TIMEOUT_MS = 60_000L;
318 
319     private Context mContext;
320     private Instrumentation mInstrumentation;
321     private ConnectivityManager mCm;
322     private ConnectivityManagerShim mCmShim;
323     private WifiManager mWifiManager;
324     private PackageManager mPackageManager;
325     private TelephonyManager mTm;
326     private final ArraySet<Integer> mNetworkTypes = new ArraySet<>();
327     private UiAutomation mUiAutomation;
328     private CtsNetUtils mCtsNetUtils;
329     // The registered callbacks.
330     private List<NetworkCallback> mRegisteredCallbacks = new ArrayList<>();
331     // Used for cleanup purposes.
332     private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>();
333 
334     private final TestHttpServer mHttpServer = new TestHttpServer(LOCALHOST_HOSTNAME);
335 
336     @Before
setUp()337     public void setUp() throws Exception {
338         mInstrumentation = InstrumentationRegistry.getInstrumentation();
339         mContext = mInstrumentation.getContext();
340         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
341         mCmShim = ConnectivityManagerShimImpl.newInstance(mContext);
342         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
343         mPackageManager = mContext.getPackageManager();
344         mCtsNetUtils = new CtsNetUtils(mContext);
345         mTm = mContext.getSystemService(TelephonyManager.class);
346 
347         if (isAtLeastS()) {
348             addSupportedNetworkTypes();
349         } else {
350             addLegacySupportedNetworkTypes();
351         }
352 
353         mUiAutomation = mInstrumentation.getUiAutomation();
354 
355         assertNotNull("CTS requires a working Internet connection", mCm.getActiveNetwork());
356     }
357 
addLegacySupportedNetworkTypes()358     private void addLegacySupportedNetworkTypes() {
359         // Network type support as expected for android R-
360         // Get com.android.internal.R.array.networkAttributes
361         int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
362         String[] naStrings = mContext.getResources().getStringArray(resId);
363         boolean wifiOnly = mPackageManager.hasSystemFeature(FEATURE_WIFI)
364                 && !mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
365         for (String naString : naStrings) {
366             try {
367                 final String[] splitConfig = naString.split(",");
368                 // Format was name,type,radio,priority,restoreTime,dependencyMet
369                 final int type = Integer.parseInt(splitConfig[1]);
370                 if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(type)) {
371                     continue;
372                 }
373                 mNetworkTypes.add(type);
374             } catch (Exception e) {}
375         }
376     }
377 
addSupportedNetworkTypes()378     private void addSupportedNetworkTypes() {
379         final PackageManager pm = mContext.getPackageManager();
380         if (pm.hasSystemFeature(FEATURE_WIFI)) {
381             mNetworkTypes.add(TYPE_WIFI);
382         }
383         if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) {
384             mNetworkTypes.add(TYPE_WIFI_P2P);
385         }
386         if (mContext.getSystemService(TelephonyManager.class).isDataCapable()) {
387             mNetworkTypes.add(TYPE_MOBILE);
388             mNetworkTypes.add(TYPE_MOBILE_MMS);
389             mNetworkTypes.add(TYPE_MOBILE_SUPL);
390             mNetworkTypes.add(TYPE_MOBILE_DUN);
391             mNetworkTypes.add(TYPE_MOBILE_HIPRI);
392             mNetworkTypes.add(TYPE_MOBILE_FOTA);
393             mNetworkTypes.add(TYPE_MOBILE_IMS);
394             mNetworkTypes.add(TYPE_MOBILE_CBS);
395             mNetworkTypes.add(TYPE_MOBILE_IA);
396             mNetworkTypes.add(TYPE_MOBILE_EMERGENCY);
397         }
398         if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) {
399             mNetworkTypes.add(TYPE_BLUETOOTH);
400         }
401         if (pm.hasSystemFeature(FEATURE_WATCH)) {
402             mNetworkTypes.add(TYPE_PROXY);
403         }
404         if (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) {
405             mNetworkTypes.add(TYPE_ETHERNET);
406         }
407         mNetworkTypes.add(TYPE_VPN);
408     }
409 
410     @After
tearDown()411     public void tearDown() throws Exception {
412         // Release any NetworkRequests filed to connect mobile data.
413         if (mCtsNetUtils.cellConnectAttempted()) {
414             mCtsNetUtils.disconnectFromCell();
415         }
416 
417         if (TestUtils.shouldTestSApis()) {
418             runWithShellPermissionIdentity(
419                     () -> mCmShim.setRequireVpnForUids(false, mVpnRequiredUidRanges),
420                     NETWORK_SETTINGS);
421         }
422 
423         // All tests in this class require a working Internet connection as they start. Make
424         // sure there is still one as they end that's ready to use for the next test to use.
425         mTestValidationConfigRule.runAfterNextCleanup(() -> {
426             final TestNetworkCallback callback = new TestNetworkCallback();
427             registerDefaultNetworkCallback(callback);
428             try {
429                 assertNotNull("Couldn't restore Internet connectivity",
430                         callback.waitForAvailable());
431             } finally {
432                 // Unregister all registered callbacks.
433                 unregisterRegisteredCallbacks();
434             }
435         });
436     }
437 
438     @Test
testIsNetworkTypeValid()439     public void testIsNetworkTypeValid() {
440         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE));
441         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI));
442         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_MMS));
443         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_SUPL));
444         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_DUN));
445         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_HIPRI));
446         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIMAX));
447         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_BLUETOOTH));
448         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_DUMMY));
449         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_ETHERNET));
450         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_FOTA));
451         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IMS));
452         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_CBS));
453         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI_P2P));
454         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE_IA));
455         assertFalse(mCm.isNetworkTypeValid(-1));
456         assertTrue(mCm.isNetworkTypeValid(0));
457         assertTrue(mCm.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE));
458         assertFalse(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.MAX_NETWORK_TYPE+1));
459 
460         NetworkInfo[] ni = mCm.getAllNetworkInfo();
461 
462         for (NetworkInfo n: ni) {
463             assertTrue(ConnectivityManager.isNetworkTypeValid(n.getType()));
464         }
465 
466     }
467 
468     @Test
testSetNetworkPreference()469     public void testSetNetworkPreference() {
470         // getNetworkPreference() and setNetworkPreference() are both deprecated so they do
471         // not preform any action.  Verify they are at least still callable.
472         mCm.setNetworkPreference(mCm.getNetworkPreference());
473     }
474 
475     @Test
testGetActiveNetworkInfo()476     public void testGetActiveNetworkInfo() {
477         NetworkInfo ni = mCm.getActiveNetworkInfo();
478 
479         assertNotNull("You must have an active network connection to complete CTS", ni);
480         assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType()));
481         assertTrue(ni.getState() == State.CONNECTED);
482     }
483 
484     @Test
testGetActiveNetwork()485     public void testGetActiveNetwork() {
486         Network network = mCm.getActiveNetwork();
487         assertNotNull("You must have an active network connection to complete CTS", network);
488 
489         NetworkInfo ni = mCm.getNetworkInfo(network);
490         assertNotNull("Network returned from getActiveNetwork was invalid", ni);
491 
492         // Similar to testGetActiveNetworkInfo above.
493         assertTrue(ConnectivityManager.isNetworkTypeValid(ni.getType()));
494         assertTrue(ni.getState() == State.CONNECTED);
495     }
496 
497     @Test
testGetNetworkInfo()498     public void testGetNetworkInfo() {
499         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) {
500             if (shouldBeSupported(type)) {
501                 NetworkInfo ni = mCm.getNetworkInfo(type);
502                 assertTrue("Info shouldn't be null for " + type, ni != null);
503                 State state = ni.getState();
504                 assertTrue("Bad state for " + type, State.UNKNOWN.ordinal() >= state.ordinal()
505                            && state.ordinal() >= State.CONNECTING.ordinal());
506                 DetailedState ds = ni.getDetailedState();
507                 assertTrue("Bad detailed state for " + type,
508                            DetailedState.FAILED.ordinal() >= ds.ordinal()
509                            && ds.ordinal() >= DetailedState.IDLE.ordinal());
510             } else {
511                 assertNull("Info should be null for " + type, mCm.getNetworkInfo(type));
512             }
513         }
514     }
515 
516     @Test
testGetAllNetworkInfo()517     public void testGetAllNetworkInfo() {
518         NetworkInfo[] ni = mCm.getAllNetworkInfo();
519         assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES);
520         for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
521             int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0);
522             int foundCount = 0;
523             for (NetworkInfo i : ni) {
524                 if (i.getType() == type) foundCount++;
525             }
526             if (foundCount != desiredFoundCount) {
527                 Log.e(TAG, "failure in testGetAllNetworkInfo.  Dump of returned NetworkInfos:");
528                 for (NetworkInfo networkInfo : ni) Log.e(TAG, "  " + networkInfo);
529             }
530             assertTrue("Unexpected foundCount of " + foundCount + " for type " + type,
531                     foundCount == desiredFoundCount);
532         }
533     }
534 
getSubscriberIdForCellNetwork(Network cellNetwork)535     private String getSubscriberIdForCellNetwork(Network cellNetwork) {
536         final NetworkCapabilities cellCaps = mCm.getNetworkCapabilities(cellNetwork);
537         final NetworkSpecifier specifier = cellCaps.getNetworkSpecifier();
538         assertTrue(specifier instanceof TelephonyNetworkSpecifier);
539         // Get subscription from Telephony network specifier.
540         final int subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
541         assertNotEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, subId);
542 
543         // Get subscriber Id from telephony manager.
544         final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
545         return runWithShellPermissionIdentity(() -> tm.getSubscriberId(subId),
546                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
547     }
548 
549     @AppModeFull(reason = "Cannot request network in instant app mode")
550     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
551     @Test
testGetAllNetworkStateSnapshots()552     public void testGetAllNetworkStateSnapshots()
553             throws InterruptedException {
554         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
555         // Make sure cell is active to retrieve IMSI for verification in later step.
556         final Network cellNetwork = mCtsNetUtils.connectToCell();
557         final String subscriberId = getSubscriberIdForCellNetwork(cellNetwork);
558         assertFalse(TextUtils.isEmpty(subscriberId));
559 
560         // Verify the API cannot be called without proper permission.
561         assertThrows(SecurityException.class, () -> mCm.getAllNetworkStateSnapshots());
562 
563         // Get all networks, verify the result of getAllNetworkStateSnapshots matches the result
564         // got from other APIs.
565         final Network[] networks = mCm.getAllNetworks();
566         assertGreaterOrEqual(networks.length, 1);
567         final TestableNetworkCallback allNetworkLinkPropertiesListener =
568                 new TestableNetworkCallback();
569         mCm.registerNetworkCallback(new NetworkRequest.Builder().clearCapabilities().build(),
570                 allNetworkLinkPropertiesListener);
571 
572         final List<NetworkStateSnapshot> snapshots = runWithShellPermissionIdentity(
573                 () -> mCm.getAllNetworkStateSnapshots(), NETWORK_SETTINGS);
574         assertEquals(networks.length, snapshots.size());
575         for (final Network network : networks) {
576             // Can't use a lambda because it will cause the test to crash on R with
577             // NoClassDefFoundError.
578             NetworkStateSnapshot snapshot = null;
579             for (NetworkStateSnapshot item : snapshots) {
580                 if (item.getNetwork().equals(network)) {
581                     snapshot = item;
582                     break;
583                 }
584             }
585             assertNotNull(snapshot);
586             final NetworkCapabilities caps =
587                     Objects.requireNonNull(mCm.getNetworkCapabilities(network));
588             // Redact specifier of the capabilities of the snapshot before comparing since
589             // the result returned from getNetworkCapabilities always get redacted.
590             final NetworkSpecifier snapshotCapSpecifier =
591                     snapshot.getNetworkCapabilities().getNetworkSpecifier();
592             final NetworkSpecifier redactedSnapshotCapSpecifier =
593                     snapshotCapSpecifier == null ? null : snapshotCapSpecifier.redact();
594             assertEquals("", caps.describeImmutableDifferences(
595                     snapshot.getNetworkCapabilities()
596                             .setNetworkSpecifier(redactedSnapshotCapSpecifier)));
597 
598             // Don't check that the mutable fields are the same with synchronous calls, as
599             // the device may add or remove content of these fields in the middle of the test.
600             // Instead, search the target LinkProperties from received LinkPropertiesChanged
601             // callbacks. This is guaranteed to succeed because the callback is registered
602             // before getAllNetworkStateSnapshots is called.
603             final LinkProperties lpFromSnapshot = snapshot.getLinkProperties();
604             allNetworkLinkPropertiesListener.eventuallyExpect(CallbackEntry.LINK_PROPERTIES_CHANGED,
605                     NETWORK_CALLBACK_TIMEOUT_MS, 0 /* mark */, entry ->
606                             entry.getNetwork().equals(network)
607                                     && entry.getLp().equals(lpFromSnapshot));
608 
609             assertEquals(mCm.getNetworkInfo(network).getType(), snapshot.getLegacyType());
610 
611             if (network.equals(cellNetwork)) {
612                 assertEquals(subscriberId, snapshot.getSubscriberId());
613             }
614         }
615     }
616 
checkPermission(String perm, int uid)617     private boolean checkPermission(String perm, int uid) {
618         return mContext.checkPermission(perm, -1 /* pid */, uid) == PERMISSION_GRANTED;
619     }
620 
findPackageByPermissions(@onNull List<String> requiredPermissions, @NonNull List<String> forbiddenPermissions)621     private String findPackageByPermissions(@NonNull List<String> requiredPermissions,
622                 @NonNull List<String> forbiddenPermissions) throws Exception {
623         final List<PackageInfo> packageInfos =
624                 mPackageManager.getInstalledPackages(GET_PERMISSIONS);
625         for (PackageInfo packageInfo : packageInfos) {
626             final int uid = mPackageManager.getPackageUid(packageInfo.packageName, 0 /* flags */);
627             if (!CollectionUtils.all(requiredPermissions, perm -> checkPermission(perm, uid))) {
628                 continue;
629             }
630             if (CollectionUtils.any(forbiddenPermissions, perm -> checkPermission(perm, uid))) {
631                 continue;
632             }
633 
634             return packageInfo.packageName;
635         }
636         return null;
637     }
638 
639     @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
640     @AppModeFull(reason = "Cannot get installed packages in instant app mode")
641     @Test
testGetRedactedLinkPropertiesForPackage()642     public void testGetRedactedLinkPropertiesForPackage() throws Exception {
643         final String groundedPkg = findPackageByPermissions(
644                 List.of(), /* requiredPermissions */
645                 List.of(ACCESS_NETWORK_STATE) /* forbiddenPermissions */);
646         assertNotNull("Couldn't find any package without ACCESS_NETWORK_STATE", groundedPkg);
647         final int groundedUid = mPackageManager.getPackageUid(groundedPkg, 0 /* flags */);
648 
649         final String normalPkg = findPackageByPermissions(
650                 List.of(ACCESS_NETWORK_STATE) /* requiredPermissions */,
651                 List.of(NETWORK_SETTINGS, NETWORK_STACK,
652                         PERMISSION_MAINLINE_NETWORK_STACK) /* forbiddenPermissions */);
653         assertNotNull("Couldn't find any package with ACCESS_NETWORK_STATE but"
654                 + " without NETWORK_SETTINGS", normalPkg);
655         final int normalUid = mPackageManager.getPackageUid(normalPkg, 0 /* flags */);
656 
657         // There are some privileged packages on the system, like the phone process, the network
658         // stack and the system server.
659         final String privilegedPkg = findPackageByPermissions(
660                 List.of(ACCESS_NETWORK_STATE, NETWORK_SETTINGS), /* requiredPermissions */
661                 List.of() /* forbiddenPermissions */);
662         assertNotNull("Couldn't find a package with sufficient permissions", privilegedPkg);
663         final int privilegedUid = mPackageManager.getPackageUid(privilegedPkg, 0);
664 
665         // Set parcelSensitiveFields to true to preserve CaptivePortalApiUrl & CaptivePortalData
666         // when parceling.
667         final LinkProperties lp = new LinkProperties(new LinkProperties(),
668                 true /* parcelSensitiveFields */);
669         final Uri capportUrl = Uri.parse("https://capport.example.com/api");
670         final CaptivePortalData capportData = new CaptivePortalData.Builder().build();
671         final int mtu = 12345;
672         lp.setMtu(mtu);
673         lp.setCaptivePortalApiUrl(capportUrl);
674         lp.setCaptivePortalData(capportData);
675 
676         // No matter what the given uid is, a SecurityException will be thrown if the caller
677         // doesn't hold the NETWORK_SETTINGS permission.
678         assertThrows(SecurityException.class,
679                 () -> mCm.getRedactedLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
680         assertThrows(SecurityException.class,
681                 () -> mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg));
682         assertThrows(SecurityException.class,
683                 () -> mCm.getRedactedLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg));
684 
685         runAsShell(NETWORK_SETTINGS, () -> {
686             // No matter what the given uid is, if the given LinkProperties is null, then
687             // NullPointerException will be thrown.
688             assertThrows(NullPointerException.class,
689                     () -> mCm.getRedactedLinkPropertiesForPackage(null, groundedUid, groundedPkg));
690             assertThrows(NullPointerException.class,
691                     () -> mCm.getRedactedLinkPropertiesForPackage(null, normalUid, normalPkg));
692             assertThrows(NullPointerException.class,
693                     () -> mCm.getRedactedLinkPropertiesForPackage(
694                             null, privilegedUid, privilegedPkg));
695 
696             // Make sure null is returned for a UID without ACCESS_NETWORK_STATE.
697             assertNull(mCm.getRedactedLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
698 
699             // CaptivePortalApiUrl & CaptivePortalData will be set to null if given uid doesn't hold
700             // the NETWORK_SETTINGS permission.
701             assertNull(mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg)
702                     .getCaptivePortalApiUrl());
703             assertNull(mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg)
704                     .getCaptivePortalData());
705             // MTU is not sensitive and is not redacted.
706             assertEquals(mtu, mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg)
707                     .getMtu());
708 
709             // CaptivePortalApiUrl & CaptivePortalData will be preserved if the given uid holds the
710             // NETWORK_SETTINGS permission.
711             assertNotNull(lp.getCaptivePortalApiUrl());
712             assertNotNull(lp.getCaptivePortalData());
713             assertEquals(lp.getCaptivePortalApiUrl(),
714                     mCm.getRedactedLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
715                             .getCaptivePortalApiUrl());
716             assertEquals(lp.getCaptivePortalData(),
717                     mCm.getRedactedLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
718                             .getCaptivePortalData());
719         });
720     }
721 
redactNc(@onNull final NetworkCapabilities nc, int uid, @NonNull String packageName)722     private NetworkCapabilities redactNc(@NonNull final NetworkCapabilities nc, int uid,
723             @NonNull String packageName) {
724         return mCm.getRedactedNetworkCapabilitiesForPackage(nc, uid, packageName);
725     }
726 
727     @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
728     @AppModeFull(reason = "Cannot get installed packages in instant app mode")
729     @Test
testGetRedactedNetworkCapabilitiesForPackage()730     public void testGetRedactedNetworkCapabilitiesForPackage() throws Exception {
731         final String groundedPkg = findPackageByPermissions(
732                 List.of(), /* requiredPermissions */
733                 List.of(ACCESS_NETWORK_STATE) /* forbiddenPermissions */);
734         assertNotNull("Couldn't find any package without ACCESS_NETWORK_STATE", groundedPkg);
735         final int groundedUid = mPackageManager.getPackageUid(groundedPkg, 0 /* flags */);
736 
737         // A package which doesn't have any of the permissions below, but has NETWORK_STATE.
738         // There should be a number of packages like this on the device; AOSP has many,
739         // including contacts, webview, the keyboard, pacprocessor, messaging.
740         final String normalPkg = findPackageByPermissions(
741                 List.of(ACCESS_NETWORK_STATE) /* requiredPermissions */,
742                 List.of(NETWORK_SETTINGS, NETWORK_FACTORY, NETWORK_SETUP_WIZARD,
743                         NETWORK_STACK, PERMISSION_MAINLINE_NETWORK_STACK,
744                         ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION) /* forbiddenPermissions */);
745         assertNotNull("Can't find a package with ACCESS_NETWORK_STATE but without any of"
746                 + " the forbidden permissions", normalPkg);
747         final int normalUid = mPackageManager.getPackageUid(normalPkg, 0 /* flags */);
748 
749         // There are some privileged packages on the system, like the phone process, the network
750         // stack and the system server.
751         final String privilegedPkg = findPackageByPermissions(
752                 List.of(ACCESS_NETWORK_STATE, NETWORK_SETTINGS, NETWORK_FACTORY,
753                         ACCESS_FINE_LOCATION), /* requiredPermissions */
754                 List.of() /* forbiddenPermissions */);
755         assertNotNull("Couldn't find a package with sufficient permissions", privilegedPkg);
756         final int privilegedUid = mPackageManager.getPackageUid(privilegedPkg, 0);
757 
758         final Set<Range<Integer>> uids = new ArraySet<>();
759         uids.add(new Range<>(10000, 10100));
760         uids.add(new Range<>(10200, 10300));
761         final String ssid = "My-WiFi";
762         // This test will set underlying networks in the capabilities to redact to see if they
763         // are appropriately redacted, so fetch the default network to put in there as an example.
764         final Network defaultNetwork = mCm.getActiveNetwork();
765         assertNotNull("CTS requires a working Internet connection", defaultNetwork);
766         final int subId1 = 1;
767         final int subId2 = 2;
768         final int[] administratorUids = {normalUid};
769         final String bssid = "location sensitive";
770         final int rssi = 43; // not location sensitive
771         final WifiInfo wifiInfo = new WifiInfo.Builder()
772                 .setBssid(bssid)
773                 .setRssi(rssi)
774                 .build();
775         final NetworkCapabilities nc = new NetworkCapabilities.Builder()
776                 .setUids(uids)
777                 .setSsid(ssid)
778                 .setUnderlyingNetworks(List.of(defaultNetwork))
779                 .setSubscriptionIds(Set.of(subId1, subId2))
780                 .setAdministratorUids(administratorUids)
781                 .setOwnerUid(normalUid)
782                 .setTransportInfo(wifiInfo)
783                 .build();
784 
785         // No matter what the given uid is, a SecurityException will be thrown if the caller
786         // doesn't hold the NETWORK_SETTINGS permission.
787         assertThrows(SecurityException.class, () -> redactNc(nc, groundedUid, groundedPkg));
788         assertThrows(SecurityException.class, () -> redactNc(nc, normalUid, normalPkg));
789         assertThrows(SecurityException.class, () -> redactNc(nc, privilegedUid, privilegedPkg));
790 
791         runAsShell(NETWORK_SETTINGS, () -> {
792             // Make sure that the NC is null if the package doesn't hold ACCESS_NETWORK_STATE.
793             assertNull(redactNc(nc, groundedUid, groundedPkg));
794 
795             // Uids, ssid, underlying networks & subscriptionIds will be redacted if the given uid
796             // doesn't hold the associated permissions. The wifi transport info is also suitably
797             // redacted.
798             final NetworkCapabilities redactedNormal = redactNc(nc, normalUid, normalPkg);
799             assertNull(redactedNormal.getUids());
800             assertNull(redactedNormal.getSsid());
801             assertNull(redactedNormal.getUnderlyingNetworks());
802             assertEquals(0, redactedNormal.getSubscriptionIds().size());
803             assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS,
804                     ((WifiInfo) redactedNormal.getTransportInfo()).getBSSID());
805             assertEquals(rssi, ((WifiInfo) redactedNormal.getTransportInfo()).getRssi());
806 
807             // Uids, ssid, underlying networks & subscriptionIds will be preserved if the given uid
808             // holds the associated permissions.
809             final NetworkCapabilities redactedPrivileged =
810                     redactNc(nc, privilegedUid, privilegedPkg);
811             assertEquals(uids, redactedPrivileged.getUids());
812             assertEquals(ssid, redactedPrivileged.getSsid());
813             assertEquals(List.of(defaultNetwork), redactedPrivileged.getUnderlyingNetworks());
814             assertEquals(Set.of(subId1, subId2), redactedPrivileged.getSubscriptionIds());
815             assertEquals(bssid, ((WifiInfo) redactedPrivileged.getTransportInfo()).getBSSID());
816             assertEquals(rssi, ((WifiInfo) redactedPrivileged.getTransportInfo()).getRssi());
817 
818             // The owner uid is only preserved when the network is a VPN and the uid is the
819             // same as the owner uid.
820             nc.addTransportType(TRANSPORT_VPN);
821             assertEquals(normalUid, redactNc(nc, normalUid, normalPkg).getOwnerUid());
822             assertEquals(INVALID_UID, redactNc(nc, privilegedUid, privilegedPkg).getOwnerUid());
823             nc.removeTransportType(TRANSPORT_VPN);
824 
825             // If the given uid doesn't hold location permissions, the owner uid will be set to
826             // INVALID_UID even when sent to that UID (this avoids a wifi suggestor knowing where
827             // the device is by virtue of the device connecting to its own network).
828             assertEquals(INVALID_UID, redactNc(nc, normalUid, normalPkg).getOwnerUid());
829 
830             // If the given uid holds location permissions, the owner uid is preserved. This works
831             // because the shell holds ACCESS_FINE_LOCATION.
832             final int[] administratorUids2 = { privilegedUid };
833             nc.setAdministratorUids(administratorUids2);
834             nc.setOwnerUid(privilegedUid);
835             assertEquals(privilegedUid, redactNc(nc, privilegedUid, privilegedPkg).getOwnerUid());
836         });
837     }
838 
839     /**
840      * Tests that connections can be opened on WiFi and cellphone networks,
841      * and that they are made from different IP addresses.
842      */
843     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
844     @Test
845     @RequiresDevice // Virtual devices use a single internet connection for all networks
testOpenConnection()846     public void testOpenConnection() throws Exception {
847         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
848         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
849 
850         Network wifiNetwork = mCtsNetUtils.connectToWifi();
851         Network cellNetwork = mCtsNetUtils.connectToCell();
852         // This server returns the requestor's IP address as the response body.
853         URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
854         String wifiAddressString = httpGet(wifiNetwork, url);
855         String cellAddressString = httpGet(cellNetwork, url);
856 
857         assertFalse(String.format("Same address '%s' on two different networks (%s, %s)",
858                 wifiAddressString, wifiNetwork, cellNetwork),
859                 wifiAddressString.equals(cellAddressString));
860 
861         // Verify that the IP addresses that the requests appeared to come from are actually on the
862         // respective networks.
863         assertOnNetwork(wifiAddressString, wifiNetwork);
864         assertOnNetwork(cellAddressString, cellNetwork);
865 
866         assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
867     }
868 
869     /**
870      * Performs a HTTP GET to the specified URL on the specified Network, and returns
871      * the response body decoded as UTF-8.
872      */
httpGet(Network network, URL httpUrl)873     private static String httpGet(Network network, URL httpUrl) throws IOException {
874         HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
875         try {
876             InputStream inputStream = connection.getInputStream();
877             return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
878         } finally {
879             connection.disconnect();
880         }
881     }
882 
assertOnNetwork(String adressString, Network network)883     private void assertOnNetwork(String adressString, Network network) throws UnknownHostException {
884         InetAddress address = InetAddress.getByName(adressString);
885         LinkProperties linkProperties = mCm.getLinkProperties(network);
886         // To make sure that the request went out on the right network, check that
887         // the IP address seen by the server is assigned to the expected network.
888         // We can only do this for IPv6 addresses, because in IPv4 we will likely
889         // have a private IPv4 address, and that won't match what the server sees.
890         if (address instanceof Inet6Address) {
891             assertContains(linkProperties.getAddresses(), address);
892         }
893     }
894 
assertContains(Collection<T> collection, T element)895     private static<T> void assertContains(Collection<T> collection, T element) {
896         assertTrue(element + " not found in " + collection, collection.contains(element));
897     }
898 
assertStartUsingNetworkFeatureUnsupported(int networkType, String feature)899     private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
900         try {
901             mCm.startUsingNetworkFeature(networkType, feature);
902             fail("startUsingNetworkFeature is no longer supported in the current API version");
903         } catch (UnsupportedOperationException expected) {}
904     }
905 
assertStopUsingNetworkFeatureUnsupported(int networkType, String feature)906     private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) {
907         try {
908             mCm.startUsingNetworkFeature(networkType, feature);
909             fail("stopUsingNetworkFeature is no longer supported in the current API version");
910         } catch (UnsupportedOperationException expected) {}
911     }
912 
assertRequestRouteToHostUnsupported(int networkType, int hostAddress)913     private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) {
914         try {
915             mCm.requestRouteToHost(networkType, hostAddress);
916             fail("requestRouteToHost is no longer supported in the current API version");
917         } catch (UnsupportedOperationException expected) {}
918     }
919 
920     @Test
testStartUsingNetworkFeature()921     public void testStartUsingNetworkFeature() {
922 
923         final String invalidateFeature = "invalidateFeature";
924         final String mmsFeature = "enableMMS";
925 
926         assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
927         assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
928         assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
929     }
930 
shouldEthernetBeSupported()931     private boolean shouldEthernetBeSupported() {
932         // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies.
933         // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on
934         // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or
935         // if the device can be a USB host and thus can use USB Ethernet adapters.
936         //
937         // Note that this test this will still fail in instant mode if a device supports Ethernet
938         // via other hardware means. We are not currently aware of any such device.
939         return hasEthernetService()
940                 || mPackageManager.hasSystemFeature(FEATURE_ETHERNET)
941                 || mPackageManager.hasSystemFeature(FEATURE_USB_HOST);
942     }
943 
hasEthernetService()944     private boolean hasEthernetService() {
945         // On Q creating EthernetManager from a thread that does not have a looper (like the test
946         // thread) crashes because it tried to use Looper.myLooper() through the default Handler
947         // constructor to run onAvailabilityChanged callbacks. Use ServiceManager to check whether
948         // the service exists instead.
949         // TODO: remove once Q is no longer supported in MTS, as ServiceManager is hidden API
950         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
951             return ServiceManager.getService(Context.ETHERNET_SERVICE) != null;
952         }
953         return mContext.getSystemService(Context.ETHERNET_SERVICE) != null;
954     }
955 
shouldBeSupported(int networkType)956     private boolean shouldBeSupported(int networkType) {
957         return mNetworkTypes.contains(networkType)
958             || (networkType == ConnectivityManager.TYPE_VPN)
959             || (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported());
960     }
961 
962     @Test
testIsNetworkSupported()963     public void testIsNetworkSupported() {
964         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
965             boolean supported = mCm.isNetworkSupported(type);
966             if (shouldBeSupported(type)) {
967                 assertTrue("Network type " + type + " should be supported", supported);
968             } else {
969                 assertFalse("Network type " + type + " should not be supported", supported);
970             }
971         }
972     }
973 
974     @Test
testRequestRouteToHost()975     public void testRequestRouteToHost() {
976         for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
977             assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
978         }
979     }
980 
981     @Test
testTest()982     public void testTest() {
983         mCm.getBackgroundDataSetting();
984     }
985 
makeDefaultRequest()986     private NetworkRequest makeDefaultRequest() {
987         // Make a request that is similar to the way framework tracks the system
988         // default network.
989         return new NetworkRequest.Builder()
990                 .clearCapabilities()
991                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
992                 .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
993                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
994                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
995                 .build();
996     }
997 
makeWifiNetworkRequest()998     private NetworkRequest makeWifiNetworkRequest() {
999         return new NetworkRequest.Builder()
1000                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
1001                 .addCapability(NET_CAPABILITY_INTERNET)
1002                 .build();
1003     }
1004 
makeCellNetworkRequest()1005     private NetworkRequest makeCellNetworkRequest() {
1006         return new NetworkRequest.Builder()
1007                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
1008                 .addCapability(NET_CAPABILITY_INTERNET)
1009                 .build();
1010     }
1011 
hasPrivateDnsValidated(CallbackEntry entry, Network networkForPrivateDns)1012     private boolean hasPrivateDnsValidated(CallbackEntry entry, Network networkForPrivateDns) {
1013         if (!networkForPrivateDns.equals(entry.getNetwork())) return false;
1014         final NetworkCapabilities nc = ((CallbackEntry.CapabilitiesChanged) entry).getCaps();
1015         return !nc.isPrivateDnsBroken() && nc.hasCapability(NET_CAPABILITY_VALIDATED);
1016     }
1017 
1018     @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
1019     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testIsPrivateDnsBroken()1020     public void testIsPrivateDnsBroken() throws InterruptedException {
1021         final String invalidPrivateDnsServer = "invalidhostname.example.com";
1022         final String goodPrivateDnsServer = "dns.google";
1023         mCtsNetUtils.storePrivateDnsSetting();
1024         final TestableNetworkCallback cb = new TestableNetworkCallback();
1025         registerNetworkCallback(makeWifiNetworkRequest(), cb);
1026         try {
1027             // Verifying the good private DNS sever
1028             mCtsNetUtils.setPrivateDnsStrictMode(goodPrivateDnsServer);
1029             final Network networkForPrivateDns =  mCtsNetUtils.ensureWifiConnected();
1030             cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
1031                     entry -> hasPrivateDnsValidated(entry, networkForPrivateDns));
1032 
1033             // Verifying the broken private DNS sever
1034             mCtsNetUtils.setPrivateDnsStrictMode(invalidPrivateDnsServer);
1035             cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
1036                     entry -> (((CallbackEntry.CapabilitiesChanged) entry).getCaps()
1037                     .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
1038         } finally {
1039             mCtsNetUtils.restorePrivateDnsSetting();
1040             // Toggle wifi to make sure it is re-validated
1041             reconnectWifi();
1042         }
1043     }
1044 
1045     /**
1046      * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
1047      * see if we get a callback for the TRANSPORT_WIFI transport type being available.
1048      *
1049      * <p>In order to test that a NetworkCallback occurs, we need some change in the network
1050      * state (either a transport or capability is now available). The most straightforward is
1051      * WiFi. We could add a version that uses the telephony data connection but it's not clear
1052      * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?).
1053      */
1054     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1055     @Test
testRegisterNetworkCallback()1056     public void testRegisterNetworkCallback() throws Exception {
1057         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1058 
1059         // We will register for a WIFI network being available or lost.
1060         final TestNetworkCallback callback = new TestNetworkCallback();
1061         registerNetworkCallback(makeWifiNetworkRequest(), callback);
1062 
1063         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
1064         registerDefaultNetworkCallback(defaultTrackingCallback);
1065 
1066         final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
1067         final TestNetworkCallback perUidCallback = new TestNetworkCallback();
1068         final TestNetworkCallback bestMatchingCallback = new TestNetworkCallback();
1069         final Handler h = new Handler(Looper.getMainLooper());
1070         if (TestUtils.shouldTestSApis()) {
1071             assertThrows(SecurityException.class, () ->
1072                     registerSystemDefaultNetworkCallback(systemDefaultCallback, h));
1073             runWithShellPermissionIdentity(() -> {
1074                 registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
1075                 registerDefaultNetworkCallbackForUid(Process.myUid(), perUidCallback, h);
1076             }, NETWORK_SETTINGS);
1077             registerBestMatchingNetworkCallback(makeDefaultRequest(), bestMatchingCallback, h);
1078         }
1079 
1080         Network wifiNetwork = null;
1081         mCtsNetUtils.ensureWifiConnected();
1082 
1083         // Now we should expect to get a network callback about availability of the wifi
1084         // network even if it was already connected as a state-based action when the callback
1085         // is registered.
1086         wifiNetwork = callback.waitForAvailable();
1087         assertNotNull("Did not receive onAvailable for TRANSPORT_WIFI request",
1088                 wifiNetwork);
1089 
1090         final Network defaultNetwork = defaultTrackingCallback.waitForAvailable();
1091         assertNotNull("Did not receive onAvailable on default network callback",
1092                 defaultNetwork);
1093 
1094         if (TestUtils.shouldTestSApis()) {
1095             assertNotNull("Did not receive onAvailable on system default network callback",
1096                     systemDefaultCallback.waitForAvailable());
1097             final Network perUidNetwork = perUidCallback.waitForAvailable();
1098             assertNotNull("Did not receive onAvailable on per-UID default network callback",
1099                     perUidNetwork);
1100             assertEquals(defaultNetwork, perUidNetwork);
1101             final Network bestMatchingNetwork = bestMatchingCallback.waitForAvailable();
1102             assertNotNull("Did not receive onAvailable on best matching network callback",
1103                     bestMatchingNetwork);
1104             assertEquals(defaultNetwork, bestMatchingNetwork);
1105         }
1106     }
1107 
1108     @ConnectivityModuleTest
1109     @IgnoreUpTo(Build.VERSION_CODES.R)
1110     @Test
testRegisterSystemDefaultNetworkCallbackPermission()1111     public void testRegisterSystemDefaultNetworkCallbackPermission() {
1112         final Handler h = new Handler(Looper.getMainLooper());
1113         // Verify registerSystemDefaultNetworkCallback can be accessed via
1114         // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
1115         runWithShellPermissionIdentity(() ->
1116                         registerSystemDefaultNetworkCallback(new TestNetworkCallback(), h),
1117                 CONNECTIVITY_USE_RESTRICTED_NETWORKS);
1118     }
1119 
1120     /**
1121      * Tests both registerNetworkCallback and unregisterNetworkCallback similarly to
1122      * {@link #testRegisterNetworkCallback} except that a {@code PendingIntent} is used instead
1123      * of a {@code NetworkCallback}.
1124      */
1125     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1126     @Test
testRegisterNetworkCallback_withPendingIntent()1127     public void testRegisterNetworkCallback_withPendingIntent() {
1128         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1129 
1130         // Create a ConnectivityActionReceiver that has an IntentFilter for our locally defined
1131         // action, NETWORK_CALLBACK_ACTION.
1132         final IntentFilter filter = new IntentFilter();
1133         filter.addAction(NETWORK_CALLBACK_ACTION);
1134 
1135         final ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
1136                 mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
1137         final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0;
1138         mContext.registerReceiver(receiver, filter, flags);
1139 
1140         // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
1141         final Intent intent = new Intent(NETWORK_CALLBACK_ACTION)
1142                 .setPackage(mContext.getPackageName());
1143         // While ConnectivityService would put extra info such as network or request id before
1144         // broadcasting the inner intent. The MUTABLE flag needs to be added accordingly.
1145         final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0 /*requestCode*/,
1146                 intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
1147 
1148         // We will register for a WIFI network being available or lost.
1149         mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
1150 
1151         try {
1152             mCtsNetUtils.ensureWifiConnected();
1153 
1154             // Now we expect to get the Intent delivered notifying of the availability of the wifi
1155             // network even if it was already connected as a state-based action when the callback
1156             // is registered.
1157             assertTrue("Did not receive expected Intent " + intent + " for TRANSPORT_WIFI",
1158                     receiver.waitForState());
1159         } catch (InterruptedException e) {
1160             fail("Broadcast receiver or NetworkCallback wait was interrupted.");
1161         } finally {
1162             mCm.unregisterNetworkCallback(pendingIntent);
1163             pendingIntent.cancel();
1164             mContext.unregisterReceiver(receiver);
1165         }
1166     }
1167 
runIdenticalPendingIntentsRequestTest(boolean useListen)1168     private void runIdenticalPendingIntentsRequestTest(boolean useListen) throws Exception {
1169         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1170 
1171         // Disconnect before registering callbacks, reconnect later to fire them
1172         mCtsNetUtils.ensureWifiDisconnected(null);
1173 
1174         final NetworkRequest firstRequest = makeWifiNetworkRequest();
1175         final NetworkRequest secondRequest = new NetworkRequest(firstRequest);
1176         // Will match wifi or test, since transports are ORed; but there should only be wifi
1177         secondRequest.networkCapabilities.addTransportType(TRANSPORT_TEST);
1178 
1179         PendingIntent firstIntent = null;
1180         PendingIntent secondIntent = null;
1181         BroadcastReceiver receiver = null;
1182 
1183         // Avoid receiving broadcasts from other runs by appending a timestamp
1184         final String broadcastAction = NETWORK_CALLBACK_ACTION + System.currentTimeMillis();
1185         try {
1186             // Intent is mutable to receive EXTRA_NETWORK_REQUEST from ConnectivityService
1187             final String extraBoolKey = "extra_bool";
1188             firstIntent = PendingIntent.getBroadcast(mContext,
1189                     0 /* requestCode */,
1190                     new Intent(broadcastAction).putExtra(extraBoolKey, false)
1191                             .setPackage(mContext.getPackageName()),
1192                     PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
1193 
1194             if (useListen) {
1195                 mCm.registerNetworkCallback(firstRequest, firstIntent);
1196             } else {
1197                 mCm.requestNetwork(firstRequest, firstIntent);
1198             }
1199 
1200             // Second intent equals the first as per filterEquals (extras don't count), so first
1201             // intent will be updated with the new extras
1202             secondIntent = PendingIntent.getBroadcast(mContext,
1203                     0 /* requestCode */,
1204                     new Intent(broadcastAction).putExtra(extraBoolKey, true)
1205                             .setPackage(mContext.getPackageName()),
1206                     PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
1207 
1208             // Because secondIntent.intentFilterEquals the first, the request should be replaced
1209             if (useListen) {
1210                 mCm.registerNetworkCallback(secondRequest, secondIntent);
1211             } else {
1212                 mCm.requestNetwork(secondRequest, secondIntent);
1213             }
1214 
1215             final IntentFilter filter = new IntentFilter();
1216             filter.addAction(broadcastAction);
1217 
1218             final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
1219             final AtomicInteger receivedCount = new AtomicInteger(0);
1220             receiver = new BroadcastReceiver() {
1221                 @Override
1222                 public void onReceive(Context context, Intent intent) {
1223                     final NetworkRequest request = intent.getParcelableExtra(EXTRA_NETWORK_REQUEST);
1224                     assertPendingIntentRequestMatches(request, secondRequest, useListen);
1225                     receivedCount.incrementAndGet();
1226                     networkFuture.complete(intent.getParcelableExtra(EXTRA_NETWORK));
1227                 }
1228             };
1229             final int flags = SdkLevel.isAtLeastT() ? RECEIVER_EXPORTED : 0;
1230             mContext.registerReceiver(receiver, filter, flags);
1231 
1232             final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
1233             try {
1234                 assertEquals(wifiNetwork, networkFuture.get(
1235                         NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS));
1236             } catch (TimeoutException e) {
1237                 throw new AssertionError("PendingIntent not received for " + secondRequest, e);
1238             }
1239 
1240             // Sleep for a small amount of time to try to check that only one callback is ever
1241             // received (so the first callback was really unregistered). This does not guarantee
1242             // that the test will fail if it runs very slowly, but it should at least be very
1243             // noticeably flaky.
1244             Thread.sleep(NO_CALLBACK_TIMEOUT_MS);
1245 
1246             // For R- frameworks, listens will receive duplicated callbacks. See b/189868426.
1247             if (isAtLeastS() || !useListen) {
1248                 assertEquals("PendingIntent should only be received once", 1, receivedCount.get());
1249             }
1250         } finally {
1251             if (firstIntent != null) mCm.unregisterNetworkCallback(firstIntent);
1252             if (secondIntent != null) mCm.unregisterNetworkCallback(secondIntent);
1253             if (receiver != null) mContext.unregisterReceiver(receiver);
1254             mCtsNetUtils.ensureWifiConnected();
1255         }
1256     }
1257 
assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed, boolean useListen)1258     private void assertPendingIntentRequestMatches(NetworkRequest broadcasted, NetworkRequest filed,
1259             boolean useListen) {
1260         assertArrayEquals(filed.networkCapabilities.getCapabilities(),
1261                 broadcasted.networkCapabilities.getCapabilities());
1262         // For R- frameworks, listens will receive duplicated callbacks. See b/189868426.
1263         if (!isAtLeastS() && useListen) return;
1264         assertArrayEquals(filed.networkCapabilities.getTransportTypes(),
1265                 broadcasted.networkCapabilities.getTransportTypes());
1266     }
1267 
1268     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1269     @Test
testRegisterNetworkRequest_identicalPendingIntents()1270     public void testRegisterNetworkRequest_identicalPendingIntents() throws Exception {
1271         runIdenticalPendingIntentsRequestTest(false /* useListen */);
1272     }
1273 
1274     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1275     @Test
testRegisterNetworkCallback_identicalPendingIntents()1276     public void testRegisterNetworkCallback_identicalPendingIntents() throws Exception {
1277         runIdenticalPendingIntentsRequestTest(true /* useListen */);
1278     }
1279 
1280     /**
1281      * Exercises the requestNetwork with NetworkCallback API. This checks to
1282      * see if we get a callback for an INTERNET request.
1283      */
1284     @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
1285     @Test
testRequestNetworkCallback()1286     public void testRequestNetworkCallback() throws Exception {
1287         final TestNetworkCallback callback = new TestNetworkCallback();
1288         requestNetwork(new NetworkRequest.Builder()
1289                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
1290                 .build(), callback);
1291 
1292         // Wait to get callback for availability of internet
1293         Network internetNetwork = callback.waitForAvailable();
1294         assertNotNull("Did not receive NetworkCallback#onAvailable for INTERNET", internetNetwork);
1295     }
1296 
1297     /**
1298      * Exercises the requestNetwork with NetworkCallback API with timeout - expected to
1299      * fail. Use WIFI and switch Wi-Fi off.
1300      */
1301     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1302     @Test
testRequestNetworkCallback_onUnavailable()1303     public void testRequestNetworkCallback_onUnavailable() {
1304         final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
1305         if (previousWifiEnabledState) {
1306             mCtsNetUtils.ensureWifiDisconnected(null);
1307         }
1308 
1309         final TestNetworkCallback callback = new TestNetworkCallback();
1310         requestNetwork(new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(),
1311                 callback, 100);
1312 
1313         try {
1314             // Wait to get callback for unavailability of requested network
1315             assertTrue("Did not receive NetworkCallback#onUnavailable",
1316                     callback.waitForUnavailable());
1317         } catch (InterruptedException e) {
1318             fail("NetworkCallback wait was interrupted.");
1319         } finally {
1320             if (previousWifiEnabledState) {
1321                 mCtsNetUtils.connectToWifi();
1322             }
1323         }
1324     }
1325 
getFirstV4Address(Network network)1326     private InetAddress getFirstV4Address(Network network) {
1327         LinkProperties linkProperties = mCm.getLinkProperties(network);
1328         for (InetAddress address : linkProperties.getAddresses()) {
1329             if (address instanceof Inet4Address) {
1330                 return address;
1331             }
1332         }
1333         return null;
1334     }
1335 
1336     /**
1337      * Checks that enabling/disabling wifi causes CONNECTIVITY_ACTION broadcasts.
1338      */
1339     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1340     @Test
testToggleWifiConnectivityAction()1341     public void testToggleWifiConnectivityAction() throws Exception {
1342         // toggleWifi calls connectToWifi and disconnectFromWifi, which both wait for
1343         // CONNECTIVITY_ACTION broadcasts.
1344         mCtsNetUtils.toggleWifi();
1345     }
1346 
1347     /** Verify restricted networks cannot be requested. */
1348     @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
1349     @Test
testRestrictedNetworks()1350     public void testRestrictedNetworks() {
1351         // Verify we can request unrestricted networks:
1352         NetworkRequest request = new NetworkRequest.Builder()
1353                 .addCapability(NET_CAPABILITY_INTERNET).build();
1354         NetworkCallback callback = new NetworkCallback();
1355         mCm.requestNetwork(request, callback);
1356         mCm.unregisterNetworkCallback(callback);
1357         // Verify we cannot request restricted networks:
1358         request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build();
1359         callback = new NetworkCallback();
1360         try {
1361             mCm.requestNetwork(request, callback);
1362             fail("No exception thrown when restricted network requested.");
1363         } catch (SecurityException expected) {}
1364     }
1365 
1366     // Returns "true", "false" or "none"
getWifiMeteredStatus(String ssid)1367     private String getWifiMeteredStatus(String ssid) throws Exception {
1368         // Interestingly giving the SSID as an argument to list wifi-networks
1369         // only works iff the network in question has the "false" policy.
1370         // Also unfortunately runShellCommand does not pass the command to the interpreter
1371         // so it's not possible to | grep the ssid.
1372         final String command = "cmd netpolicy list wifi-networks";
1373         final String policyString = runShellCommand(mInstrumentation, command);
1374 
1375         final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
1376                 Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
1377         if (!m.find()) {
1378             fail("Unexpected format from cmd netpolicy, policyString = " + policyString);
1379         }
1380         return m.group(1);
1381     }
1382 
1383     // metered should be "true", "false" or "none"
setWifiMeteredStatus(String ssid, String metered)1384     private void setWifiMeteredStatus(String ssid, String metered) throws Exception {
1385         final String setCommand = "cmd netpolicy set metered-network " + ssid + " " + metered;
1386         runShellCommand(mInstrumentation, setCommand);
1387         assertEquals(getWifiMeteredStatus(ssid), metered);
1388     }
1389 
unquoteSSID(String ssid)1390     private String unquoteSSID(String ssid) {
1391         // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
1392         // Otherwise it's guaranteed not to start with a quote.
1393         if (ssid.charAt(0) == '"') {
1394             return ssid.substring(1, ssid.length() - 1);
1395         } else {
1396             return ssid;
1397         }
1398     }
1399 
waitForActiveNetworkMetered(final int targetTransportType, final boolean requestedMeteredness, final boolean waitForValidation, final boolean useSystemDefault)1400     private Network waitForActiveNetworkMetered(final int targetTransportType,
1401             final boolean requestedMeteredness, final boolean waitForValidation,
1402             final boolean useSystemDefault)
1403             throws Exception {
1404         final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
1405         final NetworkCallback networkCallback = new NetworkCallback() {
1406             @Override
1407             public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
1408                 if (!nc.hasTransport(targetTransportType)) return;
1409 
1410                 final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
1411                 final boolean validated = nc.hasCapability(NET_CAPABILITY_VALIDATED);
1412                 if (metered == requestedMeteredness && (!waitForValidation || validated)) {
1413                     networkFuture.complete(network);
1414                 }
1415             }
1416         };
1417 
1418         try {
1419             // Registering a callback here guarantees onCapabilitiesChanged is called immediately
1420             // with the current setting. Therefore, if the setting has already been changed,
1421             // this method will return right away, and if not, it'll wait for the setting to change.
1422             if (useSystemDefault) {
1423                 runWithShellPermissionIdentity(() ->
1424                                 registerSystemDefaultNetworkCallback(networkCallback,
1425                                         new Handler(Looper.getMainLooper())),
1426                         NETWORK_SETTINGS);
1427             } else {
1428                 registerDefaultNetworkCallback(networkCallback);
1429             }
1430 
1431             // Changing meteredness on wifi involves reconnecting, which can take several seconds
1432             // (involves re-associating, DHCP...).
1433             return networkFuture.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
1434         } catch (TimeoutException e) {
1435             throw new AssertionError("Timed out waiting for active network metered status to "
1436                     + "change to " + requestedMeteredness + " ; network = "
1437                     + mCm.getActiveNetwork(), e);
1438         }
1439     }
1440 
setWifiMeteredStatusAndWait(String ssid, boolean isMetered, boolean waitForValidation)1441     private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered,
1442             boolean waitForValidation) throws Exception {
1443         setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
1444         mCtsNetUtils.ensureWifiConnected();
1445         return waitForActiveNetworkMetered(TRANSPORT_WIFI,
1446                 isMetered /* requestedMeteredness */,
1447                 waitForValidation,
1448                 true /* useSystemDefault */);
1449     }
1450 
assertMultipathPreferenceIsEventually(Network network, int oldValue, int expectedValue)1451     private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
1452             int expectedValue) {
1453         // Quick check : if oldValue == expectedValue, there is no way to guarantee the test
1454         // is not flaky.
1455         assertNotSame(oldValue, expectedValue);
1456 
1457         for (int i = 0; i < NUM_TRIES_MULTIPATH_PREF_CHECK; ++i) {
1458             final int actualValue = mCm.getMultipathPreference(network);
1459             if (actualValue == expectedValue) {
1460                 return;
1461             }
1462             if (actualValue != oldValue) {
1463                 fail("Multipath preference is neither previous (" + oldValue
1464                         + ") nor expected (" + expectedValue + ")");
1465             }
1466             SystemClock.sleep(INTERVAL_MULTIPATH_PREF_CHECK_MS);
1467         }
1468         fail("Timed out waiting for multipath preference to change. expected = "
1469                 + expectedValue + " ; actual = " + mCm.getMultipathPreference(network));
1470     }
1471 
getCurrentMeteredMultipathPreference(ContentResolver resolver)1472     private int getCurrentMeteredMultipathPreference(ContentResolver resolver) {
1473         final String rawMeteredPref = Settings.Global.getString(resolver,
1474                 NETWORK_METERED_MULTIPATH_PREFERENCE);
1475         return TextUtils.isEmpty(rawMeteredPref)
1476             ? getIntResourceForName(NETWORK_METERED_MULTIPATH_PREFERENCE_RES_NAME)
1477             : Integer.parseInt(rawMeteredPref);
1478     }
1479 
findNextPrefValue(ContentResolver resolver)1480     private int findNextPrefValue(ContentResolver resolver) {
1481         // A bit of a nuclear hammer, but race conditions in CTS are bad. To be able to
1482         // detect a correct setting value without race conditions, the next pref must
1483         // be a valid value (range 0..3) that is different from the old setting of the
1484         // metered preference and from the unmetered preference.
1485         final int meteredPref = getCurrentMeteredMultipathPreference(resolver);
1486         final int unmeteredPref = ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
1487         if (0 != meteredPref && 0 != unmeteredPref) return 0;
1488         if (1 != meteredPref && 1 != unmeteredPref) return 1;
1489         return 2;
1490     }
1491 
1492     /**
1493      * Verify that getMultipathPreference does return appropriate values
1494      * for metered and unmetered networks.
1495      */
1496     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1497     @Test
testGetMultipathPreference()1498     public void testGetMultipathPreference() throws Exception {
1499         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1500         final ContentResolver resolver = mContext.getContentResolver();
1501         mCtsNetUtils.ensureWifiConnected();
1502         final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID());
1503         final String oldMeteredSetting = getWifiMeteredStatus(ssid);
1504         final String oldMeteredMultipathPreference = Settings.Global.getString(
1505                 resolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
1506         try {
1507             final int initialMeteredPreference = getCurrentMeteredMultipathPreference(resolver);
1508             int newMeteredPreference = findNextPrefValue(resolver);
1509             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
1510                     Integer.toString(newMeteredPreference));
1511             // Wifi meteredness changes from unmetered to metered will disconnect and reconnect
1512             // since R.
1513             final Network network = setWifiMeteredStatusAndWait(ssid, true /* isMetered */,
1514                     false /* waitForValidation */);
1515             assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
1516             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
1517                     NET_CAPABILITY_NOT_METERED), false);
1518             assertMultipathPreferenceIsEventually(network, initialMeteredPreference,
1519                     newMeteredPreference);
1520 
1521             final int oldMeteredPreference = newMeteredPreference;
1522             newMeteredPreference = findNextPrefValue(resolver);
1523             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
1524                     Integer.toString(newMeteredPreference));
1525             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
1526                     NET_CAPABILITY_NOT_METERED), false);
1527             assertMultipathPreferenceIsEventually(network,
1528                     oldMeteredPreference, newMeteredPreference);
1529 
1530             // No disconnect from unmetered to metered.
1531             setWifiMeteredStatusAndWait(ssid, false /* isMetered */, false /* waitForValidation */);
1532             assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
1533                     NET_CAPABILITY_NOT_METERED), true);
1534             assertMultipathPreferenceIsEventually(network, newMeteredPreference,
1535                     ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED);
1536         } finally {
1537             Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
1538                     oldMeteredMultipathPreference);
1539             setWifiMeteredStatus(ssid, oldMeteredSetting);
1540         }
1541     }
1542 
1543     // TODO: move the following socket keep alive test to dedicated test class.
1544     /**
1545      * Callback used in tcp keepalive offload that allows caller to wait callback fires.
1546      */
1547     private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
1548         public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
1549 
1550         public static class CallbackValue {
1551             public final CallbackType callbackType;
1552             public final int error;
1553 
CallbackValue(final CallbackType type, final int error)1554             private CallbackValue(final CallbackType type, final int error) {
1555                 this.callbackType = type;
1556                 this.error = error;
1557             }
1558 
1559             public static class OnStartedCallback extends CallbackValue {
OnStartedCallback()1560                 OnStartedCallback() { super(CallbackType.ON_STARTED, 0); }
1561             }
1562 
1563             public static class OnStoppedCallback extends CallbackValue {
OnStoppedCallback()1564                 OnStoppedCallback() { super(CallbackType.ON_STOPPED, 0); }
1565             }
1566 
1567             public static class OnErrorCallback extends CallbackValue {
OnErrorCallback(final int error)1568                 OnErrorCallback(final int error) { super(CallbackType.ON_ERROR, error); }
1569             }
1570 
1571             @Override
equals(Object o)1572             public boolean equals(Object o) {
1573                 return o.getClass() == this.getClass()
1574                         && this.callbackType == ((CallbackValue) o).callbackType
1575                         && this.error == ((CallbackValue) o).error;
1576             }
1577 
1578             @Override
toString()1579             public String toString() {
1580                 return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
1581             }
1582         }
1583 
1584         private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
1585 
1586         @Override
onStarted()1587         public void onStarted() {
1588             mCallbacks.add(new CallbackValue.OnStartedCallback());
1589         }
1590 
1591         @Override
onStopped()1592         public void onStopped() {
1593             mCallbacks.add(new CallbackValue.OnStoppedCallback());
1594         }
1595 
1596         @Override
onError(final int error)1597         public void onError(final int error) {
1598             mCallbacks.add(new CallbackValue.OnErrorCallback(error));
1599         }
1600 
pollCallback()1601         public CallbackValue pollCallback() {
1602             try {
1603                 return mCallbacks.poll(KEEPALIVE_CALLBACK_TIMEOUT_MS,
1604                         TimeUnit.MILLISECONDS);
1605             } catch (InterruptedException e) {
1606                 fail("Callback not seen after " + KEEPALIVE_CALLBACK_TIMEOUT_MS + " ms");
1607             }
1608             return null;
1609         }
expectCallback(CallbackValue expectedCallback)1610         private void expectCallback(CallbackValue expectedCallback) {
1611             final CallbackValue actualCallback = pollCallback();
1612             assertEquals(expectedCallback, actualCallback);
1613         }
1614 
expectStarted()1615         public void expectStarted() {
1616             expectCallback(new CallbackValue.OnStartedCallback());
1617         }
1618 
expectStopped()1619         public void expectStopped() {
1620             expectCallback(new CallbackValue.OnStoppedCallback());
1621         }
1622 
expectError(int error)1623         public void expectError(int error) {
1624             expectCallback(new CallbackValue.OnErrorCallback(error));
1625         }
1626     }
1627 
getAddrByName(final String hostname, final int family)1628     private InetAddress getAddrByName(final String hostname, final int family) throws Exception {
1629         final InetAddress[] allAddrs = InetAddress.getAllByName(hostname);
1630         for (InetAddress addr : allAddrs) {
1631             if (family == AF_INET && addr instanceof Inet4Address) return addr;
1632 
1633             if (family == AF_INET6 && addr instanceof Inet6Address) return addr;
1634 
1635             if (family == AF_UNSPEC) return addr;
1636         }
1637         return null;
1638     }
1639 
getConnectedSocket(final Network network, final String host, final int port, final int family)1640     private Socket getConnectedSocket(final Network network, final String host, final int port,
1641             final int family) throws Exception {
1642         final Socket s = network.getSocketFactory().createSocket();
1643         try {
1644             final InetAddress addr = getAddrByName(host, family);
1645             if (addr == null) fail("Fail to get destination address for " + family);
1646 
1647             final InetSocketAddress sockAddr = new InetSocketAddress(addr, port);
1648             s.connect(sockAddr);
1649         } catch (Exception e) {
1650             s.close();
1651             throw e;
1652         }
1653         return s;
1654     }
1655 
getSupportedKeepalivesForNet(@onNull Network network)1656     private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception {
1657         final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
1658 
1659         // Get number of supported concurrent keepalives for testing network.
1660         final int[] keepalivesPerTransport = runAsShell(NETWORK_SETTINGS,
1661                 () -> mCm.getSupportedKeepalives());
1662         return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
1663                 keepalivesPerTransport, nc);
1664     }
1665 
isTcpKeepaliveSupportedByKernel()1666     private static boolean isTcpKeepaliveSupportedByKernel() {
1667         final String kVersionString = VintfRuntimeInfo.getKernelVersion();
1668         return DeviceInfoUtils.compareMajorMinorVersion(kVersionString, "4.8") >= 0;
1669     }
1670 
1671     /**
1672      * Verifies that the keepalive API cannot create any keepalive when the maximum number of
1673      * keepalives is set to 0.
1674      */
1675     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1676     // getSupportedKeepalives is available in updatable ConnectivityManager (S+)
1677     // Also, this feature is not mainlined before S, and it's fine to skip on R- devices.
1678     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
1679     @Test
testKeepaliveWifiUnsupported()1680     public void testKeepaliveWifiUnsupported() throws Exception {
1681         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1682 
1683         final Network network = mCtsNetUtils.ensureWifiConnected();
1684         if (getSupportedKeepalivesForNet(network) != 0) return;
1685         final InetAddress srcAddr = getFirstV4Address(network);
1686         assumeTrue("This test requires native IPv4", srcAddr != null);
1687 
1688         runWithShellPermissionIdentity(() -> {
1689             assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0));
1690             assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
1691         });
1692     }
1693 
1694     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1695     // getSupportedKeepalives is available in updatable ConnectivityManager (S+)
1696     // Also, this feature is not mainlined before S, and it's fine to skip on R- devices.
1697     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
1698     @Test
1699     @RequiresDevice // Keepalive is not supported on virtual hardware
testCreateTcpKeepalive()1700     public void testCreateTcpKeepalive() throws Exception {
1701         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1702 
1703         final Network network = mCtsNetUtils.ensureWifiConnected();
1704         if (getSupportedKeepalivesForNet(network) == 0) return;
1705         final InetAddress srcAddr = getFirstV4Address(network);
1706         assumeTrue("This test requires native IPv4", srcAddr != null);
1707 
1708         // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
1709         // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive
1710         // needs to be supported except if the kernel doesn't support it.
1711         if (!isTcpKeepaliveSupportedByKernel()) {
1712             // Verify that the callback result is expected.
1713             runWithShellPermissionIdentity(() -> {
1714                 assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
1715             });
1716             Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel "
1717                     + VintfRuntimeInfo.getKernelVersion());
1718             return;
1719         }
1720 
1721         final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8");
1722         // So far only ipv4 tcp keepalive offload is supported.
1723         // TODO: add test case for ipv6 tcp keepalive offload when it is supported.
1724         try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, AF_INET)) {
1725 
1726             // Should able to start keep alive offload when socket is idle.
1727             final Executor executor = mContext.getMainExecutor();
1728             final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
1729 
1730             mUiAutomation.adoptShellPermissionIdentity();
1731             try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
1732                 sk.start(MIN_KEEPALIVE_INTERVAL);
1733                 callback.expectStarted();
1734 
1735                 // App should not able to write during keepalive offload.
1736                 final OutputStream out = s.getOutputStream();
1737                 try {
1738                     out.write(requestBytes);
1739                     fail("Should not able to write");
1740                 } catch (IOException e) { }
1741                 // App should not able to read during keepalive offload.
1742                 final InputStream in = s.getInputStream();
1743                 byte[] responseBytes = new byte[4096];
1744                 try {
1745                     in.read(responseBytes);
1746                     fail("Should not able to read");
1747                 } catch (IOException e) { }
1748 
1749                 // Stop.
1750                 sk.stop();
1751                 callback.expectStopped();
1752             } finally {
1753                 mUiAutomation.dropShellPermissionIdentity();
1754             }
1755 
1756             // Ensure socket is still connected.
1757             assertTrue(s.isConnected());
1758             assertFalse(s.isClosed());
1759 
1760             // Let socket be not idle.
1761             try {
1762                 final OutputStream out = s.getOutputStream();
1763                 out.write(requestBytes);
1764             } catch (IOException e) {
1765                 fail("Failed to write data " + e);
1766             }
1767             // Make sure response data arrives.
1768             final MessageQueue fdHandlerQueue = Looper.getMainLooper().getQueue();
1769             final FileDescriptor fd = s.getFileDescriptor$();
1770             final CountDownLatch mOnReceiveLatch = new CountDownLatch(1);
1771             fdHandlerQueue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, (readyFd, events) -> {
1772                 mOnReceiveLatch.countDown();
1773                 return 0; // Unregister listener.
1774             });
1775             if (!mOnReceiveLatch.await(2, TimeUnit.SECONDS)) {
1776                 fdHandlerQueue.removeOnFileDescriptorEventListener(fd);
1777                 fail("Timeout: no response data");
1778             }
1779 
1780             // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue
1781             // that has not been read.
1782             mUiAutomation.adoptShellPermissionIdentity();
1783             try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) {
1784                 sk.start(MIN_KEEPALIVE_INTERVAL);
1785                 callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE);
1786             } finally {
1787                 mUiAutomation.dropShellPermissionIdentity();
1788             }
1789         }
1790     }
1791 
createConcurrentKeepalivesOfType( int requestCount, @NonNull TestSocketKeepaliveCallback callback, Supplier<SocketKeepalive> kaFactory)1792     private ArrayList<SocketKeepalive> createConcurrentKeepalivesOfType(
1793             int requestCount, @NonNull TestSocketKeepaliveCallback callback,
1794             Supplier<SocketKeepalive> kaFactory) {
1795         final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
1796 
1797         int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT;
1798 
1799         // Test concurrent keepalives with the given supplier.
1800         while (kalist.size() < requestCount) {
1801             final SocketKeepalive ka = kaFactory.get();
1802             ka.start(MIN_KEEPALIVE_INTERVAL);
1803             TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback();
1804             assertNotNull(cv);
1805             if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) {
1806                 if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) {
1807                     // Unsupported.
1808                     break;
1809                 } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) {
1810                     // Limit reached or temporary unavailable due to stopped slot is not yet
1811                     // released.
1812                     if (remainingRetries > 0) {
1813                         SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS);
1814                         remainingRetries--;
1815                         continue;
1816                     }
1817                     break;
1818                 }
1819             }
1820             if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) {
1821                 kalist.add(ka);
1822             } else {
1823                 fail("Unexpected error when creating " + (kalist.size() + 1) + " "
1824                         + ka.getClass().getSimpleName() + ": " + cv);
1825             }
1826         }
1827 
1828         return kalist;
1829     }
1830 
createConcurrentNattSocketKeepalives( @onNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1831     private @NonNull ArrayList<SocketKeepalive> createConcurrentNattSocketKeepalives(
1832             @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount,
1833             @NonNull TestSocketKeepaliveCallback callback)  throws Exception {
1834 
1835         final Executor executor = mContext.getMainExecutor();
1836 
1837         // Initialize a real NaT-T socket.
1838         final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
1839         final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket();
1840         final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET);
1841         assertNotNull(srcAddr);
1842         assertNotNull(dstAddr);
1843 
1844         // Test concurrent Nat-T keepalives.
1845         final ArrayList<SocketKeepalive> result = createConcurrentKeepalivesOfType(requestCount,
1846                 callback, () -> mCm.createSocketKeepalive(network, nattSocket,
1847                         srcAddr, dstAddr, executor, callback));
1848 
1849         nattSocket.close();
1850         return result;
1851     }
1852 
createConcurrentTcpSocketKeepalives( @onNull Network network, int requestCount, @NonNull TestSocketKeepaliveCallback callback)1853     private @NonNull ArrayList<SocketKeepalive> createConcurrentTcpSocketKeepalives(
1854             @NonNull Network network, int requestCount,
1855             @NonNull TestSocketKeepaliveCallback callback) {
1856         final Executor executor = mContext.getMainExecutor();
1857 
1858         // Create concurrent TCP keepalives.
1859         return createConcurrentKeepalivesOfType(requestCount, callback, () -> {
1860             // Assert that TCP connections can be established. The file descriptor of tcp
1861             // sockets will be duplicated and kept valid in service side if the keepalives are
1862             // successfully started.
1863             try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
1864                     AF_INET)) {
1865                 return mCm.createSocketKeepalive(network, tcpSocket, executor, callback);
1866             } catch (Exception e) {
1867                 fail("Unexpected error when creating TCP socket: " + e);
1868             }
1869             return null;
1870         });
1871     }
1872 
1873     /**
1874      * Creates concurrent keepalives until the specified counts of each type of keepalives are
1875      * reached or the expected error callbacks are received for each type of keepalives.
1876      *
1877      * @return the total number of keepalives created.
1878      */
1879     private int createConcurrentSocketKeepalives(
1880             @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount)
1881             throws Exception {
1882         final ArrayList<SocketKeepalive> kalist = new ArrayList<>();
1883         final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
1884 
1885         kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback));
1886         kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback));
1887 
1888         final int ret = kalist.size();
1889 
1890         // Clean up.
1891         for (final SocketKeepalive ka : kalist) {
1892             ka.stop();
1893             callback.expectStopped();
1894         }
1895         kalist.clear();
1896 
1897         return ret;
1898     }
1899 
1900     /**
1901      * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't
1902      * get leaked after iterations.
1903      */
1904     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
1905     @Test
1906     // getSupportedKeepalives is available in updatable ConnectivityManager (S+)
1907     // Also, this feature is not mainlined before S, and it's fine to skip on R- devices.
1908     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
1909     @RequiresDevice // Keepalive is not supported on virtual hardware
1910     public void testSocketKeepaliveLimitWifi() throws Exception {
1911         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
1912 
1913         final Network network = mCtsNetUtils.ensureWifiConnected();
1914         final int supported = getSupportedKeepalivesForNet(network);
1915         if (supported == 0) {
1916             return;
1917         }
1918         final InetAddress srcAddr = getFirstV4Address(network);
1919         assumeTrue("This test requires native IPv4", srcAddr != null);
1920 
1921         runWithShellPermissionIdentity(() -> {
1922             // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT.
1923             assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT);
1924 
1925             // Verifies that Nat-T keepalives can be established.
1926             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1927                     supported + 1, 0));
1928             // Verifies that keepalives don't get leaked in second round.
1929             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported,
1930                     0));
1931         });
1932 
1933         // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support
1934         // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel.
1935         if (!isTcpKeepaliveSupportedByKernel()) return;
1936 
1937         runWithShellPermissionIdentity(() -> {
1938             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
1939                     supported + 1));
1940 
1941             // Verifies that different types can be established at the same time.
1942             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1943                     supported / 2, supported - supported / 2));
1944 
1945             // Verifies that keepalives don't get leaked in second round.
1946             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0,
1947                     supported));
1948             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1949                     supported / 2, supported - supported / 2));
1950         });
1951     }
1952 
1953     /**
1954      * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and
1955      * don't get leaked after iterations.
1956      */
1957     @AppModeFull(reason = "Cannot request network in instant app mode")
1958     @Test
1959     // getSupportedKeepalives is available in updatable ConnectivityManager (S+)
1960     // Also, this feature is not mainlined before S, and it's fine to skip on R- devices.
1961     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
1962     @RequiresDevice // Keepalive is not supported on virtual hardware
1963     public void testSocketKeepaliveLimitTelephony() throws Exception {
1964         if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
1965             Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device"
1966                     + " supports telephony");
1967             return;
1968         }
1969 
1970         final int firstSdk = SdkLevel.isAtLeastS()
1971                 ? Build.VERSION.DEVICE_INITIAL_SDK_INT
1972                 // FIRST_SDK_INT was a @TestApi field renamed to DEVICE_INITIAL_SDK_INT in S
1973                 : Build.VERSION.class.getField("FIRST_SDK_INT").getInt(null);
1974         if (firstSdk < Build.VERSION_CODES.Q) {
1975             Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching"
1976                     + " before Q: " + firstSdk);
1977             return;
1978         }
1979 
1980         final Network network = mCtsNetUtils.connectToCell();
1981         final int supported = getSupportedKeepalivesForNet(network);
1982         final InetAddress srcAddr = getFirstV4Address(network);
1983         assumeTrue("This test requires native IPv4", srcAddr != null);
1984 
1985         runWithShellPermissionIdentity(() -> {
1986             // Verifies that the supported keepalive slots meet minimum requirement.
1987             assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT);
1988             // Verifies that Nat-T keepalives can be established.
1989             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr,
1990                     supported + 1, 0));
1991             // Verifies that keepalives don't get leaked in second round.
1992             assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported,
1993                     0));
1994         });
1995     }
1996 
1997     private int getIntResourceForName(@NonNull String resName) {
1998         final Resources r = mContext.getResources();
1999         final int resId = r.getIdentifier(resName, "integer", "android");
2000         return r.getInteger(resId);
2001     }
2002 
2003     /**
2004      * Verifies that the keepalive slots are limited as customized for unprivileged requests.
2005      */
2006     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2007     @Test
2008     // getSupportedKeepalives is available in updatable ConnectivityManager (S+)
2009     // Also, this feature is not mainlined before S, and it's fine to skip on R- devices.
2010     @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) @ConnectivityModuleTest
2011     @RequiresDevice // Keepalive is not supported on virtual hardware
2012     public void testSocketKeepaliveUnprivileged() throws Exception {
2013         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
2014 
2015         final Network network = mCtsNetUtils.ensureWifiConnected();
2016         final int supported = getSupportedKeepalivesForNet(network);
2017         if (supported == 0) {
2018             return;
2019         }
2020         final InetAddress srcAddr = getFirstV4Address(network);
2021         assumeTrue("This test requires native IPv4", srcAddr != null);
2022 
2023         // Resource ID might be shifted on devices that compiled with different symbols.
2024         // Thus, resolve ID at runtime is needed.
2025         final int allowedUnprivilegedPerUid =
2026                 getIntResourceForName(KEEPALIVE_ALLOWED_UNPRIVILEGED_RES_NAME);
2027         final int reservedPrivilegedSlots =
2028                 getIntResourceForName(KEEPALIVE_RESERVED_PER_SLOT_RES_NAME);
2029         // Verifies that unprivileged request per uid cannot exceed the limit customized in the
2030         // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test
2031         // does not apply to TCP.
2032         assertGreaterOrEqual(supported, reservedPrivilegedSlots);
2033         assertGreaterOrEqual(supported, allowedUnprivilegedPerUid);
2034         final int expectedUnprivileged =
2035                 Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots);
2036         assertEquals(expectedUnprivileged,
2037                 createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0));
2038     }
2039 
2040     private static void assertGreaterOrEqual(long greater, long lesser) {
2041         assertTrue("" + greater + " expected to be greater than or equal to " + lesser,
2042                 greater >= lesser);
2043     }
2044 
2045     private void verifyBindSocketToRestrictedNetworkDisallowed() throws Exception {
2046         final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
2047         final NetworkRequest testRequest = new NetworkRequest.Builder()
2048                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
2049                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
2050                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
2051                 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
2052                         TEST_RESTRICTED_NW_IFACE_NAME))
2053                 .build();
2054         runWithShellPermissionIdentity(() -> requestNetwork(testRequest, testNetworkCb),
2055                 CONNECTIVITY_USE_RESTRICTED_NETWORKS,
2056                 // CONNECTIVITY_INTERNAL is for requesting restricted network because shell does not
2057                 // have CONNECTIVITY_USE_RESTRICTED_NETWORKS on R.
2058                 CONNECTIVITY_INTERNAL);
2059 
2060         // Create a restricted network and ensure this package cannot bind to that network either.
2061         final NetworkAgent agent = createRestrictedNetworkAgent(mContext);
2062         final Network network = agent.getNetwork();
2063 
2064         try (Socket socket = new Socket()) {
2065             // Verify that the network is restricted.
2066             testNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2067                     NETWORK_CALLBACK_TIMEOUT_MS,
2068                     entry -> network.equals(entry.getNetwork())
2069                             && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
2070                             .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
2071             // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
2072             // does not allow to bind socket to restricted network.
2073             assertThrows(IOException.class, () -> network.bindSocket(socket));
2074         } finally {
2075             agent.unregister();
2076         }
2077     }
2078 
2079     /**
2080      * Verifies that apps are not allowed to access restricted networks even if they declare the
2081      * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests.
2082      * See. b/144679405.
2083      */
2084     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2085     @Test
2086     @IgnoreUpTo(Build.VERSION_CODES.Q)
2087     public void testRestrictedNetworkPermission() throws Exception {
2088         // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package.
2089         final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(),
2090                 GET_PERMISSIONS);
2091         final int index = ArrayUtils.indexOf(
2092                 app.requestedPermissions, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
2093         assertTrue(index >= 0);
2094         assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED);
2095 
2096         if (mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
2097             // Expect binding to the wifi network to succeed.
2098             final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2099             try (Socket socket = new Socket()) {
2100                 wifiNetwork.bindSocket(socket);
2101             }
2102         }
2103 
2104         // Ensure that this package cannot bind to any restricted network that's currently
2105         // connected.
2106         Network[] networks = mCm.getAllNetworks();
2107         for (Network network : networks) {
2108             final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
2109             if (nc == null) {
2110                 continue;
2111             }
2112 
2113             try (Socket socket = new Socket()) {
2114                 if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
2115                     network.bindSocket(socket);  // binding should succeed
2116                 } else {
2117                     assertThrows(IOException.class, () -> network.bindSocket(socket));
2118                 }
2119             }
2120         }
2121 
2122         verifyBindSocketToRestrictedNetworkDisallowed();
2123     }
2124 
2125     /**
2126      * Verifies that apps are allowed to call setAirplaneMode if they declare
2127      * NETWORK_AIRPLANE_MODE permission in their manifests.
2128      * See b/145164696.
2129      */
2130     @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps")
2131     @Test
2132     public void testSetAirplaneMode() throws Exception{
2133         // Starting from T, wifi supports airplane mode enhancement which may not disconnect wifi
2134         // when airplane mode is on. The actual behavior that the device will have could only be
2135         // checked with hidden wifi APIs(see Settings.Secure.WIFI_APM_STATE). Thus, stop verifying
2136         // wifi on T+ device.
2137         final boolean verifyWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI)
2138                 && !SdkLevel.isAtLeastT();
2139         final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
2140         // store the current state of airplane mode
2141         final boolean isAirplaneModeEnabled = isAirplaneModeEnabled();
2142         final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
2143         final TestableNetworkCallback telephonyCb = new TestableNetworkCallback();
2144         // disable airplane mode to reach a known state
2145         runShellCommand("cmd connectivity airplane-mode disable");
2146         // Verify that networks are available as expected if wifi or cell is supported. Continue the
2147         // test if none of them are supported since test should still able to verify the permission
2148         // mechanism.
2149         if (verifyWifi) {
2150             mCtsNetUtils.ensureWifiConnected();
2151             registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
2152         }
2153         if (supportTelephony) {
2154             // connectToCell needs to be followed by disconnectFromCell, which is called in tearDown
2155             mCtsNetUtils.connectToCell();
2156             registerCallbackAndWaitForAvailable(makeCellNetworkRequest(), telephonyCb);
2157         }
2158 
2159         try {
2160             // Verify we cannot set Airplane Mode without correct permission:
2161             assertThrows(SecurityException.class, () -> setAndVerifyAirplaneMode(true));
2162 
2163             // disable airplane mode again to reach a known state
2164             runShellCommand("cmd connectivity airplane-mode disable");
2165 
2166             // Verify we can enable Airplane Mode with correct permission.
2167             // TODO: test that NETWORK_AIRPLANE_MODE works as well, once the shell has it.
2168             runAsShell(NETWORK_SETTINGS, () -> setAndVerifyAirplaneMode(true));
2169 
2170             // Verify that the enabling airplane mode takes effect as expected to prevent flakiness
2171             // caused by fast airplane mode switches. Ensure network lost before turning off
2172             // airplane mode.
2173             if (verifyWifi) waitForLost(wifiCb);
2174             if (supportTelephony) waitForLost(telephonyCb);
2175 
2176             // Verify we can disable Airplane Mode with correct permission:
2177             runAsShell(NETWORK_SETTINGS, () -> setAndVerifyAirplaneMode(false));
2178 
2179             // Verify that turning airplane mode off takes effect as expected.
2180             // connectToCell only registers a request, it cannot / does not need to be called twice
2181             mCtsNetUtils.ensureWifiConnected();
2182             if (verifyWifi) waitForAvailable(wifiCb);
2183             if (supportTelephony) waitForAvailable(telephonyCb);
2184         } finally {
2185             // Restore the previous state of airplane mode and permissions:
2186             runShellCommand("cmd connectivity airplane-mode "
2187                     + (isAirplaneModeEnabled ? "enable" : "disable"));
2188         }
2189     }
2190 
2191     private void registerCallbackAndWaitForAvailable(@NonNull final NetworkRequest request,
2192             @NonNull final TestableNetworkCallback cb) {
2193         registerNetworkCallback(request, cb);
2194         waitForAvailable(cb);
2195     }
2196 
2197     private void waitForAvailable(@NonNull final TestableNetworkCallback cb) {
2198         cb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2199                 c -> c instanceof CallbackEntry.Available);
2200     }
2201 
2202     private void waitForTransport(
2203             @NonNull final TestableNetworkCallback cb, final int expectedTransport) {
2204         cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2205                 NETWORK_CALLBACK_TIMEOUT_MS,
2206                 entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps()
2207                         .hasTransport(expectedTransport));
2208     }
2209 
2210     private void waitForAvailable(
2211             @NonNull final TestableNetworkCallback cb, @NonNull final Network expectedNetwork) {
2212         cb.expectAvailableCallbacks(expectedNetwork, false /* suspended */,
2213                 null /* validated */,
2214                 false /* blocked */, NETWORK_CALLBACK_TIMEOUT_MS);
2215     }
2216 
2217     private void waitForLost(@NonNull final TestableNetworkCallback cb) {
2218         cb.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
2219                 c -> c instanceof CallbackEntry.Lost);
2220     }
2221 
2222     private void setAndVerifyAirplaneMode(Boolean expectedResult)
2223             throws Exception {
2224         final CompletableFuture<Boolean> actualResult = new CompletableFuture();
2225         BroadcastReceiver receiver = new BroadcastReceiver() {
2226             @Override
2227             public void onReceive(Context context, Intent intent) {
2228                 // The defaultValue of getExtraBoolean should be the opposite of what is
2229                 // expected, thus ensuring a test failure if the extra is absent.
2230                 actualResult.complete(intent.getBooleanExtra("state", !expectedResult));
2231             }
2232         };
2233         try {
2234             mContext.registerReceiver(receiver,
2235                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
2236             mCm.setAirplaneMode(expectedResult);
2237             final String msg = "Setting Airplane Mode failed,";
2238             assertEquals(msg, expectedResult, actualResult.get(AIRPLANE_MODE_CHANGE_TIMEOUT_MS,
2239                     TimeUnit.MILLISECONDS));
2240         } finally {
2241             mContext.unregisterReceiver(receiver);
2242         }
2243     }
2244 
2245     private static boolean isAirplaneModeEnabled() {
2246         return runShellCommand("cmd connectivity airplane-mode")
2247                 .trim().equals("enabled");
2248     }
2249 
2250     @Test
2251     public void testGetCaptivePortalServerUrl() {
2252         final String permission = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q
2253                 ? CONNECTIVITY_INTERNAL
2254                 : NETWORK_SETTINGS;
2255         final String url = runAsShell(permission, mCm::getCaptivePortalServerUrl);
2256         assertNotNull("getCaptivePortalServerUrl must not be null", url);
2257         try {
2258             final URL parsedUrl = new URL(url);
2259             // As per the javadoc, the URL must be HTTP
2260             assertEquals("Invalid captive portal URL protocol", "http", parsedUrl.getProtocol());
2261         } catch (MalformedURLException e) {
2262             throw new AssertionFailedError("Captive portal server URL is invalid: " + e);
2263         }
2264     }
2265 
2266     /**
2267      * Verifies that apps are forbidden from getting ssid information from
2268      * {@Code NetworkCapabilities} if they do not hold NETWORK_SETTINGS permission.
2269      * See b/161370134.
2270      */
2271     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2272     @Test
2273     public void testSsidInNetworkCapabilities() throws Exception {
2274         assumeTrue("testSsidInNetworkCapabilities cannot execute unless device supports WiFi",
2275                 mPackageManager.hasSystemFeature(FEATURE_WIFI));
2276 
2277         final Network network = mCtsNetUtils.ensureWifiConnected();
2278         final String ssid = unquoteSSID(mWifiManager.getConnectionInfo().getSSID());
2279         assertNotNull("Ssid getting from WifiManager is null", ssid);
2280         // This package should have no NETWORK_SETTINGS permission. Verify that no ssid is contained
2281         // in the NetworkCapabilities.
2282         verifySsidFromQueriedNetworkCapabilities(network, ssid, false /* hasSsid */);
2283         verifySsidFromCallbackNetworkCapabilities(ssid, false /* hasSsid */);
2284         // Adopt shell permission to allow to get ssid information.
2285         runWithShellPermissionIdentity(() -> {
2286             verifySsidFromQueriedNetworkCapabilities(network, ssid, true /* hasSsid */);
2287             verifySsidFromCallbackNetworkCapabilities(ssid, true /* hasSsid */);
2288         });
2289     }
2290 
2291     private void verifySsidFromQueriedNetworkCapabilities(@NonNull Network network,
2292             @NonNull String ssid, boolean hasSsid) throws Exception {
2293         // Verify if ssid is contained in NetworkCapabilities queried from ConnectivityManager.
2294         final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
2295         assertNotNull("NetworkCapabilities of the network is null", nc);
2296         assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find());
2297     }
2298 
2299     private void verifySsidFromCallbackNetworkCapabilities(@NonNull String ssid, boolean hasSsid)
2300             throws Exception {
2301         final CompletableFuture<NetworkCapabilities> foundNc = new CompletableFuture();
2302         final NetworkCallback callback = new NetworkCallback() {
2303             @Override
2304             public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
2305                 foundNc.complete(nc);
2306             }
2307         };
2308 
2309         registerNetworkCallback(makeWifiNetworkRequest(), callback);
2310         // Registering a callback here guarantees onCapabilitiesChanged is called immediately
2311         // because WiFi network should be connected.
2312         final NetworkCapabilities nc =
2313                 foundNc.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2314         // Verify if ssid is contained in the NetworkCapabilities received from callback.
2315         assertNotNull("NetworkCapabilities of the network is null", nc);
2316         assertEquals(hasSsid, Pattern.compile(ssid).matcher(nc.toString()).find());
2317     }
2318 
2319     /**
2320      * Verify background request can only be requested when acquiring
2321      * {@link android.Manifest.permission.NETWORK_SETTINGS}.
2322      */
2323     @AppModeFull(reason = "Instant apps cannot create test networks")
2324     @Test
2325     public void testRequestBackgroundNetwork() {
2326         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2327         // shims, and @IgnoreUpTo does not check that.
2328         assumeTrue(TestUtils.shouldTestSApis());
2329 
2330         // Create a tun interface. Use the returned interface name as the specifier to create
2331         // a test network request.
2332         final TestNetworkManager tnm = runWithShellPermissionIdentity(() ->
2333                 mContext.getSystemService(TestNetworkManager.class),
2334                 android.Manifest.permission.MANAGE_TEST_NETWORKS);
2335         final TestNetworkInterface testNetworkInterface = runWithShellPermissionIdentity(() ->
2336                     tnm.createTunInterface(new LinkAddress[]{TEST_LINKADDR}),
2337                 android.Manifest.permission.MANAGE_TEST_NETWORKS,
2338                 android.Manifest.permission.NETWORK_SETTINGS);
2339         assertNotNull(testNetworkInterface);
2340 
2341         final NetworkRequest testRequest = new NetworkRequest.Builder()
2342                 .addTransportType(TRANSPORT_TEST)
2343                 // Test networks do not have NOT_VPN or TRUSTED capabilities by default
2344                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
2345                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
2346                 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
2347                         testNetworkInterface.getInterfaceName()))
2348                 .build();
2349 
2350         // Verify background network cannot be requested without NETWORK_SETTINGS permission.
2351         final TestableNetworkCallback callback = new TestableNetworkCallback();
2352         final Handler handler = new Handler(Looper.getMainLooper());
2353         assertThrows(SecurityException.class,
2354                 () -> requestBackgroundNetwork(testRequest, callback, handler));
2355 
2356         Network testNetwork = null;
2357         try {
2358             // Request background test network via Shell identity which has NETWORK_SETTINGS
2359             // permission granted.
2360             runWithShellPermissionIdentity(
2361                     () -> requestBackgroundNetwork(testRequest, callback, handler),
2362                     new String[] { android.Manifest.permission.NETWORK_SETTINGS });
2363 
2364             // Register the test network agent which has no foreground request associated to it.
2365             // And verify it can satisfy the background network request just fired.
2366             final Binder binder = new Binder();
2367             runWithShellPermissionIdentity(() ->
2368                     tnm.setupTestNetwork(testNetworkInterface.getInterfaceName(), binder),
2369                     new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS,
2370                             android.Manifest.permission.NETWORK_SETTINGS });
2371             waitForAvailable(callback);
2372             testNetwork = callback.getLastAvailableNetwork();
2373             assertNotNull(testNetwork);
2374 
2375             // The test network that has just connected is a foreground network,
2376             // non-listen requests will get available callback before it can be put into
2377             // background if no foreground request can be satisfied. Thus, wait for a short
2378             // period is needed to let foreground capability go away.
2379             callback.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2380                     NETWORK_CALLBACK_TIMEOUT_MS,
2381                     c -> c instanceof CallbackEntry.CapabilitiesChanged
2382                             && !((CallbackEntry.CapabilitiesChanged) c).getCaps()
2383                             .hasCapability(NET_CAPABILITY_FOREGROUND));
2384             final NetworkCapabilities nc = mCm.getNetworkCapabilities(testNetwork);
2385             assertFalse("expected background network, but got " + nc,
2386                     nc.hasCapability(NET_CAPABILITY_FOREGROUND));
2387         } finally {
2388             final Network n = testNetwork;
2389             runWithShellPermissionIdentity(() -> {
2390                 if (null != n) {
2391                     tnm.teardownTestNetwork(n);
2392                     callback.eventuallyExpect(CallbackEntry.LOST,
2393                             NETWORK_CALLBACK_TIMEOUT_MS,
2394                             lost -> n.equals(lost.getNetwork()));
2395                 }
2396                 testNetworkInterface.getFileDescriptor().close();
2397             }, new String[] { android.Manifest.permission.MANAGE_TEST_NETWORKS });
2398         }
2399     }
2400 
2401     private class DetailedBlockedStatusCallback extends TestableNetworkCallback {
2402         public void expectAvailableCallbacksWithBlockedReasonNone(Network network) {
2403             super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */,
2404                     BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS);
2405         }
2406         public void eventuallyExpectBlockedStatusCallback(Network network, int blockedStatus) {
2407             super.eventuallyExpect(CallbackEntry.BLOCKED_STATUS_INT, NETWORK_CALLBACK_TIMEOUT_MS,
2408                     (it) -> it.getNetwork().equals(network) && it.getReason() == blockedStatus);
2409         }
2410         public void onBlockedStatusChanged(Network network, int blockedReasons) {
2411             Log.v(TAG, "onBlockedStatusChanged " + network + " " + blockedReasons);
2412             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
2413         }
2414         private void assertNoBlockedStatusCallback() {
2415             super.assertNoCallback(NO_CALLBACK_TIMEOUT_MS,
2416                     c -> c instanceof CallbackEntry.BlockedStatus);
2417         }
2418     }
2419 
2420     private void setRequireVpnForUids(boolean requireVpn, Collection<Range<Integer>> ranges)
2421             throws Exception {
2422         mCmShim.setRequireVpnForUids(requireVpn, ranges);
2423         for (Range<Integer> range : ranges) {
2424             if (requireVpn) {
2425                 mVpnRequiredUidRanges.add(range);
2426             } else {
2427                 assertTrue(mVpnRequiredUidRanges.remove(range));
2428             }
2429         }
2430     }
2431 
2432     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2433     @Test
2434     public void testBlockedStatusCallback() throws Exception {
2435         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2436         // shims, and @IgnoreUpTo does not check that.
2437         assumeTrue(TestUtils.shouldTestSApis());
2438         // The test will need a stable active network that is persistent during the test.
2439         // Try to connect to a wifi network and wait for it becomes the default network before
2440         // starting the test to prevent from sudden active network change caused by previous
2441         // executed tests.
2442         if (mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
2443             final Network expectedDefaultNetwork = mCtsNetUtils.ensureWifiConnected();
2444             mCtsNetUtils.expectNetworkIsSystemDefault(expectedDefaultNetwork);
2445         }
2446 
2447         final DetailedBlockedStatusCallback myUidCallback = new DetailedBlockedStatusCallback();
2448         final DetailedBlockedStatusCallback otherUidCallback = new DetailedBlockedStatusCallback();
2449 
2450         final int myUid = Process.myUid();
2451         final int otherUid = UserHandle.getUid(5, Process.FIRST_APPLICATION_UID);
2452         final Handler handler = new Handler(Looper.getMainLooper());
2453 
2454         registerDefaultNetworkCallback(myUidCallback, handler);
2455         runWithShellPermissionIdentity(() -> registerDefaultNetworkCallbackForUid(
2456                 otherUid, otherUidCallback, handler), NETWORK_SETTINGS);
2457 
2458         final Network defaultNetwork = myUidCallback.expect(CallbackEntry.AVAILABLE).getNetwork();
2459         final List<DetailedBlockedStatusCallback> allCallbacks =
2460                 List.of(myUidCallback, otherUidCallback);
2461         for (DetailedBlockedStatusCallback callback : allCallbacks) {
2462             callback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
2463         }
2464 
2465         final Range<Integer> myUidRange = new Range<>(myUid, myUid);
2466         final Range<Integer> otherUidRange = new Range<>(otherUid, otherUid);
2467 
2468         runWithShellPermissionIdentity(() -> setRequireVpnForUids(
2469                 true, List.of(myUidRange)), NETWORK_SETTINGS);
2470         myUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork,
2471                 BLOCKED_REASON_LOCKDOWN_VPN);
2472         otherUidCallback.assertNoBlockedStatusCallback();
2473 
2474         runWithShellPermissionIdentity(() -> setRequireVpnForUids(
2475                 true, List.of(myUidRange, otherUidRange)), NETWORK_SETTINGS);
2476         myUidCallback.assertNoBlockedStatusCallback();
2477         otherUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork,
2478                 BLOCKED_REASON_LOCKDOWN_VPN);
2479 
2480         // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not
2481         // unblock myUid because it was added to the blocked ranges twice.
2482         runWithShellPermissionIdentity(() ->
2483                 setRequireVpnForUids(false, List.of(myUidRange)), NETWORK_SETTINGS);
2484         myUidCallback.assertNoBlockedStatusCallback();
2485         otherUidCallback.assertNoBlockedStatusCallback();
2486 
2487         runWithShellPermissionIdentity(() -> setRequireVpnForUids(
2488                 false, List.of(myUidRange, otherUidRange)), NETWORK_SETTINGS);
2489         myUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
2490         otherUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
2491 
2492         myUidCallback.assertNoBlockedStatusCallback();
2493         otherUidCallback.assertNoBlockedStatusCallback();
2494     }
2495 
2496     @Test
2497     public void testSetVpnDefaultForUids() {
2498         assumeTrue(TestUtils.shouldTestUApis());
2499         final String session = UUID.randomUUID().toString();
2500         assertThrows(NullPointerException.class, () -> mCm.setVpnDefaultForUids(session, null));
2501         assertThrows(SecurityException.class,
2502                 () -> mCm.setVpnDefaultForUids(session, new ArraySet<>()));
2503         // For testing the complete behavior of setVpnDefaultForUids(), please refer to
2504         // HostsideVpnTests.
2505     }
2506 
2507     private void doTestLegacyLockdownEnabled() throws Exception {
2508         NetworkInfo info = mCm.getActiveNetworkInfo();
2509         assertNotNull(info);
2510         assertEquals(DetailedState.CONNECTED, info.getDetailedState());
2511 
2512         final TestableNetworkCallback callback = new TestableNetworkCallback();
2513         try {
2514             mCmShim.setLegacyLockdownVpnEnabled(true);
2515 
2516             // setLegacyLockdownVpnEnabled is asynchronous and only takes effect when the
2517             // ConnectivityService handler thread processes it. Ensure it has taken effect by doing
2518             // something that blocks until the handler thread is idle.
2519             registerDefaultNetworkCallback(callback);
2520             waitForAvailable(callback);
2521 
2522             // Test one of the effects of setLegacyLockdownVpnEnabled: the fact that any NetworkInfo
2523             // in state CONNECTED is degraded to CONNECTING if the legacy VPN is not connected.
2524             info = mCm.getActiveNetworkInfo();
2525             assertNotNull(info);
2526             assertEquals(DetailedState.CONNECTING, info.getDetailedState());
2527         } finally {
2528             mCmShim.setLegacyLockdownVpnEnabled(false);
2529         }
2530     }
2531 
2532     @Test
2533     public void testLegacyLockdownEnabled() {
2534         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2535         // shims, and @IgnoreUpTo does not check that.
2536         assumeTrue(TestUtils.shouldTestSApis());
2537         runWithShellPermissionIdentity(() -> doTestLegacyLockdownEnabled(), NETWORK_SETTINGS);
2538     }
2539 
2540     @Test
2541     public void testGetCapabilityCarrierName() {
2542         assumeTrue(TestUtils.shouldTestSApis());
2543         assertEquals("ENTERPRISE", NetworkInformationShimImpl.newInstance()
2544                 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_ENTERPRISE));
2545         assertNull(NetworkInformationShimImpl.newInstance()
2546                 .getCapabilityCarrierName(ConstantsShim.NET_CAPABILITY_NOT_VCN_MANAGED));
2547     }
2548 
2549     @Test
2550     public void testSetGlobalProxy() {
2551         assumeTrue(TestUtils.shouldTestSApis());
2552         // Behavior is verified in gts. Verify exception thrown w/o permission.
2553         assertThrows(SecurityException.class, () -> mCm.setGlobalProxy(
2554                 ProxyInfo.buildDirectProxy("example.com" /* host */, 8080 /* port */)));
2555     }
2556 
2557     @Test
2558     public void testFactoryResetWithoutPermission() {
2559         assumeTrue(TestUtils.shouldTestSApis());
2560         assertThrows(SecurityException.class, () -> mCm.factoryReset());
2561     }
2562 
2563     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
2564     @Test
2565     public void testFactoryReset() throws Exception {
2566         assumeTrue(TestUtils.shouldTestSApis());
2567 
2568         // Store current settings.
2569         final int curAvoidBadWifi =
2570                 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext);
2571         final int curPrivateDnsMode = ConnectivitySettingsManager.getPrivateDnsMode(mContext);
2572 
2573         final CtsTetheringUtils tetherUtils = new CtsTetheringUtils(mContext);
2574         final TestTetheringEventCallback tetherEventCallback =
2575                 tetherUtils.registerTetheringEventCallback();
2576         try {
2577             tetherEventCallback.assumeWifiTetheringSupported(mContext);
2578             // To prevent WiFi-to-WiFi interruption while entering APM:
2579             //  - If WiFi is retained while entering APM, hotspot will also remain enabled.
2580             //  - If WiFi is off before APM or disabled while entering APM, hotspot will be
2581             //    disabled.
2582             //
2583             // To ensure hotspot always be disabled after enabling APM, disable wifi before
2584             // enabling the hotspot.
2585             mCtsNetUtils.disableWifi();
2586 
2587             tetherUtils.startWifiTethering(tetherEventCallback);
2588             // Update setting to verify the behavior.
2589             setAirplaneMode(true);
2590             // Verify softap lost to make sure airplane mode takes effect. This could
2591             // prevent the race condition between airplane mode enabled and the followed
2592             // up wifi tethering enabled.
2593             tetherEventCallback.expectNoTetheringActive();
2594 
2595             // start wifi tethering
2596             tetherUtils.startWifiTethering(tetherEventCallback);
2597 
2598             ConnectivitySettingsManager.setPrivateDnsMode(mContext,
2599                     ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF);
2600             ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext,
2601                     ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE);
2602             assertEquals(AIRPLANE_MODE_ON, Settings.Global.getInt(
2603                     mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
2604             // Verify factoryReset
2605             runAsShell(NETWORK_SETTINGS, TETHER_PRIVILEGED, () -> {
2606                 mCm.factoryReset();
2607                 tetherEventCallback.expectNoTetheringActive();
2608             });
2609             verifySettings(AIRPLANE_MODE_OFF,
2610                     ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC,
2611                     ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT);
2612         } finally {
2613             // Restore settings.
2614             setAirplaneMode(false);
2615             ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, curAvoidBadWifi);
2616             ConnectivitySettingsManager.setPrivateDnsMode(mContext, curPrivateDnsMode);
2617             tetherUtils.unregisterTetheringEventCallback(tetherEventCallback);
2618             tetherUtils.stopAllTethering();
2619             mCtsNetUtils.ensureWifiConnected();
2620         }
2621     }
2622 
2623     private void setAirplaneMode(boolean enable) {
2624         runAsShell(NETWORK_SETTINGS, () -> mCm.setAirplaneMode(enable));
2625     }
2626 
2627     /**
2628      * Verify that {@link ConnectivityManager#setProfileNetworkPreference} cannot be called
2629      * without required NETWORK_STACK permissions.
2630      */
2631     @Test
2632     public void testSetProfileNetworkPreference_NoPermission() {
2633         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2634         // shims, and @IgnoreUpTo does not check that.
2635         assumeTrue(TestUtils.shouldTestSApis());
2636         assertThrows(SecurityException.class, () -> mCm.setProfileNetworkPreference(
2637                 UserHandle.of(0), PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null /* executor */,
2638                 null /* listener */));
2639     }
2640 
2641     @Test
2642     public void testSystemReady() {
2643         assumeTrue(TestUtils.shouldTestSApis());
2644         assertThrows(SecurityException.class, () -> mCm.systemReady());
2645     }
2646 
2647     @Test
2648     public void testGetIpSecNetIdRange() {
2649         assumeTrue(TestUtils.shouldTestSApis());
2650         // The lower refers to ConnectivityManager.TUN_INTF_NETID_START.
2651         final long lower = 64512;
2652         // The upper refers to ConnectivityManager.TUN_INTF_NETID_START
2653         // + ConnectivityManager.TUN_INTF_NETID_RANGE - 1
2654         final long upper = 65535;
2655         assertEquals(lower, (long) ConnectivityManager.getIpSecNetIdRange().getLower());
2656         assertEquals(upper, (long) ConnectivityManager.getIpSecNetIdRange().getUpper());
2657     }
2658 
2659     private void verifySettings(int expectedAirplaneMode, int expectedPrivateDnsMode,
2660             int expectedAvoidBadWifi) throws Exception {
2661         assertEquals(expectedAirplaneMode, Settings.Global.getInt(
2662                 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON));
2663         assertEquals(expectedPrivateDnsMode,
2664                 ConnectivitySettingsManager.getPrivateDnsMode(mContext));
2665         assertEquals(expectedAvoidBadWifi,
2666                 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext));
2667     }
2668 
2669     /**
2670      * Verify that per-app OEM network preference functions as expected for network preference TEST.
2671      * For specified apps, validate networks are prioritized in order: unmetered, TEST transport,
2672      * default network.
2673      */
2674     @AppModeFull(reason = "Instant apps cannot create test networks")
2675     @Test
2676     public void testSetOemNetworkPreferenceForTestPref() throws Exception {
2677         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2678         // shims, and @IgnoreUpTo does not check that.
2679         assumeTrue(TestUtils.shouldTestSApis());
2680         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
2681 
2682         final TestNetworkTracker tnt = callWithShellPermissionIdentity(
2683                 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
2684         final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
2685         final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
2686 
2687         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2688         final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity(
2689                 () -> mCm.getNetworkCapabilities(wifiNetwork));
2690         final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid());
2691         final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
2692 
2693         testAndCleanup(() -> {
2694             // This network will be used for unmetered. Wait for it to be validated because
2695             // OEM_NETWORK_PREFERENCE_TEST only prefers NOT_METERED&VALIDATED to a network with
2696             // TRANSPORT_TEST, like OEM_NETWORK_PREFERENCE_OEM_PAID.
2697             setWifiMeteredStatusAndWait(ssid, false /* isMetered */, true /* waitForValidation */);
2698 
2699             setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
2700             registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
2701 
2702             // Validate that an unmetered network is used over other networks.
2703             waitForAvailable(defaultCallback, wifiNetwork);
2704             systemDefaultCallback.eventuallyExpect(CallbackEntry.AVAILABLE,
2705                     NETWORK_CALLBACK_TIMEOUT_MS, cb -> wifiNetwork.equals(cb.getNetwork()));
2706 
2707             // Validate that when setting unmetered to metered, unmetered is lost and replaced by
2708             // the network with the TEST transport. Also wait for validation here, in case there
2709             // is a bug that's only visible when the network is validated.
2710             setWifiMeteredStatusAndWait(ssid, true /* isMetered */, true /* waitForValidation */);
2711             defaultCallback.expect(CallbackEntry.LOST, wifiNetwork, NETWORK_CALLBACK_TIMEOUT_MS);
2712             waitForAvailable(defaultCallback, tnt.getNetwork());
2713             // Depending on if this device has cellular connectivity or not, multiple available
2714             // callbacks may be received. Eventually, metered Wi-Fi should be the final available
2715             // callback in any case therefore confirm its receipt before continuing to assure the
2716             // system is in the expected state.
2717             waitForTransport(systemDefaultCallback, TRANSPORT_WIFI);
2718         }, /* cleanup */ () -> {
2719                 // Validate that removing the test network will fallback to the default network.
2720                 runWithShellPermissionIdentity(tnt::teardown);
2721                 // The other callbacks (LP or NC changes) would receive before LOST callback. Use
2722                 // eventuallyExpect to check callback for avoiding test flake.
2723                 defaultCallback.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
2724                         lost -> tnt.getNetwork().equals(lost.getNetwork()));
2725                 waitForAvailable(defaultCallback);
2726             }, /* cleanup */ () -> {
2727                 setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */);
2728             }, /* cleanup */ () -> {
2729                 // Cleanup any prior test state from setOemNetworkPreference
2730                 clearOemNetworkPreference();
2731             });
2732     }
2733 
2734     /**
2735      * Verify that per-app OEM network preference functions as expected for network pref TEST_ONLY.
2736      * For specified apps, validate that only TEST transport type networks are used.
2737      */
2738     @AppModeFull(reason = "Instant apps cannot create test networks")
2739     @Test
2740     public void testSetOemNetworkPreferenceForTestOnlyPref() throws Exception {
2741         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
2742         // shims, and @IgnoreUpTo does not check that.
2743         assumeTrue(TestUtils.shouldTestSApis());
2744         assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
2745 
2746         final TestNetworkTracker tnt = callWithShellPermissionIdentity(
2747                 () -> initTestNetwork(mContext, TEST_LINKADDR, NETWORK_CALLBACK_TIMEOUT_MS));
2748         final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
2749         final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
2750 
2751         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
2752 
2753         testAndCleanup(() -> {
2754             setOemNetworkPreferenceForMyPackage(
2755                     OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY);
2756             registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
2757             waitForAvailable(defaultCallback, tnt.getNetwork());
2758             systemDefaultCallback.eventuallyExpect(CallbackEntry.AVAILABLE,
2759                     NETWORK_CALLBACK_TIMEOUT_MS, cb -> wifiNetwork.equals(cb.getNetwork()));
2760         }, /* cleanup */ () -> {
2761                 runWithShellPermissionIdentity(tnt::teardown);
2762                 defaultCallback.expect(CallbackEntry.LOST, tnt, NETWORK_CALLBACK_TIMEOUT_MS);
2763 
2764                 // This network preference should only ever use the test network therefore available
2765                 // should not trigger when the test network goes down (e.g. switch to cellular).
2766                 defaultCallback.assertNoCallback();
2767                 // The system default should still be connected to Wi-fi
2768                 assertEquals(wifiNetwork, systemDefaultCallback.getLastAvailableNetwork());
2769             }, /* cleanup */ () -> {
2770                 // Cleanup any prior test state from setOemNetworkPreference
2771                 clearOemNetworkPreference();
2772 
2773                 // The default (non-test) network should be available as the network pref was
2774                 // cleared.
2775                 waitForAvailable(defaultCallback);
2776             });
2777     }
2778 
2779     private void registerTestOemNetworkPreferenceCallbacks(
2780             @NonNull final TestableNetworkCallback defaultCallback,
2781             @NonNull final TestableNetworkCallback systemDefaultCallback) {
2782         registerDefaultNetworkCallback(defaultCallback);
2783         runWithShellPermissionIdentity(() ->
2784                 registerSystemDefaultNetworkCallback(systemDefaultCallback,
2785                         new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
2786     }
2787 
2788     private static final class OnCompleteListenerCallback {
2789         final CompletableFuture<Object> mDone = new CompletableFuture<>();
2790 
2791         public void onComplete() {
2792             mDone.complete(new Object());
2793         }
2794 
2795         void expectOnComplete() throws Exception {
2796             try {
2797                 mDone.get(NETWORK_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
2798             } catch (TimeoutException e) {
2799                 fail("Expected onComplete() not received after "
2800                         + NETWORK_CALLBACK_TIMEOUT_MS + " ms");
2801             }
2802         }
2803     }
2804 
2805     private void setOemNetworkPreferenceForMyPackage(final int networkPref) throws Exception {
2806         final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
2807                 .addNetworkPreference(mContext.getPackageName(), networkPref)
2808                 .build();
2809         final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
2810         mUiAutomation.adoptShellPermissionIdentity();
2811         try {
2812             mCm.setOemNetworkPreference(
2813                     pref, mContext.getMainExecutor(), oemPrefListener::onComplete);
2814         } finally {
2815             mUiAutomation.dropShellPermissionIdentity();
2816         }
2817         oemPrefListener.expectOnComplete();
2818     }
2819 
2820     /**
2821      * This will clear the OEM network preference on the device. As there is currently no way of
2822      * getting the existing preference, if this is executed while an existing preference is in
2823      * place, that preference will need to be reapplied after executing this test.
2824      * @throws Exception
2825      */
2826     private void clearOemNetworkPreference() throws Exception {
2827         final OemNetworkPreferences clearPref = new OemNetworkPreferences.Builder().build();
2828         final OnCompleteListenerCallback oemPrefListener = new OnCompleteListenerCallback();
2829         mUiAutomation.adoptShellPermissionIdentity();
2830         try {
2831             mCm.setOemNetworkPreference(
2832                     clearPref, mContext.getMainExecutor(), oemPrefListener::onComplete);
2833         } finally {
2834             mUiAutomation.dropShellPermissionIdentity();
2835         }
2836         oemPrefListener.expectOnComplete();
2837     }
2838 
2839     @Test
2840     public void testSetAcceptPartialConnectivity_NoPermission_GetException() {
2841         assumeTrue(TestUtils.shouldTestSApis());
2842         assertThrows(SecurityException.class, () -> mCm.setAcceptPartialConnectivity(
2843                 mCm.getActiveNetwork(), false /* accept */ , false /* always */));
2844     }
2845 
2846     private void ensureCellIsValidatedBeforeMockingValidationUrls() {
2847         // Verify that current supported network is validated so that the mock http server will not
2848         // apply to unexpected networks. Also see aosp/2208680.
2849         //
2850         // This may also apply to wifi in principle, but in practice methods that mock validation
2851         // URL all disconnect wifi forcefully anyway, so don't wait for wifi to validate.
2852         if (mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
2853             ensureValidatedNetwork(makeCellNetworkRequest());
2854         }
2855     }
2856 
2857     private void ensureValidatedNetwork(NetworkRequest request) {
2858         final TestableNetworkCallback cb = new TestableNetworkCallback();
2859         mCm.registerNetworkCallback(request, cb);
2860         cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
2861                 NETWORK_CALLBACK_TIMEOUT_MS,
2862                 entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps()
2863                         .hasCapability(NET_CAPABILITY_VALIDATED));
2864         mCm.unregisterNetworkCallback(cb);
2865     }
2866 
2867     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2868     @Test
2869     public void testAcceptPartialConnectivity_validatedNetwork() throws Exception {
2870         assumeTrue(TestUtils.shouldTestSApis());
2871         assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
2872                         + " unless device supports WiFi",
2873                 mPackageManager.hasSystemFeature(FEATURE_WIFI));
2874 
2875         try {
2876             // Wait for partial connectivity to be detected on the network
2877             final Network network = preparePartialConnectivity();
2878 
2879             runAsShell(NETWORK_SETTINGS, () -> {
2880                 // The always bit is verified in NetworkAgentTest
2881                 mCm.setAcceptPartialConnectivity(network, true /* accept */, false /* always */);
2882             });
2883 
2884             // Accept partial connectivity network should result in a validated network
2885             expectNetworkHasCapability(network, NET_CAPABILITY_VALIDATED, WIFI_CONNECT_TIMEOUT_MS);
2886         } finally {
2887             mHttpServer.stop();
2888             mTestValidationConfigRule.runAfterNextCleanup(this::reconnectWifi);
2889         }
2890     }
2891 
2892     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2893     @Test
2894     public void testRejectPartialConnectivity_TearDownNetwork() throws Exception {
2895         assumeTrue(TestUtils.shouldTestSApis());
2896         assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
2897                         + " unless device supports WiFi",
2898                 mPackageManager.hasSystemFeature(FEATURE_WIFI));
2899 
2900         final TestNetworkCallback cb = new TestNetworkCallback();
2901         try {
2902             // Wait for partial connectivity to be detected on the network
2903             final Network network = preparePartialConnectivity();
2904 
2905             requestNetwork(makeWifiNetworkRequest(), cb);
2906             runAsShell(NETWORK_SETTINGS, () -> {
2907                 // The always bit is verified in NetworkAgentTest
2908                 mCm.setAcceptPartialConnectivity(network, false /* accept */, false /* always */);
2909             });
2910             // Reject partial connectivity network should cause the network being torn down
2911             assertEquals(network, cb.waitForLost());
2912         } finally {
2913             mHttpServer.stop();
2914             // Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot
2915             // apply here. Thus, turn off wifi first and restart to restore.
2916             mTestValidationConfigRule.runAfterNextCleanup(() -> {
2917                 mCtsNetUtils.disableWifi();
2918                 mCtsNetUtils.ensureWifiConnected();
2919             });
2920         }
2921     }
2922 
2923     @Test
2924     public void testSetAcceptUnvalidated_NoPermission_GetException() {
2925         assumeTrue(TestUtils.shouldTestSApis());
2926         assertThrows(SecurityException.class, () -> mCm.setAcceptUnvalidated(
2927                 mCm.getActiveNetwork(), false /* accept */ , false /* always */));
2928     }
2929 
2930     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2931     @Test
2932     public void testRejectUnvalidated_TearDownNetwork() throws Exception {
2933         assumeTrue(TestUtils.shouldTestSApis());
2934         final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
2935                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
2936         assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
2937                         + " unless device supports WiFi and telephony", canRunTest);
2938 
2939         final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
2940         try {
2941             // Ensure at least one default network candidate connected.
2942             mCtsNetUtils.connectToCell();
2943 
2944             final Network wifiNetwork = prepareUnvalidatedNetwork();
2945             // Default network should not be wifi ,but checking that wifi is not the default doesn't
2946             // guarantee that it won't become the default in the future.
2947             assertNotEquals(wifiNetwork, mCm.getActiveNetwork());
2948 
2949             registerNetworkCallback(makeWifiNetworkRequest(), wifiCb);
2950             runAsShell(NETWORK_SETTINGS, () -> {
2951                 mCm.setAcceptUnvalidated(wifiNetwork, false /* accept */, false /* always */);
2952             });
2953             waitForLost(wifiCb);
2954         } finally {
2955             mHttpServer.stop();
2956             /// Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot
2957             // apply here. Thus, turn off wifi first and restart to restore.
2958             mTestValidationConfigRule.runAfterNextCleanup(() -> {
2959                 mCtsNetUtils.disableWifi();
2960                 mCtsNetUtils.ensureWifiConnected();
2961             });
2962         }
2963     }
2964 
2965     @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
2966     @Test
2967     public void testSetAvoidUnvalidated() throws Exception {
2968         assumeTrue(TestUtils.shouldTestSApis());
2969         // TODO: Allow in debuggable ROM only. To be replaced by FabricatedOverlay
2970         assumeTrue(Build.isDebuggable());
2971         final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
2972                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
2973         assumeTrue("testSetAvoidUnvalidated cannot execute"
2974                 + " unless device supports WiFi and telephony", canRunTest);
2975 
2976         final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
2977         final TestableNetworkCallback defaultCb = new TestableNetworkCallback();
2978         final int previousAvoidBadWifi =
2979                 ConnectivitySettingsManager.getNetworkAvoidBadWifi(mContext);
2980 
2981         allowBadWifi();
2982 
2983         final Network cellNetwork = mCtsNetUtils.connectToCell();
2984         final Network wifiNetwork = prepareValidatedNetwork();
2985 
2986         registerDefaultNetworkCallback(defaultCb);
2987         registerNetworkCallback(makeWifiNetworkRequest(), wifiCb);
2988 
2989         try {
2990             // Verify wifi is the default network.
2991             defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2992                     entry -> wifiNetwork.equals(entry.getNetwork()));
2993             wifiCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
2994                     entry -> wifiNetwork.equals(entry.getNetwork()));
2995             assertTrue(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
2996                     NET_CAPABILITY_VALIDATED));
2997 
2998             // The cell network has already been checked to be validated.
2999             // Configure response code for unvalidated network.
3000             configTestServer(Status.INTERNAL_ERROR, Status.INTERNAL_ERROR);
3001             mCm.reportNetworkConnectivity(wifiNetwork, false);
3002             // Default network should stay on unvalidated wifi because avoid bad wifi is disabled.
3003             defaultCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
3004                     NETWORK_CALLBACK_TIMEOUT_MS,
3005                     entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps()
3006                             .hasCapability(NET_CAPABILITY_VALIDATED));
3007             wifiCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
3008                     NETWORK_CALLBACK_TIMEOUT_MS,
3009                     entry -> !((CallbackEntry.CapabilitiesChanged) entry).getCaps()
3010                             .hasCapability(NET_CAPABILITY_VALIDATED));
3011 
3012             runAsShell(NETWORK_SETTINGS, () -> {
3013                 mCm.setAvoidUnvalidated(wifiNetwork);
3014             });
3015             // Default network should be updated to validated cellular network.
3016             defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
3017                     entry -> cellNetwork.equals(entry.getNetwork()));
3018             // The network should not validate again.
3019             wifiCb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS, c -> isValidatedCaps(c));
3020         } finally {
3021             resetAvoidBadWifi(previousAvoidBadWifi);
3022             mHttpServer.stop();
3023             mTestValidationConfigRule.runAfterNextCleanup(this::reconnectWifi);
3024         }
3025     }
3026 
3027     private boolean isValidatedCaps(CallbackEntry c) {
3028         if (!(c instanceof CallbackEntry.CapabilitiesChanged)) return false;
3029         final CallbackEntry.CapabilitiesChanged capsChanged = (CallbackEntry.CapabilitiesChanged) c;
3030         return capsChanged.getCaps().hasCapability(NET_CAPABILITY_VALIDATED);
3031     }
3032 
3033     private void resetAvoidBadWifi(int settingValue) {
3034         setTestAllowBadWifiResource(0 /* timeMs */);
3035         ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext, settingValue);
3036     }
3037 
3038     private void allowBadWifi() {
3039         setTestAllowBadWifiResource(
3040                 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS /* timeMs */);
3041         ConnectivitySettingsManager.setNetworkAvoidBadWifi(mContext,
3042                 ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE);
3043     }
3044 
3045     private void setTestAllowBadWifiResource(long timeMs) {
3046         runAsShell(NETWORK_SETTINGS, () -> {
3047             mCm.setTestAllowBadWifiUntil(timeMs);
3048         });
3049     }
3050 
3051     private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout)
3052             throws Exception {
3053         final CompletableFuture<Network> future = new CompletableFuture();
3054         final NetworkCallback cb = new NetworkCallback() {
3055             @Override
3056             public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) {
3057                 if (n.equals(network) && nc.hasCapability(expectedNetCap)) {
3058                     future.complete(network);
3059                 }
3060             }
3061         };
3062 
3063         registerNetworkCallback(new NetworkRequest.Builder().build(), cb);
3064         return future.get(timeout, TimeUnit.MILLISECONDS);
3065     }
3066 
3067     private void prepareHttpServer() throws Exception {
3068         runAsShell(READ_DEVICE_CONFIG, () -> {
3069             // Verify that the test URLs are not normally set on the device, but do not fail if the
3070             // test URLs are set to what this test uses (URLs on localhost), in case the test was
3071             // interrupted manually and rerun.
3072             assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL);
3073             assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL);
3074         });
3075 
3076         NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig();
3077 
3078         mHttpServer.start();
3079     }
3080 
3081     private Network reconnectWifi() {
3082         mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
3083         return mCtsNetUtils.ensureWifiConnected();
3084     }
3085 
3086     private Network prepareValidatedNetwork() throws Exception {
3087         ensureCellIsValidatedBeforeMockingValidationUrls();
3088 
3089         prepareHttpServer();
3090         configTestServer(Status.NO_CONTENT, Status.NO_CONTENT);
3091         // Disconnect wifi first then start wifi network with configuration.
3092         final Network wifiNetwork = reconnectWifi();
3093 
3094         return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_VALIDATED,
3095                 WIFI_CONNECT_TIMEOUT_MS);
3096     }
3097 
3098     private Network preparePartialConnectivity() throws Exception {
3099         ensureCellIsValidatedBeforeMockingValidationUrls();
3100 
3101         prepareHttpServer();
3102         // Configure response code for partial connectivity
3103         configTestServer(Status.INTERNAL_ERROR  /* httpsStatusCode */,
3104                 Status.NO_CONTENT  /* httpStatusCode */);
3105         // Disconnect wifi first then start wifi network with configuration.
3106         mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
3107         final Network network = mCtsNetUtils.ensureWifiConnected();
3108 
3109         return expectNetworkHasCapability(network, NET_CAPABILITY_PARTIAL_CONNECTIVITY,
3110                 WIFI_CONNECT_TIMEOUT_MS);
3111     }
3112 
3113     private Network prepareUnvalidatedNetwork() throws Exception {
3114         ensureCellIsValidatedBeforeMockingValidationUrls();
3115 
3116         prepareHttpServer();
3117         // Configure response code for unvalidated network
3118         configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */,
3119                 Status.INTERNAL_ERROR /* httpStatusCode */);
3120 
3121         // Disconnect wifi first then start wifi network with configuration.
3122         mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
3123         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
3124         return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_INTERNET,
3125                 WIFI_CONNECT_TIMEOUT_MS);
3126     }
3127 
3128     private String makeUrl(String path) {
3129         return "http://localhost:" + mHttpServer.getListeningPort() + path;
3130     }
3131 
3132     private void assertEmptyOrLocalhostUrl(String urlKey) {
3133         final String url = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, urlKey);
3134         assertTrue(urlKey + " must not be set in production scenarios, current value= " + url,
3135                 TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME.equals(Uri.parse(url).getHost()));
3136     }
3137 
3138     private void configTestServer(IStatus httpsStatusCode, IStatus httpStatusCode) {
3139         mHttpServer.addResponse(new TestHttpServer.Request(
3140                 TEST_HTTPS_URL_PATH, Method.GET, "" /* queryParameters */),
3141                 httpsStatusCode, null /* locationHeader */, "" /* content */);
3142         mHttpServer.addResponse(new TestHttpServer.Request(
3143                 TEST_HTTP_URL_PATH, Method.GET, "" /* queryParameters */),
3144                 httpStatusCode, null /* locationHeader */, "" /* content */);
3145         NetworkValidationTestUtil.setHttpsUrlDeviceConfig(mTestValidationConfigRule,
3146                 makeUrl(TEST_HTTPS_URL_PATH));
3147         NetworkValidationTestUtil.setHttpUrlDeviceConfig(mTestValidationConfigRule,
3148                 makeUrl(TEST_HTTP_URL_PATH));
3149         NetworkValidationTestUtil.setUrlExpirationDeviceConfig(mTestValidationConfigRule,
3150                 System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS);
3151     }
3152 
3153     @AppModeFull(reason = "Need WiFi support to test the default active network")
3154     @Test
3155     public void testDefaultNetworkActiveListener() throws Exception {
3156         final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI);
3157         final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
3158         assumeTrue("testDefaultNetworkActiveListener cannot execute"
3159                 + " unless device supports WiFi or telephony", (supportWifi || supportTelephony));
3160 
3161         if (supportWifi) {
3162             mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
3163         } else {
3164             mCtsNetUtils.disconnectFromCell();
3165         }
3166 
3167         final CompletableFuture<Boolean> future = new CompletableFuture<>();
3168         final ConnectivityManager.OnNetworkActiveListener listener = () -> future.complete(true);
3169         mCm.addDefaultNetworkActiveListener(listener);
3170         testAndCleanup(() -> {
3171             // New default network connected will trigger a network activity notification.
3172             if (supportWifi) {
3173                 mCtsNetUtils.ensureWifiConnected();
3174             } else {
3175                 mCtsNetUtils.connectToCell();
3176             }
3177             assertTrue(future.get(LISTEN_ACTIVITY_TIMEOUT_MS, TimeUnit.MILLISECONDS));
3178         }, () -> {
3179                 mCm.removeDefaultNetworkActiveListener(listener);
3180             });
3181     }
3182 
3183     /**
3184      *  The networks used in this test are real networks and as such they can see seemingly random
3185      *  updates of their capabilities or link properties as conditions change, e.g. the network
3186      *  loses validation or IPv4 shows up. Many tests should simply treat these callbacks as
3187      *  spurious.
3188      */
3189     private void assertNoCallbackExceptCapOrLpChange(
3190             @NonNull final TestableNetworkCallback cb) {
3191         cb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS,
3192                 c -> !(c instanceof CallbackEntry.CapabilitiesChanged
3193                         || c instanceof CallbackEntry.LinkPropertiesChanged));
3194     }
3195 
3196     @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
3197     @Test
3198     public void testMobileDataPreferredUids() throws Exception {
3199         assumeTrue(TestUtils.shouldTestSApis());
3200         final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
3201                 && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
3202         assumeTrue("testMobileDataPreferredUidsWithCallback cannot execute"
3203                 + " unless device supports both WiFi and telephony", canRunTest);
3204 
3205         final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */);
3206         final Set<Integer> mobileDataPreferredUids =
3207                 ConnectivitySettingsManager.getMobileDataPreferredUids(mContext);
3208         // CtsNetTestCases uid should not list in MOBILE_DATA_PREFERRED_UIDS setting because it just
3209         // installs to device. In case the uid is existed in setting mistakenly, try to remove the
3210         // uid and set correct uids to setting.
3211         mobileDataPreferredUids.remove(uid);
3212         ConnectivitySettingsManager.setMobileDataPreferredUids(mContext, mobileDataPreferredUids);
3213 
3214         // For testing mobile data preferred uids feature, it needs both wifi and cell network.
3215         final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
3216         final Network cellNetwork = mCtsNetUtils.connectToCell();
3217         final TestableNetworkCallback defaultTrackingCb = new TestableNetworkCallback();
3218         final TestableNetworkCallback systemDefaultCb = new TestableNetworkCallback();
3219         final Handler h = new Handler(Looper.getMainLooper());
3220         runWithShellPermissionIdentity(() -> registerSystemDefaultNetworkCallback(
3221                 systemDefaultCb, h), NETWORK_SETTINGS);
3222         registerDefaultNetworkCallback(defaultTrackingCb);
3223 
3224         try {
3225             // CtsNetTestCases uid is not listed in MOBILE_DATA_PREFERRED_UIDS setting, so the
3226             // per-app default network should be same as system default network.
3227             waitForAvailable(systemDefaultCb, wifiNetwork);
3228             waitForAvailable(defaultTrackingCb, wifiNetwork);
3229             // Active network for CtsNetTestCases uid should be wifi now.
3230             assertEquals(wifiNetwork, mCm.getActiveNetwork());
3231 
3232             // Add CtsNetTestCases uid to MOBILE_DATA_PREFERRED_UIDS setting, then available per-app
3233             // default network callback should be received with cell network.
3234             final Set<Integer> newMobileDataPreferredUids = new ArraySet<>(mobileDataPreferredUids);
3235             newMobileDataPreferredUids.add(uid);
3236             ConnectivitySettingsManager.setMobileDataPreferredUids(
3237                     mContext, newMobileDataPreferredUids);
3238             waitForAvailable(defaultTrackingCb, cellNetwork);
3239             // No change for system default network. Expect no callback except CapabilitiesChanged
3240             // or LinkPropertiesChanged which may be triggered randomly from wifi network.
3241             assertNoCallbackExceptCapOrLpChange(systemDefaultCb);
3242             // Active network for CtsNetTestCases uid should change to cell, too.
3243             assertEquals(cellNetwork, mCm.getActiveNetwork());
3244 
3245             // Remove CtsNetTestCases uid from MOBILE_DATA_PREFERRED_UIDS setting, then available
3246             // per-app default network callback should be received again with system default network
3247             newMobileDataPreferredUids.remove(uid);
3248             ConnectivitySettingsManager.setMobileDataPreferredUids(
3249                     mContext, newMobileDataPreferredUids);
3250             waitForAvailable(defaultTrackingCb, wifiNetwork);
3251             // No change for system default network. Expect no callback except CapabilitiesChanged
3252             // or LinkPropertiesChanged which may be triggered randomly from wifi network.
3253             assertNoCallbackExceptCapOrLpChange(systemDefaultCb);
3254             // Active network for CtsNetTestCases uid should change back to wifi.
3255             assertEquals(wifiNetwork, mCm.getActiveNetwork());
3256         } finally {
3257             // Restore setting.
3258             ConnectivitySettingsManager.setMobileDataPreferredUids(
3259                     mContext, mobileDataPreferredUids);
3260         }
3261     }
3262 
3263     private void assertBindSocketToNetworkSuccess(final Network network) throws Exception {
3264         final CompletableFuture<Boolean> future = new CompletableFuture<>();
3265         final ExecutorService executor = Executors.newSingleThreadExecutor();
3266         try {
3267             executor.execute(() -> {
3268                 for (int i = 0; i < 300; i++) {
3269                     SystemClock.sleep(10);
3270 
3271                     try (Socket socket = new Socket()) {
3272                         network.bindSocket(socket);
3273                         future.complete(true);
3274                         return;
3275                     } catch (IOException e) { }
3276                 }
3277             });
3278             assertTrue(future.get(APPLYING_UIDS_ALLOWED_ON_RESTRICTED_NETWORKS_TIMEOUT_MS,
3279                     TimeUnit.MILLISECONDS));
3280         } finally {
3281             executor.shutdown();
3282         }
3283     }
3284 
3285     private static NetworkAgent createRestrictedNetworkAgent(final Context context) {
3286         // Create test network agent with restricted network.
3287         final NetworkCapabilities nc = new NetworkCapabilities.Builder()
3288                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
3289                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
3290                 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
3291                         TEST_RESTRICTED_NW_IFACE_NAME))
3292                 .build();
3293         final NetworkAgent agent = new NetworkAgent(context, Looper.getMainLooper(), TAG, nc,
3294                 new LinkProperties(), 10 /* score */, new NetworkAgentConfig.Builder().build(),
3295                 new NetworkProvider(context, Looper.getMainLooper(), TAG)) {};
3296         runWithShellPermissionIdentity(() -> agent.register(),
3297                 android.Manifest.permission.MANAGE_TEST_NETWORKS);
3298         agent.markConnected();
3299 
3300         return agent;
3301     }
3302 
3303     @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
3304     @Test
3305     public void testUidsAllowedOnRestrictedNetworks() throws Exception {
3306         assumeTestSApis();
3307 
3308         // TODO (b/175199465): figure out a reasonable permission check for
3309         //  setUidsAllowedOnRestrictedNetworks that allows tests but not system-external callers.
3310         assumeTrue(Build.isDebuggable());
3311 
3312         final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */);
3313         final Set<Integer> originalUidsAllowedOnRestrictedNetworks =
3314                 ConnectivitySettingsManager.getUidsAllowedOnRestrictedNetworks(mContext);
3315         // CtsNetTestCases uid should not list in UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting
3316         // because it has been just installed to device. In case the uid is existed in setting
3317         // mistakenly, try to remove the uid and set correct uids to setting.
3318         originalUidsAllowedOnRestrictedNetworks.remove(uid);
3319         runWithShellPermissionIdentity(() -> setUidsAllowedOnRestrictedNetworks(
3320                 mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
3321 
3322         // File a restricted network request with permission first to hold the connection.
3323         final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
3324         final NetworkRequest testRequest = new NetworkRequest.Builder()
3325                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
3326                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
3327                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
3328                 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
3329                         TEST_RESTRICTED_NW_IFACE_NAME))
3330                 .build();
3331         runWithShellPermissionIdentity(() -> requestNetwork(testRequest, testNetworkCb),
3332                 CONNECTIVITY_USE_RESTRICTED_NETWORKS);
3333 
3334         // File another restricted network request without permission.
3335         final TestableNetworkCallback restrictedNetworkCb = new TestableNetworkCallback();
3336         final NetworkRequest restrictedRequest = new NetworkRequest.Builder()
3337                 .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
3338                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
3339                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
3340                 .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
3341                         TEST_RESTRICTED_NW_IFACE_NAME))
3342                 .build();
3343         // Uid is not in allowed list and no permissions. Expect that SecurityException will throw.
3344         assertThrows(SecurityException.class,
3345                 () -> mCm.requestNetwork(restrictedRequest, restrictedNetworkCb));
3346 
3347         final NetworkAgent agent = createRestrictedNetworkAgent(mContext);
3348         final Network network = agent.getNetwork();
3349 
3350         try (Socket socket = new Socket()) {
3351             // Verify that the network is restricted.
3352             testNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
3353                     NETWORK_CALLBACK_TIMEOUT_MS,
3354                     entry -> network.equals(entry.getNetwork())
3355                             && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
3356                             .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
3357             // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
3358             // does not allow to bind socket to restricted network.
3359             assertThrows(IOException.class, () -> network.bindSocket(socket));
3360 
3361             // Add CtsNetTestCases uid to UIDS_ALLOWED_ON_RESTRICTED_NETWORKS setting, then it can
3362             // bind socket to restricted network normally.
3363             final Set<Integer> newUidsAllowedOnRestrictedNetworks =
3364                     new ArraySet<>(originalUidsAllowedOnRestrictedNetworks);
3365             newUidsAllowedOnRestrictedNetworks.add(uid);
3366             runWithShellPermissionIdentity(() -> setUidsAllowedOnRestrictedNetworks(
3367                     mContext, newUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
3368             // Wait a while for sending allowed uids on the restricted network to netd.
3369             // TODD: Have a significant signal to know the uids has been sent to netd.
3370             assertBindSocketToNetworkSuccess(network);
3371 
3372             if (TestUtils.shouldTestTApis()) {
3373                 // Uid is in allowed list. Try file network request again.
3374                 requestNetwork(restrictedRequest, restrictedNetworkCb);
3375                 // Verify that the network is restricted.
3376                 restrictedNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
3377                         NETWORK_CALLBACK_TIMEOUT_MS,
3378                         entry -> network.equals(entry.getNetwork())
3379                                 && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
3380                                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
3381             }
3382         } finally {
3383             agent.unregister();
3384 
3385             // Restore setting.
3386             runWithShellPermissionIdentity(() -> setUidsAllowedOnRestrictedNetworks(
3387                     mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
3388         }
3389     }
3390 
3391     @Test
3392     public void testDump() throws Exception {
3393         final String dumpOutput = DumpTestUtils.dumpServiceWithShellPermission(
3394                 Context.CONNECTIVITY_SERVICE, "--short");
3395         assertTrue(dumpOutput, dumpOutput.contains("Active default network"));
3396     }
3397 
3398     @Test @IgnoreUpTo(SC_V2)
3399     public void testDumpBpfNetMaps() throws Exception {
3400         final String[] args = new String[] {"--short", "trafficcontroller"};
3401         String dumpOutput = DumpTestUtils.dumpServiceWithShellPermission(
3402                 Context.CONNECTIVITY_SERVICE, args);
3403         assertTrue(dumpOutput, dumpOutput.contains("TrafficController"));
3404         assertFalse(dumpOutput, dumpOutput.contains("BPF map content"));
3405 
3406         dumpOutput = DumpTestUtils.dumpServiceWithShellPermission(
3407                 Context.CONNECTIVITY_SERVICE, args[1]);
3408         assertTrue(dumpOutput, dumpOutput.contains("BPF map content"));
3409     }
3410 
3411     private void checkFirewallBlocking(final DatagramSocket srcSock, final DatagramSocket dstSock,
3412             final boolean expectBlock, final int chain) throws Exception {
3413         final Random random = new Random();
3414         final byte[] sendData = new byte[100];
3415         random.nextBytes(sendData);
3416 
3417         final DatagramPacket pkt = new DatagramPacket(sendData, sendData.length,
3418                 InetAddresses.parseNumericAddress("::1"), dstSock.getLocalPort());
3419         try {
3420             srcSock.send(pkt);
3421         } catch (IOException e) {
3422             if (expectBlock) {
3423                 return;
3424             }
3425             fail("Expect not to be blocked by firewall but sending packet was blocked:"
3426                     + " chain=" + chain
3427                     + " chainEnabled=" + mCm.getFirewallChainEnabled(chain)
3428                     + " uidFirewallRule=" + mCm.getUidFirewallRule(chain, Process.myUid()));
3429         }
3430 
3431         dstSock.receive(pkt);
3432         assertArrayEquals(sendData, pkt.getData());
3433 
3434         if (expectBlock) {
3435             fail("Expect to be blocked by firewall but sending packet was not blocked:"
3436                     + " chain=" + chain
3437                     + " chainEnabled=" + mCm.getFirewallChainEnabled(chain)
3438                     + " uidFirewallRule=" + mCm.getUidFirewallRule(chain, Process.myUid()));
3439         }
3440     }
3441 
3442     private static final boolean EXPECT_PASS = false;
3443     private static final boolean EXPECT_BLOCK = true;
3444 
3445     // ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
3446     // DENYLIST means the firewall allows all by default, uids must be explicitly denyed
3447     private static final boolean ALLOWLIST = true;
3448     private static final boolean DENYLIST = false;
3449 
3450     private void doTestFirewallBlocking(final int chain, final boolean isAllowList) {
3451         final int myUid = Process.myUid();
3452         final int ruleToAddMatch = isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
3453         final int ruleToRemoveMatch = isAllowList ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW;
3454 
3455         runWithShellPermissionIdentity(() -> {
3456             // Firewall chain status will be restored after the test.
3457             final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain);
3458             final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, myUid);
3459             final DatagramSocket srcSock = new DatagramSocket();
3460             final DatagramSocket dstSock = new DatagramSocket();
3461             testAndCleanup(() -> {
3462                 if (wasChainEnabled) {
3463                     mCm.setFirewallChainEnabled(chain, false /* enable */);
3464                 }
3465                 if (previousUidFirewallRule == ruleToAddMatch) {
3466                     mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch);
3467                 }
3468                 dstSock.setSoTimeout(SOCKET_TIMEOUT_MS);
3469 
3470                 // Chain disabled, UID not on chain.
3471                 checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS, chain);
3472 
3473                 // Chain enabled, UID not on chain.
3474                 mCm.setFirewallChainEnabled(chain, true /* enable */);
3475                 assertTrue(mCm.getFirewallChainEnabled(chain));
3476                 checkFirewallBlocking(
3477                         srcSock, dstSock, isAllowList ? EXPECT_BLOCK : EXPECT_PASS, chain);
3478 
3479                 // Chain enabled, UID on chain.
3480                 mCm.setUidFirewallRule(chain, myUid, ruleToAddMatch);
3481                 checkFirewallBlocking(
3482                         srcSock, dstSock, isAllowList ?  EXPECT_PASS : EXPECT_BLOCK, chain);
3483 
3484                 // Chain disabled, UID on chain.
3485                 mCm.setFirewallChainEnabled(chain, false /* enable */);
3486                 assertFalse(mCm.getFirewallChainEnabled(chain));
3487                 checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS, chain);
3488 
3489                 // Chain disabled, UID not on chain.
3490                 mCm.setUidFirewallRule(chain, myUid, ruleToRemoveMatch);
3491                 checkFirewallBlocking(srcSock, dstSock, EXPECT_PASS, chain);
3492             }, /* cleanup */ () -> {
3493                     srcSock.close();
3494                     dstSock.close();
3495                 }, /* cleanup */ () -> {
3496                     // Restore the global chain status
3497                     mCm.setFirewallChainEnabled(chain, wasChainEnabled);
3498                 }, /* cleanup */ () -> {
3499                     // Restore the uid firewall rule status
3500                     try {
3501                         mCm.setUidFirewallRule(chain, myUid, previousUidFirewallRule);
3502                     } catch (IllegalStateException ignored) {
3503                         // Removing match causes an exception when the rule entry for the uid does
3504                         // not exist. But this is fine and can be ignored.
3505                     }
3506                 });
3507         }, NETWORK_SETTINGS);
3508     }
3509 
3510     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3511     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3512     public void testFirewallBlockingDozable() {
3513         doTestFirewallBlocking(FIREWALL_CHAIN_DOZABLE, ALLOWLIST);
3514     }
3515 
3516     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3517     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3518     public void testFirewallBlockingPowersave() {
3519         doTestFirewallBlocking(FIREWALL_CHAIN_POWERSAVE, ALLOWLIST);
3520     }
3521 
3522     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3523     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3524     public void testFirewallBlockingRestricted() {
3525         doTestFirewallBlocking(FIREWALL_CHAIN_RESTRICTED, ALLOWLIST);
3526     }
3527 
3528     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3529     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3530     public void testFirewallBlockingLowPowerStandby() {
3531         doTestFirewallBlocking(FIREWALL_CHAIN_LOW_POWER_STANDBY, ALLOWLIST);
3532     }
3533 
3534     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3535     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3536     public void testFirewallBlockingStandby() {
3537         doTestFirewallBlocking(FIREWALL_CHAIN_STANDBY, DENYLIST);
3538     }
3539 
3540     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3541     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3542     public void testFirewallBlockingOemDeny1() {
3543         doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_1, DENYLIST);
3544     }
3545 
3546     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3547     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3548     public void testFirewallBlockingOemDeny2() {
3549         doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_2, DENYLIST);
3550     }
3551 
3552     @Test @IgnoreUpTo(SC_V2) @ConnectivityModuleTest
3553     @AppModeFull(reason = "Socket cannot bind in instant app mode")
3554     public void testFirewallBlockingOemDeny3() {
3555         doTestFirewallBlocking(FIREWALL_CHAIN_OEM_DENY_3, DENYLIST);
3556     }
3557 
3558     private void assertSocketOpen(final Socket socket) throws Exception {
3559         mCtsNetUtils.testHttpRequest(socket);
3560     }
3561 
3562     private void assertSocketClosed(final Socket socket) throws Exception {
3563         try {
3564             mCtsNetUtils.testHttpRequest(socket);
3565             fail("Socket is expected to be closed");
3566         } catch (SocketException expected) {
3567         }
3568     }
3569 
3570     private static final boolean EXPECT_OPEN = false;
3571     private static final boolean EXPECT_CLOSE = true;
3572 
3573     private void doTestFirewallCloseSocket(final int chain, final int rule, final int targetUid,
3574             final boolean expectClose) {
3575         runWithShellPermissionIdentity(() -> {
3576             // Firewall chain status will be restored after the test.
3577             final boolean wasChainEnabled = mCm.getFirewallChainEnabled(chain);
3578             final int previousUidFirewallRule = mCm.getUidFirewallRule(chain, targetUid);
3579             final Socket socket = new Socket(TEST_HOST, HTTP_PORT);
3580             socket.setSoTimeout(NETWORK_REQUEST_TIMEOUT_MS);
3581             testAndCleanup(() -> {
3582                 mCm.setFirewallChainEnabled(chain, false /* enable */);
3583                 assertSocketOpen(socket);
3584 
3585                 try {
3586                     mCm.setUidFirewallRule(chain, targetUid, rule);
3587                 } catch (IllegalStateException ignored) {
3588                     // Removing match causes an exception when the rule entry for the uid does
3589                     // not exist. But this is fine and can be ignored.
3590                 }
3591                 mCm.setFirewallChainEnabled(chain, true /* enable */);
3592 
3593                 if (expectClose) {
3594                     assertSocketClosed(socket);
3595                 } else {
3596                     assertSocketOpen(socket);
3597                 }
3598             }, /* cleanup */ () -> {
3599                     // Restore the global chain status
3600                     mCm.setFirewallChainEnabled(chain, wasChainEnabled);
3601                 }, /* cleanup */ () -> {
3602                     // Restore the uid firewall rule status
3603                     try {
3604                         mCm.setUidFirewallRule(chain, targetUid, previousUidFirewallRule);
3605                     } catch (IllegalStateException ignored) {
3606                         // Removing match causes an exception when the rule entry for the uid does
3607                         // not exist. But this is fine and can be ignored.
3608                     }
3609                 }, /* cleanup */ () -> {
3610                     socket.close();
3611                 });
3612         }, NETWORK_SETTINGS);
3613     }
3614 
3615     @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest
3616     public void testFirewallCloseSocketAllowlistChainAllow() {
3617         doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_ALLOW,
3618                 Process.myUid(), EXPECT_OPEN);
3619     }
3620 
3621     @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest
3622     public void testFirewallCloseSocketAllowlistChainDeny() {
3623         doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_DENY,
3624                 Process.myUid(), EXPECT_CLOSE);
3625     }
3626 
3627     @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest
3628     public void testFirewallCloseSocketAllowlistChainOtherUid() {
3629         doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_ALLOW,
3630                 Process.myUid() + 1, EXPECT_CLOSE);
3631         doTestFirewallCloseSocket(FIREWALL_CHAIN_DOZABLE, FIREWALL_RULE_DENY,
3632                 Process.myUid() + 1, EXPECT_CLOSE);
3633     }
3634 
3635     @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest
3636     public void testFirewallCloseSocketDenylistChainAllow() {
3637         doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_ALLOW,
3638                 Process.myUid(), EXPECT_OPEN);
3639     }
3640 
3641     @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest
3642     public void testFirewallCloseSocketDenylistChainDeny() {
3643         doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_DENY,
3644                 Process.myUid(), EXPECT_CLOSE);
3645     }
3646 
3647     @Test @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) @ConnectivityModuleTest
3648     public void testFirewallCloseSocketDenylistChainOtherUid() {
3649         doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_ALLOW,
3650                 Process.myUid() + 1, EXPECT_OPEN);
3651         doTestFirewallCloseSocket(FIREWALL_CHAIN_STANDBY, FIREWALL_RULE_DENY,
3652                 Process.myUid() + 1, EXPECT_OPEN);
3653     }
3654 
3655     private void assumeTestSApis() {
3656         // Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
3657         // shims, and @IgnoreUpTo does not check that.
3658         assumeTrue(TestUtils.shouldTestSApis());
3659     }
3660 
3661     private void unregisterRegisteredCallbacks() {
3662         for (NetworkCallback callback: mRegisteredCallbacks) {
3663             mCm.unregisterNetworkCallback(callback);
3664         }
3665     }
3666 
3667     private void registerDefaultNetworkCallback(NetworkCallback callback) {
3668         mCm.registerDefaultNetworkCallback(callback);
3669         mRegisteredCallbacks.add(callback);
3670     }
3671 
3672     private void registerDefaultNetworkCallback(NetworkCallback callback, Handler handler) {
3673         mCm.registerDefaultNetworkCallback(callback, handler);
3674         mRegisteredCallbacks.add(callback);
3675     }
3676 
3677     private void registerNetworkCallback(NetworkRequest request, NetworkCallback callback) {
3678         mCm.registerNetworkCallback(request, callback);
3679         mRegisteredCallbacks.add(callback);
3680     }
3681 
3682     private void registerSystemDefaultNetworkCallback(NetworkCallback callback, Handler handler) {
3683         mCmShim.registerSystemDefaultNetworkCallback(callback, handler);
3684         mRegisteredCallbacks.add(callback);
3685     }
3686 
3687     private void registerDefaultNetworkCallbackForUid(int uid, NetworkCallback callback,
3688             Handler handler) throws Exception {
3689         mCmShim.registerDefaultNetworkCallbackForUid(uid, callback, handler);
3690         mRegisteredCallbacks.add(callback);
3691     }
3692 
3693     private void requestNetwork(NetworkRequest request, NetworkCallback callback) {
3694         mCm.requestNetwork(request, callback);
3695         mRegisteredCallbacks.add(callback);
3696     }
3697 
3698     private void requestNetwork(NetworkRequest request, NetworkCallback callback, int timeoutSec) {
3699         mCm.requestNetwork(request, callback, timeoutSec);
3700         mRegisteredCallbacks.add(callback);
3701     }
3702 
3703     private void registerBestMatchingNetworkCallback(NetworkRequest request,
3704             NetworkCallback callback, Handler handler) {
3705         mCm.registerBestMatchingNetworkCallback(request, callback, handler);
3706         mRegisteredCallbacks.add(callback);
3707     }
3708 
3709     private void requestBackgroundNetwork(NetworkRequest request, NetworkCallback callback,
3710             Handler handler) throws Exception {
3711         mCmShim.requestBackgroundNetwork(request, callback, handler);
3712         mRegisteredCallbacks.add(callback);
3713     }
3714 }
3715