Merge "Clean up the keepalive slots when network disconnect"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0e10de8..a69ca99 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3449,6 +3449,10 @@
             final NetworkCallback callback;
             synchronized (sCallbacks) {
                 callback = sCallbacks.get(request);
+                if (message.what == CALLBACK_UNAVAIL) {
+                    sCallbacks.remove(request);
+                    callback.networkRequest = ALREADY_UNREGISTERED;
+                }
             }
             if (DBG) {
                 Log.d(TAG, getCallbackName(message.what) + " for network " + network);
@@ -3995,8 +3999,10 @@
         synchronized (sCallbacks) {
             Preconditions.checkArgument(networkCallback.networkRequest != null,
                     "NetworkCallback was not registered");
-            Preconditions.checkArgument(networkCallback.networkRequest != ALREADY_UNREGISTERED,
-                    "NetworkCallback was already unregistered");
+            if (networkCallback.networkRequest == ALREADY_UNREGISTERED) {
+                Log.d(TAG, "NetworkCallback was already unregistered");
+                return;
+            }
             for (Map.Entry<NetworkRequest, NetworkCallback> e : sCallbacks.entrySet()) {
                 if (e.getValue() == networkCallback) {
                     reqs.add(e.getKey());
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 28c59db..c5fc9b3 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -49,8 +49,8 @@
 namespace android {
 
 constexpr int MAXPACKETSIZE = 8 * 1024;
-// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
-constexpr int MAXCMDSIZE = 1024;
+// FrameworkListener limits the size of commands to 4096 bytes.
+constexpr int MAXCMDSIZE = 4096;
 
 static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
     ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 90c86c7..63fd2fd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2861,7 +2861,7 @@
         try {
             nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            e.rethrowAsRuntimeException();
         }
 
         // With Private DNS bypass support, we can proceed to update the
@@ -3031,7 +3031,7 @@
         try {
             nai.networkMonitor().notifyNetworkDisconnected();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            e.rethrowAsRuntimeException();
         }
         mNetworkAgentInfos.remove(nai.messenger);
         nai.clatd.update();
@@ -3070,11 +3070,7 @@
             // fallback network the default or requested a new network from the
             // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
             // long time.
-            try {
-                mNetd.networkDestroy(nai.network.netId);
-            } catch (RemoteException | ServiceSpecificException e) {
-                loge("Exception destroying network: " + e);
-            }
+            destroyNativeNetwork(nai);
             mDnsManager.removeNetwork(nai.network);
         }
         synchronized (mNetworkForNetId) {
@@ -3082,6 +3078,35 @@
         }
     }
 
+    private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+        try {
+            // This should never fail.  Specifying an already in use NetID will cause failure.
+            if (networkAgent.isVPN()) {
+                mNetd.networkCreateVpn(networkAgent.network.netId,
+                        (networkAgent.networkMisc == null
+                                || !networkAgent.networkMisc.allowBypass));
+            } else {
+                mNetd.networkCreatePhysical(networkAgent.network.netId,
+                        getNetworkPermission(networkAgent.networkCapabilities));
+            }
+            mDnsResolver.createNetworkCache(networkAgent.network.netId);
+            return true;
+        } catch (RemoteException | ServiceSpecificException e) {
+            loge("Error creating network " + networkAgent.network.netId + ": "
+                    + e.getMessage());
+            return false;
+        }
+    }
+
+    private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+        try {
+            mNetd.networkDestroy(networkAgent.network.netId);
+            mDnsResolver.destroyNetworkCache(networkAgent.network.netId);
+        } catch (RemoteException | ServiceSpecificException e) {
+            loge("Exception destroying network: " + e);
+        }
+    }
+
     // If this method proves to be too slow then we can maintain a separate
     // pendingIntent => NetworkRequestInfo map.
     // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
@@ -3420,7 +3445,7 @@
             try {
                 nai.networkMonitor().setAcceptPartialConnectivity();
             } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+                e.rethrowAsRuntimeException();
             }
         }
     }
@@ -3456,7 +3481,7 @@
             try {
                 nai.networkMonitor().launchCaptivePortalApp();
             } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+                e.rethrowAsRuntimeException();
             }
         });
     }
@@ -4084,7 +4109,7 @@
         try {
             nai.networkMonitor().forceReevaluation(uid);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -5464,7 +5489,7 @@
         try {
             networkMonitor.start();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            e.rethrowAsRuntimeException();
         }
         nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
         NetworkInfo networkInfo = nai.networkInfo;
@@ -5521,7 +5546,7 @@
             try {
                 networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
             } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+                e.rethrowAsRuntimeException();
             }
             if (networkAgent.everConnected) {
                 notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
@@ -6482,21 +6507,7 @@
             // A network that has just connected has zero requests and is thus a foreground network.
             networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
 
-            try {
-                // This should never fail.  Specifying an already in use NetID will cause failure.
-                if (networkAgent.isVPN()) {
-                    mNMS.createVirtualNetwork(networkAgent.network.netId,
-                            (networkAgent.networkMisc == null ||
-                                !networkAgent.networkMisc.allowBypass));
-                } else {
-                    mNMS.createPhysicalNetwork(networkAgent.network.netId,
-                            getNetworkPermission(networkAgent.networkCapabilities));
-                }
-            } catch (Exception e) {
-                loge("Error creating network " + networkAgent.network.netId + ": "
-                        + e.getMessage());
-                return;
-            }
+            if (!createNativeNetwork(networkAgent)) return;
             networkAgent.created = true;
         }
 
