Merge "Add VCN underlying networks" am: 447fbc3788 am: b9c06bc020

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1750241

Change-Id: I93ec50a1004dc79352dd72270828cb199e0e150d
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 3214e92..7ddd135 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -409,7 +409,7 @@
     }
 
     private void reevaluateNetworks() {
-        if (mRouteSelectionCallback == null) {
+        if (mIsQuitting || mRouteSelectionCallback == null) {
             return; // UnderlyingNetworkTracker has quit.
         }
 
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index c6f3f73..3842769 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -75,6 +75,7 @@
 import android.os.ParcelUuid;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.Process;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -97,6 +98,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -937,6 +939,14 @@
 
     private WakeupMessage createScheduledAlarm(
             @NonNull String cmdName, Message delayedMessage, long delay) {
+        final Handler handler = getHandler();
+        if (handler == null) {
+            logWarn(
+                    "Attempted to schedule alarm after StateMachine has quit",
+                    new IllegalStateException());
+            return null; // StateMachine has already quit.
+        }
+
         // WakeupMessage uses Handler#dispatchMessage() to immediately handle the specified Runnable
         // at the scheduled time. dispatchMessage() immediately executes and there may be queued
         // events that resolve the scheduled alarm pending in the queue. So, use the Runnable to
@@ -945,7 +955,7 @@
         final WakeupMessage alarm =
                 mDeps.newWakeupMessage(
                         mVcnContext,
-                        getHandler(),
+                        handler,
                         cmdName,
                         () -> sendMessageAndAcquireWakeLock(delayedMessage));
         alarm.schedule(mDeps.getElapsedRealTime() + delay);
@@ -1572,6 +1582,9 @@
 
             agent.sendNetworkCapabilities(caps);
             agent.sendLinkProperties(lp);
+
+            agent.setUnderlyingNetworks(
+                    mUnderlying == null ? null : Collections.singletonList(mUnderlying.network));
         }
 
         protected VcnNetworkAgent buildNetworkAgent(
@@ -1613,6 +1626,10 @@
                                 teardownAsynchronously();
                             } /* networkUnwantedCallback */,
                             (status) -> {
+                                if (mIsQuitting) {
+                                    return; // Ignore; VcnGatewayConnection quitting or already quit
+                                }
+
                                 switch (status) {
                                     case NetworkAgent.VALIDATION_STATUS_VALID:
                                         clearFailedAttemptCounterAndSafeModeAlarm();
@@ -1632,6 +1649,8 @@
                             } /* validationStatusCallback */);
 
             agent.register();
+            agent.setUnderlyingNetworks(
+                    mUnderlying == null ? null : Collections.singletonList(mUnderlying.network));
             agent.markConnected();
 
             return agent;
@@ -1972,7 +1991,7 @@
             final int[] underlyingAdminUids = underlyingCaps.getAdministratorUids();
             Arrays.sort(underlyingAdminUids); // Sort to allow contains check below.
 
-            final int[] adminUids;
+            int[] adminUids;
             if (underlyingCaps.getOwnerUid() > 0 // No owner UID specified
                     && 0 > Arrays.binarySearch(// Owner UID not found in admin UID list.
                             underlyingAdminUids, underlyingCaps.getOwnerUid())) {
@@ -1982,6 +2001,11 @@
             } else {
                 adminUids = underlyingAdminUids;
             }
+
+            // Set owner & administrator UID
+            builder.setOwnerUid(Process.myUid());
+            adminUids = Arrays.copyOf(adminUids, adminUids.length + 1);
+            adminUids[adminUids.length - 1] = Process.myUid();
             builder.setAdministratorUids(adminUids);
 
             builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps());
@@ -2170,6 +2194,16 @@
         LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr);
     }
 
+    private void logWarn(String msg) {
+        Slog.w(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg);
+    }
+
+    private void logWarn(String msg, Throwable tr) {
+        Slog.w(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg + tr);
+    }
+
     private void logErr(String msg) {
         Slog.e(TAG, getLogPrefix() + msg);
         LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
@@ -2547,6 +2581,11 @@
             mImpl.sendLinkProperties(lp);
         }
 
+        /** Sends new NetworkCapabilities for the underlying NetworkAgent */
+        public void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) {
+            mImpl.setUnderlyingNetworks(underlyingNetworks);
+        }
+
         /** Retrieves the Network for the underlying NetworkAgent */
         @Nullable
         public Network getNetwork() {
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index f91575b..5af69b5 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -476,5 +476,16 @@
         verifyNoMoreInteractions(mNetworkTrackerCb);
     }
 
+    @Test
+    public void testRecordTrackerCallbackNotifiedAfterTeardown() {
+        UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+        mUnderlyingNetworkTracker.teardown();
+
+        cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
+
+        // Verify that the only call was during onAvailable()
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
+    }
+
     // TODO (b/187991063): Add tests for network prioritization
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 9c93f81..6bfbfb1 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -48,6 +48,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import static java.util.Collections.singletonList;
+
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -233,6 +235,8 @@
         verify(mNetworkAgent).sendLinkProperties(
                 argThat(lp -> expectedMtu == lp.getMtu()
                         && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
+        verify(mNetworkAgent)
+                .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_2.network)));
     }
 
     private void triggerChildOpened() {
@@ -293,6 +297,8 @@
                         any(),
                         any());
         verify(mNetworkAgent).register();
+        verify(mNetworkAgent)
+                .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network)));
         verify(mNetworkAgent).markConnected();
 
         verify(mIpSecSvc)
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 83610e0..a700171 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -68,7 +68,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
-    private static final int TEST_UID = Process.myUid();
+    private static final int TEST_UID = Process.myUid() + 1;
 
     private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
     private static final int TEST_SIM_SLOT_INDEX = 1;
@@ -137,7 +137,7 @@
             }
         }
 
-        assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
+        assertArrayEquals(new int[] {Process.myUid(), TEST_UID}, vcnCaps.getAdministratorUids());
         assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
         assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps());
         assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps());