Merge changes I2aedd1f1,I9bdf8d07

* changes:
  gn2bp: Cancel -DANDROID if it's not specified
  gn2bp: Added required include PATH
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 1f3fc11..c2cf92c 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -477,17 +477,10 @@
             wifiManager.registerSoftApCallback(mExecutor, softApCallback);
         }
         if (SdkLevel.isAtLeastT() && wifiManager != null) {
-            try {
-                // Although WifiManager#registerLocalOnlyHotspotSoftApCallback document that it need
-                // NEARBY_WIFI_DEVICES permission, but actually a caller who have NETWORK_STACK
-                // or MAINLINE_NETWORK_STACK permission would also able to use this API.
-                wifiManager.registerLocalOnlyHotspotSoftApCallback(mExecutor, softApCallback);
-            } catch (UnsupportedOperationException e) {
-                // Since wifi module development in internal branch,
-                // #registerLocalOnlyHotspotSoftApCallback currently doesn't supported in AOSP
-                // before AOSP switch to Android T + 1.
-                Log.wtf(TAG, "registerLocalOnlyHotspotSoftApCallback API is not supported");
-            }
+            // Although WifiManager#registerLocalOnlyHotspotSoftApCallback document that it need
+            // NEARBY_WIFI_DEVICES permission, but actually a caller who have NETWORK_STACK
+            // or MAINLINE_NETWORK_STACK permission would also able to use this API.
+            wifiManager.registerLocalOnlyHotspotSoftApCallback(mExecutor, softApCallback);
         }
 
         startTrackDefaultNetwork();
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 8ef5d71..7ed4725 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -22,6 +22,7 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
+import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
 
 import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
 import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL;
@@ -194,7 +195,7 @@
         isDunRequired = checkDunRequired(ctx);
 
         final boolean forceAutomaticUpstream = !SdkLevel.isAtLeastS()
-                && isFeatureEnabled(ctx, TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION);
+                && isConnectivityFeatureEnabled(ctx, TETHER_FORCE_UPSTREAM_AUTOMATIC_VERSION);
         chooseUpstreamAutomatically = forceAutomaticUpstream || getResourceBoolean(
                 res, R.bool.config_tether_upstream_automatic, false /** defaultValue */);
         preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
@@ -565,9 +566,23 @@
         return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name);
     }
 
+    /**
+     * This is deprecated because connectivity namespace already be used for NetworkStack mainline
+     * module. Tethering should use its own namespace to roll out the feature flag.
+     * @deprecated new caller should use isTetheringFeatureEnabled instead.
+     */
+    @Deprecated
+    private boolean isConnectivityFeatureEnabled(Context ctx, String featureVersionFlag) {
+        return isFeatureEnabled(ctx, NAMESPACE_CONNECTIVITY, featureVersionFlag);
+    }
+
+    private boolean isTetheringFeatureEnabled(Context ctx, String featureVersionFlag) {
+        return isFeatureEnabled(ctx, NAMESPACE_TETHERING, featureVersionFlag);
+    }
+
     @VisibleForTesting
-    protected boolean isFeatureEnabled(Context ctx, String featureVersionFlag) {
-        return DeviceConfigUtils.isFeatureEnabled(ctx, NAMESPACE_CONNECTIVITY, featureVersionFlag,
+    protected boolean isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag) {
+        return DeviceConfigUtils.isFeatureEnabled(ctx, namespace, featureVersionFlag,
                 TETHERING_MODULE_NAME, false /* defaultEnabled */);
     }
 
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
index 95ec38f..0d686ed 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/FakeTetheringConfiguration.java
@@ -33,7 +33,7 @@
     }
 
     @Override
-    protected boolean isFeatureEnabled(Context ctx, String featureVersionFlag) {
+    protected boolean isFeatureEnabled(Context ctx, String namespace, String featureVersionFlag) {
         return false;
     }
 
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 073cca2..752c347 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -228,13 +228,9 @@
   }
 
   public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
-    ctor public VpnTransportInfo(int, @Nullable String);
-    method public int describeContents();
+    ctor @Deprecated public VpnTransportInfo(int, @Nullable String);
     method @Nullable public String getSessionId();