@@ -6527,7 +6538,7 @@
                 networkAgent.networkMonitor().notifyNetworkConnected(
                         networkAgent.linkProperties, networkAgent.networkCapabilities);
             } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+                e.rethrowAsRuntimeException();
             }
             scheduleUnvalidatedPrompt(networkAgent);
 
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index e33392d..2321afb 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -263,12 +263,6 @@
     }
 
     public void removeNetwork(Network network) {
-        try {
-            mDnsResolver.clearResolverConfiguration(network.netId);
-        } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error clearing DNS configuration: " + e);
-            return;
-        }
         mPrivateDnsMap.remove(network.netId);
         mPrivateDnsValidationMap.remove(network.netId);
     }
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/services/net/java/android/net/NattKeepalivePacketData.java
similarity index 84%
rename from core/java/android/net/NattKeepalivePacketData.java
rename to services/net/java/android/net/NattKeepalivePacketData.java
index bdb246f..27ed11e 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/services/net/java/android/net/NattKeepalivePacketData.java
@@ -19,8 +19,10 @@
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
 
+import android.annotation.NonNull;
 import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.util.IpUtils;
+import android.os.Parcelable;
 import android.system.OsConstants;
 
 import java.net.Inet4Address;
@@ -29,8 +31,7 @@
 import java.nio.ByteOrder;
 
 /** @hide */
-public final class NattKeepalivePacketData extends KeepalivePacketData {
-
+public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
     // This should only be constructed via static factory methods, such as
     // nattKeepalivePacket
     private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
@@ -77,4 +78,18 @@
 
         return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
     }
+
+     /**
+     * Convert this NattKeepalivePacketData to a NattKeepalivePacketDataParcelable.
+     */
+    @NonNull
+    public NattKeepalivePacketDataParcelable toStableParcelable() {
+        final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
+
+        parcel.srcAddress = srcAddress.getAddress();
+        parcel.srcPort = srcPort;
+        parcel.dstAddress = dstAddress.getAddress();
+        parcel.dstPort = dstPort;
+        return parcel;
+    }
 }
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 3b2e34a..07525a6 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -23,6 +23,7 @@
         "androidx.test.rules",
         "frameworks-net-testutils",
         "junit",
+        "mockito-target-minus-junit4",
     ],
     libs: [
         "android.test.base.stubs",
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
new file mode 100644
index 0000000..eed7159
--- /dev/null
+++ b/tests/net/common/java/android/net/CaptivePortalTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 android.net;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CaptivePortalTest {
+    private static final int DEFAULT_TIMEOUT_MS = 5000;
+    private static final String TEST_PACKAGE_NAME = "com.google.android.test";
+
+    private final class MyCaptivePortalImpl extends ICaptivePortal.Stub {
+        int mCode = -1;
+        String mPackageName = null;
+
+        @Override
+        public void appResponse(final int response) throws RemoteException {
+            mCode = response;
+        }
+
+        @Override
+        public void logEvent(int eventId, String packageName) throws RemoteException {
+            mCode = eventId;
+            mPackageName = packageName;
+        }
+    }
+
+    private interface TestFunctor {
+        void useCaptivePortal(CaptivePortal o);
+    }
+
+    private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) {
+        final MyCaptivePortalImpl cp = new MyCaptivePortalImpl();
+        f.useCaptivePortal(new CaptivePortal(cp.asBinder()));
+        return cp;
+    }
+
+    @Test
+    public void testReportCaptivePortalDismissed() {
+        final MyCaptivePortalImpl result =
+                runCaptivePortalTest(c -> c.reportCaptivePortalDismissed());
+        assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED);
+    }
+
+    @Test
+    public void testIgnoreNetwork() {
+        final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork());
+        assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED);
+    }
+
+    @Test
+    public void testUseNetwork() {
+        final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork());
+        assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
+    }
+
+    @Test
+    public void testLogEvent() {
+        final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
+                MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
+                TEST_PACKAGE_NAME));
+        assertEquals(result.mCode, MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
+        assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
+    }
+}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index ad76388..6bc7c1b 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -33,6 +33,8 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
 import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
 
@@ -585,4 +587,20 @@
         nc2.set(nc1);  // Overwrites, as opposed to combineCapabilities
         assertEquals(nc1, nc2);
     }
+
+    @Test
+    public void testGetTransportTypes() {
+        final NetworkCapabilities nc = new NetworkCapabilities();
+        nc.addTransportType(TRANSPORT_CELLULAR);
+        nc.addTransportType(TRANSPORT_WIFI);
+        nc.addTransportType(TRANSPORT_VPN);
+        nc.addTransportType(TRANSPORT_TEST);
+
+        final int[] transportTypes = nc.getTransportTypes();
+        assertEquals(4, transportTypes.length);
+        assertEquals(TRANSPORT_CELLULAR, transportTypes[0]);
+        assertEquals(TRANSPORT_WIFI, transportTypes[1]);
+        assertEquals(TRANSPORT_VPN, transportTypes[2]);
+        assertEquals(TRANSPORT_TEST, transportTypes[3]);
+    }
 }
