Merge "Add NATT keepalive resources and methods into IpSecService"
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index e274005..4ac4a69 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -56,6 +56,26 @@
     /**
      * Sets up a capability-limited, testing-only network for a given interface
      *
+     * @param lp The LinkProperties for the TestNetworkService to use for this test network. Note
+     *     that the interface name and link addresses will be overwritten, and the passed-in values
+     *     discarded.
+     * @param isMetered Whether or not the network should be considered metered.
+     * @param binder A binder object guarding the lifecycle of this test network.
+     * @hide
+     */
+    public void setupTestNetwork(
+            @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
+        Preconditions.checkNotNull(lp, "Invalid LinkProperties");
+        try {
+            mService.setupTestNetwork(lp.getInterfaceName(), lp, isMetered, binder);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets up a capability-limited, testing-only network for a given interface
+     *
      * @param iface the name of the interface to be used for the Network LinkProperties.
      * @param binder A binder object guarding the lifecycle of this test network.
      * @hide
@@ -63,7 +83,7 @@
     @TestApi
     public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
         try {
-            mService.setupTestNetwork(iface, binder);
+            mService.setupTestNetwork(iface, null, true, binder);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c1aff75..244fef4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -634,7 +634,8 @@
      *    the first network for a given type changes, or if the default network
      *    changes.
      */
-    private class LegacyTypeTracker {
+    @VisibleForTesting
+    static class LegacyTypeTracker {
 
         private static final boolean DBG = true;
         private static final boolean VDBG = false;
@@ -660,10 +661,12 @@
          *  - dump is thread-safe with respect to concurrent add and remove calls.
          */
         private final ArrayList<NetworkAgentInfo> mTypeLists[];
+        @NonNull
+        private final ConnectivityService mService;
 
-        public LegacyTypeTracker() {
-            mTypeLists = (ArrayList<NetworkAgentInfo>[])
-                    new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
+        LegacyTypeTracker(@NonNull ConnectivityService service) {
+            mService = service;
+            mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
         }
 
         public void addSupportedType(int type) {
@@ -712,10 +715,10 @@
             }
 
             // Send a broadcast if this is the first network of its type or if it's the default.
-            final boolean isDefaultNetwork = isDefaultNetwork(nai);
+            final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
             if ((list.size() == 1) || isDefaultNetwork) {
                 maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
-                sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
+                mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
             }
         }
 
@@ -737,15 +740,15 @@
 
             if (wasFirstNetwork || wasDefault) {
                 maybeLogBroadcast(nai, state, type, wasDefault);
-                sendLegacyNetworkBroadcast(nai, state, type);
+                mService.sendLegacyNetworkBroadcast(nai, state, type);
             }
 
             if (!list.isEmpty() && wasFirstNetwork) {
                 if (DBG) log("Other network available for type " + type +
                               ", sending connected broadcast");
                 final NetworkAgentInfo replacement = list.get(0);
-                maybeLogBroadcast(replacement, state, type, isDefaultNetwork(replacement));
-                sendLegacyNetworkBroadcast(replacement, state, type);
+                maybeLogBroadcast(replacement, state, type, mService.isDefaultNetwork(replacement));
+                mService.sendLegacyNetworkBroadcast(replacement, state, type);
             }
         }
 
@@ -760,7 +763,7 @@
         // send out another legacy broadcast - currently only used for suspend/unsuspend
         // toggle
         public void update(NetworkAgentInfo nai) {
-            final boolean isDefault = isDefaultNetwork(nai);
+            final boolean isDefault = mService.isDefaultNetwork(nai);
             final DetailedState state = nai.networkInfo.getDetailedState();
             for (int type = 0; type < mTypeLists.length; type++) {
                 final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
@@ -768,7 +771,7 @@
                 final boolean isFirst = contains && (nai == list.get(0));
                 if (isFirst || contains && isDefault) {
                     maybeLogBroadcast(nai, state, type, isDefault);
-                    sendLegacyNetworkBroadcast(nai, state, type);
+                    mService.sendLegacyNetworkBroadcast(nai, state, type);
                 }
             }
         }
@@ -804,7 +807,7 @@
             pw.println();
         }
     }
-    private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
+    private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this);
 
     /**
      * Helper class which parses out priority arguments and dumps sections according to their
@@ -5371,7 +5374,8 @@
         }
     }
 
-    private boolean isDefaultNetwork(NetworkAgentInfo nai) {
+    @VisibleForTesting
+    protected boolean isDefaultNetwork(NetworkAgentInfo nai) {
         return nai == getDefaultNetwork();
     }
 
@@ -6671,7 +6675,8 @@
         }
     }
 
-    private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
+    @VisibleForTesting
+    protected void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
         // The NetworkInfo we actually send out has no bearing on the real
         // state of affairs. For example, if the default connection is mobile,
         // and a request for HIPRI has just gone away, we need to pretend that
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 40bf7bc..d19d2dd 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -19,6 +19,7 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetd;
@@ -53,6 +54,7 @@
 import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
+import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /** @hide */
@@ -226,6 +228,8 @@
             @NonNull Looper looper,
             @NonNull Context context,
             @NonNull String iface,
+            @Nullable LinkProperties lp,
+            boolean isMetered,
             int callingUid,
             @NonNull IBinder binder)
             throws RemoteException, SocketException {
@@ -245,9 +249,19 @@
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
+        if (!isMetered) {
+            nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        }
 
         // Build LinkProperties
-        LinkProperties lp = new LinkProperties();
+        if (lp == null) {
+            lp = new LinkProperties();
+        } else {
+            lp = new LinkProperties(lp);
+            // Use LinkAddress(es) from the interface itself to minimize how much the caller
+            // is trusted.
+            lp.setLinkAddresses(new ArrayList<>());
+        }
         lp.setInterfaceName(iface);
 
         // Find the currently assigned addresses, and add them to LinkProperties
@@ -284,7 +298,11 @@
      * <p>This method provides a Network that is useful only for testing.
      */
     @Override
-    public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
+    public void setupTestNetwork(
+            @NonNull String iface,
+            @Nullable LinkProperties lp,
+            boolean isMetered,
+            @NonNull IBinder binder) {
         enforceTestNetworkPermissions(mContext);
 
         checkNotNull(iface, "missing Iface");
@@ -315,6 +333,8 @@
                                             mHandler.getLooper(),
                                             mContext,
                                             iface,
+                                            lp,
+                                            isMetered,
                                             callingUid,
                                             binder);
 
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 9098f90..1fbb658 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -6,6 +6,7 @@
     static_libs: [
         "FrameworksNetCommonTests",
         "frameworks-base-testutils",
+        "frameworks-net-testutils",
         "framework-protos",
         "androidx.test.rules",
         "mockito-target-minus-junit4",
@@ -63,7 +64,7 @@
 android_test {
     name: "FrameworksNetTests",
     defaults: ["FrameworksNetTests-jni-defaults"],
-    srcs: ["java/**/*.java"],
+    srcs: ["java/**/*.java", "java/**/*.kt"],
     platform_apis: true,
     test_suites: ["device-tests"],
     certificate: "platform",
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 0a1ac75..9ee5858 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -21,6 +21,7 @@
     srcs: ["java/**/*.java"],
     static_libs: [
         "androidx.test.rules",
+        "frameworks-net-testutils",
         "junit",
     ],
     libs: [
diff --git a/tests/net/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
similarity index 100%
rename from tests/net/java/android/net/LinkAddressTest.java
rename to tests/net/common/java/android/net/LinkAddressTest.java
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
similarity index 100%
rename from tests/net/java/android/net/LinkPropertiesTest.java
rename to tests/net/common/java/android/net/LinkPropertiesTest.java
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
similarity index 100%
rename from tests/net/java/android/net/NetworkCapabilitiesTest.java
rename to tests/net/common/java/android/net/NetworkCapabilitiesTest.java
diff --git a/tests/net/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java
similarity index 100%
rename from tests/net/java/android/net/NetworkTest.java
rename to tests/net/common/java/android/net/NetworkTest.java
diff --git a/tests/net/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
similarity index 100%
rename from tests/net/java/android/net/RouteInfoTest.java
rename to tests/net/common/java/android/net/RouteInfoTest.java
diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
similarity index 100%
rename from tests/net/java/android/net/StaticIpConfigurationTest.java
rename to tests/net/common/java/android/net/StaticIpConfigurationTest.java
diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
similarity index 96%
rename from tests/net/java/android/net/apf/ApfCapabilitiesTest.java
rename to tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
index 75752c3..7238895 100644
--- a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
@@ -19,11 +19,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
-import android.net.shared.ParcelableTestUtil;
-
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.ParcelableTestUtil;
 import com.android.internal.util.TestUtils;
 
 import org.junit.Test;
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
new file mode 100644
index 0000000..d983b65
--- /dev/null
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server
+
+import android.net.ConnectivityManager.TYPE_ETHERNET
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.ConnectivityManager.TYPE_WIMAX
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.ConnectivityService.LegacyTypeTracker
+import com.android.server.connectivity.NetworkAgentInfo
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+
+const val UNSUPPORTED_TYPE = TYPE_WIMAX
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class LegacyTypeTrackerTest {
+    private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET)
+
+    private val mMockService = mock(ConnectivityService::class.java).apply {
+        doReturn(false).`when`(this).isDefaultNetwork(any())
+    }
+    private val mTracker = LegacyTypeTracker(mMockService).apply {
+        supportedTypes.forEach {
+            addSupportedType(it)
+        }
+    }
+
+    @Test
+    fun testSupportedTypes() {
+        try {
+            mTracker.addSupportedType(supportedTypes[0])
+            fail("Expected IllegalStateException")
+        } catch (expected: IllegalStateException) {}
+        supportedTypes.forEach {
+            assertTrue(mTracker.isTypeSupported(it))
+        }
+        assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE))
+    }
+
+    @Test
+    fun testAddNetwork() {
+        val mobileNai = mock(NetworkAgentInfo::class.java)
+        val wifiNai = mock(NetworkAgentInfo::class.java)
+        mTracker.add(TYPE_MOBILE, mobileNai)
+        mTracker.add(TYPE_WIFI, wifiNai)
+        assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+        assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+        // Make sure adding a second NAI does not change the results.
+        val secondMobileNai = mock(NetworkAgentInfo::class.java)
+        mTracker.add(TYPE_MOBILE, secondMobileNai)
+        assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+        assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+        // Make sure removing a network that wasn't added for this type is a no-op.
+        mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
+        assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+        assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+        // Remove the top network for mobile and make sure the second one becomes the network
+        // of record for this type.
+        mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
+        assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
+        assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+        // Make sure adding a network for an unsupported type does not register it.
+        mTracker.add(UNSUPPORTED_TYPE, mobileNai)
+        assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE))
+    }
+}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
index fb84611..a83faf3 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static org.junit.Assert.assertEquals;