-    method public int getType();
     method @NonNull public android.net.VpnTransportInfo makeCopy(long);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
   }
 
 }
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 8b35197..c7872a0 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -511,6 +511,15 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
   }
 
+  public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+    ctor public VpnTransportInfo(int, @Nullable String, boolean);
+    method public int describeContents();
+    method public boolean getBypassable();
+    method public int getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+  }
+
 }
 
 package android.net.apf {
diff --git a/framework/src/android/net/VpnTransportInfo.java b/framework/src/android/net/VpnTransportInfo.java
index 4071c9a..ebad477 100644
--- a/framework/src/android/net/VpnTransportInfo.java
+++ b/framework/src/android/net/VpnTransportInfo.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.annotation.SystemApi.Client.PRIVILEGED_APPS;
 import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
 
 import android.annotation.NonNull;
@@ -27,6 +28,10 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import androidx.annotation.RequiresApi;
+
+import com.android.modules.utils.build.SdkLevel;
+
 import java.util.Objects;
 
 /**
@@ -37,7 +42,7 @@
  *
  * @hide
  */
-@SystemApi(client = MODULE_LIBRARIES)
+@SystemApi(client = PRIVILEGED_APPS)
 public final class VpnTransportInfo implements TransportInfo, Parcelable {
     /** Type of this VPN. */
     private final int mType;
@@ -45,6 +50,13 @@
     @Nullable
     private final String mSessionId;
 
+    private final boolean mBypassable;
+
+    // TODO: Refer to Build.VERSION_CODES when it's available in every branch.
+    private static final int UPSIDE_DOWN_CAKE = 34;
+
+    /** @hide */
+    @SystemApi(client = MODULE_LIBRARIES)
     @Override
     public @RedactionType long getApplicableRedactions() {
         return REDACT_FOR_NETWORK_SETTINGS;
@@ -52,21 +64,58 @@
 
     /**
      * Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
+     * @hide
      */
     @NonNull
+    @SystemApi(client = MODULE_LIBRARIES)
     public VpnTransportInfo makeCopy(@RedactionType long redactions) {
         return new VpnTransportInfo(mType,
-            ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : mSessionId);
+            ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : mSessionId, mBypassable);
     }
 
+    /**
+     * @deprecated please use {@link VpnTransportInfo(int,String,boolean)} instead.
+     * @hide
+     */
+    @Deprecated
+    @SystemApi(client = MODULE_LIBRARIES)
     public VpnTransportInfo(int type, @Nullable String sessionId) {
+        // When the module runs on older SDKs, |bypassable| will always be false since the old Vpn
+        // code will call this constructor. For Settings VPNs, this is always correct as they are
+        // never bypassable. For VpnManager and VpnService types, this may be wrong since both of
+        // them have a choice. However, on these SDKs VpnTransportInfo#getBypassable is not
+        // available anyway, so this should be harmless. False is a better choice than true here
+        // regardless because it is the default value for both VpnManager and VpnService if the app
+        // does not do anything about it.
+        this(type, sessionId, false /* bypassable */);
+    }
+
+    public VpnTransportInfo(int type, @Nullable String sessionId, boolean bypassable) {
         this.mType = type;
         this.mSessionId = sessionId;
+        this.mBypassable = bypassable;
+    }
+
+    /**
+     * Returns whether the VPN is allowing bypass.
+     *
+     * This method is not supported in SDK below U, and will throw
+     * {@code UnsupportedOperationException} if called.
+     */
+    @RequiresApi(UPSIDE_DOWN_CAKE)
+    public boolean getBypassable() {
+        if (!SdkLevel.isAtLeastU()) {
+            throw new UnsupportedOperationException("Not supported before U");
+        }
+
+        return mBypassable;
     }
 
     /**
      * Returns the session Id of this VpnTransportInfo.
+     * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     @Nullable
     public String getSessionId() {
         return mSessionId;
@@ -84,17 +133,19 @@
         if (!(o instanceof VpnTransportInfo)) return false;
 
         VpnTransportInfo that = (VpnTransportInfo) o;
-        return (this.mType == that.mType) && TextUtils.equals(this.mSessionId, that.mSessionId);
+        return (this.mType == that.mType) && TextUtils.equals(this.mSessionId, that.mSessionId)
+                && (this.mBypassable == that.mBypassable);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mType, mSessionId);
+        return Objects.hash(mType, mSessionId, mBypassable);
     }
 
     @Override
     public String toString() {
-        return String.format("VpnTransportInfo{type=%d, sessionId=%s}", mType, mSessionId);
+        return String.format("VpnTransportInfo{type=%d, sessionId=%s, bypassable=%b}",
+                mType, mSessionId, mBypassable);
     }
 
     @Override
@@ -106,12 +157,13 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mType);
         dest.writeString(mSessionId);
+        dest.writeBoolean(mBypassable);
     }
 
     public static final @NonNull Creator<VpnTransportInfo> CREATOR =
             new Creator<VpnTransportInfo>() {
         public VpnTransportInfo createFromParcel(Parcel in) {
-            return new VpnTransportInfo(in.readInt(), in.readString());
+            return new VpnTransportInfo(in.readInt(), in.readString(), in.readBoolean());
         }
         public VpnTransportInfo[] newArray(int size) {
             return new VpnTransportInfo[size];
diff --git a/service/Android.bp b/service/Android.bp
index 326f91b..691c1ad 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -178,7 +178,10 @@
         "networkstack-client",
         "PlatformProperties",
         "service-connectivity-protos",
-        "service-connectivity-stats-protos",
+        // TODO: Adding the stats protos currently affects test coverage.
+        // So remove the protos in ConnectivityService until all
+        // tests for proto apis are added.
+        //"service-connectivity-stats-protos",
         "NetworkStackApiStableShims",
     ],
     apex_available: [
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index fd219d2..f796ecc 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -2378,8 +2378,9 @@
             super.expectAvailableCallbacks(network, false /* suspended */, true /* validated */,
                     BLOCKED_REASON_NONE, NETWORK_CALLBACK_TIMEOUT_MS);
         }