diff --git a/tests/net/common/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java
index 0bee7cd..bef66b2 100644
--- a/tests/net/common/java/android/net/NetworkTest.java
+++ b/tests/net/common/java/android/net/NetworkTest.java
@@ -155,4 +155,12 @@
     private static <T> void assertNotEqual(T t1, T t2) {
         assertFalse(Objects.equals(t1, t2));
     }
+
+    @Test
+    public void testGetPrivateDnsBypassingCopy() {
+        final Network copy = mNetwork.getPrivateDnsBypassingCopy();
+        assertEquals(mNetwork.netId, copy.netId);
+        assertNotEqual(copy.netId, copy.getNetIdForResolv());
+        assertNotEqual(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
+    }
 }
diff --git a/tests/net/common/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
index 8449ca7..5096be2 100644
--- a/tests/net/common/java/android/net/StaticIpConfigurationTest.java
+++ b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
@@ -31,7 +31,9 @@
 import org.junit.runner.RunWith;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
 
 @RunWith(AndroidJUnit4.class)
@@ -46,6 +48,7 @@
     private static final InetAddress DNS2 = IpAddress("8.8.4.4");
     private static final InetAddress DNS3 = IpAddress("4.2.2.2");
     private static final String IFACE = "eth0";
+    private static final String FAKE_DOMAINS = "google.com";
 
     private static InetAddress IpAddress(String addr) {
         return InetAddress.parseNumericAddress(addr);
@@ -69,7 +72,7 @@
         s.dnsServers.add(DNS1);
         s.dnsServers.add(DNS2);
         s.dnsServers.add(DNS3);
-        s.domains = "google.com";
+        s.domains = FAKE_DOMAINS;
         return s;
     }
 
@@ -178,8 +181,8 @@
         expected.addDnsServer(DNS3);
         assertEquals(expected, s.toLinkProperties(IFACE));
 
-        s.domains = "google.com";
-        expected.setDomains("google.com");
+        s.domains = FAKE_DOMAINS;
+        expected.setDomains(FAKE_DOMAINS);
         assertEquals(expected, s.toLinkProperties(IFACE));
 
         s.gateway = null;
@@ -218,4 +221,53 @@
         StaticIpConfiguration s2 = passThroughParcel(s);
         assertEquals(s, s2);
     }
+
+    @Test
+    public void testBuilder() {
+        final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+        dnsServers.add(DNS1);
+
+        final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
+                .setIpAddress(ADDR)
+                .setGateway(GATEWAY)
+                .setDomains(FAKE_DOMAINS)
+                .setDnsServers(dnsServers)
+                .build();
+
+        assertEquals(s.ipAddress, s.getIpAddress());
+        assertEquals(ADDR, s.getIpAddress());
+        assertEquals(s.gateway, s.getGateway());
+        assertEquals(GATEWAY, s.getGateway());
+        assertEquals(s.domains, s.getDomains());
+        assertEquals(FAKE_DOMAINS, s.getDomains());
+        assertTrue(s.dnsServers.equals(s.getDnsServers()));
+        assertEquals(1, s.getDnsServers().size());
+        assertEquals(DNS1, s.getDnsServers().get(0));
+    }
+
+    @Test
+    public void testAddDnsServers() {
+        final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
+        checkEmpty(s);
+
+        s.addDnsServer(DNS1);
+        assertEquals(1, s.getDnsServers().size());
+        assertEquals(DNS1, s.getDnsServers().get(0));
+
+        s.addDnsServer(DNS2);
+        s.addDnsServer(DNS3);
+        assertEquals(3, s.getDnsServers().size());
+        assertEquals(DNS2, s.getDnsServers().get(1));
+        assertEquals(DNS3, s.getDnsServers().get(2));
+    }
+
+    @Test
+    public void testGetRoutes() {
+        final StaticIpConfiguration s = makeTestObject();
+        final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
+
+        assertEquals(2, routeInfoList.size());
+        assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
+        assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
+    }
 }
