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