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