diff --git a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
new file mode 100644
index 0000000..8d055c9
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
@@ -0,0 +1,79 @@
+/*
+ * 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 android.net.metrics;
+
+import android.os.Parcelable
+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.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ApfProgramEventTest {
+    private fun <T: Parcelable> testParcel(obj: T, fieldCount: Int) {
+        ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java)
+        TestUtils.assertParcelingIsLossless(obj)
+    }
+
+    private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0
+
+    @Test
+    fun testBuilderAndParcel() {
+        val apfProgramEvent = ApfProgramEvent.Builder()
+                .setLifetime(1)
+                .setActualLifetime(2)
+                .setFilteredRas(3)
+                .setCurrentRas(4)
+                .setProgramLength(5)
+                .setFlags(true, true)
+                .build()
+
+        assertEquals(1, apfProgramEvent.lifetime)
+        assertEquals(2, apfProgramEvent.actualLifetime)
+        assertEquals(3, apfProgramEvent.filteredRas)
+        assertEquals(4, apfProgramEvent.currentRas)
+        assertEquals(5, apfProgramEvent.programLength)
+        assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags)
+
+        testParcel(apfProgramEvent, 6)
+    }
+
+    @Test
+    fun testFlagsFor() {
+        var flags = ApfProgramEvent.flagsFor(false, false)
+        assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+        assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+
+        flags = ApfProgramEvent.flagsFor(true, false)
+        assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+        assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+
+        flags = ApfProgramEvent.flagsFor(false, true)
+        assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+        assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+
+        flags = ApfProgramEvent.flagsFor(true, true)
+        assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+        assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt
new file mode 100644
index 0000000..f8eb40c
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt
@@ -0,0 +1,64 @@
+/*
+ * 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 android.net.metrics
+
+import android.os.Parcelable
+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.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ApfStatsTest {
+    private fun <T: Parcelable> testParcel(obj: T, fieldCount: Int) {
+        ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java)
+        TestUtils.assertParcelingIsLossless(obj)
+    }
+
+    @Test
+    fun testBuilderAndParcel() {
+        val apfStats = ApfStats.Builder()
+                .setDurationMs(Long.MAX_VALUE)
+                .setReceivedRas(1)
+                .setMatchingRas(2)
+                .setDroppedRas(3)
+                .setZeroLifetimeRas(4)
+                .setParseErrors(5)
+                .setProgramUpdates(6)
+                .setProgramUpdatesAll(7)
+                .setProgramUpdatesAllowingMulticast(8)
+                .setMaxProgramSize(9)
+                .build()
+
+        assertEquals(Long.MAX_VALUE, apfStats.durationMs)
+        assertEquals(1, apfStats.receivedRas)
+        assertEquals(2, apfStats.matchingRas)
+        assertEquals(3, apfStats.droppedRas)
+        assertEquals(4, apfStats.zeroLifetimeRas)
+        assertEquals(5, apfStats.parseErrors)
+        assertEquals(6, apfStats.programUpdates)
+        assertEquals(7, apfStats.programUpdatesAll)
+        assertEquals(8, apfStats.programUpdatesAllowingMulticast)
+        assertEquals(9, apfStats.maxProgramSize)
+
+        testParcel(apfStats, 10)
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
index e191953..e9d5e6d 100644
--- a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
+++ b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
@@ -13,9 +13,7 @@
 import org.junit.runner.RunWith
 
 private const val TEST_ERROR_CODE = 12345
-/**
- * DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java)
- */
+//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected)
 private const val DHCP_SUBNET_MASK = 1
 
 @RunWith(AndroidJUnit4::class)