-        public void expectBlockedStatusCallback(Network network, int blockedStatus) {
-            super.expectBlockedStatusCallback(blockedStatus, network, NETWORK_CALLBACK_TIMEOUT_MS);
+        public void eventuallyExpectBlockedStatusCallback(Network network, int blockedStatus) {
+            super.eventuallyExpect(CallbackEntry.BLOCKED_STATUS_INT, NETWORK_CALLBACK_TIMEOUT_MS,
+                    (it) -> it.getNetwork().equals(network) && it.getBlocked() == blockedStatus);
         }
         public void onBlockedStatusChanged(Network network, int blockedReasons) {
             getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
@@ -2424,12 +2425,14 @@
         final Range<Integer> otherUidRange = new Range<>(otherUid, otherUid);
 
         setRequireVpnForUids(true, List.of(myUidRange));
-        myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN);
+        myUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork,
+                BLOCKED_REASON_LOCKDOWN_VPN);
         otherUidCallback.assertNoBlockedStatusCallback();
 
         setRequireVpnForUids(true, List.of(myUidRange, otherUidRange));
         myUidCallback.assertNoBlockedStatusCallback();
-        otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_LOCKDOWN_VPN);
+        otherUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork,
+                BLOCKED_REASON_LOCKDOWN_VPN);
 
         // setRequireVpnForUids does no deduplication or refcounting. Removing myUidRange does not
         // unblock myUid because it was added to the blocked ranges twice.
@@ -2438,8 +2441,8 @@
         otherUidCallback.assertNoBlockedStatusCallback();
 
         setRequireVpnForUids(false, List.of(myUidRange, otherUidRange));
-        myUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
-        otherUidCallback.expectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
+        myUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
+        otherUidCallback.eventuallyExpectBlockedStatusCallback(defaultNetwork, BLOCKED_REASON_NONE);
 
         myUidCallback.assertNoBlockedStatusCallback();
         otherUidCallback.assertNoBlockedStatusCallback();
