Merge "Use READ_PHONE_STATE when checking Carrier Configs."
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 5526c65..23aa7f8 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -17,6 +17,7 @@
 java_defaults {
     name: "TetheringAndroidLibraryDefaults",
     sdk_version: "module_current",
+    min_sdk_version: "30",
     srcs: [
         "src/**/*.java",
         ":framework-tethering-shared-srcs",
@@ -58,7 +59,7 @@
         "//apex_available:platform", // Used by InProcessTethering
         "com.android.tethering",
     ],
-    min_sdk_version: "current",
+    min_sdk_version: "30",
     srcs: [
         "jni/android_net_util_TetheringUtils.cpp",
     ],
@@ -119,7 +120,7 @@
     // InProcessTethering is a replacement for Tethering
     overrides: ["Tethering"],
     apex_available: ["com.android.tethering"],
-    min_sdk_version: "current",
+    min_sdk_version: "30",
 }
 
 // Updatable tethering packaged as an application
@@ -133,5 +134,5 @@
     // The permission configuration *must* be included to ensure security of the device
     required: ["NetworkPermissionConfig"],
     apex_available: ["com.android.tethering"],
-    min_sdk_version: "current",
+    min_sdk_version: "30",
 }
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 0524374..a1e7fd2 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -17,7 +17,7 @@
 apex {
     name: "com.android.tethering",
     updatable: true,
-    min_sdk_version: "current",
+    min_sdk_version: "30",
     java_libs: ["framework-tethering"],
     bpfs: ["offload.o"],
     apps: ["Tethering"],
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index ddb6880..a10729d 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -29,6 +29,7 @@
     hostdex: true, // for hiddenapi check
     apex_available: ["com.android.tethering"],
     permitted_packages: ["android.net"],
+    min_sdk_version: "30",
 }
 
 filegroup {
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 5a0c5b0..2c91d10 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -1080,8 +1080,13 @@
     }
 
     @VisibleForTesting
+    SparseArray<TetheringRequestParcel> getActiveTetheringRequests() {
+        return mActiveTetheringRequests;
+    }
+
+    @VisibleForTesting
     boolean isTetheringActive() {
-        return mActiveTetheringRequests.size() > 0;
+        return getTetheredIfaces().length > 0;
     }
 
     @VisibleForTesting
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 114cb7c..0a37f54 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -52,6 +52,7 @@
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
 import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
+import static com.android.networkstack.tethering.Tethering.UserRestrictionActionListener;
 import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
 import static com.android.networkstack.tethering.UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES;
 
@@ -125,6 +126,7 @@
 import android.net.wifi.p2p.WifiP2pGroup;
 import android.net.wifi.p2p.WifiP2pInfo;
 import android.net.wifi.p2p.WifiP2pManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -734,9 +736,12 @@
         initTetheringUpstream(upstreamState);
 
         // Emulate pressing the USB tethering button in Settings UI.
-        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
+        final TetheringRequestParcel request = createTetheringRequestParcel(TETHERING_USB);
+        mTethering.startTethering(request, null);
         mLooper.dispatchAll();
         verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
+        assertEquals(1, mTethering.getActiveTetheringRequests().size());
+        assertEquals(request, mTethering.getActiveTetheringRequests().get(TETHERING_USB));
 
         mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
     }
@@ -844,6 +849,14 @@
         mLooper.dispatchAll();
     }
 
+    private void assertSetIfaceToDadProxy(final int numOfCalls, final String ifaceName) {
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME)
+                    || "T".equals(Build.VERSION.CODENAME)) {
+            verify(mDadProxy, times(numOfCalls)).setUpstreamIface(
+                     argThat(ifaceParams  -> ifaceName.equals(ifaceParams.name)));
+        }
+    }
+
     @Test
     public void workingMobileUsbTethering_IPv4() throws Exception {
         UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
@@ -853,7 +866,7 @@
         verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
 
         sendIPv6TetherUpdates(upstreamState);
-        verify(mDadProxy, never()).setUpstreamIface(notNull());
+        assertSetIfaceToDadProxy(0 /* numOfCalls */, "" /* ifaceName */);
         verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
         verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
                 any(), any());
@@ -881,7 +894,7 @@
 
         sendIPv6TetherUpdates(upstreamState);
         // TODO: add interfaceParams to compare in verify.
-        verify(mDadProxy, times(1)).setUpstreamIface(notNull());
+        assertSetIfaceToDadProxy(1 /* numOfCalls */, TEST_MOBILE_IFNAME /* ifaceName */);
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
     }
@@ -898,7 +911,7 @@
                 any(), any());
 
         sendIPv6TetherUpdates(upstreamState);