diff --git a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
new file mode 100644
index 0000000..d4780d3
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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 android.net.metrics;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.Network;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.BitUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpConnectivityLogTest {
+    private static final int FAKE_NET_ID = 100;
+    private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
+    private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
+    private static final String FAKE_INTERFACE_NAME = "test";
+    private static final IpReachabilityEvent FAKE_EV =
+            new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
+
+    @Mock IIpConnectivityMetrics mMockService;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testLoggingEvents() throws Exception {
+        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
+
+        assertTrue(logger.log(FAKE_EV));
+        assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
+        assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
+        assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
+        assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
+        assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
+                FAKE_INTERFACE_NAME)));
+
+        List<ConnectivityMetricsEvent> got = verifyEvents(6);
+        assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
+        assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
+        assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
+                TRANSPORT_WIFI, null), got.get(2));
+        assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
+                TRANSPORT_WIFI, null), got.get(3));
+        assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
+                got.get(4));
+        assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
+                TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
+    }
+
+    @Test
+    public void testLoggingEventsWithMultipleCallers() throws Exception {
+        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
+
+        final int nCallers = 10;
+        final int nEvents = 10;
+        for (int n = 0; n < nCallers; n++) {
+            final int i = n;
+            new Thread() {
+                public void run() {
+                    for (int j = 0; j < nEvents; j++) {
+                        assertTrue(logger.log(makeExpectedEvent(
+                                FAKE_TIME_STAMP + i * 100 + j,
+                                FAKE_NET_ID + i * 100 + j,
+                                ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
+                                FAKE_INTERFACE_NAME)));
+                    }
+                }
+            }.start();
+        }
+
+        List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
+        Collections.sort(got, EVENT_COMPARATOR);
+        Iterator<ConnectivityMetricsEvent> iter = got.iterator();
+        for (int i = 0; i < nCallers; i++) {
+            for (int j = 0; j < nEvents; j++) {
+                final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
+                final int expectedNetId = FAKE_NET_ID + i * 100 + j;
+                final long expectedTransports =
+                        ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
+                assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
+                        expectedTransports, FAKE_INTERFACE_NAME), iter.next());
+            }
+        }
+    }
+
+    private List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
+        ArgumentCaptor<ConnectivityMetricsEvent> captor =
+                ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
+        verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
+        return captor.getAllValues();
+    }
+
+    private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
+        return verifyEvents(n, 10);
+    }
+
+
+    private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
+            String ifname) {
+        ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+        ev.timestamp = timestamp;
+        ev.data = FAKE_EV;
+        ev.netId = netId;
+        ev.transports = transports;
+        ev.ifname = ifname;
+        return ev;
+    }
+
+    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
+    private void assertEventsEqual(ConnectivityMetricsEvent expected,
+            ConnectivityMetricsEvent got) {
+        assertEquals(expected.data, got.data);
+        assertEquals(expected.timestamp, got.timestamp);
+        assertEquals(expected.netId, got.netId);
+        assertEquals(expected.transports, got.transports);
+        assertEquals(expected.ifname, got.ifname);
+    }
+
+    static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
+            Comparator.comparingLong((ev) -> ev.timestamp);
+}
diff --git a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
new file mode 100644
index 0000000..d76ebf6
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
@@ -0,0 +1,45 @@
+/*
+ * 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 android.net.metrics
+
+import android.os.Parcelable
+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.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class IpReachabilityEventTest {
+    private fun <T: Parcelable> testParcel(obj: T, fieldCount: Int) {
+        ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java)
+        TestUtils.assertParcelingIsLossless(obj)
+    }
+
+    @Test
+    fun testConstructorAndParcel() {
+        (IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach {
+            val ipReachabilityEvent = IpReachabilityEvent(it)
+            assertEquals(it, ipReachabilityEvent.eventType)
+
+            testParcel(ipReachabilityEvent, 1)
+        }
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/RaEventTest.kt b/tests/net/common/java/android/net/metrics/RaEventTest.kt
new file mode 100644
index 0000000..f38d328
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/RaEventTest.kt
@@ -0,0 +1,79 @@
+/*
+ * 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 android.net.metrics
+
+import android.os.Parcelable
+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.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val NO_LIFETIME: Long = -1L
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class RaEventTest {
+    private fun <T: Parcelable> testParcel(obj: T, fieldCount: Int) {
+        ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java)
+        TestUtils.assertParcelingIsLossless(obj)
+    }
+
+    @Test
+    fun testConstructorAndParcel() {
+        var raEvent = RaEvent.Builder().build()
+        assertEquals(NO_LIFETIME, raEvent.routerLifetime)
+        assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime)
+        assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime)
+        assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime)
+        assertEquals(NO_LIFETIME, raEvent.rdnssLifetime)
+        assertEquals(NO_LIFETIME, raEvent.dnsslLifetime)
+
+        raEvent = RaEvent.Builder()
+                .updateRouterLifetime(1)
+                .updatePrefixValidLifetime(2)
+                .updatePrefixPreferredLifetime(3)
+                .updateRouteInfoLifetime(4)
+                .updateRdnssLifetime(5)
+                .updateDnsslLifetime(6)
+                .build()
+        assertEquals(1, raEvent.routerLifetime)
+        assertEquals(2, raEvent.prefixValidLifetime)
+        assertEquals(3, raEvent.prefixPreferredLifetime)
+        assertEquals(4, raEvent.routeInfoLifetime)
+        assertEquals(5, raEvent.rdnssLifetime)
+        assertEquals(6, raEvent.dnsslLifetime)
+
+        raEvent = RaEvent.Builder()
+                .updateRouterLifetime(Long.MIN_VALUE)
+                .updateRouterLifetime(Long.MAX_VALUE)
+                .build()
+        assertEquals(Long.MIN_VALUE, raEvent.routerLifetime)
+
+        raEvent = RaEvent(1, 2, 3, 4, 5, 6)
+        assertEquals(1, raEvent.routerLifetime)
+        assertEquals(2, raEvent.prefixValidLifetime)
+        assertEquals(3, raEvent.prefixPreferredLifetime)
+        assertEquals(4, raEvent.routeInfoLifetime)
+        assertEquals(5, raEvent.rdnssLifetime)
+        assertEquals(6, raEvent.dnsslLifetime)
+
+        testParcel(raEvent, 6)
+    }
+}
diff --git a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
new file mode 100644
index 0000000..c0cef8f
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
@@ -0,0 +1,79 @@
+/*
+ * 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 android.net.metrics
+
+import android.os.Parcelable
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.util.ParcelableTestUtil
+import com.android.internal.util.TestUtils
+import java.lang.reflect.Modifier
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val FIRST_VALIDATION: Int = 1 shl 8
+private const val REVALIDATION: Int = 2 shl 8
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ValidationProbeEventTest {
+    private fun <T: Parcelable> testParcel(obj: T, fieldCount: Int) {
+        ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java)
+        TestUtils.assertParcelingIsLossless(obj)
+    }
+
+    private infix fun Int.hasType(type: Int) = (type and this) == type
+
+    @Test
+    fun testBuilderAndParcel() {
+        var validationProbeEvent = ValidationProbeEvent.Builder()
+                .setProbeType(ValidationProbeEvent.PROBE_DNS, false).build()
+
+        assertTrue(validationProbeEvent.probeType hasType REVALIDATION)
+
+        validationProbeEvent = ValidationProbeEvent.Builder()
+                .setDurationMs(Long.MAX_VALUE)
+                .setProbeType(ValidationProbeEvent.PROBE_DNS, true)
+                .setReturnCode(ValidationProbeEvent.DNS_SUCCESS)
+                .build()
+
+        assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs)
+        assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS)
+        assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION)
+        assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode)
+
+        testParcel(validationProbeEvent, 3)
+    }
+
+    @Test
+    fun testGetProbeName() {
+        val probeFields = ValidationProbeEvent::class.java.declaredFields.filter {
+            it.type == Int::class.javaPrimitiveType
+              && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
+              && it.name.contains("PROBE")
+        }
+
+        probeFields.forEach {
+            val intValue = it.getInt(null)
+            val stringValue = ValidationProbeEvent.getProbeName(intValue)
+            assertEquals(it.name, stringValue)
+        }
+
+    }
+}
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 18c6768..8ff2de9 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -16,10 +16,26 @@
 
 package android.net;
 
-import static org.mockito.ArgumentMatchers.any;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.Status;
+import android.os.RemoteException;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -27,28 +43,57 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IpMemoryStoreTest {
+    private static final String TAG = IpMemoryStoreTest.class.getSimpleName();
+    private static final String TEST_CLIENT_ID = "testClientId";
+    private static final String TEST_DATA_NAME = "testData";
+    private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other";
+    private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
+            -128, 0, 89, 112, 91, -34 };
+    private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes(
+            "hint", 219);
+
     @Mock
     Context mMockContext;
     @Mock
     NetworkStackClient mNetworkStackClient;
     @Mock
     IIpMemoryStore mMockService;
+    @Mock
+    IOnStatusListener mIOnStatusListener;
     IpMemoryStore mStore;
 
+    @Captor
+    ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor;
+    @Captor
+    ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        doAnswer(invocation -> {
-            ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
-                    .onIpMemoryStoreFetched(mMockService);
-            return null;
-        }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+    }
+
+    private void startIpMemoryStore(boolean supplyService) {
+        if (supplyService) {
+            doAnswer(invocation -> {
+                ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
+                        .onIpMemoryStoreFetched(mMockService);
+                return null;
+            }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+        } else {
+            doNothing().when(mNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
+        }
         mStore = new IpMemoryStore(mMockContext) {
             @Override
             protected NetworkStackClient getNetworkStackClient() {
@@ -57,24 +102,228 @@
         };
     }
 
-    @Test
-    public void testNetworkAttributes() {
-        // TODO : implement this
+    private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) {
+        return new NetworkAttributes.Builder()
+                .setGroupHint(hint)
+                .setMtu(mtu)
+                .build();
     }
 
     @Test
-    public void testPrivateData() {
-        // TODO : implement this
+    public void testNetworkAttributes() throws Exception {
+        startIpMemoryStore(true);
+        final String l2Key = "fakeKey";
+
+        mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key),
+                mNapCaptor.capture(), any());
+        assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+
+        mStore.retrieveNetworkAttributes(l2Key,
+                (status, key, attr) -> {
+                    assertTrue("Retrieve network attributes not successful : "
+                            + status.resultCode, status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
+                });
+
+        verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any());
     }
 
     @Test
-    public void testFindL2Key() {
-        // TODO : implement this
+    public void testPrivateData() throws RemoteException {
+        startIpMemoryStore(true);
+        final Blob b = new Blob();
+        b.data = TEST_BLOB_DATA;
+        final String l2Key = "fakeKey";
+
+        mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+                eq(b), any());
+
+        mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+                (status, key, name, data) -> {
+                    assertTrue("Retrieve blob status not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(name, TEST_DATA_NAME);
+                    assertTrue(Arrays.equals(b.data, data.data));
+                });
+        verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+                eq(TEST_OTHER_DATA_NAME), any());
     }
 
     @Test
-    public void testIsSameNetwork() {
-        // TODO : implement this
+    public void testFindL2Key()
+            throws UnknownHostException, RemoteException, Exception {
+        startIpMemoryStore(true);
+        final String l2Key = "fakeKey";
+
+        mStore.findL2Key(TEST_NETWORK_ATTRIBUTES,
+                (status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(l2Key, key);
+                });
+        verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any());
+        assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
     }
 
+    @Test
+    public void testIsSameNetwork() throws UnknownHostException, RemoteException {
+        startIpMemoryStore(true);
+        final String l2Key1 = "fakeKey1";
+        final String l2Key2 = "fakeKey2";
+
+        mStore.isSameNetwork(l2Key1, l2Key2,
+                (status, answer) -> {
+                    assertFalse("Retrieve network sameness suspiciously successful : "
+                            + status.resultCode, status.isSuccess());
+                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+                    assertNull(answer);
+                });
+        verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any());
+    }
+
+    @Test
+    public void testEnqueuedIpMsRequests() throws Exception {
+        startIpMemoryStore(false);
+
+        final Blob b = new Blob();
+        b.data = TEST_BLOB_DATA;
+        final String l2Key = "fakeKey";
+
+        // enqueue multiple ipms requests
+        mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        mStore.retrieveNetworkAttributes(l2Key,
+                (status, key, attr) -> {
+                    assertTrue("Retrieve network attributes not successful : "
+                            + status.resultCode, status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
+                });
+        mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+                (status, key, name, data) -> {
+                    assertTrue("Retrieve blob status not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(name, TEST_DATA_NAME);
+                    assertTrue(Arrays.equals(b.data, data.data));
+                });
+
+        // get ipms service ready
+        mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService);
+
+        InOrder inOrder = inOrder(mMockService);
+
+        inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
+        inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
+        inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+                eq(b), any());
+        inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+                eq(TEST_OTHER_DATA_NAME), any());
+        assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+    }
+
+    @Test
+    public void testEnqueuedIpMsRequestsWithException() throws Exception {
+        startIpMemoryStore(true);
+        doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any());
+
+        final Blob b = new Blob();
+        b.data = TEST_BLOB_DATA;
+        final String l2Key = "fakeKey";
+
+        // enqueue multiple ipms requests
+        mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        mStore.retrieveNetworkAttributes(l2Key,
+                (status, key, attr) -> {
+                    assertTrue("Retrieve network attributes not successful : "
+                            + status.resultCode, status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
+                });
+        mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+                (status, key, name, data) -> {
+                    assertTrue("Retrieve blob status not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(name, TEST_DATA_NAME);
+                    assertTrue(Arrays.equals(b.data, data.data));
+                });
+
+        // verify the rest of the queue is still processed in order even if the remote exception
+        // occurs when calling one or more requests
+        InOrder inOrder = inOrder(mMockService);
+
+        inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
+        inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+                eq(b), any());
+        inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+                eq(TEST_OTHER_DATA_NAME), any());
+        assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+    }
+
+    @Test
+    public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception {
+        startIpMemoryStore(true);
+
+        final Blob b = new Blob();
+        b.data = TEST_BLOB_DATA;
+        final String l2Key = "fakeKey";
+
+        // enqueue multiple ipms requests
+        mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+                status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                });
+        mStore.retrieveNetworkAttributes(l2Key,
+                (status, key, attr) -> {
+                    throw new RuntimeException("retrieveNetworkAttributes test");
+                });
+        mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+                status -> {
+                    throw new RuntimeException("storeBlob test");
+                });
+        mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+                (status, key, name, data) -> {
+                    assertTrue("Retrieve blob status not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(l2Key, key);
+                    assertEquals(name, TEST_DATA_NAME);
+                    assertTrue(Arrays.equals(b.data, data.data));
+                });
+
+        // verify the rest of the queue is still processed in order even if when one or more
+        // callback throw the remote exception
+        InOrder inOrder = inOrder(mMockService);
+
+        inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(),
+                any());
+        inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+                eq(b), any());
+        inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+                eq(TEST_OTHER_DATA_NAME), any());
+        assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+    }
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 64672bd..3c5bb6a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
@@ -103,6 +105,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
@@ -146,6 +149,7 @@
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
+import android.os.Binder;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -272,6 +276,7 @@
     @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
     @Mock NetworkStackClient mNetworkStack;
+    @Mock PackageManager mPackageManager;
     @Mock UserManager mUserManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
@@ -357,7 +362,12 @@
         public Resources getResources() {
             return mResources;
         }
-    }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+   }
 
     public void waitForIdle(int timeoutMsAsInt) {
         long timeoutMs = timeoutMsAsInt;
@@ -557,6 +567,16 @@
                 protected void preventAutomaticReconnect() {
                     mPreventReconnectReceived.open();
                 }
+
+                @Override
+                protected void addKeepalivePacketFilter(Message msg) {
+                    Log.i(TAG, "Add keepalive packet filter.");
+                }
+
+                @Override
+                protected void removeKeepalivePacketFilter(Message msg) {
+                    Log.i(TAG, "Remove keepalive packet filter.");
+                }
             };
 
             assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
@@ -1232,6 +1252,7 @@
         if (Looper.myLooper() == null) {
             Looper.prepare();
         }
+        mockDefaultPackages();
 
         FakeSettingsProvider.clearSettingsProvider();
         mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
@@ -1284,7 +1305,24 @@
         FakeSettingsProvider.clearSettingsProvider();
     }
 
-    private static int transportToLegacyType(int transport) {
+    private void mockDefaultPackages() throws Exception {
+        final String testPackageName = mContext.getPackageName();
+        final PackageInfo testPackageInfo = mContext.getPackageManager().getPackageInfo(
+                testPackageName, PackageManager.GET_PERMISSIONS);
+        when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn(
+                new String[] {testPackageName});
+        when(mPackageManager.getPackageInfoAsUser(eq(testPackageName), anyInt(),
+                eq(UserHandle.getCallingUserId()))).thenReturn(testPackageInfo);
+
+        when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+                Arrays.asList(new PackageInfo[] {
+                        buildPackageInfo(/* SYSTEM */ false, APP1_UID),
+                        buildPackageInfo(/* SYSTEM */ false, APP2_UID),
+                        buildPackageInfo(/* SYSTEM */ false, VPN_UID)
+                }));
+    }
+
+   private static int transportToLegacyType(int transport) {
         switch (transport) {
             case TRANSPORT_ETHERNET:
                 return TYPE_ETHERNET;
@@ -3816,6 +3854,9 @@
         networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
         testFactory.waitForRequests();
 
+        // unregister network callback - a no-op, but should not fail
+        mCm.unregisterNetworkCallback(networkCallback);
+
         testFactory.unregister();
         handlerThread.quit();
     }
@@ -4891,7 +4932,10 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(false);
         waitForIdle();
-        // CS tells netd about the empty DNS config for this network.
+
+        verify(mMockDnsResolver, times(1)).createNetworkCache(
+                eq(mCellNetworkAgent.getNetwork().netId));
+        // CS tells dnsresolver about the empty DNS config for this network.
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
         reset(mMockDnsResolver);
 
@@ -4975,6 +5019,8 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(false);
         waitForIdle();
+        verify(mMockDnsResolver, times(1)).createNetworkCache(
+                eq(mCellNetworkAgent.getNetwork().netId));
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 mResolverParamsParcelCaptor.capture());
         ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