diff --git a/tests/cts/net/src/android/net/cts/TestUtils.java b/tests/cts/net/src/android/net/cts/TestUtils.java
index 001aa01..6180845 100644
--- a/tests/cts/net/src/android/net/cts/TestUtils.java
+++ b/tests/cts/net/src/android/net/cts/TestUtils.java
@@ -16,8 +16,6 @@
 
 package android.net.cts;
 
-import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
-
 import android.os.Build;
 
 import com.android.modules.utils.build.SdkLevel;
@@ -37,11 +35,18 @@
     }
 
     /**
-     * Whether to test T+ APIs. This requires a) that the test be running on an S+ device, and
+     * Whether to test T+ APIs. This requires a) that the test be running on an T+ device, and
      * b) that the code be compiled against shims new enough to access these APIs.
      */
     public static boolean shouldTestTApis() {
-        // TODO: replace SC_V2 with Build.VERSION_CODES.S_V2 when it's available in mainline branch.
-        return SdkLevel.isAtLeastT() && ConstantsShim.VERSION > SC_V2;
+        return SdkLevel.isAtLeastT() && ConstantsShim.VERSION > Build.VERSION_CODES.S_V2;
+    }
+
+    /**
+     * Whether to test U+ APIs. This requires a) that the test be running on an U+ device, and
+     * b) that the code be compiled against shims new enough to access these APIs.
+     */
+    public static boolean shouldTestUApis() {
+        return SdkLevel.isAtLeastU() && ConstantsShim.VERSION > Build.VERSION_CODES.TIRAMISU;
     }
 }
diff --git a/tests/unit/java/android/net/VpnTransportInfoTest.java b/tests/unit/java/android/net/VpnTransportInfoTest.java
index b4c7ac4..0510209 100644
--- a/tests/unit/java/android/net/VpnTransportInfoTest.java
+++ b/tests/unit/java/android/net/VpnTransportInfoTest.java
@@ -19,10 +19,13 @@
 import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
 import static android.net.NetworkCapabilities.REDACT_NONE;
 
+import static com.android.testutils.MiscAsserts.assertThrows;
 import static com.android.testutils.ParcelUtils.assertParcelSane;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.os.Build;
 
@@ -31,6 +34,7 @@
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRunner;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -38,36 +42,67 @@
 @SmallTest
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
 public class VpnTransportInfoTest {
+    @Rule
+    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
 
     @Test
     public void testParceling() {
-        VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
-        assertParcelSane(v, 2 /* fieldCount */);
+        final VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
+        assertParcelSane(v, 3 /* fieldCount */);
+
+        final VpnTransportInfo v2 =
+                new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345", true);
+        assertParcelSane(v2, 3 /* fieldCount */);
     }
 
     @Test
     public void testEqualsAndHashCode() {
         String session1 = "12345";
         String session2 = "6789";
-        VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
-        VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
-        VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
-        VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
-        VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
-        VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
+        final VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+        final VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
+        final VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+        final VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
+        final VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
+        final VpnTransportInfo v16 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1, true);
+        final VpnTransportInfo v17 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1, true);
+        final VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
 
-        VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
-        VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+        final VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+        final VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+        final VpnTransportInfo v33 = v16.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+        final VpnTransportInfo v34 = v17.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
 
         assertNotEquals(v11, v12);
         assertNotEquals(v13, v14);
         assertNotEquals(v14, v15);
         assertNotEquals(v14, v21);
+        assertNotEquals(v15, v16);
 
         assertEquals(v11, v13);
         assertEquals(v31, v32);
+        assertEquals(v33, v34);
         assertEquals(v11.hashCode(), v13.hashCode());
+        assertEquals(v16.hashCode(), v17.hashCode());
         assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
         assertEquals(session1, v15.makeCopy(REDACT_NONE).getSessionId());
     }
+
+    @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.TIRAMISU)
+    @Test
+    public void testGetBypassable_beforeU() {
+        final VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
+        assertThrows(UnsupportedOperationException.class, () -> v.getBypassable());
+    }
+
+    @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+    @Test
+    public void testGetBypassable_afterU() {
+        final VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
+        assertFalse(v.getBypassable());
+
+        final VpnTransportInfo v2 =
+                new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345", true);
+        assertTrue(v2.getBypassable());
+    }
 }