-        verify(mDadProxy, times(1)).setUpstreamIface(notNull());
+        assertSetIfaceToDadProxy(1 /* numOfCalls */, TEST_MOBILE_IFNAME /* ifaceName */);
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
     }
@@ -916,7 +929,7 @@
         verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
 
         sendIPv6TetherUpdates(upstreamState);
-        verify(mDadProxy, times(1)).setUpstreamIface(notNull());
+        assertSetIfaceToDadProxy(1 /* numOfCalls */, TEST_MOBILE_IFNAME /* ifaceName */);
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
     }
@@ -1165,20 +1178,26 @@
         verifyNoMoreInteractions(mNetd);
     }
 
+    private UserRestrictionActionListener makeUserRestrictionActionListener(
+            final Tethering tethering, final boolean currentDisallow, final boolean nextDisallow) {
+        final Bundle newRestrictions = new Bundle();
+        newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
+        when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
+
+        final UserRestrictionActionListener ural =
+                new UserRestrictionActionListener(mUserManager, tethering, mNotificationUpdater);
+        ural.mDisallowTethering = currentDisallow;
+        return ural;
+    }
+
     private void runUserRestrictionsChange(
             boolean currentDisallow, boolean nextDisallow, boolean isTetheringActive,
             int expectedInteractionsWithShowNotification) throws  Exception {
-        final Bundle newRestrictions = new Bundle();
-        newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
         final Tethering mockTethering = mock(Tethering.class);
         when(mockTethering.isTetheringActive()).thenReturn(isTetheringActive);
-        when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
 
-        final Tethering.UserRestrictionActionListener ural =
-                new Tethering.UserRestrictionActionListener(
-                        mUserManager, mockTethering, mNotificationUpdater);
-        ural.mDisallowTethering = currentDisallow;
-
+        final UserRestrictionActionListener ural =
+                makeUserRestrictionActionListener(mockTethering, currentDisallow, nextDisallow);
         ural.onUserRestrictionsChanged();
 
         verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
@@ -1247,6 +1266,27 @@
                 expectedInteractionsWithShowNotification);
     }
 
+    @Test
+    public void testUntetherUsbWhenRestrictionIsOn() {
+        // Start usb tethering and check that usb interface is tethered.
+        final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
+        runUsbTethering(upstreamState);
+        assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
+        assertTrue(mTethering.isTetheringActive());
+        assertEquals(0, mTethering.getActiveTetheringRequests().size());
+
+        final Tethering.UserRestrictionActionListener ural = makeUserRestrictionActionListener(
+                mTethering, false /* currentDisallow */, true /* nextDisallow */);
+
+        ural.onUserRestrictionsChanged();
+        mLooper.dispatchAll();
+
+        // Verify that restriction notification has showed to user.
+        verify(mNotificationUpdater, times(1)).notifyTetheringDisabledByRestriction();
+        // Verify that usb tethering has been disabled.
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
+    }
+
     private class TestTetheringEventCallback extends ITetheringEventCallback.Stub {
         private final ArrayList<Network> mActualUpstreams = new ArrayList<>();
         private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs =
diff --git a/tests/cts/net/OWNERS b/tests/cts/net/OWNERS
index d558556..7722bb3 100644
--- a/tests/cts/net/OWNERS
+++ b/tests/cts/net/OWNERS
@@ -1,3 +1,5 @@
 # Bug component: 31808
 lorenzo@google.com
 satk@google.com
+
+per-file src/android/net/cts/NetworkWatchlistTest.java=alanstokes@google.com
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index db4e3e7..cbf43e7 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.net.cts;
 
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.content.pm.PackageManager.FEATURE_ETHERNET;
@@ -1517,7 +1518,10 @@
 
     @Test
     public void testGetCaptivePortalServerUrl() {
-        final String url = runAsShell(NETWORK_SETTINGS, mCm::getCaptivePortalServerUrl);
+        final String permission = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q
+                ? CONNECTIVITY_INTERNAL
+                : NETWORK_SETTINGS;
+        final String url = runAsShell(permission, mCm::getCaptivePortalServerUrl);
         assertNotNull("getCaptivePortalServerUrl must not be null", url);
         try {
             final URL parsedUrl = new URL(url);
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 34c6541..0527011 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -16,6 +16,7 @@
 
 package android.net.cts.util;
 
+import static android.Manifest.permission.ACCESS_WIFI_STATE;
 import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -331,7 +332,7 @@
      * to them.
      */
     private void clearWifiBlacklist() {
-        runAsShell(NETWORK_SETTINGS, () -> {
+        runAsShell(NETWORK_SETTINGS, ACCESS_WIFI_STATE, () -> {
             for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) {
                 assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */));
             }