@@ -5848,12 +5894,17 @@
         cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
         reset(mNetworkManagementService);
         reset(mMockDnsResolver);
+        reset(mMockNetd);
         when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfig(myIpv4));
 
         // Connect with ipv6 link properties. Expect prefix discovery to be started.
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
+
+        verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
+        verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
@@ -6045,7 +6096,7 @@
         verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
         verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
         verify(mMockDnsResolver, times(1))
-                .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId));
+                .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
@@ -6169,7 +6220,6 @@
     }
 
     @Test
-    @Ignore
     public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("tun0");
@@ -6196,7 +6246,6 @@
     }
 
     @Test
-    @Ignore
     public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("tun0");
@@ -6210,7 +6259,6 @@
     }
 
     @Test
-    @Ignore
     public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule()
             throws Exception {
         LinkProperties lp = new LinkProperties();
@@ -6226,7 +6274,6 @@
     }
 
     @Test
-    @Ignore
     public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("tun0");
@@ -6276,7 +6323,6 @@
     }
 
     @Test
-    @Ignore
     public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("tun0");
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index d5b2c87..3a07166 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -21,11 +21,8 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -59,16 +56,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -98,48 +90,6 @@
     }
 
     @Test
-    public void testLoggingEvents() throws Exception {
-        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
-        assertTrue(logger.log(1, FAKE_EV));
-        assertTrue(logger.log(2, FAKE_EV));
-        assertTrue(logger.log(3, FAKE_EV));
-
-        List<ConnectivityMetricsEvent> got = verifyEvents(3);
-        assertEventsEqual(expectedEvent(1), got.get(0));
-        assertEventsEqual(expectedEvent(2), got.get(1));
-        assertEventsEqual(expectedEvent(3), got.get(2));
-    }
-
-    @Test
-    public void testLoggingEventsWithMultipleCallers() throws Exception {
-        IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
-        final int nCallers = 10;
-        final int nEvents = 10;
-        for (int n = 0; n < nCallers; n++) {
-            final int i = n;
-            new Thread() {
-                public void run() {
-                    for (int j = 0; j < nEvents; j++) {
-                        assertTrue(logger.log(1 + i * 100 + j, FAKE_EV));
-                    }
-                }
-            }.start();
-        }
-
-        List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
-        Collections.sort(got, EVENT_COMPARATOR);
-        Iterator<ConnectivityMetricsEvent> iter = got.iterator();
-        for (int i = 0; i < nCallers; i++) {
-            for (int j = 0; j < nEvents; j++) {
-                int expectedTimestamp = 1 + i * 100 + j;
-                assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
-            }
-        }
-    }
-
-    @Test
     public void testBufferFlushing() {
         String output1 = getdump("flush");
         assertEquals("", output1);
@@ -653,16 +603,7 @@
         return nai;
     }
 
-    List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
-        ArgumentCaptor<ConnectivityMetricsEvent> captor =
-                ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
-        verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
-        return captor.getAllValues();
-    }
 
-    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
-        return verifyEvents(n, 10);
-    }
 
     static void verifySerialization(String want, String output) {
         try {
@@ -674,28 +615,4 @@
             fail(e.toString());
         }
     }
-
-    static String joinLines(String ... elems) {
-        StringBuilder b = new StringBuilder();
-        for (String s : elems) {
-            b.append(s).append("\n");
-        }
-        return b.toString();
-    }
-
-    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
-        ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
-        ev.timestamp = timestamp;
-        ev.data = FAKE_EV;
-        return ev;
-    }
-
-    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
-    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
-        assertEquals(expected.timestamp, got.timestamp);
-        assertEquals(expected.data, got.data);
-    }
-
-    static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
-        Comparator.comparingLong((ev) -> ev.timestamp);
 }
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 a83faf3..fb84611 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.connectivity.ipmemorystore;
+package com.android.server.net.ipmemorystore;
 
 import static org.junit.Assert.assertEquals;