Remove these subdirectories per b/133225687

Bug: 133225687
Test: Local compile/test.
Change-Id: I94f962e4e15c5addb193d6a54a6776614ed02657
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
deleted file mode 100644
index c9183f6..0000000
--- a/packages/CaptivePortalLogin/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// 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.
-//
-
-java_defaults {
-    name: "CaptivePortalLoginDefaults",
-    srcs: ["src/**/*.java"],
-    sdk_version: "system_current",
-    min_sdk_version: "28",
-    static_libs: [
-        "android-support-v4",
-        "metrics-constants-protos",
-        "captiveportal-lib",
-    ],
-    manifest: "AndroidManifest.xml",
-}
-
-android_app {
-    name: "CaptivePortalLogin",
-    defaults: ["CaptivePortalLoginDefaults"],
-    certificate: "networkstack",
-}
-
-// Alternative CaptivePortalLogin signed with the platform cert, to use
-// with InProcessNetworkStack.
-android_app {
-    name: "PlatformCaptivePortalLogin",
-    defaults: ["CaptivePortalLoginDefaults"],
-    certificate: "platform",
-    overrides: ["CaptivePortalLogin"],
-}
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
deleted file mode 100644
index 0a03425f..0000000
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2014 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.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.captiveportallogin"
-    android:versionCode="11"
-    android:versionName="Q-initial">
-
-    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
-    <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
-    <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
-
-    <application android:label="@string/app_name"
-                 android:icon="@drawable/app_icon"
-                 android:usesCleartextTraffic="true"
-                 android:supportsRtl="true" >
-        <activity
-            android:name="com.android.captiveportallogin.CaptivePortalLoginActivity"
-            android:label="@string/action_bar_label"
-            android:theme="@style/AppTheme"
-            android:configChanges="keyboardHidden|orientation|screenSize" >
-            <intent-filter>
-                <action android:name="android.net.conn.CAPTIVE_PORTAL"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/packages/CaptivePortalLogin/OWNERS b/packages/CaptivePortalLogin/OWNERS
deleted file mode 100644
index 5f3635e..0000000
--- a/packages/CaptivePortalLogin/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-set noparent
-
-lorenzo@google.com
-reminv@google.com
-baligh@google.com
-delphij@google.com
diff --git a/packages/CaptivePortalLogin/assets/quantum_ic_warning_amber_96.png b/packages/CaptivePortalLogin/assets/quantum_ic_warning_amber_96.png
deleted file mode 100644
index 08294ce..0000000
--- a/packages/CaptivePortalLogin/assets/quantum_ic_warning_amber_96.png
+++ /dev/null
Binary files differ
diff --git a/packages/CaptivePortalLogin/res/drawable/app_icon.xml b/packages/CaptivePortalLogin/res/drawable/app_icon.xml
deleted file mode 100644
index 456ca83..0000000
--- a/packages/CaptivePortalLogin/res/drawable/app_icon.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-    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.
--->
-<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background>
-        <color android:color="@*android:color/accent_device_default_light" />
-    </background>
-    <foreground>
-        <inset
-            android:drawable="@drawable/maybe_wifi"
-            android:inset="25%">
-        </inset>
-    </foreground>
-</adaptive-icon>
diff --git a/packages/CaptivePortalLogin/res/drawable/maybe_wifi.xml b/packages/CaptivePortalLogin/res/drawable/maybe_wifi.xml
deleted file mode 100644
index 207aade..0000000
--- a/packages/CaptivePortalLogin/res/drawable/maybe_wifi.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="26.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="26.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="M19.1,14l-3.4,0l0,-1.5c0,-1.8 0.8,-2.8 1.5,-3.4C18.1,8.3 19.200001,8 20.6,8c1.2,0 2.3,0.3 3.1,0.8l1.9,-2.3C25.1,6.1 20.299999,2.1 13,2.1S0.9,6.1 0.4,6.5L13,22l0,0l0,0l0,0l0,0l6.5,-8.1L19.1,14z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.5,17.799999c0,-0.8 0.1,-1.3 0.2,-1.6c0.2,-0.3 0.5,-0.7 1.1,-1.2c0.4,-0.4 0.7,-0.8 1,-1.1s0.4,-0.8 0.4,-1.2c0,-0.5 -0.1,-0.9 -0.4,-1.2c-0.3,-0.3 -0.7,-0.4 -1.2,-0.4c-0.4,0 -0.8,0.1 -1.1,0.3c-0.3,0.2 -0.4,0.6 -0.4,1.1l-1.9,0c0,-1 0.3,-1.7 1,-2.2c0.6,-0.5 1.5,-0.8 2.5,-0.8c1.1,0 2,0.3 2.6,0.8c0.6,0.5 0.9,1.3 0.9,2.3c0,0.7 -0.2,1.3 -0.6,1.8c-0.4,0.6 -0.9,1.1 -1.5,1.6c-0.3,0.3 -0.5,0.5 -0.6,0.7c-0.1,0.2 -0.1,0.6 -0.1,1L19.5,17.700001zM21.4,21l-1.9,0l0,-1.8l1.9,0L21.4,21z"/>
-</vector>
diff --git a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml b/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
deleted file mode 100644
index c292323..0000000
--- a/packages/CaptivePortalLogin/res/layout/activity_captive_portal_login.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context="com.android.captiveportallogin.CaptivePortalLoginActivity"
-    tools:ignore="MergeRootFrame" >
-
-    <LinearLayout
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical" >
-
-      <FrameLayout
-          android:layout_width="match_parent"
-          android:layout_height="4dp" >
-
-        <!-- Eliminates ProgressBar padding by boxing it into a 4dp high container -->
-        <ProgressBar
-            android:id="@+id/progress_bar"
-            style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
-            android:indeterminate="false"
-            android:max="100"
-            android:progress="0"
-            android:layout_gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-      </FrameLayout>
-
-      <android.support.v4.widget.SwipeRefreshLayout
-            android:id="@+id/swipe_refresh"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-        <WebView
-              android:id="@+id/webview"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layout_alignParentBottom="false"
-              android:layout_alignParentRight="false" />
-      </android.support.v4.widget.SwipeRefreshLayout>
-
-    </LinearLayout>
-</FrameLayout>
diff --git a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
deleted file mode 100644
index ce05e78..0000000
--- a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical" >
-
-    <!-- ssl error type -->
-    <TextView
-        android:id="@+id/ssl_error_type"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="start"
-        android:text="SSL_UNKNOWN"
-        android:layout_marginStart="24dip"
-        android:layout_marginEnd="24dip"
-        android:layout_marginBottom="0dip"
-        android:layout_marginTop="24dip" />
-
-    <!-- Page info: -->
-    <TextView
-        android:id="@+id/page_info"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/page_info"
-        android:textStyle="bold"
-        android:layout_marginStart="24dip"
-        android:layout_marginEnd="24dip" />
-
-    <!-- Title: -->
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textStyle="bold"
-        android:layout_marginStart="24dip"
-        android:layout_marginEnd="24dip" />
-
-    <!-- Address: -->
-    <TextView
-        android:id="@+id/address_header"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/page_info_address"
-        android:layout_marginStart="24dip"
-        android:layout_marginEnd="24dip" />
-
-    <TextView
-        android:id="@+id/address"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="24dip"
-        android:layout_marginEnd="24dip" />
-
-    <ScrollView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingStart="4dip"
-        android:paddingEnd="4dip" >
-
-        <!-- certificate view: -->
-        <LinearLayout
-            android:id="@+id/certificate_layout"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:layout_marginBottom="16dip" >
-            <TextView
-                android:id="@+id/ssl_error_msg"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textAppearance="?android:attr/textAppearanceSmall"
-                android:layout_marginStart="20dip"
-                android:layout_marginEnd="20dip"
-                android:gravity="center_vertical"
-                android:layout_marginBottom="4dip"
-                android:layout_marginTop="16dip" />
-        </LinearLayout>
-
-    </ScrollView>
-
-</LinearLayout>
diff --git a/packages/CaptivePortalLogin/res/menu/captive_portal_login.xml b/packages/CaptivePortalLogin/res/menu/captive_portal_login.xml
deleted file mode 100644
index 1a88c5c..0000000
--- a/packages/CaptivePortalLogin/res/menu/captive_portal_login.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    tools:context="com.android.captiveportallogin.CaptivePortalLoginActivity" >
-    <item
-        android:id="@+id/action_do_not_use_network"
-        android:orderInCategory="100"
-        android:showAsAction="never"
-        android:title="@string/action_do_not_use_network"/>
-    <item
-        android:id="@+id/action_use_network"
-        android:orderInCategory="200"
-        android:showAsAction="never"
-        android:title="@string/action_use_network"/>
-
-</menu>
diff --git a/packages/CaptivePortalLogin/res/values-af/strings.xml b/packages/CaptivePortalLogin/res/values-af/strings.xml
deleted file mode 100644
index cf4dc82..0000000
--- a/packages/CaptivePortalLogin/res/values-af/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortal-aanmelding"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Gebruik hierdie netwerk nes dit is"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Moenie hierdie netwerk gebruik nie"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Meld by netwerk aan"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Meld aan by %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Die netwerk waarby jy probeer aansluit, het sekuriteitkwessies."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Gaan in elk geval deur blaaier voort"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Bladsy-inligting"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sekuriteitswaarskuwing"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Bekyk sertifikaat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Hierdie sertifikaat is nie van \'n betroubare owerheid nie."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Die naam van die werf kom nie ooreen met die naam op die sertifikaat nie."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Hierdie sertifikaat het verval."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Hierdie sertifikaat is nog nie geldig nie."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Hierdie sertifikaat het \'n ongeldige datum."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Hierdie sertifikaat is ongeldig."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Onbekende sertifikaatfout."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-am/strings.xml b/packages/CaptivePortalLogin/res/values-am/strings.xml
deleted file mode 100644
index cdcb5a5..0000000
--- a/packages/CaptivePortalLogin/res/values-am/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ይህን አውታረ መረብ እንዳለ ተጠቀምበት"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ይህን አውታረ መረብ አትጠቀምበት"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"ወደ %1$s ይግቡ"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ለመቀላቀል እየሞከሩ ያሉት አውታረ መረብ የደህንነት ችግሮች አሉበት።"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ለምሳሌ፣ የመግቢያ ገጹ የሚታየው ድርጅት ላይሆን ይችላል።"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ለማንኛውም በአሳሽ በኩል ይቀጥሉ"</string>
-    <string name="ok" msgid="1509280796718850364">"እሺ"</string>
-    <string name="page_info" msgid="4048529256302257195">"የገፅ መረጃ"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"አድራሻ:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"የደህንነት ቅንብሮች"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"ምስክሮች ይመልከቱ"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"ይህ ምስክር ከታማኝ ቦታ አይደለም።"</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"የጣቢያው ስም ከምስክር ወረቀቱ ስም ጋር አይዛመድም።"</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"ይህ ምስክር ጊዜው አልፏል"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"ይህ ምስክር ገና ትክክል አይደለም።"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"ይህ ምስክር ትክክለኛ ቀን አለው።"</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"ይህ ምስክር ትክክል ያልሆነ ነው።"</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"ያልታወቀ የምስክር ስህተት።"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ar/strings.xml b/packages/CaptivePortalLogin/res/values-ar/strings.xml
deleted file mode 100644
index 799b8aa..0000000
--- a/packages/CaptivePortalLogin/res/values-ar/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"استخدام هذه الشبكة كما هي"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"عدم استخدام هذه الشبكة"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"تسجيل الدخول إلى الشبكة"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for action_bar_title (5645564790486983117) -->
-    <skip />
-    <string name="ssl_error_warning" msgid="6653188881418638872">"الشبكة التي تحاول الانضمام إليها بها مشكلات أمنية."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"على سبيل المثال، قد لا تنتمي صفحة تسجيل الدخول إلى المنظمة المعروضة."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"المتابعة على أي حال عبر المتصفح"</string>
-    <string name="ok" msgid="1509280796718850364">"موافق"</string>
-    <string name="page_info" msgid="4048529256302257195">"معلومات الصفحة"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"العنوان:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"تحذير أمان"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"عرض الشهادة"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"هذه الشهادة ليست من جهة موثوق بها."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"لا يتطابق اسم الموقع مع الاسم على الشهادة."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"انتهت صلاحية هذه الشهادة."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"هذه الشهادة ليست صالحة بعد."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"تشتمل هذه الشهادة على تاريخ غير صالح."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"هذه الشهادة غير صالحة."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"حدث خطأ غير معروف بالشهادة."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-as/strings.xml b/packages/CaptivePortalLogin/res/values-as/strings.xml
deleted file mode 100644
index 94c3147..0000000
--- a/packages/CaptivePortalLogin/res/values-as/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"এই নেটৱৰ্কটো এইদৰে ব্যৱহাৰ কৰক"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"এই নেটৱৰ্কটো ব্যৱহাৰ নকৰিব"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$st ছাইন ইন কৰক"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"আপুনি সংযোগ কৰিবলৈ চেষ্টা কৰি থকা নেটৱৰ্কটোত সুৰক্ষাজনিত সমস্যা আছে।"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"উদাহৰণস্বৰূপে, আপোনাক দেখুওৱা লগ ইনৰ পৃষ্ঠাটো প্ৰতিষ্ঠানটোৰ নিজা নহ\'বও পাৰে।"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"তথাপি ব্ৰাউজাৰৰ জৰিয়তে অব্যাহত ৰাখক"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-az/strings.xml b/packages/CaptivePortalLogin/res/values-az/strings.xml
deleted file mode 100644
index 44b406d..0000000
--- a/packages/CaptivePortalLogin/res/values-az/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Bu şəbəkəni olduğu kimi istifadə edin"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Bu şəbəkəni istifadə etməyin"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Şəbəkəyə daxil olun"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Daxil olun: %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Qoşulmaq istədiyiniz şəbəkənin təhlükəsizlik problemləri var."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Məsələn, giriş səhifəsi göstərilən təşkilata aid olmaya bilər."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Hər bir halda brazuer ilə davam edin"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-b+sr+Latn/strings.xml b/packages/CaptivePortalLogin/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index f2a6e07..0000000
--- a/packages/CaptivePortalLogin/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Koristi ovu mrežu takvu kakva je"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne koristi ovu mrežu"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Prijavi me na mrežu"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Prijavite se u: %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj pokušavate da se pridružite ima bezbednosnih problema."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi preko pregledača"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-be/strings.xml b/packages/CaptivePortalLogin/res/values-be/strings.xml
deleted file mode 100644
index 09ed1de..0000000
--- a/packages/CaptivePortalLogin/res/values-be/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Выкарыстоўваць гэтую сетку як ёсць"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Не выкарыстоўваць гэту сетку"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Увайсці ў сетку"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Увайсці ў %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"У сеткі, да якой вы спрабуеце далучыцца, ёсць праблемы з бяспекай."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Усё роўна працягнуць праз браўзер"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-bg/strings.xml b/packages/CaptivePortalLogin/res/values-bg/strings.xml
deleted file mode 100644
index 4dd8aa0..0000000
--- a/packages/CaptivePortalLogin/res/values-bg/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Директно използване на тази мрежа"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Без използване на тази мрежа"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Вход в мрежата"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Влезте в/ъв %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Мрежата, към която опитвате да се присъедините, има проблеми със сигурността."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Например страницата за вход може да не принадлежи на показаната организация."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Продължаване през браузър въпреки това"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Данни за страницата"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Адрес:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Предупреждение относно защитата"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Преглед на сертификата"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Сертификатът не е от надежден орган."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Името на сайта не съответства на името в сертификата."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Сертификатът е изтекъл."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Сертификатът още не е валиден."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Този сертификат е с невалидна дата."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Този сертификат е невалиден."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Неизвестна грешка в сертификата."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-bn/strings.xml b/packages/CaptivePortalLogin/res/values-bn/strings.xml
deleted file mode 100644
index fb703cf..0000000
--- a/packages/CaptivePortalLogin/res/values-bn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"যেভাবে আছে সেভাবেই এই নেটওয়ার্ক ব্যবহার করুন"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"এই নেটওয়ার্ক ব্যবহার করবেন না"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে সাইন-ইন করুন"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s তে সাইন-ইন করুন"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন তাতে নিরাপত্তার সমস্যা আছে।"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"উদাহরণস্বরূপ, লগ-ইন পৃষ্ঠাটি প্রদর্শিত প্রতিষ্ঠানের অন্তর্গত নাও হতে পারে৷"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"যাই হোক না কেন ব্রাউজারের মাধ্যমে অবিরত রাখুন"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Sideinfo"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sikkerhetsadvarsel"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vis sertifikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sertifikatet er ikke fra en pålitelig myndighet."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Navnet på nettstedet samsvarer ikke med navnet på sertifikatet."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Sertifikatet er utløpt."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sertifikatet er ikke gyldig ennå."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dette sertifikatet har en ugyldig dato."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Dette sertifikatet er ugyldig."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Ukjent sertifikatfeil."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-bs/strings.xml b/packages/CaptivePortalLogin/res/values-bs/strings.xml
deleted file mode 100644
index 10be0e5..0000000
--- a/packages/CaptivePortalLogin/res/values-bs/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"Prijava na zaštitnom portalu"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Koristi ovu mrežu kakva jeste"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne koristi ovu mrežu"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Prijava na mrežu"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Prijava na %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Naprimjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi preko preglednika"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ca/strings.xml b/packages/CaptivePortalLogin/res/values-ca/strings.xml
deleted file mode 100644
index a2c9ed8..0000000
--- a/packages/CaptivePortalLogin/res/values-ca/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Fes servir aquesta xarxa tal com està."</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"No facis servir aquesta xarxa."</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Inicia la sessió a la xarxa"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Inicia la sessió a %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"La xarxa a què et vols connectar té problemes de seguretat."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continua igualment mitjançant el navegador"</string>
-    <string name="ok" msgid="1509280796718850364">"D\'acord"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informació de la pàgina"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adreça:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Advertiment de seguretat"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visualitza el certificat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Aquest certificat no és d\'una autoritat de confiança."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"El nom del lloc no coincideix amb el del certificat."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Aquest certificat ha caducat."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Aquest certificat encara no és vàlid."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Aquest certificat té una data no vàlida."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Aquest certificat no és vàlid."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Error de certificat desconegut."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-cs/strings.xml b/packages/CaptivePortalLogin/res/values-cs/strings.xml
deleted file mode 100644
index be649a5..0000000
--- a/packages/CaptivePortalLogin/res/values-cs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Použít tuto síť tak, jak je"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Tuto síť nepoužívat"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Přihlásit se k síti"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Přihlaste se k síti %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Síť, ke které se pokoušíte připojit, má bezpečnostní problémy."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Například přihlašovací stránka nemusí patřit do zobrazované organizace."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Přesto pokračovat prostřednictvím prohlížeče"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informace o stránce"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresa:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Upozornění zabezpečení"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Zobrazit certifikát"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Tento certifikát nepochází od důvěryhodné autority."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Název webu se neshoduje s názvem uvedeným v certifikátu."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Platnost certifikátu vypršela."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Tento certifikát ještě není platný."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Datum tohoto certifikátu není platné."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Tento certifikát je neplatný."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Neznámá chyba certifikátu."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-da/strings.xml b/packages/CaptivePortalLogin/res/values-da/strings.xml
deleted file mode 100644
index 8183105..0000000
--- a/packages/CaptivePortalLogin/res/values-da/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"Login til captive portal"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Brug dette netværk, som det er"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Brug ikke dette netværk"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Log ind på netværk"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Log ind på %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Der er sikkerhedsproblemer på det netværk, du forsøger at logge ind på."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Det er f.eks. ikke sikkert, at loginsiden tilhører den anførte organisation."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Fortsæt alligevel via browseren"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Sideoplysninger"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sikkerhedsadvarsel"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vis certifikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Dette certifikat stammer ikke fra en troværdig autoritet."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Navnet på websitet stemmer ikke overens med navnet på certifikatet."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Dette certifikat er udløbet."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Dette certifikat er endnu ikke gyldigt."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dette certifikat har en ugyldig dato."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Dette certifikat er ugyldigt."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Ukendt fejl i certifikatet."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-de/strings.xml b/packages/CaptivePortalLogin/res/values-de/strings.xml
deleted file mode 100644
index 68862bf..0000000
--- a/packages/CaptivePortalLogin/res/values-de/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Dieses Netzwerk im Istzustand verwenden"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Dieses Netzwerk nicht verwenden"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Im Netzwerk anmelden"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"In %1$s anmelden"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört möglicherweise nicht zur angezeigten Organisation."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Trotzdem in einem Browser fortfahren"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Seiteninfo"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sicherheitswarnung"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Zertifikat ansehen"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Dieses Zertifikat wurde nicht von einer vertrauenswürdigen Stelle ausgegeben."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Name der Website stimmt nicht mit dem Namen auf dem Zertifikat überein."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Dieses Zertifikat ist abgelaufen."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Dieses Zertifikat ist noch nicht gültig."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dieses Zertifikat weist ein ungültiges Datum auf."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Dieses Zertifikat ist ungültig."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Unbekannter Zertifikatfehler"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-el/strings.xml b/packages/CaptivePortalLogin/res/values-el/strings.xml
deleted file mode 100644
index 16bf6e2..0000000
--- a/packages/CaptivePortalLogin/res/values-el/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Χρήση αυτού του δικτύου ως έχει"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Να μη χρησιμοποιείται αυτό το δίκτυο"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Σύνδεση στο δίκτυο"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Συνδεθείτε στο %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Παρουσιάζονται προβλήματα ασφάλειας στο δίκτυο στο οποίο προσπαθείτε να συνδεθείτε."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Για παράδειγμα, η σελίδα σύνδεσης ενδέχεται να μην ανήκει στον οργανισμό που εμφανίζεται."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Συνέχεια ούτως ή άλλως μέσω του προγράμματος περιήγησης"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Πληροφορίες σελίδας"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Διεύθυνση:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Προειδοποίηση ασφαλείας"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Προβολή πιστοποιητικού"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Αυτό το πιστοποιητικό δεν προέρχεται από αξιόπιστη αρχή."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Το όνομα του ιστότοπου δεν αντιστοιχεί με το όνομα στο πιστοποιητικό."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Αυτό το πιστοποιητικό έχει λήξει."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Αυτό το πιστοποιητικό δεν είναι έγκυρο ακόμα."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Αυτό το πιστοποιητικό δεν έχει έγκυρη ημερομηνία."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Αυτό το πιστοποιητικό δεν είναι έγκυρο."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Άγνωστο σφάλμα πιστοποιητικού."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-en-rAU/strings.xml b/packages/CaptivePortalLogin/res/values-en-rAU/strings.xml
deleted file mode 100644
index 2e8d1f0..0000000
--- a/packages/CaptivePortalLogin/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Use this network as is"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Do not use this network"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Sign in to network"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Sign in to %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"The network that you’re trying to join has security issues."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"For example, the login page might not belong to the organisation shown."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continue anyway via browser"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-en-rCA/strings.xml b/packages/CaptivePortalLogin/res/values-en-rCA/strings.xml
deleted file mode 100644
index 2e8d1f0..0000000
--- a/packages/CaptivePortalLogin/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Use this network as is"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Do not use this network"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Sign in to network"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Sign in to %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"The network that you’re trying to join has security issues."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"For example, the login page might not belong to the organisation shown."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continue anyway via browser"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml b/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml
deleted file mode 100644
index f940299..0000000
--- a/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Use this network as is"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Do not use this network"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Sign in to network"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Sign in to %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"The network that you’re trying to join has security issues."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"For example, the login page might not belong to the organisation shown."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continue anyway via browser"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Page info"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Address:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Security warning"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"View certificate"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"This certificate isn\'t from a trusted authority."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"The name of the site doesn\'t match the name on the certificate."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"This certificate has expired."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"This certificate isn\'t valid yet."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"This certificate has an invalid date."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"This certificate is invalid."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Unknown certificate error."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml b/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml
deleted file mode 100644
index f940299..0000000
--- a/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Use this network as is"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Do not use this network"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Sign in to network"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Sign in to %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"The network that you’re trying to join has security issues."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"For example, the login page might not belong to the organisation shown."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continue anyway via browser"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Page info"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Address:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Security warning"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"View certificate"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"This certificate isn\'t from a trusted authority."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"The name of the site doesn\'t match the name on the certificate."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"This certificate has expired."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"This certificate isn\'t valid yet."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"This certificate has an invalid date."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"This certificate is invalid."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Unknown certificate error."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-en-rXC/strings.xml b/packages/CaptivePortalLogin/res/values-en-rXC/strings.xml
deleted file mode 100644
index 6d29fd9..0000000
--- a/packages/CaptivePortalLogin/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎CaptivePortalLogin‎‏‎‎‏‎"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎Use this network as is‎‏‎‎‏‎"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‎Do not use this network‎‏‎‎‏‎"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎Sign in to network‎‏‎‎‏‎"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‎‏‎Sign in to %1$s‎‏‎‎‏‎"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎The network you’re trying to join has security issues.‎‏‎‎‏‎"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎For example, the login page may not belong to the organization shown.‎‏‎‎‏‎"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎Continue anyway via browser‎‏‎‎‏‎"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml b/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml
deleted file mode 100644
index c011664..0000000
--- a/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Usar esta red como está"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"No usar esta red"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Acceder a la red"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Acceder a %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"La red a la que intentas conectarte tiene problemas de seguridad."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar de todos modos desde el navegador"</string>
-    <string name="ok" msgid="1509280796718850364">"Aceptar"</string>
-    <string name="page_info" msgid="4048529256302257195">"Información de la página"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Dirección:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Advertencia de seguridad"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Ver certificado"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado no proviene de una autoridad confiable."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"El nombre del sitio no coincide con el nombre del certificado."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado ha expirado."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado aún no es válido."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"La fecha de este certificado no es válida."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado no es válido."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Error de certificado desconocido"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-es/strings.xml b/packages/CaptivePortalLogin/res/values-es/strings.xml
deleted file mode 100644
index 65244e7..0000000
--- a/packages/CaptivePortalLogin/res/values-es/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utilizar esta red tal cual"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"No utilizar esta red"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Iniciar sesión en la red"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Inicia sesión en %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"La red a la que intentas unirte tiene problemas de seguridad."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Por ejemplo, es posible que la página de inicio de sesión no pertenezca a la organización mostrada."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar de todos modos a través del navegador"</string>
-    <string name="ok" msgid="1509280796718850364">"Aceptar"</string>
-    <string name="page_info" msgid="4048529256302257195">"Información de la página"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Dirección:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Advertencia de seguridad"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Ver certificado"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado no procede de una entidad de certificación de confianza."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"El nombre del sitio no coincide con el del certificado."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado ha caducado."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado aún no es válido."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"La fecha de este certificado no es válida."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado no es válido."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Error de certificado desconocido"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-et/strings.xml b/packages/CaptivePortalLogin/res/values-et/strings.xml
deleted file mode 100644
index e4c4c98..0000000
--- a/packages/CaptivePortalLogin/res/values-et/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Kasuta seda võrku olemasoleval kujul"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ära kasuta seda võrku"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Logi võrku sisse"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Logige sisse: %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Võrgul, millega üritate ühenduse luua, on turvaprobleeme."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Näiteks ei pruugi sisselogimisleht kuuluda kuvatavale organisatsioonile."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Jätka siiski brauseris"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Lehe teave"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Aadress:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Turvahoiatus"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Kuva sertifikaat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"See sertifikaat ei pärine usaldusväärselt asutuselt."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Saidi nimi ei vasta sertifikaadil olevale nimele."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"See sertifikaat on aegunud."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"See sertifikaat pole veel kehtiv."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Sellel sertifikaadil on kehtetu kuupäev."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"See sertifikaat on kehtetu."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Tundmatu sertifikaadiviga."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-eu/strings.xml b/packages/CaptivePortalLogin/res/values-eu/strings.xml
deleted file mode 100644
index 8925aac..0000000
--- a/packages/CaptivePortalLogin/res/values-eu/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Erabili sare hau bere horretan"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ez erabili sare hau"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Hasi saioa sarean"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Hasi saioa %1$s sarean"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Erabili nahi duzun sareak segurtasun-arazoak ditu."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Adibidez, baliteke saioa hasteko orria adierazitako erakundearena ez izatea."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Jarraitu arakatzailearen bidez, halere"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-fa/strings.xml b/packages/CaptivePortalLogin/res/values-fa/strings.xml
deleted file mode 100644
index 27b9b7f..0000000
--- a/packages/CaptivePortalLogin/res/values-fa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"از این شبکه همانطور که هست استفاده شود"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"از این شبکه استفاده نشود"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ورود به سیستم شبکه"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"‏ورود به سیستم %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"شبکه‌ای که می‌خواهید به آن بپیوندید مشکلات امنیتی دارد."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"به عنوان مثال، صفحه ورود به سیستم ممکن است متعلق به سازمان نشان داده شده نباشد."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"در هر صورت از طریق مرورگر ادامه یابد"</string>
-    <string name="ok" msgid="1509280796718850364">"تأیید"</string>
-    <string name="page_info" msgid="4048529256302257195">"اطلاعات صفحه"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"آدرس:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"اخطار امنیتی"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"مشاهده گواهی"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"این گواهی از یک منبع مورد اطمینان صادر نشده است."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"نام سایت با نام موجود در گواهی مطابقت ندارد."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"این گواهی منقضی شده است."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"این گواهی هنوز معتبر نیست."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"تاریخ این گواهی نامعتبر است."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"این گواهی نامعتبر است."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"خطای ناشناخته در گواهی."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-fi/strings.xml b/packages/CaptivePortalLogin/res/values-fi/strings.xml
deleted file mode 100644
index 8086fbf..0000000
--- a/packages/CaptivePortalLogin/res/values-fi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Käytä tätä verkkoa sellaisenaan"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Älä käytä tätä verkkoa"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Kirjaudu verkkoon"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Kirjaudu sisään kohteeseen %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Verkossa, johon yrität muodostaa yhteyttä, on turvallisuusongelmia."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Kirjautumissivu ei välttämättä kuulu näytetylle organisaatiolle."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Jatka silti selaimen kautta."</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Sivun tiedot"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Osoite:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Suojausvaroitus"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Näytä varmenne"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Varmenteen myöntäjä ei ole luotettava taho."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Sivuston nimi ei vastaa varmenteessa olevaa nimeä."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Varmenne ei ole enää voimassa."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Varmenne ei ole vielä voimassa."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Varmenteen päiväys ei kelpaa."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Varmenne on virheellinen."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Tuntematon varmennevirhe."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-fr-rCA/strings.xml b/packages/CaptivePortalLogin/res/values-fr-rCA/strings.xml
deleted file mode 100644
index a7525a5..0000000
--- a/packages/CaptivePortalLogin/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utiliser ce réseau tel quel"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne pas utiliser ce réseau"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Connectez-vous au réseau"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Connexion à %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Le réseau que vous essayez de rejoindre présente des problèmes de sécurité."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Par exemple, la page de connexion pourrait ne pas appartenir à l\'organisation représentée."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuer quand même dans un navigateur"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-fr/strings.xml b/packages/CaptivePortalLogin/res/values-fr/strings.xml
deleted file mode 100644
index 39fc569..0000000
--- a/packages/CaptivePortalLogin/res/values-fr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utiliser ce réseau tel quel"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne pas utiliser ce réseau"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Se connecter au réseau"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Se connecter à %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Le réseau que vous essayez de rejoindre présente des problèmes de sécurité."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Par exemple, la page de connexion peut ne pas appartenir à l\'organisation représentée."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuer quand même dans le navigateur"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Infos sur la page"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresse :"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Avertissement de sécurité"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Afficher le certificat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ce certificat provient d\'une autorité non approuvée."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Le nom du site ne correspond pas au nom indiqué dans le certificat."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Le certificat a expiré."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Ce certificat n\'est pas encore valide."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"La date de ce certificat n\'est pas valide."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Ce certificat n\'est pas valide."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Erreur : Certificat inconnu."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-gl/strings.xml b/packages/CaptivePortalLogin/res/values-gl/strings.xml
deleted file mode 100644
index 6578285..0000000
--- a/packages/CaptivePortalLogin/res/values-gl/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utilizar esta rede tal como está"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Non utilizar esta rede"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Inicia sesión na rede"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Iniciar sesión en %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"A rede á que tentas unirte ten problemas de seguranza."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Por exemplo, é posible que a páxina de inicio de sesión non pertenza á organización que se mostra."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar igualmente co navegador"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-gu/strings.xml b/packages/CaptivePortalLogin/res/values-gu/strings.xml
deleted file mode 100644
index c15eca4..0000000
--- a/packages/CaptivePortalLogin/res/values-gu/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"આ નેટવર્કનો જેમનો તેમ ઉપયોગ કરો"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"આ નેટવર્કનો ઉપયોગ કરશો નહીં"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"નેટવર્ક પર સાઇન ઇન કરો"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$sમાં સઇન ઇન કરો"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"તમે જોડાવાનો પ્રયાસ કરી રહ્યાં છો તે નેટવર્કમાં સુરક્ષા સમસ્યાઓ છે."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ઉદાહરણ તરીકે, લોગિન પૃષ્ઠ દર્શાવેલ સંસ્થાનું હોઈ શકતું નથી."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"બ્રાઉઝર મારફતે કોઈપણ રીતે ચાલુ રાખો"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-hi/strings.xml b/packages/CaptivePortalLogin/res/values-hi/strings.xml
deleted file mode 100644
index d924fff..0000000
--- a/packages/CaptivePortalLogin/res/values-hi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"इस नेटवर्क का उपयोग जैसा है वैसा ही करें"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"इस नेटवर्क का उपयोग न करें"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"नेटवर्क में साइन इन करें"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s में साइन इन करें"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"आप जिस नेटवर्क में शामिल होने का प्रयास कर रहे हैं उसमें सुरक्षा समस्‍याएं हैं."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"उदाहरण के लिए, हो सकता है कि लॉगिन पृष्‍ठ दिखाए गए संगठन से संबद्ध ना हो."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ब्राउज़र के द्वारा फिर जारी रखें"</string>
-    <string name="ok" msgid="1509280796718850364">"ठीक"</string>
-    <string name="page_info" msgid="4048529256302257195">"पृष्ठ जानकारी"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"पता:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"सुरक्षा चेतावनी"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"प्रमाणपत्र देखें"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"यह प्रमाणपत्र किसी विश्वस्त प्राधिकारी का नहीं है."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"साइट का नाम, प्रमाणपत्र के नाम से मिलान नहीं करता."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"इस प्रमाणपत्र की समय सीमा समाप्त हो गई है."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"यह प्रमाणपत्र अभी तक मान्य नहीं है."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"इस प्रमाणपत्र में एक अमान्‍य दिनांक है."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"यह प्रमाणपत्र अमान्य है."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"अज्ञात प्रमाणपत्र त्रुटि."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-hr/strings.xml b/packages/CaptivePortalLogin/res/values-hr/strings.xml
deleted file mode 100644
index 11b1dd3..0000000
--- a/packages/CaptivePortalLogin/res/values-hr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Upotrebljavaj ovu mrežu u zatečenom stanju"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne upotrebljavaj ovu mrežu"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Prijava na mrežu"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Prijavite se na %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj se pokušavate pridružiti ima sigurnosne poteškoće."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi putem preglednika"</string>
-    <string name="ok" msgid="1509280796718850364">"U redu"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informacije o stranici"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresa:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Upozorenje o sigurnosti"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Prikaži certifikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ovaj certifikat ne potječe iz pouzdanog izvora."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Naziv web-lokacije ne podudara se s nazivom na certifikatu."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Ovaj je certifikat istekao."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Ovaj certifikat još nije važeći."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Ovaj certifikat ima nevažeći datum."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Ovaj certifikat nije valjan."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Nepoznata pogreška certifikata."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-hu/strings.xml b/packages/CaptivePortalLogin/res/values-hu/strings.xml
deleted file mode 100644
index 145e2ab..0000000
--- a/packages/CaptivePortalLogin/res/values-hu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Hálózat használata jelen állapotában"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne használja ezt a hálózatot"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Bejelentkezés a hálózatba"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Bejelentkezés a következőbe: %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Például lehet, hogy a bejelentkezési oldal nem a megjelenített szervezethez tartozik."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Folytatás ennek ellenére böngészőn keresztül"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Oldaladatok"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Cím:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Biztonsági figyelmeztetés"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Tanúsítvány megtekintése"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ez a tanúsítvány nem hiteles tanúsítványkibocsátótól származik."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"A webhely neve nem egyezik a tanúsítványon lévő névvel."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"A tanúsítvány lejárt."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"A tanúsítvány még nem érvényes."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"A tanúsítvány dátuma érvénytelen."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Ez a tanúsítvány érvénytelen."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Ismeretlen tanúsítványhiba."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-hy/strings.xml b/packages/CaptivePortalLogin/res/values-hy/strings.xml
deleted file mode 100644
index a0ee862..0000000
--- a/packages/CaptivePortalLogin/res/values-hy/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Օգտագործել այս ցանցն ինչպես կա"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Չօգտագործել այս ցանցը"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Մուտք գործել ցանց"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Մուտք գործել %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Ցանցը, որին փորձում եք միանալ, անվտանգության խնդիրներ ունի:"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Օրինակ՝ մուտքի էջը կարող է ցուցադրված կազմակերպության էջը չլինել:"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Շարունակել այնուամենայնիվ դիտարկիչի միջոցով"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-in/strings.xml b/packages/CaptivePortalLogin/res/values-in/strings.xml
deleted file mode 100644
index e5b4eb4..0000000
--- a/packages/CaptivePortalLogin/res/values-in/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Gunakan jaringan ini sebagaimana adanya"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Jangan gunakan jaringan ini"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Masuk ke jaringan"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Login ke %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Jaringan yang ingin Anda masuki mengalami masalah keamanan."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Misalnya, halaman masuk mungkin bukan milik organisasi yang ditampilkan."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Tetap lanjutkan melalui browser"</string>
-    <string name="ok" msgid="1509280796718850364">"Oke"</string>
-    <string name="page_info" msgid="4048529256302257195">"Info laman"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Alamat:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Peringatan sertifikat"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Lihat sertifikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sertifikat ini tidak berasal dari otoritas tepercaya."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Nama situs tidak cocok dengan nama pada sertifikat."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Sertifikat ini telah kedaluwarsa."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sertifikat ini belum valid."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Tanggal sertifikat ini tidak valid."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Sertifikat ini tidak valid."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Kesalahan sertifikat tak dikenal."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-is/strings.xml b/packages/CaptivePortalLogin/res/values-is/strings.xml
deleted file mode 100644
index 8fde24b..0000000
--- a/packages/CaptivePortalLogin/res/values-is/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Nota þetta net óbreytt"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ekki nota þetta net"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Skrá inn á net"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Skrá inn á %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Öryggisvandamál eru á netinu sem þú ert að reyna að tengjast."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Til dæmis getur verið að innskráningarsíðan tilheyri ekki fyrirtækinu sem birtist."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Halda samt áfram í vafra"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-it/strings.xml b/packages/CaptivePortalLogin/res/values-it/strings.xml
deleted file mode 100644
index 2cc4038..0000000
--- a/packages/CaptivePortalLogin/res/values-it/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utilizza questa rete così com\'è"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Non utilizzare questa rete"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Accedi alla rete"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Accedi a %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"La rete a cui stai tentando di accedere presenta problemi di sicurezza."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Ad esempio, la pagina di accesso potrebbe non appartenere all\'organizzazione indicata."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continua comunque dal browser"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Info pagina"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Indirizzo:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Avviso di sicurezza"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visualizza certificato"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Questo certificato non proviene da un\'autorità attendibile."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Il nome del sito non corrisponde al nome nel certificato."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Il certificato è scaduto."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Questo certificato non è ancora valido."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Questo certificato presenta una data non valida."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Questo certificato non è valido."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Errore certificato sconosciuto."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-iw/strings.xml b/packages/CaptivePortalLogin/res/values-iw/strings.xml
deleted file mode 100644
index 527e692..0000000
--- a/packages/CaptivePortalLogin/res/values-iw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"השתמש ברשת זו כפי שהיא"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"אל תשתמש ברשת זו"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"היכנס לרשת"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"‏כניסה אל %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"יש בעיות אבטחה ברשת שאליה אתה מנסה להתחבר."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"המשך בכל זאת באמצעות דפדפן"</string>
-    <string name="ok" msgid="1509280796718850364">"אישור"</string>
-    <string name="page_info" msgid="4048529256302257195">"פרטי דף"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"כתובת:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"אזהרת אבטחה"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"הצג אישור"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"אישור זה אינו מגיע מרשות אמינה."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"שם האתר לא תואם לשם באישור."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"פג תוקפו של אישור זה."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"אישור זה אינו חוקי עדיין."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"לאישור זה יש תאריך בלתי חוקי."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"אישור זה אינו חוקי."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"שגיאת אישור לא ידועה."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ja/strings.xml b/packages/CaptivePortalLogin/res/values-ja/strings.xml
deleted file mode 100644
index bcc8686..0000000
--- a/packages/CaptivePortalLogin/res/values-ja/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"このネットワークをそのまま使用する"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"このネットワークを使用しない"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ネットワークにログイン"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s にログイン"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"接続しようとしているネットワークにセキュリティの問題があります。"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ブラウザから続行"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"ページ情報"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"アドレス:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"セキュリティ警告"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"証明書を表示"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"この証明書は信頼できる認証機関のものではありません。"</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"サイト名と証明書上の名前が一致しません。"</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"この証明書は有効期限切れです。"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"この証明書はまだ有効ではありません。"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"この証明書の日付は無効です。"</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"この証明書は無効です。"</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"不明な証明書エラーです。"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ka/strings.xml b/packages/CaptivePortalLogin/res/values-ka/strings.xml
deleted file mode 100644
index 1ccff12..0000000
--- a/packages/CaptivePortalLogin/res/values-ka/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ამ ქსელის გამოყენება, როგორც არის"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ეს ქსელი არ გამოიყენო"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ქსელში შესვლა"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s-ში შესვლა"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ქსელს, რომელზედაც მიერთებას ცდილობთ, უსაფრთხოების პრობლემები აქვს."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"მაგალითად, სისტემაში შესვლის გვერდი შეიძლება არ ეკუთვნოდეს ნაჩვენებ ორგანიზაციას."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ბრაუზერში გაგრძელება"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-kk/strings.xml b/packages/CaptivePortalLogin/res/values-kk/strings.xml
deleted file mode 100644
index a904dea..0000000
--- a/packages/CaptivePortalLogin/res/values-kk/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Осы желіні бар күйінде пайдалану"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Осы желіні пайдаланбау"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Желіге кіру"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s жүйесіне кіру"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Қосылайын деп жатқан желіңіз қауіпсіз болуы мүмкін."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Мысалы, кіру беті көрсетілген ұйымға тиесілі болмауы мүмкін."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Бәрібір браузер арқылы жалғастыру"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-km/strings.xml b/packages/CaptivePortalLogin/res/values-km/strings.xml
deleted file mode 100644
index a0497f8..0000000
--- a/packages/CaptivePortalLogin/res/values-km/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ប្រើ​បណ្ដាញ​នេះ​ជា"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"កុំ​ប្រើ​បណ្ដាញ​នេះ"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ចូលទៅបណ្ដាញ"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"ចូលទៅ %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"បណ្តាញដែលអ្នកកំពុងព្យាយាមចូលមានបញ្ហាសុវត្ថិភាព។"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ឧបករណ៍៖ ទំព័រចូលនេះអាចនឹងមិនមែនជាកម្មសិទ្ធិរបស់ស្ថាប័នដែលបានបង្ហាញនេះទេ។"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"យ៉ាងណាក៏ដោយនៅតែបន្តតាមរយៈកម្មវិធីរុករក"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-kn/strings.xml b/packages/CaptivePortalLogin/res/values-kn/strings.xml
deleted file mode 100644
index 3084504..0000000
--- a/packages/CaptivePortalLogin/res/values-kn/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ಈ ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಹೀಗೆ ಬಳಸಿ"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ಈ ನೆಟ್‌ವರ್ಕ್ ಬಳಸಬೇಡಿ"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ನೀವು ಸೇರಬೇಕೆಂದಿರುವ ನೆಟ್‌ವರ್ಕ್ ಭದ್ರತೆ ಸಮಸ್ಯೆಗಳನ್ನು ಹೊಂದಿದೆ."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ಉದಾಹರಣೆಗೆ, ಲಾಗಿನ್ ಪುಟವು ತೋರಿಸಲಾಗಿರುವ ಸಂಸ್ಥೆಗೆ ಸಂಬಂಧಿಸಿರುವುದಿಲ್ಲ."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ಹೇಗಾದರೂ ಬ್ರೌಸರ್ ಮೂಲಕ ಮುಂದುವರಿಸಿ"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ko/strings.xml b/packages/CaptivePortalLogin/res/values-ko/strings.xml
deleted file mode 100644
index 7a7f7e0..0000000
--- a/packages/CaptivePortalLogin/res/values-ko/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"현재 상태로 이 네트워크 사용"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"이 네트워크 사용 안함"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"네트워크에 로그인"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s에 로그인"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"가입하려는 네트워크에 보안 문제가 있습니다."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"브라우저를 통해 계속하기"</string>
-    <string name="ok" msgid="1509280796718850364">"확인"</string>
-    <string name="page_info" msgid="4048529256302257195">"페이지 정보"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"주소:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"보안 경고"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"인증서 보기"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"신뢰할 수 있는 인증 기관에서 발급한 인증서가 아닙니다."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"사이트 이름이 인증서에 있는 것과 일치하지 않습니다."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"인증서가 만료되었습니다."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"인증서가 아직 유효하지 않습니다."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"인증서 날짜가 유효하지 않습니다."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"인증서가 잘못되었습니다."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"알 수 없는 인증서 오류입니다."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ky/strings.xml b/packages/CaptivePortalLogin/res/values-ky/strings.xml
deleted file mode 100644
index af81ce3..0000000
--- a/packages/CaptivePortalLogin/res/values-ky/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Бул тармак кандай болсо, ошондой колдонулсун"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Бул тармак колдонулбасын"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Тармакка кирүү"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s каттоо эсебине кириңиз"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Кошулайын деген тармагыңызда коопсуздук көйгөйлөрү бар."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Мисалы, каттоо эсебине кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Баары бир серепчи аркылуу улантуу"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-lo/strings.xml b/packages/CaptivePortalLogin/res/values-lo/strings.xml
deleted file mode 100644
index ee2b263..0000000
--- a/packages/CaptivePortalLogin/res/values-lo/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"​ໃຊ້​ເຄືອ​ຂ່າຍ​ນີ້​ຕາມ​ທີ່​ມັນ​ເປັນ"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ບໍ່​ໃຊ້​ເຄືອ​ຂ່າຍ​ນີ້"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"ເຂົ້າສູ່ລະບົບ %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ເຄືອ​ຂ່າຍ​ທີ່​ທ່ານ​ກຳ​ລັງ​ເຂົ້າ​ຮ່ວມ​ມີ​ບັນ​ຫາ​ຄວາມ​ປອດ​ໄພ."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ຕົວ​ຢ່າງ, ໜ້າ​ລົງ​ຊື່​ເຂົ້າ​ໃຊ້​ອາດ​ຈະ​ບໍ່​ເປັນ​ຂອງ​ອົງ​ການ​ທີ່​ສະ​ແດງ​ຂຶ້ນ."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ແນວ​ໃດ​ກໍ່​ສືບ​ຕໍ່​ຜ່ານບ​ຣາວ​ເຊີ"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-lt/strings.xml b/packages/CaptivePortalLogin/res/values-lt/strings.xml
deleted file mode 100644
index 158f7ce..0000000
--- a/packages/CaptivePortalLogin/res/values-lt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Naudoti šį tinklą tokį, koks yra"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Nenaudoti šio tinklo"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Prisijungti prie tinklo"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Prisijungimas prie „%1$s“"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Kilo tinklo, prie kurio bandote prisijungti, problemų."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Vis tiek tęsti naudojant naršyklę"</string>
-    <string name="ok" msgid="1509280796718850364">"Gerai"</string>
-    <string name="page_info" msgid="4048529256302257195">"Puslapio informacija"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresas:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Saugos įspėjimas"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Žiūrėti sertifikatą"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Šį sertifikatą išdavė nepatikima įstaiga."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Svetainės pavadinimas neatitinka sertifikate nurodyto pavadinimo."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Šio sertifikato galiojimo laikas baigėsi."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Šis sertifikatas dar negalioja."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Šio sertifikato data netinkama."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Šis sertifikatas netinkamas."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Nežinoma sertifikato klaida."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-lv/strings.xml b/packages/CaptivePortalLogin/res/values-lv/strings.xml
deleted file mode 100644
index a42cb22..0000000
--- a/packages/CaptivePortalLogin/res/values-lv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Izmantot tīklu ar pašreizējiem iestatījumiem"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Neizmantot šo tīklu"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Pierakstīties tīklā"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Pierakstieties produktā %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Tīklam, kuram mēģināt pievienoties, ir drošības problēmas."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Piemēram, pieteikšanās lapa, iespējams, nepieder norādītajai organizācijai."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Tik un tā turpināt, izmantojot pārlūkprogrammu"</string>
-    <string name="ok" msgid="1509280796718850364">"Labi"</string>
-    <string name="page_info" msgid="4048529256302257195">"Lapas informācija"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adrese:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Drošības brīdinājums"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Skatīt sertifikātu"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Šo sertifikātu nav izsniegusi uzticama iestāde."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Vietnes nosaukums neatbilst nosaukumam sertifikātā."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Šī sertifikāta derīguma termiņš ir beidzies."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Šis sertifikāts vēl nav derīgs."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Šī sertifikāta datums nav derīgs."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Šis sertifikāts nav derīgs."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Nezināma sertifikāta kļūda."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-mk/strings.xml b/packages/CaptivePortalLogin/res/values-mk/strings.xml
deleted file mode 100644
index 2ae32c8..0000000
--- a/packages/CaptivePortalLogin/res/values-mk/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Користи ја мрежата во оваа состојба"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Не ја користи мрежата"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Најавете се на мрежа"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Најавете се на %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Мрежата на која се обидувате да се придружите има проблеми со безбедноста."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"На пример, страницата за најавување може да не припаѓа на организацијата што е прикажана."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Сепак продолжи преку прелистувач"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ml/strings.xml b/packages/CaptivePortalLogin/res/values-ml/strings.xml
deleted file mode 100644
index 79551f8..0000000
--- a/packages/CaptivePortalLogin/res/values-ml/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ഈ നെറ്റ്‌വർക്ക് മാറ്റമൊന്നും വരുത്താതെ ഉപയോഗിക്കുക"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ഈ നെറ്റ്‌വർക്ക് ഉപയോഗിക്കരുത്"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"നെറ്റ്‌വർക്കിൽ സൈൻ ഇൻ ചെയ്യുക"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s എന്നതിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"നിങ്ങൾ ചേരാൻ ശ്രമിക്കുന്ന നെറ്റ്‌വർക്കിൽ സുരക്ഷാ പ്രശ്‌നങ്ങളുണ്ടായിരിക്കാം."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ഉദാഹരണത്തിന്, കാണിച്ചിരിക്കുന്ന ഓർഗനൈസേഷന്റേതായിരിക്കില്ല ലോഗിൻ പേജ്."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"എന്തായാലും ബ്രൗസർ വഴി തുടരുക"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-mn/strings.xml b/packages/CaptivePortalLogin/res/values-mn/strings.xml
deleted file mode 100644
index 67670915..0000000
--- a/packages/CaptivePortalLogin/res/values-mn/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Энэ сүлжээг ашиглана уу"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Энэ сүлжээг бүү ашиглана уу"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Сүлжээнд нэвтэрнэ үү"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s-д нэвтрэх"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Таны нэгдэх гэж буй сүлжээ аюулгүй байдлын асуудалтай байна."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Жишээлбэл нэвтрэх хуудас нь харагдах байгууллагынх биш байж болзошгүй."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Ямартаа ч хөтчөөр үргэлжлүүлэх"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-mr/strings.xml b/packages/CaptivePortalLogin/res/values-mr/strings.xml
deleted file mode 100644
index fac0a08..0000000
--- a/packages/CaptivePortalLogin/res/values-mr/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"हे नेटवर्क जसेच्या तसे वापरा"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"हे नेटवर्क वापरू नका"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"नेटवर्क मध्‍ये साइन इन करा"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$sमध्‍ये साइन इन करा"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ज्या नेटवर्कमध्‍ये आपण सामील होण्याचा प्रयत्न करीत आहात त्यात सुरक्षितता समस्या आहेत."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"उदाहरणार्थ, लॉगिन पृष्‍ठ कदाचित दर्शविलेल्या संस्थेच्या मालकीचे नसावे."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ब्राउझरद्वारे तरीही सुरु ठेवा"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ms/strings.xml b/packages/CaptivePortalLogin/res/values-ms/strings.xml
deleted file mode 100644
index aaa51c8..0000000
--- a/packages/CaptivePortalLogin/res/values-ms/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Gunakan rangkaian ini"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Jangan gunakan rangkaian ini"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Log masuk ke rangkaian"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Log masuk ke %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Rangkaian yang anda cuba sertai mempunyai isu keselamatan."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Teruskan juga melalui penyemak imbas"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Maklumat halaman"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Alamat:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Amaran keselamatan"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Lihat sijil"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sijil ini bukan daripada pihak berkuasa yang dipercayai."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Nama tapak tidak sepadan dengan nama pada sijil."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Sijil ini telah tamat tempoh."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sijil ini belum lagi sah."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Sijil ini mempunyai tarikh yang tidak sah."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Sijil ini tidak sah."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Ralat sijil tidak diketahui."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-my/strings.xml b/packages/CaptivePortalLogin/res/values-my/strings.xml
deleted file mode 100644
index 902834b..0000000
--- a/packages/CaptivePortalLogin/res/values-my/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ဒီကွန်ရက်ကို လက်ရှိအတိုင်း သုံးရန်"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ဒီကွန်ရက်ကို မသုံးပါနှင့်"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"သင်ချိတ်ဆက်ရန် ကြိုးစားနေသည့် ကွန်ရက်သည် လုံခြုံရေးပြဿနာ ရှိနေသည်။"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ဥပမာ၊ ဝင်ရောက်ရန် စာမျက်နှာသည် ပြသထားသည့် အဖွဲ့အစည်းနှင့် သက်ဆိုင်မှု မရှိနိုင်ပါ။"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ဘရောက်ဇာမှတစ်ဆင့် ဆက်လုပ်ရန်"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-nb/strings.xml b/packages/CaptivePortalLogin/res/values-nb/strings.xml
deleted file mode 100644
index 29c23ed..0000000
--- a/packages/CaptivePortalLogin/res/values-nb/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Bruk dette nettverket som det er"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ikke bruk dette nettverket"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Logg på nettverk"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Logg på %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Nettverket du prøver å logge på, har sikkerhetsproblemer."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Det er for eksempel mulig at påloggingssiden kanskje ikke tilhører organisasjonen som vises."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Fortsett likevel via nettleseren"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Sideinfo"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sikkerhetsadvarsel"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vis sertifikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sertifikatet er ikke fra en pålitelig myndighet."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Navnet på nettstedet samsvarer ikke med navnet på sertifikatet."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Sertifikatet er utløpt."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sertifikatet er ikke gyldig ennå."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dette sertifikatet har en ugyldig dato."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Dette sertifikatet er ugyldig."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Ukjent sertifikatfeil."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ne/strings.xml b/packages/CaptivePortalLogin/res/values-ne/strings.xml
deleted file mode 100644
index 87a30c0..0000000
--- a/packages/CaptivePortalLogin/res/values-ne/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"यो सञ्जाल जस्तो छ प्रयोग गर्नुहोस्"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"यो सञ्जाल प्रयोग नगर्नुहोस्"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"सञ्जालमा साइन इन गर्नुहोस्"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s मा साइन इन गर्नुहोस्"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"तपाईँले सामेल हुन प्रयास गरिरहनु भएको नेटवर्कमा सुरक्षा मुद्दाहरू छन्।"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"उदाहरणका लागि, लग इन पृष्ठ देखाइएको संस्थाको नहुन सक्छ।"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"जे भए पनि ब्राउजर मार्फत जारी राख्नुहोस्"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-nl/strings.xml b/packages/CaptivePortalLogin/res/values-nl/strings.xml
deleted file mode 100644
index 2cbca06..0000000
--- a/packages/CaptivePortalLogin/res/values-nl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Dit netwerk in de huidige staat gebruiken"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Dit netwerk niet gebruiken"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Inloggen bij netwerk"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Inloggen bij %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Het netwerk waarmee u verbinding probeert te maken, heeft beveiligingsproblemen."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Zo hoort de weergegeven inlogpagina misschien niet bij de weergegeven organisatie."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Toch doorgaan via browser"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Pagina-informatie"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Beveiligingsmelding"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Certificaat weergeven"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Dit is geen certificaat van een vertrouwde autoriteit."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"De naam van deze site komt niet overeen met de naam op het certificaat."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Dit certificaat is verlopen."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Dit certificaat is nog niet geldig."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dit certificaat heeft een ongeldige datum."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Dit certificaat is ongeldig."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Onbekende certificaatfout."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-or/strings.xml b/packages/CaptivePortalLogin/res/values-or/strings.xml
deleted file mode 100644
index 80074c3..0000000
--- a/packages/CaptivePortalLogin/res/values-or/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ଏହି ନେଟ୍‌ୱର୍କ ଯେପରି ଅଛି, ସେହିପରି ବ୍ୟବହାର କରନ୍ତୁ"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ଏହି ନେଟ୍‌ୱର୍କକୁ ବ୍ୟବହାର କରନ୍ତୁ ନାହିଁ"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ନେଟ୍‌ୱର୍କରେ ସାଇନ୍‍ ଇନ୍‍ କରନ୍ତୁ"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$sରେ ସାଇନ୍‍-ଇନ୍‍ କରନ୍ତୁ"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ଆପଣ ଯୋଗ ଦେବାକୁ ଚେଷ୍ଟା କରୁଥିବା ନେଟ୍‌ୱର୍କର ସୁରକ୍ଷା ସମସ୍ୟା ଅଛି।"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ଉଦାହରଣସ୍ୱରୂପ, ଲଗଇନ୍‍ ପୃଷ୍ଠା ଦେଖାଯାଇଥିବା ସଂସ୍ଥାର ନହୋଇଥାଇପାରେ।"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ବ୍ରାଉଜର୍‍ ଜରିଆରେ ଯେମିତିବି ହେଉ ଜାରି ରଖନ୍ତୁ"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-pa/strings.xml b/packages/CaptivePortalLogin/res/values-pa/strings.xml
deleted file mode 100644
index 03e252f..0000000
--- a/packages/CaptivePortalLogin/res/values-pa/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ਇਸ ਨੈੱਟਵਰਕ ਨੂੰ ਉਵੇਂ ਵਰਤੋ ਜਿਵੇਂ ਇਹ ਹੈ"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ਇਹ ਨੈੱਟਵਰਕ ਨਾ ਵਰਤੋ"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ਤੁਹਾਡੇ ਦੁਆਰਾ ਸ਼ਾਮਿਲ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੇ ਜਾ ਰਹੇ ਨੈੱਟਵਰਕ ਵਿੱਚ ਸੁਰੱਖਿਆ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ।"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ਉਦਾਹਰਣ ਵੱਜੋਂ, ਲੌਗ-ਇਨ ਪੰਨਾ ਦਿਖਾਈ ਗਈ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਨਹੀਂ ਹੋ ਸਕਦਾ ਹੈ।"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ਬ੍ਰਾਊਜ਼ਰ ਰਾਹੀਂ ਫਿਰ ਵੀ ਜਾਰੀ ਰੱਖੋ"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-pl/strings.xml b/packages/CaptivePortalLogin/res/values-pl/strings.xml
deleted file mode 100644
index 9ba066e..0000000
--- a/packages/CaptivePortalLogin/res/values-pl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Używaj tej sieci tak jak jest"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Nie używaj tej sieci"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Zaloguj się do sieci"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Zaloguj się w aplikacji %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"W sieci, z którą próbujesz się połączyć, występują problemy z zabezpieczeniami."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Na przykład strona logowania może nie należeć do wyświetlanej organizacji."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Kontynuuj mimo to w przeglądarce"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informacje o stronie"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Ostrzeżenie zabezpieczeń"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Wyświetl certyfikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Certyfikat nie pochodzi od zaufanego urzędu."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Nazwa witryny nie pasuje do nazwy na certyfikacie."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Ten certyfikat wygasł."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Certyfikat nie jest jeszcze ważny."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Certyfikat ma nieprawidłową datę."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Certyfikat jest nieprawidłowy."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Nieznany błąd certyfikatu"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-pt-rBR/strings.xml b/packages/CaptivePortalLogin/res/values-pt-rBR/strings.xml
deleted file mode 100644
index 3d1064c..0000000
--- a/packages/CaptivePortalLogin/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Usar esta rede como está"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Não usar esta rede"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Fazer login na rede"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Fazer login em %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"A rede à qual você está tentando se conectar tem problemas de segurança."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar mesmo assim pelo navegador"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml b/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 5bef235..0000000
--- a/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utilizar esta rede como está"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Não utilizar esta rede"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Início de sessão na rede"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Iniciar sessão em %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"A rede à qual está a tentar aceder tem problemas de segurança."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Por exemplo, a página de início de sessão pode não pertencer à entidade apresentada."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar mesmo assim através do navegador"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informações da página"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Endereço:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Aviso de segurança"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Ver certificado"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado não pertence a uma autoridade fidedigna."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"O nome do Web site não corresponde ao nome constante no certificado."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado expirou."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado ainda não é válido."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Este certificado tem uma data inválida."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado é inválido."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Erro: certificado desconhecido."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-pt/strings.xml b/packages/CaptivePortalLogin/res/values-pt/strings.xml
deleted file mode 100644
index ebe4148..0000000
--- a/packages/CaptivePortalLogin/res/values-pt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Usar esta rede como está"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Não usar esta rede"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Fazer login na rede"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Fazer login em %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"A rede à qual você está tentando se conectar tem problemas de segurança."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar mesmo assim pelo navegador"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informações da página"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Endereço:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Aviso de segurança"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visualizar certificado"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado não é de uma autoridade confiável."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"O nome do site não corresponde ao nome no certificado."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado expirou."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado ainda não é válido."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Este certificado tem uma data inválida."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado é inválido."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Erro de certificado desconhecido."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ro/strings.xml b/packages/CaptivePortalLogin/res/values-ro/strings.xml
deleted file mode 100644
index e2e4eac..0000000
--- a/packages/CaptivePortalLogin/res/values-ro/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Utilizați această rețea în starea actuală"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Nu utilizați această rețea"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Conectați-vă la rețea"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Conectați-vă la %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Rețeaua la care încercați să vă conectați are probleme de securitate."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Continuați oricum prin browser"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informaţii pagină"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresă:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Avertisment de securitate"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vizualizaţi certificatul"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Acest certificat nu provine de la o autoritate de încredere."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Numele acestui site nu se potriveşte cu numele de pe certificat."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Acest certificat a expirat."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Acest certificat nu este încă valid."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Acest certificat are o dată nevalidă."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Acest certificat este nevalid."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Eroare de certificat necunoscută."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ru/strings.xml b/packages/CaptivePortalLogin/res/values-ru/strings.xml
deleted file mode 100644
index c0153e6..0000000
--- a/packages/CaptivePortalLogin/res/values-ru/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Использовать эту сеть"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Не использовать эту сеть"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Регистрация в сети"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Войти: %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Сеть, к которой вы хотите подключиться, небезопасна."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Например, страница входа в аккаунт может быть фиктивной."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Игнорировать и открыть браузер"</string>
-    <string name="ok" msgid="1509280796718850364">"ОК"</string>
-    <string name="page_info" msgid="4048529256302257195">"Информация о странице"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Адрес:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Угроза безопасности"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Просмотреть сертификат"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Этот сертификат получен из ненадежных источников."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Название сайта не соответствует названию в сертификате."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Срок действия сертификата истек."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Сертификат еще не действителен."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Дата этого сертификата недействительна."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Этот сертификат недействителен."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Неизвестная ошибка сертификата."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-si/strings.xml b/packages/CaptivePortalLogin/res/values-si/strings.xml
deleted file mode 100644
index a307913..0000000
--- a/packages/CaptivePortalLogin/res/values-si/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"මෙම ජාලය ලෙසම භාවිතා කරන්න"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"මෙම ජාලය භාවිතා කරන්න එපා"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ජාලයට පුරනය වන්න"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s වෙත පුරන්න"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"ඔබ සම්බන්ධ වීමට උත්සහ කරන ජාලයේ ආරක්ෂක ගැටළු ඇත."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"උදාහරණයක් ලෙස, පුරනය වන පිටුව පෙන්වා ඇති සංවිධානයට අයිති නැති විය හැක."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"කෙසේ වුවත් බ්‍රවුසරය හරහා ඉදිරියට යන්න"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-sk/strings.xml b/packages/CaptivePortalLogin/res/values-sk/strings.xml
deleted file mode 100644
index 8ba24b1..0000000
--- a/packages/CaptivePortalLogin/res/values-sk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Použiť túto sieť tak, ako je"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Túto sieť nepoužívať"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Prihlásiť sa do siete"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Prihláste sa do služby %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Sieť, ku ktorej sa pokúšate pripojiť, má problémy so zabezpečením"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Napríklad prihlasovacia stránka nemusí patriť uvedenej organizácii."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Pokračovať pomocou prehliadača"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Informácie o stránke"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adresa:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Upozornenie zabezpečenia"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Zobraziť certifikát"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Tento certifikát nepochádza od dôveryhodnej autority."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Názov stránky sa nezhoduje s názvom uvedeným v certifikáte."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Platnosť certifikátu skončila."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Tento certifikát zatiaľ nie je platný."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Tento certifikát má neplatný dátum."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Tento certifikát je neplatný."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Neznáma chyba certifikátu."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-sl/strings.xml b/packages/CaptivePortalLogin/res/values-sl/strings.xml
deleted file mode 100644
index b7d9a8a..0000000
--- a/packages/CaptivePortalLogin/res/values-sl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Uporabljajte to omrežje, »kakršno je«"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne uporabljajte tega omrežja"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Prijavite se v omrežje"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Prijava v %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Omrežje, ki se mu poskušate pridružiti, ima varnostne težave."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Vseeno nadaljuj v brskalniku"</string>
-    <string name="ok" msgid="1509280796718850364">"V redu"</string>
-    <string name="page_info" msgid="4048529256302257195">"Podatki o strani"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Naslov:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Varnostno opozorilo"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Prikaži potrdilo"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Potrdila ni izdal zaupanja vreden overitelj."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Ime spletnega mesta se ne ujema z imenom na potrdilu."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Potrdilo je poteklo."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"To potrdilo še ni veljavno."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Potrdilo ima neveljaven datum."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"To potrdilo ni veljavno."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Neznana napaka potrdila."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-sq/strings.xml b/packages/CaptivePortalLogin/res/values-sq/strings.xml
deleted file mode 100644
index b06da6d..0000000
--- a/packages/CaptivePortalLogin/res/values-sq/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Përdore këtë rrjet siç është"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Mos e përdor këtë rrjet"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Identifikohu në rrjet"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Identifikohu në %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Rrjeti në të cilin po përpiqesh të bashkohesh ka probleme sigurie."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"për shembull, faqja e identifikimit mund të mos i përkasë organizatës së shfaqur."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Vazhdo gjithsesi nëpërmjet shfletuesit"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-sr/strings.xml b/packages/CaptivePortalLogin/res/values-sr/strings.xml
deleted file mode 100644
index 967c8ba..0000000
--- a/packages/CaptivePortalLogin/res/values-sr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Користи ову мрежу такву каква је"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Не користи ову мрежу"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Пријави ме на мрежу"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Пријавите се у: %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Мрежа којој покушавате да се придружите има безбедносних проблема."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"На пример, страница за пријављивање можда не припада приказаној организацији."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Ипак настави преко прегледача"</string>
-    <string name="ok" msgid="1509280796718850364">"Потврди"</string>
-    <string name="page_info" msgid="4048529256302257195">"Информације о страници"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Адреса:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Безбедносно упозорење"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Прикажи сертификат"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Овај сертификат не потиче од поузданог ауторитета."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Назив сајта се не подудара са називом на сертификату."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Овај сертификат је истекао."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Овај сертификат још увек није важећи."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Датум овог сертификата је неважећи."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Овај сертификат је неважећи."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Непозната грешка сертификата."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-sv/strings.xml b/packages/CaptivePortalLogin/res/values-sv/strings.xml
deleted file mode 100644
index 75356f0..0000000
--- a/packages/CaptivePortalLogin/res/values-sv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Använd det här nätverket som det är"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Använd inte det här nätverket"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Logga in på nätverket"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Logga in på %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Nätverket du försöker ansluta till har säkerhetsproblem."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Det kan t.ex. hända att inloggningssidan inte tillhör den organisation som visas."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Fortsätt ändå via webbläsaren"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Sidinformation"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adress:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Säkerhetsvarning"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visa certifikat"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Certifikatet kommer inte från en betrodd utfärdare."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Webbplatsens namn stämmer inte med namnet på certifikatet."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Certifikatet har upphört att gälla."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Certifikatet är inte giltigt än."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Det här certifikatet har ett ogiltigt datum."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Certifikatet är ogiltigt."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Okänt certifikatfel."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-sw/strings.xml b/packages/CaptivePortalLogin/res/values-sw/strings.xml
deleted file mode 100644
index feb2dde..0000000
--- a/packages/CaptivePortalLogin/res/values-sw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Tumia mtandao huu jinsi ulivyo"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Usitumie mtandao huu"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Ingia katika mtandao"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Ingia katika akaunti ya %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Mtandao unaojaribu kujiunga nao una matatizo ya usalama."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Kwa mfano, ukurasa wa kuingia katika akaunti unaweza usiwe unamilikiwa na shirika lililoonyeshwa."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Endelea hata hivyo kupitia kivinjari"</string>
-    <string name="ok" msgid="1509280796718850364">"Sawa"</string>
-    <string name="page_info" msgid="4048529256302257195">"Maelezo ya ukurasa"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Anwani:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Ilani ya usalama"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Tazama cheti"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Cheti hiki hakijatoka kwa mamlaka inayoaminika."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Jina la tovuti halilingani na jina lililo katika cheti."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Cheti hiki kimepitwa na muda"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Cheti bado si halali."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Cheti hiki kina tarehe batili."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Hati hii ni batili."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Hitilafu isiyojulikana ya cheti."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ta/strings.xml b/packages/CaptivePortalLogin/res/values-ta/strings.xml
deleted file mode 100644
index 6a60ed7..0000000
--- a/packages/CaptivePortalLogin/res/values-ta/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"இந்த நெட்வொர்க்கைப் பயன்படுத்து"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"இந்த நெட்வொர்க்கைப் பயன்படுத்த வேண்டாம்"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s இல் உள்நுழைக"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"நீங்கள் சேர முயற்சிக்கும் நெட்வொர்க்கில் பாதுகாப்புச் சிக்கல்கள் உள்ளன."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"எடுத்துக்காட்டாக, உள்நுழைவுப் பக்கமானது காட்டப்படும் அமைப்பிற்குச் சொந்தமானதாக இல்லாமல் இருக்கலாம்."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"பரவாயில்லை, உலாவி வழியாகத் தொடரவும்"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-te/strings.xml b/packages/CaptivePortalLogin/res/values-te/strings.xml
deleted file mode 100644
index c209d34..0000000
--- a/packages/CaptivePortalLogin/res/values-te/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ఈ నెట్‌వర్క్‌ని యథావిధిగా ఉపయోగించు"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ఈ నెట్‌వర్క్‌ని ఉపయోగించవద్దు"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$sకి సైన్ ఇన్ చేయండి"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"మీరు చేరడానికి ప్రయత్నిస్తున్న నెట్‌వర్క్ భద్రతా సమస్యలను కలిగి ఉంది."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ఉదాహరణకు, లాగిన్ పేజీ చూపిన సంస్థకు చెందినది కాకపోవచ్చు."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ఏదేమైనా బ్రౌజర్ ద్వారా కొనసాగించు"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-th/strings.xml b/packages/CaptivePortalLogin/res/values-th/strings.xml
deleted file mode 100644
index 11a2131..0000000
--- a/packages/CaptivePortalLogin/res/values-th/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"ใช้เครือข่ายนี้ตามที่เป็นอยู่"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"ไม่ใช้เครือข่ายนี้"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"ลงชื่อเข้าใช้เครือข่าย"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"ลงชื่อเข้าใช้ %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"เครือข่ายที่คุณพยายามเข้าร่วมมีปัญหาด้านความปลอดภัย"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"ดำเนินการต่อผ่านเบราว์เซอร์"</string>
-    <string name="ok" msgid="1509280796718850364">"ตกลง"</string>
-    <string name="page_info" msgid="4048529256302257195">"ข้อมูลหน้าเว็บ"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"ที่อยู่:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"คำเตือนเกี่ยวกับความปลอดภัย"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"ดูใบรับรอง"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"ใบรับรองนี้ไม่ได้มาจากผู้ออกที่เชื่อถือได้"</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"ชื่อไซต์ไม่ตรงกับในใบรับรอง"</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"ใบรับรองนี้หมดอายุแล้ว"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"ใบรับรองนี้ยังใช้งานไม่ได้"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"ใบรับรองนี้มีวันที่ไม่ถูกต้อง"</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"ใบรับรองนี้ไม่ถูกต้อง"</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"ข้อผิดพลาดใบรับรองที่ไม่รู้จัก"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-tl/strings.xml b/packages/CaptivePortalLogin/res/values-tl/strings.xml
deleted file mode 100644
index 07a2479..0000000
--- a/packages/CaptivePortalLogin/res/values-tl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Gamitin ang network na ito nang walang pagbabago"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Huwag gamitin ang network na ito"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Mag-sign in sa network"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Mag-sign in sa %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"May mga isyu sa seguridad ang network kung saan mo sinusubukang sumali."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Halimbawa, maaaring hindi sa organisasyong ipinapakita ang page sa pag-log in."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Magpatuloy pa rin sa pamamagitan ng browser"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Impormasyon ng pahina"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Address:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Babala sa seguridad"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Tingnan ang certificate"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ang certificate ay hindi mula sa isang pinagkakatiwalaang kinauukulan."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Ang pangalan ng site ay hindi tumutugma sa pangalan sa certificate."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Nag-expire na ang certificate na ito."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Wala pang bisa ang certificate na ito."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Ang certificate ay mayroong di-wastong petsa."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Di-wasto ang certificate na ito."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Hindi kilalang error ng certificate."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-tr/strings.xml b/packages/CaptivePortalLogin/res/values-tr/strings.xml
deleted file mode 100644
index cdedd33..0000000
--- a/packages/CaptivePortalLogin/res/values-tr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Bu ağı olduğu gibi kullan"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Bu ağı kullanma"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Ağda oturum açın"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s üzerinde oturum açın"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Katılmaya çalıştığınız ağda güvenlik sorunları var."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Örneğin, giriş sayfası, gösterilen kuruluşa ait olmayabilir."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Yine de tarayıcıyla devam et"</string>
-    <string name="ok" msgid="1509280796718850364">"Tamam"</string>
-    <string name="page_info" msgid="4048529256302257195">"Sayfa bilgileri"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Güvenlik uyarısı"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Sertifikayı görüntüle"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Bu sertifika güvenilir bir yetkiliden değil."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Sitenin adı sertifika üzerindeki adla eşleşmiyor."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Bu sertifikanın süresi dolmuş."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Bu sertifika henüz geçerli değil."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Bu sertifikanın tarihi geçersiz."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Bu sertifika geçersiz."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Bilinmeyen sertifika hatası."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-uk/strings.xml b/packages/CaptivePortalLogin/res/values-uk/strings.xml
deleted file mode 100644
index 0f4cd16..0000000
--- a/packages/CaptivePortalLogin/res/values-uk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Використовувати цю мережу як є"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Не використовувати цю мережу"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Увійти в мережу"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Увійти в обліковий запис %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"У мережі, до якої ви намагаєтеся під’єднатись, є проблеми з безпекою."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Наприклад, сторінка входу може не належати вказаній організації."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Усе одно продовжити у веб-переглядачі"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Інфо про стор."</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Адреса:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Застереж. про небезп."</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Переглянути сертиф."</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Сертифікат видано ненадійним центром сертифікації."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Назва сайту не збігається з назвою в сертифікаті."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Термін дії сертиф. завершився."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Цей сертифікат ще не дійсний."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Цей сертифікат має недійсну дату."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Цей сертифікат недійсний."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Помилка невідомого сертифіката."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-ur/strings.xml b/packages/CaptivePortalLogin/res/values-ur/strings.xml
deleted file mode 100644
index 05d8fb9..0000000
--- a/packages/CaptivePortalLogin/res/values-ur/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"جوں کا توں اس نیٹ ورک کا استعمال کریں"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"اس نیٹ ورک کا استعمال نہ کریں"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"نیٹ ورک میں سائن ان کریں"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"‏%1$s میں سائن ان کریں"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"جس نیٹ ورک میں آپ شامل ہونے کی کوشش کر رہے ہیں اس میں سیکیورٹی کے مسائل ہیں۔"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"مثال کے طور پر ہو سکتا ہے کہ لاگ ان صفحہ دکھائی گئی تنظیم سے تعلق نہ رکھتا ہو۔"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-uz/strings.xml b/packages/CaptivePortalLogin/res/values-uz/strings.xml
deleted file mode 100644
index cac96ea..0000000
--- a/packages/CaptivePortalLogin/res/values-uz/strings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Ushbu tarmoqdan o‘z holicha foydalanilsin"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ushbu tarmoqdan foydalanilmasin"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Tarmoqqa kirish"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"%1$s hisobiga kirish"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Siz ulanmoqchi bo‘lgan tarmoqda xavfsizlik bilan bog‘liq muammolar mavjud."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Masalan, tizimga kirish sahifasi ko‘rsatilgan tashkilotga tegishli bo‘lmasligi mumkin."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"E’tiborsiz qoldirilsin va brauzer ochilsin"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-vi/strings.xml b/packages/CaptivePortalLogin/res/values-vi/strings.xml
deleted file mode 100644
index 9c702b9..0000000
--- a/packages/CaptivePortalLogin/res/values-vi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Sử dụng mạng này"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Không sử dụng mạng này"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Đăng nhập vào mạng"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Đăng nhập vào %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Mạng mà bạn đang cố gắng tham gia có vấn đề về bảo mật."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Ví dụ, trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Vẫn tiếp tục qua trình duyệt"</string>
-    <string name="ok" msgid="1509280796718850364">"OK"</string>
-    <string name="page_info" msgid="4048529256302257195">"Thông tin trang"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Địa chỉ:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Cảnh báo bảo mật"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Xem chứng chỉ"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Chứng chỉ này không xuất phát từ tổ chức phát hành đáng tin cậy."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Tên của trang web không khớp với tên trên chứng chỉ."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Chứng chỉ này đã hết hạn."</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Chứng chỉ này chưa hợp lệ."</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Chứng chỉ này có ngày không hợp lệ."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Chứng chỉ này không hợp lệ."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Lỗi chứng chỉ không xác định."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml b/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 70c2a08..0000000
--- a/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"直接使用此网络"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"不要使用此网络"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"登录到网络"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"登录%1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"您尝试加入的网络存在安全问题。"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"例如,登录页面可能并不属于页面上显示的单位。"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"仍然通过浏览器继续操作"</string>
-    <string name="ok" msgid="1509280796718850364">"确定"</string>
-    <string name="page_info" msgid="4048529256302257195">"网页信息"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"网址:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"安全警告"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"查看证书"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"该证书并非来自可信的授权中心。"</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"网站的名称与证书上的名称不一致。"</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"该证书已过期。"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"该证书尚未生效。"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"该证书的日期无效。"</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"该证书无效。"</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"未知证书错误。"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml b/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml
deleted file mode 100644
index df1c700..0000000
--- a/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"依照現況使用這個網絡"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"不要使用這個網絡"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"登入網絡"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"登入「%1$s」"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"您正在嘗試加入的網絡有安全性問題。"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"例如,登入頁面並不屬於所顯示的機構。"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"透過瀏覽器繼續"</string>
-    <string name="ok" msgid="1509280796718850364">"確定"</string>
-    <string name="page_info" msgid="4048529256302257195">"網頁資訊"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"地址:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"安全性警告"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"查看憑證"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"這個憑證並非由受信任的權威機構發出。"</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"網站名稱與憑證上的名稱不相符。"</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"這個憑證已過期。"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"這個憑證尚未生效。"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"此憑證的日期無效。"</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"此憑證是無效的。"</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"不明的憑證錯誤。"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml b/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 2a2e397..0000000
--- a/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"依現況使用這個網路"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"不使用這個網路"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"登入網路"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"登入 %1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"你嘗試加入的網路有安全問題。"</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"透過瀏覽器繼續"</string>
-    <string name="ok" msgid="1509280796718850364">"確定"</string>
-    <string name="page_info" msgid="4048529256302257195">"頁面資訊"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"位址:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"安全性警告"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"檢視憑證"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"這個憑證並非來自信任的授權單位。"</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"網站名稱與憑證上的名稱不相符。"</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"此憑證已過期"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"這個憑證尚未生效。"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"這個憑證的日期無效。"</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"這個憑證無效。"</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"不明的憑證錯誤。"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-zu/strings.xml b/packages/CaptivePortalLogin/res/values-zu/strings.xml
deleted file mode 100644
index 7943645..0000000
--- a/packages/CaptivePortalLogin/res/values-zu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5934709770924185752">"I-CaptivePortalLogin"</string>
-    <string name="action_use_network" msgid="6076184727448466030">"Sebenzisa le nethiwekhi njengoba injalo"</string>
-    <string name="action_do_not_use_network" msgid="4577366536956516683">"Ungasebenzisi le nethiwekhi"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"Ngena ngemvume kunethiwekhi"</string>
-    <string name="action_bar_title" msgid="5645564790486983117">"Ngena ngemvume ku-%1$s"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Inethiwekhi ozama ukuyijoyina inezinkinga zokuvikela."</string>
-    <string name="ssl_error_example" msgid="647898534624078900">"Isibonelo, ikhasi lokungena ngemvume kungenzeka lingelenhlangano ebonisiwe."</string>
-    <string name="ssl_error_continue" msgid="6492718244923937110">"Qhubeka noma kunjalo ngesiphequluli"</string>
-    <string name="ok" msgid="1509280796718850364">"KULUNGILE"</string>
-    <string name="page_info" msgid="4048529256302257195">"Ulwazi lekhasi"</string>
-    <string name="page_info_address" msgid="2222306609532903254">"Ikheli:"</string>
-    <string name="ssl_security_warning_title" msgid="6607795404322797541">"Isexwayiso sokuvikeleka"</string>
-    <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Buka isitifiketi"</string>
-    <string name="ssl_error_untrusted" msgid="7754507359360636447">"Lesi sitifiketi asiphumi embusweni othembekile."</string>
-    <string name="ssl_error_mismatch" msgid="3809794439740523641">"Igama lale ngosi alifani negama elikusitifiketi."</string>
-    <string name="ssl_error_expired" msgid="5739349389499575559">"Lesi sitifiketi siphelelwe yisikhathi"</string>
-    <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Lesi sitifiketi asilungile okwamanje"</string>
-    <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Lesi sitifiketi sinosuku olungalungile."</string>
-    <string name="ssl_error_invalid" msgid="9041704741505449967">"Lesi sitifiketi asilungile."</string>
-    <string name="ssl_error_unknown" msgid="5679243486524754571">"Iphutha lesitifiketi elingaziwa."</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values/dimens.xml b/packages/CaptivePortalLogin/res/values/dimens.xml
deleted file mode 100644
index 55c1e590..0000000
--- a/packages/CaptivePortalLogin/res/values/dimens.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<resources>
-
-    <!-- Default screen margins, per the Android Design guidelines. -->
-    <dimen name="activity_horizontal_margin">16dp</dimen>
-    <dimen name="activity_vertical_margin">16dp</dimen>
-
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values/strings.xml b/packages/CaptivePortalLogin/res/values/strings.xml
deleted file mode 100644
index e9698db..0000000
--- a/packages/CaptivePortalLogin/res/values/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
-    <string name="app_name">CaptivePortalLogin</string>
-    <string name="action_use_network">Use this network as is</string>
-    <string name="action_do_not_use_network">Do not use this network</string>
-    <string name="action_bar_label">Sign in to network</string>
-    <string name="action_bar_title">Sign in to %1$s</string>
-    <string name="ssl_error_warning">The network you&#8217;re trying to join has security issues.</string>
-    <string name="ssl_error_example">For example, the login page may not belong to the organization shown.</string>
-    <string name="ssl_error_continue">Continue anyway via browser</string>
-    <string name="ssl_error_untrusted">This certificate isn\'t from a trusted authority.</string>
-    <string name="ssl_error_mismatch">The name of the site doesn\'t match the name on the certificate.</string>
-    <string name="ssl_error_expired">This certificate has expired.</string>
-    <string name="ssl_error_not_yet_valid">This certificate isn\'t valid yet.</string>
-    <string name="ssl_error_date_invalid">This certificate has an invalid date.</string>
-    <string name="ssl_error_invalid">This certificate is invalid.</string>
-    <string name="ssl_error_unknown">Unknown certificate error.</string>
-    <string name="ssl_security_warning_title">Security warning</string>
-    <string name="ssl_error_view_certificate">View certificate</string>
-    <string name="ok">OK</string>
-    <string name="page_info_address">Address:</string>
-    <string name="page_info">Page info</string>
-
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values/styles.xml b/packages/CaptivePortalLogin/res/values/styles.xml
deleted file mode 100644
index f6c2339..0000000
--- a/packages/CaptivePortalLogin/res/values/styles.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<resources>
-
-    <!--
-        Base application theme, dependent on API level. This theme is replaced
-        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-    -->
-    <style name="AppBaseTheme" parent="@android:style/Theme.DeviceDefault.Settings">
-        <!--
-            Theme customizations available in newer API levels can go in
-            res/values-vXX/styles.xml, while customizations related to
-            backward-compatibility can go here.
-        -->
-    </style>
-
-    <!-- Application theme. -->
-    <style name="AppTheme" parent="AppBaseTheme">
-        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
-    </style>
-</resources>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
deleted file mode 100644
index 3d5710d..0000000
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * Copyright (C) 2014 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.captiveportallogin;
-
-import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Application;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.CaptivePortal;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.Proxy;
-import android.net.Uri;
-import android.net.captiveportal.CaptivePortalProbeSpec;
-import android.net.http.SslCertificate;
-import android.net.http.SslError;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.SystemProperties;
-import android.support.v4.widget.SwipeRefreshLayout;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.webkit.CookieManager;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Objects;
-import java.util.Random;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class CaptivePortalLoginActivity extends Activity {
-    private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName();
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
-    private static final int SOCKET_TIMEOUT_MS = 10000;
-    public static final String HTTP_LOCATION_HEADER_NAME = "Location";
-
-    private enum Result {
-        DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED),
-        UNWANTED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED),
-        WANTED_AS_IS(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS);
-
-        final int metricsEvent;
-        Result(int metricsEvent) { this.metricsEvent = metricsEvent; }
-    };
-
-    private URL mUrl;
-    private CaptivePortalProbeSpec mProbeSpec;
-    private String mUserAgent;
-    private Network mNetwork;
-    private CaptivePortal mCaptivePortal;
-    private NetworkCallback mNetworkCallback;
-    private ConnectivityManager mCm;
-    private WifiManager mWifiManager;
-    private boolean mLaunchBrowser = false;
-    private MyWebViewClient mWebViewClient;
-    private SwipeRefreshLayout mSwipeRefreshLayout;
-    // Ensures that done() happens once exactly, handling concurrent callers with atomic operations.
-    private final AtomicBoolean isDone = new AtomicBoolean(false);
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
-        logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
-
-        mCm = getSystemService(ConnectivityManager.class);
-        mWifiManager = getSystemService(WifiManager.class);
-        mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
-        mUserAgent =
-                getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT);
-        mUrl = getUrl();
-        if (mUrl == null) {
-            // getUrl() failed to parse the url provided in the intent: bail out in a way that
-            // at least provides network access.
-            done(Result.WANTED_AS_IS);
-            return;
-        }
-        if (DBG) {
-            Log.d(TAG, String.format("onCreate for %s", mUrl.toString()));
-        }
-
-        final String spec = getIntent().getStringExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC);
-        try {
-            mProbeSpec = CaptivePortalProbeSpec.parseSpecOrNull(spec);
-        } catch (Exception e) {
-            // Make extra sure that invalid configurations do not cause crashes
-            mProbeSpec = null;
-        }
-
-        mNetworkCallback = new NetworkCallback() {
-            @Override
-            public void onLost(Network lostNetwork) {
-                // If the network disappears while the app is up, exit.
-                if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
-            }
-        };
-        mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), mNetworkCallback);
-
-        // If the network has disappeared, exit.
-        final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
-        if (networkCapabilities == null) {
-            finishAndRemoveTask();
-            return;
-        }
-
-        // Also initializes proxy system properties.
-        mNetwork = mNetwork.getPrivateDnsBypassingCopy();
-        mCm.bindProcessToNetwork(mNetwork);
-
-        // Proxy system properties must be initialized before setContentView is called because
-        // setContentView initializes the WebView logic which in turn reads the system properties.
-        setContentView(R.layout.activity_captive_portal_login);
-
-        getActionBar().setDisplayShowHomeEnabled(false);
-        getActionBar().setElevation(0); // remove shadow
-        getActionBar().setTitle(getHeaderTitle());
-        getActionBar().setSubtitle("");
-
-        final WebView webview = getWebview();
-        webview.clearCache(true);
-        CookieManager.getInstance().setAcceptThirdPartyCookies(webview, true);
-        WebSettings webSettings = webview.getSettings();
-        webSettings.setJavaScriptEnabled(true);
-        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
-        webSettings.setUseWideViewPort(true);
-        webSettings.setLoadWithOverviewMode(true);
-        webSettings.setSupportZoom(true);
-        webSettings.setBuiltInZoomControls(true);
-        webSettings.setDisplayZoomControls(false);
-        webSettings.setDomStorageEnabled(true);
-        mWebViewClient = new MyWebViewClient();
-        webview.setWebViewClient(mWebViewClient);
-        webview.setWebChromeClient(new MyWebChromeClient());
-        // Start initial page load so WebView finishes loading proxy settings.
-        // Actual load of mUrl is initiated by MyWebViewClient.
-        webview.loadData("", "text/html", null);
-
-        mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
-        mSwipeRefreshLayout.setOnRefreshListener(() -> {
-                webview.reload();
-                mSwipeRefreshLayout.setRefreshing(true);
-            });
-
-    }
-
-    // Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
-    private void setWebViewProxy() {
-        // TODO: migrate to androidx WebView proxy setting API as soon as it is finalized
-        try {
-            final Field loadedApkField = Application.class.getDeclaredField("mLoadedApk");
-            final Class<?> loadedApkClass = loadedApkField.getType();
-            final Object loadedApk = loadedApkField.get(getApplication());
-            Field receiversField = loadedApkClass.getDeclaredField("mReceivers");
-            receiversField.setAccessible(true);
-            ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
-            for (Object receiverMap : receivers.values()) {
-                for (Object rec : ((ArrayMap) receiverMap).keySet()) {
-                    Class clazz = rec.getClass();
-                    if (clazz.getName().contains("ProxyChangeListener")) {
-                        Method onReceiveMethod = clazz.getDeclaredMethod("onReceive", Context.class,
-                                Intent.class);
-                        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
-                        onReceiveMethod.invoke(rec, getApplicationContext(), intent);
-                        Log.v(TAG, "Prompting WebView proxy reload.");
-                    }
-                }
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "Exception while setting WebView proxy: " + e);
-        }
-    }
-
-    private void done(Result result) {
-        if (isDone.getAndSet(true)) {
-            // isDone was already true: done() already called
-            return;
-        }
-        if (DBG) {
-            Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString()));
-        }
-        logMetricsEvent(result.metricsEvent);
-        switch (result) {
-            case DISMISSED:
-                mCaptivePortal.reportCaptivePortalDismissed();
-                break;
-            case UNWANTED:
-                mCaptivePortal.ignoreNetwork();
-                break;
-            case WANTED_AS_IS:
-                mCaptivePortal.useNetwork();
-                break;
-        }
-        finishAndRemoveTask();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.captive_portal_login, menu);
-        return true;
-    }
-
-    @Override
-    public void onBackPressed() {
-        WebView myWebView = findViewById(R.id.webview);
-        if (myWebView.canGoBack() && mWebViewClient.allowBack()) {
-            myWebView.goBack();
-        } else {
-            super.onBackPressed();
-        }
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        final Result result;
-        final String action;
-        final int id = item.getItemId();
-        switch (id) {
-            case R.id.action_use_network:
-                result = Result.WANTED_AS_IS;
-                action = "USE_NETWORK";
-                break;
-            case R.id.action_do_not_use_network:
-                result = Result.UNWANTED;
-                action = "DO_NOT_USE_NETWORK";
-                break;
-            default:
-                return super.onOptionsItemSelected(item);
-        }
-        if (DBG) {
-            Log.d(TAG, String.format("onOptionsItemSelect %s for %s", action, mUrl.toString()));
-        }
-        done(result);
-        return true;
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        final WebView webview = (WebView) findViewById(R.id.webview);
-        if (webview != null) {
-            webview.stopLoading();
-            webview.setWebViewClient(null);
-            webview.setWebChromeClient(null);
-            webview.destroy();
-        }
-        if (mNetworkCallback != null) {
-            // mNetworkCallback is not null if mUrl is not null.
-            mCm.unregisterNetworkCallback(mNetworkCallback);
-        }
-        if (mLaunchBrowser) {
-            // Give time for this network to become default. After 500ms just proceed.
-            for (int i = 0; i < 5; i++) {
-                // TODO: This misses when mNetwork underlies a VPN.
-                if (mNetwork.equals(mCm.getActiveNetwork())) break;
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                }
-            }
-            final String url = mUrl.toString();
-            if (DBG) {
-                Log.d(TAG, "starting activity with intent ACTION_VIEW for " + url);
-            }
-            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
-        }
-    }
-
-    private URL getUrl() {
-        String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
-        if (url == null) {
-            url = mCm.getCaptivePortalServerUrl();
-        }
-        return makeURL(url);
-    }
-
-    private static URL makeURL(String url) {
-        try {
-            return new URL(url);
-        } catch (MalformedURLException e) {
-            Log.e(TAG, "Invalid URL " + url);
-        }
-        return null;
-    }
-
-    private static String host(URL url) {
-        if (url == null) {
-            return null;
-        }
-        return url.getHost();
-    }
-
-    private static String sanitizeURL(URL url) {
-        // In non-Debug build, only show host to avoid leaking private info.
-        return isDebuggable() ? Objects.toString(url) : host(url);
-    }
-
-    private static boolean isDebuggable() {
-        return SystemProperties.getInt("ro.debuggable", 0) == 1;
-    }
-
-    private void testForCaptivePortal() {
-        // TODO: reuse NetworkMonitor facilities for consistent captive portal detection.
-        new Thread(new Runnable() {
-            public void run() {
-                // Give time for captive portal to open.
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException e) {
-                }
-                HttpURLConnection urlConnection = null;
-                int httpResponseCode = 500;
-                String locationHeader = null;
-                try {
-                    urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl);
-                    urlConnection.setInstanceFollowRedirects(false);
-                    urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
-                    urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
-                    urlConnection.setUseCaches(false);
-                    if (mUserAgent != null) {
-                       urlConnection.setRequestProperty("User-Agent", mUserAgent);
-                    }
-                    // cannot read request header after connection
-                    String requestHeader = urlConnection.getRequestProperties().toString();
-
-                    urlConnection.getInputStream();
-                    httpResponseCode = urlConnection.getResponseCode();
-                    locationHeader = urlConnection.getHeaderField(HTTP_LOCATION_HEADER_NAME);
-                    if (DBG) {
-                        Log.d(TAG, "probe at " + mUrl +
-                                " ret=" + httpResponseCode +
-                                " request=" + requestHeader +
-                                " headers=" + urlConnection.getHeaderFields());
-                    }
-                } catch (IOException e) {
-                } finally {
-                    if (urlConnection != null) urlConnection.disconnect();
-                }
-                if (isDismissed(httpResponseCode, locationHeader, mProbeSpec)) {
-                    done(Result.DISMISSED);
-                }
-            }
-        }).start();
-    }
-
-    private static boolean isDismissed(
-            int httpResponseCode, String locationHeader, CaptivePortalProbeSpec probeSpec) {
-        return (probeSpec != null)
-                ? probeSpec.getResult(httpResponseCode, locationHeader).isSuccessful()
-                : (httpResponseCode == 204);
-    }
-
-    private class MyWebViewClient extends WebViewClient {
-        private static final String INTERNAL_ASSETS = "file:///android_asset/";
-
-        private final String mBrowserBailOutToken = Long.toString(new Random().nextLong());
-        private final String mCertificateOutToken = Long.toString(new Random().nextLong());
-        // How many Android device-independent-pixels per scaled-pixel
-        // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp)
-        private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
-                    getResources().getDisplayMetrics()) /
-                    TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
-                    getResources().getDisplayMetrics());
-        private int mPagesLoaded;
-        private String mMainFrameUrl;
-
-        // If we haven't finished cleaning up the history, don't allow going back.
-        public boolean allowBack() {
-            return mPagesLoaded > 1;
-        }
-
-        private String mSslErrorTitle = null;
-        private SslErrorHandler mSslErrorHandler = null;
-        private SslError mSslError = null;
-
-        @Override
-        public void onPageStarted(WebView view, String urlString, Bitmap favicon) {
-            if (urlString.contains(mBrowserBailOutToken)) {
-                mLaunchBrowser = true;
-                done(Result.WANTED_AS_IS);
-                return;
-            }
-            // The first page load is used only to cause the WebView to
-            // fetch the proxy settings.  Don't update the URL bar, and
-            // don't check if the captive portal is still there.
-            if (mPagesLoaded == 0) {
-                return;
-            }
-            final URL url = makeURL(urlString);
-            Log.d(TAG, "onPageStarted: " + sanitizeURL(url));
-            // For internally generated pages, leave URL bar listing prior URL as this is the URL
-            // the page refers to.
-            if (!urlString.startsWith(INTERNAL_ASSETS)) {
-                String subtitle = (url != null) ? getHeaderSubtitle(url) : urlString;
-                getActionBar().setSubtitle(subtitle);
-            }
-            getProgressBar().setVisibility(View.VISIBLE);
-            testForCaptivePortal();
-        }
-
-        @Override
-        public void onPageFinished(WebView view, String url) {
-            mPagesLoaded++;
-            getProgressBar().setVisibility(View.INVISIBLE);
-            mSwipeRefreshLayout.setRefreshing(false);
-            if (mPagesLoaded == 1) {
-                // Now that WebView has loaded at least one page we know it has read in the proxy
-                // settings.  Now prompt the WebView read the Network-specific proxy settings.
-                setWebViewProxy();
-                // Load the real page.
-                view.loadUrl(mUrl.toString());
-                return;
-            } else if (mPagesLoaded == 2) {
-                // Prevent going back to empty first page.
-                // Fix for missing focus, see b/62449959 for details. Remove it once we get a
-                // newer version of WebView (60.x.y).
-                view.requestFocus();
-                view.clearHistory();
-            }
-            testForCaptivePortal();
-        }
-
-        // Convert Android scaled-pixels (sp) to HTML size.
-        private String sp(int sp) {
-            // Convert sp to dp's.
-            float dp = sp * mDpPerSp;
-            // Apply a scale factor to make things look right.
-            dp *= 1.3;
-            // Convert dp's to HTML size.
-            // HTML px's are scaled just like dp's, so just add "px" suffix.
-            return Integer.toString((int)dp) + "px";
-        }
-
-        // Check if webview is trying to load the main frame and record its url.
-        @Override
-        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
-            if (request.isForMainFrame()) {
-                mMainFrameUrl = request.getUrl().toString();
-            }
-            // Be careful that two shouldOverrideUrlLoading methods are overridden, but
-            // shouldOverrideUrlLoading(WebView view, String url) was deprecated in API level 24.
-            // TODO: delete deprecated one ??
-            return shouldOverrideUrlLoading(view, mMainFrameUrl);
-        }
-
-        // A web page consisting of a large broken lock icon to indicate SSL failure.
-
-        @Override
-        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-            final URL errorUrl = makeURL(error.getUrl());
-            final URL mainFrameUrl = makeURL(mMainFrameUrl);
-            Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
-                    sslErrorName(error), sanitizeURL(errorUrl), error.getCertificate()));
-            if (errorUrl == null
-                    // Ignore SSL errors from resources by comparing the main frame url with SSL
-                    // error url.
-                    || !errorUrl.equals(mainFrameUrl)) {
-                Log.d(TAG, "onReceivedSslError: mMainFrameUrl = " + mMainFrameUrl);
-                handler.cancel();
-                return;
-            }
-            logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
-            final String sslErrorPage = makeSslErrorPage();
-            view.loadDataWithBaseURL(INTERNAL_ASSETS, sslErrorPage, "text/HTML", "UTF-8", null);
-            mSslErrorTitle = view.getTitle() == null ? "" : view.getTitle();
-            mSslErrorHandler = handler;
-            mSslError = error;
-        }
-
-        private String makeSslErrorPage() {
-            final String warningMsg = getString(R.string.ssl_error_warning);
-            final String exampleMsg = getString(R.string.ssl_error_example);
-            final String continueMsg = getString(R.string.ssl_error_continue);
-            final String certificateMsg = getString(R.string.ssl_error_view_certificate);
-            return String.join("\n",
-                    "<html>",
-                    "<head>",
-                    "  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">",
-                    "  <style>",
-                    "    body {",
-                    "      background-color:#fafafa;",
-                    "      margin:auto;",
-                    "      width:80%;",
-                    "      margin-top: 96px",
-                    "    }",
-                    "    img {",
-                    "      height:48px;",
-                    "      width:48px;",
-                    "    }",
-                    "    div.warn {",
-                    "      font-size:" + sp(16) + ";",
-                    "      line-height:1.28;",
-                    "      margin-top:16px;",
-                    "      opacity:0.87;",
-                    "    }",
-                    "    div.example {",
-                    "      font-size:" + sp(14) + ";",
-                    "      line-height:1.21905;",
-                    "      margin-top:16px;",
-                    "      opacity:0.54;",
-                    "    }",
-                    "    a {",
-                    "      color:#4285F4;",
-                    "      display:inline-block;",
-                    "      font-size:" + sp(14) + ";",
-                    "      font-weight:bold;",
-                    "      height:48px;",
-                    "      margin-top:24px;",
-                    "      text-decoration:none;",
-                    "      text-transform:uppercase;",
-                    "    }",
-                    "    a.certificate {",
-                    "      margin-top:0px;",
-                    "    }",
-                    "  </style>",
-                    "</head>",
-                    "<body>",
-                    "  <p><img src=quantum_ic_warning_amber_96.png><br>",
-                    "  <div class=warn>" + warningMsg + "</div>",
-                    "  <div class=example>" + exampleMsg + "</div>",
-                    "  <a href=" + mBrowserBailOutToken + ">" + continueMsg + "</a><br>",
-                    "  <a class=certificate href=" + mCertificateOutToken + ">" + certificateMsg +
-                            "</a>",
-                    "</body>",
-                    "</html>");
-        }
-
-        @Override
-        public boolean shouldOverrideUrlLoading (WebView view, String url) {
-            if (url.startsWith("tel:")) {
-                startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
-                return true;
-            }
-            if (url.contains(mCertificateOutToken) && mSslError != null) {
-                showSslAlertDialog(mSslErrorHandler, mSslError, mSslErrorTitle);
-                return true;
-            }
-            return false;
-        }
-        private void showSslAlertDialog(SslErrorHandler handler, SslError error, String title) {
-            final LayoutInflater factory = LayoutInflater.from(CaptivePortalLoginActivity.this);
-            final View sslWarningView = factory.inflate(R.layout.ssl_warning, null);
-
-            // Set Security certificate
-            setViewSecurityCertificate(sslWarningView.findViewById(R.id.certificate_layout), error);
-            ((TextView) sslWarningView.findViewById(R.id.ssl_error_type))
-                    .setText(sslErrorName(error));
-            ((TextView) sslWarningView.findViewById(R.id.title)).setText(mSslErrorTitle);
-            ((TextView) sslWarningView.findViewById(R.id.address)).setText(error.getUrl());
-
-            AlertDialog sslAlertDialog = new AlertDialog.Builder(CaptivePortalLoginActivity.this)
-                    .setTitle(R.string.ssl_security_warning_title)
-                    .setView(sslWarningView)
-                    .setPositiveButton(R.string.ok, (DialogInterface dialog, int whichButton) -> {
-                        // handler.cancel is called via OnCancelListener.
-                        dialog.cancel();
-                    })
-                    .setOnCancelListener((DialogInterface dialogInterface) -> handler.cancel())
-                    .create();
-            sslAlertDialog.show();
-        }
-
-        private void setViewSecurityCertificate(LinearLayout certificateLayout, SslError error) {
-            ((TextView) certificateLayout.findViewById(R.id.ssl_error_msg))
-                    .setText(sslErrorMessage(error));
-            SslCertificate cert = error.getCertificate();
-            // TODO: call the method directly once inflateCertificateView is @SystemApi
-            try {
-                final View certificateView = (View) SslCertificate.class.getMethod(
-                        "inflateCertificateView", Context.class)
-                        .invoke(cert, CaptivePortalLoginActivity.this);
-                certificateLayout.addView(certificateView);
-            } catch (ReflectiveOperationException | SecurityException e) {
-                Log.e(TAG, "Could not create certificate view", e);
-            }
-        }
-    }
-
-    private class MyWebChromeClient extends WebChromeClient {
-        @Override
-        public void onProgressChanged(WebView view, int newProgress) {
-            getProgressBar().setProgress(newProgress);
-        }
-    }
-
-    private ProgressBar getProgressBar() {
-        return findViewById(R.id.progress_bar);
-    }
-
-    private WebView getWebview() {
-        return findViewById(R.id.webview);
-    }
-
-    private String getHeaderTitle() {
-        NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
-        final String ssid = getSsid();
-        if (TextUtils.isEmpty(ssid)
-                || nc == null || !nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
-            return getString(R.string.action_bar_label);
-        }
-        return getString(R.string.action_bar_title, ssid);
-    }
-
-    // TODO: remove once SSID is obtained from NetworkCapabilities
-    private String getSsid() {
-        if (mWifiManager == null) {
-            return null;
-        }
-        final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-        return removeDoubleQuotes(wifiInfo.getSSID());
-    }
-
-    private static String removeDoubleQuotes(String string) {
-        if (string == null) return null;
-        final int length = string.length();
-        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
-            return string.substring(1, length - 1);
-        }
-        return string;
-    }
-
-    private String getHeaderSubtitle(URL url) {
-        String host = host(url);
-        final String https = "https";
-        if (https.equals(url.getProtocol())) {
-            return https + "://" + host;
-        }
-        return host;
-    }
-
-    private void logMetricsEvent(int event) {
-        mCaptivePortal.logEvent(event, getPackageName());
-    }
-
-    private static final SparseArray<String> SSL_ERRORS = new SparseArray<>();
-    static {
-        SSL_ERRORS.put(SslError.SSL_NOTYETVALID,  "SSL_NOTYETVALID");
-        SSL_ERRORS.put(SslError.SSL_EXPIRED,      "SSL_EXPIRED");
-        SSL_ERRORS.put(SslError.SSL_IDMISMATCH,   "SSL_IDMISMATCH");
-        SSL_ERRORS.put(SslError.SSL_UNTRUSTED,    "SSL_UNTRUSTED");
-        SSL_ERRORS.put(SslError.SSL_DATE_INVALID, "SSL_DATE_INVALID");
-        SSL_ERRORS.put(SslError.SSL_INVALID,      "SSL_INVALID");
-    }
-
-    private static String sslErrorName(SslError error) {
-        return SSL_ERRORS.get(error.getPrimaryError(), "UNKNOWN");
-    }
-
-    private static final SparseArray<Integer> SSL_ERROR_MSGS = new SparseArray<>();
-    static {
-        SSL_ERROR_MSGS.put(SslError.SSL_NOTYETVALID,  R.string.ssl_error_not_yet_valid);
-        SSL_ERROR_MSGS.put(SslError.SSL_EXPIRED,      R.string.ssl_error_expired);
-        SSL_ERROR_MSGS.put(SslError.SSL_IDMISMATCH,   R.string.ssl_error_mismatch);
-        SSL_ERROR_MSGS.put(SslError.SSL_UNTRUSTED,    R.string.ssl_error_untrusted);
-        SSL_ERROR_MSGS.put(SslError.SSL_DATE_INVALID, R.string.ssl_error_date_invalid);
-        SSL_ERROR_MSGS.put(SslError.SSL_INVALID,      R.string.ssl_error_invalid);
-    }
-
-    private static Integer sslErrorMessage(SslError error) {
-        return SSL_ERROR_MSGS.get(error.getPrimaryError(), R.string.ssl_error_unknown);
-    }
-}
diff --git a/packages/ExtServices/Android.bp b/packages/ExtServices/Android.bp
deleted file mode 100644
index db94eec..0000000
--- a/packages/ExtServices/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2016 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.
-
-android_app {
-    name: "ExtServices",
-    srcs: ["src/**/*.java"],
-    platform_apis: true,
-    certificate: "platform",
-    aaptflags: ["--shared-lib"],
-    export_package_resources: true,
-    optimize: {
-        proguard_flags_files: ["proguard.proguard"],
-    },
-    privileged: true,
-}
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
deleted file mode 100644
index 45e557c..0000000
--- a/packages/ExtServices/AndroidManifest.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    package="android.ext.services"
-    android:versionCode="1"
-    android:versionName="1"
-    coreApp="true">
-
-    <uses-permission android:name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" />
-
-    <application android:label="@string/app_name"
-        android:defaultToDeviceProtectedStorage="true"
-        android:directBootAware="true">
-
-        <service android:name=".storage.CacheQuotaServiceImpl"
-             android:permission="android.permission.BIND_CACHE_QUOTA_SERVICE">
-            <intent-filter>
-                <action android:name="android.app.usage.CacheQuotaService" />
-            </intent-filter>
-        </service>
-
-        <service android:name=".resolver.LRResolverRankerService"
-                 android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"
-                 android:priority="-1" >
-            <intent-filter>
-                <action android:name="android.service.resolver.ResolverRankerService" />
-            </intent-filter>
-        </service>
-
-        <service android:name=".notification.Assistant"
-                 android:label="@string/notification_assistant"
-                 android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
-                 android:exported="true">
-            <intent-filter>
-                <action android:name="android.service.notification.NotificationAssistantService" />
-            </intent-filter>
-        </service>
-
-        <service android:name=".autofill.AutofillFieldClassificationServiceImpl"
-             android:permission="android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE">
-            <intent-filter>
-                <action android:name="android.service.autofill.AutofillFieldClassificationService" />
-            </intent-filter>
-            <meta-data
-                android:name="android.autofill.field_classification.default_algorithm"
-                android:resource="@string/autofill_field_classification_default_algorithm" />
-            <meta-data
-                android:name="android.autofill.field_classification.available_algorithms"
-                android:resource="@array/autofill_field_classification_available_algorithms" />
-        </service>
-
-        <library android:name="android.ext.services"/>
-    </application>
-
-</manifest>
diff --git a/packages/ExtServices/MODULE_LICENSE_APACHE2 b/packages/ExtServices/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/packages/ExtServices/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/packages/ExtServices/NOTICE b/packages/ExtServices/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/packages/ExtServices/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, 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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/packages/ExtServices/OWNERS b/packages/ExtServices/OWNERS
deleted file mode 100644
index 7640b91..0000000
--- a/packages/ExtServices/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-baligh@google.com
-delphij@google.com
diff --git a/packages/ExtServices/proguard.proguard b/packages/ExtServices/proguard.proguard
deleted file mode 100644
index e5dfbe1..0000000
--- a/packages/ExtServices/proguard.proguard
+++ /dev/null
@@ -1,7 +0,0 @@
--keepparameternames
--keepattributes Exceptions,InnerClasses,Signature,Deprecated,
-                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-
--keep public class * {
-    public protected *;
-}
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
deleted file mode 100644
index 72647ab..0000000
--- a/packages/ExtServices/res/values/strings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name">Android Services Library</string>
-
-    <string name="notification_assistant">Notification Assistant</string>
-    <string name="prompt_block_reason">Too many dismissals:views</string>
-
-    <string name="autofill_field_classification_default_algorithm">EDIT_DISTANCE</string>
-    <string-array name="autofill_field_classification_available_algorithms">
-        <item>EDIT_DISTANCE</item>
-    </string-array>
-</resources>
diff --git a/packages/ExtServices/src/android/ext/services/Version.java b/packages/ExtServices/src/android/ext/services/Version.java
deleted file mode 100644
index 026cccd..0000000
--- a/packages/ExtServices/src/android/ext/services/Version.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2016 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.ext.services;
-
-/**
- * Class that provides the version of the library.
- */
-public final class Version {
-
-    private Version() {
-        /* do nothing - hide constructor */
-    }
-
-    /**
-     * Gets the version of the library.
-     *
-     * @return The version.
-     */
-    public static int getVersionCode() {
-        return 1;
-    }
-}
\ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java b/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java
deleted file mode 100644
index 9ba7e09..0000000
--- a/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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.ext.services.autofill;
-
-import static android.ext.services.autofill.EditDistanceScorer.DEFAULT_ALGORITHM;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.service.autofill.AutofillFieldClassificationService;
-import android.util.Log;
-import android.view.autofill.AutofillValue;
-
-import com.android.internal.util.ArrayUtils;
-
-import java.util.List;
-
-public class AutofillFieldClassificationServiceImpl extends AutofillFieldClassificationService {
-
-    private static final String TAG = "AutofillFieldClassificationServiceImpl";
-
-    @Nullable
-    @Override
-    public float[][] onGetScores(@Nullable String algorithmName,
-            @Nullable Bundle algorithmArgs, @NonNull List<AutofillValue> actualValues,
-            @NonNull List<String> userDataValues) {
-        if (ArrayUtils.isEmpty(actualValues) || ArrayUtils.isEmpty(userDataValues)) {
-            Log.w(TAG, "getScores(): empty currentvalues (" + actualValues + ") or userValues ("
-                    + userDataValues + ")");
-            return null;
-        }
-        if (algorithmName != null && !algorithmName.equals(DEFAULT_ALGORITHM)) {
-            Log.w(TAG, "Ignoring invalid algorithm (" + algorithmName + ") and using "
-                    + DEFAULT_ALGORITHM + " instead");
-        }
-
-        return EditDistanceScorer.getScores(actualValues, userDataValues);
-    }
-}
diff --git a/packages/ExtServices/src/android/ext/services/autofill/EditDistanceScorer.java b/packages/ExtServices/src/android/ext/services/autofill/EditDistanceScorer.java
deleted file mode 100644
index 302b160..0000000
--- a/packages/ExtServices/src/android/ext/services/autofill/EditDistanceScorer.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2017 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.ext.services.autofill;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.Log;
-import android.view.autofill.AutofillValue;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.List;
-
-final class EditDistanceScorer {
-
-    private static final String TAG = "EditDistanceScorer";
-
-    // TODO(b/70291841): STOPSHIP - set to false before launching
-    private static final boolean DEBUG = true;
-
-    static final String DEFAULT_ALGORITHM = "EDIT_DISTANCE";
-
-    /**
-     * Gets the field classification score of 2 values based on the edit distance between them.
-     *
-     * <p>The score is defined as: @(max_length - edit_distance) / max_length
-     */
-    @VisibleForTesting
-    static float getScore(@Nullable AutofillValue actualValue, @Nullable String userDataValue) {
-        if (actualValue == null || !actualValue.isText() || userDataValue == null) return 0;
-
-        final String actualValueText = actualValue.getTextValue().toString();
-        final int actualValueLength = actualValueText.length();
-        final int userDatalength = userDataValue.length();
-        if (userDatalength == 0) {
-            return (actualValueLength == 0) ? 1 : 0;
-        }
-
-        final int distance = editDistance(actualValueText.toLowerCase(),
-                userDataValue.toLowerCase());
-        final int maxLength = Math.max(actualValueLength, userDatalength);
-        return ((float) maxLength - distance) / maxLength;
-    }
-
-    /**
-     * Computes the edit distance (number of insertions, deletions or substitutions to edit one
-     * string into the other) between two strings. In particular, this will compute the Levenshtein
-     * distance.
-     *
-     * <p>See http://en.wikipedia.org/wiki/Levenshtein_distance for details.
-     *
-     * @param s the first string to compare
-     * @param t the second string to compare
-     * @return the edit distance between the two strings
-     */
-    // Note: copied verbatim from com.android.tools.lint.detector.api.LintUtils.java
-    public static int editDistance(@NonNull String s, @NonNull String t) {
-        return editDistance(s, t, Integer.MAX_VALUE);
-    }
-
-    /**
-     * Computes the edit distance (number of insertions, deletions or substitutions to edit one
-     * string into the other) between two strings. In particular, this will compute the Levenshtein
-     * distance.
-     *
-     * <p>See http://en.wikipedia.org/wiki/Levenshtein_distance for details.
-     *
-     * @param s the first string to compare
-     * @param t the second string to compare
-     * @param max the maximum edit distance that we care about; if for example the string length
-     *     delta is greater than this we don't bother computing the exact edit distance since the
-     *     caller has indicated they're not interested in the result
-     * @return the edit distance between the two strings, or some other value greater than that if
-     *     the edit distance is at least as big as the {@code max} parameter
-     */
-    // Note: copied verbatim from com.android.tools.lint.detector.api.LintUtils.java
-    private static int editDistance(@NonNull String s, @NonNull String t, int max) {
-        if (s.equals(t)) {
-            return 0;
-        }
-
-        if (Math.abs(s.length() - t.length()) > max) {
-            // The string lengths differ more than the allowed edit distance;
-            // no point in even attempting to compute the edit distance (requires
-            // O(n*m) storage and O(n*m) speed, where n and m are the string lengths)
-            return Integer.MAX_VALUE;
-        }
-
-        int m = s.length();
-        int n = t.length();
-        int[][] d = new int[m + 1][n + 1];
-        for (int i = 0; i <= m; i++) {
-            d[i][0] = i;
-        }
-        for (int j = 0; j <= n; j++) {
-            d[0][j] = j;
-        }
-        for (int j = 1; j <= n; j++) {
-            for (int i = 1; i <= m; i++) {
-                if (s.charAt(i - 1) == t.charAt(j - 1)) {
-                    d[i][j] = d[i - 1][j - 1];
-                } else {
-                    int deletion = d[i - 1][j] + 1;
-                    int insertion = d[i][j - 1] + 1;
-                    int substitution = d[i - 1][j - 1] + 1;
-                    d[i][j] = Math.min(deletion, Math.min(insertion, substitution));
-                }
-            }
-        }
-
-        return d[m][n];
-    }
-    /**
-     * Gets the scores in a batch.
-     */
-    static float[][] getScores(@NonNull List<AutofillValue> actualValues,
-            @NonNull List<String> userDataValues) {
-        final int actualValuesSize = actualValues.size();
-        final int userDataValuesSize = userDataValues.size();
-        if (DEBUG) {
-            Log.d(TAG, "getScores() will return a " + actualValuesSize + "x"
-                    + userDataValuesSize + " matrix for " + DEFAULT_ALGORITHM);
-        }
-        final float[][] scores = new float[actualValuesSize][userDataValuesSize];
-
-        for (int i = 0; i < actualValuesSize; i++) {
-            for (int j = 0; j < userDataValuesSize; j++) {
-                final float score = getScore(actualValues.get(i), userDataValues.get(j));
-                scores[i][j] = score;
-            }
-        }
-        return scores;
-    }
-
-}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
deleted file mode 100644
index f878822..0000000
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/**
- * Copyright (C) 2017 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.ext.services.notification;
-
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
-
-import android.app.INotificationManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.ext.services.R;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.storage.StorageManager;
-import android.provider.Settings;
-import android.service.notification.Adjustment;
-import android.service.notification.NotificationAssistantService;
-import android.service.notification.NotificationStats;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Slog;
-import android.util.Xml;
-
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
-
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Map;
-
-/**
- * Notification assistant that provides guidance on notification channel blocking
- */
-public class Assistant extends NotificationAssistantService {
-    private static final String TAG = "ExtAssistant";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final String TAG_ASSISTANT = "assistant";
-    private static final String TAG_IMPRESSION = "impression-set";
-    private static final String ATT_KEY = "key";
-    private static final int DB_VERSION = 1;
-    private static final String ATTR_VERSION = "version";
-
-    private static final ArrayList<Integer> PREJUDICAL_DISMISSALS = new ArrayList<>();
-    static {
-        PREJUDICAL_DISMISSALS.add(REASON_CANCEL);
-        PREJUDICAL_DISMISSALS.add(REASON_LISTENER_CANCEL);
-    }
-
-    private float mDismissToViewRatioLimit;
-    private int mStreakLimit;
-
-    // key : impressions tracker
-    // TODO: prune deleted channels and apps
-    final ArrayMap<String, ChannelImpressions> mkeyToImpressions = new ArrayMap<>();
-    // SBN key : channel id
-    ArrayMap<String, String> mLiveNotifications = new ArrayMap<>();
-
-    private Ranking mFakeRanking = null;
-    private AtomicFile mFile = null;
-
-    public Assistant() {
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        // Contexts are correctly hooked up by the creation step, which is required for the observer
-        // to be hooked up/initialized.
-        new SettingsObserver(mHandler);
-    }
-
-    private void loadFile() {
-        if (DEBUG) Slog.d(TAG, "loadFile");
-        AsyncTask.execute(() -> {
-            InputStream infile = null;
-            try {
-                infile = mFile.openRead();
-                readXml(infile);
-            } catch (FileNotFoundException e) {
-                Log.d(TAG, "File doesn't exist or isn't readable yet");
-            } catch (IOException e) {
-                Log.e(TAG, "Unable to read channel impressions", e);
-            } catch (NumberFormatException | XmlPullParserException e) {
-                Log.e(TAG, "Unable to parse channel impressions", e);
-            } finally {
-                IoUtils.closeQuietly(infile);
-            }
-        });
-    }
-
-    protected void readXml(InputStream stream)
-            throws XmlPullParserException, NumberFormatException, IOException {
-        final XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(stream, StandardCharsets.UTF_8.name());
-        final int outerDepth = parser.getDepth();
-        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-            if (!TAG_ASSISTANT.equals(parser.getName())) {
-                continue;
-            }
-            final int impressionOuterDepth = parser.getDepth();
-            while (XmlUtils.nextElementWithin(parser, impressionOuterDepth)) {
-                if (!TAG_IMPRESSION.equals(parser.getName())) {
-                    continue;
-                }
-                String key = parser.getAttributeValue(null, ATT_KEY);
-                ChannelImpressions ci = createChannelImpressionsWithThresholds();
-                ci.populateFromXml(parser);
-                synchronized (mkeyToImpressions) {
-                    ci.append(mkeyToImpressions.get(key));
-                    mkeyToImpressions.put(key, ci);
-                }
-            }
-        }
-    }
-
-    private void saveFile() throws IOException {
-        AsyncTask.execute(() -> {
-            final FileOutputStream stream;
-            try {
-                stream = mFile.startWrite();
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to save policy file", e);
-                return;
-            }
-            try {
-                final XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(stream, StandardCharsets.UTF_8.name());
-                writeXml(out);
-                mFile.finishWrite(stream);
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to save impressions file, restoring backup", e);
-                mFile.failWrite(stream);
-            }
-        });
-    }
-
-    protected void writeXml(XmlSerializer out) throws IOException {
-        out.startDocument(null, true);
-        out.startTag(null, TAG_ASSISTANT);
-        out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
-        synchronized (mkeyToImpressions) {
-            for (Map.Entry<String, ChannelImpressions> entry
-                    : mkeyToImpressions.entrySet()) {
-                // TODO: ensure channel still exists
-                out.startTag(null, TAG_IMPRESSION);
-                out.attribute(null, ATT_KEY, entry.getKey());
-                entry.getValue().writeXml(out);
-                out.endTag(null, TAG_IMPRESSION);
-            }
-        }
-        out.endTag(null, TAG_ASSISTANT);
-        out.endDocument();
-    }
-
-    @Override
-    public Adjustment onNotificationEnqueued(StatusBarNotification sbn) {
-        if (DEBUG) Log.i(TAG, "ENQUEUED " + sbn.getKey());
-        return null;
-    }
-
-    @Override
-    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
-        if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey());
-        try {
-            Ranking ranking = getRanking(sbn.getKey(), rankingMap);
-            if (ranking != null && ranking.getChannel() != null) {
-                String key = getKey(
-                        sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
-                ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
-                        createChannelImpressionsWithThresholds());
-                if (ranking.getImportance() > IMPORTANCE_MIN && ci.shouldTriggerBlock()) {
-                    adjustNotification(createNegativeAdjustment(
-                            sbn.getPackageName(), sbn.getKey(), sbn.getUserId()));
-                }
-                mkeyToImpressions.put(key, ci);
-                mLiveNotifications.put(sbn.getKey(), ranking.getChannel().getId());
-            }
-        } catch (Throwable e) {
-            Log.e(TAG, "Error occurred processing post", e);
-        }
-    }
-
-    @Override
-    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
-            NotificationStats stats, int reason) {
-        try {
-            boolean updatedImpressions = false;
-            String channelId = mLiveNotifications.remove(sbn.getKey());
-            String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId);
-            synchronized (mkeyToImpressions) {
-                ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
-                        createChannelImpressionsWithThresholds());
-                if (stats.hasSeen()) {
-                    ci.incrementViews();
-                    updatedImpressions = true;
-                }
-                if (PREJUDICAL_DISMISSALS.contains(reason)) {
-                    if ((!sbn.isAppGroup() || sbn.getNotification().isGroupChild())
-                            && !stats.hasInteracted()
-                            && stats.getDismissalSurface() != NotificationStats.DISMISSAL_AOD
-                            && stats.getDismissalSurface() != NotificationStats.DISMISSAL_PEEK
-                            && stats.getDismissalSurface() != NotificationStats.DISMISSAL_OTHER) {
-                        if (DEBUG) Log.i(TAG, "increment dismissals " + key);
-                        ci.incrementDismissals();
-                        updatedImpressions = true;
-                    } else {
-                        if (DEBUG) Slog.i(TAG, "reset streak " + key);
-                        if (ci.getStreak() > 0) {
-                            updatedImpressions = true;
-                        }
-                        ci.resetStreak();
-                    }
-                }
-                mkeyToImpressions.put(key, ci);
-            }
-            if (updatedImpressions) {
-                saveFile();
-            }
-        } catch (Throwable e) {
-            Slog.e(TAG, "Error occurred processing removal", e);
-        }
-    }
-
-    @Override
-    public void onNotificationSnoozedUntilContext(StatusBarNotification sbn,
-            String snoozeCriterionId) {
-    }
-
-    @Override
-    public void onListenerConnected() {
-        if (DEBUG) Log.i(TAG, "CONNECTED");
-        try {
-            mFile = new AtomicFile(new File(new File(
-                    Environment.getDataUserCePackageDirectory(
-                            StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
-                    "assistant"), "blocking_helper_stats.xml"));
-            loadFile();
-            for (StatusBarNotification sbn : getActiveNotifications()) {
-                onNotificationPosted(sbn);
-            }
-        } catch (Throwable e) {
-            Log.e(TAG, "Error occurred on connection", e);
-        }
-    }
-
-    protected String getKey(String pkg, int userId, String channelId) {
-        return pkg + "|" + userId + "|" + channelId;
-    }
-
-    private Ranking getRanking(String key, RankingMap rankingMap) {
-        if (mFakeRanking != null) {
-            return mFakeRanking;
-        }
-        Ranking ranking = new Ranking();
-        rankingMap.getRanking(key, ranking);
-        return ranking;
-    }
-
-    private Adjustment createNegativeAdjustment(String packageName, String key, int user) {
-        if (DEBUG) Log.d(TAG, "User probably doesn't want " + key);
-        Bundle signals = new Bundle();
-        signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
-        return new Adjustment(packageName, key,  signals,
-                getContext().getString(R.string.prompt_block_reason), user);
-    }
-
-    // for testing
-
-    protected void setFile(AtomicFile file) {
-        mFile = file;
-    }
-
-    protected void setFakeRanking(Ranking ranking) {
-        mFakeRanking = ranking;
-    }
-
-    protected void setNoMan(INotificationManager noMan) {
-        mNoMan = noMan;
-    }
-
-    protected void setContext(Context context) {
-        mSystemContext = context;
-    }
-
-    protected ChannelImpressions getImpressions(String key) {
-        synchronized (mkeyToImpressions) {
-            return mkeyToImpressions.get(key);
-        }
-    }
-
-    protected void insertImpressions(String key, ChannelImpressions ci) {
-        synchronized (mkeyToImpressions) {
-            mkeyToImpressions.put(key, ci);
-        }
-    }
-
-    private ChannelImpressions createChannelImpressionsWithThresholds() {
-        ChannelImpressions impressions = new ChannelImpressions();
-        impressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit);
-        return impressions;
-    }
-
-    /**
-     * Observer for updates on blocking helper threshold values.
-     */
-    private final class SettingsObserver extends ContentObserver {
-        private final Uri STREAK_LIMIT_URI =
-                Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT);
-        private final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI =
-                Settings.Global.getUriFor(
-                        Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT);
-
-        public SettingsObserver(Handler handler) {
-            super(handler);
-            ContentResolver resolver = getApplicationContext().getContentResolver();
-            resolver.registerContentObserver(
-                    DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, getUserId());
-            resolver.registerContentObserver(STREAK_LIMIT_URI, false, this, getUserId());
-
-            // Update all uris on creation.
-            update(null);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            update(uri);
-        }
-
-        private void update(Uri uri) {
-            ContentResolver resolver = getApplicationContext().getContentResolver();
-            if (uri == null || DISMISS_TO_VIEW_RATIO_LIMIT_URI.equals(uri)) {
-                mDismissToViewRatioLimit = Settings.Global.getFloat(
-                        resolver, Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
-                        ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT);
-            }
-            if (uri == null || STREAK_LIMIT_URI.equals(uri)) {
-                mStreakLimit = Settings.Global.getInt(
-                        resolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
-                        ChannelImpressions.DEFAULT_STREAK_LIMIT);
-            }
-
-            // Update all existing channel impression objects with any new limits/thresholds.
-            synchronized (mkeyToImpressions) {
-                for (ChannelImpressions channelImpressions: mkeyToImpressions.values()) {
-                    channelImpressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit);
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
deleted file mode 100644
index 29ee920..0000000
--- a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/**
- * Copyright (C) 2017 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.ext.services.notification;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-
-public final class ChannelImpressions implements Parcelable {
-    private static final String TAG = "ExtAssistant.CI";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    static final float DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT = .8f;
-    static final int DEFAULT_STREAK_LIMIT = 2;
-    static final String ATT_DISMISSALS = "dismisses";
-    static final String ATT_VIEWS = "views";
-    static final String ATT_STREAK = "streak";
-
-    private int mDismissals = 0;
-    private int mViews = 0;
-    private int mStreak = 0;
-
-    private float mDismissToViewRatioLimit;
-    private int mStreakLimit;
-
-    public ChannelImpressions() {
-        mDismissToViewRatioLimit = DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT;
-        mStreakLimit = DEFAULT_STREAK_LIMIT;
-    }
-
-    protected ChannelImpressions(Parcel in) {
-        mDismissals = in.readInt();
-        mViews = in.readInt();
-        mStreak = in.readInt();
-        mDismissToViewRatioLimit = in.readFloat();
-        mStreakLimit = in.readInt();
-    }
-
-    public int getStreak() {
-        return mStreak;
-    }
-
-    public int getDismissals() {
-        return mDismissals;
-    }
-
-    public int getViews() {
-        return mViews;
-    }
-
-    public void incrementDismissals() {
-        mDismissals++;
-        mStreak++;
-    }
-
-    void updateThresholds(float dismissToViewRatioLimit, int streakLimit) {
-        mDismissToViewRatioLimit = dismissToViewRatioLimit;
-        mStreakLimit = streakLimit;
-    }
-
-    @VisibleForTesting
-    float getDismissToViewRatioLimit() {
-        return mDismissToViewRatioLimit;
-    }
-
-    @VisibleForTesting
-    int getStreakLimit() {
-        return mStreakLimit;
-    }
-
-    public void append(ChannelImpressions additionalImpressions) {
-        if (additionalImpressions != null) {
-            mViews += additionalImpressions.getViews();
-            mStreak += additionalImpressions.getStreak();
-            mDismissals += additionalImpressions.getDismissals();
-        }
-    }
-
-    public void incrementViews() {
-        mViews++;
-    }
-
-    public void resetStreak() {
-        mStreak = 0;
-    }
-
-    public boolean shouldTriggerBlock() {
-        if (getViews() == 0) {
-            return false;
-        }
-        if (DEBUG) {
-            Log.d(TAG, "should trigger? " + getDismissals() + " " + getViews() + " " + getStreak());
-        }
-        return ((float) getDismissals() / getViews()) > mDismissToViewRatioLimit
-                && getStreak() > mStreakLimit;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mDismissals);
-        dest.writeInt(mViews);
-        dest.writeInt(mStreak);
-        dest.writeFloat(mDismissToViewRatioLimit);
-        dest.writeInt(mStreakLimit);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Creator<ChannelImpressions> CREATOR = new Creator<ChannelImpressions>() {
-        @Override
-        public ChannelImpressions createFromParcel(Parcel in) {
-            return new ChannelImpressions(in);
-        }
-
-        @Override
-        public ChannelImpressions[] newArray(int size) {
-            return new ChannelImpressions[size];
-        }
-    };
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        ChannelImpressions that = (ChannelImpressions) o;
-
-        if (mDismissals != that.mDismissals) return false;
-        if (mViews != that.mViews) return false;
-        return mStreak == that.mStreak;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = mDismissals;
-        result = 31 * result + mViews;
-        result = 31 * result + mStreak;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder("ChannelImpressions{");
-        sb.append("mDismissals=").append(mDismissals);
-        sb.append(", mViews=").append(mViews);
-        sb.append(", mStreak=").append(mStreak);
-        sb.append(", thresholds=(").append(mDismissToViewRatioLimit);
-        sb.append(",").append(mStreakLimit);
-        sb.append(")}");
-        return sb.toString();
-    }
-
-    protected void populateFromXml(XmlPullParser parser) {
-        mDismissals = safeInt(parser, ATT_DISMISSALS, 0);
-        mStreak = safeInt(parser, ATT_STREAK, 0);
-        mViews = safeInt(parser, ATT_VIEWS, 0);
-    }
-
-    protected void writeXml(XmlSerializer out) throws IOException {
-        if (mDismissals != 0) {
-            out.attribute(null, ATT_DISMISSALS, String.valueOf(mDismissals));
-        }
-        if (mStreak != 0) {
-            out.attribute(null, ATT_STREAK, String.valueOf(mStreak));
-        }
-        if (mViews != 0) {
-            out.attribute(null, ATT_VIEWS, String.valueOf(mViews));
-        }
-    }
-
-    private static int safeInt(XmlPullParser parser, String att, int defValue) {
-        final String val = parser.getAttributeValue(null, att);
-        return tryParseInt(val, defValue);
-    }
-
-    private static int tryParseInt(String value, int defValue) {
-        if (TextUtils.isEmpty(value)) return defValue;
-        try {
-            return Integer.parseInt(value);
-        } catch (NumberFormatException e) {
-            return defValue;
-        }
-    }
-}
diff --git a/packages/ExtServices/src/android/ext/services/resolver/LRResolverRankerService.java b/packages/ExtServices/src/android/ext/services/resolver/LRResolverRankerService.java
deleted file mode 100644
index 9d7a568..0000000
--- a/packages/ExtServices/src/android/ext/services/resolver/LRResolverRankerService.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2017 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.ext.services.resolver;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Environment;
-import android.os.IBinder;
-import android.os.storage.StorageManager;
-import android.service.resolver.ResolverRankerService;
-import android.service.resolver.ResolverTarget;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A Logistic Regression based {@link android.service.resolver.ResolverRankerService}, to be used
- * in {@link ResolverComparator}.
- */
-public final class LRResolverRankerService extends ResolverRankerService {
-    private static final String TAG = "LRResolverRankerService";
-
-    private static final boolean DEBUG = false;
-
-    private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
-    private static final String BIAS_PREF_KEY = "bias";
-    private static final String VERSION_PREF_KEY = "version";
-
-    private static final String LAUNCH_SCORE = "launch";
-    private static final String TIME_SPENT_SCORE = "timeSpent";
-    private static final String RECENCY_SCORE = "recency";
-    private static final String CHOOSER_SCORE = "chooser";
-
-    // parameters for a pre-trained model, to initialize the app ranker. When updating the
-    // pre-trained model, please update these params, as well as initModel().
-    private static final int CURRENT_VERSION = 1;
-    private static final float LEARNING_RATE = 0.0001f;
-    private static final float REGULARIZER_PARAM = 0.0001f;
-
-    private SharedPreferences mParamSharedPref;
-    private ArrayMap<String, Float> mFeatureWeights;
-    private float mBias;
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        initModel();
-        return super.onBind(intent);
-    }
-
-    @Override
-    public void onPredictSharingProbabilities(List<ResolverTarget> targets) {
-        final int size = targets.size();
-        for (int i = 0; i < size; ++i) {
-            ResolverTarget target = targets.get(i);
-            ArrayMap<String, Float> features = getFeatures(target);
-            target.setSelectProbability(predict(features));
-        }
-    }
-
-    @Override
-    public void onTrainRankingModel(List<ResolverTarget> targets, int selectedPosition) {
-        final int size = targets.size();
-        if (selectedPosition < 0 || selectedPosition >= size) {
-            if (DEBUG) {
-                Log.d(TAG, "Invalid Position of Selected App " + selectedPosition);
-            }
-            return;
-        }
-        final ArrayMap<String, Float> positive = getFeatures(targets.get(selectedPosition));
-        final float positiveProbability = targets.get(selectedPosition).getSelectProbability();
-        final int targetSize = targets.size();
-        for (int i = 0; i < targetSize; ++i) {
-            if (i == selectedPosition) {
-                continue;
-            }
-            final ArrayMap<String, Float> negative = getFeatures(targets.get(i));
-            final float negativeProbability = targets.get(i).getSelectProbability();
-            if (negativeProbability > positiveProbability) {
-                update(negative, negativeProbability, false);
-                update(positive, positiveProbability, true);
-            }
-        }
-        commitUpdate();
-    }
-
-    private void initModel() {
-        mParamSharedPref = getParamSharedPref();
-        mFeatureWeights = new ArrayMap<>(4);
-        if (mParamSharedPref == null ||
-                mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
-            // Initializing the app ranker to a pre-trained model. When updating the pre-trained
-            // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
-            // REGULARIZER_PARAM.
-            mBias = -1.6568f;
-            mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
-            mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
-            mFeatureWeights.put(RECENCY_SCORE, 0.269f);
-            mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
-        } else {
-            mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
-            mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
-            mFeatureWeights.put(
-                    TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
-            mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
-            mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
-        }
-    }
-
-    private ArrayMap<String, Float> getFeatures(ResolverTarget target) {
-        ArrayMap<String, Float> features = new ArrayMap<>(4);
-        features.put(RECENCY_SCORE, target.getRecencyScore());
-        features.put(TIME_SPENT_SCORE, target.getTimeSpentScore());
-        features.put(LAUNCH_SCORE, target.getLaunchScore());
-        features.put(CHOOSER_SCORE, target.getChooserScore());
-        return features;
-    }
-
-    private float predict(ArrayMap<String, Float> target) {
-        if (target == null) {
-            return 0.0f;
-        }
-        final int featureSize = target.size();
-        float sum = 0.0f;
-        for (int i = 0; i < featureSize; i++) {
-            String featureName = target.keyAt(i);
-            float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-            sum += weight * target.valueAt(i);
-        }
-        return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
-    }
-
-    private void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
-        if (target == null) {
-            return;
-        }
-        final int featureSize = target.size();
-        float error = isSelected ? 1.0f - predict : -predict;
-        for (int i = 0; i < featureSize; i++) {
-            String featureName = target.keyAt(i);
-            float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-            mBias += LEARNING_RATE * error;
-            currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
-                    LEARNING_RATE * error * target.valueAt(i);
-            mFeatureWeights.put(featureName, currentWeight);
-        }
-        if (DEBUG) {
-            Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
-        }
-    }
-
-    private void commitUpdate() {
-        try {
-            SharedPreferences.Editor editor = mParamSharedPref.edit();
-            editor.putFloat(BIAS_PREF_KEY, mBias);
-            final int size = mFeatureWeights.size();
-            for (int i = 0; i < size; i++) {
-                editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
-            }
-            editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
-            editor.apply();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to commit update" + e);
-        }
-    }
-
-    private SharedPreferences getParamSharedPref() {
-        // The package info in the context isn't initialized in the way it is for normal apps,
-        // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
-        // build the path manually below using the same policy that appears in ContextImpl.
-        if (DEBUG) {
-            Log.d(TAG, "Context Package Name: " + getPackageName());
-        }
-        final File prefsFile = new File(new File(
-                Environment.getDataUserCePackageDirectory(
-                        StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
-                "shared_prefs"),
-                PARAM_SHARED_PREF_NAME + ".xml");
-        return getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
-    }
-}
\ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/storage/CacheQuotaServiceImpl.java b/packages/ExtServices/src/android/ext/services/storage/CacheQuotaServiceImpl.java
deleted file mode 100644
index 862f50b2..0000000
--- a/packages/ExtServices/src/android/ext/services/storage/CacheQuotaServiceImpl.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2017 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.ext.services.storage;
-
-import android.app.usage.CacheQuotaHint;
-import android.app.usage.CacheQuotaService;
-import android.os.Environment;
-import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
-import android.util.ArrayMap;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * CacheQuotaServiceImpl implements the CacheQuotaService with a strategy for populating the quota
- * of {@link CacheQuotaHint}.
- */
-public class CacheQuotaServiceImpl extends CacheQuotaService {
-    private static final double CACHE_RESERVE_RATIO = 0.15;
-
-    @Override
-    public List<CacheQuotaHint> onComputeCacheQuotaHints(List<CacheQuotaHint> requests) {
-        ArrayMap<String, List<CacheQuotaHint>> byUuid = new ArrayMap<>();
-        final int requestCount = requests.size();
-        for (int i = 0; i < requestCount; i++) {
-            CacheQuotaHint request = requests.get(i);
-            String uuid = request.getVolumeUuid();
-            List<CacheQuotaHint> listForUuid = byUuid.get(uuid);
-            if (listForUuid == null) {
-                listForUuid = new ArrayList<>();
-                byUuid.put(uuid, listForUuid);
-            }
-            listForUuid.add(request);
-        }
-
-        List<CacheQuotaHint> processed = new ArrayList<>();
-        byUuid.entrySet().forEach(
-                requestListEntry -> {
-                    // Collapse all usage stats to the same uid.
-                    Map<Integer, List<CacheQuotaHint>> byUid = requestListEntry.getValue()
-                            .stream()
-                            .collect(Collectors.groupingBy(CacheQuotaHint::getUid));
-                    byUid.values().forEach(uidGroupedList -> {
-                        int size = uidGroupedList.size();
-                        if (size < 2) {
-                            return;
-                        }
-                        CacheQuotaHint first = uidGroupedList.get(0);
-                        for (int i = 1; i < size; i++) {
-                            /* Note: We can't use the UsageStats built-in addition function because
-                                     UIDs may span multiple packages and usage stats adding has
-                                     matching package names as a precondition. */
-                            first.getUsageStats().mTotalTimeInForeground +=
-                                    uidGroupedList.get(i).getUsageStats().mTotalTimeInForeground;
-                        }
-                    });
-
-                    // Because the foreground stats have been added to the first element, we need
-                    // a list of only the first values (which contain the merged foreground time).
-                    List<CacheQuotaHint> flattenedRequests =
-                            byUid.values()
-                                 .stream()
-                                 .map(entryList -> entryList.get(0))
-                                 .filter(entry -> entry.getUsageStats().mTotalTimeInForeground != 0)
-                                 .sorted(sCacheQuotaRequestComparator)
-                                 .collect(Collectors.toList());
-
-                    // Because the elements are sorted, we can use the index to also be the sorted
-                    // index for cache quota calculation.
-                    double sum = getSumOfFairShares(flattenedRequests.size());
-                    String uuid = requestListEntry.getKey();
-                    long reservedSize = getReservedCacheSize(uuid);
-                    for (int count = 0; count < flattenedRequests.size(); count++) {
-                        double share = getFairShareForPosition(count) / sum;
-                        CacheQuotaHint entry = flattenedRequests.get(count);
-                        CacheQuotaHint.Builder builder = new CacheQuotaHint.Builder(entry);
-                        builder.setQuota(Math.round(share * reservedSize));
-                        processed.add(builder.build());
-                    }
-                }
-        );
-
-        return processed.stream()
-                .filter(request -> request.getQuota() > 0).collect(Collectors.toList());
-    }
-
-    private double getFairShareForPosition(int position) {
-        double value = 1.0 / Math.log(position + 3) - 0.285;
-        return (value > 0.01) ? value : 0.01;
-    }
-
-    private double getSumOfFairShares(int size) {
-        double sum = 0;
-        for (int i = 0; i < size; i++) {
-            sum += getFairShareForPosition(i);
-        }
-        return sum;
-    }
-
-    private long getReservedCacheSize(String uuid) {
-        // TODO: Revisit the cache size after running more storage tests.
-        // TODO: Figure out how to ensure ExtServices has the permissions to call
-        //       StorageStatsManager, because this is ignoring the cache...
-        StorageManager storageManager = getSystemService(StorageManager.class);
-        long freeBytes = 0;
-        if (uuid == StorageManager.UUID_PRIVATE_INTERNAL) { // regular equals because of null
-            freeBytes = Environment.getDataDirectory().getUsableSpace();
-        } else {
-            final VolumeInfo vol = storageManager.findVolumeByUuid(uuid);
-            freeBytes = vol.getPath().getUsableSpace();
-        }
-        return Math.round(freeBytes * CACHE_RESERVE_RATIO);
-    }
-
-    // Compares based upon foreground time.
-    private static Comparator<CacheQuotaHint> sCacheQuotaRequestComparator =
-            new Comparator<CacheQuotaHint>() {
-        @Override
-        public int compare(CacheQuotaHint o, CacheQuotaHint t1) {
-            long x = t1.getUsageStats().getTotalTimeInForeground();
-            long y = o.getUsageStats().getTotalTimeInForeground();
-            return (x < y) ? -1 : ((x == y) ? 0 : 1);
-        }
-    };
-}
diff --git a/packages/ExtServices/tests/Android.bp b/packages/ExtServices/tests/Android.bp
deleted file mode 100644
index db16027..0000000
--- a/packages/ExtServices/tests/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-android_test {
-    name: "ExtServicesUnitTests",
-    certificate: "platform",
-    libs: [
-        "android.test.runner",
-        "android.test.base",
-    ],
-    static_libs: [
-        "androidx.test.rules",
-        "mockito-target-minus-junit4",
-        "androidx.test.espresso.core",
-        "truth-prebuilt",
-        "testables",
-    ],
-    // Include all test java files.
-    srcs: ["src/**/*.java"],
-    platform_apis: true,
-    instrumentation_for: "ExtServices",
-}
diff --git a/packages/ExtServices/tests/AndroidManifest.xml b/packages/ExtServices/tests/AndroidManifest.xml
deleted file mode 100644
index 42293b5..0000000
--- a/packages/ExtServices/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.ext.services.tests.unit">
-
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="android.ext.services"
-                     android:label="ExtServices Test Cases">
-    </instrumentation>
-
-</manifest>
\ No newline at end of file
diff --git a/packages/ExtServices/tests/AndroidTest.xml b/packages/ExtServices/tests/AndroidTest.xml
deleted file mode 100644
index cd26ebc..0000000
--- a/packages/ExtServices/tests/AndroidTest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-<configuration description="Runs Tests for ExtServices">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="ExtServicesUnitTests.apk" />
-    </target_preparer>
-
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="framework-base-presubmit" />
-    <option name="test-tag" value="ExtServicesUnitTests" />
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.ext.services.tests.unit" />
-        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
-        <option name="hidden-api-checks" value="false"/>
-    </test>
-</configuration>
\ No newline at end of file
diff --git a/packages/ExtServices/tests/src/android/ext/services/autofill/AutofillFieldClassificationServiceImplTest.java b/packages/ExtServices/tests/src/android/ext/services/autofill/AutofillFieldClassificationServiceImplTest.java
deleted file mode 100644
index 48c076e..0000000
--- a/packages/ExtServices/tests/src/android/ext/services/autofill/AutofillFieldClassificationServiceImplTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 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.ext.services.autofill;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.view.autofill.AutofillValue;
-
-/**
- * Contains the base tests that does not rely on the specific algorithm implementation.
- */
-public class AutofillFieldClassificationServiceImplTest {
-
-    private final AutofillFieldClassificationServiceImpl mService =
-            new AutofillFieldClassificationServiceImpl();
-
-    @Test
-    public void testOnGetScores_nullActualValues() {
-        assertThat(mService.onGetScores(null, null, null, Arrays.asList("whatever"))).isNull();
-    }
-
-    @Test
-    public void testOnGetScores_emptyActualValues() {
-        assertThat(mService.onGetScores(null, null, Collections.emptyList(),
-                Arrays.asList("whatever"))).isNull();
-    }
-
-    @Test
-    public void testOnGetScores_nullUserDataValues() {
-        assertThat(mService.onGetScores(null, null,
-                Arrays.asList(AutofillValue.forText("whatever")), null)).isNull();
-    }
-
-    @Test
-    public void testOnGetScores_emptyUserDataValues() {
-        assertThat(mService.onGetScores(null, null,
-                Arrays.asList(AutofillValue.forText("whatever")), Collections.emptyList()))
-                        .isNull();
-    }
-}
diff --git a/packages/ExtServices/tests/src/android/ext/services/autofill/EditDistanceScorerTest.java b/packages/ExtServices/tests/src/android/ext/services/autofill/EditDistanceScorerTest.java
deleted file mode 100644
index afe2236..0000000
--- a/packages/ExtServices/tests/src/android/ext/services/autofill/EditDistanceScorerTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2018 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.ext.services.autofill;
-
-import static android.ext.services.autofill.EditDistanceScorer.getScore;
-import static android.ext.services.autofill.EditDistanceScorer.getScores;
-import static android.view.autofill.AutofillValue.forText;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.view.autofill.AutofillValue;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.List;
-
-public class EditDistanceScorerTest {
-
-    @Test
-    public void testGetScore_nullValue() {
-        assertFloat(getScore(null, "D'OH!"), 0);
-    }
-
-    @Test
-    public void testGetScore_nonTextValue() {
-        assertFloat(getScore(AutofillValue.forToggle(true), "D'OH!"), 0);
-    }
-
-    @Test
-    public void testGetScore_nullUserData() {
-        assertFloat(getScore(AutofillValue.forText("D'OH!"), null), 0);
-    }
-
-    @Test
-    public void testGetScore_fullMatch() {
-        assertFloat(getScore(AutofillValue.forText("D'OH!"), "D'OH!"), 1);
-        assertFloat(getScore(AutofillValue.forText(""), ""), 1);
-    }
-
-    @Test
-    public void testGetScore_fullMatchMixedCase() {
-        assertFloat(getScore(AutofillValue.forText("D'OH!"), "D'oH!"), 1);
-    }
-
-    @Test
-    public void testGetScore_mismatchDifferentSizes() {
-        assertFloat(getScore(AutofillValue.forText("X"), "Xy"), 0.50F);
-        assertFloat(getScore(AutofillValue.forText("Xy"), "X"), 0.50F);
-        assertFloat(getScore(AutofillValue.forText("One"), "MoreThanOne"), 0.27F);
-        assertFloat(getScore(AutofillValue.forText("MoreThanOne"), "One"), 0.27F);
-        assertFloat(getScore(AutofillValue.forText("1600 Amphitheatre Parkway"),
-                "1600 Amphitheatre Pkwy"), 0.88F);
-        assertFloat(getScore(AutofillValue.forText("1600 Amphitheatre Pkwy"),
-                "1600 Amphitheatre Parkway"), 0.88F);
-    }
-
-    @Test
-    public void testGetScore_partialMatch() {
-        assertFloat(getScore(AutofillValue.forText("Dude"), "Dxxx"), 0.25F);
-        assertFloat(getScore(AutofillValue.forText("Dude"), "DUxx"), 0.50F);
-        assertFloat(getScore(AutofillValue.forText("Dude"), "DUDx"), 0.75F);
-        assertFloat(getScore(AutofillValue.forText("Dxxx"), "Dude"), 0.25F);
-        assertFloat(getScore(AutofillValue.forText("DUxx"), "Dude"), 0.50F);
-        assertFloat(getScore(AutofillValue.forText("DUDx"), "Dude"), 0.75F);
-    }
-
-    @Test
-    public void testGetScores() {
-        final List<AutofillValue> actualValues = Arrays.asList(forText("A"), forText("b"));
-        final List<String> userDataValues = Arrays.asList("a", "B", "ab", "c");
-        final float[][] expectedScores = new float[][] {
-            new float[] { 1F, 0F, 0.5F, 0F },
-            new float[] { 0F, 1F, 0.5F, 0F }
-        };
-        final float[][] actualScores = getScores(actualValues, userDataValues);
-
-        // Unfortunately, Truth does not have an easy way to compare float matrices and show useful
-        // messages in case of error, so we need to check.
-        assertWithMessage("actual=%s, expected=%s", toString(actualScores),
-                toString(expectedScores)).that(actualScores.length).isEqualTo(2);
-        assertWithMessage("actual=%s, expected=%s", toString(actualScores),
-                toString(expectedScores)).that(actualScores[0].length).isEqualTo(4);
-        assertWithMessage("actual=%s, expected=%s", toString(actualScores),
-                toString(expectedScores)).that(actualScores[1].length).isEqualTo(4);
-        for (int i = 0; i < actualScores.length; i++) {
-            final float[] line = actualScores[i];
-            for (int j = 0; j < line.length; j++) {
-                float cell = line[j];
-                assertWithMessage("wrong score at [%s, %s]", i, j).that(cell).isWithin(0.01F)
-                        .of(expectedScores[i][j]);
-            }
-        }
-    }
-
-    public static void assertFloat(float actualValue, float expectedValue) {
-        assertThat(actualValue).isWithin(0.01F).of(expectedValue);
-    }
-
-    public static String toString(float[][] matrix) {
-        final StringBuilder string = new StringBuilder("[ ");
-        for (int i = 0; i < matrix.length; i++) {
-            string.append(Arrays.toString(matrix[i])).append(" ");
-        }
-        return string.append(" ]").toString();
-    }
-}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
deleted file mode 100644
index 6ef25e5..0000000
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/**
- * Copyright (C) 2017 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.ext.services.notification;
-
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Application;
-import android.app.INotificationManager;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.notification.Adjustment;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.NotificationStats;
-import android.service.notification.StatusBarNotification;
-import android.test.ServiceTestCase;
-import android.testing.TestableContext;
-import android.util.AtomicFile;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.util.FastXmlSerializer;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileOutputStream;
-
-public class AssistantTest extends ServiceTestCase<Assistant> {
-
-    private static final String PKG1 = "pkg1";
-    private static final int UID1 = 1;
-    private static final NotificationChannel P1C1 =
-            new NotificationChannel("one", "", IMPORTANCE_LOW);
-    private static final NotificationChannel P1C2 =
-            new NotificationChannel("p1c2", "", IMPORTANCE_DEFAULT);
-    private static final NotificationChannel P1C3 =
-            new NotificationChannel("p1c3", "", IMPORTANCE_MIN);
-    private static final String PKG2 = "pkg2";
-
-    private static final int UID2 = 2;
-    private static final NotificationChannel P2C1 =
-            new NotificationChannel("one", "", IMPORTANCE_LOW);
-
-    @Mock INotificationManager mNoMan;
-    @Mock AtomicFile mFile;
-
-    Assistant mAssistant;
-    Application mApplication;
-
-    @Rule
-    public final TestableContext mContext =
-            new TestableContext(InstrumentationRegistry.getContext(), null);
-
-    public AssistantTest() {
-        super(Assistant.class);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        Intent startIntent =
-                new Intent("android.service.notification.NotificationAssistantService");
-        startIntent.setPackage("android.ext.services");
-
-        // To bypass real calls to global settings values, set the Settings values here.
-        Settings.Global.putFloat(mContext.getContentResolver(),
-                Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT, 0.8f);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, 2);
-        mApplication = (Application) InstrumentationRegistry.getInstrumentation().
-                getTargetContext().getApplicationContext();
-        // Force the test to use the correct application instead of trying to use a mock application
-        setApplication(mApplication);
-        bindService(startIntent);
-        mAssistant = getService();
-        mAssistant.setNoMan(mNoMan);
-        mAssistant.setFile(mFile);
-        when(mFile.startWrite()).thenReturn(mock(FileOutputStream.class));
-    }
-
-    private StatusBarNotification generateSbn(String pkg, int uid, NotificationChannel channel,
-            String tag, String groupKey) {
-        Notification n = new Notification.Builder(mContext, channel.getId())
-                .setContentTitle("foo")
-                .setGroup(groupKey)
-                .build();
-
-        StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 0, tag, uid, uid, n,
-                UserHandle.SYSTEM, null, 0);
-
-        return sbn;
-    }
-
-    private Ranking generateRanking(StatusBarNotification sbn, NotificationChannel channel) {
-        Ranking mockRanking = mock(Ranking.class);
-        when(mockRanking.getChannel()).thenReturn(channel);
-        when(mockRanking.getImportance()).thenReturn(channel.getImportance());
-        when(mockRanking.getKey()).thenReturn(sbn.getKey());
-        when(mockRanking.getOverrideGroupKey()).thenReturn(null);
-        return mockRanking;
-    }
-
-    private void almostBlockChannel(String pkg, int uid, NotificationChannel channel) {
-        for (int i = 0; i < ChannelImpressions.DEFAULT_STREAK_LIMIT; i++) {
-            dismissBadNotification(pkg, uid, channel, String.valueOf(i));
-        }
-    }
-
-    private void dismissBadNotification(String pkg, int uid, NotificationChannel channel,
-            String tag) {
-        StatusBarNotification sbn = generateSbn(pkg, uid, channel, tag, null);
-        mAssistant.setFakeRanking(generateRanking(sbn, channel));
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-        mAssistant.setFakeRanking(mock(Ranking.class));
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
-        stats.setSeen();
-        mAssistant.onNotificationRemoved(
-                sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
-    }
-
-    @Test
-    public void testNoAdjustmentForInitialPost() throws Exception {
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, null, null);
-
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-        dismissBadNotification(PKG1, UID1, P1C1, "trigger!");
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "new one!", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        ArgumentCaptor<Adjustment> captor = ArgumentCaptor.forClass(Adjustment.class);
-        verify(mNoMan, times(1)).applyAdjustmentFromAssistant(any(), captor.capture());
-        assertEquals(sbn.getKey(), captor.getValue().getKey());
-        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE,
-                captor.getValue().getSignals().getInt(Adjustment.KEY_USER_SENTIMENT));
-    }
-
-    @Test
-    public void testMinCannotTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C3);
-        dismissBadNotification(PKG1, UID1, P1C3, "trigger!");
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C3, "new one!", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C3));
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testGroupChildCanTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", "I HAVE A GROUP");
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
-        stats.setSeen();
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-        mAssistant.onNotificationRemoved(
-                sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
-
-        sbn = generateSbn(PKG1, UID1, P1C1, "new one!", "group");
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        ArgumentCaptor<Adjustment> captor = ArgumentCaptor.forClass(Adjustment.class);
-        verify(mNoMan, times(1)).applyAdjustmentFromAssistant(any(), captor.capture());
-        assertEquals(sbn.getKey(), captor.getValue().getKey());
-        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE,
-                captor.getValue().getSignals().getInt(Adjustment.KEY_USER_SENTIMENT));
-    }
-
-    @Test
-    public void testGroupSummaryCannotTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", "I HAVE A GROUP");
-        sbn.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
-        stats.setSeen();
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-        mAssistant.onNotificationRemoved(
-                sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
-
-        sbn = generateSbn(PKG1, UID1, P1C1, "new one!", "group");
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testAodCannotTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_AOD);
-        stats.setSeen();
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-        mAssistant.onNotificationRemoved(
-                sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
-
-        sbn = generateSbn(PKG1, UID1, P1C1, "new one!", null);
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testInteractedCannotTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
-        stats.setSeen();
-        stats.setExpanded();
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-        mAssistant.onNotificationRemoved(
-                sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
-
-        sbn = generateSbn(PKG1, UID1, P1C1, "new one!", null);
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testAppDismissedCannotTriggerAdjustment() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
-        stats.setSeen();
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-        mAssistant.onNotificationRemoved(
-                sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_APP_CANCEL);
-
-        sbn = generateSbn(PKG1, UID1, P1C1, "new one!", null);
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testAppSeparation() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-        dismissBadNotification(PKG1, UID1, P1C1, "trigger!");
-
-        StatusBarNotification sbn = generateSbn(PKG2, UID2, P2C1, "new app!", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P2C1));
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testChannelSeparation() throws Exception {
-        almostBlockChannel(PKG1, UID1, P1C1);
-        dismissBadNotification(PKG1, UID1, P1C1, "trigger!");
-
-        StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C2, "new app!", null);
-        mAssistant.setFakeRanking(generateRanking(sbn, P1C2));
-        mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
-
-        verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
-    }
-
-    @Test
-    public void testReadXml() throws Exception {
-        String key1 = mAssistant.getKey("pkg1", 1, "channel1");
-        int streak1 = 2;
-        int views1 = 5;
-        int dismiss1 = 9;
-
-        int streak1a = 3;
-        int views1a = 10;
-        int dismiss1a = 99;
-        String key1a = mAssistant.getKey("pkg1", 1, "channel1a");
-
-        int streak2 = 7;
-        int views2 = 77;
-        int dismiss2 = 777;
-        String key2 = mAssistant.getKey("pkg2", 2, "channel2");
-
-        String xml = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                + "<assistant version=\"1\">\n"
-                + "<impression-set key=\"" + key1 + "\" "
-                + "dismisses=\"" + dismiss1 + "\" views=\"" + views1
-                + "\" streak=\"" + streak1 + "\"/>\n"
-                + "<impression-set key=\"" + key1a + "\" "
-                + "dismisses=\"" + dismiss1a + "\" views=\"" + views1a
-                + "\" streak=\"" + streak1a + "\"/>\n"
-                + "<impression-set key=\"" + key2 + "\" "
-                + "dismisses=\"" + dismiss2 + "\" views=\"" + views2
-                + "\" streak=\"" + streak2 + "\"/>\n"
-                + "</assistant>\n";
-        mAssistant.readXml(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())));
-
-        ChannelImpressions c1 = mAssistant.getImpressions(key1);
-        assertEquals(2, c1.getStreak());
-        assertEquals(5, c1.getViews());
-        assertEquals(9, c1.getDismissals());
-
-        ChannelImpressions c1a = mAssistant.getImpressions(key1a);
-        assertEquals(3, c1a.getStreak());
-        assertEquals(10, c1a.getViews());
-        assertEquals(99, c1a.getDismissals());
-
-        ChannelImpressions c2 = mAssistant.getImpressions(key2);
-        assertEquals(7, c2.getStreak());
-        assertEquals(77, c2.getViews());
-        assertEquals(777, c2.getDismissals());
-    }
-
-    @Test
-    public void testRoundTripXml() throws Exception {
-        String key1 = mAssistant.getKey("pkg1", 1, "channel1");
-        ChannelImpressions ci1 = new ChannelImpressions();
-        String key2 = mAssistant.getKey("pkg1", 1, "channel2");
-        ChannelImpressions ci2 = new ChannelImpressions();
-        for (int i = 0; i < 3; i++) {
-            ci2.incrementViews();
-            ci2.incrementDismissals();
-        }
-        ChannelImpressions ci3 = new ChannelImpressions();
-        String key3 = mAssistant.getKey("pkg3", 3, "channel2");
-        for (int i = 0; i < 9; i++) {
-            ci3.incrementViews();
-            if (i % 3 == 0) {
-                ci3.incrementDismissals();
-            }
-        }
-
-        mAssistant.insertImpressions(key1, ci1);
-        mAssistant.insertImpressions(key2, ci2);
-        mAssistant.insertImpressions(key3, ci3);
-
-        XmlSerializer serializer = new FastXmlSerializer();
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
-        mAssistant.writeXml(serializer);
-
-        Assistant assistant = new Assistant();
-        assistant.readXml(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
-
-        assertEquals(ci1, assistant.getImpressions(key1));
-        assertEquals(ci2, assistant.getImpressions(key2));
-        assertEquals(ci3, assistant.getImpressions(key3));
-    }
-
-    @Test
-    public void testSettingsProviderUpdate() {
-        ContentResolver resolver = mApplication.getContentResolver();
-
-        // Set up channels
-        String key = mAssistant.getKey("pkg1", 1, "channel1");
-        ChannelImpressions ci = new ChannelImpressions();
-        for (int i = 0; i < 3; i++) {
-            ci.incrementViews();
-            if (i % 2 == 0) {
-                ci.incrementDismissals();
-            }
-        }
-
-        mAssistant.insertImpressions(key, ci);
-
-        // With default values, the blocking helper shouldn't be triggered.
-        assertEquals(false, ci.shouldTriggerBlock());
-
-        // Update settings values.
-        float newDismissToViewRatioLimit = 0f;
-        int newStreakLimit = 0;
-        Settings.Global.putFloat(resolver,
-                Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
-                newDismissToViewRatioLimit);
-        Settings.Global.putInt(resolver,
-                Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, newStreakLimit);
-
-        // Notify for the settings values we updated.
-        resolver.notifyChange(
-                Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT), null);
-        resolver.notifyChange(
-                Settings.Global.getUriFor(
-                        Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT),
-                null);
-
-        // With the new threshold, the blocking helper should be triggered.
-        assertEquals(true, ci.shouldTriggerBlock());
-    }
-}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java
deleted file mode 100644
index 3253802..0000000
--- a/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * Copyright (C) 2017 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.ext.services.notification;
-
-import static android.ext.services.notification.ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT;
-import static android.ext.services.notification.ChannelImpressions.DEFAULT_STREAK_LIMIT;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-public class ChannelImpressionsTest {
-
-    @Test
-    public void testNoResultNoBlock() {
-        ChannelImpressions ci = new ChannelImpressions();
-        assertFalse(ci.shouldTriggerBlock());
-    }
-
-    @Test
-    public void testNoStreakNoBlock() {
-        ChannelImpressions ci = new ChannelImpressions();
-
-        for (int i = 0; i < DEFAULT_STREAK_LIMIT - 1; i++) {
-            ci.incrementViews();
-            ci.incrementDismissals();
-        }
-
-        assertFalse(ci.shouldTriggerBlock());
-    }
-
-    @Test
-    public void testNoStreakNoBlock_breakStreak() {
-        ChannelImpressions ci = new ChannelImpressions();
-
-        for (int i = 0; i < DEFAULT_STREAK_LIMIT; i++) {
-            ci.incrementViews();
-            ci.incrementDismissals();
-            if (i == DEFAULT_STREAK_LIMIT - 1) {
-                ci.resetStreak();
-            }
-        }
-
-        assertFalse(ci.shouldTriggerBlock());
-    }
-
-    @Test
-    public void testStreakBlock() {
-        ChannelImpressions ci = new ChannelImpressions();
-
-        for (int i = 0; i <= DEFAULT_STREAK_LIMIT; i++) {
-            ci.incrementViews();
-            ci.incrementDismissals();
-        }
-
-        assertTrue(ci.shouldTriggerBlock());
-    }
-
-    @Test
-    public void testRatio_NoBlockEvenWithStreak() {
-        ChannelImpressions ci = new ChannelImpressions();
-
-        for (int i = 0; i < DEFAULT_STREAK_LIMIT; i++) {
-            ci.incrementViews();
-            ci.incrementDismissals();
-            ci.incrementViews();
-        }
-
-        assertFalse(ci.shouldTriggerBlock());
-    }
-
-    @Test
-    public void testAppend() {
-        ChannelImpressions ci = new ChannelImpressions();
-        ci.incrementViews();
-        ci.incrementDismissals();
-
-        ChannelImpressions ci2 = new ChannelImpressions();
-        ci2.incrementViews();
-        ci2.incrementDismissals();
-        ci2.incrementViews();
-
-        ci.append(ci2);
-        assertEquals(3, ci.getViews());
-        assertEquals(2, ci.getDismissals());
-        assertEquals(2, ci.getStreak());
-
-        assertEquals(2, ci2.getViews());
-        assertEquals(1, ci2.getDismissals());
-        assertEquals(1, ci2.getStreak());
-
-        // no crash
-        ci.append(null);
-    }
-
-    @Test
-    public void testUpdateThresholds_streakLimitsCorrectlyApplied() {
-        int updatedStreakLimit = DEFAULT_STREAK_LIMIT + 3;
-        ChannelImpressions ci = new ChannelImpressions();
-        ci.updateThresholds(DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT, updatedStreakLimit);
-
-        for (int i = 0; i <= updatedStreakLimit; i++) {
-            ci.incrementViews();
-            ci.incrementDismissals();
-        }
-
-        ChannelImpressions ci2 = new ChannelImpressions();
-        ci2.updateThresholds(DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT, updatedStreakLimit);
-
-        for (int i = 0; i < updatedStreakLimit; i++) {
-            ci2.incrementViews();
-            ci2.incrementDismissals();
-        }
-
-        assertTrue(ci.shouldTriggerBlock());
-        assertFalse(ci2.shouldTriggerBlock());
-    }
-
-    @Test
-    public void testUpdateThresholds_ratioLimitsCorrectlyApplied() {
-        float updatedDismissRatio = .99f;
-        ChannelImpressions ci = new ChannelImpressions();
-        ci.updateThresholds(updatedDismissRatio, DEFAULT_STREAK_LIMIT);
-
-        // N views, N-1 dismissals, which doesn't satisfy the ratio = 1 criteria.
-        for (int i = 0; i <= DEFAULT_STREAK_LIMIT; i++) {
-            ci.incrementViews();
-            if (i != DEFAULT_STREAK_LIMIT) {
-                ci.incrementDismissals();
-            }
-        }
-
-        ChannelImpressions ci2 = new ChannelImpressions();
-        ci2.updateThresholds(updatedDismissRatio, DEFAULT_STREAK_LIMIT);
-
-        for (int i = 0; i <= DEFAULT_STREAK_LIMIT; i++) {
-            ci2.incrementViews();
-            ci2.incrementDismissals();
-        }
-
-        assertFalse(ci.shouldTriggerBlock());
-        assertTrue(ci2.shouldTriggerBlock());
-    }
-}
diff --git a/packages/ExtServices/tests/src/android/ext/services/storage/CacheQuotaServiceImplTest.java b/packages/ExtServices/tests/src/android/ext/services/storage/CacheQuotaServiceImplTest.java
deleted file mode 100644
index df4738f..0000000
--- a/packages/ExtServices/tests/src/android/ext/services/storage/CacheQuotaServiceImplTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2017 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.ext.services.storage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.app.usage.CacheQuotaHint;
-import android.app.usage.UsageStats;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
-import android.test.ServiceTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-public class CacheQuotaServiceImplTest extends ServiceTestCase<CacheQuotaServiceImpl> {
-    private static final String sTestVolUuid = "uuid";
-    private static final String sSecondTestVolUuid = "otherUuid";
-
-    @Mock private Context mContext;
-    @Mock private File mFile;
-    @Mock private VolumeInfo mVolume;
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private StorageManager mStorageManager;
-
-    public CacheQuotaServiceImplTest() {
-        super(CacheQuotaServiceImpl.class);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        MockitoAnnotations.initMocks(this);
-        mContext = Mockito.spy(new ContextWrapper(getSystemContext()));
-        setContext(mContext);
-        when(mContext.getSystemService(Context.STORAGE_SERVICE)).thenReturn(mStorageManager);
-
-        when(mFile.getUsableSpace()).thenReturn(10000L);
-        when(mVolume.getPath()).thenReturn(mFile);
-        when(mStorageManager.findVolumeByUuid(sTestVolUuid)).thenReturn(mVolume);
-        when(mStorageManager.findVolumeByUuid(sSecondTestVolUuid)).thenReturn(mVolume);
-
-        Intent intent = new Intent(getContext(), CacheQuotaServiceImpl.class);
-        startService(intent);
-    }
-
-    @Test
-    public void testNoApps() {
-        CacheQuotaServiceImpl service = getService();
-        assertEquals(service.onComputeCacheQuotaHints(new ArrayList()).size(), 0);
-    }
-
-    @Test
-    public void testOneApp() throws Exception {
-        ArrayList<CacheQuotaHint> requests = new ArrayList<>();
-        CacheQuotaHint request = makeNewRequest("com.test", sTestVolUuid, 1001, 100L);
-        requests.add(request);
-
-        List<CacheQuotaHint> output = getService().onComputeCacheQuotaHints(requests);
-
-        assertThat(output).hasSize(1);
-        assertThat(output.get(0).getQuota()).isEqualTo(1500L);
-    }
-
-    @Test
-    public void testTwoAppsOneVolume() throws Exception {
-        ArrayList<CacheQuotaHint> requests = new ArrayList<>();
-        requests.add(makeNewRequest("com.test", sTestVolUuid, 1001, 100L));
-        requests.add(makeNewRequest("com.test2", sTestVolUuid, 1002, 99L));
-
-        List<CacheQuotaHint> output = getService().onComputeCacheQuotaHints(requests);
-
-        // Note that the sizes are just the cache area split up.
-        assertThat(output).hasSize(2);
-        assertThat(output.get(0).getQuota()).isEqualTo(883);
-        assertThat(output.get(1).getQuota()).isEqualTo(1500 - 883);
-    }
-
-    @Test
-    public void testTwoAppsTwoVolumes() throws Exception {
-        ArrayList<CacheQuotaHint> requests = new ArrayList<>();
-        requests.add(makeNewRequest("com.test", sTestVolUuid, 1001, 100L));
-        requests.add(makeNewRequest("com.test2", sSecondTestVolUuid, 1002, 99L));
-
-        List<CacheQuotaHint> output = getService().onComputeCacheQuotaHints(requests);
-
-        assertThat(output).hasSize(2);
-        assertThat(output.get(0).getQuota()).isEqualTo(1500);
-        assertThat(output.get(1).getQuota()).isEqualTo(1500);
-    }
-
-    @Test
-    public void testMultipleAppsPerUidIsCollated() throws Exception {
-        ArrayList<CacheQuotaHint> requests = new ArrayList<>();
-        requests.add(makeNewRequest("com.test", sTestVolUuid, 1001, 100L));
-        requests.add(makeNewRequest("com.test2", sTestVolUuid, 1001, 99L));
-
-        List<CacheQuotaHint> output = getService().onComputeCacheQuotaHints(requests);
-
-        assertThat(output).hasSize(1);
-        assertThat(output.get(0).getQuota()).isEqualTo(1500);
-    }
-
-    @Test
-    public void testTwoAppsTwoVolumesTwoUuidsShouldBESeparate() throws Exception {
-        ArrayList<CacheQuotaHint> requests = new ArrayList<>();
-        requests.add(makeNewRequest("com.test", sTestVolUuid, 1001, 100L));
-        requests.add(makeNewRequest("com.test2", sSecondTestVolUuid, 1001, 99L));
-
-        List<CacheQuotaHint> output = getService().onComputeCacheQuotaHints(requests);
-
-        assertThat(output).hasSize(2);
-        assertThat(output.get(0).getQuota()).isEqualTo(1500);
-        assertThat(output.get(1).getQuota()).isEqualTo(1500);
-    }
-
-    private CacheQuotaHint makeNewRequest(String packageName, String uuid, int uid, long foregroundTime) {
-        UsageStats stats = new UsageStats();
-        stats.mPackageName = packageName;
-        stats.mTotalTimeInForeground = foregroundTime;
-        return new CacheQuotaHint.Builder()
-                .setVolumeUuid(uuid).setUid(uid).setUsageStats(stats).setQuota(-1).build();
-    }
-}
diff --git a/packages/NetworkPermissionConfig/Android.bp b/packages/NetworkPermissionConfig/Android.bp
deleted file mode 100644
index 6e50459..0000000
--- a/packages/NetworkPermissionConfig/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// 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.
-//
-
-java_defaults {
-    name: "NetworkPermissionConfigDefaults",
-    // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
-    // a classes.dex.
-    srcs: ["src/**/*.java"],
-    platform_apis: true,
-    min_sdk_version: "28",
-    privileged: true,
-    manifest: "AndroidManifest.xml",
-}
-
-// Stub APK to define permissions for NetworkStack
-android_app {
-    name: "NetworkPermissionConfig",
-    defaults: ["NetworkPermissionConfigDefaults"],
-    certificate: "networkstack",
-}
-
-// Alternative stub APK signed with platform certificate. To use with InProcessNetworkStack.
-android_app {
-    name: "PlatformNetworkPermissionConfig",
-    defaults: ["NetworkPermissionConfigDefaults"],
-    certificate: "platform",
-    overrides: ["NetworkPermissionConfig"],
-}
diff --git a/packages/NetworkPermissionConfig/AndroidManifest.xml b/packages/NetworkPermissionConfig/AndroidManifest.xml
deleted file mode 100644
index 34f987c..0000000
--- a/packages/NetworkPermissionConfig/AndroidManifest.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * 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.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.networkstack.permissionconfig"
-    android:sharedUserId="android.uid.networkstack"
-    android:versionCode="11"
-    android:versionName="Q-initial">
-    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
-    <!--
-    This package only exists to define the below permissions, and enforce that they are only
-    granted to apps sharing the same signature.
-    Permissions defined here are intended to be used only by the NetworkStack: both
-    NetworkStack and this stub APK are to be signed with a dedicated certificate to ensure
-    that, with the below permissions being signature permissions.
-
-    This APK *must* be installed, even if the NetworkStack app is not installed, because otherwise,
-    any application will be able to define this permission and the system will give that application
-    full access to the network stack.
-     -->
-    <permission android:name="android.permission.MAINLINE_NETWORK_STACK"
-                android:protectionLevel="signature"/>
-
-    <application android:name="com.android.server.NetworkPermissionConfig"/>
-</manifest>
diff --git a/packages/NetworkPermissionConfig/OWNERS b/packages/NetworkPermissionConfig/OWNERS
deleted file mode 100644
index ceaa065..0000000
--- a/packages/NetworkPermissionConfig/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-baligh@google.com
-lorenzo@google.com
-delphij@google.com
diff --git a/packages/NetworkPermissionConfig/src/com/android/server/NetworkPermissionConfig.java b/packages/NetworkPermissionConfig/src/com/android/server/NetworkPermissionConfig.java
deleted file mode 100644
index c904e23..0000000
--- a/packages/NetworkPermissionConfig/src/com/android/server/NetworkPermissionConfig.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.app.Application;
-
-/**
- * Empty application for NetworkPermissionConfig that only exists because
- * soong builds complain if APKs have no source file.
- */
-public class NetworkPermissionConfig extends Application {
-}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
deleted file mode 100644
index 3b644e9..0000000
--- a/packages/NetworkStack/Android.bp
+++ /dev/null
@@ -1,132 +0,0 @@
-//
-// Copyright (C) 2018 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.
-//
-
-java_library {
-    name: "captiveportal-lib",
-    srcs: ["common/**/*.java"],
-    libs: [
-        "androidx.annotation_annotation",
-    ],
-    sdk_version: "system_current",
-}
-
-java_defaults {
-    name: "NetworkStackCommon",
-    sdk_version: "system_current",
-    min_sdk_version: "28",
-}
-
-// Library including the network stack, used to compile both variants of the network stack
-android_library {
-    name: "NetworkStackBase",
-    defaults: ["NetworkStackCommon"],
-    srcs: [
-        "src/**/*.java",
-        ":framework-networkstack-shared-srcs",
-        ":services-networkstack-shared-srcs",
-        ":statslog-networkstack-java-gen",
-    ],
-    static_libs: [
-        "androidx.annotation_annotation",
-        "ipmemorystore-client",
-        "netd_aidl_interface-V2-java",
-        "networkstack-aidl-interfaces-V3-java",
-        "datastallprotosnano",
-        "networkstackprotosnano",
-        "captiveportal-lib",
-    ],
-    manifest: "AndroidManifestBase.xml",
-}
-
-cc_library_shared {
-    name: "libnetworkstackutilsjni",
-    srcs: [
-        "jni/network_stack_utils_jni.cpp"
-    ],
-    sdk_version: "current",
-    shared_libs: [
-        "liblog",
-        "libnativehelper_compat_libc++",
-    ],
-
-    // We cannot use plain "libc++" here to link libc++ dynamically because it results in:
-    //   java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
-    // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't
-    // build because soong complains of:
-    //   module NetworkStack missing dependencies: libc++_shared
-    //
-    // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries
-    // we depend on do not dynamically link libc++. This is currently the case, because liblog is
-    // C-only and libnativehelper_compat_libc also uses stl: "c++_static".
-    //
-    // TODO: find a better solution for this in R.
-    stl: "c++_static",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
-}
-
-java_defaults {
-    name: "NetworkStackAppCommon",
-    defaults: ["NetworkStackCommon"],
-    privileged: true,
-    static_libs: [
-        "NetworkStackBase",
-    ],
-    jni_libs: [
-        "libnativehelper_compat_libc++",
-        "libnetworkstackutilsjni",
-    ],
-    // Resources already included in NetworkStackBase
-    resource_dirs: [],
-    jarjar_rules: "jarjar-rules-shared.txt",
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
-}
-
-// Non-updatable network stack running in the system server process for devices not using the module
-android_app {
-    name: "InProcessNetworkStack",
-    defaults: ["NetworkStackAppCommon"],
-    certificate: "platform",
-    manifest: "AndroidManifest_InProcess.xml",
-    // InProcessNetworkStack is a replacement for NetworkStack
-    overrides: ["NetworkStack"],
-    // The permission configuration *must* be included to ensure security of the device
-    required: ["PlatformNetworkPermissionConfig"],
-}
-
-// Updatable network stack packaged as an application
-android_app {
-    name: "NetworkStack",
-    defaults: ["NetworkStackAppCommon"],
-    certificate: "networkstack",
-    manifest: "AndroidManifest.xml",
-    use_embedded_native_libs: true,
-    // The permission configuration *must* be included to ensure security of the device
-    required: ["NetworkPermissionConfig"],
-}
-
-genrule {
-    name: "statslog-networkstack-java-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --module network_stack" +
-         " --javaPackage com.android.networkstack.metrics --javaClass NetworkStackStatsLog",
-    out: ["com/android/networkstack/metrics/NetworkStackStatsLog.java"],
-}
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
deleted file mode 100644
index bb838a2..0000000
--- a/packages/NetworkStack/AndroidManifest.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * 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.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.networkstack"
-          android:sharedUserId="android.uid.networkstack">
-    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
-
-    <!-- Permissions must be defined here, and not in the base manifest, as the network stack
-         running in the system server process does not need any permission, and having privileged
-         permissions added would cause crashes on startup unless they are also added to the
-         privileged permissions whitelist for that package. -->
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
-    <!-- Send latency broadcast as current user -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
-    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
-    <!-- Signature permission defined in NetworkStackStub -->
-    <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
-    <application
-        android:extractNativeLibs="false"
-        android:persistent="true">
-        <service android:name="com.android.server.NetworkStackService">
-            <intent-filter>
-                <action android:name="android.net.INetworkStackConnector"/>
-            </intent-filter>
-        </service>
-        <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
-                 android:permission="android.permission.BIND_JOB_SERVICE" >
-        </service>
-    </application>
-</manifest>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
deleted file mode 100644
index 69a4da4..0000000
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * 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.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.networkstack"
-          android:versionCode="11"
-          android:versionName="Q-initial">
-    <application
-        android:label="NetworkStack"
-        android:defaultToDeviceProtectedStorage="true"
-        android:directBootAware="true"
-        android:usesCleartextTraffic="true">
-    </application>
-</manifest>
diff --git a/packages/NetworkStack/AndroidManifest_InProcess.xml b/packages/NetworkStack/AndroidManifest_InProcess.xml
deleted file mode 100644
index 2778a2a..0000000
--- a/packages/NetworkStack/AndroidManifest_InProcess.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * 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.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.networkstack.inprocess"
-          android:sharedUserId="android.uid.system"
-          android:process="system">
-    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
-    <application>
-        <service android:name="com.android.server.NetworkStackService" android:process="system">
-            <intent-filter>
-                <action android:name="android.net.INetworkStackConnector.InProcess"/>
-            </intent-filter>
-        </service>
-        <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
-                 android:process="system"
-                 android:permission="android.permission.BIND_JOB_SERVICE" >
-        </service>
-    </application>
-</manifest>
diff --git a/packages/NetworkStack/OWNERS b/packages/NetworkStack/OWNERS
deleted file mode 100644
index 09dd8f8..0000000
--- a/packages/NetworkStack/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-lorenzo@google.com
-reminv@google.com
-baligh@google.com
-delphij@google.com
diff --git a/packages/NetworkStack/TEST_MAPPING b/packages/NetworkStack/TEST_MAPPING
deleted file mode 100644
index fe9731fe..0000000
--- a/packages/NetworkStack/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "NetworkStackTests"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/packages/NetworkStack/common/CaptivePortalProbeResult.java b/packages/NetworkStack/common/CaptivePortalProbeResult.java
deleted file mode 100644
index 48cd48b..0000000
--- a/packages/NetworkStack/common/CaptivePortalProbeResult.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 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.captiveportal;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Result of calling isCaptivePortal().
- * @hide
- */
-public final class CaptivePortalProbeResult {
-    public static final int SUCCESS_CODE = 204;
-    public static final int FAILED_CODE = 599;
-    public static final int PORTAL_CODE = 302;
-    // Set partial connectivity http response code to -1 to prevent conflict with the other http
-    // response codes. Besides the default http response code of probe result is set as 599 in
-    // NetworkMonitor#sendParallelHttpProbes(), so response code will be set as -1 only when
-    // NetworkMonitor detects partial connectivity.
-    /**
-     * @hide
-     */
-    public static final int PARTIAL_CODE = -1;
-
-    @NonNull
-    public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE);
-    @NonNull
-    public static final CaptivePortalProbeResult SUCCESS =
-            new CaptivePortalProbeResult(SUCCESS_CODE);
-    public static final CaptivePortalProbeResult PARTIAL =
-            new CaptivePortalProbeResult(PARTIAL_CODE);
-
-    private final int mHttpResponseCode;  // HTTP response code returned from Internet probe.
-    @Nullable
-    public final String redirectUrl;      // Redirect destination returned from Internet probe.
-    @Nullable
-    public final String detectUrl;        // URL where a 204 response code indicates
-                                          // captive portal has been appeased.
-    @Nullable
-    public final CaptivePortalProbeSpec probeSpec;
-
-    public CaptivePortalProbeResult(int httpResponseCode) {
-        this(httpResponseCode, null, null);
-    }
-
-    public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
-            @Nullable String detectUrl) {
-        this(httpResponseCode, redirectUrl, detectUrl, null);
-    }
-
-    public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
-            @Nullable String detectUrl, @Nullable CaptivePortalProbeSpec probeSpec) {
-        mHttpResponseCode = httpResponseCode;
-        this.redirectUrl = redirectUrl;
-        this.detectUrl = detectUrl;
-        this.probeSpec = probeSpec;
-    }
-
-    public boolean isSuccessful() {
-        return mHttpResponseCode == SUCCESS_CODE;
-    }
-
-    public boolean isPortal() {
-        return !isSuccessful() && (mHttpResponseCode >= 200) && (mHttpResponseCode <= 399);
-    }
-
-    public boolean isFailed() {
-        return !isSuccessful() && !isPortal();
-    }
-
-    public boolean isPartialConnectivity() {
-        return mHttpResponseCode == PARTIAL_CODE;
-    }
-}
diff --git a/packages/NetworkStack/common/CaptivePortalProbeSpec.java b/packages/NetworkStack/common/CaptivePortalProbeSpec.java
deleted file mode 100644
index bf983a5..0000000
--- a/packages/NetworkStack/common/CaptivePortalProbeSpec.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2018 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.captiveportal;
-
-import static android.net.captiveportal.CaptivePortalProbeResult.PORTAL_CODE;
-import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-/** @hide */
-public abstract class CaptivePortalProbeSpec {
-    private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName();
-    private static final String REGEX_SEPARATOR = "@@/@@";
-    private static final String SPEC_SEPARATOR = "@@,@@";
-
-    private final String mEncodedSpec;
-    private final URL mUrl;
-
-    CaptivePortalProbeSpec(@NonNull String encodedSpec, @NonNull URL url) {
-        mEncodedSpec = checkNotNull(encodedSpec);
-        mUrl = checkNotNull(url);
-    }
-
-    /**
-     * Parse a {@link CaptivePortalProbeSpec} from a {@link String}.
-     *
-     * <p>The valid format is a URL followed by two regular expressions, each separated by "@@/@@".
-     * @throws MalformedURLException The URL has invalid format for {@link URL#URL(String)}.
-     * @throws ParseException The string is empty, does not match the above format, or a regular
-     * expression is invalid for {@link Pattern#compile(String)}.
-     * @hide
-     */
-    @VisibleForTesting
-    @NonNull
-    public static CaptivePortalProbeSpec parseSpec(@NonNull String spec) throws ParseException,
-            MalformedURLException {
-        if (TextUtils.isEmpty(spec)) {
-            throw new ParseException("Empty probe spec", 0 /* errorOffset */);
-        }
-
-        String[] splits = TextUtils.split(spec, REGEX_SEPARATOR);
-        if (splits.length != 3) {
-            throw new ParseException("Probe spec does not have 3 parts", 0 /* errorOffset */);
-        }
-
-        final int statusRegexPos = splits[0].length() + REGEX_SEPARATOR.length();
-        final int locationRegexPos = statusRegexPos + splits[1].length() + REGEX_SEPARATOR.length();
-        final Pattern statusRegex = parsePatternIfNonEmpty(splits[1], statusRegexPos);
-        final Pattern locationRegex = parsePatternIfNonEmpty(splits[2], locationRegexPos);
-
-        return new RegexMatchProbeSpec(spec, new URL(splits[0]), statusRegex, locationRegex);
-    }
-
-    @Nullable
-    private static Pattern parsePatternIfNonEmpty(@Nullable String pattern, int pos)
-            throws ParseException {
-        if (TextUtils.isEmpty(pattern)) {
-            return null;
-        }
-        try {
-            return Pattern.compile(pattern);
-        } catch (PatternSyntaxException e) {
-            throw new ParseException(
-                    String.format("Invalid status pattern [%s]: %s", pattern, e),
-                    pos /* errorOffset */);
-        }
-    }
-
-    /**
-     * Parse a {@link CaptivePortalProbeSpec} from a {@link String}, or return a fallback spec
-     * based on the status code of the provided URL if the spec cannot be parsed.
-     */
-    @Nullable
-    public static CaptivePortalProbeSpec parseSpecOrNull(@Nullable String spec) {
-        if (spec != null) {
-            try {
-                return parseSpec(spec);
-            } catch (ParseException | MalformedURLException e) {
-                Log.e(TAG, "Invalid probe spec: " + spec, e);
-                // Fall through
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Parse a config String to build an array of {@link CaptivePortalProbeSpec}.
-     *
-     * <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}.
-     * <p>This method does not throw but ignores any entry that could not be parsed.
-     */
-    @NonNull
-    public static Collection<CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(
-            @NonNull String settingsVal) {
-        List<CaptivePortalProbeSpec> specs = new ArrayList<>();
-        if (settingsVal != null) {
-            for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
-                try {
-                    specs.add(parseSpec(spec));
-                } catch (ParseException | MalformedURLException e) {
-                    Log.e(TAG, "Invalid probe spec: " + spec, e);
-                }
-            }
-        }
-
-        if (specs.isEmpty()) {
-            Log.e(TAG, String.format("could not create any validation spec from %s", settingsVal));
-        }
-        return specs;
-    }
-
-    /**
-     * Get the probe result from HTTP status and location header.
-     */
-    @NonNull
-    public abstract CaptivePortalProbeResult getResult(int status, @Nullable String locationHeader);
-
-    @NonNull
-    public String getEncodedSpec() {
-        return mEncodedSpec;
-    }
-
-    @NonNull
-    public URL getUrl() {
-        return mUrl;
-    }
-
-    /**
-     * Implementation of {@link CaptivePortalProbeSpec} that is based on configurable regular
-     * expressions for the HTTP status code and location header (if any). Matches indicate that
-     * the page is not a portal.
-     * This probe cannot fail: it always returns SUCCESS_CODE or PORTAL_CODE
-     */
-    private static class RegexMatchProbeSpec extends CaptivePortalProbeSpec {
-        @Nullable
-        final Pattern mStatusRegex;
-        @Nullable
-        final Pattern mLocationHeaderRegex;
-
-        RegexMatchProbeSpec(
-                String spec, URL url, Pattern statusRegex, Pattern locationHeaderRegex) {
-            super(spec, url);
-            mStatusRegex = statusRegex;
-            mLocationHeaderRegex = locationHeaderRegex;
-        }
-
-        @Override
-        public CaptivePortalProbeResult getResult(int status, String locationHeader) {
-            final boolean statusMatch = safeMatch(String.valueOf(status), mStatusRegex);
-            final boolean locationMatch = safeMatch(locationHeader, mLocationHeaderRegex);
-            final int returnCode = statusMatch && locationMatch ? SUCCESS_CODE : PORTAL_CODE;
-            return new CaptivePortalProbeResult(
-                    returnCode, locationHeader, getUrl().toString(), this);
-        }
-    }
-
-    private static boolean safeMatch(@Nullable String value, @Nullable Pattern pattern) {
-        // No value is a match ("no location header" passes the location rule for non-redirects)
-        return pattern == null || TextUtils.isEmpty(value) || pattern.matcher(value).matches();
-    }
-
-    // Throws NullPointerException if the input is null.
-    private static <T> T checkNotNull(T object) {
-        if (object == null) throw new NullPointerException();
-        return object;
-    }
-}
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
deleted file mode 100644
index 7346b1a..0000000
--- a/packages/NetworkStack/jarjar-rules-shared.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-rule com.android.internal.util.** android.net.networkstack.util.@1
-
-rule android.net.shared.Inet4AddressUtils* android.net.networkstack.shared.Inet4AddressUtils@1
-rule android.net.shared.InetAddressUtils* android.net.networkstack.shared.InetAddressUtils@1
-
-# Ignore DhcpResultsParcelable, but jarjar DhcpResults
-# TODO: move DhcpResults into services.net and delete from here
-rule android.net.DhcpResultsParcelable* @0
-rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
-rule android.net.LocalLog* android.net.networkstack.LocalLog@1
diff --git a/packages/NetworkStack/jni/network_stack_utils_jni.cpp b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
deleted file mode 100644
index f2ba575..0000000
--- a/packages/NetworkStack/jni/network_stack_utils_jni.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "NetworkStackUtils-JNI"
-
-#include <errno.h>
-#include <jni.h>
-#include <linux/filter.h>
-#include <linux/if_arp.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <netinet/icmp6.h>
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/udp.h>
-#include <stdlib.h>
-
-#include <string>
-
-#include <nativehelper/JNIHelp.h>
-#include <android/log.h>
-
-namespace android {
-constexpr const char NETWORKSTACKUTILS_PKG_NAME[] = "android/net/util/NetworkStackUtils";
-
-static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type);
-static const uint32_t kEtherHeaderLen = sizeof(ether_header);
-static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol);
-static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off);
-static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt);
-static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr);
-static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
-static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source);
-static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
-static const uint16_t kDhcpClientPort = 68;
-
-static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst) {
-    if (env->GetArrayLength(addr) != len) {
-        return false;
-    }
-    env->GetByteArrayRegion(addr, 0, len, reinterpret_cast<jbyte*>(dst));
-    return true;
-}
-
-static void network_stack_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr,
-        jbyteArray ipv4Addr, jstring ifname, jobject javaFd) {
-    arpreq req = {};
-    sockaddr_in& netAddrStruct = *reinterpret_cast<sockaddr_in*>(&req.arp_pa);
-    sockaddr& ethAddrStruct = req.arp_ha;
-
-    ethAddrStruct.sa_family = ARPHRD_ETHER;
-    if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) {
-        jniThrowException(env, "java/io/IOException", "Invalid ethAddr length");
-        return;
-    }
-
-    netAddrStruct.sin_family = AF_INET;
-    if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) {
-        jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length");
-        return;
-    }
-
-    int ifLen = env->GetStringLength(ifname);
-    // IFNAMSIZ includes the terminating NULL character
-    if (ifLen >= IFNAMSIZ) {
-        jniThrowException(env, "java/io/IOException", "ifname too long");
-        return;
-    }
-    env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev);
-
-    req.arp_flags = ATF_COM;  // Completed entry (ha valid)
-    int fd = jniGetFDFromFileDescriptor(env, javaFd);
-    if (fd < 0) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
-        return;
-    }
-    // See also: man 7 arp
-    if (ioctl(fd, SIOCSARP, &req)) {
-        jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno));
-        return;
-    }
-}
-
-static void network_stack_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd) {
-    static sock_filter filter_code[] = {
-        // Check the protocol is UDP.
-        BPF_STMT(BPF_LD  | BPF_B    | BPF_ABS, kIPv4Protocol),
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   IPPROTO_UDP, 0, 6),
-
-        // Check this is not a fragment.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_ABS, kIPv4FlagsOffset),
-        BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K,   IP_OFFMASK, 4, 0),
-
-        // Get the IP header length.
-        BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, kEtherHeaderLen),
-
-        // Check the destination port.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, kUDPDstPortIndirectOffset),
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   kDhcpClientPort, 0, 1),
-
-        // Accept or reject.
-        BPF_STMT(BPF_RET | BPF_K,              0xffff),
-        BPF_STMT(BPF_RET | BPF_K,              0)
-    };
-    static const sock_fprog filter = {
-        sizeof(filter_code) / sizeof(filter_code[0]),
-        filter_code,
-    };
-
-    int fd = jniGetFDFromFileDescriptor(env, javaFd);
-    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
-    }
-}
-
-static void network_stack_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
-        jint hardwareAddressType) {
-    if (hardwareAddressType != ARPHRD_ETHER) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "attachRaFilter only supports ARPHRD_ETHER");
-        return;
-    }
-
-    static sock_filter filter_code[] = {
-        // Check IPv6 Next Header is ICMPv6.
-        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kIPv6NextHeader),
-        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_ICMPV6, 0, 3),
-
-        // Check ICMPv6 type is Router Advertisement.
-        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kICMPv6TypeOffset),
-        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    ND_ROUTER_ADVERT, 0, 1),
-
-        // Accept or reject.
-        BPF_STMT(BPF_RET | BPF_K,              0xffff),
-        BPF_STMT(BPF_RET | BPF_K,              0)
-    };
-    static const sock_fprog filter = {
-        sizeof(filter_code) / sizeof(filter_code[0]),
-        filter_code,
-    };
-
-    int fd = jniGetFDFromFileDescriptor(env, javaFd);
-    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
-    }
-}
-
-// TODO: Move all this filter code into libnetutils.
-static void network_stack_utils_attachControlPacketFilter(
-        JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) {
-    if (hardwareAddressType != ARPHRD_ETHER) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "attachControlPacketFilter only supports ARPHRD_ETHER");
-        return;
-    }
-
-    // Capture all:
-    //     - ARPs
-    //     - DHCPv4 packets
-    //     - Router Advertisements & Solicitations
-    //     - Neighbor Advertisements & Solicitations
-    //
-    // tcpdump:
-    //     arp or
-    //     '(ip and udp port 68)' or
-    //     '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)'
-    static sock_filter filter_code[] = {
-        // Load the link layer next payload field.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_ABS,  kEtherTypeOffset),
-
-        // Accept all ARP.
-        // TODO: Figure out how to better filter ARPs on noisy networks.
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   ETHERTYPE_ARP, 16, 0),
-
-        // If IPv4:
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   ETHERTYPE_IP, 0, 9),
-
-        // Check the protocol is UDP.
-        BPF_STMT(BPF_LD  | BPF_B    | BPF_ABS, kIPv4Protocol),
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   IPPROTO_UDP, 0, 14),
-
-        // Check this is not a fragment.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_ABS, kIPv4FlagsOffset),
-        BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K,   IP_OFFMASK, 12, 0),
-
-        // Get the IP header length.
-        BPF_STMT(BPF_LDX | BPF_B    | BPF_MSH, kEtherHeaderLen),
-
-        // Check the source port.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, kUDPSrcPortIndirectOffset),
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   kDhcpClientPort, 8, 0),
-
-        // Check the destination port.
-        BPF_STMT(BPF_LD  | BPF_H    | BPF_IND, kUDPDstPortIndirectOffset),
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   kDhcpClientPort, 6, 7),
-
-        // IPv6 ...
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   ETHERTYPE_IPV6, 0, 6),
-        // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ...
-        BPF_STMT(BPF_LD  | BPF_B    | BPF_ABS, kIPv6NextHeader),
-        BPF_JUMP(BPF_JMP | BPF_JEQ  | BPF_K,   IPPROTO_ICMPV6, 0, 4),
-        // ... and check the ICMPv6 type is one of RS/RA/NS/NA.
-        BPF_STMT(BPF_LD  | BPF_B    | BPF_ABS, kICMPv6TypeOffset),
-        BPF_JUMP(BPF_JMP | BPF_JGE  | BPF_K,   ND_ROUTER_SOLICIT, 0, 2),
-        BPF_JUMP(BPF_JMP | BPF_JGT  | BPF_K,   ND_NEIGHBOR_ADVERT, 1, 0),
-
-        // Accept or reject.
-        BPF_STMT(BPF_RET | BPF_K,              0xffff),
-        BPF_STMT(BPF_RET | BPF_K,              0)
-    };
-    static const sock_fprog filter = {
-        sizeof(filter_code) / sizeof(filter_code[0]),
-        filter_code,
-    };
-
-    int fd = jniGetFDFromFileDescriptor(env, javaFd);
-    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
-        jniThrowExceptionFmt(env, "java/net/SocketException",
-                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
-    }
-}
-
-/*
- * JNI registration.
- */
-static const JNINativeMethod gNetworkStackUtilsMethods[] = {
-    /* name, signature, funcPtr */
-    { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) network_stack_utils_addArpEntry },
-    { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) network_stack_utils_attachDhcpFilter },
-    { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) network_stack_utils_attachRaFilter },
-    { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) network_stack_utils_attachControlPacketFilter },
-};
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
-    JNIEnv *env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
-        return JNI_ERR;
-    }
-
-    if (jniRegisterNativeMethods(env, NETWORKSTACKUTILS_PKG_NAME,
-            gNetworkStackUtilsMethods, NELEM(gNetworkStackUtilsMethods)) < 0) {
-        return JNI_ERR;
-    }
-
-    return JNI_VERSION_1_6;
-
-}
-}; // namespace android
diff --git a/packages/NetworkStack/proguard.flags b/packages/NetworkStack/proguard.flags
deleted file mode 100644
index c60f6c3..0000000
--- a/packages/NetworkStack/proguard.flags
+++ /dev/null
@@ -1,9 +0,0 @@
--keepclassmembers class android.net.ip.IpClient {
-    static final int CMD_*;
-    static final int EVENT_*;
-}
-
--keepclassmembers class android.net.dhcp.DhcpClient {
-    static final int CMD_*;
-    static final int EVENT_*;
-}
diff --git a/packages/NetworkStack/res/values-mcc460/config.xml b/packages/NetworkStack/res/values-mcc460/config.xml
deleted file mode 100644
index fd4a848..0000000
--- a/packages/NetworkStack/res/values-mcc460/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <!-- Network validation URL configuration for devices using a Chinese SIM (MCC 460).
-         The below URLs are often whitelisted by captive portals, so they should not be used in the
-         general case as this could degrade the user experience (portals not detected properly).
-         However in China the default URLs are not accessible in general. The below alternatives
-         should allow users to connect to local networks normally. -->
-    <string name="default_captive_portal_https_url" translatable="false">https://connectivitycheck.gstatic.com/generate_204</string>
-    <string-array name="default_captive_portal_fallback_urls" translatable="false">
-        <item>http://www.googleapis.cn/generate_204</item>
-    </string-array>
-</resources>
diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml
deleted file mode 100644
index 478ed6b..0000000
--- a/packages/NetworkStack/res/values/config.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <!--
-    OEMs that wish to change the below settings must do so via a runtime resource overlay package
-    and *NOT* by changing this file. This file is part of the NetworkStack mainline module.
-    The overlays must apply to the config_* values, not the default_* values. The default_*
-    values are meant to be the default when no other configuration is specified.
-    -->
-
-    <!-- DNS probe timeout for network validation. Enough for 3 DNS queries 5 seconds apart. -->
-    <integer name="default_captive_portal_dns_probe_timeout">12500</integer>
-
-    <!-- HTTP URL for network validation, to use for detecting captive portals. -->
-    <string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
-
-    <!-- HTTPS URL for network validation, to use for confirming internet connectivity. -->
-    <string name="default_captive_portal_https_url" translatable="false">https://www.google.com/generate_204</string>
-
-    <!-- List of fallback URLs to use for detecting captive portals. -->
-    <string-array name="default_captive_portal_fallback_urls" translatable="false">
-        <item>http://www.google.com/gen_204</item>
-        <item>http://play.googleapis.com/generate_204</item>
-    </string-array>
-
-    <!-- List of fallback probe specs to use for detecting captive portals.
-         This is an alternative to fallback URLs that provides more flexibility on detection rules.
-         Empty, so unused by default. -->
-    <string-array name="default_captive_portal_fallback_probe_specs" translatable="false">
-    </string-array>
-
-    <!-- Configuration hooks for the above settings.
-         Empty by default but may be overridden by RROs. -->
-    <integer name="config_captive_portal_dns_probe_timeout"></integer>
-    <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
-    <string name="config_captive_portal_http_url" translatable="false"></string>
-    <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
-    <string name="config_captive_portal_https_url" translatable="false"></string>
-    <string-array name="config_captive_portal_fallback_urls" translatable="false">
-    </string-array>
-    <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
-    </string-array>
-
-    <!-- Customized default DNS Servers address. -->
-    <string-array name="config_default_dns_servers" translatable="false">
-    </string-array>
-</resources>
diff --git a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
deleted file mode 100644
index 41715b2..0000000
--- a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 android.annotation.NonNull;
-import android.content.Context;
-
-import java.util.concurrent.ExecutionException;
-import java.util.function.Consumer;
-
-/**
- * service used to communicate with the ip memory store service in network stack,
- * which is running in the same module.
- * @see com.android.server.connectivity.ipmemorystore.IpMemoryStoreService
- * @hide
- */
-public class NetworkStackIpMemoryStore extends IpMemoryStoreClient {
-    @NonNull private final IIpMemoryStore mService;
-
-    public NetworkStackIpMemoryStore(@NonNull final Context context,
-            @NonNull final IIpMemoryStore service) {
-        super(context);
-        mService = service;
-    }
-
-    @Override
-    protected void runWhenServiceReady(Consumer<IIpMemoryStore> cb) throws ExecutionException {
-        cb.accept(mService);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
deleted file mode 100644
index f054319..0000000
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ /dev/null
@@ -1,1981 +0,0 @@
-/*
- * Copyright (C) 2016 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.apf;
-
-import static android.net.util.SocketUtils.makePacketSocketAddress;
-import static android.system.OsConstants.AF_PACKET;
-import static android.system.OsConstants.ARPHRD_ETHER;
-import static android.system.OsConstants.ETH_P_ARP;
-import static android.system.OsConstants.ETH_P_IP;
-import static android.system.OsConstants.ETH_P_IPV6;
-import static android.system.OsConstants.IPPROTO_ICMPV6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_RAW;
-
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
-
-import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NattKeepalivePacketDataParcelable;
-import android.net.TcpKeepalivePacketDataParcelable;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IpClient.IpClientCallbacksWrapper;
-import android.net.metrics.ApfProgramEvent;
-import android.net.metrics.ApfStats;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.RaEvent;
-import android.net.util.InterfaceParams;
-import android.net.util.NetworkStackUtils;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.HexDump;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * For networks that support packet filtering via APF programs, {@code ApfFilter}
- * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
- * filter out redundant duplicate ones.
- *
- * Threading model:
- * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
- * know what RAs to filter for, thus generating APF programs is dependent on mRas.
- * mRas can be accessed by multiple threads:
- * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
- * - callers of:
- *    - setMulticastFilter(), which can cause an APF program to be generated.
- *    - dump(), which dumps mRas among other things.
- *    - shutdown(), which clears mRas.
- * So access to mRas is synchronized.
- *
- * @hide
- */
-public class ApfFilter {
-
-    // Helper class for specifying functional filter parameters.
-    public static class ApfConfiguration {
-        public ApfCapabilities apfCapabilities;
-        public boolean multicastFilter;
-        public boolean ieee802_3Filter;
-        public int[] ethTypeBlackList;
-    }
-
-    // Enums describing the outcome of receiving an RA packet.
-    private static enum ProcessRaResult {
-        MATCH,          // Received RA matched a known RA
-        DROPPED,        // Received RA ignored due to MAX_RAS
-        PARSE_ERROR,    // Received RA could not be parsed
-        ZERO_LIFETIME,  // Received RA had 0 lifetime
-        UPDATE_NEW_RA,  // APF program updated for new RA
-        UPDATE_EXPIRY   // APF program updated for expiry
-    }
-
-    /**
-     * APF packet counters.
-     *
-     * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
-     * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
-     * the last writable 32bit word.
-     */
-    @VisibleForTesting
-    public static enum Counter {
-        RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
-        TOTAL_PACKETS,
-        PASSED_ARP,
-        PASSED_DHCP,
-        PASSED_IPV4,
-        PASSED_IPV6_NON_ICMP,
-        PASSED_IPV4_UNICAST,
-        PASSED_IPV6_ICMP,
-        PASSED_IPV6_UNICAST_NON_ICMP,
-        PASSED_ARP_NON_IPV4,
-        PASSED_ARP_UNKNOWN,
-        PASSED_ARP_UNICAST_REPLY,
-        PASSED_NON_IP_UNICAST,
-        DROPPED_ETH_BROADCAST,
-        DROPPED_RA,
-        DROPPED_GARP_REPLY,
-        DROPPED_ARP_OTHER_HOST,
-        DROPPED_IPV4_L2_BROADCAST,
-        DROPPED_IPV4_BROADCAST_ADDR,
-        DROPPED_IPV4_BROADCAST_NET,
-        DROPPED_IPV4_MULTICAST,
-        DROPPED_IPV6_ROUTER_SOLICITATION,
-        DROPPED_IPV6_MULTICAST_NA,
-        DROPPED_IPV6_MULTICAST,
-        DROPPED_IPV6_MULTICAST_PING,
-        DROPPED_IPV6_NON_ICMP_MULTICAST,
-        DROPPED_802_3_FRAME,
-        DROPPED_ETHERTYPE_BLACKLISTED,
-        DROPPED_ARP_REPLY_SPA_NO_HOST,
-        DROPPED_IPV4_KEEPALIVE_ACK,
-        DROPPED_IPV6_KEEPALIVE_ACK,
-        DROPPED_IPV4_NATT_KEEPALIVE;
-
-        // Returns the negative byte offset from the end of the APF data segment for
-        // a given counter.
-        public int offset() {
-            return - this.ordinal() * 4;  // Currently, all counters are 32bit long.
-        }
-
-        // Returns the total size of the data segment in bytes.
-        public static int totalSize() {
-            return (Counter.class.getEnumConstants().length - 1) * 4;
-        }
-    }
-
-    /**
-     * When APFv4 is supported, loads R1 with the offset of the specified counter.
-     */
-    private void maybeSetupCounter(ApfGenerator gen, Counter c) {
-        if (mApfCapabilities.hasDataAccess()) {
-            gen.addLoadImmediate(Register.R1, c.offset());
-        }
-    }
-
-    // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
-    // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
-    private final String mCountAndPassLabel;
-    private final String mCountAndDropLabel;
-
-    // Thread to listen for RAs.
-    @VisibleForTesting
-    class ReceiveThread extends Thread {
-        private final byte[] mPacket = new byte[1514];
-        private final FileDescriptor mSocket;
-        private final long mStart = SystemClock.elapsedRealtime();
-
-        private int mReceivedRas = 0;
-        private int mMatchingRas = 0;
-        private int mDroppedRas = 0;
-        private int mParseErrors = 0;
-        private int mZeroLifetimeRas = 0;
-        private int mProgramUpdates = 0;
-
-        private volatile boolean mStopped;
-
-        public ReceiveThread(FileDescriptor socket) {
-            mSocket = socket;
-        }
-
-        public void halt() {
-            mStopped = true;
-            // Interrupts the read() call the thread is blocked in.
-            NetworkStackUtils.closeSocketQuietly(mSocket);
-        }
-
-        @Override
-        public void run() {
-            log("begin monitoring");
-            while (!mStopped) {
-                try {
-                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
-                    updateStats(processRa(mPacket, length));
-                } catch (IOException|ErrnoException e) {
-                    if (!mStopped) {
-                        Log.e(TAG, "Read error", e);
-                    }
-                }
-            }
-            logStats();
-        }
-
-        private void updateStats(ProcessRaResult result) {
-            mReceivedRas++;
-            switch(result) {
-                case MATCH:
-                    mMatchingRas++;
-                    return;
-                case DROPPED:
-                    mDroppedRas++;
-                    return;
-                case PARSE_ERROR:
-                    mParseErrors++;
-                    return;
-                case ZERO_LIFETIME:
-                    mZeroLifetimeRas++;
-                    return;
-                case UPDATE_EXPIRY:
-                    mMatchingRas++;
-                    mProgramUpdates++;
-                    return;
-                case UPDATE_NEW_RA:
-                    mProgramUpdates++;
-                    return;
-            }
-        }
-
-        private void logStats() {
-            final long nowMs = SystemClock.elapsedRealtime();
-            synchronized (this) {
-                final ApfStats stats = new ApfStats.Builder()
-                        .setReceivedRas(mReceivedRas)
-                        .setMatchingRas(mMatchingRas)
-                        .setDroppedRas(mDroppedRas)
-                        .setParseErrors(mParseErrors)
-                        .setZeroLifetimeRas(mZeroLifetimeRas)
-                        .setProgramUpdates(mProgramUpdates)
-                        .setDurationMs(nowMs - mStart)
-                        .setMaxProgramSize(mApfCapabilities.maximumApfProgramSize)
-                        .setProgramUpdatesAll(mNumProgramUpdates)
-                        .setProgramUpdatesAllowingMulticast(mNumProgramUpdatesAllowingMulticast)
-                        .build();
-                mMetricsLog.log(stats);
-                logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
-            }
-        }
-    }
-
-    private static final String TAG = "ApfFilter";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
-    private static final int ETH_HEADER_LEN = 14;
-    private static final int ETH_DEST_ADDR_OFFSET = 0;
-    private static final int ETH_ETHERTYPE_OFFSET = 12;
-    private static final int ETH_TYPE_MIN = 0x0600;
-    private static final int ETH_TYPE_MAX = 0xFFFF;
-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
-            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
-    private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
-    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
-    // Endianness is not an issue for this constant because the APF interpreter always operates in
-    // network byte order.
-    private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
-    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
-    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
-    private static final int IPV4_ANY_HOST_ADDRESS = 0;
-    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
-    private static final int IPV4_HEADER_LEN = 20; // Without options
-
-    // Traffic class and Flow label are not byte aligned. Luckily we
-    // don't care about either value so we'll consider bytes 1-3 of the
-    // IPv6 header as don't care.
-    private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
-    private static final int IPV6_FLOW_LABEL_LEN = 3;
-    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
-    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
-    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
-    private static final int IPV6_HEADER_LEN = 40;
-    // The IPv6 all nodes address ff02::1
-    private static final byte[] IPV6_ALL_NODES_ADDRESS =
-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-
-    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-
-    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
-    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
-    private static final int UDP_HEADER_LEN = 8;
-
-    private static final int TCP_HEADER_SIZE_OFFSET = 12;
-
-    private static final int DHCP_CLIENT_PORT = 68;
-    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
-    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
-
-    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
-    private static final byte[] ARP_IPV4_HEADER = {
-            0, 1, // Hardware type: Ethernet (1)
-            8, 0, // Protocol type: IP (0x0800)
-            6,    // Hardware size: 6
-            4,    // Protocol size: 4
-    };
-    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
-    // Opcode: ARP request (0x0001), ARP reply (0x0002)
-    private static final short ARP_OPCODE_REQUEST = 1;
-    private static final short ARP_OPCODE_REPLY = 2;
-    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
-    // Do not log ApfProgramEvents whose actual lifetimes was less than this.
-    private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
-    // Limit on the Black List size to cap on program usage for this
-    // TODO: Select a proper max length
-    private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
-
-    private final ApfCapabilities mApfCapabilities;
-    private final IpClientCallbacksWrapper mIpClientCallback;
-    private final InterfaceParams mInterfaceParams;
-    private final IpConnectivityLog mMetricsLog;
-
-    @VisibleForTesting
-    byte[] mHardwareAddress;
-    @VisibleForTesting
-    ReceiveThread mReceiveThread;
-    @GuardedBy("this")
-    private long mUniqueCounter;
-    @GuardedBy("this")
-    private boolean mMulticastFilter;
-    @GuardedBy("this")
-    private boolean mInDozeMode;
-    private final boolean mDrop802_3Frames;
-    private final int[] mEthTypeBlackList;
-
-    // Detects doze mode state transitions.
-    private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
-                PowerManager powerManager =
-                        (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-                final boolean deviceIdle = powerManager.isDeviceIdleMode();
-                setDozeMode(deviceIdle);
-            }
-        }
-    };
-    private final Context mContext;
-
-    // Our IPv4 address, if we have just one, otherwise null.
-    @GuardedBy("this")
-    private byte[] mIPv4Address;
-    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
-    @GuardedBy("this")
-    private int mIPv4PrefixLength;
-
-    @VisibleForTesting
-    ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
-            IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) {
-        mApfCapabilities = config.apfCapabilities;
-        mIpClientCallback = ipClientCallback;
-        mInterfaceParams = ifParams;
-        mMulticastFilter = config.multicastFilter;
-        mDrop802_3Frames = config.ieee802_3Filter;
-        mContext = context;
-
-        if (mApfCapabilities.hasDataAccess()) {
-            mCountAndPassLabel = "countAndPass";
-            mCountAndDropLabel = "countAndDrop";
-        } else {
-            // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
-            // preserving the original pre-APFv4 behavior.
-            mCountAndPassLabel = ApfGenerator.PASS_LABEL;
-            mCountAndDropLabel = ApfGenerator.DROP_LABEL;
-        }
-
-        // Now fill the black list from the passed array
-        mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
-
-        mMetricsLog = log;
-
-        // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
-        maybeStartFilter();
-
-        // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
-        mContext.registerReceiver(mDeviceIdleReceiver,
-                new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
-    }
-
-    public synchronized void setDataSnapshot(byte[] data) {
-        mDataSnapshot = data;
-    }
-
-    private void log(String s) {
-        Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
-    }
-
-    @GuardedBy("this")
-    private long getUniqueNumberLocked() {
-        return mUniqueCounter++;
-    }
-
-    @GuardedBy("this")
-    private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
-        ArrayList<Integer> bl = new ArrayList<Integer>();
-
-        for (int p : ethTypeBlackList) {
-            // Check if the protocol is a valid ether type
-            if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
-                continue;
-            }
-
-            // Check if the protocol is not repeated in the passed array
-            if (bl.contains(p)) {
-                continue;
-            }
-
-            // Check if list reach its max size
-            if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
-                Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
-                        ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
-                break;
-            }
-
-            // Now add the protocol to the list
-            bl.add(p);
-        }
-
-        return bl.stream().mapToInt(Integer::intValue).toArray();
-    }
-
-    /**
-     * Attempt to start listening for RAs and, if RAs are received, generating and installing
-     * filters to ignore useless RAs.
-     */
-    @VisibleForTesting
-    void maybeStartFilter() {
-        FileDescriptor socket;
-        try {
-            mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
-            synchronized(this) {
-                // Clear the APF memory to reset all counters upon connecting to the first AP
-                // in an SSID. This is limited to APFv4 devices because this large write triggers
-                // a crash on some older devices (b/78905546).
-                if (mApfCapabilities.hasDataAccess()) {
-                    byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
-                    mIpClientCallback.installPacketFilter(zeroes);
-                }
-
-                // Install basic filters
-                installNewProgramLocked();
-            }
-            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
-            SocketAddress addr = makePacketSocketAddress(
-                    (short) ETH_P_IPV6, mInterfaceParams.index);
-            Os.bind(socket, addr);
-            NetworkStackUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
-        } catch(SocketException|ErrnoException e) {
-            Log.e(TAG, "Error starting filter", e);
-            return;
-        }
-        mReceiveThread = new ReceiveThread(socket);
-        mReceiveThread.start();
-    }
-
-    // Returns seconds since device boot.
-    @VisibleForTesting
-    protected long currentTimeSeconds() {
-        return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
-    }
-
-    public static class InvalidRaException extends Exception {
-        public InvalidRaException(String m) {
-            super(m);
-        }
-    }
-
-    // A class to hold information about an RA.
-    @VisibleForTesting
-    class Ra {
-        // From RFC4861:
-        private static final int ICMP6_RA_HEADER_LEN = 16;
-        private static final int ICMP6_RA_CHECKSUM_OFFSET =
-                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
-        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
-        private static final int ICMP6_RA_OPTION_OFFSET =
-                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
-        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
-                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
-        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
-        // Prefix information option.
-        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
-        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
-        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
-        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
-        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
-        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
-
-        // From RFC6106: Recursive DNS Server option
-        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
-        // From RFC6106: DNS Search List option
-        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
-
-        // From RFC4191: Route Information option
-        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
-        // Above three options all have the same format:
-        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
-        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
-
-        // Note: mPacket's position() cannot be assumed to be reset.
-        private final ByteBuffer mPacket;
-        // List of binary ranges that include the whole packet except the lifetimes.
-        // Pairs consist of offset and length.
-        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
-                new ArrayList<Pair<Integer, Integer>>();
-        // Minimum lifetime in packet
-        long mMinLifetime;
-        // When the packet was last captured, in seconds since Unix Epoch
-        long mLastSeen;
-
-        // For debugging only. Offsets into the packet where PIOs are.
-        private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
-
-        // For debugging only. Offsets into the packet where RDNSS options are.
-        private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
-
-        // For debugging only. How many times this RA was seen.
-        int seenCount = 0;
-
-        // For debugging only. Returns the hex representation of the last matching packet.
-        String getLastMatchingPacket() {
-            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
-                    false /* lowercase */);
-        }
-
-        // For debugging only. Returns the string representation of the IPv6 address starting at
-        // position pos in the packet.
-        private String IPv6AddresstoString(int pos) {
-            try {
-                byte[] array = mPacket.array();
-                // Can't just call copyOfRange() and see if it throws, because if it reads past the
-                // end it pads with zeros instead of throwing.
-                if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
-                    return "???";
-                }
-                byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
-                InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
-                return address.getHostAddress();
-            } catch (UnsupportedOperationException e) {
-                // array() failed. Cannot happen, mPacket is array-backed and read-write.
-                return "???";
-            } catch (ClassCastException|UnknownHostException e) {
-                // Cannot happen.
-                return "???";
-            }
-        }
-
-        // Can't be static because it's in a non-static inner class.
-        // TODO: Make this static once RA is its own class.
-        private void prefixOptionToString(StringBuffer sb, int offset) {
-            String prefix = IPv6AddresstoString(offset + 16);
-            int length = getUint8(mPacket, offset + 2);
-            long valid = getUint32(mPacket, offset + 4);
-            long preferred = getUint32(mPacket, offset + 8);
-            sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
-        }
-
-        private void rdnssOptionToString(StringBuffer sb, int offset) {
-            int optLen = getUint8(mPacket, offset + 1) * 8;
-            if (optLen < 24) return;  // Malformed or empty.
-            long lifetime = getUint32(mPacket, offset + 4);
-            int numServers = (optLen - 8) / 16;
-            sb.append("DNS ").append(lifetime).append("s");
-            for (int server = 0; server < numServers; server++) {
-                sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
-            }
-        }
-
-        public String toString() {
-            try {
-                StringBuffer sb = new StringBuffer();
-                sb.append(String.format("RA %s -> %s %ds ",
-                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
-                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
-                        getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
-                for (int i: mPrefixOptionOffsets) {
-                    prefixOptionToString(sb, i);
-                }
-                for (int i: mRdnssOptionOffsets) {
-                    rdnssOptionToString(sb, i);
-                }
-                return sb.toString();
-            } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
-                return "<Malformed RA>";
-            }
-        }
-
-        /**
-         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
-         * Assumes mPacket.position() is as far as we've parsed the packet.
-         * @param lastNonLifetimeStart offset within packet of where the last binary range of
-         *                             data not including a lifetime.
-         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
-         * @param lifetimeLength length of the next lifetime data.
-         * @return offset within packet of where the next binary range of data not including
-         *         a lifetime. This can be passed into the next invocation of this function
-         *         via {@code lastNonLifetimeStart}.
-         */
-        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
-                int lifetimeLength) {
-            lifetimeOffset += mPacket.position();
-            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
-                    lifetimeOffset - lastNonLifetimeStart));
-            return lifetimeOffset + lifetimeLength;
-        }
-
-        private int addNonLifetimeU32(int lastNonLifetimeStart) {
-            return addNonLifetime(lastNonLifetimeStart,
-                    ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
-        }
-
-        // Note that this parses RA and may throw InvalidRaException (from
-        // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
-        // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
-        // specifications.
-        Ra(byte[] packet, int length) throws InvalidRaException {
-            if (length < ICMP6_RA_OPTION_OFFSET) {
-                throw new InvalidRaException("Not an ICMP6 router advertisement");
-            }
-
-            mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
-            mLastSeen = currentTimeSeconds();
-
-            // Sanity check packet in case a packet arrives before we attach RA filter
-            // to our packet socket. b/29586253
-            if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
-                    getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
-                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
-                throw new InvalidRaException("Not an ICMP6 router advertisement");
-            }
-
-
-            RaEvent.Builder builder = new RaEvent.Builder();
-
-            // Ignore the flow label and low 4 bits of traffic class.
-            int lastNonLifetimeStart = addNonLifetime(0,
-                    IPV6_FLOW_LABEL_OFFSET,
-                    IPV6_FLOW_LABEL_LEN);
-
-            // Ignore the checksum.
-            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                    ICMP6_RA_CHECKSUM_OFFSET,
-                    ICMP6_RA_CHECKSUM_LEN);
-
-            // Parse router lifetime
-            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
-                    ICMP6_RA_ROUTER_LIFETIME_LEN);
-            builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
-
-            // Ensures that the RA is not truncated.
-            mPacket.position(ICMP6_RA_OPTION_OFFSET);
-            while (mPacket.hasRemaining()) {
-                final int position = mPacket.position();
-                final int optionType = getUint8(mPacket, position);
-                final int optionLength = getUint8(mPacket, position + 1) * 8;
-                long lifetime;
-                switch (optionType) {
-                    case ICMP6_PREFIX_OPTION_TYPE:
-                        // Parse valid lifetime
-                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
-                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
-                        lifetime = getUint32(mPacket,
-                                position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
-                        builder.updatePrefixValidLifetime(lifetime);
-                        // Parse preferred lifetime
-                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
-                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
-                        lifetime = getUint32(mPacket,
-                                position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
-                        builder.updatePrefixPreferredLifetime(lifetime);
-                        mPrefixOptionOffsets.add(position);
-                        break;
-                    // These three options have the same lifetime offset and size, and
-                    // are processed with the same specialized addNonLifetimeU32:
-                    case ICMP6_RDNSS_OPTION_TYPE:
-                        mRdnssOptionOffsets.add(position);
-                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
-                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
-                        builder.updateRdnssLifetime(lifetime);
-                        break;
-                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
-                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
-                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
-                        builder.updateRouteInfoLifetime(lifetime);
-                        break;
-                    case ICMP6_DNSSL_OPTION_TYPE:
-                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
-                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
-                        builder.updateDnsslLifetime(lifetime);
-                        break;
-                    default:
-                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
-                        // compatibility.
-                        break;
-                }
-                if (optionLength <= 0) {
-                    throw new InvalidRaException(String.format(
-                        "Invalid option length opt=%d len=%d", optionType, optionLength));
-                }
-                mPacket.position(position + optionLength);
-            }
-            // Mark non-lifetime bytes since last lifetime.
-            addNonLifetime(lastNonLifetimeStart, 0, 0);
-            mMinLifetime = minLifetime(packet, length);
-            mMetricsLog.log(builder.build());
-        }
-
-        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
-        boolean matches(byte[] packet, int length) {
-            if (length != mPacket.capacity()) return false;
-            byte[] referencePacket = mPacket.array();
-            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
-                for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
-                    if (packet[i] != referencePacket[i]) return false;
-                }
-            }
-            return true;
-        }
-
-        // What is the minimum of all lifetimes within {@code packet} in seconds?
-        // Precondition: matches(packet, length) already returned true.
-        long minLifetime(byte[] packet, int length) {
-            long minLifetime = Long.MAX_VALUE;
-            // Wrap packet in ByteBuffer so we can read big-endian values easily
-            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
-            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
-                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
-
-                // The flow label is in mNonLifetimes, but it's not a lifetime.
-                if (offset == IPV6_FLOW_LABEL_OFFSET) {
-                    continue;
-                }
-
-                // The checksum is in mNonLifetimes, but it's not a lifetime.
-                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
-                    continue;
-                }
-
-                final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
-                final long optionLifetime;
-                switch (lifetimeLength) {
-                    case 2:
-                        optionLifetime = getUint16(byteBuffer, offset);
-                        break;
-                    case 4:
-                        optionLifetime = getUint32(byteBuffer, offset);
-                        break;
-                    default:
-                        throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
-                }
-                minLifetime = Math.min(minLifetime, optionLifetime);
-            }
-            return minLifetime;
-        }
-
-        // How many seconds does this RA's have to live, taking into account the fact
-        // that we might have seen it a while ago.
-        long currentLifetime() {
-            return mMinLifetime - (currentTimeSeconds() - mLastSeen);
-        }
-
-        boolean isExpired() {
-            // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
-            // have to calculate the filter lifetime specially as a fraction of 0 is still 0.
-            return currentLifetime() <= 0;
-        }
-
-        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
-        // Jump to the next filter if packet doesn't match this RA.
-        @GuardedBy("ApfFilter.this")
-        long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-            String nextFilterLabel = "Ra" + getUniqueNumberLocked();
-            // Skip if packet is not the right size
-            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
-            gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
-            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
-            // Skip filter if expired
-            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
-            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
-            for (int i = 0; i < mNonLifetimes.size(); i++) {
-                // Generate code to match the packet bytes
-                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
-                // Don't generate JNEBS instruction for 0 bytes as it always fails the
-                // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
-                // the number of bytes to compare. nonLifetime is zero between the
-                // valid and preferred lifetimes in the prefix option.
-                if (nonLifetime.second != 0) {
-                    gen.addLoadImmediate(Register.R0, nonLifetime.first);
-                    gen.addJumpIfBytesNotEqual(Register.R0,
-                            Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
-                                               nonLifetime.first + nonLifetime.second),
-                            nextFilterLabel);
-                }
-                // Generate code to test the lifetimes haven't gone down too far
-                if ((i + 1) < mNonLifetimes.size()) {
-                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
-                    int offset = nonLifetime.first + nonLifetime.second;
-
-                    // Skip the Flow label.
-                    if (offset == IPV6_FLOW_LABEL_OFFSET) {
-                        continue;
-                    }
-                    // Skip the checksum.
-                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
-                        continue;
-                    }
-                    int length = nextNonLifetime.first - offset;
-                    switch (length) {
-                        case 4: gen.addLoad32(Register.R0, offset); break;
-                        case 2: gen.addLoad16(Register.R0, offset); break;
-                        default: throw new IllegalStateException("bogus lifetime size " + length);
-                    }
-                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
-                }
-            }
-            maybeSetupCounter(gen, Counter.DROPPED_RA);
-            gen.addJump(mCountAndDropLabel);
-            gen.defineLabel(nextFilterLabel);
-            return filterLifetime;
-        }
-    }
-
-    // TODO: Refactor these subclasses to avoid so much repetition.
-    private abstract static class KeepalivePacket {
-        // Note that the offset starts from IP header.
-        // These must be added ether header length when generating program.
-        static final int IP_HEADER_OFFSET = 0;
-        static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
-
-        // Append a filter for this keepalive ack to {@code gen}.
-        // Jump to drop if it matches the keepalive ack.
-        // Jump to the next filter if packet doesn't match the keepalive ack.
-        abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
-    }
-
-    // A class to hold NAT-T keepalive ack information.
-    private class NattKeepaliveResponse extends KeepalivePacket {
-        static final int UDP_LENGTH_OFFSET = 4;
-        static final int UDP_HEADER_LEN = 8;
-
-        protected class NattKeepaliveResponseData {
-            public final byte[] srcAddress;
-            public final int srcPort;
-            public final byte[] dstAddress;
-            public final int dstPort;
-
-            NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
-                srcAddress = sentKeepalivePacket.dstAddress;
-                srcPort = sentKeepalivePacket.dstPort;
-                dstAddress = sentKeepalivePacket.srcAddress;
-                dstPort = sentKeepalivePacket.srcPort;
-            }
-        }
-
-        protected final NattKeepaliveResponseData mPacket;
-        protected final byte[] mSrcDstAddr;
-        protected final byte[] mPortFingerprint;
-        // NAT-T keepalive packet
-        protected final byte[] mPayload = {(byte) 0xff};
-
-        NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
-            mPacket = new NattKeepaliveResponseData(sentKeepalivePacket);
-            mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress);
-            mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
-        }
-
-        byte[] generatePortFingerprint(int srcPort, int dstPort) {
-            final ByteBuffer fp = ByteBuffer.allocate(4);
-            fp.order(ByteOrder.BIG_ENDIAN);
-            fp.putShort((short) srcPort);
-            fp.putShort((short) dstPort);
-            return fp.array();
-        }
-
-        @Override
-        void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-            final String nextFilterLabel = "natt_keepalive_filter" + getUniqueNumberLocked();
-
-            gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
-            gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
-
-            // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
-            // Check payload length is 1
-            gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addAdd(UDP_HEADER_LEN);
-            gen.addSwap();
-            gen.addLoad16(Register.R0, IPV4_TOTAL_LENGTH_OFFSET);
-            gen.addNeg(Register.R1);
-            gen.addAddR1();
-            gen.addJumpIfR0NotEquals(1, nextFilterLabel);
-
-            // Check that the ports match
-            gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addAdd(ETH_HEADER_LEN);
-            gen.addJumpIfBytesNotEqual(Register.R0, mPortFingerprint, nextFilterLabel);
-
-            // Payload offset = R0 + UDP header length
-            gen.addAdd(UDP_HEADER_LEN);
-            gen.addJumpIfBytesNotEqual(Register.R0, mPayload, nextFilterLabel);
-
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_NATT_KEEPALIVE);
-            gen.addJump(mCountAndDropLabel);
-            gen.defineLabel(nextFilterLabel);
-        }
-
-        public String toString() {
-            try {
-                return String.format("%s -> %s",
-                        NetworkStackUtils.addressAndPortToString(
-                                InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
-                        NetworkStackUtils.addressAndPortToString(
-                                InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
-            } catch (UnknownHostException e) {
-                return "Unknown host";
-            }
-        }
-    }
-
-    // A class to hold TCP keepalive ack information.
-    private abstract static class TcpKeepaliveAck extends KeepalivePacket {
-        protected static class TcpKeepaliveAckData {
-            public final byte[] srcAddress;
-            public final int srcPort;
-            public final byte[] dstAddress;
-            public final int dstPort;
-            public final int seq;
-            public final int ack;
-
-            // Create the characteristics of the ack packet from the sent keepalive packet.
-            TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
-                srcAddress = sentKeepalivePacket.dstAddress;
-                srcPort = sentKeepalivePacket.dstPort;
-                dstAddress = sentKeepalivePacket.srcAddress;
-                dstPort = sentKeepalivePacket.srcPort;
-                seq = sentKeepalivePacket.ack;
-                ack = sentKeepalivePacket.seq + 1;
-            }
-        }
-
-        protected final TcpKeepaliveAckData mPacket;
-        protected final byte[] mSrcDstAddr;
-        protected final byte[] mPortSeqAckFingerprint;
-
-        TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
-            mPacket = packet;
-            mSrcDstAddr = srcDstAddr;
-            mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
-                    mPacket.dstPort, mPacket.seq, mPacket.ack);
-        }
-
-        static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
-            final ByteBuffer fp = ByteBuffer.allocate(12);
-            fp.order(ByteOrder.BIG_ENDIAN);
-            fp.putShort((short) srcPort);
-            fp.putShort((short) dstPort);
-            fp.putInt(seq);
-            fp.putInt(ack);
-            return fp.array();
-        }
-
-        public String toString() {
-            try {
-                return String.format("%s -> %s , seq=%d, ack=%d",
-                        NetworkStackUtils.addressAndPortToString(
-                                InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
-                        NetworkStackUtils.addressAndPortToString(
-                                InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
-                        Integer.toUnsignedLong(mPacket.seq),
-                        Integer.toUnsignedLong(mPacket.ack));
-            } catch (UnknownHostException e) {
-                return "Unknown host";
-            }
-        }
-
-        // Append a filter for this keepalive ack to {@code gen}.
-        // Jump to drop if it matches the keepalive ack.
-        // Jump to the next filter if packet doesn't match the keepalive ack.
-        abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
-    }
-
-    private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
-
-        TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
-            this(new TcpKeepaliveAckData(sentKeepalivePacket));
-        }
-        TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
-            super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
-        }
-
-        @Override
-        void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-            final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
-
-            gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
-            gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
-
-            // Skip to the next filter if it's not zero-sized :
-            // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
-            // Load the IP header size into R1
-            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            // Load the TCP header size into R0 (it's indexed by R1)
-            gen.addLoad8Indexed(Register.R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
-            // Size offset is in the top nibble, but it must be multiplied by 4, and the two
-            // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
-            gen.addRightShift(2);
-            // R0 += R1 -> R0 contains TCP + IP headers length
-            gen.addAddR1();
-            // Load IPv4 total length
-            gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
-            gen.addNeg(Register.R0);
-            gen.addAddR1();
-            gen.addJumpIfR0NotEquals(0, nextFilterLabel);
-            // Add IPv4 header length
-            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
-            gen.addAddR1();
-            gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
-
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
-            gen.addJump(mCountAndDropLabel);
-            gen.defineLabel(nextFilterLabel);
-        }
-    }
-
-    private class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
-        TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
-            this(new TcpKeepaliveAckData(sentKeepalivePacket));
-        }
-        TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
-            super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
-        }
-
-        @Override
-        void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-            throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
-        }
-    }
-
-    // Maximum number of RAs to filter for.
-    private static final int MAX_RAS = 10;
-
-    @GuardedBy("this")
-    private ArrayList<Ra> mRas = new ArrayList<>();
-    @GuardedBy("this")
-    private SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
-
-    // There is always some marginal benefit to updating the installed APF program when an RA is
-    // seen because we can extend the program's lifetime slightly, but there is some cost to
-    // updating the program, so don't bother unless the program is going to expire soon. This
-    // constant defines "soon" in seconds.
-    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
-    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
-    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
-    // packets may be dropped, so let's use 6.
-    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
-
-    // When did we last install a filter program? In seconds since Unix Epoch.
-    @GuardedBy("this")
-    private long mLastTimeInstalledProgram;
-    // How long should the last installed filter program live for? In seconds.
-    @GuardedBy("this")
-    private long mLastInstalledProgramMinLifetime;
-    @GuardedBy("this")
-    private ApfProgramEvent.Builder mLastInstallEvent;
-
-    // For debugging only. The last program installed.
-    @GuardedBy("this")
-    private byte[] mLastInstalledProgram;
-
-    /**
-     * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
-     *
-     * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
-     * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
-     * the opcodes to access the data buffer (LDDW and STDW).
-     */
-    @GuardedBy("this") @Nullable
-    private byte[] mDataSnapshot;
-
-    // How many times the program was updated since we started.
-    @GuardedBy("this")
-    private int mNumProgramUpdates = 0;
-    // How many times the program was updated since we started for allowing multicast traffic.
-    @GuardedBy("this")
-    private int mNumProgramUpdatesAllowingMulticast = 0;
-
-    /**
-     * Generate filter code to process ARP packets. Execution of this code ends in either the
-     * DROP_LABEL or PASS_LABEL and does not fall off the end.
-     * Preconditions:
-     *  - Packet being filtered is ARP
-     */
-    @GuardedBy("this")
-    private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-        // Here's a basic summary of what the ARP filter program does:
-        //
-        // if not ARP IPv4
-        //   pass
-        // if not ARP IPv4 reply or request
-        //   pass
-        // if ARP reply source ip is 0.0.0.0
-        //   drop
-        // if unicast ARP reply
-        //   pass
-        // if interface has no IPv4 address
-        //   if target ip is 0.0.0.0
-        //      drop
-        // else
-        //   if target ip is not the interface ip
-        //      drop
-        // pass
-
-        final String checkTargetIPv4 = "checkTargetIPv4";
-
-        // Pass if not ARP IPv4.
-        gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
-        maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
-        gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
-
-        // Pass if unknown ARP opcode.
-        gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
-        gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
-        maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
-        gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
-
-        // Drop if ARP reply source IP is 0.0.0.0
-        gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
-        maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
-        gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
-
-        // Pass if unicast reply.
-        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-        maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
-        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-
-        // Either a unicast request, a unicast reply, or a broadcast reply.
-        gen.defineLabel(checkTargetIPv4);
-        if (mIPv4Address == null) {
-            // When there is no IPv4 address, drop GARP replies (b/29404209).
-            gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
-            maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
-            gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
-        } else {
-            // When there is an IPv4 address, drop unicast/broadcast requests
-            // and broadcast replies with a different target IPv4 address.
-            gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
-            maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
-            gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
-        }
-
-        maybeSetupCounter(gen, Counter.PASSED_ARP);
-        gen.addJump(mCountAndPassLabel);
-    }
-
-    /**
-     * Generate filter code to process IPv4 packets. Execution of this code ends in either the
-     * DROP_LABEL or PASS_LABEL and does not fall off the end.
-     * Preconditions:
-     *  - Packet being filtered is IPv4
-     */
-    @GuardedBy("this")
-    private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-        // Here's a basic summary of what the IPv4 filter program does:
-        //
-        // if filtering multicast (i.e. multicast lock not held):
-        //   if it's DHCP destined to our MAC:
-        //     pass
-        //   if it's L2 broadcast:
-        //     drop
-        //   if it's IPv4 multicast:
-        //     drop
-        //   if it's IPv4 broadcast:
-        //     drop
-        // if keepalive ack
-        //   drop
-        // pass
-
-        if (mMulticastFilter) {
-            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
-
-            // Pass DHCP addressed to us.
-            // Check it's UDP.
-            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
-            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
-            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
-            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
-            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
-            // Check it's addressed to DHCP client port.
-            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
-            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
-            // Check it's DHCP to our MAC address.
-            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
-            // NOTE: Relies on R1 containing IPv4 header offset.
-            gen.addAddR1();
-            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
-            maybeSetupCounter(gen, Counter.PASSED_DHCP);
-            gen.addJump(mCountAndPassLabel);
-
-            // Drop all multicasts/broadcasts.
-            gen.defineLabel(skipDhcpv4Filter);
-
-            // If IPv4 destination address is in multicast range, drop.
-            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
-            gen.addAnd(0xf0);
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
-            gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
-
-            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
-            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
-            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
-            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
-                maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
-                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
-                gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
-            }
-
-            // If any TCP keepalive filter matches, drop
-            generateV4KeepaliveFilters(gen);
-
-            // If any NAT-T keepalive filter matches, drop
-            generateV4NattKeepaliveFilters(gen);
-
-            // Otherwise, this is an IPv4 unicast, pass
-            // If L2 broadcast packet, drop.
-            // TODO: can we invert this condition to fall through to the common pass case below?
-            maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
-            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
-            gen.addJump(mCountAndDropLabel);
-        } else {
-            generateV4KeepaliveFilters(gen);
-            generateV4NattKeepaliveFilters(gen);
-        }
-
-        // Otherwise, pass
-        maybeSetupCounter(gen, Counter.PASSED_IPV4);
-        gen.addJump(mCountAndPassLabel);
-    }
-
-    private void generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto,
-            int offset, String label) throws IllegalInstructionException {
-        final boolean haveKeepaliveResponses = NetworkStackUtils.any(mKeepalivePackets,
-                ack -> filterType.isInstance(ack));
-
-        // If no keepalive packets of this type
-        if (!haveKeepaliveResponses) return;
-
-        // If not the right proto, skip keepalive filters
-        gen.addLoad8(Register.R0, offset);
-        gen.addJumpIfR0NotEquals(proto, label);
-
-        // Drop Keepalive responses
-        for (int i = 0; i < mKeepalivePackets.size(); ++i) {
-            final KeepalivePacket response = mKeepalivePackets.valueAt(i);
-            if (filterType.isInstance(response)) response.generateFilterLocked(gen);
-        }
-
-        gen.defineLabel(label);
-    }
-
-    private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
-        generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
-                "skip_v4_keepalive_filter");
-    }
-
-    private void generateV4NattKeepaliveFilters(ApfGenerator gen)
-            throws IllegalInstructionException {
-        generateKeepaliveFilters(gen, NattKeepaliveResponse.class,
-                IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, "skip_v4_nattkeepalive_filter");
-    }
-
-    /**
-     * Generate filter code to process IPv6 packets. Execution of this code ends in either the
-     * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
-     * Preconditions:
-     *  - Packet being filtered is IPv6
-     */
-    @GuardedBy("this")
-    private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-        // Here's a basic summary of what the IPv6 filter program does:
-        //
-        // if we're dropping multicast
-        //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
-        //     if it's multicast:
-        //       drop
-        //     pass
-        // if it's ICMPv6 RS to any:
-        //   drop
-        // if it's ICMPv6 NA to ff02::1:
-        //   drop
-        // if keepalive ack
-        //   drop
-
-        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
-
-        // Drop multicast if the multicast filter is enabled.
-        if (mMulticastFilter) {
-            final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
-            final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
-
-            // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
-            // While awake, let all ICMPv6 multicasts through.
-            if (mInDozeMode) {
-                // Not ICMPv6? -> Proceed to multicast filtering
-                gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
-
-                // ICMPv6 but not ECHO? -> Skip the multicast filter.
-                // (ICMPv6 ECHO requests will go through the multicast filter below).
-                gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
-                gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
-            } else {
-                gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
-            }
-
-            // Drop all other packets sent to ff00::/8 (multicast prefix).
-            gen.defineLabel(dropAllIPv6MulticastsLabel);
-            maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
-            gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
-            gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
-            // If any keepalive filter matches, drop
-            generateV6KeepaliveFilters(gen);
-            // Not multicast. Pass.
-            maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
-            gen.addJump(mCountAndPassLabel);
-            gen.defineLabel(skipIPv6MulticastFilterLabel);
-        } else {
-            generateV6KeepaliveFilters(gen);
-            // If not ICMPv6, pass.
-            maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
-            gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
-        }
-
-        // If we got this far, the packet is ICMPv6.  Drop some specific types.
-
-        // Add unsolicited multicast neighbor announcements filter
-        String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
-        gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
-        // Drop all router solicitations (b/32833400)
-        maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
-        gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
-        // If not neighbor announcements, skip filter.
-        gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
-        // If to ff02::1, drop.
-        // TODO: Drop only if they don't contain the address of on-link neighbours.
-        gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
-        gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
-                skipUnsolicitedMulticastNALabel);
-        maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
-        gen.addJump(mCountAndDropLabel);
-        gen.defineLabel(skipUnsolicitedMulticastNALabel);
-    }
-
-    private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
-        generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
-                "skip_v6_keepalive_filter");
-    }
-
-    /**
-     * Begin generating an APF program to:
-     * <ul>
-     * <li>Drop/Pass 802.3 frames (based on policy)
-     * <li>Drop packets with EtherType within the Black List
-     * <li>Drop ARP requests not for us, if mIPv4Address is set,
-     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
-     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
-     * <li>Pass all other IPv4 packets,
-     * <li>Drop all broadcast non-IP non-ARP packets.
-     * <li>Pass all non-ICMPv6 IPv6 packets,
-     * <li>Pass all non-IPv4 and non-IPv6 packets,
-     * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
-     * <li>Drop IPv6 ICMPv6 RSs.
-     * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
-     * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
-     * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
-     *     insertion of RA filters here, or if there aren't any, just passes the packets.
-     * </ul>
-     */
-    @GuardedBy("this")
-    private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
-        // This is guaranteed to succeed because of the check in maybeCreate.
-        ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
-
-        if (mApfCapabilities.hasDataAccess()) {
-            // Increment TOTAL_PACKETS
-            maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
-            gen.addLoadData(Register.R0, 0);  // load counter
-            gen.addAdd(1);
-            gen.addStoreData(Register.R0, 0);  // write-back counter
-        }
-
-        // Here's a basic summary of what the initial program does:
-        //
-        // if it's a 802.3 Frame (ethtype < 0x0600):
-        //    drop or pass based on configurations
-        // if it has a ether-type that belongs to the black list
-        //    drop
-        // if it's ARP:
-        //   insert ARP filter to drop or pass these appropriately
-        // if it's IPv4:
-        //   insert IPv4 filter to drop or pass these appropriately
-        // if it's not IPv6:
-        //   if it's broadcast:
-        //     drop
-        //   pass
-        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
-
-        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
-
-        if (mDrop802_3Frames) {
-            // drop 802.3 frames (ethtype < 0x0600)
-            maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
-            gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
-        }
-
-        // Handle ether-type black list
-        maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
-        for (int p : mEthTypeBlackList) {
-            gen.addJumpIfR0Equals(p, mCountAndDropLabel);
-        }
-
-        // Add ARP filters:
-        String skipArpFiltersLabel = "skipArpFilters";
-        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
-        generateArpFilterLocked(gen);
-        gen.defineLabel(skipArpFiltersLabel);
-
-        // Add IPv4 filters:
-        String skipIPv4FiltersLabel = "skipIPv4Filters";
-        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
-        // execute the ARP filter, since that filter does not fall through, but either drops or
-        // passes.
-        gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
-        generateIPv4FilterLocked(gen);
-        gen.defineLabel(skipIPv4FiltersLabel);
-
-        // Check for IPv6:
-        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
-        // execute the ARP or IPv4 filters, since those filters do not fall through, but either
-        // drop or pass.
-        String ipv6FilterLabel = "IPv6Filters";
-        gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
-
-        // Drop non-IP non-ARP broadcasts, pass the rest
-        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-        maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
-        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-        maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
-        gen.addJump(mCountAndDropLabel);
-
-        // Add IPv6 filters:
-        gen.defineLabel(ipv6FilterLabel);
-        generateIPv6FilterLocked(gen);
-        return gen;
-    }
-
-    /**
-     * Append packet counting epilogue to the APF program.
-     *
-     * Currently, the epilogue consists of two trampolines which count passed and dropped packets
-     * before jumping to the actual PASS and DROP labels.
-     */
-    @GuardedBy("this")
-    private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
-        // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
-        // will just fall-through to the PASS label.
-        if (!mApfCapabilities.hasDataAccess()) return;
-
-        // Execution will reach the bottom of the program if none of the filters match,
-        // which will pass the packet to the application processor.
-        maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
-
-        // Append the count & pass trampoline, which increments the counter at the data address
-        // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
-        // the entire sequence inline for every counter.
-        gen.defineLabel(mCountAndPassLabel);
-        gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
-        gen.addAdd(1);                     // R0++
-        gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
-        gen.addJump(gen.PASS_LABEL);
-
-        // Same as above for the count & drop trampoline.
-        gen.defineLabel(mCountAndDropLabel);
-        gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
-        gen.addAdd(1);                     // R0++
-        gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
-        gen.addJump(gen.DROP_LABEL);
-    }
-
-    /**
-     * Generate and install a new filter program.
-     */
-    @GuardedBy("this")
-    @VisibleForTesting
-    void installNewProgramLocked() {
-        purgeExpiredRasLocked();
-        ArrayList<Ra> rasToFilter = new ArrayList<>();
-        final byte[] program;
-        long programMinLifetime = Long.MAX_VALUE;
-        long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
-        if (mApfCapabilities.hasDataAccess()) {
-            // Reserve space for the counters.
-            maximumApfProgramSize -= Counter.totalSize();
-        }
-
-        try {
-            // Step 1: Determine how many RA filters we can fit in the program.
-            ApfGenerator gen = emitPrologueLocked();
-
-            // The epilogue normally goes after the RA filters, but add it early to include its
-            // length when estimating the total.
-            emitEpilogue(gen);
-
-            // Can't fit the program even without any RA filters?
-            if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
-                Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
-                return;
-            }
-
-            for (Ra ra : mRas) {
-                ra.generateFilterLocked(gen);
-                // Stop if we get too big.
-                if (gen.programLengthOverEstimate() > maximumApfProgramSize) break;
-                rasToFilter.add(ra);
-            }
-
-            // Step 2: Actually generate the program
-            gen = emitPrologueLocked();
-            for (Ra ra : rasToFilter) {
-                programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
-            }
-            emitEpilogue(gen);
-            program = gen.generate();
-        } catch (IllegalInstructionException|IllegalStateException e) {
-            Log.e(TAG, "Failed to generate APF program.", e);
-            return;
-        }
-        final long now = currentTimeSeconds();
-        mLastTimeInstalledProgram = now;
-        mLastInstalledProgramMinLifetime = programMinLifetime;
-        mLastInstalledProgram = program;
-        mNumProgramUpdates++;
-
-        if (VDBG) {
-            hexDump("Installing filter: ", program, program.length);
-        }
-        mIpClientCallback.installPacketFilter(program);
-        logApfProgramEventLocked(now);
-        mLastInstallEvent = new ApfProgramEvent.Builder()
-                .setLifetime(programMinLifetime)
-                .setFilteredRas(rasToFilter.size())
-                .setCurrentRas(mRas.size())
-                .setProgramLength(program.length)
-                .setFlags(mIPv4Address != null, mMulticastFilter);
-    }
-
-    @GuardedBy("this")
-    private void logApfProgramEventLocked(long now) {
-        if (mLastInstallEvent == null) {
-            return;
-        }
-        ApfProgramEvent.Builder ev = mLastInstallEvent;
-        mLastInstallEvent = null;
-        final long actualLifetime = now - mLastTimeInstalledProgram;
-        ev.setActualLifetime(actualLifetime);
-        if (actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
-            return;
-        }
-        mMetricsLog.log(ev.build());
-    }
-
-    /**
-     * Returns {@code true} if a new program should be installed because the current one dies soon.
-     */
-    private boolean shouldInstallnewProgram() {
-        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
-        return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
-    }
-
-    private void hexDump(String msg, byte[] packet, int length) {
-        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
-    }
-
-    @GuardedBy("this")
-    private void purgeExpiredRasLocked() {
-        for (int i = 0; i < mRas.size();) {
-            if (mRas.get(i).isExpired()) {
-                log("Expiring " + mRas.get(i));
-                mRas.remove(i);
-            } else {
-                i++;
-            }
-        }
-    }
-
-    /**
-     * Process an RA packet, updating the list of known RAs and installing a new APF program
-     * if the current APF program should be updated.
-     * @return a ProcessRaResult enum describing what action was performed.
-     */
-    @VisibleForTesting
-    synchronized ProcessRaResult processRa(byte[] packet, int length) {
-        if (VDBG) hexDump("Read packet = ", packet, length);
-
-        // Have we seen this RA before?
-        for (int i = 0; i < mRas.size(); i++) {
-            Ra ra = mRas.get(i);
-            if (ra.matches(packet, length)) {
-                if (VDBG) log("matched RA " + ra);
-                // Update lifetimes.
-                ra.mLastSeen = currentTimeSeconds();
-                ra.mMinLifetime = ra.minLifetime(packet, length);
-                ra.seenCount++;
-
-                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
-                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
-                // until the filter program exceeds the maximum filter program size allowed by the
-                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
-                // filter program.
-                // TODO: consider sorting the RAs in order of increasing expiry time as well.
-                // Swap to front of array.
-                mRas.add(0, mRas.remove(i));
-
-                // If the current program doesn't expire for a while, don't update.
-                if (shouldInstallnewProgram()) {
-                    installNewProgramLocked();
-                    return ProcessRaResult.UPDATE_EXPIRY;
-                }
-                return ProcessRaResult.MATCH;
-            }
-        }
-        purgeExpiredRasLocked();
-        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
-        if (mRas.size() >= MAX_RAS) {
-            return ProcessRaResult.DROPPED;
-        }
-        final Ra ra;
-        try {
-            ra = new Ra(packet, length);
-        } catch (Exception e) {
-            Log.e(TAG, "Error parsing RA", e);
-            return ProcessRaResult.PARSE_ERROR;
-        }
-        // Ignore 0 lifetime RAs.
-        if (ra.isExpired()) {
-            return ProcessRaResult.ZERO_LIFETIME;
-        }
-        log("Adding " + ra);
-        mRas.add(ra);
-        installNewProgramLocked();
-        return ProcessRaResult.UPDATE_NEW_RA;
-    }
-
-    /**
-     * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
-     * filtering using APF programs.
-     */
-    public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
-            InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback) {
-        if (context == null || config == null || ifParams == null) return null;
-        ApfCapabilities apfCapabilities =  config.apfCapabilities;
-        if (apfCapabilities == null) return null;
-        if (apfCapabilities.apfVersionSupported == 0) return null;
-        if (apfCapabilities.maximumApfProgramSize < 512) {
-            Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
-            return null;
-        }
-        // For now only support generating programs for Ethernet frames. If this restriction is
-        // lifted:
-        //   1. the program generator will need its offsets adjusted.
-        //   2. the packet filter attached to our packet socket will need its offset adjusted.
-        if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
-        if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
-            Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
-            return null;
-        }
-
-        return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
-    }
-
-    public synchronized void shutdown() {
-        if (mReceiveThread != null) {
-            log("shutting down");
-            mReceiveThread.halt();  // Also closes socket.
-            mReceiveThread = null;
-        }
-        mRas.clear();
-        mContext.unregisterReceiver(mDeviceIdleReceiver);
-    }
-
-    public synchronized void setMulticastFilter(boolean isEnabled) {
-        if (mMulticastFilter == isEnabled) return;
-        mMulticastFilter = isEnabled;
-        if (!isEnabled) {
-            mNumProgramUpdatesAllowingMulticast++;
-        }
-        installNewProgramLocked();
-    }
-
-    @VisibleForTesting
-    public synchronized void setDozeMode(boolean isEnabled) {
-        if (mInDozeMode == isEnabled) return;
-        mInDozeMode = isEnabled;
-        installNewProgramLocked();
-    }
-
-    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
-    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
-        LinkAddress ipv4Address = null;
-        for (LinkAddress address : lp.getLinkAddresses()) {
-            if (!(address.getAddress() instanceof Inet4Address)) {
-                continue;
-            }
-            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
-                // More than one IPv4 address, abort.
-                return null;
-            }
-            ipv4Address = address;
-        }
-        return ipv4Address;
-    }
-
-    public synchronized void setLinkProperties(LinkProperties lp) {
-        // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
-        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
-        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
-        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
-        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
-            return;
-        }
-        mIPv4Address = addr;
-        mIPv4PrefixLength = prefix;
-        installNewProgramLocked();
-    }
-
-    /**
-     * Add TCP keepalive ack packet filter.
-     * This will add a filter to drop acks to the keepalive packet passed as an argument.
-     *
-     * @param slot The index used to access the filter.
-     * @param sentKeepalivePacket The attributes of the sent keepalive packet.
-     */
-    public synchronized void addTcpKeepalivePacketFilter(final int slot,
-            final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
-        log("Adding keepalive ack(" + slot + ")");
-        if (null != mKeepalivePackets.get(slot)) {
-            throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
-        }
-        final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
-        mKeepalivePackets.put(slot, (ipVersion == 4)
-                ? new TcpKeepaliveAckV4(sentKeepalivePacket)
-                : new TcpKeepaliveAckV6(sentKeepalivePacket));
-        installNewProgramLocked();
-    }
-
-    /**
-     * Add NAT-T keepalive packet filter.
-     * This will add a filter to drop NAT-T keepalive packet which is passed as an argument.
-     *
-     * @param slot The index used to access the filter.
-     * @param sentKeepalivePacket The attributes of the sent keepalive packet.
-     */
-    public synchronized void addNattKeepalivePacketFilter(final int slot,
-            final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
-        log("Adding NAT-T keepalive packet(" + slot + ")");
-        if (null != mKeepalivePackets.get(slot)) {
-            throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied");
-        }
-        if (sentKeepalivePacket.srcAddress.length != 4) {
-            throw new IllegalArgumentException("NAT-T keepalive is only supported on IPv4");
-        }
-        mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket));
-        installNewProgramLocked();
-    }
-
-    /**
-     * Remove keepalive packet filter.
-     *
-     * @param slot The index used to access the filter.
-     */
-    public synchronized void removeKeepalivePacketFilter(int slot) {
-        log("Removing keepalive packet(" + slot + ")");
-        mKeepalivePackets.remove(slot);
-        installNewProgramLocked();
-    }
-
-    static public long counterValue(byte[] data, Counter counter)
-            throws ArrayIndexOutOfBoundsException {
-        // Follow the same wrap-around addressing scheme of the interpreter.
-        int offset = counter.offset();
-        if (offset < 0) {
-            offset = data.length + offset;
-        }
-
-        // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
-        long value = 0;
-        for (int i = 0; i < 4; i++) {
-            value = value << 8 | (data[offset] & 0xFF);
-            offset++;
-        }
-        return value;
-    }
-
-    public synchronized void dump(IndentingPrintWriter pw) {
-        pw.println("Capabilities: " + mApfCapabilities);
-        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
-        pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
-        try {
-            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
-        } catch (UnknownHostException|NullPointerException e) {}
-
-        if (mLastTimeInstalledProgram == 0) {
-            pw.println("No program installed.");
-            return;
-        }
-        pw.println("Program updates: " + mNumProgramUpdates);
-        pw.println(String.format(
-                "Last program length %d, installed %ds ago, lifetime %ds",
-                mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
-                mLastInstalledProgramMinLifetime));
-
-        pw.println("RA filters:");
-        pw.increaseIndent();
-        for (Ra ra: mRas) {
-            pw.println(ra);
-            pw.increaseIndent();
-            pw.println(String.format(
-                    "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
-            if (DBG) {
-                pw.println("Last match:");
-                pw.increaseIndent();
-                pw.println(ra.getLastMatchingPacket());
-                pw.decreaseIndent();
-            }
-            pw.decreaseIndent();
-        }
-        pw.decreaseIndent();
-
-        pw.println("TCP Keepalive filters:");
-        pw.increaseIndent();
-        for (int i = 0; i < mKeepalivePackets.size(); ++i) {
-            final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
-            if (keepalivePacket instanceof TcpKeepaliveAck) {
-                pw.print("Slot ");
-                pw.print(mKeepalivePackets.keyAt(i));
-                pw.print(": ");
-                pw.println(keepalivePacket);
-            }
-        }
-        pw.decreaseIndent();
-
-        pw.println("NAT-T Keepalive filters:");
-        pw.increaseIndent();
-        for (int i = 0; i < mKeepalivePackets.size(); ++i) {
-            final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
-            if (keepalivePacket instanceof NattKeepaliveResponse) {
-                pw.print("Slot ");
-                pw.print(mKeepalivePackets.keyAt(i));
-                pw.print(": ");
-                pw.println(keepalivePacket);
-            }
-        }
-        pw.decreaseIndent();
-
-        if (DBG) {
-            pw.println("Last program:");
-            pw.increaseIndent();
-            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
-            pw.decreaseIndent();
-        }
-
-        pw.println("APF packet counters: ");
-        pw.increaseIndent();
-        if (!mApfCapabilities.hasDataAccess()) {
-            pw.println("APF counters not supported");
-        } else if (mDataSnapshot == null) {
-            pw.println("No last snapshot.");
-        } else {
-            try {
-                Counter[] counters = Counter.class.getEnumConstants();
-                for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
-                    long value = counterValue(mDataSnapshot, c);
-                    // Only print non-zero counters
-                    if (value != 0) {
-                        pw.println(c.toString() + ": " + value);
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                pw.println("Uh-oh: " + e);
-            }
-            if (VDBG) {
-                pw.println("Raw data dump: ");
-                pw.println(HexDump.dumpHexString(mDataSnapshot));
-            }
-        }
-        pw.decreaseIndent();
-    }
-
-    // TODO: move to android.net.NetworkUtils
-    @VisibleForTesting
-    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
-        return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
-    }
-
-    private static int uint8(byte b) {
-        return b & 0xff;
-    }
-
-    private static int getUint16(ByteBuffer buffer, int position) {
-        return buffer.getShort(position) & 0xffff;
-    }
-
-    private static long getUint32(ByteBuffer buffer, int position) {
-        return Integer.toUnsignedLong(buffer.getInt(position));
-    }
-
-    private static int getUint8(ByteBuffer buffer, int position) {
-        return uint8(buffer.get(position));
-    }
-
-    private static int bytesToBEInt(byte[] bytes) {
-        return (uint8(bytes[0]) << 24)
-                + (uint8(bytes[1]) << 16)
-                + (uint8(bytes[2]) << 8)
-                + (uint8(bytes[3]));
-    }
-
-    private static byte[] concatArrays(final byte[]... arr) {
-        int size = 0;
-        for (byte[] a : arr) {
-            size += a.length;
-        }
-        final byte[] result = new byte[size];
-        int offset = 0;
-        for (byte[] a : arr) {
-            System.arraycopy(a, 0, result, offset, a.length);
-            offset += a.length;
-        }
-        return result;
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
deleted file mode 100644
index 44ce2db..0000000
--- a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
+++ /dev/null
@@ -1,937 +0,0 @@
-/*
- * Copyright (C) 2016 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.apf;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * APF assembler/generator.  A tool for generating an APF program.
- *
- * Call add*() functions to add instructions to the program, then call
- * {@link generate} to get the APF bytecode for the program.
- *
- * @hide
- */
-public class ApfGenerator {
-    /**
-     * This exception is thrown when an attempt is made to generate an illegal instruction.
-     */
-    public static class IllegalInstructionException extends Exception {
-        IllegalInstructionException(String msg) {
-            super(msg);
-        }
-    }
-    private enum Opcodes {
-        LABEL(-1),
-        LDB(1),    // Load 1 byte from immediate offset, e.g. "ldb R0, [5]"
-        LDH(2),    // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]"
-        LDW(3),    // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]"
-        LDBX(4),   // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0"
-        LDHX(5),   // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0"
-        LDWX(6),   // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0"
-        ADD(7),    // Add, e.g. "add R0,5"
-        MUL(8),    // Multiply, e.g. "mul R0,5"
-        DIV(9),    // Divide, e.g. "div R0,5"
-        AND(10),   // And, e.g. "and R0,5"
-        OR(11),    // Or, e.g. "or R0,5"
-        SH(12),    // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right)
-        LI(13),    // Load immediate, e.g. "li R0,5" (immediate encoded as signed value)
-        JMP(14),   // Jump, e.g. "jmp label"
-        JEQ(15),   // Compare equal and branch, e.g. "jeq R0,5,label"
-        JNE(16),   // Compare not equal and branch, e.g. "jne R0,5,label"
-        JGT(17),   // Compare greater than and branch, e.g. "jgt R0,5,label"
-        JLT(18),   // Compare less than and branch, e.g. "jlt R0,5,label"
-        JSET(19),  // Compare any bits set and branch, e.g. "jset R0,5,label"
-        JNEBS(20), // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455"
-        EXT(21),   // Followed by immediate indicating ExtendedOpcodes.
-        LDDW(22),  // Load 4 bytes from data memory address (register + immediate): "lddw R0, [5]R1"
-        STDW(23);  // Store 4 bytes to data memory address (register + immediate): "stdw R0, [5]R1"
-
-        final int value;
-
-        private Opcodes(int value) {
-            this.value = value;
-        }
-    }
-    // Extended opcodes. Primary opcode is Opcodes.EXT. ExtendedOpcodes are encoded in the immediate
-    // field.
-    private enum ExtendedOpcodes {
-        LDM(0),   // Load from memory, e.g. "ldm R0,5"
-        STM(16),  // Store to memory, e.g. "stm R0,5"
-        NOT(32),  // Not, e.g. "not R0"
-        NEG(33),  // Negate, e.g. "neg R0"
-        SWAP(34), // Swap, e.g. "swap R0,R1"
-        MOVE(35);  // Move, e.g. "move R0,R1"
-
-        final int value;
-
-        private ExtendedOpcodes(int value) {
-            this.value = value;
-        }
-    }
-    public enum Register {
-        R0(0),
-        R1(1);
-
-        final int value;
-
-        private Register(int value) {
-            this.value = value;
-        }
-    }
-    private class Instruction {
-        private final byte mOpcode;   // A "Opcode" value.
-        private final byte mRegister; // A "Register" value.
-        private boolean mHasImm;
-        private byte mImmSize;
-        private boolean mImmSigned;
-        private int mImm;
-        // When mOpcode is a jump:
-        private byte mTargetLabelSize;
-        private String mTargetLabel;
-        // When mOpcode == Opcodes.LABEL:
-        private String mLabel;
-        // When mOpcode == Opcodes.JNEBS:
-        private byte[] mCompareBytes;
-        // Offset in bytes from the beginning of this program. Set by {@link ApfGenerator#generate}.
-        int offset;
-
-        Instruction(Opcodes opcode, Register register) {
-            mOpcode = (byte)opcode.value;
-            mRegister = (byte)register.value;
-        }
-
-        Instruction(Opcodes opcode) {
-            this(opcode, Register.R0);
-        }
-
-        void setImm(int imm, boolean signed) {
-            mHasImm = true;
-            mImm = imm;
-            mImmSigned = signed;
-            mImmSize = calculateImmSize(imm, signed);
-        }
-
-        void setUnsignedImm(int imm) {
-            setImm(imm, false);
-        }
-
-        void setSignedImm(int imm) {
-            setImm(imm, true);
-        }
-
-        void setLabel(String label) throws IllegalInstructionException {
-            if (mLabels.containsKey(label)) {
-                throw new IllegalInstructionException("duplicate label " + label);
-            }
-            if (mOpcode != Opcodes.LABEL.value) {
-                throw new IllegalStateException("adding label to non-label instruction");
-            }
-            mLabel = label;
-            mLabels.put(label, this);
-        }
-
-        void setTargetLabel(String label) {
-            mTargetLabel = label;
-            mTargetLabelSize = 4; // May shrink later on in generate().
-        }
-
-        void setCompareBytes(byte[] bytes) {
-            if (mOpcode != Opcodes.JNEBS.value) {
-                throw new IllegalStateException("adding compare bytes to non-JNEBS instruction");
-            }
-            mCompareBytes = bytes;
-        }
-
-        /**
-         * @return size of instruction in bytes.
-         */
-        int size() {
-            if (mOpcode == Opcodes.LABEL.value) {
-                return 0;
-            }
-            int size = 1;
-            if (mHasImm) {
-                size += generatedImmSize();
-            }
-            if (mTargetLabel != null) {
-                size += generatedImmSize();
-            }
-            if (mCompareBytes != null) {
-                size += mCompareBytes.length;
-            }
-            return size;
-        }
-
-        /**
-         * Resize immediate value field so that it's only as big as required to
-         * contain the offset of the jump destination.
-         * @return {@code true} if shrunk.
-         */
-        boolean shrink() throws IllegalInstructionException {
-            if (mTargetLabel == null) {
-                return false;
-            }
-            int oldSize = size();
-            int oldTargetLabelSize = mTargetLabelSize;
-            mTargetLabelSize = calculateImmSize(calculateTargetLabelOffset(), false);
-            if (mTargetLabelSize > oldTargetLabelSize) {
-                throw new IllegalStateException("instruction grew");
-            }
-            return size() < oldSize;
-        }
-
-        /**
-         * Assemble value for instruction size field.
-         */
-        private byte generateImmSizeField() {
-            byte immSize = generatedImmSize();
-            // Encode size field to fit in 2 bits: 0->0, 1->1, 2->2, 3->4.
-            return immSize == 4 ? 3 : immSize;
-        }
-
-        /**
-         * Assemble first byte of generated instruction.
-         */
-        private byte generateInstructionByte() {
-            byte sizeField = generateImmSizeField();
-            return (byte)((mOpcode << 3) | (sizeField << 1) | mRegister);
-        }
-
-        /**
-         * Write {@code value} at offset {@code writingOffset} into {@code bytecode}.
-         * {@link generatedImmSize} bytes are written. {@code value} is truncated to
-         * {@code generatedImmSize} bytes. {@code value} is treated simply as a
-         * 32-bit value, so unsigned values should be zero extended and the truncation
-         * should simply throw away their zero-ed upper bits, and signed values should
-         * be sign extended and the truncation should simply throw away their signed
-         * upper bits.
-         */
-        private int writeValue(int value, byte[] bytecode, int writingOffset) {
-            for (int i = generatedImmSize() - 1; i >= 0; i--) {
-                bytecode[writingOffset++] = (byte)((value >> (i * 8)) & 255);
-            }
-            return writingOffset;
-        }
-
-        /**
-         * Generate bytecode for this instruction at offset {@link offset}.
-         */
-        void generate(byte[] bytecode) throws IllegalInstructionException {
-            if (mOpcode == Opcodes.LABEL.value) {
-                return;
-            }
-            int writingOffset = offset;
-            bytecode[writingOffset++] = generateInstructionByte();
-            if (mTargetLabel != null) {
-                writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset);
-            }
-            if (mHasImm) {
-                writingOffset = writeValue(mImm, bytecode, writingOffset);
-            }
-            if (mCompareBytes != null) {
-                System.arraycopy(mCompareBytes, 0, bytecode, writingOffset, mCompareBytes.length);
-                writingOffset += mCompareBytes.length;
-            }
-            if ((writingOffset - offset) != size()) {
-                throw new IllegalStateException("wrote " + (writingOffset - offset) +
-                        " but should have written " + size());
-            }
-        }
-
-        /**
-         * Calculate the size of either the immediate field or the target label field, if either is
-         * present. Most instructions have either an immediate or a target label field, but for the
-         * instructions that have both, the size of the target label field must be the same as the
-         * size of the immediate field, because there is only one length field in the instruction
-         * byte, hence why this function simply takes the maximum of the two sizes, so neither is
-         * truncated.
-         */
-        private byte generatedImmSize() {
-            return mImmSize > mTargetLabelSize ? mImmSize : mTargetLabelSize;
-        }
-
-        private int calculateTargetLabelOffset() throws IllegalInstructionException {
-            Instruction targetLabelInstruction;
-            if (mTargetLabel == DROP_LABEL) {
-                targetLabelInstruction = mDropLabel;
-            } else if (mTargetLabel == PASS_LABEL) {
-                targetLabelInstruction = mPassLabel;
-            } else {
-                targetLabelInstruction = mLabels.get(mTargetLabel);
-            }
-            if (targetLabelInstruction == null) {
-                throw new IllegalInstructionException("label not found: " + mTargetLabel);
-            }
-            // Calculate distance from end of this instruction to instruction.offset.
-            final int targetLabelOffset = targetLabelInstruction.offset - (offset + size());
-            if (targetLabelOffset < 0) {
-                throw new IllegalInstructionException("backward branches disallowed; label: " +
-                        mTargetLabel);
-            }
-            return targetLabelOffset;
-        }
-
-        private byte calculateImmSize(int imm, boolean signed) {
-            if (imm == 0) {
-                return 0;
-            }
-            if (signed && (imm >= -128 && imm <= 127) ||
-                    !signed && (imm >= 0 && imm <= 255)) {
-                return 1;
-            }
-            if (signed && (imm >= -32768 && imm <= 32767) ||
-                    !signed && (imm >= 0 && imm <= 65535)) {
-                return 2;
-            }
-            return 4;
-        }
-    }
-
-    /**
-     * Jump to this label to terminate the program and indicate the packet
-     * should be dropped.
-     */
-    public static final String DROP_LABEL = "__DROP__";
-
-    /**
-     * Jump to this label to terminate the program and indicate the packet
-     * should be passed to the AP.
-     */
-    public static final String PASS_LABEL = "__PASS__";
-
-    /**
-     * Number of memory slots available for access via APF stores to memory and loads from memory.
-     * The memory slots are numbered 0 to {@code MEMORY_SLOTS} - 1. This must be kept in sync with
-     * the APF interpreter.
-     */
-    public static final int MEMORY_SLOTS = 16;
-
-    /**
-     * Memory slot number that is prefilled with the IPv4 header length.
-     * Note that this memory slot may be overwritten by a program that
-     * executes stores to this memory slot. This must be kept in sync with
-     * the APF interpreter.
-     */
-    public static final int IPV4_HEADER_SIZE_MEMORY_SLOT = 13;
-
-    /**
-     * Memory slot number that is prefilled with the size of the packet being filtered in bytes.
-     * Note that this memory slot may be overwritten by a program that
-     * executes stores to this memory slot. This must be kept in sync with the APF interpreter.
-     */
-    public static final int PACKET_SIZE_MEMORY_SLOT = 14;
-
-    /**
-     * Memory slot number that is prefilled with the age of the filter in seconds. The age of the
-     * filter is the time since the filter was installed until now.
-     * Note that this memory slot may be overwritten by a program that
-     * executes stores to this memory slot. This must be kept in sync with the APF interpreter.
-     */
-    public static final int FILTER_AGE_MEMORY_SLOT = 15;
-
-    /**
-     * First memory slot containing prefilled values. Can be used in range comparisons to determine
-     * if memory slot index is within prefilled slots.
-     */
-    public static final int FIRST_PREFILLED_MEMORY_SLOT = IPV4_HEADER_SIZE_MEMORY_SLOT;
-
-    /**
-     * Last memory slot containing prefilled values. Can be used in range comparisons to determine
-     * if memory slot index is within prefilled slots.
-     */
-    public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT;
-
-    // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
-    private static final int MIN_APF_VERSION = 2;
-
-    private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>();
-    private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>();
-    private final Instruction mDropLabel = new Instruction(Opcodes.LABEL);
-    private final Instruction mPassLabel = new Instruction(Opcodes.LABEL);
-    private final int mVersion;
-    private boolean mGenerated;
-
-    /**
-     * Creates an ApfGenerator instance which is able to emit instructions for the specified
-     * {@code version} of the APF interpreter. Throws {@code IllegalInstructionException} if
-     * the requested version is unsupported.
-     */
-    ApfGenerator(int version) throws IllegalInstructionException {
-        mVersion = version;
-        requireApfVersion(MIN_APF_VERSION);
-    }
-
-    /**
-     * Returns true if the ApfGenerator supports the specified {@code version}, otherwise false.
-     */
-    public static boolean supportsVersion(int version) {
-        return version >= MIN_APF_VERSION;
-    }
-
-    private void requireApfVersion(int minimumVersion) throws IllegalInstructionException {
-        if (mVersion < minimumVersion) {
-            throw new IllegalInstructionException("Requires APF >= " + minimumVersion);
-        }
-    }
-
-    private void addInstruction(Instruction instruction) {
-        if (mGenerated) {
-            throw new IllegalStateException("Program already generated");
-        }
-        mInstructions.add(instruction);
-    }
-
-    /**
-     * Define a label at the current end of the program. Jumps can jump to this label. Labels are
-     * their own separate instructions, though with size 0. This facilitates having labels with
-     * no corresponding code to execute, for example a label at the end of a program. For example
-     * an {@link ApfGenerator} might be passed to a function that adds a filter like so:
-     * <pre>
-     *   load from packet
-     *   compare loaded data, jump if not equal to "next_filter"
-     *   load from packet
-     *   compare loaded data, jump if not equal to "next_filter"
-     *   jump to drop label
-     *   define "next_filter" here
-     * </pre>
-     * In this case "next_filter" may not have any generated code associated with it.
-     */
-    public ApfGenerator defineLabel(String name) throws IllegalInstructionException {
-        Instruction instruction = new Instruction(Opcodes.LABEL);
-        instruction.setLabel(name);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an unconditional jump instruction to the end of the program.
-     */
-    public ApfGenerator addJump(String target) {
-        Instruction instruction = new Instruction(Opcodes.JMP);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load the byte at offset {@code offset}
-     * bytes from the beginning of the packet into {@code register}.
-     */
-    public ApfGenerator addLoad8(Register register, int offset) {
-        Instruction instruction = new Instruction(Opcodes.LDB, register);
-        instruction.setUnsignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
-     * bytes from the beginning of the packet into {@code register}.
-     */
-    public ApfGenerator addLoad16(Register register, int offset) {
-        Instruction instruction = new Instruction(Opcodes.LDH, register);
-        instruction.setUnsignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
-     * bytes from the beginning of the packet into {@code register}.
-     */
-    public ApfGenerator addLoad32(Register register, int offset) {
-        Instruction instruction = new Instruction(Opcodes.LDW, register);
-        instruction.setUnsignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load a byte from the packet into
-     * {@code register}. The offset of the loaded byte from the beginning of the packet is
-     * the sum of {@code offset} and the value in register R1.
-     */
-    public ApfGenerator addLoad8Indexed(Register register, int offset) {
-        Instruction instruction = new Instruction(Opcodes.LDBX, register);
-        instruction.setUnsignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load 16-bits from the packet into
-     * {@code register}. The offset of the loaded 16-bits from the beginning of the packet is
-     * the sum of {@code offset} and the value in register R1.
-     */
-    public ApfGenerator addLoad16Indexed(Register register, int offset) {
-        Instruction instruction = new Instruction(Opcodes.LDHX, register);
-        instruction.setUnsignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load 32-bits from the packet into
-     * {@code register}. The offset of the loaded 32-bits from the beginning of the packet is
-     * the sum of {@code offset} and the value in register R1.
-     */
-    public ApfGenerator addLoad32Indexed(Register register, int offset) {
-        Instruction instruction = new Instruction(Opcodes.LDWX, register);
-        instruction.setUnsignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to add {@code value} to register R0.
-     */
-    public ApfGenerator addAdd(int value) {
-        Instruction instruction = new Instruction(Opcodes.ADD);
-        instruction.setSignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to multiply register R0 by {@code value}.
-     */
-    public ApfGenerator addMul(int value) {
-        Instruction instruction = new Instruction(Opcodes.MUL);
-        instruction.setSignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to divide register R0 by {@code value}.
-     */
-    public ApfGenerator addDiv(int value) {
-        Instruction instruction = new Instruction(Opcodes.DIV);
-        instruction.setSignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to logically and register R0 with {@code value}.
-     */
-    public ApfGenerator addAnd(int value) {
-        Instruction instruction = new Instruction(Opcodes.AND);
-        instruction.setUnsignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to logically or register R0 with {@code value}.
-     */
-    public ApfGenerator addOr(int value) {
-        Instruction instruction = new Instruction(Opcodes.OR);
-        instruction.setUnsignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to shift left register R0 by {@code value} bits.
-     */
-    public ApfGenerator addLeftShift(int value) {
-        Instruction instruction = new Instruction(Opcodes.SH);
-        instruction.setSignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to shift right register R0 by {@code value}
-     * bits.
-     */
-    public ApfGenerator addRightShift(int value) {
-        Instruction instruction = new Instruction(Opcodes.SH);
-        instruction.setSignedImm(-value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to add register R1 to register R0.
-     */
-    public ApfGenerator addAddR1() {
-        Instruction instruction = new Instruction(Opcodes.ADD, Register.R1);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to multiply register R0 by register R1.
-     */
-    public ApfGenerator addMulR1() {
-        Instruction instruction = new Instruction(Opcodes.MUL, Register.R1);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to divide register R0 by register R1.
-     */
-    public ApfGenerator addDivR1() {
-        Instruction instruction = new Instruction(Opcodes.DIV, Register.R1);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to logically and register R0 with register R1
-     * and store the result back into register R0.
-     */
-    public ApfGenerator addAndR1() {
-        Instruction instruction = new Instruction(Opcodes.AND, Register.R1);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to logically or register R0 with register R1
-     * and store the result back into register R0.
-     */
-    public ApfGenerator addOrR1() {
-        Instruction instruction = new Instruction(Opcodes.OR, Register.R1);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to shift register R0 left by the value in
-     * register R1.
-     */
-    public ApfGenerator addLeftShiftR1() {
-        Instruction instruction = new Instruction(Opcodes.SH, Register.R1);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to move {@code value} into {@code register}.
-     */
-    public ApfGenerator addLoadImmediate(Register register, int value) {
-        Instruction instruction = new Instruction(Opcodes.LI, register);
-        instruction.setSignedImm(value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value equals {@code value}.
-     */
-    public ApfGenerator addJumpIfR0Equals(int value, String target) {
-        Instruction instruction = new Instruction(Opcodes.JEQ);
-        instruction.setUnsignedImm(value);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value does not equal {@code value}.
-     */
-    public ApfGenerator addJumpIfR0NotEquals(int value, String target) {
-        Instruction instruction = new Instruction(Opcodes.JNE);
-        instruction.setUnsignedImm(value);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value is greater than {@code value}.
-     */
-    public ApfGenerator addJumpIfR0GreaterThan(int value, String target) {
-        Instruction instruction = new Instruction(Opcodes.JGT);
-        instruction.setUnsignedImm(value);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value is less than {@code value}.
-     */
-    public ApfGenerator addJumpIfR0LessThan(int value, String target) {
-        Instruction instruction = new Instruction(Opcodes.JLT);
-        instruction.setUnsignedImm(value);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value has any bits set that are also set in {@code value}.
-     */
-    public ApfGenerator addJumpIfR0AnyBitsSet(int value, String target) {
-        Instruction instruction = new Instruction(Opcodes.JSET);
-        instruction.setUnsignedImm(value);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value equals register R1's value.
-     */
-    public ApfGenerator addJumpIfR0EqualsR1(String target) {
-        Instruction instruction = new Instruction(Opcodes.JEQ, Register.R1);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value does not equal register R1's value.
-     */
-    public ApfGenerator addJumpIfR0NotEqualsR1(String target) {
-        Instruction instruction = new Instruction(Opcodes.JNE, Register.R1);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value is greater than register R1's value.
-     */
-    public ApfGenerator addJumpIfR0GreaterThanR1(String target) {
-        Instruction instruction = new Instruction(Opcodes.JGT, Register.R1);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value is less than register R1's value.
-     */
-    public ApfGenerator addJumpIfR0LessThanR1(String target) {
-        Instruction instruction = new Instruction(Opcodes.JLT, Register.R1);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if register R0's
-     * value has any bits set that are also set in R1's value.
-     */
-    public ApfGenerator addJumpIfR0AnyBitsSetR1(String target) {
-        Instruction instruction = new Instruction(Opcodes.JSET, Register.R1);
-        instruction.setTargetLabel(target);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to jump to {@code target} if the bytes of the
-     * packet at an offset specified by {@code register} match {@code bytes}.
-     */
-    public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target)
-            throws IllegalInstructionException {
-        if (register == Register.R1) {
-            throw new IllegalInstructionException("JNEBS fails with R1");
-        }
-        Instruction instruction = new Instruction(Opcodes.JNEBS, register);
-        instruction.setUnsignedImm(bytes.length);
-        instruction.setTargetLabel(target);
-        instruction.setCompareBytes(bytes);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load memory slot {@code slot} into
-     * {@code register}.
-     */
-    public ApfGenerator addLoadFromMemory(Register register, int slot)
-            throws IllegalInstructionException {
-        if (slot < 0 || slot > (MEMORY_SLOTS - 1)) {
-            throw new IllegalInstructionException("illegal memory slot number: " + slot);
-        }
-        Instruction instruction = new Instruction(Opcodes.EXT, register);
-        instruction.setUnsignedImm(ExtendedOpcodes.LDM.value + slot);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to store {@code register} into memory slot
-     * {@code slot}.
-     */
-    public ApfGenerator addStoreToMemory(Register register, int slot)
-            throws IllegalInstructionException {
-        if (slot < 0 || slot > (MEMORY_SLOTS - 1)) {
-            throw new IllegalInstructionException("illegal memory slot number: " + slot);
-        }
-        Instruction instruction = new Instruction(Opcodes.EXT, register);
-        instruction.setUnsignedImm(ExtendedOpcodes.STM.value + slot);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to logically not {@code register}.
-     */
-    public ApfGenerator addNot(Register register) {
-        Instruction instruction = new Instruction(Opcodes.EXT, register);
-        instruction.setUnsignedImm(ExtendedOpcodes.NOT.value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to negate {@code register}.
-     */
-    public ApfGenerator addNeg(Register register) {
-        Instruction instruction = new Instruction(Opcodes.EXT, register);
-        instruction.setUnsignedImm(ExtendedOpcodes.NEG.value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to swap the values in register R0 and register R1.
-     */
-    public ApfGenerator addSwap() {
-        Instruction instruction = new Instruction(Opcodes.EXT);
-        instruction.setUnsignedImm(ExtendedOpcodes.SWAP.value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to move the value into
-     * {@code register} from the other register.
-     */
-    public ApfGenerator addMove(Register register) {
-        Instruction instruction = new Instruction(Opcodes.EXT, register);
-        instruction.setUnsignedImm(ExtendedOpcodes.MOVE.value);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to load 32 bits from the data memory into
-     * {@code register}. The source address is computed by adding the signed immediate
-     * @{code offset} to the other register.
-     * Requires APF v3 or greater.
-     */
-    public ApfGenerator addLoadData(Register destinationRegister, int offset)
-            throws IllegalInstructionException {
-        requireApfVersion(3);
-        Instruction instruction = new Instruction(Opcodes.LDDW, destinationRegister);
-        instruction.setSignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Add an instruction to the end of the program to store 32 bits from {@code register} into the
-     * data memory. The destination address is computed by adding the signed immediate
-     * @{code offset} to the other register.
-     * Requires APF v3 or greater.
-     */
-    public ApfGenerator addStoreData(Register sourceRegister, int offset)
-            throws IllegalInstructionException {
-        requireApfVersion(3);
-        Instruction instruction = new Instruction(Opcodes.STDW, sourceRegister);
-        instruction.setSignedImm(offset);
-        addInstruction(instruction);
-        return this;
-    }
-
-    /**
-     * Updates instruction offset fields using latest instruction sizes.
-     * @return current program length in bytes.
-     */
-    private int updateInstructionOffsets() {
-        int offset = 0;
-        for (Instruction instruction : mInstructions) {
-            instruction.offset = offset;
-            offset += instruction.size();
-        }
-        return offset;
-    }
-
-    /**
-     * Returns an overestimate of the size of the generated program. {@link #generate} may return
-     * a program that is smaller.
-     */
-    public int programLengthOverEstimate() {
-        return updateInstructionOffsets();
-    }
-
-    /**
-     * Generate the bytecode for the APF program.
-     * @return the bytecode.
-     * @throws IllegalStateException if a label is referenced but not defined.
-     */
-    public byte[] generate() throws IllegalInstructionException {
-        // Enforce that we can only generate once because we cannot unshrink instructions and
-        // PASS/DROP labels may move further away requiring unshrinking if we add further
-        // instructions.
-        if (mGenerated) {
-            throw new IllegalStateException("Can only generate() once!");
-        }
-        mGenerated = true;
-        int total_size;
-        boolean shrunk;
-        // Shrink the immediate value fields of instructions.
-        // As we shrink the instructions some branch offset
-        // fields may shrink also, thereby shrinking the
-        // instructions further. Loop until we've reached the
-        // minimum size. Rarely will this loop more than a few times.
-        // Limit iterations to avoid O(n^2) behavior.
-        int iterations_remaining = 10;
-        do {
-            total_size = updateInstructionOffsets();
-            // Update drop and pass label offsets.
-            mDropLabel.offset = total_size + 1;
-            mPassLabel.offset = total_size;
-            // Limit run-time in aberant circumstances.
-            if (iterations_remaining-- == 0) break;
-            // Attempt to shrink instructions.
-            shrunk = false;
-            for (Instruction instruction : mInstructions) {
-                if (instruction.shrink()) {
-                    shrunk = true;
-                }
-            }
-        } while (shrunk);
-        // Generate bytecode for instructions.
-        byte[] bytecode = new byte[total_size];
-        for (Instruction instruction : mInstructions) {
-            instruction.generate(bytecode);
-        }
-        return bytecode;
-    }
-}
-
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpAckPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpAckPacket.java
deleted file mode 100644
index b2eb4e2..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpAckPacket.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the DHCP-ACK packet.
- */
-class DhcpAckPacket extends DhcpPacket {
-
-    /**
-     * The address of the server which sent this packet.
-     */
-    private final Inet4Address mSrcIp;
-
-    DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
-            Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
-        super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast);
-        mBroadcast = broadcast;
-        mSrcIp = serverAddress;
-    }
-
-    public String toString() {
-        String s = super.toString();
-        String dnsServers = " DNS servers: ";
-
-        for (Inet4Address dnsServer: mDnsServers) {
-            dnsServers += dnsServer.toString() + " ";
-        }
-
-        return s + " ACK: your new IP " + mYourIp +
-                ", netmask " + mSubnetMask +
-                ", gateways " + mGateways + dnsServers +
-                ", lease time " + mLeaseTime;
-    }
-
-    /**
-     * Fills in a packet with the requested ACK parameters.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-        Inet4Address destIp = mBroadcast ? INADDR_BROADCAST : mYourIp;
-        Inet4Address srcIp = mBroadcast ? INADDR_ANY : mSrcIp;
-
-        fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result,
-            DHCP_BOOTREPLY, mBroadcast);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds the optional parameters to the client-generated ACK packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_ACK);
-        addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
-
-        addCommonServerTlvs(buffer);
-        addTlvEnd(buffer);
-    }
-
-    /**
-     * Un-boxes an Integer, returning 0 if a null reference is supplied.
-     */
-    private static final int getInt(Integer v) {
-        if (v == null) {
-            return 0;
-        } else {
-            return v.intValue();
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
deleted file mode 100644
index ca6c17a..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ /dev/null
@@ -1,1070 +0,0 @@
-/*
- * Copyright (C) 2015 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.dhcp;
-
-import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
-import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
-import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
-import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_MTU;
-import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
-import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
-import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
-import static android.net.dhcp.DhcpPacket.INADDR_ANY;
-import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
-import static android.net.util.NetworkStackUtils.closeSocketQuietly;
-import static android.net.util.SocketUtils.makePacketSocketAddress;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_PACKET;
-import static android.system.OsConstants.ETH_P_IP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_RAW;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_BROADCAST;
-import static android.system.OsConstants.SO_RCVBUF;
-import static android.system.OsConstants.SO_REUSEADDR;
-
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-
-import android.content.Context;
-import android.net.DhcpResults;
-import android.net.InetAddresses;
-import android.net.TrafficStats;
-import android.net.ip.IpClient;
-import android.net.metrics.DhcpClientEvent;
-import android.net.metrics.DhcpErrorEvent;
-import android.net.metrics.IpConnectivityLog;
-import android.net.util.InterfaceParams;
-import android.net.util.NetworkStackUtils;
-import android.net.util.SocketUtils;
-import android.os.Message;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.util.HexDump;
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.internal.util.TrafficStatsConstants;
-import com.android.internal.util.WakeupMessage;
-import com.android.networkstack.R;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-
-/**
- * A DHCPv4 client.
- *
- * Written to behave similarly to the DhcpStateMachine + dhcpcd 5.5.6 combination used in Android
- * 5.1 and below, as configured on Nexus 6. The interface is the same as DhcpStateMachine.
- *
- * TODO:
- *
- * - Exponential backoff when receiving NAKs (not specified by the RFC, but current behaviour).
- * - Support persisting lease state and support INIT-REBOOT. Android 5.1 does this, but it does not
- *   do so correctly: instead of requesting the lease last obtained on a particular network (e.g., a
- *   given SSID), it requests the last-leased IP address on the same interface, causing a delay if
- *   the server NAKs or a timeout if it doesn't.
- *
- * Known differences from current behaviour:
- *
- * - Does not request the "static routes" option.
- * - Does not support BOOTP servers. DHCP has been around since 1993, should be everywhere now.
- * - Requests the "broadcast" option, but does nothing with it.
- * - Rejects invalid subnet masks such as 255.255.255.1 (current code treats that as 255.255.255.0).
- *
- * @hide
- */
-public class DhcpClient extends StateMachine {
-
-    private static final String TAG = "DhcpClient";
-    private static final boolean DBG = true;
-    private static final boolean STATE_DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean MSG_DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean PACKET_DBG = Log.isLoggable(TAG, Log.DEBUG);
-
-    // Metrics events: must be kept in sync with server-side aggregation code.
-    /** Represents transitions from DhcpInitState to DhcpBoundState */
-    private static final String EVENT_INITIAL_BOUND = "InitialBoundState";
-    /** Represents transitions from and to DhcpBoundState via DhcpRenewingState */
-    private static final String EVENT_RENEWING_BOUND = "RenewingBoundState";
-
-    // Timers and timeouts.
-    private static final int SECONDS = 1000;
-    private static final int FIRST_TIMEOUT_MS   =   2 * SECONDS;
-    private static final int MAX_TIMEOUT_MS     = 128 * SECONDS;
-
-    // This is not strictly needed, since the client is asynchronous and implements exponential
-    // backoff. It's maintained for backwards compatibility with the previous DHCP code, which was
-    // a blocking operation with a 30-second timeout. We pick 36 seconds so we can send packets at
-    // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
-    private static final int DHCP_TIMEOUT_MS    =  36 * SECONDS;
-
-    // DhcpClient uses IpClient's handler.
-    private static final int PUBLIC_BASE = IpClient.DHCPCLIENT_CMD_BASE;
-
-    // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
-    /* Commands from controller to start/stop DHCP */
-    public static final int CMD_START_DHCP                  = PUBLIC_BASE + 1;
-    public static final int CMD_STOP_DHCP                   = PUBLIC_BASE + 2;
-
-    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
-    public static final int CMD_PRE_DHCP_ACTION             = PUBLIC_BASE + 3;
-    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
-     * success/failure */
-    public static final int CMD_POST_DHCP_ACTION            = PUBLIC_BASE + 4;
-    /* Notification from DHCP state machine before quitting */
-    public static final int CMD_ON_QUIT                     = PUBLIC_BASE + 5;
-
-    /* Command from controller to indicate DHCP discovery/renewal can continue
-     * after pre DHCP action is complete */
-    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = PUBLIC_BASE + 6;
-
-    /* Command and event notification to/from IpManager requesting the setting
-     * (or clearing) of an IPv4 LinkAddress.
-     */
-    public static final int CMD_CLEAR_LINKADDRESS           = PUBLIC_BASE + 7;
-    public static final int CMD_CONFIGURE_LINKADDRESS       = PUBLIC_BASE + 8;
-    public static final int EVENT_LINKADDRESS_CONFIGURED    = PUBLIC_BASE + 9;
-
-    /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */
-    public static final int DHCP_SUCCESS = 1;
-    public static final int DHCP_FAILURE = 2;
-
-    // Internal messages.
-    private static final int PRIVATE_BASE         = IpClient.DHCPCLIENT_CMD_BASE + 100;
-    private static final int CMD_KICK             = PRIVATE_BASE + 1;
-    private static final int CMD_RECEIVED_PACKET  = PRIVATE_BASE + 2;
-    private static final int CMD_TIMEOUT          = PRIVATE_BASE + 3;
-    private static final int CMD_RENEW_DHCP       = PRIVATE_BASE + 4;
-    private static final int CMD_REBIND_DHCP      = PRIVATE_BASE + 5;
-    private static final int CMD_EXPIRE_DHCP      = PRIVATE_BASE + 6;
-
-    // For message logging.
-    private static final Class[] sMessageClasses = { DhcpClient.class };
-    private static final SparseArray<String> sMessageNames =
-            MessageUtils.findMessageNames(sMessageClasses);
-
-    // DHCP parameters that we request.
-    /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
-        DHCP_SUBNET_MASK,
-        DHCP_ROUTER,
-        DHCP_DNS_SERVER,
-        DHCP_DOMAIN_NAME,
-        DHCP_MTU,
-        DHCP_BROADCAST_ADDRESS,  // TODO: currently ignored.
-        DHCP_LEASE_TIME,
-        DHCP_RENEWAL_TIME,
-        DHCP_REBINDING_TIME,
-        DHCP_VENDOR_INFO,
-    };
-
-    // DHCP flag that means "yes, we support unicast."
-    private static final boolean DO_UNICAST   = false;
-
-    // System services / libraries we use.
-    private final Context mContext;
-    private final Random mRandom;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-
-    // Sockets.
-    // - We use a packet socket to receive, because servers send us packets bound for IP addresses
-    //   which we have not yet configured, and the kernel protocol stack drops these.
-    // - We use a UDP socket to send, so the kernel handles ARP and routing for us (DHCP servers can
-    //   be off-link as well as on-link).
-    private FileDescriptor mPacketSock;
-    private FileDescriptor mUdpSock;
-    private ReceiveThread mReceiveThread;
-
-    // State variables.
-    private final StateMachine mController;
-    private final WakeupMessage mKickAlarm;
-    private final WakeupMessage mTimeoutAlarm;
-    private final WakeupMessage mRenewAlarm;
-    private final WakeupMessage mRebindAlarm;
-    private final WakeupMessage mExpiryAlarm;
-    private final String mIfaceName;
-
-    private boolean mRegisteredForPreDhcpNotification;
-    private InterfaceParams mIface;
-    // TODO: MacAddress-ify more of this class hierarchy.
-    private byte[] mHwAddr;
-    private SocketAddress mInterfaceBroadcastAddr;
-    private int mTransactionId;
-    private long mTransactionStartMillis;
-    private DhcpResults mDhcpLease;
-    private long mDhcpLeaseExpiry;
-    private DhcpResults mOffer;
-
-    // Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
-    private long mLastInitEnterTime;
-    private long mLastBoundExitTime;
-
-    // States.
-    private State mStoppedState = new StoppedState();
-    private State mDhcpState = new DhcpState();
-    private State mDhcpInitState = new DhcpInitState();
-    private State mDhcpSelectingState = new DhcpSelectingState();
-    private State mDhcpRequestingState = new DhcpRequestingState();
-    private State mDhcpHaveLeaseState = new DhcpHaveLeaseState();
-    private State mConfiguringInterfaceState = new ConfiguringInterfaceState();
-    private State mDhcpBoundState = new DhcpBoundState();
-    private State mDhcpRenewingState = new DhcpRenewingState();
-    private State mDhcpRebindingState = new DhcpRebindingState();
-    private State mDhcpInitRebootState = new DhcpInitRebootState();
-    private State mDhcpRebootingState = new DhcpRebootingState();
-    private State mWaitBeforeStartState = new WaitBeforeStartState(mDhcpInitState);
-    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(mDhcpRenewingState);
-
-    private WakeupMessage makeWakeupMessage(String cmdName, int cmd) {
-        cmdName = DhcpClient.class.getSimpleName() + "." + mIfaceName + "." + cmdName;
-        return new WakeupMessage(mContext, getHandler(), cmdName, cmd);
-    }
-
-    // TODO: Take an InterfaceParams instance instead of an interface name String.
-    private DhcpClient(Context context, StateMachine controller, String iface) {
-        super(TAG, controller.getHandler());
-
-        mContext = context;
-        mController = controller;
-        mIfaceName = iface;
-
-        addState(mStoppedState);
-        addState(mDhcpState);
-            addState(mDhcpInitState, mDhcpState);
-            addState(mWaitBeforeStartState, mDhcpState);
-            addState(mDhcpSelectingState, mDhcpState);
-            addState(mDhcpRequestingState, mDhcpState);
-            addState(mDhcpHaveLeaseState, mDhcpState);
-                addState(mConfiguringInterfaceState, mDhcpHaveLeaseState);
-                addState(mDhcpBoundState, mDhcpHaveLeaseState);
-                addState(mWaitBeforeRenewalState, mDhcpHaveLeaseState);
-                addState(mDhcpRenewingState, mDhcpHaveLeaseState);
-                addState(mDhcpRebindingState, mDhcpHaveLeaseState);
-            addState(mDhcpInitRebootState, mDhcpState);
-            addState(mDhcpRebootingState, mDhcpState);
-
-        setInitialState(mStoppedState);
-
-        mRandom = new Random();
-
-        // Used to schedule packet retransmissions.
-        mKickAlarm = makeWakeupMessage("KICK", CMD_KICK);
-        // Used to time out PacketRetransmittingStates.
-        mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
-        // Used to schedule DHCP reacquisition.
-        mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
-        mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
-        mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);
-    }
-
-    public void registerForPreDhcpNotification() {
-        mRegisteredForPreDhcpNotification = true;
-    }
-
-    public static DhcpClient makeDhcpClient(
-            Context context, StateMachine controller, InterfaceParams ifParams) {
-        DhcpClient client = new DhcpClient(context, controller, ifParams.name);
-        client.mIface = ifParams;
-        client.start();
-        return client;
-    }
-
-    private boolean initInterface() {
-        if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName);
-        if (mIface == null) {
-            Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName);
-            return false;
-        }
-
-        mHwAddr = mIface.macAddr.toByteArray();
-        mInterfaceBroadcastAddr = makePacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST);
-        return true;
-    }
-
-    private void startNewTransaction() {
-        mTransactionId = mRandom.nextInt();
-        mTransactionStartMillis = SystemClock.elapsedRealtime();
-    }
-
-    private boolean initSockets() {
-        return initPacketSocket() && initUdpSocket();
-    }
-
-    private boolean initPacketSocket() {
-        try {
-            mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
-            SocketAddress addr = makePacketSocketAddress((short) ETH_P_IP, mIface.index);
-            Os.bind(mPacketSock, addr);
-            NetworkStackUtils.attachDhcpFilter(mPacketSock);
-        } catch(SocketException|ErrnoException e) {
-            Log.e(TAG, "Error creating packet socket", e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean initUdpSocket() {
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                TrafficStatsConstants.TAG_SYSTEM_DHCP);
-        try {
-            mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-            SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName);
-            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
-            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
-            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
-            Os.bind(mUdpSock, IPV4_ADDR_ANY, DhcpPacket.DHCP_CLIENT);
-        } catch(SocketException|ErrnoException e) {
-            Log.e(TAG, "Error creating UDP socket", e);
-            return false;
-        } finally {
-            TrafficStats.setThreadStatsTag(oldTag);
-        }
-        return true;
-    }
-
-    private boolean connectUdpSock(Inet4Address to) {
-        try {
-            Os.connect(mUdpSock, to, DhcpPacket.DHCP_SERVER);
-            return true;
-        } catch (SocketException|ErrnoException e) {
-            Log.e(TAG, "Error connecting UDP socket", e);
-            return false;
-        }
-    }
-
-    private void closeSockets() {
-        closeSocketQuietly(mUdpSock);
-        closeSocketQuietly(mPacketSock);
-    }
-
-    class ReceiveThread extends Thread {
-
-        private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
-        private volatile boolean mStopped = false;
-
-        public void halt() {
-            mStopped = true;
-            closeSockets();  // Interrupts the read() call the thread is blocked in.
-        }
-
-        @Override
-        public void run() {
-            if (DBG) Log.d(TAG, "Receive thread started");
-            while (!mStopped) {
-                int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
-                try {
-                    length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
-                    DhcpPacket packet = null;
-                    packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
-                    if (DBG) Log.d(TAG, "Received packet: " + packet);
-                    sendMessage(CMD_RECEIVED_PACKET, packet);
-                } catch (IOException|ErrnoException e) {
-                    if (!mStopped) {
-                        Log.e(TAG, "Read error", e);
-                        logError(DhcpErrorEvent.RECEIVE_ERROR);
-                    }
-                } catch (DhcpPacket.ParseException e) {
-                    Log.e(TAG, "Can't parse packet: " + e.getMessage());
-                    if (PACKET_DBG) {
-                        Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
-                    }
-                    if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
-                        int snetTagId = 0x534e4554;
-                        String bugId = "31850211";
-                        int uid = -1;
-                        String data = DhcpPacket.ParseException.class.getName();
-                        EventLog.writeEvent(snetTagId, bugId, uid, data);
-                    }
-                    logError(e.errorCode);
-                }
-            }
-            if (DBG) Log.d(TAG, "Receive thread stopped");
-        }
-    }
-
-    private short getSecs() {
-        return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000);
-    }
-
-    private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) {
-        try {
-            if (encap == DhcpPacket.ENCAP_L2) {
-                if (DBG) Log.d(TAG, "Broadcasting " + description);
-                Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
-            } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) {
-                if (DBG) Log.d(TAG, "Broadcasting " + description);
-                // We only send L3-encapped broadcasts in DhcpRebindingState,
-                // where we have an IP address and an unconnected UDP socket.
-                //
-                // N.B.: We only need this codepath because DhcpRequestPacket
-                // hardcodes the source IP address to 0.0.0.0. We could reuse
-                // the packet socket if this ever changes.
-                Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
-            } else {
-                // It's safe to call getpeername here, because we only send unicast packets if we
-                // have an IP address, and we connect the UDP socket in DhcpBoundState#enter.
-                if (DBG) Log.d(TAG, String.format("Unicasting %s to %s",
-                        description, Os.getpeername(mUdpSock)));
-                Os.write(mUdpSock, buf);
-            }
-        } catch(ErrnoException|IOException e) {
-            Log.e(TAG, "Can't send packet: ", e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean sendDiscoverPacket() {
-        ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
-                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
-                DO_UNICAST, REQUESTED_PARAMS);
-        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
-    }
-
-    private boolean sendRequestPacket(
-            Inet4Address clientAddress, Inet4Address requestedAddress,
-            Inet4Address serverAddress, Inet4Address to) {
-        // TODO: should we use the transaction ID from the server?
-        final int encap = INADDR_ANY.equals(clientAddress)
-                ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
-
-        ByteBuffer packet = DhcpPacket.buildRequestPacket(
-                encap, mTransactionId, getSecs(), clientAddress,
-                DO_UNICAST, mHwAddr, requestedAddress,
-                serverAddress, REQUESTED_PARAMS, null);
-        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
-        String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
-                             " request=" + requestedAddress.getHostAddress() +
-                             " serverid=" + serverStr;
-        return transmitPacket(packet, description, encap, to);
-    }
-
-    private void scheduleLeaseTimers() {
-        if (mDhcpLeaseExpiry == 0) {
-            Log.d(TAG, "Infinite lease, no timer scheduling needed");
-            return;
-        }
-
-        final long now = SystemClock.elapsedRealtime();
-
-        // TODO: consider getting the renew and rebind timers from T1 and T2.
-        // See also:
-        //     https://tools.ietf.org/html/rfc2131#section-4.4.5
-        //     https://tools.ietf.org/html/rfc1533#section-9.9
-        //     https://tools.ietf.org/html/rfc1533#section-9.10
-        final long remainingDelay = mDhcpLeaseExpiry - now;
-        final long renewDelay = remainingDelay / 2;
-        final long rebindDelay = remainingDelay * 7 / 8;
-        mRenewAlarm.schedule(now + renewDelay);
-        mRebindAlarm.schedule(now + rebindDelay);
-        mExpiryAlarm.schedule(now + remainingDelay);
-        Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s");
-        Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s");
-        Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s");
-    }
-
-    private void notifySuccess() {
-        mController.sendMessage(
-                CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
-    }
-
-    private void notifyFailure() {
-        mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
-    }
-
-    private void acceptDhcpResults(DhcpResults results, String msg) {
-        mDhcpLease = results;
-        if (mDhcpLease.dnsServers.isEmpty()) {
-            // supplement customized dns servers
-            String[] dnsServersList =
-                    mContext.getResources().getStringArray(R.array.config_default_dns_servers);
-            for (final String dnsServer : dnsServersList) {
-                try {
-                    mDhcpLease.dnsServers.add(InetAddresses.parseNumericAddress(dnsServer));
-                } catch (IllegalArgumentException e) {
-                    Log.e(TAG, "Invalid default DNS server: " + dnsServer, e);
-                }
-            }
-        }
-        mOffer = null;
-        Log.d(TAG, msg + " lease: " + mDhcpLease);
-        notifySuccess();
-    }
-
-    private void clearDhcpState() {
-        mDhcpLease = null;
-        mDhcpLeaseExpiry = 0;
-        mOffer = null;
-    }
-
-    /**
-     * Quit the DhcpStateMachine.
-     *
-     * @hide
-     */
-    public void doQuit() {
-        Log.d(TAG, "doQuit");
-        quit();
-    }
-
-    @Override
-    protected void onQuitting() {
-        Log.d(TAG, "onQuitting");
-        mController.sendMessage(CMD_ON_QUIT);
-    }
-
-    abstract class LoggingState extends State {
-        private long mEnterTimeMs;
-
-        @Override
-        public void enter() {
-            if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
-            mEnterTimeMs = SystemClock.elapsedRealtime();
-        }
-
-        @Override
-        public void exit() {
-            long durationMs = SystemClock.elapsedRealtime() - mEnterTimeMs;
-            logState(getName(), (int) durationMs);
-        }
-
-        private String messageName(int what) {
-            return sMessageNames.get(what, Integer.toString(what));
-        }
-
-        private String messageToString(Message message) {
-            long now = SystemClock.uptimeMillis();
-            return new StringBuilder(" ")
-                    .append(message.getWhen() - now)
-                    .append(messageName(message.what))
-                    .append(" ").append(message.arg1)
-                    .append(" ").append(message.arg2)
-                    .append(" ").append(message.obj)
-                    .toString();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (MSG_DBG) {
-                Log.d(TAG, getName() + messageToString(message));
-            }
-            return NOT_HANDLED;
-        }
-
-        @Override
-        public String getName() {
-            // All DhcpClient's states are inner classes with a well defined name.
-            // Use getSimpleName() and avoid super's getName() creating new String instances.
-            return getClass().getSimpleName();
-        }
-    }
-
-    // Sends CMD_PRE_DHCP_ACTION to the controller, waits for the controller to respond with
-    // CMD_PRE_DHCP_ACTION_COMPLETE, and then transitions to mOtherState.
-    abstract class WaitBeforeOtherState extends LoggingState {
-        protected State mOtherState;
-
-        @Override
-        public void enter() {
-            super.enter();
-            mController.sendMessage(CMD_PRE_DHCP_ACTION);
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    transitionTo(mOtherState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    class StoppedState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_START_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        transitionTo(mWaitBeforeStartState);
-                    } else {
-                        transitionTo(mDhcpInitState);
-                    }
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    class WaitBeforeStartState extends WaitBeforeOtherState {
-        public WaitBeforeStartState(State otherState) {
-            super();
-            mOtherState = otherState;
-        }
-    }
-
-    class WaitBeforeRenewalState extends WaitBeforeOtherState {
-        public WaitBeforeRenewalState(State otherState) {
-            super();
-            mOtherState = otherState;
-        }
-    }
-
-    class DhcpState extends State {
-        @Override
-        public void enter() {
-            clearDhcpState();
-            if (initInterface() && initSockets()) {
-                mReceiveThread = new ReceiveThread();
-                mReceiveThread.start();
-            } else {
-                notifyFailure();
-                transitionTo(mStoppedState);
-            }
-        }
-
-        @Override
-        public void exit() {
-            if (mReceiveThread != null) {
-                mReceiveThread.halt();  // Also closes sockets.
-                mReceiveThread = null;
-            }
-            clearDhcpState();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_STOP_DHCP:
-                    transitionTo(mStoppedState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    public boolean isValidPacket(DhcpPacket packet) {
-        // TODO: check checksum.
-        int xid = packet.getTransactionId();
-        if (xid != mTransactionId) {
-            Log.d(TAG, "Unexpected transaction ID " + xid + ", expected " + mTransactionId);
-            return false;
-        }
-        if (!Arrays.equals(packet.getClientMac(), mHwAddr)) {
-            Log.d(TAG, "MAC addr mismatch: got " +
-                    HexDump.toHexString(packet.getClientMac()) + ", expected " +
-                    HexDump.toHexString(packet.getClientMac()));
-            return false;
-        }
-        return true;
-    }
-
-    public void setDhcpLeaseExpiry(DhcpPacket packet) {
-        long leaseTimeMillis = packet.getLeaseTimeMillis();
-        mDhcpLeaseExpiry =
-                (leaseTimeMillis > 0) ? SystemClock.elapsedRealtime() + leaseTimeMillis : 0;
-    }
-
-    /**
-     * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
-     * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass
-     * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout
-     * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the
-     * state.
-     *
-     * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
-     * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
-     * sent by the receive thread. They may also set mTimeout and implement timeout.
-     */
-    abstract class PacketRetransmittingState extends LoggingState {
-
-        private int mTimer;
-        protected int mTimeout = 0;
-
-        @Override
-        public void enter() {
-            super.enter();
-            initTimer();
-            maybeInitTimeout();
-            sendMessage(CMD_KICK);
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_KICK:
-                    sendPacket();
-                    scheduleKick();
-                    return HANDLED;
-                case CMD_RECEIVED_PACKET:
-                    receivePacket((DhcpPacket) message.obj);
-                    return HANDLED;
-                case CMD_TIMEOUT:
-                    timeout();
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            super.exit();
-            mKickAlarm.cancel();
-            mTimeoutAlarm.cancel();
-        }
-
-        abstract protected boolean sendPacket();
-        abstract protected void receivePacket(DhcpPacket packet);
-        protected void timeout() {}
-
-        protected void initTimer() {
-            mTimer = FIRST_TIMEOUT_MS;
-        }
-
-        protected int jitterTimer(int baseTimer) {
-            int maxJitter = baseTimer / 10;
-            int jitter = mRandom.nextInt(2 * maxJitter) - maxJitter;
-            return baseTimer + jitter;
-        }
-
-        protected void scheduleKick() {
-            long now = SystemClock.elapsedRealtime();
-            long timeout = jitterTimer(mTimer);
-            long alarmTime = now + timeout;
-            mKickAlarm.schedule(alarmTime);
-            mTimer *= 2;
-            if (mTimer > MAX_TIMEOUT_MS) {
-                mTimer = MAX_TIMEOUT_MS;
-            }
-        }
-
-        protected void maybeInitTimeout() {
-            if (mTimeout > 0) {
-                long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
-                mTimeoutAlarm.schedule(alarmTime);
-            }
-        }
-    }
-
-    class DhcpInitState extends PacketRetransmittingState {
-        public DhcpInitState() {
-            super();
-        }
-
-        @Override
-        public void enter() {
-            super.enter();
-            startNewTransaction();
-            mLastInitEnterTime = SystemClock.elapsedRealtime();
-        }
-
-        protected boolean sendPacket() {
-            return sendDiscoverPacket();
-        }
-
-        protected void receivePacket(DhcpPacket packet) {
-            if (!isValidPacket(packet)) return;
-            if (!(packet instanceof DhcpOfferPacket)) return;
-            mOffer = packet.toDhcpResults();
-            if (mOffer != null) {
-                Log.d(TAG, "Got pending lease: " + mOffer);
-                transitionTo(mDhcpRequestingState);
-            }
-        }
-    }
-
-    // Not implemented. We request the first offer we receive.
-    class DhcpSelectingState extends LoggingState {
-    }
-
-    class DhcpRequestingState extends PacketRetransmittingState {
-        public DhcpRequestingState() {
-            mTimeout = DHCP_TIMEOUT_MS / 2;
-        }
-
-        protected boolean sendPacket() {
-            return sendRequestPacket(
-                    INADDR_ANY,                                    // ciaddr
-                    (Inet4Address) mOffer.ipAddress.getAddress(),  // DHCP_REQUESTED_IP
-                    (Inet4Address) mOffer.serverAddress,           // DHCP_SERVER_IDENTIFIER
-                    INADDR_BROADCAST);                             // packet destination address
-        }
-
-        protected void receivePacket(DhcpPacket packet) {
-            if (!isValidPacket(packet)) return;
-            if ((packet instanceof DhcpAckPacket)) {
-                DhcpResults results = packet.toDhcpResults();
-                if (results != null) {
-                    setDhcpLeaseExpiry(packet);
-                    acceptDhcpResults(results, "Confirmed");
-                    transitionTo(mConfiguringInterfaceState);
-                }
-            } else if (packet instanceof DhcpNakPacket) {
-                // TODO: Wait a while before returning into INIT state.
-                Log.d(TAG, "Received NAK, returning to INIT");
-                mOffer = null;
-                transitionTo(mDhcpInitState);
-            }
-        }
-
-        @Override
-        protected void timeout() {
-            // After sending REQUESTs unsuccessfully for a while, go back to init.
-            transitionTo(mDhcpInitState);
-        }
-    }
-
-    class DhcpHaveLeaseState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_EXPIRE_DHCP:
-                    Log.d(TAG, "Lease expired!");
-                    notifyFailure();
-                    transitionTo(mDhcpInitState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            // Clear any extant alarms.
-            mRenewAlarm.cancel();
-            mRebindAlarm.cancel();
-            mExpiryAlarm.cancel();
-            clearDhcpState();
-            // Tell IpManager to clear the IPv4 address. There is no need to
-            // wait for confirmation since any subsequent packets are sent from
-            // INADDR_ANY anyway (DISCOVER, REQUEST).
-            mController.sendMessage(CMD_CLEAR_LINKADDRESS);
-        }
-    }
-
-    class ConfiguringInterfaceState extends LoggingState {
-        @Override
-        public void enter() {
-            super.enter();
-            mController.sendMessage(CMD_CONFIGURE_LINKADDRESS, mDhcpLease.ipAddress);
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case EVENT_LINKADDRESS_CONFIGURED:
-                    transitionTo(mDhcpBoundState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    class DhcpBoundState extends LoggingState {
-        @Override
-        public void enter() {
-            super.enter();
-            if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) {
-                // There's likely no point in going into DhcpInitState here, we'll probably
-                // just repeat the transaction, get the same IP address as before, and fail.
-                //
-                // NOTE: It is observed that connectUdpSock() basically never fails, due to
-                // SO_BINDTODEVICE. Examining the local socket address shows it will happily
-                // return an IPv4 address from another interface, or even return "0.0.0.0".
-                //
-                // TODO: Consider deleting this check, following testing on several kernels.
-                notifyFailure();
-                transitionTo(mStoppedState);
-            }
-
-            scheduleLeaseTimers();
-            logTimeToBoundState();
-        }
-
-        @Override
-        public void exit() {
-            super.exit();
-            mLastBoundExitTime = SystemClock.elapsedRealtime();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_RENEW_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        transitionTo(mWaitBeforeRenewalState);
-                    } else {
-                        transitionTo(mDhcpRenewingState);
-                    }
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        private void logTimeToBoundState() {
-            long now = SystemClock.elapsedRealtime();
-            if (mLastBoundExitTime > mLastInitEnterTime) {
-                logState(EVENT_RENEWING_BOUND, (int) (now - mLastBoundExitTime));
-            } else {
-                logState(EVENT_INITIAL_BOUND, (int) (now - mLastInitEnterTime));
-            }
-        }
-    }
-
-    abstract class DhcpReacquiringState extends PacketRetransmittingState {
-        protected String mLeaseMsg;
-
-        @Override
-        public void enter() {
-            super.enter();
-            startNewTransaction();
-        }
-
-        abstract protected Inet4Address packetDestination();
-
-        protected boolean sendPacket() {
-            return sendRequestPacket(
-                    (Inet4Address) mDhcpLease.ipAddress.getAddress(),  // ciaddr
-                    INADDR_ANY,                                        // DHCP_REQUESTED_IP
-                    null,                                              // DHCP_SERVER_IDENTIFIER
-                    packetDestination());                              // packet destination address
-        }
-
-        protected void receivePacket(DhcpPacket packet) {
-            if (!isValidPacket(packet)) return;
-            if ((packet instanceof DhcpAckPacket)) {
-                final DhcpResults results = packet.toDhcpResults();
-                if (results != null) {
-                    if (!mDhcpLease.ipAddress.equals(results.ipAddress)) {
-                        Log.d(TAG, "Renewed lease not for our current IP address!");
-                        notifyFailure();
-                        transitionTo(mDhcpInitState);
-                    }
-                    setDhcpLeaseExpiry(packet);
-                    // Updating our notion of DhcpResults here only causes the
-                    // DNS servers and routes to be updated in LinkProperties
-                    // in IpManager and by any overridden relevant handlers of
-                    // the registered IpManager.Callback.  IP address changes
-                    // are not supported here.
-                    acceptDhcpResults(results, mLeaseMsg);
-                    transitionTo(mDhcpBoundState);
-                }
-            } else if (packet instanceof DhcpNakPacket) {
-                Log.d(TAG, "Received NAK, returning to INIT");
-                notifyFailure();
-                transitionTo(mDhcpInitState);
-            }
-        }
-    }
-
-    class DhcpRenewingState extends DhcpReacquiringState {
-        public DhcpRenewingState() {
-            mLeaseMsg = "Renewed";
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (super.processMessage(message) == HANDLED) {
-                return HANDLED;
-            }
-
-            switch (message.what) {
-                case CMD_REBIND_DHCP:
-                    transitionTo(mDhcpRebindingState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        protected Inet4Address packetDestination() {
-            // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
-            // http://b/25343517 . Try to make things work anyway by using broadcast renews.
-            return (mDhcpLease.serverAddress != null) ?
-                    mDhcpLease.serverAddress : INADDR_BROADCAST;
-        }
-    }
-
-    class DhcpRebindingState extends DhcpReacquiringState {
-        public DhcpRebindingState() {
-            mLeaseMsg = "Rebound";
-        }
-
-        @Override
-        public void enter() {
-            super.enter();
-
-            // We need to broadcast and possibly reconnect the socket to a
-            // completely different server.
-            closeSocketQuietly(mUdpSock);
-            if (!initUdpSocket()) {
-                Log.e(TAG, "Failed to recreate UDP socket");
-                transitionTo(mDhcpInitState);
-            }
-        }
-
-        @Override
-        protected Inet4Address packetDestination() {
-            return INADDR_BROADCAST;
-        }
-    }
-
-    class DhcpInitRebootState extends LoggingState {
-    }
-
-    class DhcpRebootingState extends LoggingState {
-    }
-
-    private void logError(int errorCode) {
-        mMetricsLog.log(mIfaceName, new DhcpErrorEvent(errorCode));
-    }
-
-    private void logState(String name, int durationMs) {
-        final DhcpClientEvent event = new DhcpClientEvent.Builder()
-                .setMsg(name)
-                .setDurationMs(durationMs)
-                .build();
-        mMetricsLog.log(mIfaceName, event);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpDeclinePacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpDeclinePacket.java
deleted file mode 100644
index 7ecdea7..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpDeclinePacket.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the DHCP-DECLINE packet.
- */
-class DhcpDeclinePacket extends DhcpPacket {
-    /**
-     * Generates a DECLINE packet with the specified parameters.
-     */
-    DhcpDeclinePacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
-                      Inet4Address nextIp, Inet4Address relayIp,
-                      byte[] clientMac) {
-        super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false);
-    }
-
-    public String toString() {
-        String s = super.toString();
-        return s + " DECLINE";
-    }
-
-    /**
-     * Fills in a packet with the requested DECLINE attributes.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-
-        fillInPacket(encap, mClientIp, mYourIp, destUdp, srcUdp, result,
-            DHCP_BOOTREQUEST, false);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds optional parameters to the DECLINE packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DECLINE);
-        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
-        // RFC 2131 says we MUST NOT include our common client TLVs or the parameter request list.
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java
deleted file mode 100644
index 11f2b61..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the DHCP-DISCOVER packet.
- */
-class DhcpDiscoverPacket extends DhcpPacket {
-    /**
-     * The IP address of the client which sent this packet.
-     */
-    final Inet4Address mSrcIp;
-
-    /**
-     * Generates a DISCOVER packet with the specified parameters.
-     */
-    DhcpDiscoverPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac,
-            boolean broadcast, Inet4Address srcIp) {
-        super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast);
-        mSrcIp = srcIp;
-    }
-
-    public String toString() {
-        String s = super.toString();
-        return s + " DISCOVER " +
-                (mBroadcast ? "broadcast " : "unicast ");
-    }
-
-    /**
-     * Fills in a packet with the requested DISCOVER parameters.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-        fillInPacket(encap, INADDR_BROADCAST, mSrcIp, destUdp, srcUdp, result, DHCP_BOOTREQUEST,
-                mBroadcast);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds optional parameters to a DISCOVER packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DISCOVER);
-        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
-        addCommonClientTlvs(buffer);
-        addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpInformPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpInformPacket.java
deleted file mode 100644
index 7a83466..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpInformPacket.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the (unused) DHCP-INFORM packet.
- */
-class DhcpInformPacket extends DhcpPacket {
-    /**
-     * Generates an INFORM packet with the specified parameters.
-     */
-    DhcpInformPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
-                     Inet4Address nextIp, Inet4Address relayIp,
-                     byte[] clientMac) {
-        super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false);
-    }
-
-    public String toString() {
-        String s = super.toString();
-        return s + " INFORM";
-    }
-
-    /**
-     * Builds an INFORM packet.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-
-        fillInPacket(encap, mClientIp, mYourIp, destUdp, srcUdp, result,
-            DHCP_BOOTREQUEST, false);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds additional parameters to the INFORM packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_INFORM);
-        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
-        addCommonClientTlvs(buffer);
-        addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java
deleted file mode 100644
index 6849cfa..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.MacAddress;
-import android.os.SystemClock;
-import android.text.TextUtils;
-
-import com.android.internal.util.HexDump;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * An IPv4 address assignment done through DHCPv4.
- * @hide
- */
-public class DhcpLease {
-    public static final long EXPIRATION_NEVER = Long.MAX_VALUE;
-    public static final String HOSTNAME_NONE = null;
-
-    @Nullable
-    private final byte[] mClientId;
-    @NonNull
-    private final MacAddress mHwAddr;
-    @NonNull
-    private final Inet4Address mNetAddr;
-    /**
-     * Expiration time for the lease, to compare with {@link SystemClock#elapsedRealtime()}.
-     */
-    private final long mExpTime;
-    @Nullable
-    private final String mHostname;
-
-    public DhcpLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address netAddr, long expTime, @Nullable String hostname) {
-        mClientId = (clientId == null ? null : Arrays.copyOf(clientId, clientId.length));
-        mHwAddr = hwAddr;
-        mNetAddr = netAddr;
-        mExpTime = expTime;
-        mHostname = hostname;
-    }
-
-    /**
-     * Get the clientId associated with this lease, if any.
-     *
-     * <p>If the lease is not associated to a clientId, this returns null.
-     */
-    @Nullable
-    public byte[] getClientId() {
-        if (mClientId == null) {
-            return null;
-        }
-        return Arrays.copyOf(mClientId, mClientId.length);
-    }
-
-    @NonNull
-    public MacAddress getHwAddr() {
-        return mHwAddr;
-    }
-
-    @Nullable
-    public String getHostname() {
-        return mHostname;
-    }
-
-    @NonNull
-    public Inet4Address getNetAddr() {
-        return mNetAddr;
-    }
-
-    public long getExpTime() {
-        return mExpTime;
-    }
-
-    /**
-     * Push back the expiration time of this lease. If the provided time is sooner than the original
-     * expiration time, the lease time will not be updated.
-     *
-     * <p>The lease hostname is updated with the provided one if set.
-     * @return A {@link DhcpLease} with expiration time set to max(expTime, currentExpTime)
-     */
-    public DhcpLease renewedLease(long expTime, @Nullable String hostname) {
-        return new DhcpLease(mClientId, mHwAddr, mNetAddr, Math.max(expTime, mExpTime),
-                (hostname == null ? mHostname : hostname));
-    }
-
-    /**
-     * Determine whether this lease matches a client with the specified parameters.
-     * @param clientId clientId of the client if any, or null otherwise.
-     * @param hwAddr Hardware address of the client.
-     */
-    public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
-        if (mClientId != null) {
-            return Arrays.equals(mClientId, clientId);
-        } else {
-            return clientId == null && mHwAddr.equals(hwAddr);
-        }
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof DhcpLease)) {
-            return false;
-        }
-        final DhcpLease other = (DhcpLease) obj;
-        return Arrays.equals(mClientId, other.mClientId)
-                && mHwAddr.equals(other.mHwAddr)
-                && mNetAddr.equals(other.mNetAddr)
-                && mExpTime == other.mExpTime
-                && TextUtils.equals(mHostname, other.mHostname);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mClientId, mHwAddr, mNetAddr, mHostname, mExpTime);
-    }
-
-    static String clientIdToString(byte[] bytes) {
-        if (bytes == null) {
-            return "null";
-        }
-        return HexDump.toHexString(bytes);
-    }
-
-    static String inet4AddrToString(@Nullable Inet4Address addr) {
-        return (addr == null) ? "null" : addr.getHostAddress();
-    }
-
-    @Override
-    public String toString() {
-        return String.format("clientId: %s, hwAddr: %s, netAddr: %s, expTime: %d, hostname: %s",
-                clientIdToString(mClientId), mHwAddr.toString(), inet4AddrToString(mNetAddr),
-                mExpTime, mHostname);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
deleted file mode 100644
index 0a15cd7..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER;
-import static android.net.dhcp.DhcpLease.inet4AddrToString;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
-
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_BITS;
-
-import static java.lang.Math.min;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.util.SharedLog;
-import android.util.ArrayMap;
-
-import java.net.Inet4Address;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * A repository managing IPv4 address assignments through DHCPv4.
- *
- * <p>This class is not thread-safe. All public methods should be called on a common thread or
- * use some synchronization mechanism.
- *
- * <p>Methods are optimized for a small number of allocated leases, assuming that most of the time
- * only 2~10 addresses will be allocated, which is the common case. Managing a large number of
- * addresses is supported but will be slower: some operations have complexity in O(num_leases).
- * @hide
- */
-class DhcpLeaseRepository {
-    public static final byte[] CLIENTID_UNSPEC = null;
-    public static final Inet4Address INETADDR_UNSPEC = null;
-
-    @NonNull
-    private final SharedLog mLog;
-    @NonNull
-    private final Clock mClock;
-
-    @NonNull
-    private IpPrefix mPrefix;
-    @NonNull
-    private Set<Inet4Address> mReservedAddrs;
-    private int mSubnetAddr;
-    private int mSubnetMask;
-    private int mNumAddresses;
-    private long mLeaseTimeMs;
-
-    /**
-     * Next timestamp when committed or declined leases should be checked for expired ones. This
-     * will always be lower than or equal to the time for the first lease to expire: it's OK not to
-     * update this when removing entries, but it must always be updated when adding/updating.
-     */
-    private long mNextExpirationCheck = EXPIRATION_NEVER;
-
-    static class DhcpLeaseException extends Exception {
-        DhcpLeaseException(String message) {
-            super(message);
-        }
-    }
-
-    static class OutOfAddressesException extends DhcpLeaseException {
-        OutOfAddressesException(String message) {
-            super(message);
-        }
-    }
-
-    static class InvalidAddressException extends DhcpLeaseException {
-        InvalidAddressException(String message) {
-            super(message);
-        }
-    }
-
-    static class InvalidSubnetException extends DhcpLeaseException {
-        InvalidSubnetException(String message) {
-            super(message);
-        }
-    }
-
-    /**
-     * Leases by IP address
-     */
-    private final ArrayMap<Inet4Address, DhcpLease> mCommittedLeases = new ArrayMap<>();
-
-    /**
-     * Map address -> expiration timestamp in ms. Addresses are guaranteed to be valid as defined
-     * by {@link #isValidAddress(Inet4Address)}, but are not necessarily otherwise available for
-     * assignment.
-     */
-    private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>();
-
-    DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
-            long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) {
-        updateParams(prefix, reservedAddrs, leaseTimeMs);
-        mLog = log;
-        mClock = clock;
-    }
-
-    public void updateParams(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
-            long leaseTimeMs) {
-        mPrefix = prefix;
-        mReservedAddrs = Collections.unmodifiableSet(new HashSet<>(reservedAddrs));
-        mSubnetMask = prefixLengthToV4NetmaskIntHTH(prefix.getPrefixLength());
-        mSubnetAddr = inet4AddressToIntHTH((Inet4Address) prefix.getAddress()) & mSubnetMask;
-        mNumAddresses = 1 << (IPV4_ADDR_BITS - prefix.getPrefixLength());
-        mLeaseTimeMs = leaseTimeMs;
-
-        cleanMap(mCommittedLeases);
-        cleanMap(mDeclinedAddrs);
-    }
-
-    /**
-     * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as
-     * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address.
-     */
-    private <T> void cleanMap(Map<Inet4Address, T> map) {
-        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
-        while (it.hasNext()) {
-            final Inet4Address addr = it.next().getKey();
-            if (!isValidAddress(addr) || mReservedAddrs.contains(addr)) {
-                it.remove();
-            }
-        }
-    }
-
-    /**
-     * Get a DHCP offer, to reply to a DHCPDISCOVER. Follows RFC2131 #4.3.1.
-     *
-     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
-     * @param relayAddr Internet address of the relay (giaddr), can be {@link Inet4Address#ANY}
-     * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
-     * @param hostname Client-provided hostname, or {@link DhcpLease#HOSTNAME_NONE}
-     * @throws OutOfAddressesException The server does not have any available address
-     * @throws InvalidSubnetException The lease was requested from an unsupported subnet
-     */
-    @NonNull
-    public DhcpLease getOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address relayAddr, @Nullable Inet4Address reqAddr,
-            @Nullable String hostname) throws OutOfAddressesException, InvalidSubnetException {
-        final long currentTime = mClock.elapsedRealtime();
-        final long expTime = currentTime + mLeaseTimeMs;
-
-        removeExpiredLeases(currentTime);
-        checkValidRelayAddr(relayAddr);
-
-        final DhcpLease currentLease = findByClient(clientId, hwAddr);
-        final DhcpLease newLease;
-        if (currentLease != null) {
-            newLease = currentLease.renewedLease(expTime, hostname);
-            mLog.log("Offering extended lease " + newLease);
-            // Do not update lease time in the map: the offer is not committed yet.
-        } else if (reqAddr != null && isValidAddress(reqAddr) && isAvailable(reqAddr)) {
-            newLease = new DhcpLease(clientId, hwAddr, reqAddr, expTime, hostname);
-            mLog.log("Offering requested lease " + newLease);
-        } else {
-            newLease = makeNewOffer(clientId, hwAddr, expTime, hostname);
-            mLog.log("Offering new generated lease " + newLease);
-        }
-        return newLease;
-    }
-
-    private void checkValidRelayAddr(@Nullable Inet4Address relayAddr)
-            throws InvalidSubnetException {
-        // As per #4.3.1, addresses are assigned based on the relay address if present. This
-        // implementation only assigns addresses if the relayAddr is inside our configured subnet.
-        // This also applies when the client requested a specific address for consistency between
-        // requests, and with older behavior.
-        if (isIpAddrOutsidePrefix(mPrefix, relayAddr)) {
-            throw new InvalidSubnetException("Lease requested by relay from outside of subnet");
-        }
-    }
-
-    private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix,
-            @Nullable Inet4Address addr) {
-        return addr != null && !addr.equals(IPV4_ADDR_ANY) && !prefix.contains(addr);
-    }
-
-    @Nullable
-    private DhcpLease findByClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
-        for (DhcpLease lease : mCommittedLeases.values()) {
-            if (lease.matchesClient(clientId, hwAddr)) {
-                return lease;
-            }
-        }
-
-        // Note this differs from dnsmasq behavior, which would match by hwAddr if clientId was
-        // given but no lease keyed on clientId matched. This would prevent one interface from
-        // obtaining multiple leases with different clientId.
-        return null;
-    }
-
-    /**
-     * Make a lease conformant to a client DHCPREQUEST or renew the client's existing lease,
-     * commit it to the repository and return it.
-     *
-     * <p>This method always succeeds and commits the lease if it does not throw, and has no side
-     * effects if it throws.
-     *
-     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
-     * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
-     * @param sidSet Whether the server identifier was set in the request
-     * @return The newly created or renewed lease
-     * @throws InvalidAddressException The client provided an address that conflicts with its
-     *                                 current configuration, or other committed/reserved leases.
-     */
-    @NonNull
-    public DhcpLease requestLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address clientAddr, @NonNull Inet4Address relayAddr,
-            @Nullable Inet4Address reqAddr, boolean sidSet, @Nullable String hostname)
-            throws InvalidAddressException, InvalidSubnetException {
-        final long currentTime = mClock.elapsedRealtime();
-        removeExpiredLeases(currentTime);
-        checkValidRelayAddr(relayAddr);
-        final DhcpLease assignedLease = findByClient(clientId, hwAddr);
-
-        final Inet4Address leaseAddr = reqAddr != null ? reqAddr : clientAddr;
-        if (assignedLease != null) {
-            if (sidSet && reqAddr != null) {
-                // Client in SELECTING state; remove any current lease before creating a new one.
-                mCommittedLeases.remove(assignedLease.getNetAddr());
-            } else if (!assignedLease.getNetAddr().equals(leaseAddr)) {
-                // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr.
-                // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration.
-                // In both cases, throw if clientAddr or reqAddr does not match the known lease.
-                throw new InvalidAddressException("Incorrect address for client in "
-                        + (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING"));
-            }
-        }
-
-        // In the init-reboot case, RFC2131 #4.3.2 says that the server must not reply if
-        // assignedLease == null, but dnsmasq will let the client use the requested address if
-        // available, when configured with --dhcp-authoritative. This is preferable to avoid issues
-        // if the server lost the lease DB: the client would not get a reply because the server
-        // does not know their lease.
-        // Similarly in RENEWING/REBINDING state, create a lease when possible if the
-        // client-provided lease is unknown.
-        final DhcpLease lease =
-                checkClientAndMakeLease(clientId, hwAddr, leaseAddr, hostname, currentTime);
-        mLog.logf("DHCPREQUEST assignedLease %s, reqAddr=%s, sidSet=%s: created/renewed lease %s",
-                assignedLease, inet4AddrToString(reqAddr), sidSet, lease);
-        return lease;
-    }
-
-    /**
-     * Check that the client can request the specified address, make or renew the lease if yes, and
-     * commit it.
-     *
-     * <p>This method always succeeds and returns the lease if it does not throw, and has no
-     * side-effect if it throws.
-     *
-     * @return The newly created or renewed, committed lease
-     * @throws InvalidAddressException The client provided an address that conflicts with its
-     *                                 current configuration, or other committed/reserved leases.
-     */
-    private DhcpLease checkClientAndMakeLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address addr, @Nullable String hostname, long currentTime)
-            throws InvalidAddressException {
-        final long expTime = currentTime + mLeaseTimeMs;
-        final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
-        if (currentLease != null && !currentLease.matchesClient(clientId, hwAddr)) {
-            throw new InvalidAddressException("Address in use");
-        }
-
-        final DhcpLease lease;
-        if (currentLease == null) {
-            if (isValidAddress(addr) && !mReservedAddrs.contains(addr)) {
-                lease = new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
-            } else {
-                throw new InvalidAddressException("Lease not found and address unavailable");
-            }
-        } else {
-            lease = currentLease.renewedLease(expTime, hostname);
-        }
-        commitLease(lease);
-        return lease;
-    }
-
-    private void commitLease(@NonNull DhcpLease lease) {
-        mCommittedLeases.put(lease.getNetAddr(), lease);
-        maybeUpdateEarliestExpiration(lease.getExpTime());
-    }
-
-    /**
-     * Delete a committed lease from the repository.
-     *
-     * @return true if a lease matching parameters was found.
-     */
-    public boolean releaseLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address addr) {
-        final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
-        if (currentLease == null) {
-            mLog.w("Could not release unknown lease for " + inet4AddrToString(addr));
-            return false;
-        }
-        if (currentLease.matchesClient(clientId, hwAddr)) {
-            mCommittedLeases.remove(addr);
-            mLog.log("Released lease " + currentLease);
-            return true;
-        }
-        mLog.w(String.format("Not releasing lease %s: does not match client (cid %s, hwAddr %s)",
-                currentLease, DhcpLease.clientIdToString(clientId), hwAddr));
-        return false;
-    }
-
-    public void markLeaseDeclined(@NonNull Inet4Address addr) {
-        if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) {
-            mLog.logf("Not marking %s as declined: already declined or not assignable",
-                    inet4AddrToString(addr));
-            return;
-        }
-        final long expTime = mClock.elapsedRealtime() + mLeaseTimeMs;
-        mDeclinedAddrs.put(addr, expTime);
-        mLog.logf("Marked %s as declined expiring %d", inet4AddrToString(addr), expTime);
-        maybeUpdateEarliestExpiration(expTime);
-    }
-
-    /**
-     * Get the list of currently valid committed leases in the repository.
-     */
-    @NonNull
-    public List<DhcpLease> getCommittedLeases() {
-        removeExpiredLeases(mClock.elapsedRealtime());
-        return new ArrayList<>(mCommittedLeases.values());
-    }
-
-    /**
-     * Get the set of addresses that have been marked as declined in the repository.
-     */
-    @NonNull
-    public Set<Inet4Address> getDeclinedAddresses() {
-        removeExpiredLeases(mClock.elapsedRealtime());
-        return new HashSet<>(mDeclinedAddrs.keySet());
-    }
-
-    /**
-     * Given the expiration time of a new committed lease or declined address, update
-     * {@link #mNextExpirationCheck} so it stays lower than or equal to the time for the first lease
-     * to expire.
-     */
-    private void maybeUpdateEarliestExpiration(long expTime) {
-        if (expTime < mNextExpirationCheck) {
-            mNextExpirationCheck = expTime;
-        }
-    }
-
-    /**
-     * Remove expired entries from a map keyed by {@link Inet4Address}.
-     *
-     * @param tag Type of lease in the map, for logging
-     * @param getExpTime Functor returning the expiration time for an object in the map.
-     *                   Must not return null.
-     * @return The lowest expiration time among entries remaining in the map
-     */
-    private <T> long removeExpired(long currentTime, @NonNull Map<Inet4Address, T> map,
-            @NonNull String tag, @NonNull Function<T, Long> getExpTime) {
-        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
-        long firstExpiration = EXPIRATION_NEVER;
-        while (it.hasNext()) {
-            final Entry<Inet4Address, T> lease = it.next();
-            final long expTime = getExpTime.apply(lease.getValue());
-            if (expTime <= currentTime) {
-                mLog.logf("Removing expired %s lease for %s (expTime=%s, currentTime=%s)",
-                        tag, lease.getKey(), expTime, currentTime);
-                it.remove();
-            } else {
-                firstExpiration = min(firstExpiration, expTime);
-            }
-        }
-        return firstExpiration;
-    }
-
-    /**
-     * Go through committed and declined leases and remove the expired ones.
-     */
-    private void removeExpiredLeases(long currentTime) {
-        if (currentTime < mNextExpirationCheck) {
-            return;
-        }
-
-        final long commExp = removeExpired(
-                currentTime, mCommittedLeases, "committed", DhcpLease::getExpTime);
-        final long declExp = removeExpired(
-                currentTime, mDeclinedAddrs, "declined", Function.identity());
-
-        mNextExpirationCheck = min(commExp, declExp);
-    }
-
-    private boolean isAvailable(@NonNull Inet4Address addr) {
-        return !mReservedAddrs.contains(addr) && !mCommittedLeases.containsKey(addr);
-    }
-
-    /**
-     * Get the 0-based index of an address in the subnet.
-     *
-     * <p>Given ordering of addresses 5.6.7.8 < 5.6.7.9 < 5.6.8.0, the index on a subnet is defined
-     * so that the first address is 0, the second 1, etc. For example on a /16, 192.168.0.0 -> 0,
-     * 192.168.0.1 -> 1, 192.168.1.0 -> 256
-     *
-     */
-    private int getAddrIndex(int addr) {
-        return addr & ~mSubnetMask;
-    }
-
-    private int getAddrByIndex(int index) {
-        return mSubnetAddr | index;
-    }
-
-    /**
-     * Get a valid address starting from the supplied one.
-     *
-     * <p>This only checks that the address is numerically valid for assignment, not whether it is
-     * already in use. The return value is always inside the configured prefix, even if the supplied
-     * address is not.
-     *
-     * <p>If the provided address is valid, it is returned as-is. Otherwise, the next valid
-     * address (with the ordering in {@link #getAddrIndex(int)}) is returned.
-     */
-    private int getValidAddress(int addr) {
-        final int lastByteMask = 0xff;
-        int addrIndex = getAddrIndex(addr); // 0-based index of the address in the subnet
-
-        // Some OSes do not handle addresses in .255 or .0 correctly: avoid those.
-        final int lastByte = getAddrByIndex(addrIndex) & lastByteMask;
-        if (lastByte == lastByteMask) {
-            // Avoid .255 address, and .0 address that follows
-            addrIndex = (addrIndex + 2) % mNumAddresses;
-        } else if (lastByte == 0) {
-            // Avoid .0 address
-            addrIndex = (addrIndex + 1) % mNumAddresses;
-        }
-
-        // Do not use first or last address of range
-        if (addrIndex == 0 || addrIndex == mNumAddresses - 1) {
-            // Always valid and not end of range since prefixLength is at most 30 in serving params
-            addrIndex = 1;
-        }
-        return getAddrByIndex(addrIndex);
-    }
-
-    /**
-     * Returns whether the address is in the configured subnet and part of the assignable range.
-     */
-    private boolean isValidAddress(Inet4Address addr) {
-        final int intAddr = inet4AddressToIntHTH(addr);
-        return getValidAddress(intAddr) == intAddr;
-    }
-
-    private int getNextAddress(int addr) {
-        final int addrIndex = getAddrIndex(addr);
-        final int nextAddress = getAddrByIndex((addrIndex + 1) % mNumAddresses);
-        return getValidAddress(nextAddress);
-    }
-
-    /**
-     * Calculate a first candidate address for a client by hashing the hardware address.
-     *
-     * <p>This will be a valid address as checked by {@link #getValidAddress(int)}, but may be
-     * in use.
-     *
-     * @return An IPv4 address encoded as 32-bit int
-     */
-    private int getFirstClientAddress(MacAddress hwAddr) {
-        // This follows dnsmasq behavior. Advantages are: clients will often get the same
-        // offers for different DISCOVER even if the lease was not yet accepted or has expired,
-        // and address generation will generally not need to loop through many allocated addresses
-        // until it finds a free one.
-        int hash = 0;
-        for (byte b : hwAddr.toByteArray()) {
-            hash += b + (b << 8) + (b << 16);
-        }
-        // This implementation will not always result in the same IPs as dnsmasq would give out in
-        // Android <= P, because it includes invalid and reserved addresses in mNumAddresses while
-        // the configured ranges for dnsmasq did not.
-        final int addrIndex = hash % mNumAddresses;
-        return getValidAddress(getAddrByIndex(addrIndex));
-    }
-
-    /**
-     * Create a lease that can be offered to respond to a client DISCOVER.
-     *
-     * <p>This method always succeeds and returns the lease if it does not throw. If no non-declined
-     * address is available, it will try to offer the oldest declined address if valid.
-     *
-     * @throws OutOfAddressesException The server has no address left to offer
-     */
-    private DhcpLease makeNewOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            long expTime, @Nullable String hostname) throws OutOfAddressesException {
-        int intAddr = getFirstClientAddress(hwAddr);
-        // Loop until a free address is found, or there are no more addresses.
-        // There is slightly less than this many usable addresses, but some extra looping is OK
-        for (int i = 0; i < mNumAddresses; i++) {
-            final Inet4Address addr = intToInet4AddressHTH(intAddr);
-            if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) {
-                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
-            }
-            intAddr = getNextAddress(intAddr);
-        }
-
-        // Try freeing DECLINEd addresses if out of addresses.
-        final Iterator<Inet4Address> it = mDeclinedAddrs.keySet().iterator();
-        while (it.hasNext()) {
-            final Inet4Address addr = it.next();
-            it.remove();
-            mLog.logf("Out of addresses in address pool: dropped declined addr %s",
-                    inet4AddrToString(addr));
-            // isValidAddress() is always verified for entries in mDeclinedAddrs.
-            // However declined addresses may have been requested (typically by the machine that was
-            // already using the address) after being declined.
-            if (isAvailable(addr)) {
-                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
-            }
-        }
-
-        throw new OutOfAddressesException("No address available for offer");
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpNakPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpNakPacket.java
deleted file mode 100644
index 1da0b73..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpNakPacket.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the DHCP-NAK packet.
- */
-class DhcpNakPacket extends DhcpPacket {
-    /**
-     * Generates a NAK packet with the specified parameters.
-     */
-    DhcpNakPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac,
-            boolean broadcast) {
-        super(transId, secs, INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */,
-                INADDR_ANY /* nextIp */, relayIp, clientMac, broadcast);
-    }
-
-    public String toString() {
-        String s = super.toString();
-        return s + " NAK, reason " + (mMessage == null ? "(none)" : mMessage);
-    }
-
-    /**
-     * Fills in a packet with the requested NAK attributes.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-        // Constructor does not set values for layers <= 3: use empty values
-        Inet4Address destIp = INADDR_ANY;
-        Inet4Address srcIp = INADDR_ANY;
-
-        fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result, DHCP_BOOTREPLY, mBroadcast);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds the optional parameters to the client-generated NAK packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_NAK);
-        addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
-        addTlv(buffer, DHCP_MESSAGE, mMessage);
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpOfferPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpOfferPacket.java
deleted file mode 100644
index 0eba77e..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpOfferPacket.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the DHCP-OFFER packet.
- */
-class DhcpOfferPacket extends DhcpPacket {
-    /**
-     * The IP address of the server which sent this packet.
-     */
-    private final Inet4Address mSrcIp;
-
-    /**
-     * Generates a OFFER packet with the specified parameters.
-     */
-    DhcpOfferPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
-            Inet4Address relayIp, Inet4Address clientIp, Inet4Address yourIp, byte[] clientMac) {
-        super(transId, secs, clientIp, yourIp, serverAddress, relayIp, clientMac, broadcast);
-        mSrcIp = serverAddress;
-    }
-
-    public String toString() {
-        String s = super.toString();
-        String dnsServers = ", DNS servers: ";
-
-        if (mDnsServers != null) {
-            for (Inet4Address dnsServer: mDnsServers) {
-                dnsServers += dnsServer + " ";
-            }
-        }
-
-        return s + " OFFER, ip " + mYourIp + ", mask " + mSubnetMask +
-                dnsServers + ", gateways " + mGateways +
-                " lease time " + mLeaseTime + ", domain " + mDomainName;
-    }
-
-    /**
-     * Fills in a packet with the specified OFFER attributes.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-        Inet4Address destIp = mBroadcast ? INADDR_BROADCAST : mYourIp;
-        Inet4Address srcIp = mBroadcast ? INADDR_ANY : mSrcIp;
-
-        fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result,
-            DHCP_BOOTREPLY, mBroadcast);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds the optional parameters to the server-generated OFFER packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_OFFER);
-        addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
-
-        addCommonServerTlvs(buffer);
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
deleted file mode 100644
index a15d423..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
+++ /dev/null
@@ -1,1397 +0,0 @@
-package android.net.dhcp;
-
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-
-import android.annotation.Nullable;
-import android.net.DhcpResults;
-import android.net.LinkAddress;
-import android.net.metrics.DhcpErrorEvent;
-import android.net.shared.Inet4AddressUtils;
-import android.os.Build;
-import android.os.SystemProperties;
-import android.system.OsConstants;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.UnsupportedEncodingException;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Defines basic data and operations needed to build and use packets for the
- * DHCP protocol.  Subclasses create the specific packets used at each
- * stage of the negotiation.
- *
- * @hide
- */
-public abstract class DhcpPacket {
-    protected static final String TAG = "DhcpPacket";
-
-    // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack.
-    private static final int IPV4_MIN_MTU = 68;
-
-    // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
-    // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
-    // DHCP client timeout.
-    public static final int MINIMUM_LEASE = 60;
-    public static final int INFINITE_LEASE = (int) 0xffffffff;
-
-    public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY;
-    public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL;
-    public static final byte[] ETHER_BROADCAST = new byte[] {
-            (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            (byte) 0xff, (byte) 0xff, (byte) 0xff,
-    };
-
-    /**
-     * Packet encapsulations.
-     */
-    public static final int ENCAP_L2 = 0;    // EthernetII header included
-    public static final int ENCAP_L3 = 1;    // IP/UDP header included
-    public static final int ENCAP_BOOTP = 2; // BOOTP contents only
-
-    /**
-     * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
-     */
-    public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
-    public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
-    public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
-
-    public static final int HWADDR_LEN = 16;
-    public static final int MAX_OPTION_LEN = 255;
-
-    /**
-     * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
-     * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
-     * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
-     * because in general it is risky to assume that the hardware is able to send/receive packets
-     * larger than 1500 bytes even if the network supports it.
-     */
-    private static final int MIN_MTU = 1280;
-    private static final int MAX_MTU = 1500;
-
-    /**
-     * IP layer definitions.
-     */
-    private static final byte IP_TYPE_UDP = (byte) 0x11;
-
-    /**
-     * IP: Version 4, Header Length 20 bytes
-     */
-    private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
-
-    /**
-     * IP: Flags 0, Fragment Offset 0, Don't Fragment
-     */
-    private static final short IP_FLAGS_OFFSET = (short) 0x4000;
-
-    /**
-     * IP: TOS
-     */
-    private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
-
-    /**
-     * IP: TTL -- use default 64 from RFC1340
-     */
-    private static final byte IP_TTL = (byte) 0x40;
-
-    /**
-     * The client DHCP port.
-     */
-    static final short DHCP_CLIENT = (short) 68;
-
-    /**
-     * The server DHCP port.
-     */
-    static final short DHCP_SERVER = (short) 67;
-
-    /**
-     * The message op code indicating a request from a client.
-     */
-    protected static final byte DHCP_BOOTREQUEST = (byte) 1;
-
-    /**
-     * The message op code indicating a response from the server.
-     */
-    protected static final byte DHCP_BOOTREPLY = (byte) 2;
-
-    /**
-     * The code type used to identify an Ethernet MAC address in the
-     * Client-ID field.
-     */
-    protected static final byte CLIENT_ID_ETHER = (byte) 1;
-
-    /**
-     * The maximum length of a packet that can be constructed.
-     */
-    protected static final int MAX_LENGTH = 1500;
-
-    /**
-     * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
-     */
-    private static final int DHCP_MAGIC_COOKIE = 0x63825363;
-
-    /**
-     * DHCP Optional Type: DHCP Subnet Mask
-     */
-    protected static final byte DHCP_SUBNET_MASK = 1;
-    protected Inet4Address mSubnetMask;
-
-    /**
-     * DHCP Optional Type: DHCP Router
-     */
-    protected static final byte DHCP_ROUTER = 3;
-    protected List <Inet4Address> mGateways;
-
-    /**
-     * DHCP Optional Type: DHCP DNS Server
-     */
-    protected static final byte DHCP_DNS_SERVER = 6;
-    protected List<Inet4Address> mDnsServers;
-
-    /**
-     * DHCP Optional Type: DHCP Host Name
-     */
-    protected static final byte DHCP_HOST_NAME = 12;
-    protected String mHostName;
-
-    /**
-     * DHCP Optional Type: DHCP DOMAIN NAME
-     */
-    protected static final byte DHCP_DOMAIN_NAME = 15;
-    protected String mDomainName;
-
-    /**
-     * DHCP Optional Type: DHCP Interface MTU
-     */
-    protected static final byte DHCP_MTU = 26;
-    protected Short mMtu;
-
-    /**
-     * DHCP Optional Type: DHCP BROADCAST ADDRESS
-     */
-    protected static final byte DHCP_BROADCAST_ADDRESS = 28;
-    protected Inet4Address mBroadcastAddress;
-
-    /**
-     * DHCP Optional Type: Vendor specific information
-     */
-    protected static final byte DHCP_VENDOR_INFO = 43;
-    protected String mVendorInfo;
-
-    /**
-     * Value of the vendor specific option used to indicate that the network is metered
-     */
-    public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
-
-    /**
-     * DHCP Optional Type: Option overload option
-     */
-    protected static final byte DHCP_OPTION_OVERLOAD = 52;
-
-    /**
-     * Possible values of the option overload option.
-     */
-    private static final byte OPTION_OVERLOAD_FILE = 1;
-    private static final byte OPTION_OVERLOAD_SNAME = 2;
-    private static final byte OPTION_OVERLOAD_BOTH = 3;
-
-    /**
-     * DHCP Optional Type: DHCP Requested IP Address
-     */
-    protected static final byte DHCP_REQUESTED_IP = 50;
-    protected Inet4Address mRequestedIp;
-
-    /**
-     * DHCP Optional Type: DHCP Lease Time
-     */
-    protected static final byte DHCP_LEASE_TIME = 51;
-    protected Integer mLeaseTime;
-
-    /**
-     * DHCP Optional Type: DHCP Message Type
-     */
-    protected static final byte DHCP_MESSAGE_TYPE = 53;
-    // the actual type values
-    protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
-    protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
-    protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
-    protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
-    protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
-    protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
-    protected static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
-    protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
-
-    /**
-     * DHCP Optional Type: DHCP Server Identifier
-     */
-    protected static final byte DHCP_SERVER_IDENTIFIER = 54;
-    protected Inet4Address mServerIdentifier;
-
-    /**
-     * DHCP Optional Type: DHCP Parameter List
-     */
-    protected static final byte DHCP_PARAMETER_LIST = 55;
-    protected byte[] mRequestedParams;
-
-    /**
-     * DHCP Optional Type: DHCP MESSAGE
-     */
-    protected static final byte DHCP_MESSAGE = 56;
-    protected String mMessage;
-
-    /**
-     * DHCP Optional Type: Maximum DHCP Message Size
-     */
-    protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
-    protected Short mMaxMessageSize;
-
-    /**
-     * DHCP Optional Type: DHCP Renewal Time Value
-     */
-    protected static final byte DHCP_RENEWAL_TIME = 58;
-    protected Integer mT1;
-
-    /**
-     * DHCP Optional Type: Rebinding Time Value
-     */
-    protected static final byte DHCP_REBINDING_TIME = 59;
-    protected Integer mT2;
-
-    /**
-     * DHCP Optional Type: Vendor Class Identifier
-     */
-    protected static final byte DHCP_VENDOR_CLASS_ID = 60;
-    protected String mVendorId;
-
-    /**
-     * DHCP Optional Type: DHCP Client Identifier
-     */
-    protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
-    protected byte[] mClientId;
-
-    /**
-     * DHCP zero-length option code: pad
-     */
-    protected static final byte DHCP_OPTION_PAD = 0x00;
-
-    /**
-     * DHCP zero-length option code: end of options
-     */
-    protected static final byte DHCP_OPTION_END = (byte) 0xff;
-
-    /**
-     * The transaction identifier used in this particular DHCP negotiation
-     */
-    protected final int mTransId;
-
-    /**
-     * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
-     */
-    protected final short mSecs;
-
-    /**
-     * The IP address of the client host.  This address is typically
-     * proposed by the client (from an earlier DHCP negotiation) or
-     * supplied by the server.
-     */
-    protected final Inet4Address mClientIp;
-    protected final Inet4Address mYourIp;
-    private final Inet4Address mNextIp;
-    protected final Inet4Address mRelayIp;
-
-    /**
-     * Does the client request a broadcast response?
-     */
-    protected boolean mBroadcast;
-
-    /**
-     * The six-octet MAC of the client.
-     */
-    protected final byte[] mClientMac;
-
-    /**
-     * The server host name from server.
-     */
-    protected String mServerHostName;
-
-    /**
-     * Asks the packet object to create a ByteBuffer serialization of
-     * the packet for transmission.
-     */
-    public abstract ByteBuffer buildPacket(int encap, short destUdp,
-        short srcUdp);
-
-    /**
-     * Allows the concrete class to fill in packet-type-specific details,
-     * typically optional parameters at the end of the packet.
-     */
-    abstract void finishPacket(ByteBuffer buffer);
-
-    // Set in unit tests, to ensure that the test does not break when run on different devices and
-    // on different releases.
-    static String testOverrideVendorId = null;
-    static String testOverrideHostname = null;
-
-    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
-                         Inet4Address nextIp, Inet4Address relayIp,
-                         byte[] clientMac, boolean broadcast) {
-        mTransId = transId;
-        mSecs = secs;
-        mClientIp = clientIp;
-        mYourIp = yourIp;
-        mNextIp = nextIp;
-        mRelayIp = relayIp;
-        mClientMac = clientMac;
-        mBroadcast = broadcast;
-    }
-
-    /**
-     * Returns the transaction ID.
-     */
-    public int getTransactionId() {
-        return mTransId;
-    }
-
-    /**
-     * Returns the client MAC.
-     */
-    public byte[] getClientMac() {
-        return mClientMac;
-    }
-
-    // TODO: refactor DhcpClient to set clientId when constructing packets and remove
-    // hasExplicitClientId logic
-    /**
-     * Returns whether a client ID was set in the options for this packet.
-     */
-    public boolean hasExplicitClientId() {
-        return mClientId != null;
-    }
-
-    /**
-     * Convenience method to return the client ID if it was set explicitly, or null otherwise.
-     */
-    @Nullable
-    public byte[] getExplicitClientIdOrNull() {
-        return hasExplicitClientId() ? getClientId() : null;
-    }
-
-    /**
-     * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID
-     * based on the hardware address.
-     */
-    public byte[] getClientId() {
-        final byte[] clientId;
-        if (hasExplicitClientId()) {
-            clientId = Arrays.copyOf(mClientId, mClientId.length);
-        } else {
-            clientId = new byte[mClientMac.length + 1];
-            clientId[0] = CLIENT_ID_ETHER;
-            System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
-        }
-        return clientId;
-    }
-
-    /**
-     * Returns whether a parameter is included in the parameter request list option of this packet.
-     *
-     * <p>If there is no parameter request list option in the packet, false is returned.
-     *
-     * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
-     */
-    public boolean hasRequestedParam(byte paramId) {
-        if (mRequestedParams == null) {
-            return false;
-        }
-
-        for (byte reqParam : mRequestedParams) {
-            if (reqParam == paramId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Creates a new L3 packet (including IP header) containing the
-     * DHCP udp packet.  This method relies upon the delegated method
-     * finishPacket() to insert the per-packet contents.
-     */
-    protected void fillInPacket(int encap, Inet4Address destIp,
-        Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
-        byte requestCode, boolean broadcast) {
-        byte[] destIpArray = destIp.getAddress();
-        byte[] srcIpArray = srcIp.getAddress();
-        int ipHeaderOffset = 0;
-        int ipLengthOffset = 0;
-        int ipChecksumOffset = 0;
-        int endIpHeader = 0;
-        int udpHeaderOffset = 0;
-        int udpLengthOffset = 0;
-        int udpChecksumOffset = 0;
-
-        buf.clear();
-        buf.order(ByteOrder.BIG_ENDIAN);
-
-        if (encap == ENCAP_L2) {
-            buf.put(ETHER_BROADCAST);
-            buf.put(mClientMac);
-            buf.putShort((short) OsConstants.ETH_P_IP);
-        }
-
-        // if a full IP packet needs to be generated, put the IP & UDP
-        // headers in place, and pre-populate with artificial values
-        // needed to seed the IP checksum.
-        if (encap <= ENCAP_L3) {
-            ipHeaderOffset = buf.position();
-            buf.put(IP_VERSION_HEADER_LEN);
-            buf.put(IP_TOS_LOWDELAY);    // tos: IPTOS_LOWDELAY
-            ipLengthOffset = buf.position();
-            buf.putShort((short)0);  // length
-            buf.putShort((short)0);  // id
-            buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
-            buf.put(IP_TTL);    // TTL: use default 64 from RFC1340
-            buf.put(IP_TYPE_UDP);
-            ipChecksumOffset = buf.position();
-            buf.putShort((short) 0); // checksum
-
-            buf.put(srcIpArray);
-            buf.put(destIpArray);
-            endIpHeader = buf.position();
-
-            // UDP header
-            udpHeaderOffset = buf.position();
-            buf.putShort(srcUdp);
-            buf.putShort(destUdp);
-            udpLengthOffset = buf.position();
-            buf.putShort((short) 0); // length
-            udpChecksumOffset = buf.position();
-            buf.putShort((short) 0); // UDP checksum -- initially zero
-        }
-
-        // DHCP payload
-        buf.put(requestCode);
-        buf.put((byte) 1); // Hardware Type: Ethernet
-        buf.put((byte) mClientMac.length); // Hardware Address Length
-        buf.put((byte) 0); // Hop Count
-        buf.putInt(mTransId);  // Transaction ID
-        buf.putShort(mSecs); // Elapsed Seconds
-
-        if (broadcast) {
-            buf.putShort((short) 0x8000); // Flags
-        } else {
-            buf.putShort((short) 0x0000); // Flags
-        }
-
-        buf.put(mClientIp.getAddress());
-        buf.put(mYourIp.getAddress());
-        buf.put(mNextIp.getAddress());
-        buf.put(mRelayIp.getAddress());
-        buf.put(mClientMac);
-        buf.position(buf.position() +
-                     (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
-                     + 64     // empty server host name (64 bytes)
-                     + 128);  // empty boot file name (128 bytes)
-        buf.putInt(DHCP_MAGIC_COOKIE); // magic number
-        finishPacket(buf);
-
-        // round up to an even number of octets
-        if ((buf.position() & 1) == 1) {
-            buf.put((byte) 0);
-        }
-
-        // If an IP packet is being built, the IP & UDP checksums must be
-        // computed.
-        if (encap <= ENCAP_L3) {
-            // fix UDP header: insert length
-            short udpLen = (short)(buf.position() - udpHeaderOffset);
-            buf.putShort(udpLengthOffset, udpLen);
-            // fix UDP header: checksum
-            // checksum for UDP at udpChecksumOffset
-            int udpSeed = 0;
-
-            // apply IPv4 pseudo-header.  Read IP address src and destination
-            // values from the IP header and accumulate checksum.
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
-
-            // accumulate extra data for the pseudo-header
-            udpSeed += IP_TYPE_UDP;
-            udpSeed += udpLen;
-            // and compute UDP checksum
-            buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
-                                                             udpHeaderOffset,
-                                                             buf.position()));
-            // fix IP header: insert length
-            buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
-            // fixup IP-header checksum
-            buf.putShort(ipChecksumOffset,
-                         (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
-        }
-    }
-
-    /**
-     * Converts a signed short value to an unsigned int value.  Needed
-     * because Java does not have unsigned types.
-     */
-    private static int intAbs(short v) {
-        return v & 0xFFFF;
-    }
-
-    /**
-     * Performs an IP checksum (used in IP header and across UDP
-     * payload) on the specified portion of a ByteBuffer.  The seed
-     * allows the checksum to commence with a specified value.
-     */
-    private int checksum(ByteBuffer buf, int seed, int start, int end) {
-        int sum = seed;
-        int bufPosition = buf.position();
-
-        // set position of original ByteBuffer, so that the ShortBuffer
-        // will be correctly initialized
-        buf.position(start);
-        ShortBuffer shortBuf = buf.asShortBuffer();
-
-        // re-set ByteBuffer position
-        buf.position(bufPosition);
-
-        short[] shortArray = new short[(end - start) / 2];
-        shortBuf.get(shortArray);
-
-        for (short s : shortArray) {
-            sum += intAbs(s);
-        }
-
-        start += shortArray.length * 2;
-
-        // see if a singleton byte remains
-        if (end != start) {
-            short b = buf.get(start);
-
-            // make it unsigned
-            if (b < 0) {
-                b += 256;
-            }
-
-            sum += b * 256;
-        }
-
-        sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
-        sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
-        int negated = ~sum;
-        return intAbs((short) negated);
-    }
-
-    /**
-     * Adds an optional parameter containing a single byte value.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, byte value) {
-        buf.put(type);
-        buf.put((byte) 1);
-        buf.put(value);
-    }
-
-    /**
-     * Adds an optional parameter containing an array of bytes.
-     *
-     * <p>This method is a no-op if the payload argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) {
-        if (payload != null) {
-            if (payload.length > MAX_OPTION_LEN) {
-                throw new IllegalArgumentException("DHCP option too long: "
-                        + payload.length + " vs. " + MAX_OPTION_LEN);
-            }
-            buf.put(type);
-            buf.put((byte) payload.length);
-            buf.put(payload);
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing an IP address.
-     *
-     * <p>This method is a no-op if the address argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) {
-        if (addr != null) {
-            addTlv(buf, type, addr.getAddress());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing a list of IP addresses.
-     *
-     * <p>This method is a no-op if the addresses argument is null or empty.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) {
-        if (addrs == null || addrs.size() == 0) return;
-
-        int optionLen = 4 * addrs.size();
-        if (optionLen > MAX_OPTION_LEN) {
-            throw new IllegalArgumentException("DHCP option too long: "
-                    + optionLen + " vs. " + MAX_OPTION_LEN);
-        }
-
-        buf.put(type);
-        buf.put((byte)(optionLen));
-
-        for (Inet4Address addr : addrs) {
-            buf.put(addr.getAddress());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing a short integer.
-     *
-     * <p>This method is a no-op if the value argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) {
-        if (value != null) {
-            buf.put(type);
-            buf.put((byte) 2);
-            buf.putShort(value.shortValue());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing a simple integer.
-     *
-     * <p>This method is a no-op if the value argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) {
-        if (value != null) {
-            buf.put(type);
-            buf.put((byte) 4);
-            buf.putInt(value.intValue());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing an ASCII string.
-     *
-     * <p>This method is a no-op if the string argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) {
-        if (str != null) {
-            try {
-                addTlv(buf, type, str.getBytes("US-ASCII"));
-            } catch (UnsupportedEncodingException e) {
-                throw new IllegalArgumentException("String is not US-ASCII: " + str);
-            }
-        }
-    }
-
-    /**
-     * Adds the special end-of-optional-parameters indicator.
-     */
-    protected static void addTlvEnd(ByteBuffer buf) {
-        buf.put((byte) 0xFF);
-    }
-
-    private String getVendorId() {
-        if (testOverrideVendorId != null) return testOverrideVendorId;
-        return "android-dhcp-" + Build.VERSION.RELEASE;
-    }
-
-    private String getHostname() {
-        if (testOverrideHostname != null) return testOverrideHostname;
-        return SystemProperties.get("net.hostname");
-    }
-
-    /**
-     * Adds common client TLVs.
-     *
-     * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
-     * methods to take them.
-     */
-    protected void addCommonClientTlvs(ByteBuffer buf) {
-        addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
-        addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId());
-        final String hn = getHostname();
-        if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
-    }
-
-    protected void addCommonServerTlvs(ByteBuffer buf) {
-        addTlv(buf, DHCP_LEASE_TIME, mLeaseTime);
-        if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) {
-            // The client should renew at 1/2 the lease-expiry interval
-            addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2));
-            // Default rebinding time is set as below by RFC2131
-            addTlv(buf, DHCP_REBINDING_TIME,
-                    (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L));
-        }
-        addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask);
-        addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
-        addTlv(buf, DHCP_ROUTER, mGateways);
-        addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
-        addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
-        addTlv(buf, DHCP_HOST_NAME, mHostName);
-        addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
-        if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
-            addTlv(buf, DHCP_MTU, mMtu);
-        }
-    }
-
-    /**
-     * Converts a MAC from an array of octets to an ASCII string.
-     */
-    public static String macToString(byte[] mac) {
-        String macAddr = "";
-
-        for (int i = 0; i < mac.length; i++) {
-            String hexString = "0" + Integer.toHexString(mac[i]);
-
-            // substring operation grabs the last 2 digits: this
-            // allows signed bytes to be converted correctly.
-            macAddr += hexString.substring(hexString.length() - 2);
-
-            if (i != (mac.length - 1)) {
-                macAddr += ":";
-            }
-        }
-
-        return macAddr;
-    }
-
-    public String toString() {
-        String macAddr = macToString(mClientMac);
-
-        return macAddr;
-    }
-
-    /**
-     * Reads a four-octet value from a ByteBuffer and construct
-     * an IPv4 address from that value.
-     */
-    private static Inet4Address readIpAddress(ByteBuffer packet) {
-        Inet4Address result = null;
-        byte[] ipAddr = new byte[4];
-        packet.get(ipAddr);
-
-        try {
-            result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
-        } catch (UnknownHostException ex) {
-            // ipAddr is numeric, so this should not be
-            // triggered.  However, if it is, just nullify
-            result = null;
-        }
-
-        return result;
-    }
-
-    /**
-     * Reads a string of specified length from the buffer.
-     */
-    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
-        byte[] bytes = new byte[byteCount];
-        buf.get(bytes);
-        int length = bytes.length;
-        if (!nullOk) {
-            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
-            // name) are passed to netd via FrameworkListener, which refuses arguments containing
-            // null bytes. We don't do this by default because vendorInfo is an opaque string which
-            // could in theory contain null bytes.
-            for (length = 0; length < bytes.length; length++) {
-                if (bytes[length] == 0) {
-                    break;
-                }
-            }
-        }
-        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
-    }
-
-    private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
-        return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
-    }
-
-    private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
-        return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
-    }
-
-    public static class ParseException extends Exception {
-        public final int errorCode;
-        public ParseException(int errorCode, String msg, Object... args) {
-            super(String.format(msg, args));
-            this.errorCode = errorCode;
-        }
-    }
-
-    /**
-     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
-     * buffer may have an L2 encapsulation (which is the full EthernetII
-     * format starting with the source-address MAC) or an L3 encapsulation
-     * (which starts with the IP header).
-     * <br>
-     * A subset of the optional parameters are parsed and are stored
-     * in object fields.
-     */
-    @VisibleForTesting
-    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
-    {
-        // bootp parameters
-        int transactionId;
-        short secs;
-        Inet4Address clientIp;
-        Inet4Address yourIp;
-        Inet4Address nextIp;
-        Inet4Address relayIp;
-        byte[] clientMac;
-        byte[] clientId = null;
-        List<Inet4Address> dnsServers = new ArrayList<>();
-        List<Inet4Address> gateways = new ArrayList<>();  // aka router
-        Inet4Address serverIdentifier = null;
-        Inet4Address netMask = null;
-        String message = null;
-        String vendorId = null;
-        String vendorInfo = null;
-        byte[] expectedParams = null;
-        String hostName = null;
-        String domainName = null;
-        Inet4Address ipSrc = null;
-        Inet4Address ipDst = null;
-        Inet4Address bcAddr = null;
-        Inet4Address requestedIp = null;
-        String serverHostName;
-        byte optionOverload = 0;
-
-        // The following are all unsigned integers. Internally we store them as signed integers of
-        // the same length because that way we're guaranteed that they can't be out of the range of
-        // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
-        // to cast it.
-        Short mtu = null;
-        Short maxMessageSize = null;
-        Integer leaseTime = null;
-        Integer T1 = null;
-        Integer T2 = null;
-
-        // dhcp options
-        byte dhcpType = (byte) 0xFF;
-
-        packet.order(ByteOrder.BIG_ENDIAN);
-
-        // check to see if we need to parse L2, IP, and UDP encaps
-        if (pktType == ENCAP_L2) {
-            if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
-                throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
-                        "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
-            }
-
-            byte[] l2dst = new byte[6];
-            byte[] l2src = new byte[6];
-
-            packet.get(l2dst);
-            packet.get(l2src);
-
-            short l2type = packet.getShort();
-
-            if (l2type != OsConstants.ETH_P_IP) {
-                throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
-                        "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
-            }
-        }
-
-        if (pktType <= ENCAP_L3) {
-            if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
-                throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
-                        "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
-            }
-
-            byte ipTypeAndLength = packet.get();
-            int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
-            if (ipVersion != 4) {
-                throw new ParseException(
-                        DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
-            }
-
-            // System.out.println("ipType is " + ipType);
-            byte ipDiffServicesField = packet.get();
-            short ipTotalLength = packet.getShort();
-            short ipIdentification = packet.getShort();
-            byte ipFlags = packet.get();
-            byte ipFragOffset = packet.get();
-            byte ipTTL = packet.get();
-            byte ipProto = packet.get();
-            short ipChksm = packet.getShort();
-
-            ipSrc = readIpAddress(packet);
-            ipDst = readIpAddress(packet);
-
-            if (ipProto != IP_TYPE_UDP) {
-                throw new ParseException(
-                        DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
-            }
-
-            // Skip options. This cannot cause us to read beyond the end of the buffer because the
-            // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
-            // MIN_PACKET_LENGTH_L3.
-            int optionWords = ((ipTypeAndLength & 0x0f) - 5);
-            for (int i = 0; i < optionWords; i++) {
-                packet.getInt();
-            }
-
-            // assume UDP
-            short udpSrcPort = packet.getShort();
-            short udpDstPort = packet.getShort();
-            short udpLen = packet.getShort();
-            short udpChkSum = packet.getShort();
-
-            // Only accept packets to or from the well-known client port (expressly permitting
-            // packets from ports other than the well-known server port; http://b/24687559), and
-            // server-to-server packets, e.g. for relays.
-            if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
-                !isPacketServerToServer(udpSrcPort, udpDstPort)) {
-                // This should almost never happen because we use SO_ATTACH_FILTER on the packet
-                // socket to drop packets that don't have the right source ports. However, it's
-                // possible that a packet arrives between when the socket is bound and when the
-                // filter is set. http://b/26696823 .
-                throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
-                        "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
-            }
-        }
-
-        // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
-        if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
-            throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
-                        "Invalid type or BOOTP packet too short, %d < %d",
-                        packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
-        }
-
-        byte type = packet.get();
-        byte hwType = packet.get();
-        int addrLen = packet.get() & 0xff;
-        byte hops = packet.get();
-        transactionId = packet.getInt();
-        secs = packet.getShort();
-        short bootpFlags = packet.getShort();
-        boolean broadcast = (bootpFlags & 0x8000) != 0;
-        byte[] ipv4addr = new byte[4];
-
-        try {
-            packet.get(ipv4addr);
-            clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-            packet.get(ipv4addr);
-            yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-            packet.get(ipv4addr);
-            nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-            packet.get(ipv4addr);
-            relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-        } catch (UnknownHostException ex) {
-            throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
-                    "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
-        }
-
-        // Some DHCP servers have been known to announce invalid client hardware address values such
-        // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
-        // all but only checks that the interface MAC address matches the first bytes of the address
-        // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
-        // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
-        // TODO: evaluate whether to make this test more liberal.
-        if (addrLen > HWADDR_LEN) {
-            addrLen = ETHER_BROADCAST.length;
-        }
-
-        clientMac = new byte[addrLen];
-        packet.get(clientMac);
-
-        // skip over address padding (16 octets allocated)
-        packet.position(packet.position() + (16 - addrLen));
-        serverHostName = readAsciiString(packet, 64, false);
-        packet.position(packet.position() + 128);
-
-        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
-        if (packet.remaining() < 4) {
-            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
-        }
-
-        int dhcpMagicCookie = packet.getInt();
-        if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
-            throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
-                    "Bad magic cookie 0x%08x, should be 0x%08x",
-                    dhcpMagicCookie, DHCP_MAGIC_COOKIE);
-        }
-
-        // parse options
-        boolean notFinishedOptions = true;
-
-        while ((packet.position() < packet.limit()) && notFinishedOptions) {
-            final byte optionType = packet.get(); // cannot underflow because position < limit
-            try {
-                if (optionType == DHCP_OPTION_END) {
-                    notFinishedOptions = false;
-                } else if (optionType == DHCP_OPTION_PAD) {
-                    // The pad option doesn't have a length field. Nothing to do.
-                } else {
-                    int optionLen = packet.get() & 0xFF;
-                    int expectedLen = 0;
-
-                    switch(optionType) {
-                        case DHCP_SUBNET_MASK:
-                            netMask = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_ROUTER:
-                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
-                                gateways.add(readIpAddress(packet));
-                            }
-                            break;
-                        case DHCP_DNS_SERVER:
-                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
-                                dnsServers.add(readIpAddress(packet));
-                            }
-                            break;
-                        case DHCP_HOST_NAME:
-                            expectedLen = optionLen;
-                            hostName = readAsciiString(packet, optionLen, false);
-                            break;
-                        case DHCP_MTU:
-                            expectedLen = 2;
-                            mtu = packet.getShort();
-                            break;
-                        case DHCP_DOMAIN_NAME:
-                            expectedLen = optionLen;
-                            domainName = readAsciiString(packet, optionLen, false);
-                            break;
-                        case DHCP_BROADCAST_ADDRESS:
-                            bcAddr = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_REQUESTED_IP:
-                            requestedIp = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_LEASE_TIME:
-                            leaseTime = Integer.valueOf(packet.getInt());
-                            expectedLen = 4;
-                            break;
-                        case DHCP_MESSAGE_TYPE:
-                            dhcpType = packet.get();
-                            expectedLen = 1;
-                            break;
-                        case DHCP_SERVER_IDENTIFIER:
-                            serverIdentifier = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_PARAMETER_LIST:
-                            expectedParams = new byte[optionLen];
-                            packet.get(expectedParams);
-                            expectedLen = optionLen;
-                            break;
-                        case DHCP_MESSAGE:
-                            expectedLen = optionLen;
-                            message = readAsciiString(packet, optionLen, false);
-                            break;
-                        case DHCP_MAX_MESSAGE_SIZE:
-                            expectedLen = 2;
-                            maxMessageSize = Short.valueOf(packet.getShort());
-                            break;
-                        case DHCP_RENEWAL_TIME:
-                            expectedLen = 4;
-                            T1 = Integer.valueOf(packet.getInt());
-                            break;
-                        case DHCP_REBINDING_TIME:
-                            expectedLen = 4;
-                            T2 = Integer.valueOf(packet.getInt());
-                            break;
-                        case DHCP_VENDOR_CLASS_ID:
-                            expectedLen = optionLen;
-                            // Embedded nulls are safe as this does not get passed to netd.
-                            vendorId = readAsciiString(packet, optionLen, true);
-                            break;
-                        case DHCP_CLIENT_IDENTIFIER: { // Client identifier
-                            byte[] id = new byte[optionLen];
-                            packet.get(id);
-                            expectedLen = optionLen;
-                        } break;
-                        case DHCP_VENDOR_INFO:
-                            expectedLen = optionLen;
-                            // Embedded nulls are safe as this does not get passed to netd.
-                            vendorInfo = readAsciiString(packet, optionLen, true);
-                            break;
-                        case DHCP_OPTION_OVERLOAD:
-                            expectedLen = 1;
-                            optionOverload = packet.get();
-                            optionOverload &= OPTION_OVERLOAD_BOTH;
-                            break;
-                        default:
-                            // ignore any other parameters
-                            for (int i = 0; i < optionLen; i++) {
-                                expectedLen++;
-                                byte throwaway = packet.get();
-                            }
-                    }
-
-                    if (expectedLen != optionLen) {
-                        final int errorCode = DhcpErrorEvent.errorCodeWithOption(
-                                DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
-                        throw new ParseException(errorCode,
-                                "Invalid length %d for option %d, expected %d",
-                                optionLen, optionType, expectedLen);
-                    }
-                }
-            } catch (BufferUnderflowException e) {
-                final int errorCode = DhcpErrorEvent.errorCodeWithOption(
-                        DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
-                throw new ParseException(errorCode, "BufferUnderflowException");
-            }
-        }
-
-        DhcpPacket newPacket;
-
-        switch(dhcpType) {
-            case (byte) 0xFF:
-                throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
-                        "No DHCP message type option");
-            case DHCP_MESSAGE_TYPE_DISCOVER:
-                newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac,
-                        broadcast, ipSrc);
-                break;
-            case DHCP_MESSAGE_TYPE_OFFER:
-                newPacket = new DhcpOfferPacket(
-                    transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_REQUEST:
-                newPacket = new DhcpRequestPacket(
-                    transactionId, secs, clientIp, relayIp, clientMac, broadcast);
-                break;
-            case DHCP_MESSAGE_TYPE_DECLINE:
-                newPacket = new DhcpDeclinePacket(
-                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
-                    clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_ACK:
-                newPacket = new DhcpAckPacket(
-                    transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_NAK:
-                newPacket = new DhcpNakPacket(
-                        transactionId, secs, relayIp, clientMac, broadcast);
-                break;
-            case DHCP_MESSAGE_TYPE_RELEASE:
-                if (serverIdentifier == null) {
-                    throw new ParseException(DhcpErrorEvent.MISC_ERROR,
-                            "DHCPRELEASE without server identifier");
-                }
-                newPacket = new DhcpReleasePacket(
-                        transactionId, serverIdentifier, clientIp, relayIp, clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_INFORM:
-                newPacket = new DhcpInformPacket(
-                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
-                    clientMac);
-                break;
-            default:
-                throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
-                        "Unimplemented DHCP type %d", dhcpType);
-        }
-
-        newPacket.mBroadcastAddress = bcAddr;
-        newPacket.mClientId = clientId;
-        newPacket.mDnsServers = dnsServers;
-        newPacket.mDomainName = domainName;
-        newPacket.mGateways = gateways;
-        newPacket.mHostName = hostName;
-        newPacket.mLeaseTime = leaseTime;
-        newPacket.mMessage = message;
-        newPacket.mMtu = mtu;
-        newPacket.mRequestedIp = requestedIp;
-        newPacket.mRequestedParams = expectedParams;
-        newPacket.mServerIdentifier = serverIdentifier;
-        newPacket.mSubnetMask = netMask;
-        newPacket.mMaxMessageSize = maxMessageSize;
-        newPacket.mT1 = T1;
-        newPacket.mT2 = T2;
-        newPacket.mVendorId = vendorId;
-        newPacket.mVendorInfo = vendorInfo;
-        if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) {
-            newPacket.mServerHostName = serverHostName;
-        } else {
-            newPacket.mServerHostName = "";
-        }
-        return newPacket;
-    }
-
-    /**
-     * Parse a packet from an array of bytes, stopping at the given length.
-     */
-    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
-            throws ParseException {
-        ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
-        try {
-            return decodeFullPacket(buffer, pktType);
-        } catch (ParseException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
-        }
-    }
-
-    /**
-     *  Construct a DhcpResults object from a DHCP reply packet.
-     */
-    public DhcpResults toDhcpResults() {
-        Inet4Address ipAddress = mYourIp;
-        if (ipAddress.equals(IPV4_ADDR_ANY)) {
-            ipAddress = mClientIp;
-            if (ipAddress.equals(IPV4_ADDR_ANY)) {
-                return null;
-            }
-        }
-
-        int prefixLength;
-        if (mSubnetMask != null) {
-            try {
-                prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask);
-            } catch (IllegalArgumentException e) {
-                // Non-contiguous netmask.
-                return null;
-            }
-        } else {
-            prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress);
-        }
-
-        DhcpResults results = new DhcpResults();
-        try {
-            results.ipAddress = new LinkAddress(ipAddress, prefixLength);
-        } catch (IllegalArgumentException e) {
-            return null;
-        }
-
-        if (mGateways.size() > 0) {
-            results.gateway = mGateways.get(0);
-        }
-
-        results.dnsServers.addAll(mDnsServers);
-        results.domains = mDomainName;
-        results.serverAddress = mServerIdentifier;
-        results.vendorInfo = mVendorInfo;
-        results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
-        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
-        results.serverHostName = mServerHostName;
-
-        return results;
-    }
-
-    /**
-     * Returns the parsed lease time, in milliseconds, or 0 for infinite.
-     */
-    public long getLeaseTimeMillis() {
-        // dhcpcd treats the lack of a lease time option as an infinite lease.
-        if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
-            return 0;
-        } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
-            return MINIMUM_LEASE * 1000;
-        } else {
-            return (mLeaseTime & 0xffffffffL) * 1000;
-        }
-    }
-
-    /**
-     * Builds a DHCP-DISCOVER packet from the required specified
-     * parameters.
-     */
-    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
-        short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
-        DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
-                clientMac, broadcast, INADDR_ANY /* srcIp */);
-        pkt.mRequestedParams = expectedParams;
-        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
-    }
-
-    /**
-     * Builds a DHCP-OFFER packet from the required specified
-     * parameters.
-     */
-    public static ByteBuffer buildOfferPacket(int encap, int transactionId,
-        boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
-        Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
-        Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
-        Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
-        short mtu) {
-        DhcpPacket pkt = new DhcpOfferPacket(
-                transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
-                INADDR_ANY /* clientIp */, yourIp, mac);
-        pkt.mGateways = gateways;
-        pkt.mDnsServers = dnsServers;
-        pkt.mLeaseTime = timeout;
-        pkt.mDomainName = domainName;
-        pkt.mHostName = hostname;
-        pkt.mServerIdentifier = dhcpServerIdentifier;
-        pkt.mSubnetMask = netMask;
-        pkt.mBroadcastAddress = bcAddr;
-        pkt.mMtu = mtu;
-        if (metered) {
-            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
-        }
-        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
-    }
-
-    /**
-     * Builds a DHCP-ACK packet from the required specified parameters.
-     */
-    public static ByteBuffer buildAckPacket(int encap, int transactionId,
-        boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
-        Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
-        Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
-        Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
-        short mtu) {
-        DhcpPacket pkt = new DhcpAckPacket(
-                transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
-                mac);
-        pkt.mGateways = gateways;
-        pkt.mDnsServers = dnsServers;
-        pkt.mLeaseTime = timeout;
-        pkt.mDomainName = domainName;
-        pkt.mHostName = hostname;
-        pkt.mSubnetMask = netMask;
-        pkt.mServerIdentifier = dhcpServerIdentifier;
-        pkt.mBroadcastAddress = bcAddr;
-        pkt.mMtu = mtu;
-        if (metered) {
-            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
-        }
-        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
-    }
-
-    /**
-     * Builds a DHCP-NAK packet from the required specified parameters.
-     */
-    public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
-            Inet4Address relayIp, byte[] mac, boolean broadcast, String message) {
-        DhcpPacket pkt = new DhcpNakPacket(
-                transactionId, (short) 0, relayIp, mac, broadcast);
-        pkt.mMessage = message;
-        pkt.mServerIdentifier = serverIpAddr;
-        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
-    }
-
-    /**
-     * Builds a DHCP-REQUEST packet from the required specified parameters.
-     */
-    public static ByteBuffer buildRequestPacket(int encap,
-        int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
-        byte[] clientMac, Inet4Address requestedIpAddress,
-        Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
-        DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
-                INADDR_ANY /* relayIp */, clientMac, broadcast);
-        pkt.mRequestedIp = requestedIpAddress;
-        pkt.mServerIdentifier = serverIdentifier;
-        pkt.mHostName = hostName;
-        pkt.mRequestedParams = requestedParams;
-        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
-        return result;
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
deleted file mode 100644
index 97d26c7c..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.util.FdEventsReader;
-import android.os.Handler;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-
-/**
- * A {@link FdEventsReader} to receive and parse {@link DhcpPacket}.
- * @hide
- */
-abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> {
-    static final class Payload {
-        protected final byte[] mBytes = new byte[DhcpPacket.MAX_LENGTH];
-        protected Inet4Address mSrcAddr;
-        protected int mSrcPort;
-    }
-
-    DhcpPacketListener(@NonNull Handler handler) {
-        super(handler, new Payload());
-    }
-
-    @Override
-    protected int recvBufSize(@NonNull Payload buffer) {
-        return buffer.mBytes.length;
-    }
-
-    @Override
-    protected final void handlePacket(@NonNull Payload recvbuf, int length) {
-        if (recvbuf.mSrcAddr == null) {
-            return;
-        }
-
-        try {
-            final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.mBytes, length,
-                    DhcpPacket.ENCAP_BOOTP);
-            onReceive(packet, recvbuf.mSrcAddr, recvbuf.mSrcPort);
-        } catch (DhcpPacket.ParseException e) {
-            logParseError(recvbuf.mBytes, length, e);
-        }
-    }
-
-    @Override
-    protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer)
-            throws Exception {
-        final InetSocketAddress addr = new InetSocketAddress(0);
-        final int read = Os.recvfrom(
-                fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr);
-
-        // Buffers with null srcAddr will be dropped in handlePacket()
-        packetBuffer.mSrcAddr = inet4AddrOrNull(addr);
-        packetBuffer.mSrcPort = addr.getPort();
-        return read;
-    }
-
-    @Nullable
-    private static Inet4Address inet4AddrOrNull(@NonNull InetSocketAddress addr) {
-        return addr.getAddress() instanceof Inet4Address
-                ? (Inet4Address) addr.getAddress()
-                : null;
-    }
-
-    protected abstract void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
-            int srcPort);
-    protected abstract void logParseError(@NonNull byte[] packet, int length,
-            @NonNull DhcpPacket.ParseException e);
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpReleasePacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpReleasePacket.java
deleted file mode 100644
index 3958303..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpReleasePacket.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * Implements DHCP-RELEASE
- */
-class DhcpReleasePacket extends DhcpPacket {
-
-    final Inet4Address mClientAddr;
-
-    /**
-     * Generates a RELEASE packet with the specified parameters.
-     */
-    public DhcpReleasePacket(int transId, Inet4Address serverId, Inet4Address clientAddr,
-            Inet4Address relayIp, byte[] clientMac) {
-        super(transId, (short)0, clientAddr, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */,
-                relayIp, clientMac, false /* broadcast */);
-        mServerIdentifier = serverId;
-        mClientAddr = clientAddr;
-    }
-
-
-    @Override
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-        fillInPacket(encap, mServerIdentifier /* destIp */, mClientIp /* srcIp */, destUdp, srcUdp,
-                result, DHCP_BOOTREPLY, mBroadcast);
-        result.flip();
-        return result;
-    }
-
-    @Override
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_RELEASE);
-        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
-        addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
-        addCommonClientTlvs(buffer);
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpRequestPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpRequestPacket.java
deleted file mode 100644
index 231d0457..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpRequestPacket.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import android.util.Log;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-
-/**
- * This class implements the DHCP-REQUEST packet.
- */
-class DhcpRequestPacket extends DhcpPacket {
-    /**
-     * Generates a REQUEST packet with the specified parameters.
-     */
-    DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, Inet4Address relayIp,
-            byte[] clientMac, boolean broadcast) {
-        super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast);
-    }
-
-    public String toString() {
-        String s = super.toString();
-        return s + " REQUEST, desired IP " + mRequestedIp + " from host '"
-            + mHostName + "', param list length "
-            + (mRequestedParams == null ? 0 : mRequestedParams.length);
-    }
-
-    /**
-     * Fills in a packet with the requested REQUEST attributes.
-     */
-    public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
-        ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-
-        fillInPacket(encap, INADDR_BROADCAST, INADDR_ANY, destUdp, srcUdp,
-            result, DHCP_BOOTREQUEST, mBroadcast);
-        result.flip();
-        return result;
-    }
-
-    /**
-     * Adds the optional parameters to the client-generated REQUEST packet.
-     */
-    void finishPacket(ByteBuffer buffer) {
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_REQUEST);
-        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
-        if (!INADDR_ANY.equals(mRequestedIp)) {
-            addTlv(buffer, DHCP_REQUESTED_IP, mRequestedIp);
-        }
-        if (!INADDR_ANY.equals(mServerIdentifier)) {
-            addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
-        }
-        addCommonClientTlvs(buffer);
-        addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
-        addTlvEnd(buffer);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
deleted file mode 100644
index b8ab94c..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
-import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
-import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
-import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
-import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_NONBLOCK;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_BROADCAST;
-import static android.system.OsConstants.SO_REUSEADDR;
-
-import static com.android.internal.util.TrafficStatsConstants.TAG_SYSTEM_DHCP_SERVER;
-import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
-
-import static java.lang.Integer.toUnsignedLong;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.INetworkStackStatusCallback;
-import android.net.MacAddress;
-import android.net.TrafficStats;
-import android.net.util.NetworkStackUtils;
-import android.net.util.SharedLog;
-import android.net.util.SocketUtils;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.TextUtils;
-import android.util.Pair;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.HexDump;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-
-/**
- * A DHCPv4 server.
- *
- * <p>This server listens for and responds to packets on a single interface. It considers itself
- * authoritative for all leases on the subnet, which means that DHCP requests for unknown leases of
- * unknown hosts receive a reply instead of being ignored.
- *
- * <p>The server is single-threaded (including send/receive operations): all internal operations are
- * done on the provided {@link Looper}. Public methods are thread-safe and will schedule operations
- * on the looper asynchronously.
- * @hide
- */
-public class DhcpServer extends IDhcpServer.Stub {
-    private static final String REPO_TAG = "Repository";
-
-    // Lease time to transmit to client instead of a negative time in case a lease expired before
-    // the server could send it (if the server process is suspended for example).
-    private static final int EXPIRED_FALLBACK_LEASE_TIME_SECS = 120;
-
-    private static final int CMD_START_DHCP_SERVER = 1;
-    private static final int CMD_STOP_DHCP_SERVER = 2;
-    private static final int CMD_UPDATE_PARAMS = 3;
-
-    @NonNull
-    private final HandlerThread mHandlerThread;
-    @NonNull
-    private final String mIfName;
-    @NonNull
-    private final DhcpLeaseRepository mLeaseRepo;
-    @NonNull
-    private final SharedLog mLog;
-    @NonNull
-    private final Dependencies mDeps;
-    @NonNull
-    private final Clock mClock;
-
-    @Nullable
-    private volatile ServerHandler mHandler;
-
-    // Accessed only on the handler thread
-    @Nullable
-    private DhcpPacketListener mPacketListener;
-    @Nullable
-    private FileDescriptor mSocket;
-    @NonNull
-    private DhcpServingParams mServingParams;
-
-    /**
-     * Clock to be used by DhcpServer to track time for lease expiration.
-     *
-     * <p>The clock should track time as may be measured by clients obtaining a lease. It does not
-     * need to be monotonous across restarts of the server as long as leases are cleared when the
-     * server is stopped.
-     */
-    public static class Clock {
-        /**
-         * @see SystemClock#elapsedRealtime()
-         */
-        public long elapsedRealtime() {
-            return SystemClock.elapsedRealtime();
-        }
-    }
-
-    /**
-     * Dependencies for the DhcpServer. Useful to be mocked in tests.
-     */
-    public interface Dependencies {
-        /**
-         * Send a packet to the specified datagram socket.
-         *
-         * @param fd File descriptor of the socket.
-         * @param buffer Data to be sent.
-         * @param dst Destination address of the packet.
-         */
-        void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
-                @NonNull InetAddress dst) throws ErrnoException, IOException;
-
-        /**
-         * Create a DhcpLeaseRepository for the server.
-         * @param servingParams Parameters used to serve DHCP requests.
-         * @param log Log to be used by the repository.
-         * @param clock Clock that the repository must use to track time.
-         */
-        DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
-                @NonNull SharedLog log, @NonNull Clock clock);
-
-        /**
-         * Create a packet listener that will send packets to be processed.
-         */
-        DhcpPacketListener makePacketListener();
-
-        /**
-         * Create a clock that the server will use to track time.
-         */
-        Clock makeClock();
-
-        /**
-         * Add an entry to the ARP cache table.
-         * @param fd Datagram socket file descriptor that must use the new entry.
-         */
-        void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
-                @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException;
-
-        /**
-         * Verify that the caller is allowed to call public methods on DhcpServer.
-         * @throws SecurityException The caller is not allowed to call public methods on DhcpServer.
-         */
-        void checkCaller() throws SecurityException;
-    }
-
-    private class DependenciesImpl implements Dependencies {
-        @Override
-        public void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
-                @NonNull InetAddress dst) throws ErrnoException, IOException {
-            Os.sendto(fd, buffer, 0, dst, DhcpPacket.DHCP_CLIENT);
-        }
-
-        @Override
-        public DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
-                @NonNull SharedLog log, @NonNull Clock clock) {
-            return new DhcpLeaseRepository(
-                    DhcpServingParams.makeIpPrefix(servingParams.serverAddr),
-                    servingParams.excludedAddrs,
-                    servingParams.dhcpLeaseTimeSecs * 1000, log.forSubComponent(REPO_TAG), clock);
-        }
-
-        @Override
-        public DhcpPacketListener makePacketListener() {
-            return new PacketListener();
-        }
-
-        @Override
-        public Clock makeClock() {
-            return new Clock();
-        }
-
-        @Override
-        public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
-                @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException {
-            NetworkStackUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
-        }
-
-        @Override
-        public void checkCaller() {
-            checkNetworkStackCallingPermission();
-        }
-    }
-
-    private static class MalformedPacketException extends Exception {
-        MalformedPacketException(String message, Throwable t) {
-            super(message, t);
-        }
-    }
-
-    public DhcpServer(@NonNull String ifName,
-            @NonNull DhcpServingParams params, @NonNull SharedLog log) {
-        this(new HandlerThread(DhcpServer.class.getSimpleName() + "." + ifName),
-                ifName, params, log, null);
-    }
-
-    @VisibleForTesting
-    DhcpServer(@NonNull HandlerThread handlerThread, @NonNull String ifName,
-            @NonNull DhcpServingParams params, @NonNull SharedLog log,
-            @Nullable Dependencies deps) {
-        if (deps == null) {
-            deps = new DependenciesImpl();
-        }
-        mHandlerThread = handlerThread;
-        mIfName = ifName;
-        mServingParams = params;
-        mLog = log;
-        mDeps = deps;
-        mClock = deps.makeClock();
-        mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock);
-    }
-
-    /**
-     * Start listening for and responding to packets.
-     *
-     * <p>It is not legal to call this method more than once; in particular the server cannot be
-     * restarted after being stopped.
-     */
-    @Override
-    public void start(@Nullable INetworkStackStatusCallback cb) {
-        mDeps.checkCaller();
-        mHandlerThread.start();
-        mHandler = new ServerHandler(mHandlerThread.getLooper());
-        sendMessage(CMD_START_DHCP_SERVER, cb);
-    }
-
-    /**
-     * Update serving parameters. All subsequently received requests will be handled with the new
-     * parameters, and current leases that are incompatible with the new parameters are dropped.
-     */
-    @Override
-    public void updateParams(@Nullable DhcpServingParamsParcel params,
-            @Nullable INetworkStackStatusCallback cb) throws RemoteException {
-        mDeps.checkCaller();
-        final DhcpServingParams parsedParams;
-        try {
-            // throws InvalidParameterException with null params
-            parsedParams = DhcpServingParams.fromParcelableObject(params);
-        } catch (DhcpServingParams.InvalidParameterException e) {
-            mLog.e("Invalid parameters sent to DhcpServer", e);
-            if (cb != null) {
-                cb.onStatusAvailable(STATUS_INVALID_ARGUMENT);
-            }
-            return;
-        }
-        sendMessage(CMD_UPDATE_PARAMS, new Pair<>(parsedParams, cb));
-    }
-
-    /**
-     * Stop listening for packets.
-     *
-     * <p>As the server is stopped asynchronously, some packets may still be processed shortly after
-     * calling this method.
-     */
-    @Override
-    public void stop(@Nullable INetworkStackStatusCallback cb) {
-        mDeps.checkCaller();
-        sendMessage(CMD_STOP_DHCP_SERVER, cb);
-    }
-
-    private void sendMessage(int what, @Nullable Object obj) {
-        if (mHandler == null) {
-            mLog.e("Attempting to send a command to stopped DhcpServer: " + what);
-            return;
-        }
-        mHandler.sendMessage(mHandler.obtainMessage(what, obj));
-    }
-
-    private class ServerHandler extends Handler {
-        ServerHandler(@NonNull Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(@NonNull Message msg) {
-            final INetworkStackStatusCallback cb;
-            switch (msg.what) {
-                case CMD_UPDATE_PARAMS:
-                    final Pair<DhcpServingParams, INetworkStackStatusCallback> pair =
-                            (Pair<DhcpServingParams, INetworkStackStatusCallback>) msg.obj;
-                    final DhcpServingParams params = pair.first;
-                    mServingParams = params;
-                    mLeaseRepo.updateParams(
-                            DhcpServingParams.makeIpPrefix(mServingParams.serverAddr),
-                            params.excludedAddrs,
-                            params.dhcpLeaseTimeSecs);
-
-                    cb = pair.second;
-                    break;
-                case CMD_START_DHCP_SERVER:
-                    mPacketListener = mDeps.makePacketListener();
-                    mPacketListener.start();
-                    cb = (INetworkStackStatusCallback) msg.obj;
-                    break;
-                case CMD_STOP_DHCP_SERVER:
-                    if (mPacketListener != null) {
-                        mPacketListener.stop();
-                        mPacketListener = null;
-                    }
-                    mHandlerThread.quitSafely();
-                    cb = (INetworkStackStatusCallback) msg.obj;
-                    break;
-                default:
-                    return;
-            }
-            if (cb != null) {
-                try {
-                    cb.onStatusAvailable(STATUS_SUCCESS);
-                } catch (RemoteException e) {
-                    mLog.e("Could not send status back to caller", e);
-                }
-            }
-        }
-    }
-
-    @VisibleForTesting
-    void processPacket(@NonNull DhcpPacket packet, int srcPort) {
-        final String packetType = packet.getClass().getSimpleName();
-        if (srcPort != DHCP_CLIENT) {
-            mLog.logf("Ignored packet of type %s sent from client port %d", packetType, srcPort);
-            return;
-        }
-
-        mLog.log("Received packet of type " + packetType);
-        final Inet4Address sid = packet.mServerIdentifier;
-        if (sid != null && !sid.equals(mServingParams.serverAddr.getAddress())) {
-            mLog.log("Packet ignored due to wrong server identifier: " + sid);
-            return;
-        }
-
-        try {
-            if (packet instanceof DhcpDiscoverPacket) {
-                processDiscover((DhcpDiscoverPacket) packet);
-            } else if (packet instanceof DhcpRequestPacket) {
-                processRequest((DhcpRequestPacket) packet);
-            } else if (packet instanceof DhcpReleasePacket) {
-                processRelease((DhcpReleasePacket) packet);
-            } else {
-                mLog.e("Unknown packet type: " + packet.getClass().getSimpleName());
-            }
-        } catch (MalformedPacketException e) {
-            // Not an internal error: only logging exception message, not stacktrace
-            mLog.e("Ignored malformed packet: " + e.getMessage());
-        }
-    }
-
-    private void logIgnoredPacketInvalidSubnet(DhcpLeaseRepository.InvalidSubnetException e) {
-        // Not an internal error: only logging exception message, not stacktrace
-        mLog.e("Ignored packet from invalid subnet: " + e.getMessage());
-    }
-
-    private void processDiscover(@NonNull DhcpDiscoverPacket packet)
-            throws MalformedPacketException {
-        final DhcpLease lease;
-        final MacAddress clientMac = getMacAddr(packet);
-        try {
-            lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac,
-                    packet.mRelayIp, packet.mRequestedIp, packet.mHostName);
-        } catch (DhcpLeaseRepository.OutOfAddressesException e) {
-            transmitNak(packet, "Out of addresses to offer");
-            return;
-        } catch (DhcpLeaseRepository.InvalidSubnetException e) {
-            logIgnoredPacketInvalidSubnet(e);
-            return;
-        }
-
-        transmitOffer(packet, lease, clientMac);
-    }
-
-    private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException {
-        // If set, packet SID matches with this server's ID as checked in processPacket().
-        final boolean sidSet = packet.mServerIdentifier != null;
-        final DhcpLease lease;
-        final MacAddress clientMac = getMacAddr(packet);
-        try {
-            lease = mLeaseRepo.requestLease(packet.getExplicitClientIdOrNull(), clientMac,
-                    packet.mClientIp, packet.mRelayIp, packet.mRequestedIp, sidSet,
-                    packet.mHostName);
-        } catch (DhcpLeaseRepository.InvalidAddressException e) {
-            transmitNak(packet, "Invalid requested address");
-            return;
-        } catch (DhcpLeaseRepository.InvalidSubnetException e) {
-            logIgnoredPacketInvalidSubnet(e);
-            return;
-        }
-
-        transmitAck(packet, lease, clientMac);
-    }
-
-    private void processRelease(@NonNull DhcpReleasePacket packet)
-            throws MalformedPacketException {
-        final byte[] clientId = packet.getExplicitClientIdOrNull();
-        final MacAddress macAddr = getMacAddr(packet);
-        // Don't care about success (there is no ACK/NAK); logging is already done in the repository
-        mLeaseRepo.releaseLease(clientId, macAddr, packet.mClientIp);
-    }
-
-    private Inet4Address getAckOrOfferDst(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
-            boolean broadcastFlag) {
-        // Unless relayed or broadcast, send to client IP if already configured on the client, or to
-        // the lease address if the client has no configured address
-        if (!isEmpty(request.mRelayIp)) {
-            return request.mRelayIp;
-        } else if (broadcastFlag) {
-            return IPV4_ADDR_ALL;
-        } else if (!isEmpty(request.mClientIp)) {
-            return request.mClientIp;
-        } else {
-            return lease.getNetAddr();
-        }
-    }
-
-    /**
-     * Determine whether the broadcast flag should be set in the BOOTP packet flags. This does not
-     * apply to NAK responses, which should always have it set.
-     */
-    private static boolean getBroadcastFlag(@NonNull DhcpPacket request, @NonNull DhcpLease lease) {
-        // No broadcast flag if the client already has a configured IP to unicast to. RFC2131 #4.1
-        // has some contradictions regarding broadcast behavior if a client already has an IP
-        // configured and sends a request with both ciaddr (renew/rebind) and the broadcast flag
-        // set. Sending a unicast response to ciaddr matches previous behavior and is more
-        // efficient.
-        // If the client has no configured IP, broadcast if requested by the client or if the lease
-        // address cannot be used to send a unicast reply either.
-        return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr()));
-    }
-
-    /**
-     * Get the hostname from a lease if non-empty and requested in the incoming request.
-     * @param request The incoming request.
-     * @return The hostname, or null if not requested or empty.
-     */
-    @Nullable
-    private static String getHostnameIfRequested(@NonNull DhcpPacket request,
-            @NonNull DhcpLease lease) {
-        return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname())
-                ? lease.getHostname()
-                : null;
-    }
-
-    private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
-            @NonNull MacAddress clientMac) {
-        final boolean broadcastFlag = getBroadcastFlag(request, lease);
-        final int timeout = getLeaseTimeout(lease);
-        final Inet4Address prefixMask =
-                getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength());
-        final Inet4Address broadcastAddr = getBroadcastAddress(
-                mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
-        final String hostname = getHostnameIfRequested(request, lease);
-        final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
-                ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
-                request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
-                broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
-                new ArrayList<>(mServingParams.dnsServers),
-                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
-                mServingParams.metered, (short) mServingParams.linkMtu);
-
-        return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
-    }
-
-    private boolean transmitAck(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
-            @NonNull MacAddress clientMac) {
-        // TODO: replace DhcpPacket's build methods with real builders and use common code with
-        // transmitOffer above
-        final boolean broadcastFlag = getBroadcastFlag(request, lease);
-        final int timeout = getLeaseTimeout(lease);
-        final String hostname = getHostnameIfRequested(request, lease);
-        final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
-                broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
-                lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout,
-                mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
-                new ArrayList<>(mServingParams.defaultRouters),
-                new ArrayList<>(mServingParams.dnsServers),
-                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
-                mServingParams.metered, (short) mServingParams.linkMtu);
-
-        return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
-    }
-
-    private boolean transmitNak(DhcpPacket request, String message) {
-        mLog.w("Transmitting NAK: " + message);
-        // Always set broadcast flag for NAK: client may not have a correct IP
-        final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
-                ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
-                request.mRelayIp, request.mClientMac, true /* broadcast */, message);
-
-        final Inet4Address dst = isEmpty(request.mRelayIp)
-                ? IPV4_ADDR_ALL
-                : request.mRelayIp;
-        return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst);
-    }
-
-    private boolean transmitOfferOrAckPacket(@NonNull ByteBuffer buf, @NonNull DhcpPacket request,
-            @NonNull DhcpLease lease, @NonNull MacAddress clientMac, boolean broadcastFlag) {
-        mLog.logf("Transmitting %s with lease %s", request.getClass().getSimpleName(), lease);
-        // Client may not yet respond to ARP for the lease address, which may be the destination
-        // address. Add an entry to the ARP cache to save future ARP probes and make sure the
-        // packet reaches its destination.
-        if (!addArpEntry(clientMac, lease.getNetAddr())) {
-            // Logging for error already done
-            return false;
-        }
-        final Inet4Address dst = getAckOrOfferDst(request, lease, broadcastFlag);
-        return transmitPacket(buf, request.getClass().getSimpleName(), dst);
-    }
-
-    private boolean transmitPacket(@NonNull ByteBuffer buf, @NonNull String packetTypeTag,
-            @NonNull Inet4Address dst) {
-        try {
-            mDeps.sendPacket(mSocket, buf, dst);
-        } catch (ErrnoException | IOException e) {
-            mLog.e("Can't send packet " + packetTypeTag, e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean addArpEntry(@NonNull MacAddress macAddr, @NonNull Inet4Address inetAddr) {
-        try {
-            mDeps.addArpEntry(inetAddr, macAddr, mIfName, mSocket);
-            return true;
-        } catch (IOException e) {
-            mLog.e("Error adding client to ARP table", e);
-            return false;
-        }
-    }
-
-    /**
-     * Get the remaining lease time in seconds, starting from {@link Clock#elapsedRealtime()}.
-     *
-     * <p>This is an unsigned 32-bit integer, so it cannot be read as a standard (signed) Java int.
-     * The return value is only intended to be used to populate the lease time field in a DHCP
-     * response, considering that lease time is an unsigned 32-bit integer field in DHCP packets.
-     *
-     * <p>Lease expiration times are tracked internally with millisecond precision: this method
-     * returns a rounded down value.
-     */
-    private int getLeaseTimeout(@NonNull DhcpLease lease) {
-        final long remainingTimeSecs = (lease.getExpTime() - mClock.elapsedRealtime()) / 1000;
-        if (remainingTimeSecs < 0) {
-            mLog.e("Processing expired lease " + lease);
-            return EXPIRED_FALLBACK_LEASE_TIME_SECS;
-        }
-
-        if (remainingTimeSecs >= toUnsignedLong(INFINITE_LEASE)) {
-            return INFINITE_LEASE;
-        }
-
-        return (int) remainingTimeSecs;
-    }
-
-    /**
-     * Get the client MAC address from a packet.
-     *
-     * @throws MalformedPacketException The address in the packet uses an unsupported format.
-     */
-    @NonNull
-    private MacAddress getMacAddr(@NonNull DhcpPacket packet) throws MalformedPacketException {
-        try {
-            return MacAddress.fromBytes(packet.getClientMac());
-        } catch (IllegalArgumentException e) {
-            final String message = "Invalid MAC address in packet: "
-                    + HexDump.dumpHexString(packet.getClientMac());
-            throw new MalformedPacketException(message, e);
-        }
-    }
-
-    private static boolean isEmpty(@Nullable Inet4Address address) {
-        return address == null || IPV4_ADDR_ANY.equals(address);
-    }
-
-    private class PacketListener extends DhcpPacketListener {
-        PacketListener() {
-            super(mHandler);
-        }
-
-        @Override
-        protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
-                int srcPort) {
-            processPacket(packet, srcPort);
-        }
-
-        @Override
-        protected void logError(@NonNull String msg, Exception e) {
-            mLog.e("Error receiving packet: " + msg, e);
-        }
-
-        @Override
-        protected void logParseError(@NonNull byte[] packet, int length,
-                @NonNull DhcpPacket.ParseException e) {
-            mLog.e("Error parsing packet", e);
-        }
-
-        @Override
-        protected FileDescriptor createFd() {
-            // TODO: have and use an API to set a socket tag without going through the thread tag
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_DHCP_SERVER);
-            try {
-                mSocket = Os.socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
-                SocketUtils.bindSocketToInterface(mSocket, mIfName);
-                Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1);
-                Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
-                Os.bind(mSocket, IPV4_ADDR_ANY, DHCP_SERVER);
-
-                return mSocket;
-            } catch (IOException | ErrnoException e) {
-                mLog.e("Error creating UDP socket", e);
-                DhcpServer.this.stop(null);
-                return null;
-            } finally {
-                TrafficStats.setThreadStatsTag(oldTag);
-            }
-        }
-    }
-
-    @Override
-    public int getInterfaceVersion() {
-        return this.VERSION;
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
deleted file mode 100644
index 230b693..0000000
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-
-import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
-import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU;
-import static com.android.server.util.NetworkStackConstants.IPV4_MIN_MTU;
-
-import static java.lang.Integer.toUnsignedLong;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.shared.Inet4AddressUtils;
-import android.util.ArraySet;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Parameters used by the DhcpServer to serve requests.
- *
- * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate.
- * @hide
- */
-public class DhcpServingParams {
-    public static final int MTU_UNSET = 0;
-    public static final int MIN_PREFIX_LENGTH = 16;
-    public static final int MAX_PREFIX_LENGTH = 30;
-
-    /** Server inet address and prefix to serve */
-    @NonNull
-    public final LinkAddress serverAddr;
-
-    /**
-     * Default routers to be advertised to DHCP clients. May be empty.
-     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
-     */
-    @NonNull
-    public final Set<Inet4Address> defaultRouters;
-
-    /**
-     * DNS servers to be advertised to DHCP clients. May be empty.
-     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
-     */
-    @NonNull
-    public final Set<Inet4Address> dnsServers;
-
-    /**
-     * Excluded addresses that the DHCP server is not allowed to assign to clients.
-     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
-     */
-    @NonNull
-    public final Set<Inet4Address> excludedAddrs;
-
-    // DHCP uses uint32. Use long for clearer code, and check range when building.
-    public final long dhcpLeaseTimeSecs;
-    public final int linkMtu;
-
-    /**
-     * Indicates whether the DHCP server should send the ANDROID_METERED vendor-specific option.
-     */
-    public final boolean metered;
-
-    /**
-     * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
-     * missing or invalid.
-     */
-    public static class InvalidParameterException extends Exception {
-        public InvalidParameterException(String message) {
-            super(message);
-        }
-    }
-
-    private DhcpServingParams(@NonNull LinkAddress serverAddr,
-            @NonNull Set<Inet4Address> defaultRouters,
-            @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
-            long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
-        this.serverAddr = serverAddr;
-        this.defaultRouters = defaultRouters;
-        this.dnsServers = dnsServers;
-        this.excludedAddrs = excludedAddrs;
-        this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
-        this.linkMtu = linkMtu;
-        this.metered = metered;
-    }
-
-    /**
-     * Create parameters from a stable AIDL-compatible parcel.
-     * @throws InvalidParameterException The parameters parcelable is null or invalid.
-     */
-    public static DhcpServingParams fromParcelableObject(@Nullable DhcpServingParamsParcel parcel)
-            throws InvalidParameterException {
-        if (parcel == null) {
-            throw new InvalidParameterException("Null serving parameters");
-        }
-        final LinkAddress serverAddr = new LinkAddress(
-                intToInet4AddressHTH(parcel.serverAddr),
-                parcel.serverAddrPrefixLength);
-        return new Builder()
-                .setServerAddr(serverAddr)
-                .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters))
-                .setDnsServers(toInet4AddressSet(parcel.dnsServers))
-                .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs))
-                .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs)
-                .setLinkMtu(parcel.linkMtu)
-                .setMetered(parcel.metered)
-                .build();
-    }
-
-    private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) {
-        if (addrs == null) {
-            return new HashSet<>(0);
-        }
-
-        final HashSet<Inet4Address> res = new HashSet<>();
-        for (int addr : addrs) {
-            res.add(intToInet4AddressHTH(addr));
-        }
-        return res;
-    }
-
-    @NonNull
-    public Inet4Address getServerInet4Addr() {
-        return (Inet4Address) serverAddr.getAddress();
-    }
-
-    /**
-     * Get the served prefix mask as an IPv4 address.
-     *
-     * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0.
-     */
-    @NonNull
-    public Inet4Address getPrefixMaskAsAddress() {
-        return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength());
-    }
-
-    /**
-     * Get the server broadcast address.
-     *
-     * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return
-     * 192.168.42.255.
-     */
-    @NonNull
-    public Inet4Address getBroadcastAddress() {
-        return Inet4AddressUtils.getBroadcastAddress(
-                getServerInet4Addr(), serverAddr.getPrefixLength());
-    }
-
-    /**
-     * Utility class to create new instances of {@link DhcpServingParams} while checking validity
-     * of the parameters.
-     */
-    public static class Builder {
-        private LinkAddress mServerAddr;
-        private Set<Inet4Address> mDefaultRouters;
-        private Set<Inet4Address> mDnsServers;
-        private Set<Inet4Address> mExcludedAddrs;
-        private long mDhcpLeaseTimeSecs;
-        private int mLinkMtu = MTU_UNSET;
-        private boolean mMetered;
-
-        /**
-         * Set the server address and served prefix for the DHCP server.
-         *
-         * <p>This parameter is required.
-         */
-        public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
-            this.mServerAddr = serverAddr;
-            return this;
-        }
-
-        /**
-         * Set the default routers to be advertised to DHCP clients.
-         *
-         * <p>Each router must be inside the served prefix. This may be an empty set, but it must
-         * always be set explicitly before building the {@link DhcpServingParams}.
-         */
-        public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
-            this.mDefaultRouters = defaultRouters;
-            return this;
-        }
-
-        /**
-         * Set the default routers to be advertised to DHCP clients.
-         *
-         * <p>Each router must be inside the served prefix. This may be an empty list of routers,
-         * but it must always be set explicitly before building the {@link DhcpServingParams}.
-         */
-        public Builder setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
-            return setDefaultRouters(makeArraySet(defaultRouters));
-        }
-
-        /**
-         * Convenience method to build the parameters with no default router.
-         *
-         * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
-         */
-        public Builder withNoDefaultRouter() {
-            return setDefaultRouters();
-        }
-
-        /**
-         * Set the DNS servers to be advertised to DHCP clients.
-         *
-         * <p>This may be an empty set, but it must always be set explicitly before building the
-         * {@link DhcpServingParams}.
-         */
-        public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
-            this.mDnsServers = dnsServers;
-            return this;
-        }
-
-        /**
-         * Set the DNS servers to be advertised to DHCP clients.
-         *
-         * <p>This may be an empty list of servers, but it must always be set explicitly before
-         * building the {@link DhcpServingParams}.
-         */
-        public Builder setDnsServers(@NonNull Inet4Address... dnsServers) {
-            return setDnsServers(makeArraySet(dnsServers));
-        }
-
-        /**
-         * Convenience method to build the parameters with no DNS server.
-         *
-         * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
-         */
-        public Builder withNoDnsServer() {
-            return setDnsServers();
-        }
-
-        /**
-         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
-         *
-         * <p>This parameter is optional. DNS servers and default routers are always excluded
-         * and do not need to be set here.
-         */
-        public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
-            this.mExcludedAddrs = excludedAddrs;
-            return this;
-        }
-
-        /**
-         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
-         *
-         * <p>This parameter is optional. DNS servers and default routers are always excluded
-         * and do not need to be set here.
-         */
-        public Builder setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
-            return setExcludedAddrs(makeArraySet(excludedAddrs));
-        }
-
-        /**
-         * Set the lease time for leases assigned by the DHCP server.
-         *
-         * <p>This parameter is required.
-         */
-        public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
-            this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
-            return this;
-        }
-
-        /**
-         * Set the link MTU to be advertised to DHCP clients.
-         *
-         * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
-         * is optional and defaults to {@link #MTU_UNSET}.
-         */
-        public Builder setLinkMtu(int linkMtu) {
-            this.mLinkMtu = linkMtu;
-            return this;
-        }
-
-        /**
-         * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
-         *
-         * <p>If not set, the default value is false.
-         */
-        public Builder setMetered(boolean metered) {
-            this.mMetered = metered;
-            return this;
-        }
-
-        /**
-         * Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
-         *
-         * <p>This method has no side-effects. If it does not throw, a valid
-         * {@link DhcpServingParams} is returned.
-         * @return The constructed parameters.
-         * @throws InvalidParameterException At least one parameter is missing or invalid.
-         */
-        @NonNull
-        public DhcpServingParams build() throws InvalidParameterException {
-            if (mServerAddr == null) {
-                throw new InvalidParameterException("Missing serverAddr");
-            }
-            if (mDefaultRouters == null) {
-                throw new InvalidParameterException("Missing defaultRouters");
-            }
-            if (mDnsServers == null) {
-                // Empty set is OK, but enforce explicitly setting it
-                throw new InvalidParameterException("Missing dnsServers");
-            }
-            if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
-                throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs);
-            }
-            if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
-                throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
-            }
-            if (!mServerAddr.isIpv4()) {
-                throw new InvalidParameterException("serverAddr must be IPv4");
-            }
-            if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
-                    || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
-                throw new InvalidParameterException("Prefix length is not in supported range");
-            }
-
-            final IpPrefix prefix = makeIpPrefix(mServerAddr);
-            for (Inet4Address addr : mDefaultRouters) {
-                if (!prefix.contains(addr)) {
-                    throw new InvalidParameterException(String.format(
-                            "Default router %s is not in server prefix %s", addr, mServerAddr));
-                }
-            }
-
-            final Set<Inet4Address> excl = new HashSet<>();
-            if (mExcludedAddrs != null) {
-                excl.addAll(mExcludedAddrs);
-            }
-            excl.add((Inet4Address) mServerAddr.getAddress());
-            excl.addAll(mDefaultRouters);
-            excl.addAll(mDnsServers);
-
-            return new DhcpServingParams(mServerAddr,
-                    Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)),
-                    Collections.unmodifiableSet(new HashSet<>(mDnsServers)),
-                    Collections.unmodifiableSet(excl),
-                    mDhcpLeaseTimeSecs, mLinkMtu, mMetered);
-        }
-    }
-
-    /**
-     * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress.
-     */
-    @NonNull
-    static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
-        return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
-    }
-
-    private static <T> ArraySet<T> makeArraySet(T[] elements) {
-        final ArraySet<T> set = new ArraySet<>(elements.length);
-        set.addAll(Arrays.asList(elements));
-        return set;
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
deleted file mode 100644
index eb49218..0000000
--- a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2016 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.ip;
-
-import static android.net.util.SocketUtils.makePacketSocketAddress;
-import static android.system.OsConstants.AF_PACKET;
-import static android.system.OsConstants.ARPHRD_ETHER;
-import static android.system.OsConstants.ETH_P_ALL;
-import static android.system.OsConstants.SOCK_NONBLOCK;
-import static android.system.OsConstants.SOCK_RAW;
-
-import android.net.util.ConnectivityPacketSummary;
-import android.net.util.InterfaceParams;
-import android.net.util.NetworkStackUtils;
-import android.net.util.PacketReader;
-import android.os.Handler;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-
-import com.android.internal.util.HexDump;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-
-/**
- * Critical connectivity packet tracking daemon.
- *
- * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
- *
- * This class's constructor, start() and stop() methods must only be called
- * from the same thread on which the passed in |log| is accessed.
- *
- * Log lines include a hexdump of the packet, which can be decoded via:
- *
- *     echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
- *                       | text2pcap - -
- *                       | tcpdump -n -vv -e -r -
- *
- * @hide
- */
-public class ConnectivityPacketTracker {
-    private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
-    private static final boolean DBG = false;
-    private static final String MARK_START = "--- START ---";
-    private static final String MARK_STOP = "--- STOP ---";
-    private static final String MARK_NAMED_START = "--- START (%s) ---";
-    private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
-
-    private final String mTag;
-    private final LocalLog mLog;
-    private final PacketReader mPacketListener;
-    private boolean mRunning;
-    private String mDisplayName;
-
-    public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
-        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
-
-        mTag = TAG + "." + ifParams.name;
-        mLog = log;
-        mPacketListener = new PacketListener(h, ifParams);
-    }
-
-    public void start(String displayName) {
-        mRunning = true;
-        mDisplayName = displayName;
-        mPacketListener.start();
-    }
-
-    public void stop() {
-        mPacketListener.stop();
-        mRunning = false;
-        mDisplayName = null;
-    }
-
-    private final class PacketListener extends PacketReader {
-        private final InterfaceParams mInterface;
-
-        PacketListener(Handler h, InterfaceParams ifParams) {
-            super(h, ifParams.defaultMtu);
-            mInterface = ifParams;
-        }
-
-        @Override
-        protected FileDescriptor createFd() {
-            FileDescriptor s = null;
-            try {
-                s = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
-                NetworkStackUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
-                Os.bind(s, makePacketSocketAddress((short) ETH_P_ALL, mInterface.index));
-            } catch (ErrnoException | IOException e) {
-                logError("Failed to create packet tracking socket: ", e);
-                closeFd(s);
-                return null;
-            }
-            return s;
-        }
-
-        @Override
-        protected void handlePacket(byte[] recvbuf, int length) {
-            final String summary = ConnectivityPacketSummary.summarize(
-                    mInterface.macAddr, recvbuf, length);
-            if (summary == null) return;
-
-            if (DBG) Log.d(mTag, summary);
-            addLogEntry(summary + "\n[" + HexDump.toHexString(recvbuf, 0, length) + "]");
-        }
-
-        @Override
-        protected void onStart() {
-            final String msg = TextUtils.isEmpty(mDisplayName)
-                    ? MARK_START
-                    : String.format(MARK_NAMED_START, mDisplayName);
-            mLog.log(msg);
-        }
-
-        @Override
-        protected void onStop() {
-            String msg = TextUtils.isEmpty(mDisplayName)
-                    ? MARK_STOP
-                    : String.format(MARK_NAMED_STOP, mDisplayName);
-            if (!mRunning) msg += " (packet listener stopped unexpectedly)";
-            mLog.log(msg);
-        }
-
-        @Override
-        protected void logError(String msg, Exception e) {
-            Log.e(mTag, msg, e);
-            addLogEntry(msg + e);
-        }
-
-        private void addLogEntry(String entry) {
-            mLog.log(entry);
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
deleted file mode 100644
index 266b1b0..0000000
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ /dev/null
@@ -1,1784 +0,0 @@
-/*
- * Copyright (C) 2017 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.ip;
-
-import static android.net.RouteInfo.RTN_UNICAST;
-import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
-
-import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.DhcpResults;
-import android.net.INetd;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NattKeepalivePacketDataParcelable;
-import android.net.NetworkStackIpMemoryStore;
-import android.net.ProvisioningConfigurationParcelable;
-import android.net.ProxyInfo;
-import android.net.RouteInfo;
-import android.net.TcpKeepalivePacketDataParcelable;
-import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
-import android.net.dhcp.DhcpClient;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpManagerEvent;
-import android.net.shared.InitialConfiguration;
-import android.net.shared.ProvisioningConfiguration;
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IState;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.internal.util.WakeupMessage;
-import com.android.server.NetworkObserverRegistry;
-import com.android.server.NetworkStackService.NetworkStackServiceManager;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.InetAddress;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-
-/**
- * IpClient
- *
- * This class provides the interface to IP-layer provisioning and maintenance
- * functionality that can be used by transport layers like Wi-Fi, Ethernet,
- * et cetera.
- *
- * [ Lifetime ]
- * IpClient is designed to be instantiated as soon as the interface name is
- * known and can be as long-lived as the class containing it (i.e. declaring
- * it "private final" is okay).
- *
- * @hide
- */
-public class IpClient extends StateMachine {
-    private static final boolean DBG = false;
-
-    // For message logging.
-    private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
-    private static final SparseArray<String> sWhatToString =
-            MessageUtils.findMessageNames(sMessageClasses);
-    // Two static concurrent hashmaps of interface name to logging classes.
-    // One holds StateMachine logs and the other connectivity packet logs.
-    private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
-    private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
-    private final NetworkStackIpMemoryStore mIpMemoryStore;
-
-    /**
-     * Dump all state machine and connectivity packet logs to the specified writer.
-     * @param skippedIfaces Interfaces for which logs should not be dumped.
-     */
-    public static void dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces) {
-        for (String ifname : sSmLogs.keySet()) {
-            if (skippedIfaces.contains(ifname)) continue;
-
-            writer.println(String.format("--- BEGIN %s ---", ifname));
-
-            final SharedLog smLog = sSmLogs.get(ifname);
-            if (smLog != null) {
-                writer.println("State machine log:");
-                smLog.dump(null, writer, null);
-            }
-
-            writer.println("");
-
-            final LocalLog pktLog = sPktLogs.get(ifname);
-            if (pktLog != null) {
-                writer.println("Connectivity packet log:");
-                pktLog.readOnlyLocalLog().dump(null, writer, null);
-            }
-
-            writer.println(String.format("--- END %s ---", ifname));
-        }
-    }
-
-    // Use a wrapper class to log in order to ensure complete and detailed
-    // logging. This method is lighter weight than annotations/reflection
-    // and has the following benefits:
-    //
-    //     - No invoked method can be forgotten.
-    //       Any new method added to IpClient.Callback must be overridden
-    //       here or it will never be called.
-    //
-    //     - No invoking call site can be forgotten.
-    //       Centralized logging in this way means call sites don't need to
-    //       remember to log, and therefore no call site can be forgotten.
-    //
-    //     - No variation in log format among call sites.
-    //       Encourages logging of any available arguments, and all call sites
-    //       are necessarily logged identically.
-    //
-    // NOTE: Log first because passed objects may or may not be thread-safe and
-    // once passed on to the callback they may be modified by another thread.
-    //
-    // TODO: Find an lighter weight approach.
-    public static class IpClientCallbacksWrapper {
-        private static final String PREFIX = "INVOKE ";
-        private final IIpClientCallbacks mCallback;
-        private final SharedLog mLog;
-
-        @VisibleForTesting
-        protected IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log) {
-            mCallback = callback;
-            mLog = log;
-        }
-
-        private void log(String msg) {
-            mLog.log(PREFIX + msg);
-        }
-
-        private void log(String msg, Throwable e) {
-            mLog.e(PREFIX + msg, e);
-        }
-
-        public void onPreDhcpAction() {
-            log("onPreDhcpAction()");
-            try {
-                mCallback.onPreDhcpAction();
-            } catch (RemoteException e) {
-                log("Failed to call onPreDhcpAction", e);
-            }
-        }
-
-        public void onPostDhcpAction() {
-            log("onPostDhcpAction()");
-            try {
-                mCallback.onPostDhcpAction();
-            } catch (RemoteException e) {
-                log("Failed to call onPostDhcpAction", e);
-            }
-        }
-
-        public void onNewDhcpResults(DhcpResults dhcpResults) {
-            log("onNewDhcpResults({" + dhcpResults + "})");
-            try {
-                mCallback.onNewDhcpResults(toStableParcelable(dhcpResults));
-            } catch (RemoteException e) {
-                log("Failed to call onNewDhcpResults", e);
-            }
-        }
-
-        public void onProvisioningSuccess(LinkProperties newLp) {
-            log("onProvisioningSuccess({" + newLp + "})");
-            try {
-                mCallback.onProvisioningSuccess(newLp);
-            } catch (RemoteException e) {
-                log("Failed to call onProvisioningSuccess", e);
-            }
-        }
-
-        public void onProvisioningFailure(LinkProperties newLp) {
-            log("onProvisioningFailure({" + newLp + "})");
-            try {
-                mCallback.onProvisioningFailure(newLp);
-            } catch (RemoteException e) {
-                log("Failed to call onProvisioningFailure", e);
-            }
-        }
-
-        public void onLinkPropertiesChange(LinkProperties newLp) {
-            log("onLinkPropertiesChange({" + newLp + "})");
-            try {
-                mCallback.onLinkPropertiesChange(newLp);
-            } catch (RemoteException e) {
-                log("Failed to call onLinkPropertiesChange", e);
-            }
-        }
-
-        public void onReachabilityLost(String logMsg) {
-            log("onReachabilityLost(" + logMsg + ")");
-            try {
-                mCallback.onReachabilityLost(logMsg);
-            } catch (RemoteException e) {
-                log("Failed to call onReachabilityLost", e);
-            }
-        }
-
-        public void onQuit() {
-            log("onQuit()");
-            try {
-                mCallback.onQuit();
-            } catch (RemoteException e) {
-                log("Failed to call onQuit", e);
-            }
-        }
-
-        public void installPacketFilter(byte[] filter) {
-            log("installPacketFilter(byte[" + filter.length + "])");
-            try {
-                mCallback.installPacketFilter(filter);
-            } catch (RemoteException e) {
-                log("Failed to call installPacketFilter", e);
-            }
-        }
-
-        public void startReadPacketFilter() {
-            log("startReadPacketFilter()");
-            try {
-                mCallback.startReadPacketFilter();
-            } catch (RemoteException e) {
-                log("Failed to call startReadPacketFilter", e);
-            }
-        }
-
-        public void setFallbackMulticastFilter(boolean enabled) {
-            log("setFallbackMulticastFilter(" + enabled + ")");
-            try {
-                mCallback.setFallbackMulticastFilter(enabled);
-            } catch (RemoteException e) {
-                log("Failed to call setFallbackMulticastFilter", e);
-            }
-        }
-
-        public void setNeighborDiscoveryOffload(boolean enable) {
-            log("setNeighborDiscoveryOffload(" + enable + ")");
-            try {
-                mCallback.setNeighborDiscoveryOffload(enable);
-            } catch (RemoteException e) {
-                log("Failed to call setNeighborDiscoveryOffload", e);
-            }
-        }
-    }
-
-    public static final String DUMP_ARG_CONFIRM = "confirm";
-
-    // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
-    private static final int CMD_TERMINATE_AFTER_STOP             = 1;
-    private static final int CMD_STOP                             = 2;
-    private static final int CMD_START                            = 3;
-    private static final int CMD_CONFIRM                          = 4;
-    private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
-    // Triggered by NetlinkTracker to communicate netlink events.
-    private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
-    private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
-    private static final int CMD_UPDATE_HTTP_PROXY                = 8;
-    private static final int CMD_SET_MULTICAST_FILTER             = 9;
-    private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
-    private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
-    private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
-    private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
-    private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
-    private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15;
-
-    // Internal commands to use instead of trying to call transitionTo() inside
-    // a given State's enter() method. Calling transitionTo() from enter/exit
-    // encounters a Log.wtf() that can cause trouble on eng builds.
-    private static final int CMD_JUMP_STARTED_TO_RUNNING          = 100;
-    private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
-    private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
-
-    // IpClient shares a handler with DhcpClient: commands must not overlap
-    public static final int DHCPCLIENT_CMD_BASE = 1000;
-
-    private static final int MAX_LOG_RECORDS = 500;
-    private static final int MAX_PACKET_RECORDS = 100;
-
-    private static final boolean NO_CALLBACKS = false;
-    private static final boolean SEND_CALLBACKS = true;
-
-    // This must match the interface prefix in clatd.c.
-    // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
-    private static final String CLAT_PREFIX = "v4-";
-
-    private static final int IMMEDIATE_FAILURE_DURATION = 0;
-
-    private static final int PROV_CHANGE_STILL_NOT_PROVISIONED = 1;
-    private static final int PROV_CHANGE_LOST_PROVISIONING = 2;
-    private static final int PROV_CHANGE_GAINED_PROVISIONING = 3;
-    private static final int PROV_CHANGE_STILL_PROVISIONED = 4;
-
-    private final State mStoppedState = new StoppedState();
-    private final State mStoppingState = new StoppingState();
-    private final State mStartedState = new StartedState();
-    private final State mRunningState = new RunningState();
-
-    private final String mTag;
-    private final Context mContext;
-    private final String mInterfaceName;
-    private final String mClatInterfaceName;
-    @VisibleForTesting
-    protected final IpClientCallbacksWrapper mCallback;
-    private final Dependencies mDependencies;
-    private final CountDownLatch mShutdownLatch;
-    private final ConnectivityManager mCm;
-    private final INetd mNetd;
-    private final NetworkObserverRegistry mObserverRegistry;
-    private final IpClientLinkObserver mLinkObserver;
-    private final WakeupMessage mProvisioningTimeoutAlarm;
-    private final WakeupMessage mDhcpActionTimeoutAlarm;
-    private final SharedLog mLog;
-    private final LocalLog mConnectivityPacketLog;
-    private final MessageHandlingLogger mMsgStateLogger;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-    private final InterfaceController mInterfaceCtrl;
-
-    private InterfaceParams mInterfaceParams;
-
-    /**
-     * Non-final member variables accessed only from within our StateMachine.
-     */
-    private LinkProperties mLinkProperties;
-    private android.net.shared.ProvisioningConfiguration mConfiguration;
-    private IpReachabilityMonitor mIpReachabilityMonitor;
-    private DhcpClient mDhcpClient;
-    private DhcpResults mDhcpResults;
-    private String mTcpBufferSizes;
-    private ProxyInfo mHttpProxy;
-    private ApfFilter mApfFilter;
-    private String mL2Key; // The L2 key for this network, for writing into the memory store
-    private String mGroupHint; // The group hint for this network, for writing into the memory store
-    private boolean mMulticastFiltering;
-    private long mStartTimeMillis;
-
-    /**
-     * Reading the snapshot is an asynchronous operation initiated by invoking
-     * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
-     * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
-     * signals when a new snapshot is ready.
-     */
-    private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
-
-    public static class Dependencies {
-        /**
-         * Get interface parameters for the specified interface.
-         */
-        public InterfaceParams getInterfaceParams(String ifname) {
-            return InterfaceParams.getByName(ifname);
-        }
-
-        /**
-         * Get a INetd connector.
-         */
-        public INetd getNetd(Context context) {
-            return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
-        }
-    }
-
-    public IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
-        this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
-    }
-
-    @VisibleForTesting
-    IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
-            Dependencies deps) {
-        super(IpClient.class.getSimpleName() + "." + ifName);
-        Preconditions.checkNotNull(ifName);
-        Preconditions.checkNotNull(callback);
-
-        mTag = getName();
-
-        mContext = context;
-        mInterfaceName = ifName;
-        mClatInterfaceName = CLAT_PREFIX + ifName;
-        mDependencies = deps;
-        mShutdownLatch = new CountDownLatch(1);
-        mCm = mContext.getSystemService(ConnectivityManager.class);
-        mObserverRegistry = observerRegistry;
-        mIpMemoryStore =
-                new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
-
-        sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
-        mLog = sSmLogs.get(mInterfaceName);
-        sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
-        mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
-        mMsgStateLogger = new MessageHandlingLogger();
-        mCallback = new IpClientCallbacksWrapper(callback, mLog);
-
-        // TODO: Consider creating, constructing, and passing in some kind of
-        // InterfaceController.Dependencies class.
-        mNetd = deps.getNetd(mContext);
-        mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
-
-        mLinkObserver = new IpClientLinkObserver(
-                mInterfaceName,
-                () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) {
-            @Override
-            public void onInterfaceAdded(String iface) {
-                super.onInterfaceAdded(iface);
-                if (mClatInterfaceName.equals(iface)) {
-                    mCallback.setNeighborDiscoveryOffload(false);
-                } else if (!mInterfaceName.equals(iface)) {
-                    return;
-                }
-
-                final String msg = "interfaceAdded(" + iface + ")";
-                logMsg(msg);
-            }
-
-            @Override
-            public void onInterfaceRemoved(String iface) {
-                super.onInterfaceRemoved(iface);
-                // TODO: Also observe mInterfaceName going down and take some
-                // kind of appropriate action.
-                if (mClatInterfaceName.equals(iface)) {
-                    // TODO: consider sending a message to the IpClient main
-                    // StateMachine thread, in case "NDO enabled" state becomes
-                    // tied to more things that 464xlat operation.
-                    mCallback.setNeighborDiscoveryOffload(true);
-                } else if (!mInterfaceName.equals(iface)) {
-                    return;
-                }
-
-                final String msg = "interfaceRemoved(" + iface + ")";
-                logMsg(msg);
-            }
-
-            private void logMsg(String msg) {
-                Log.d(mTag, msg);
-                getHandler().post(() -> mLog.log("OBSERVED " + msg));
-            }
-        };
-
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-
-        mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
-                mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
-        mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
-                mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
-
-        // Anything the StateMachine may access must have been instantiated
-        // before this point.
-        configureAndStartStateMachine();
-
-        // Anything that may send messages to the StateMachine must only be
-        // configured to do so after the StateMachine has started (above).
-        startStateMachineUpdaters();
-    }
-
-    /**
-     * Make a IIpClient connector to communicate with this IpClient.
-     */
-    public IIpClient makeConnector() {
-        return new IpClientConnector();
-    }
-
-    class IpClientConnector extends IIpClient.Stub {
-        @Override
-        public void completedPreDhcpAction() {
-            checkNetworkStackCallingPermission();
-            IpClient.this.completedPreDhcpAction();
-        }
-        @Override
-        public void confirmConfiguration() {
-            checkNetworkStackCallingPermission();
-            IpClient.this.confirmConfiguration();
-        }
-        @Override
-        public void readPacketFilterComplete(byte[] data) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.readPacketFilterComplete(data);
-        }
-        @Override
-        public void shutdown() {
-            checkNetworkStackCallingPermission();
-            IpClient.this.shutdown();
-        }
-        @Override
-        public void startProvisioning(ProvisioningConfigurationParcelable req) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req));
-        }
-        @Override
-        public void stop() {
-            checkNetworkStackCallingPermission();
-            IpClient.this.stop();
-        }
-        @Override
-        public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint);
-        }
-        @Override
-        public void setTcpBufferSizes(String tcpBufferSizes) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.setTcpBufferSizes(tcpBufferSizes);
-        }
-        @Override
-        public void setHttpProxy(ProxyInfo proxyInfo) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.setHttpProxy(proxyInfo);
-        }
-        @Override
-        public void setMulticastFilter(boolean enabled) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.setMulticastFilter(enabled);
-        }
-        @Override
-        public void addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.addKeepalivePacketFilter(slot, pkt);
-        }
-        @Override
-        public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
-        }
-        @Override
-        public void removeKeepalivePacketFilter(int slot) {
-            checkNetworkStackCallingPermission();
-            IpClient.this.removeKeepalivePacketFilter(slot);
-        }
-
-        @Override
-        public int getInterfaceVersion() {
-            return this.VERSION;
-        }
-    }
-
-    public String getInterfaceName() {
-        return mInterfaceName;
-    }
-
-    private void configureAndStartStateMachine() {
-        // CHECKSTYLE:OFF IndentationCheck
-        addState(mStoppedState);
-        addState(mStartedState);
-            addState(mRunningState, mStartedState);
-        addState(mStoppingState);
-        // CHECKSTYLE:ON IndentationCheck
-
-        setInitialState(mStoppedState);
-
-        super.start();
-    }
-
-    private void startStateMachineUpdaters() {
-        mObserverRegistry.registerObserverForNonblockingCallback(mLinkObserver);
-    }
-
-    private void stopStateMachineUpdaters() {
-        mObserverRegistry.unregisterObserver(mLinkObserver);
-    }
-
-    @Override
-    protected void onQuitting() {
-        mCallback.onQuit();
-        mShutdownLatch.countDown();
-    }
-
-    /**
-     * Shut down this IpClient instance altogether.
-     */
-    public void shutdown() {
-        stop();
-        sendMessage(CMD_TERMINATE_AFTER_STOP);
-    }
-
-    /**
-     * Start provisioning with the provided parameters.
-     */
-    public void startProvisioning(ProvisioningConfiguration req) {
-        if (!req.isValid()) {
-            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-            return;
-        }
-
-        mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
-        if (mInterfaceParams == null) {
-            logError("Failed to find InterfaceParams for " + mInterfaceName);
-            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
-            return;
-        }
-
-        mCallback.setNeighborDiscoveryOffload(true);
-        sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
-    }
-
-    /**
-     * Stop this IpClient.
-     *
-     * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}.
-     */
-    public void stop() {
-        sendMessage(CMD_STOP);
-    }
-
-    /**
-     * Confirm the provisioning configuration.
-     */
-    public void confirmConfiguration() {
-        sendMessage(CMD_CONFIRM);
-    }
-
-    /**
-     * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be
-     * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to
-     * proceed.
-     */
-    public void completedPreDhcpAction() {
-        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
-    }
-
-    /**
-     * Indicate that packet filter read is complete.
-     */
-    public void readPacketFilterComplete(byte[] data) {
-        sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
-    }
-
-    /**
-     * Set the TCP buffer sizes to use.
-     *
-     * This may be called, repeatedly, at any time before or after a call to
-     * #startProvisioning(). The setting is cleared upon calling #stop().
-     */
-    public void setTcpBufferSizes(String tcpBufferSizes) {
-        sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
-    }
-
-    /**
-     * Set the L2 key and group hint for storing info into the memory store.
-     */
-    public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
-        sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint));
-    }
-
-    /**
-     * Set the HTTP Proxy configuration to use.
-     *
-     * This may be called, repeatedly, at any time before or after a call to
-     * #startProvisioning(). The setting is cleared upon calling #stop().
-     */
-    public void setHttpProxy(ProxyInfo proxyInfo) {
-        sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
-    }
-
-    /**
-     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
-     * if not, Callback.setFallbackMulticastFilter() is called.
-     */
-    public void setMulticastFilter(boolean enabled) {
-        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
-    }
-
-    /**
-     * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
-     * keepalive offload.
-     */
-    public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
-        sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
-    }
-
-    /**
-     *  Called by WifiStateMachine to add NATT keepalive packet filter before setting up
-     *  keepalive offload.
-     */
-    public void addNattKeepalivePacketFilter(int slot,
-            @NonNull NattKeepalivePacketDataParcelable pkt) {
-        sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */ , pkt);
-    }
-
-    /**
-     * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive
-     * offload.
-     */
-    public void removeKeepalivePacketFilter(int slot) {
-        sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */);
-    }
-
-    /**
-     * Dump logs of this IpClient.
-     */
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
-            // Execute confirmConfiguration() and take no further action.
-            confirmConfiguration();
-            return;
-        }
-
-        // Thread-unsafe access to mApfFilter but just used for debugging.
-        final ApfFilter apfFilter = mApfFilter;
-        final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
-        final ApfCapabilities apfCapabilities = (provisioningConfig != null)
-                ? provisioningConfig.mApfCapabilities : null;
-
-        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println(mTag + " APF dump:");
-        pw.increaseIndent();
-        if (apfFilter != null) {
-            if (apfCapabilities.hasDataAccess()) {
-                // Request a new snapshot, then wait for it.
-                mApfDataSnapshotComplete.close();
-                mCallback.startReadPacketFilter();
-                if (!mApfDataSnapshotComplete.block(1000)) {
-                    pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
-                }
-            }
-            apfFilter.dump(pw);
-
-        } else {
-            pw.print("No active ApfFilter; ");
-            if (provisioningConfig == null) {
-                pw.println("IpClient not yet started.");
-            } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
-                pw.println("Hardware does not support APF.");
-            } else {
-                pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
-            }
-        }
-        pw.decreaseIndent();
-        pw.println();
-        pw.println(mTag + " current ProvisioningConfiguration:");
-        pw.increaseIndent();
-        pw.println(Objects.toString(provisioningConfig, "N/A"));
-        pw.decreaseIndent();
-
-        final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
-        if (iprm != null) {
-            pw.println();
-            pw.println(mTag + " current IpReachabilityMonitor state:");
-            pw.increaseIndent();
-            iprm.dump(pw);
-            pw.decreaseIndent();
-        }
-
-        pw.println();
-        pw.println(mTag + " StateMachine dump:");
-        pw.increaseIndent();
-        mLog.dump(fd, pw, args);
-        pw.decreaseIndent();
-
-        pw.println();
-        pw.println(mTag + " connectivity packet log:");
-        pw.println();
-        pw.println("Debug with python and scapy via:");
-        pw.println("shell$ python");
-        pw.println(">>> from scapy import all as scapy");
-        pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
-        pw.println();
-
-        pw.increaseIndent();
-        mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
-        pw.decreaseIndent();
-    }
-
-
-    /**
-     * Internals.
-     */
-
-    @Override
-    protected String getWhatToString(int what) {
-        return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
-    }
-
-    @Override
-    protected String getLogRecString(Message msg) {
-        final String logLine = String.format(
-                "%s/%d %d %d %s [%s]",
-                mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
-                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
-
-        final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
-        mLog.log(richerLogLine);
-        if (DBG) {
-            Log.d(mTag, richerLogLine);
-        }
-
-        mMsgStateLogger.reset();
-        return logLine;
-    }
-
-    @Override
-    protected boolean recordLogRec(Message msg) {
-        // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
-        // and we already log any LinkProperties change that results in an
-        // invocation of IpClient.Callback#onLinkPropertiesChange().
-        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
-        if (!shouldLog) {
-            mMsgStateLogger.reset();
-        }
-        return shouldLog;
-    }
-
-    private void logError(String fmt, Object... args) {
-        final String msg = "ERROR " + String.format(fmt, args);
-        Log.e(mTag, msg);
-        mLog.log(msg);
-    }
-
-    // This needs to be called with care to ensure that our LinkProperties
-    // are in sync with the actual LinkProperties of the interface. For example,
-    // we should only call this if we know for sure that there are no IP addresses
-    // assigned to the interface, etc.
-    private void resetLinkProperties() {
-        mLinkObserver.clearLinkProperties();
-        mConfiguration = null;
-        mDhcpResults = null;
-        mTcpBufferSizes = "";
-        mHttpProxy = null;
-
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-    }
-
-    private void recordMetric(final int type) {
-        // We may record error metrics prior to starting.
-        // Map this to IMMEDIATE_FAILURE_DURATION.
-        final long duration = (mStartTimeMillis > 0)
-                ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
-                : IMMEDIATE_FAILURE_DURATION;
-        mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
-    }
-
-    // For now: use WifiStateMachine's historical notion of provisioned.
-    @VisibleForTesting
-    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
-        // For historical reasons, we should connect even if all we have is
-        // an IPv4 address and nothing else.
-        if (lp.hasIpv4Address() || lp.isProvisioned()) {
-            return true;
-        }
-        if (config == null) {
-            return false;
-        }
-
-        // When an InitialConfiguration is specified, ignore any difference with previous
-        // properties and instead check if properties observed match the desired properties.
-        return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
-    }
-
-    // TODO: Investigate folding all this into the existing static function
-    // LinkProperties.compareProvisioning() or some other single function that
-    // takes two LinkProperties objects and returns a ProvisioningChange
-    // object that is a correct and complete assessment of what changed, taking
-    // account of the asymmetries described in the comments in this function.
-    // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
-    private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
-        int delta;
-        InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
-        final boolean wasProvisioned = isProvisioned(oldLp, config);
-        final boolean isProvisioned = isProvisioned(newLp, config);
-
-        if (!wasProvisioned && isProvisioned) {
-            delta = PROV_CHANGE_GAINED_PROVISIONING;
-        } else if (wasProvisioned && isProvisioned) {
-            delta = PROV_CHANGE_STILL_PROVISIONED;
-        } else if (!wasProvisioned && !isProvisioned) {
-            delta = PROV_CHANGE_STILL_NOT_PROVISIONED;
-        } else {
-            // (wasProvisioned && !isProvisioned)
-            //
-            // Note that this is true even if we lose a configuration element
-            // (e.g., a default gateway) that would not be required to advance
-            // into provisioned state. This is intended: if we have a default
-            // router and we lose it, that's a sure sign of a problem, but if
-            // we connect to a network with no IPv4 DNS servers, we consider
-            // that to be a network without DNS servers and connect anyway.
-            //
-            // See the comment below.
-            delta = PROV_CHANGE_LOST_PROVISIONING;
-        }
-
-        final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned();
-        final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address();
-        final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute();
-
-        // If bad wifi avoidance is disabled, then ignore IPv6 loss of
-        // provisioning. Otherwise, when a hotspot that loses Internet
-        // access sends out a 0-lifetime RA to its clients, the clients
-        // will disconnect and then reconnect, avoiding the bad hotspot,
-        // instead of getting stuck on the bad hotspot. http://b/31827713 .
-        //
-        // This is incorrect because if the hotspot then regains Internet
-        // access with a different prefix, TCP connections on the
-        // deprecated addresses will remain stuck.
-        //
-        // Note that we can still be disconnected by IpReachabilityMonitor
-        // if the IPv6 default gateway (but not the IPv6 DNS servers; see
-        // accompanying code in IpReachabilityMonitor) is unreachable.
-        final boolean ignoreIPv6ProvisioningLoss =
-                mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
-                && mCm.shouldAvoidBadWifi();
-
-        // Additionally:
-        //
-        // Partial configurations (e.g., only an IPv4 address with no DNS
-        // servers and no default route) are accepted as long as DHCPv4
-        // succeeds. On such a network, isProvisioned() will always return
-        // false, because the configuration is not complete, but we want to
-        // connect anyway. It might be a disconnected network such as a
-        // Chromecast or a wireless printer, for example.
-        //
-        // Because on such a network isProvisioned() will always return false,
-        // delta will never be LOST_PROVISIONING. So check for loss of
-        // provisioning here too.
-        if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
-            delta = PROV_CHANGE_LOST_PROVISIONING;
-        }
-
-        // Additionally:
-        //
-        // If the previous link properties had a global IPv6 address and an
-        // IPv6 default route then also consider the loss of that default route
-        // to be a loss of provisioning. See b/27962810.
-        if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
-            delta = PROV_CHANGE_LOST_PROVISIONING;
-        }
-
-        return delta;
-    }
-
-    private void dispatchCallback(int delta, LinkProperties newLp) {
-        switch (delta) {
-            case PROV_CHANGE_GAINED_PROVISIONING:
-                if (DBG) {
-                    Log.d(mTag, "onProvisioningSuccess()");
-                }
-                recordMetric(IpManagerEvent.PROVISIONING_OK);
-                mCallback.onProvisioningSuccess(newLp);
-                break;
-
-            case PROV_CHANGE_LOST_PROVISIONING:
-                if (DBG) {
-                    Log.d(mTag, "onProvisioningFailure()");
-                }
-                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
-                mCallback.onProvisioningFailure(newLp);
-                break;
-
-            default:
-                if (DBG) {
-                    Log.d(mTag, "onLinkPropertiesChange()");
-                }
-                mCallback.onLinkPropertiesChange(newLp);
-                break;
-        }
-    }
-
-    // Updates all IpClient-related state concerned with LinkProperties.
-    // Returns a ProvisioningChange for possibly notifying other interested
-    // parties that are not fronted by IpClient.
-    private int setLinkProperties(LinkProperties newLp) {
-        if (mApfFilter != null) {
-            mApfFilter.setLinkProperties(newLp);
-        }
-        if (mIpReachabilityMonitor != null) {
-            mIpReachabilityMonitor.updateLinkProperties(newLp);
-        }
-
-        int delta = compareProvisioning(mLinkProperties, newLp);
-        mLinkProperties = new LinkProperties(newLp);
-
-        if (delta == PROV_CHANGE_GAINED_PROVISIONING) {
-            // TODO: Add a proper ProvisionedState and cancel the alarm in
-            // its enter() method.
-            mProvisioningTimeoutAlarm.cancel();
-        }
-
-        return delta;
-    }
-
-    private LinkProperties assembleLinkProperties() {
-        // [1] Create a new LinkProperties object to populate.
-        LinkProperties newLp = new LinkProperties();
-        newLp.setInterfaceName(mInterfaceName);
-
-        // [2] Pull in data from netlink:
-        //         - IPv4 addresses
-        //         - IPv6 addresses
-        //         - IPv6 routes
-        //         - IPv6 DNS servers
-        //
-        // N.B.: this is fundamentally race-prone and should be fixed by
-        // changing IpClientLinkObserver from a hybrid edge/level model to an
-        // edge-only model, or by giving IpClient its own netlink socket(s)
-        // so as to track all required information directly.
-        LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
-        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
-        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
-            newLp.addRoute(route);
-        }
-        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
-
-        // [3] Add in data from DHCPv4, if available.
-        //
-        // mDhcpResults is never shared with any other owner so we don't have
-        // to worry about concurrent modification.
-        if (mDhcpResults != null) {
-            final List<RouteInfo> routes =
-                    mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
-            for (RouteInfo route : routes) {
-                newLp.addRoute(route);
-            }
-            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
-            newLp.setDomains(mDhcpResults.domains);
-
-            if (mDhcpResults.mtu != 0) {
-                newLp.setMtu(mDhcpResults.mtu);
-            }
-        }
-
-        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
-        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
-            newLp.setTcpBufferSizes(mTcpBufferSizes);
-        }
-        if (mHttpProxy != null) {
-            newLp.setHttpProxy(mHttpProxy);
-        }
-
-        // [5] Add data from InitialConfiguration
-        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
-            InitialConfiguration config = mConfiguration.mInitialConfig;
-            // Add InitialConfiguration routes and dns server addresses once all addresses
-            // specified in the InitialConfiguration have been observed with Netlink.
-            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
-                for (IpPrefix prefix : config.directlyConnectedRoutes) {
-                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST));
-                }
-            }
-            addAllReachableDnsServers(newLp, config.dnsServers);
-        }
-        final LinkProperties oldLp = mLinkProperties;
-        if (DBG) {
-            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
-                    netlinkLinkProperties, newLp, oldLp));
-        }
-
-        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
-        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
-        return newLp;
-    }
-
-    private static void addAllReachableDnsServers(
-            LinkProperties lp, Iterable<InetAddress> dnses) {
-        // TODO: Investigate deleting this reachability check.  We should be
-        // able to pass everything down to netd and let netd do evaluation
-        // and RFC6724-style sorting.
-        for (InetAddress dns : dnses) {
-            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
-                lp.addDnsServer(dns);
-            }
-        }
-    }
-
-    // Returns false if we have lost provisioning, true otherwise.
-    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
-        final LinkProperties newLp = assembleLinkProperties();
-        if (Objects.equals(newLp, mLinkProperties)) {
-            return true;
-        }
-        final int delta = setLinkProperties(newLp);
-        // Most of the attributes stored in the memory store are deduced from
-        // the link properties, therefore when the properties update the memory
-        // store record should be updated too.
-        maybeSaveNetworkToIpMemoryStore();
-        if (sendCallbacks) {
-            dispatchCallback(delta, newLp);
-        }
-        return (delta != PROV_CHANGE_LOST_PROVISIONING);
-    }
-
-    private void handleIPv4Success(DhcpResults dhcpResults) {
-        mDhcpResults = new DhcpResults(dhcpResults);
-        final LinkProperties newLp = assembleLinkProperties();
-        final int delta = setLinkProperties(newLp);
-
-        if (DBG) {
-            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
-        }
-        mCallback.onNewDhcpResults(dhcpResults);
-        maybeSaveNetworkToIpMemoryStore();
-        dispatchCallback(delta, newLp);
-    }
-
-    private void handleIPv4Failure() {
-        // TODO: Investigate deleting this clearIPv4Address() call.
-        //
-        // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
-        // that could trigger a call to this function. If we missed handling
-        // that message in StartedState for some reason we would still clear
-        // any addresses upon entry to StoppedState.
-        mInterfaceCtrl.clearIPv4Address();
-        mDhcpResults = null;
-        if (DBG) {
-            Log.d(mTag, "onNewDhcpResults(null)");
-        }
-        mCallback.onNewDhcpResults(null);
-
-        handleProvisioningFailure();
-    }
-
-    private void handleProvisioningFailure() {
-        final LinkProperties newLp = assembleLinkProperties();
-        int delta = setLinkProperties(newLp);
-        // If we've gotten here and we're still not provisioned treat that as
-        // a total loss of provisioning.
-        //
-        // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
-        // there was no usable IPv6 obtained before a non-zero provisioning
-        // timeout expired.
-        //
-        // Regardless: GAME OVER.
-        if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) {
-            delta = PROV_CHANGE_LOST_PROVISIONING;
-        }
-
-        dispatchCallback(delta, newLp);
-        if (delta == PROV_CHANGE_LOST_PROVISIONING) {
-            transitionTo(mStoppingState);
-        }
-    }
-
-    private void doImmediateProvisioningFailure(int failureType) {
-        logError("onProvisioningFailure(): %s", failureType);
-        recordMetric(failureType);
-        mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
-    }
-
-    private boolean startIPv4() {
-        // If we have a StaticIpConfiguration attempt to apply it and
-        // handle the result accordingly.
-        if (mConfiguration.mStaticIpConfig != null) {
-            if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
-                handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
-            } else {
-                return false;
-            }
-        } else {
-            // Start DHCPv4.
-            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
-            mDhcpClient.registerForPreDhcpNotification();
-            mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
-        }
-
-        return true;
-    }
-
-    private boolean startIPv6() {
-        return mInterfaceCtrl.setIPv6PrivacyExtensions(true)
-                && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode)
-                && mInterfaceCtrl.enableIPv6();
-    }
-
-    private boolean applyInitialConfig(InitialConfiguration config) {
-        // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
-        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) {
-            if (!mInterfaceCtrl.addAddress(addr)) return false;
-        }
-
-        return true;
-    }
-
-    private boolean startIpReachabilityMonitor() {
-        try {
-            // TODO: Fetch these parameters from settings, and install a
-            // settings observer to watch for update and re-program these
-            // parameters (Q: is this level of dynamic updatability really
-            // necessary or does reading from settings at startup suffice?).
-            final int numSolicits = 5;
-            final int interSolicitIntervalMs = 750;
-            setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs);
-        } catch (Exception e) {
-            mLog.e("Failed to adjust neighbor parameters", e);
-            // Carry on using the system defaults (currently: 3, 1000);
-        }
-
-        try {
-            mIpReachabilityMonitor = new IpReachabilityMonitor(
-                    mContext,
-                    mInterfaceParams,
-                    getHandler(),
-                    mLog,
-                    new IpReachabilityMonitor.Callback() {
-                        @Override
-                        public void notifyLost(InetAddress ip, String logMsg) {
-                            mCallback.onReachabilityLost(logMsg);
-                        }
-                    },
-                    mConfiguration.mUsingMultinetworkPolicyTracker);
-        } catch (IllegalArgumentException iae) {
-            // Failed to start IpReachabilityMonitor. Log it and call
-            // onProvisioningFailure() immediately.
-            //
-            // See http://b/31038971.
-            logError("IpReachabilityMonitor failure: %s", iae);
-            mIpReachabilityMonitor = null;
-        }
-
-        return (mIpReachabilityMonitor != null);
-    }
-
-    private void stopAllIP() {
-        // We don't need to worry about routes, just addresses, because:
-        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
-        //     - we don't get IPv4 routes from netlink
-        // so we neither react to nor need to wait for changes in either.
-
-        mInterfaceCtrl.disableIPv6();
-        mInterfaceCtrl.clearAllAddresses();
-    }
-
-    private void maybeSaveNetworkToIpMemoryStore() {
-        // TODO : implement this
-    }
-
-    class StoppedState extends State {
-        @Override
-        public void enter() {
-            stopAllIP();
-
-            resetLinkProperties();
-            if (mStartTimeMillis > 0) {
-                // Completed a life-cycle; send a final empty LinkProperties
-                // (cleared in resetLinkProperties() above) and record an event.
-                mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
-                recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
-                mStartTimeMillis = 0;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_TERMINATE_AFTER_STOP:
-                    stopStateMachineUpdaters();
-                    quit();
-                    break;
-
-                case CMD_STOP:
-                    break;
-
-                case CMD_START:
-                    mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
-                    transitionTo(mStartedState);
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_TCP_BUFFER_SIZES:
-                    mTcpBufferSizes = (String) msg.obj;
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_HTTP_PROXY:
-                    mHttpProxy = (ProxyInfo) msg.obj;
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_L2KEY_GROUPHINT: {
-                    final Pair<String, String> args = (Pair<String, String>) msg.obj;
-                    mL2Key = args.first;
-                    mGroupHint = args.second;
-                    break;
-                }
-
-                case CMD_SET_MULTICAST_FILTER:
-                    mMulticastFiltering = (boolean) msg.obj;
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    // Everything is already stopped.
-                    logError("Unexpected CMD_ON_QUIT (already stopped).");
-                    break;
-
-                default:
-                    return NOT_HANDLED;
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    class StoppingState extends State {
-        @Override
-        public void enter() {
-            if (mDhcpClient == null) {
-                // There's no DHCPv4 for which to wait; proceed to stopped.
-                deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_JUMP_STOPPING_TO_STOPPED:
-                    transitionTo(mStoppedState);
-                    break;
-
-                case CMD_STOP:
-                    break;
-
-                case DhcpClient.CMD_CLEAR_LINKADDRESS:
-                    mInterfaceCtrl.clearIPv4Address();
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    mDhcpClient = null;
-                    transitionTo(mStoppedState);
-                    break;
-
-                default:
-                    deferMessage(msg);
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    class StartedState extends State {
-        @Override
-        public void enter() {
-            mStartTimeMillis = SystemClock.elapsedRealtime();
-
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime()
-                        + mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
-            if (readyToProceed()) {
-                deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
-            } else {
-                // Clear all IPv4 and IPv6 before proceeding to RunningState.
-                // Clean up any leftover state from an abnormal exit from
-                // tethering or during an IpClient restart.
-                stopAllIP();
-            }
-        }
-
-        @Override
-        public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_JUMP_STARTED_TO_RUNNING:
-                    transitionTo(mRunningState);
-                    break;
-
-                case CMD_STOP:
-                    transitionTo(mStoppingState);
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    if (readyToProceed()) {
-                        transitionTo(mRunningState);
-                    }
-                    break;
-
-                case CMD_UPDATE_L2KEY_GROUPHINT: {
-                    final Pair<String, String> args = (Pair<String, String>) msg.obj;
-                    mL2Key = args.first;
-                    mGroupHint = args.second;
-                    // TODO : attributes should be saved to the memory store with
-                    // these new values if they differ from the previous ones.
-                    // If the state machine is in pure StartedState, then the values to input
-                    // are not known yet and should be updated when the LinkProperties are updated.
-                    // If the state machine is in RunningState (which is a child of StartedState)
-                    // then the next NUD check should be used to store the new values to avoid
-                    // inputting current values for what may be a different L3 network.
-                    break;
-                }
-
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
-                default:
-                    // It's safe to process messages out of order because the
-                    // only message that can both
-                    //     a) be received at this time and
-                    //     b) affect provisioning state
-                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
-                    deferMessage(msg);
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-
-        private boolean readyToProceed() {
-            return (!mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address());
-        }
-    }
-
-    class RunningState extends State {
-        private ConnectivityPacketTracker mPacketTracker;
-        private boolean mDhcpActionInFlight;
-
-        @Override
-        public void enter() {
-            ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
-            apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
-            apfConfig.multicastFilter = mMulticastFiltering;
-            // Get the Configuration for ApfFilter from Context
-            apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
-            apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
-            mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
-            // TODO: investigate the effects of any multicast filtering racing/interfering with the
-            // rest of this IP configuration startup.
-            if (mApfFilter == null) {
-                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
-            }
-
-            mPacketTracker = createPacketTracker();
-            if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
-
-            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
-                enqueueJumpToStoppingState();
-                return;
-            }
-
-            if (mConfiguration.mEnableIPv4 && !startIPv4()) {
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
-                enqueueJumpToStoppingState();
-                return;
-            }
-
-            final InitialConfiguration config = mConfiguration.mInitialConfig;
-            if ((config != null) && !applyInitialConfig(config)) {
-                // TODO introduce a new IpManagerEvent constant to distinguish this error case.
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-                enqueueJumpToStoppingState();
-                return;
-            }
-
-            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
-                doImmediateProvisioningFailure(
-                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
-                enqueueJumpToStoppingState();
-                return;
-            }
-        }
-
-        @Override
-        public void exit() {
-            stopDhcpAction();
-
-            if (mIpReachabilityMonitor != null) {
-                mIpReachabilityMonitor.stop();
-                mIpReachabilityMonitor = null;
-            }
-
-            if (mDhcpClient != null) {
-                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
-                mDhcpClient.doQuit();
-            }
-
-            if (mPacketTracker != null) {
-                mPacketTracker.stop();
-                mPacketTracker = null;
-            }
-
-            if (mApfFilter != null) {
-                mApfFilter.shutdown();
-                mApfFilter = null;
-            }
-
-            resetLinkProperties();
-        }
-
-        private void enqueueJumpToStoppingState() {
-            deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
-        }
-
-        private ConnectivityPacketTracker createPacketTracker() {
-            try {
-                return new ConnectivityPacketTracker(
-                        getHandler(), mInterfaceParams, mConnectivityPacketLog);
-            } catch (IllegalArgumentException e) {
-                return null;
-            }
-        }
-
-        private void ensureDhcpAction() {
-            if (!mDhcpActionInFlight) {
-                mCallback.onPreDhcpAction();
-                mDhcpActionInFlight = true;
-                final long alarmTime = SystemClock.elapsedRealtime()
-                        + mConfiguration.mRequestedPreDhcpActionMs;
-                mDhcpActionTimeoutAlarm.schedule(alarmTime);
-            }
-        }
-
-        private void stopDhcpAction() {
-            mDhcpActionTimeoutAlarm.cancel();
-            if (mDhcpActionInFlight) {
-                mCallback.onPostDhcpAction();
-                mDhcpActionInFlight = false;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_JUMP_RUNNING_TO_STOPPING:
-                case CMD_STOP:
-                    transitionTo(mStoppingState);
-                    break;
-
-                case CMD_START:
-                    logError("ALERT: START received in StartedState. Please fix caller.");
-                    break;
-
-                case CMD_CONFIRM:
-                    // TODO: Possibly introduce a second type of confirmation
-                    // that both probes (a) on-link neighbors and (b) does
-                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
-                    // roams.
-                    if (mIpReachabilityMonitor != null) {
-                        mIpReachabilityMonitor.probeAll();
-                    }
-                    break;
-
-                case EVENT_PRE_DHCP_ACTION_COMPLETE:
-                    // It's possible to reach here if, for example, someone
-                    // calls completedPreDhcpAction() after provisioning with
-                    // a static IP configuration.
-                    if (mDhcpClient != null) {
-                        mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
-                    }
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
-                        transitionTo(mStoppingState);
-                    }
-                    break;
-
-                case CMD_UPDATE_TCP_BUFFER_SIZES:
-                    mTcpBufferSizes = (String) msg.obj;
-                    // This cannot possibly change provisioning state.
-                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_HTTP_PROXY:
-                    mHttpProxy = (ProxyInfo) msg.obj;
-                    // This cannot possibly change provisioning state.
-                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
-                    break;
-
-                case CMD_SET_MULTICAST_FILTER: {
-                    mMulticastFiltering = (boolean) msg.obj;
-                    if (mApfFilter != null) {
-                        mApfFilter.setMulticastFilter(mMulticastFiltering);
-                    } else {
-                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
-                    }
-                    break;
-                }
-
-                case EVENT_READ_PACKET_FILTER_COMPLETE: {
-                    if (mApfFilter != null) {
-                        mApfFilter.setDataSnapshot((byte[]) msg.obj);
-                    }
-                    mApfDataSnapshotComplete.open();
-                    break;
-                }
-
-                case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
-                    final int slot = msg.arg1;
-
-                    if (mApfFilter != null) {
-                        if (msg.obj instanceof NattKeepalivePacketDataParcelable) {
-                            mApfFilter.addNattKeepalivePacketFilter(slot,
-                                    (NattKeepalivePacketDataParcelable) msg.obj);
-                        } else if (msg.obj instanceof TcpKeepalivePacketDataParcelable) {
-                            mApfFilter.addTcpKeepalivePacketFilter(slot,
-                                    (TcpKeepalivePacketDataParcelable) msg.obj);
-                        }
-                    }
-                    break;
-                }
-
-                case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
-                    final int slot = msg.arg1;
-                    if (mApfFilter != null) {
-                        mApfFilter.removeKeepalivePacketFilter(slot);
-                    }
-                    break;
-                }
-
-                case EVENT_DHCPACTION_TIMEOUT:
-                    stopDhcpAction();
-                    break;
-
-                case DhcpClient.CMD_PRE_DHCP_ACTION:
-                    if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
-                        ensureDhcpAction();
-                    } else {
-                        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
-                    }
-                    break;
-
-                case DhcpClient.CMD_CLEAR_LINKADDRESS:
-                    mInterfaceCtrl.clearIPv4Address();
-                    break;
-
-                case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
-                    final LinkAddress ipAddress = (LinkAddress) msg.obj;
-                    if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
-                        mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
-                    } else {
-                        logError("Failed to set IPv4 address.");
-                        dispatchCallback(PROV_CHANGE_LOST_PROVISIONING,
-                                new LinkProperties(mLinkProperties));
-                        transitionTo(mStoppingState);
-                    }
-                    break;
-                }
-
-                // This message is only received when:
-                //
-                //     a) initial address acquisition succeeds,
-                //     b) renew succeeds or is NAK'd,
-                //     c) rebind succeeds or is NAK'd, or
-                //     c) the lease expires,
-                //
-                // but never when initial address acquisition fails. The latter
-                // condition is now governed by the provisioning timeout.
-                case DhcpClient.CMD_POST_DHCP_ACTION:
-                    stopDhcpAction();
-
-                    switch (msg.arg1) {
-                        case DhcpClient.DHCP_SUCCESS:
-                            handleIPv4Success((DhcpResults) msg.obj);
-                            break;
-                        case DhcpClient.DHCP_FAILURE:
-                            handleIPv4Failure();
-                            break;
-                        default:
-                            logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
-                    }
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    // DHCPv4 quit early for some reason.
-                    logError("Unexpected CMD_ON_QUIT.");
-                    mDhcpClient = null;
-                    break;
-
-                default:
-                    return NOT_HANDLED;
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    private static class MessageHandlingLogger {
-        public String processedInState;
-        public String receivedInState;
-
-        public void reset() {
-            processedInState = null;
-            receivedInState = null;
-        }
-
-        public void handled(State processedIn, IState receivedIn) {
-            processedInState = processedIn.getClass().getSimpleName();
-            receivedInState = receivedIn.getName();
-        }
-
-        public String toString() {
-            return String.format("rcvd_in=%s, proc_in=%s",
-                                 receivedInState, processedInState);
-        }
-    }
-
-    private static void setNeighborParameters(
-            INetd netd, String ifName, int numSolicits, int interSolicitIntervalMs)
-            throws RemoteException, IllegalArgumentException {
-        Preconditions.checkNotNull(netd);
-        Preconditions.checkArgument(!TextUtils.isEmpty(ifName));
-        Preconditions.checkArgument(numSolicits > 0);
-        Preconditions.checkArgument(interSolicitIntervalMs > 0);
-
-        for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) {
-            netd.setProcSysNet(family, INetd.NEIGH, ifName, "retrans_time_ms",
-                    Integer.toString(interSolicitIntervalMs));
-            netd.setProcSysNet(family, INetd.NEIGH, ifName, "ucast_solicit",
-                    Integer.toString(numSolicits));
-        }
-    }
-
-    // TODO: extract out into CollectionUtils.
-    static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
-        for (T t : coll) {
-            if (fn.test(t)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
-        return !any(coll, not(fn));
-    }
-
-    static <T> Predicate<T> not(Predicate<T> fn) {
-        return (t) -> !fn.test(t);
-    }
-
-    static <T> String join(String delimiter, Collection<T> coll) {
-        return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
-    }
-
-    static <T> T find(Iterable<T> coll, Predicate<T> fn) {
-        for (T t: coll) {
-            if (fn.test(t)) {
-                return t;
-            }
-        }
-        return null;
-    }
-
-    static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
-        return coll.stream().filter(fn).collect(Collectors.toList());
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java
deleted file mode 100644
index 8ad99aa0..0000000
--- a/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2014 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.ip;
-
-import android.net.InetAddresses;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.RouteInfo;
-import android.util.Log;
-
-import com.android.server.NetworkObserver;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Keeps track of link configuration received from Netd.
- *
- * An instance of this class is constructed by passing in an interface name and a callback. The
- * owner is then responsible for registering the tracker with NetworkObserverRegistry. When the
- * class receives update notifications, it applies the update to its local LinkProperties, and if
- * something has changed, notifies its owner of the update via the callback.
- *
- * The owner can then call {@code getLinkProperties()} in order to find out
- * what changed. If in the meantime the LinkProperties stored here have changed,
- * this class will return the current LinkProperties. Because each change
- * triggers an update callback after the change is made, the owner may get more
- * callbacks than strictly necessary (some of which may be no-ops), but will not
- * be out of sync once all callbacks have been processed.
- *
- * Threading model:
- *
- * - The owner of this class is expected to create it, register it, and call
- *   getLinkProperties or clearLinkProperties on its thread.
- * - Most of the methods in the class are implementing NetworkObserver and are called
- *   on the handler used to register the observer.
- * - All accesses to mLinkProperties must be synchronized(this). All the other
- *   member variables are immutable once the object is constructed.
- *
- * @hide
- */
-public class IpClientLinkObserver implements NetworkObserver {
-    private final String mTag;
-
-    /**
-     * Callback used by {@link IpClientLinkObserver} to send update notifications.
-     */
-    public interface Callback {
-        /**
-         * Called when some properties of the link were updated.
-         */
-        void update();
-    }
-
-    private final String mInterfaceName;
-    private final Callback mCallback;
-    private final LinkProperties mLinkProperties;
-    private DnsServerRepository mDnsServerRepository;
-
-    private static final boolean DBG = false;
-
-    public IpClientLinkObserver(String iface, Callback callback) {
-        mTag = "NetlinkTracker/" + iface;
-        mInterfaceName = iface;
-        mCallback = callback;
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-        mDnsServerRepository = new DnsServerRepository();
-    }
-
-    private void maybeLog(String operation, String iface, LinkAddress address) {
-        if (DBG) {
-            Log.d(mTag, operation + ": " + address + " on " + iface
-                    + " flags " + address.getFlags() + " scope " + address.getScope());
-        }
-    }
-
-    private void maybeLog(String operation, Object o) {
-        if (DBG) {
-            Log.d(mTag, operation + ": " + o.toString());
-        }
-    }
-
-    @Override
-    public void onInterfaceRemoved(String iface) {
-        maybeLog("interfaceRemoved", iface);
-        if (mInterfaceName.equals(iface)) {
-            // Our interface was removed. Clear our LinkProperties and tell our owner that they are
-            // now empty. Note that from the moment that the interface is removed, any further
-            // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
-            // code that parses them will not be able to resolve the ifindex to an interface name.
-            clearLinkProperties();
-            mCallback.update();
-        }
-    }
-
-    @Override
-    public void onInterfaceAddressUpdated(LinkAddress address, String iface) {
-        if (mInterfaceName.equals(iface)) {
-            maybeLog("addressUpdated", iface, address);
-            boolean changed;
-            synchronized (this) {
-                changed = mLinkProperties.addLinkAddress(address);
-            }
-            if (changed) {
-                mCallback.update();
-            }
-        }
-    }
-
-    @Override
-    public void onInterfaceAddressRemoved(LinkAddress address, String iface) {
-        if (mInterfaceName.equals(iface)) {
-            maybeLog("addressRemoved", iface, address);
-            boolean changed;
-            synchronized (this) {
-                changed = mLinkProperties.removeLinkAddress(address);
-            }
-            if (changed) {
-                mCallback.update();
-            }
-        }
-    }
-
-    @Override
-    public void onRouteUpdated(RouteInfo route) {
-        if (mInterfaceName.equals(route.getInterface())) {
-            maybeLog("routeUpdated", route);
-            boolean changed;
-            synchronized (this) {
-                changed = mLinkProperties.addRoute(route);
-            }
-            if (changed) {
-                mCallback.update();
-            }
-        }
-    }
-
-    @Override
-    public void onRouteRemoved(RouteInfo route) {
-        if (mInterfaceName.equals(route.getInterface())) {
-            maybeLog("routeRemoved", route);
-            boolean changed;
-            synchronized (this) {
-                changed = mLinkProperties.removeRoute(route);
-            }
-            if (changed) {
-                mCallback.update();
-            }
-        }
-    }
-
-    @Override
-    public void onInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
-        if (mInterfaceName.equals(iface)) {
-            maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses));
-            boolean changed = mDnsServerRepository.addServers(lifetime, addresses);
-            if (changed) {
-                synchronized (this) {
-                    mDnsServerRepository.setDnsServersOn(mLinkProperties);
-                }
-                mCallback.update();
-            }
-        }
-    }
-
-    /**
-     * Returns a copy of this object's LinkProperties.
-     */
-    public synchronized LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
-    }
-
-    /**
-     * Reset this object's LinkProperties.
-     */
-    public synchronized void clearLinkProperties() {
-        // Clear the repository before clearing mLinkProperties. That way, if a clear() happens
-        // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
-        // mLinkProperties, as desired.
-        mDnsServerRepository = new DnsServerRepository();
-        mLinkProperties.clear();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-    }
-
-    /**
-     * Tracks DNS server updates received from Netlink.
-     *
-     * The network may announce an arbitrary number of DNS servers in Router Advertisements at any
-     * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be
-     * used any more. In this way, the network can gracefully migrate clients from one set of DNS
-     * servers to another. Announcements can both raise and lower the lifetime, and an announcement
-     * can expire servers by announcing them with a lifetime of zero.
-     *
-     * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of
-     * DNS servers at any given time. These are referred to as the current servers. In case all the
-     * current servers expire, the class also keeps track of a larger (but limited) number of
-     * servers that are promoted to current servers when the current ones expire. In order to
-     * minimize updates to the rest of the system (and potentially expensive cache flushes) this
-     * class attempts to keep the list of current servers constant where possible. More
-     * specifically, the list of current servers is only updated if a new server is learned and
-     * there are not yet {@code NUM_CURRENT_SERVERS} current servers, or if one or more of the
-     * current servers expires or is pushed out of the set. Therefore, the current servers will not
-     * necessarily be the ones with the highest lifetime, but the ones learned first.
-     *
-     * This is by design: if instead the class always preferred the servers with the highest
-     * lifetime, a (misconfigured?) network where two or more routers announce more than
-     * {@code NUM_CURRENT_SERVERS} unique servers would cause persistent oscillations.
-     *
-     * TODO: Currently servers are only expired when a new DNS update is received.
-     * Update them using timers, or possibly on every notification received by NetlinkTracker.
-     *
-     * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink
-     * notifications are sent by multiple threads. If future threads use alarms to expire, those
-     * alarms must also be synchronized(this).
-     *
-     */
-    private static class DnsServerRepository {
-
-        /** How many DNS servers we will use. 3 is suggested by RFC 6106. */
-        static final int NUM_CURRENT_SERVERS = 3;
-
-        /** How many DNS servers we'll keep track of, in total. */
-        static final int NUM_SERVERS = 12;
-
-        /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */
-        private Set<InetAddress> mCurrentServers;
-
-        public static final String TAG = "DnsServerRepository";
-
-        /**
-         * Stores all the DNS servers we know about, for use when the current servers expire.
-         * Always sorted in order of decreasing expiry. The elements in this list are also the
-         * values of mIndex, and may be elements in mCurrentServers.
-         */
-        private ArrayList<DnsServerEntry> mAllServers;
-
-        /**
-         * Indexes the servers so we can update their lifetimes more quickly in the common case
-         * where servers are not being added, but only being refreshed.
-         */
-        private HashMap<InetAddress, DnsServerEntry> mIndex;
-
-        DnsServerRepository() {
-            mCurrentServers = new HashSet<>();
-            mAllServers = new ArrayList<>(NUM_SERVERS);
-            mIndex = new HashMap<>(NUM_SERVERS);
-        }
-
-        /** Sets the DNS servers of the provided LinkProperties object to the current servers. */
-        public synchronized void setDnsServersOn(LinkProperties lp) {
-            lp.setDnsServers(mCurrentServers);
-        }
-
-        /**
-         * Notifies the class of new DNS server information.
-         * @param lifetime the time in seconds that the DNS servers are valid.
-         * @param addresses the string representations of the IP addresses of DNS servers to use.
-         */
-        public synchronized boolean addServers(long lifetime, String[] addresses) {
-            // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
-            // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
-            // (136 years) is close enough.
-            long now = System.currentTimeMillis();
-            long expiry = now + 1000 * lifetime;
-
-            // Go through the list of servers. For each one, update the entry if one exists, and
-            // create one if it doesn't.
-            for (String addressString : addresses) {
-                InetAddress address;
-                try {
-                    address = InetAddresses.parseNumericAddress(addressString);
-                } catch (IllegalArgumentException ex) {
-                    continue;
-                }
-
-                if (!updateExistingEntry(address, expiry)) {
-                    // There was no entry for this server. Create one, unless it's already expired
-                    // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned).
-                    if (expiry > now) {
-                        DnsServerEntry entry = new DnsServerEntry(address, expiry);
-                        mAllServers.add(entry);
-                        mIndex.put(address, entry);
-                    }
-                }
-            }
-
-            // Sort the servers by expiry.
-            Collections.sort(mAllServers);
-
-            // Prune excess entries and update the current server list.
-            return updateCurrentServers();
-        }
-
-        private synchronized boolean updateExistingEntry(InetAddress address, long expiry) {
-            DnsServerEntry existing = mIndex.get(address);
-            if (existing != null) {
-                existing.expiry = expiry;
-                return true;
-            }
-            return false;
-        }
-
-        private synchronized boolean updateCurrentServers() {
-            long now = System.currentTimeMillis();
-            boolean changed = false;
-
-            // Prune excess or expired entries.
-            for (int i = mAllServers.size() - 1; i >= 0; i--) {
-                if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) {
-                    DnsServerEntry removed = mAllServers.remove(i);
-                    mIndex.remove(removed.address);
-                    changed |= mCurrentServers.remove(removed.address);
-                } else {
-                    break;
-                }
-            }
-
-            // Add servers to the current set, in order of decreasing lifetime, until it has enough.
-            // Prefer existing servers over new servers in order to minimize updates to the rest of
-            // the system and avoid persistent oscillations.
-            for (DnsServerEntry entry : mAllServers) {
-                if (mCurrentServers.size() < NUM_CURRENT_SERVERS) {
-                    changed |= mCurrentServers.add(entry.address);
-                } else {
-                    break;
-                }
-            }
-            return changed;
-        }
-    }
-
-    /**
-     * Represents a DNS server entry with an expiry time.
-     *
-     * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first.
-     * The ordering of entries with the same lifetime is unspecified, because given two servers with
-     * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much
-     * faster than comparing the IP address as well.
-     *
-     * Note: this class has a natural ordering that is inconsistent with equals.
-     */
-    private static class DnsServerEntry implements Comparable<DnsServerEntry> {
-        /** The IP address of the DNS server. */
-        public final InetAddress address;
-        /** The time until which the DNS server may be used. A Java millisecond time as might be
-         * returned by currentTimeMillis(). */
-        public long expiry;
-
-        DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException {
-            this.address = address;
-            this.expiry = expiry;
-        }
-
-        public int compareTo(DnsServerEntry other) {
-            return Long.compare(other.expiry, this.expiry);
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
deleted file mode 100644
index 6ae9a2b..0000000
--- a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2017 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.ip;
-
-import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
-import static android.net.netlink.NetlinkConstants.hexify;
-import static android.net.netlink.NetlinkConstants.stringForNlMsgType;
-import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
-import static android.system.OsConstants.AF_NETLINK;
-import static android.system.OsConstants.NETLINK_ROUTE;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_NONBLOCK;
-
-import android.net.MacAddress;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdMsg;
-import android.net.util.NetworkStackUtils;
-import android.net.util.PacketReader;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.StringJoiner;
-
-
-/**
- * IpNeighborMonitor.
- *
- * Monitors the kernel rtnetlink neighbor notifications and presents to callers
- * NeighborEvents describing each event. Callers can provide a consumer instance
- * to both filter (e.g. by interface index and IP address) and handle the
- * generated NeighborEvents.
- *
- * @hide
- */
-public class IpNeighborMonitor extends PacketReader {
-    private static final String TAG = IpNeighborMonitor.class.getSimpleName();
-    private static final boolean DBG = false;
-    private static final boolean VDBG = false;
-
-    /**
-     * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
-     * for the given IP address on the specified interface index.
-     *
-     * @return 0 if the request was successfully passed to the kernel; otherwise return
-     *         a non-zero error code.
-     */
-    public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) {
-        final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
-        if (DBG) { Log.d(TAG, msgSnippet); }
-
-        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
-                1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-
-        try {
-            NetlinkSocket.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
-        } catch (ErrnoException e) {
-            Log.e(TAG, "Error " + msgSnippet + ": " + e);
-            return -e.errno;
-        }
-
-        return 0;
-    }
-
-    public static class NeighborEvent {
-        final long elapsedMs;
-        final short msgType;
-        final int ifindex;
-        final InetAddress ip;
-        final short nudState;
-        final MacAddress macAddr;
-
-        public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
-                short nudState, MacAddress macAddr) {
-            this.elapsedMs = elapsedMs;
-            this.msgType = msgType;
-            this.ifindex = ifindex;
-            this.ip = ip;
-            this.nudState = nudState;
-            this.macAddr = macAddr;
-        }
-
-        boolean isConnected() {
-            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState);
-        }
-
-        boolean isValid() {
-            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState);
-        }
-
-        @Override
-        public String toString() {
-            final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
-            return j.add("@" + elapsedMs)
-                    .add(stringForNlMsgType(msgType))
-                    .add("if=" + ifindex)
-                    .add(ip.getHostAddress())
-                    .add(StructNdMsg.stringForNudState(nudState))
-                    .add("[" + macAddr + "]")
-                    .toString();
-        }
-    }
-
-    public interface NeighborEventConsumer {
-        // Every neighbor event received on the netlink socket is passed in
-        // here. Subclasses should filter for events of interest.
-        public void accept(NeighborEvent event);
-    }
-
-    private final SharedLog mLog;
-    private final NeighborEventConsumer mConsumer;
-
-    public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) {
-        super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
-        mLog = log.forSubComponent(TAG);
-        mConsumer = (cb != null) ? cb : (event) -> { /* discard */ };
-    }
-
-    @Override
-    protected FileDescriptor createFd() {
-        FileDescriptor fd = null;
-
-        try {
-            fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, NETLINK_ROUTE);
-            Os.bind(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH));
-            NetlinkSocket.connectToKernel(fd);
-
-            if (VDBG) {
-                final SocketAddress nlAddr = Os.getsockname(fd);
-                Log.d(TAG, "bound to sockaddr_nl{" + nlAddr.toString() + "}");
-            }
-        } catch (ErrnoException|SocketException e) {
-            logError("Failed to create rtnetlink socket", e);
-            NetworkStackUtils.closeSocketQuietly(fd);
-            return null;
-        }
-
-        return fd;
-    }
-
-    @Override
-    protected void handlePacket(byte[] recvbuf, int length) {
-        final long whenMs = SystemClock.elapsedRealtime();
-
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        parseNetlinkMessageBuffer(byteBuffer, whenMs);
-    }
-
-    private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
-        while (byteBuffer.remaining() > 0) {
-            final int position = byteBuffer.position();
-            final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
-            if (nlMsg == null || nlMsg.getHeader() == null) {
-                byteBuffer.position(position);
-                mLog.e("unparsable netlink msg: " + hexify(byteBuffer));
-                break;
-            }
-
-            final int srcPortId = nlMsg.getHeader().nlmsg_pid;
-            if (srcPortId !=  0) {
-                mLog.e("non-kernel source portId: " + Integer.toUnsignedLong(srcPortId));
-                break;
-            }
-
-            if (nlMsg instanceof NetlinkErrorMessage) {
-                mLog.e("netlink error: " + nlMsg);
-                continue;
-            } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
-                mLog.i("non-rtnetlink neighbor msg: " + nlMsg);
-                continue;
-            }
-
-            evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
-        }
-    }
-
-    private void evaluateRtNetlinkNeighborMessage(
-            RtNetlinkNeighborMessage neighMsg, long whenMs) {
-        final short msgType = neighMsg.getHeader().nlmsg_type;
-        final StructNdMsg ndMsg = neighMsg.getNdHeader();
-        if (ndMsg == null) {
-            mLog.e("RtNetlinkNeighborMessage without ND message header!");
-            return;
-        }
-
-        final int ifindex = ndMsg.ndm_ifindex;
-        final InetAddress destination = neighMsg.getDestination();
-        final short nudState =
-                (msgType == RTM_DELNEIGH)
-                ? StructNdMsg.NUD_NONE
-                : ndMsg.ndm_state;
-
-        final NeighborEvent event = new NeighborEvent(
-                whenMs, msgType, ifindex, destination, nudState,
-                getMacAddress(neighMsg.getLinkLayerAddress()));
-
-        if (VDBG) {
-            Log.d(TAG, neighMsg.toString());
-        }
-        if (DBG) {
-            Log.d(TAG, event.toString());
-        }
-
-        mConsumer.accept(event);
-    }
-
-    private static MacAddress getMacAddress(byte[] linkLayerAddress) {
-        if (linkLayerAddress != null) {
-            try {
-                return MacAddress.fromBytes(linkLayerAddress);
-            } catch (IllegalArgumentException e) {
-                Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress));
-            }
-        }
-
-        return null;
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
deleted file mode 100644
index c19a24e..0000000
--- a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2015 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.ip;
-
-import static android.net.metrics.IpReachabilityEvent.NUD_FAILED;
-import static android.net.metrics.IpReachabilityEvent.NUD_FAILED_ORGANIC;
-import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST;
-import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST_ORGANIC;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.RouteInfo;
-import android.net.ip.IpNeighborMonitor.NeighborEvent;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpReachabilityEvent;
-import android.net.netlink.StructNdMsg;
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * IpReachabilityMonitor.
- *
- * Monitors on-link IP reachability and notifies callers whenever any on-link
- * addresses of interest appear to have become unresponsive.
- *
- * This code does not concern itself with "why" a neighbour might have become
- * unreachable. Instead, it primarily reacts to the kernel's notion of IP
- * reachability for each of the neighbours we know to be critically important
- * to normal network connectivity. As such, it is often "just the messenger":
- * the neighbours about which it warns are already deemed by the kernel to have
- * become unreachable.
- *
- *
- * How it works:
- *
- *   1. The "on-link neighbours of interest" found in a given LinkProperties
- *      instance are added to a "watch list" via #updateLinkProperties().
- *      This usually means all default gateways and any on-link DNS servers.
- *
- *   2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,
- *      RTM_DELNEIGH), watching only for neighbours in the watch list.
- *
- *        - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and
- *          even NUD_PROBE is perfectly normal; we merely record the new state.
- *
- *        - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due
- *          to garbage collection.  This is not necessarily of immediate
- *          concern; we record the neighbour as moving to NUD_NONE.
- *
- *        - A neighbour transitioning to NUD_FAILED (for any reason) is
- *          critically important and is handled as described below in #4.
- *
- *   3. All on-link neighbours in the watch list can be forcibly "probed" by
- *      calling #probeAll(). This should be called whenever it is important to
- *      verify that critical neighbours on the link are still reachable, e.g.
- *      when roaming between BSSIDs.
- *
- *        - The kernel will send unicast ARP requests for IPv4 neighbours and
- *          unicast NS packets for IPv6 neighbours.  The expected replies will
- *          likely be unicast.
- *
- *        - The forced probing is done holding a wakelock. The kernel may,
- *          however, initiate probing of a neighbor on its own, i.e. whenever
- *          a neighbour has expired from NUD_DELAY.
- *
- *        - The kernel sends:
- *
- *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit
- *
- *          number of probes (usually 3) every:
- *
- *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms
- *
- *          number of milliseconds (usually 1000ms). This normally results in
- *          3 unicast packets, 1 per second.
- *
- *        - If no response is received to any of the probe packets, the kernel
- *          marks the neighbour as being in state NUD_FAILED, and the listening
- *          process in #2 will learn of it.
- *
- *   4. We call the supplied Callback#notifyLost() function if the loss of a
- *      neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to
- *      become incomplete (a loss of provisioning).
- *
- *        - For example, losing all our IPv4 on-link DNS servers (or losing
- *          our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6)
- *          provisioning; Callback#notifyLost() would be called.
- *
- *        - Since it can be non-trivial to reacquire certain IP provisioning
- *          state it may be best for the link to disconnect completely and
- *          reconnect afresh.
- *
- * Accessing an instance of this class from multiple threads is NOT safe.
- *
- * @hide
- */
-public class IpReachabilityMonitor {
-    private static final String TAG = "IpReachabilityMonitor";
-    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
-
-    public interface Callback {
-        // This callback function must execute as quickly as possible as it is
-        // run on the same thread that listens to kernel neighbor updates.
-        //
-        // TODO: refactor to something like notifyProvisioningLost(String msg).
-        public void notifyLost(InetAddress ip, String logMsg);
-    }
-
-    /**
-     * Encapsulates IpReachabilityMonitor depencencies on systems that hinder unit testing.
-     * TODO: consider also wrapping MultinetworkPolicyTracker in this interface.
-     */
-    interface Dependencies {
-        void acquireWakeLock(long durationMs);
-
-        static Dependencies makeDefault(Context context, String iface) {
-            final String lockName = TAG + "." + iface;
-            final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-            final WakeLock lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
-
-            return new Dependencies() {
-                public void acquireWakeLock(long durationMs) {
-                    lock.acquire(durationMs);
-                }
-            };
-        }
-    }
-
-    private final InterfaceParams mInterfaceParams;
-    private final IpNeighborMonitor mIpNeighborMonitor;
-    private final SharedLog mLog;
-    private final Callback mCallback;
-    private final Dependencies mDependencies;
-    private final boolean mUsingMultinetworkPolicyTracker;
-    private final ConnectivityManager mCm;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-    private LinkProperties mLinkProperties = new LinkProperties();
-    private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
-    // Time in milliseconds of the last forced probe request.
-    private volatile long mLastProbeTimeMs;
-
-    public IpReachabilityMonitor(
-            Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
-            boolean usingMultinetworkPolicyTracker) {
-        this(context, ifParams, h, log, callback, usingMultinetworkPolicyTracker,
-                Dependencies.makeDefault(context, ifParams.name));
-    }
-
-    @VisibleForTesting
-    IpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log,
-            Callback callback, boolean usingMultinetworkPolicyTracker, Dependencies dependencies) {
-        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
-
-        mInterfaceParams = ifParams;
-        mLog = log.forSubComponent(TAG);
-        mCallback = callback;
-        mUsingMultinetworkPolicyTracker = usingMultinetworkPolicyTracker;
-        mCm = context.getSystemService(ConnectivityManager.class);
-        mDependencies = dependencies;
-
-        mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
-                (NeighborEvent event) -> {
-                    if (mInterfaceParams.index != event.ifindex) return;
-                    if (!mNeighborWatchList.containsKey(event.ip)) return;
-
-                    final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
-
-                    // TODO: Consider what to do with other states that are not within
-                    // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
-                    if (event.nudState == StructNdMsg.NUD_FAILED) {
-                        mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
-                        handleNeighborLost(event);
-                    }
-                });
-        mIpNeighborMonitor.start();
-    }
-
-    public void stop() {
-        mIpNeighborMonitor.stop();
-        clearLinkProperties();
-    }
-
-    public void dump(PrintWriter pw) {
-        if (Looper.myLooper() == mIpNeighborMonitor.getHandler().getLooper()) {
-            pw.println(describeWatchList("\n"));
-            return;
-        }
-
-        final ConditionVariable cv = new ConditionVariable(false);
-        mIpNeighborMonitor.getHandler().post(() -> {
-            pw.println(describeWatchList("\n"));
-            cv.open();
-        });
-
-        if (!cv.block(1000)) {
-            pw.println("Timed out waiting for IpReachabilityMonitor dump");
-        }
-    }
-
-    private String describeWatchList() { return describeWatchList(" "); }
-
-    private String describeWatchList(String sep) {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("iface{" + mInterfaceParams + "}," + sep);
-        sb.append("ntable=[" + sep);
-        String delimiter = "";
-        for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
-            sb.append(delimiter).append(entry.getKey().getHostAddress() + "/" + entry.getValue());
-            delimiter = "," + sep;
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
-        for (RouteInfo route : routes) {
-            if (!route.hasGateway() && route.matches(ip)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void updateLinkProperties(LinkProperties lp) {
-        if (!mInterfaceParams.name.equals(lp.getInterfaceName())) {
-            // TODO: figure out whether / how to cope with interface changes.
-            Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() +
-                    "' does not match: " + mInterfaceParams.name);
-            return;
-        }
-
-        mLinkProperties = new LinkProperties(lp);
-        Map<InetAddress, NeighborEvent> newNeighborWatchList = new HashMap<>();
-
-        final List<RouteInfo> routes = mLinkProperties.getRoutes();
-        for (RouteInfo route : routes) {
-            if (route.hasGateway()) {
-                InetAddress gw = route.getGateway();
-                if (isOnLink(routes, gw)) {
-                    newNeighborWatchList.put(gw, mNeighborWatchList.getOrDefault(gw, null));
-                }
-            }
-        }
-
-        for (InetAddress dns : lp.getDnsServers()) {
-            if (isOnLink(routes, dns)) {
-                newNeighborWatchList.put(dns, mNeighborWatchList.getOrDefault(dns, null));
-            }
-        }
-
-        mNeighborWatchList = newNeighborWatchList;
-        if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
-    }
-
-    public void clearLinkProperties() {
-        mLinkProperties.clear();
-        mNeighborWatchList.clear();
-        if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
-    }
-
-    private void handleNeighborLost(NeighborEvent event) {
-        final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
-
-        InetAddress ip = null;
-        for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
-            // TODO: Consider using NeighborEvent#isValid() here; it's more
-            // strict but may interact badly if other entries are somehow in
-            // NUD_INCOMPLETE (say, during network attach).
-            if (entry.getValue().nudState != StructNdMsg.NUD_FAILED) continue;
-
-            ip = entry.getKey();
-            for (RouteInfo route : mLinkProperties.getRoutes()) {
-                if (ip.equals(route.getGateway())) {
-                    whatIfLp.removeRoute(route);
-                }
-            }
-
-            if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
-                // We should do this unconditionally, but alas we cannot: b/31827713.
-                whatIfLp.removeDnsServer(ip);
-            }
-        }
-
-        final boolean lostProvisioning =
-                (mLinkProperties.isIpv4Provisioned() && !whatIfLp.isIpv4Provisioned())
-                || (mLinkProperties.isIpv6Provisioned() && !whatIfLp.isIpv6Provisioned());
-
-        if (lostProvisioning) {
-            final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
-            Log.w(TAG, logMsg);
-            if (mCallback != null) {
-                // TODO: remove |ip| when the callback signature no longer has
-                // an InetAddress argument.
-                mCallback.notifyLost(ip, logMsg);
-            }
-        }
-        logNudFailed(lostProvisioning);
-    }
-
-    private boolean avoidingBadLinks() {
-        return !mUsingMultinetworkPolicyTracker || mCm.shouldAvoidBadWifi();
-    }
-
-    public void probeAll() {
-        final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
-
-        if (!ipProbeList.isEmpty()) {
-            // Keep the CPU awake long enough to allow all ARP/ND
-            // probes a reasonable chance at success. See b/23197666.
-            //
-            // The wakelock we use is (by default) refcounted, and this version
-            // of acquire(timeout) queues a release message to keep acquisitions
-            // and releases balanced.
-            mDependencies.acquireWakeLock(getProbeWakeLockDuration());
-        }
-
-        for (InetAddress ip : ipProbeList) {
-            final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip);
-            mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
-                     ip.getHostAddress(), rval));
-            logEvent(IpReachabilityEvent.PROBE, rval);
-        }
-        mLastProbeTimeMs = SystemClock.elapsedRealtime();
-    }
-
-    private static long getProbeWakeLockDuration() {
-        // Ideally, this would be computed by examining the values of:
-        //
-        //     /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit
-        //
-        // and:
-        //
-        //     /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms
-        //
-        // For now, just make some assumptions.
-        final long numUnicastProbes = 3;
-        final long retransTimeMs = 1000;
-        final long gracePeriodMs = 500;
-        return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
-    }
-
-    private void logEvent(int probeType, int errorCode) {
-        int eventType = probeType | (errorCode & 0xff);
-        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
-    }
-
-    private void logNudFailed(boolean lostProvisioning) {
-        long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
-        boolean isFromProbe = (duration < getProbeWakeLockDuration());
-        int eventType = nudFailureEventType(isFromProbe, lostProvisioning);
-        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
-    }
-
-    /**
-     * Returns the NUD failure event type code corresponding to the given conditions.
-     */
-    private static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
-        if (isFromProbe) {
-            return isProvisioningLost ? PROVISIONING_LOST : NUD_FAILED;
-        } else {
-            return isProvisioningLost ? PROVISIONING_LOST_ORGANIC : NUD_FAILED_ORGANIC;
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/util/ConnectivityPacketSummary.java b/packages/NetworkStack/src/android/net/util/ConnectivityPacketSummary.java
deleted file mode 100644
index 08c3f60..0000000
--- a/packages/NetworkStack/src/android/net/util/ConnectivityPacketSummary.java
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import static android.system.OsConstants.IPPROTO_ICMPV6;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import static com.android.server.util.NetworkStackConstants.ARP_HWTYPE_ETHER;
-import static com.android.server.util.NetworkStackConstants.ARP_PAYLOAD_LEN;
-import static com.android.server.util.NetworkStackConstants.ARP_REPLY;
-import static com.android.server.util.NetworkStackConstants.ARP_REQUEST;
-import static com.android.server.util.NetworkStackConstants.DHCP4_CLIENT_PORT;
-import static com.android.server.util.NetworkStackConstants.ETHER_ADDR_LEN;
-import static com.android.server.util.NetworkStackConstants.ETHER_DST_ADDR_OFFSET;
-import static com.android.server.util.NetworkStackConstants.ETHER_HEADER_LEN;
-import static com.android.server.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET;
-import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_ARP;
-import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_IPV4;
-import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_IPV6;
-import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_OFFSET;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_MIN_LENGTH;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_LEN;
-import static com.android.server.util.NetworkStackConstants.IPV4_DST_ADDR_OFFSET;
-import static com.android.server.util.NetworkStackConstants.IPV4_FLAGS_OFFSET;
-import static com.android.server.util.NetworkStackConstants.IPV4_FRAGMENT_MASK;
-import static com.android.server.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
-import static com.android.server.util.NetworkStackConstants.IPV4_IHL_MASK;
-import static com.android.server.util.NetworkStackConstants.IPV4_PROTOCOL_OFFSET;
-import static com.android.server.util.NetworkStackConstants.IPV4_SRC_ADDR_OFFSET;
-import static com.android.server.util.NetworkStackConstants.IPV6_ADDR_LEN;
-import static com.android.server.util.NetworkStackConstants.IPV6_HEADER_LEN;
-import static com.android.server.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET;
-import static com.android.server.util.NetworkStackConstants.IPV6_SRC_ADDR_OFFSET;
-import static com.android.server.util.NetworkStackConstants.UDP_HEADER_LEN;
-
-import android.net.MacAddress;
-import android.net.dhcp.DhcpPacket;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.StringJoiner;
-
-
-/**
- * Critical connectivity packet summarizing class.
- *
- * Outputs short descriptions of ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
- *
- * @hide
- */
-public class ConnectivityPacketSummary {
-    private static final String TAG = ConnectivityPacketSummary.class.getSimpleName();
-
-    private final byte[] mHwAddr;
-    private final byte[] mBytes;
-    private final int mLength;
-    private final ByteBuffer mPacket;
-    private final String mSummary;
-
-    public static String summarize(MacAddress hwaddr, byte[] buffer) {
-        return summarize(hwaddr, buffer, buffer.length);
-    }
-
-    // Methods called herein perform some but by no means all error checking.
-    // They may throw runtime exceptions on malformed packets.
-    public static String summarize(MacAddress macAddr, byte[] buffer, int length) {
-        if ((macAddr == null) || (buffer == null)) return null;
-        length = Math.min(length, buffer.length);
-        return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString();
-    }
-
-    private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) {
-        mHwAddr = macAddr.toByteArray();
-        mBytes = buffer;
-        mLength = Math.min(length, mBytes.length);
-        mPacket = ByteBuffer.wrap(mBytes, 0, mLength);
-        mPacket.order(ByteOrder.BIG_ENDIAN);
-
-        final StringJoiner sj = new StringJoiner(" ");
-        // TODO: support other link-layers, or even no link-layer header.
-        parseEther(sj);
-        mSummary = sj.toString();
-    }
-
-    public String toString() {
-        return mSummary;
-    }
-
-    private void parseEther(StringJoiner sj) {
-        if (mPacket.remaining() < ETHER_HEADER_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(ETHER_SRC_ADDR_OFFSET);
-        final ByteBuffer srcMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
-        sj.add(ByteBuffer.wrap(mHwAddr).equals(srcMac) ? "TX" : "RX");
-        sj.add(getMacAddressString(srcMac));
-
-        mPacket.position(ETHER_DST_ADDR_OFFSET);
-        final ByteBuffer dstMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
-        sj.add(">").add(getMacAddressString(dstMac));
-
-        mPacket.position(ETHER_TYPE_OFFSET);
-        final int etherType = asUint(mPacket.getShort());
-        switch (etherType) {
-            case ETHER_TYPE_ARP:
-                sj.add("arp");
-                parseARP(sj);
-                break;
-            case ETHER_TYPE_IPV4:
-                sj.add("ipv4");
-                parseIPv4(sj);
-                break;
-            case ETHER_TYPE_IPV6:
-                sj.add("ipv6");
-                parseIPv6(sj);
-                break;
-            default:
-                // Unknown ether type.
-                sj.add("ethtype").add(asString(etherType));
-                break;
-        }
-    }
-
-    private void parseARP(StringJoiner sj) {
-        if (mPacket.remaining() < ARP_PAYLOAD_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        if (asUint(mPacket.getShort()) != ARP_HWTYPE_ETHER ||
-            asUint(mPacket.getShort()) != ETHER_TYPE_IPV4 ||
-            asUint(mPacket.get()) != ETHER_ADDR_LEN ||
-            asUint(mPacket.get()) != IPV4_ADDR_LEN) {
-            sj.add("unexpected header");
-            return;
-        }
-
-        final int opCode = asUint(mPacket.getShort());
-
-        final String senderHwAddr = getMacAddressString(mPacket);
-        final String senderIPv4 = getIPv4AddressString(mPacket);
-        getMacAddressString(mPacket);  // target hardware address, unused
-        final String targetIPv4 = getIPv4AddressString(mPacket);
-
-        if (opCode == ARP_REQUEST) {
-            sj.add("who-has").add(targetIPv4);
-        } else if (opCode == ARP_REPLY) {
-            sj.add("reply").add(senderIPv4).add(senderHwAddr);
-        } else {
-            sj.add("unknown opcode").add(asString(opCode));
-        }
-    }
-
-    private void parseIPv4(StringJoiner sj) {
-        if (!mPacket.hasRemaining()) {
-            sj.add("runt");
-            return;
-        }
-
-        final int startOfIpLayer = mPacket.position();
-        final int ipv4HeaderLength = (mPacket.get(startOfIpLayer) & IPV4_IHL_MASK) * 4;
-        if (mPacket.remaining() < ipv4HeaderLength ||
-            mPacket.remaining() < IPV4_HEADER_MIN_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-        final int startOfTransportLayer = startOfIpLayer + ipv4HeaderLength;
-
-        mPacket.position(startOfIpLayer + IPV4_FLAGS_OFFSET);
-        final int flagsAndFragment = asUint(mPacket.getShort());
-        final boolean isFragment = (flagsAndFragment & IPV4_FRAGMENT_MASK) != 0;
-
-        mPacket.position(startOfIpLayer + IPV4_PROTOCOL_OFFSET);
-        final int protocol = asUint(mPacket.get());
-
-        mPacket.position(startOfIpLayer + IPV4_SRC_ADDR_OFFSET);
-        final String srcAddr = getIPv4AddressString(mPacket);
-
-        mPacket.position(startOfIpLayer + IPV4_DST_ADDR_OFFSET);
-        final String dstAddr = getIPv4AddressString(mPacket);
-
-        sj.add(srcAddr).add(">").add(dstAddr);
-
-        mPacket.position(startOfTransportLayer);
-        if (protocol == IPPROTO_UDP) {
-            sj.add("udp");
-            if (isFragment) sj.add("fragment");
-            else parseUDP(sj);
-        } else {
-            sj.add("proto").add(asString(protocol));
-            if (isFragment) sj.add("fragment");
-        }
-    }
-
-    private void parseIPv6(StringJoiner sj) {
-        if (mPacket.remaining() < IPV6_HEADER_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        final int startOfIpLayer = mPacket.position();
-
-        mPacket.position(startOfIpLayer + IPV6_PROTOCOL_OFFSET);
-        final int protocol = asUint(mPacket.get());
-
-        mPacket.position(startOfIpLayer + IPV6_SRC_ADDR_OFFSET);
-        final String srcAddr = getIPv6AddressString(mPacket);
-        final String dstAddr = getIPv6AddressString(mPacket);
-
-        sj.add(srcAddr).add(">").add(dstAddr);
-
-        mPacket.position(startOfIpLayer + IPV6_HEADER_LEN);
-        if (protocol == IPPROTO_ICMPV6) {
-            sj.add("icmp6");
-            parseICMPv6(sj);
-        } else {
-            sj.add("proto").add(asString(protocol));
-        }
-    }
-
-    private void parseICMPv6(StringJoiner sj) {
-        if (mPacket.remaining() < ICMPV6_HEADER_MIN_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        final int icmp6Type = asUint(mPacket.get());
-        final int icmp6Code = asUint(mPacket.get());
-        mPacket.getShort();  // checksum, unused
-
-        switch (icmp6Type) {
-            case ICMPV6_ROUTER_SOLICITATION:
-                sj.add("rs");
-                parseICMPv6RouterSolicitation(sj);
-                break;
-            case ICMPV6_ROUTER_ADVERTISEMENT:
-                sj.add("ra");
-                parseICMPv6RouterAdvertisement(sj);
-                break;
-            case ICMPV6_NEIGHBOR_SOLICITATION:
-                sj.add("ns");
-                parseICMPv6NeighborMessage(sj);
-                break;
-            case ICMPV6_NEIGHBOR_ADVERTISEMENT:
-                sj.add("na");
-                parseICMPv6NeighborMessage(sj);
-                break;
-            default:
-                sj.add("type").add(asString(icmp6Type));
-                sj.add("code").add(asString(icmp6Code));
-                break;
-        }
-    }
-
-    private void parseICMPv6RouterSolicitation(StringJoiner sj) {
-        final int RESERVED = 4;
-        if (mPacket.remaining() < RESERVED) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(mPacket.position() + RESERVED);
-        parseICMPv6NeighborDiscoveryOptions(sj);
-    }
-
-    private void parseICMPv6RouterAdvertisement(StringJoiner sj) {
-        final int FLAGS_AND_TIMERS = 3 * 4;
-        if (mPacket.remaining() < FLAGS_AND_TIMERS) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(mPacket.position() + FLAGS_AND_TIMERS);
-        parseICMPv6NeighborDiscoveryOptions(sj);
-    }
-
-    private void parseICMPv6NeighborMessage(StringJoiner sj) {
-        final int RESERVED = 4;
-        final int minReq = RESERVED + IPV6_ADDR_LEN;
-        if (mPacket.remaining() < minReq) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(mPacket.position() + RESERVED);
-        sj.add(getIPv6AddressString(mPacket));
-        parseICMPv6NeighborDiscoveryOptions(sj);
-    }
-
-    private void parseICMPv6NeighborDiscoveryOptions(StringJoiner sj) {
-        // All ND options are TLV, where T is one byte and L is one byte equal
-        // to the length of T + L + V in units of 8 octets.
-        while (mPacket.remaining() >= ICMPV6_ND_OPTION_MIN_LENGTH) {
-            final int ndType = asUint(mPacket.get());
-            final int ndLength = asUint(mPacket.get());
-            final int ndBytes = ndLength * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR - 2;
-            if (ndBytes < 0 || ndBytes > mPacket.remaining()) {
-                sj.add("<malformed>");
-                break;
-            }
-            final int position = mPacket.position();
-
-            switch (ndType) {
-                    case ICMPV6_ND_OPTION_SLLA:
-                        sj.add("slla");
-                        sj.add(getMacAddressString(mPacket));
-                        break;
-                    case ICMPV6_ND_OPTION_TLLA:
-                        sj.add("tlla");
-                        sj.add(getMacAddressString(mPacket));
-                        break;
-                    case ICMPV6_ND_OPTION_MTU:
-                        sj.add("mtu");
-                        final short reserved = mPacket.getShort();
-                        sj.add(asString(mPacket.getInt()));
-                        break;
-                    default:
-                        // Skip.
-                        break;
-            }
-
-            mPacket.position(position + ndBytes);
-        }
-    }
-
-    private void parseUDP(StringJoiner sj) {
-        if (mPacket.remaining() < UDP_HEADER_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        final int previous = mPacket.position();
-        final int srcPort = asUint(mPacket.getShort());
-        final int dstPort = asUint(mPacket.getShort());
-        sj.add(asString(srcPort)).add(">").add(asString(dstPort));
-
-        mPacket.position(previous + UDP_HEADER_LEN);
-        if (srcPort == DHCP4_CLIENT_PORT || dstPort == DHCP4_CLIENT_PORT) {
-            sj.add("dhcp4");
-            parseDHCPv4(sj);
-        }
-    }
-
-    private void parseDHCPv4(StringJoiner sj) {
-        final DhcpPacket dhcpPacket;
-        try {
-            dhcpPacket = DhcpPacket.decodeFullPacket(mBytes, mLength, DhcpPacket.ENCAP_L2);
-            sj.add(dhcpPacket.toString());
-        } catch (DhcpPacket.ParseException e) {
-            sj.add("parse error: " + e);
-        }
-    }
-
-    private static String getIPv4AddressString(ByteBuffer ipv4) {
-        return getIpAddressString(ipv4, IPV4_ADDR_LEN);
-    }
-
-    private static String getIPv6AddressString(ByteBuffer ipv6) {
-        return getIpAddressString(ipv6, IPV6_ADDR_LEN);
-    }
-
-    private static String getIpAddressString(ByteBuffer ip, int byteLength) {
-        if (ip == null || ip.remaining() < byteLength) return "invalid";
-
-        byte[] bytes = new byte[byteLength];
-        ip.get(bytes, 0, byteLength);
-        try {
-            InetAddress addr = InetAddress.getByAddress(bytes);
-            return addr.getHostAddress();
-        } catch (UnknownHostException uhe) {
-            return "unknown";
-        }
-    }
-
-    private static String getMacAddressString(ByteBuffer mac) {
-        if (mac == null || mac.remaining() < ETHER_ADDR_LEN) return "invalid";
-
-        byte[] bytes = new byte[ETHER_ADDR_LEN];
-        mac.get(bytes, 0, bytes.length);
-        Object[] printableBytes = new Object[bytes.length];
-        int i = 0;
-        for (byte b : bytes) printableBytes[i++] = new Byte(b);
-
-        final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x";
-        return String.format(MAC48_FORMAT, printableBytes);
-    }
-
-    /**
-     * Convenience method to convert an int to a String.
-     */
-    public static String asString(int i) {
-        return Integer.toString(i);
-    }
-
-    /**
-     * Convenience method to read a byte as an unsigned int.
-     */
-    public static int asUint(byte b) {
-        return (b & 0xff);
-    }
-
-    /**
-     * Convenience method to read a short as an unsigned int.
-     */
-    public static int asUint(short s) {
-        return (s & 0xffff);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/util/DataStallUtils.java b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
deleted file mode 100644
index b6dbeb1..0000000
--- a/packages/NetworkStack/src/android/net/util/DataStallUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.util;
-
-/**
- * Collection of utilities for data stall.
- */
-public class DataStallUtils {
-    /**
-     * Detect data stall via using dns timeout counts.
-     */
-    public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
-    // Default configuration values for data stall detection.
-    public static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
-    public static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
-    public static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
-    /**
-     * The threshold value for the number of consecutive dns timeout events received to be a
-     * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
-     * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
-     * that the value should be {@code > 0} if the DNS data stall detection is enabled.
-     *
-     */
-    public static final String CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
-            "data_stall_consecutive_dns_timeout_threshold";
-
-    /**
-     * The minimal time interval in milliseconds for data stall reevaluation.
-     *
-     */
-    public static final String CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL =
-            "data_stall_min_evaluate_interval";
-
-    /**
-     * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
-     * a data stall.
-     *
-     */
-    public static final String CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD =
-            "data_stall_valid_dns_time_threshold";
-
-    /**
-     * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
-     * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
-     *
-     * Type: int
-     * Valid values:
-     *   {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
-     */
-    public static final String CONFIG_DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-    public static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = DATA_STALL_EVALUATION_TYPE_DNS;
-    // The default number of DNS events kept of the log kept for dns signal evaluation. Each event
-    // is represented by a {@link com.android.server.connectivity.NetworkMonitor#DnsResult} objects.
-    // It's also the size of array of {@link com.android.server.connectivity.nano.DnsEvent} kept in
-    // metrics. Note that increasing the size may cause statsd log buffer bust. Need to check the
-    // design in statsd when you try to increase the size.
-    public static final int DEFAULT_DNS_LOG_SIZE = 20;
-}
diff --git a/packages/NetworkStack/src/android/net/util/FdEventsReader.java b/packages/NetworkStack/src/android/net/util/FdEventsReader.java
deleted file mode 100644
index 1380ea7..0000000
--- a/packages/NetworkStack/src/android/net/util/FdEventsReader.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-
-/**
- * This class encapsulates the mechanics of registering a file descriptor
- * with a thread's Looper and handling read events (and errors).
- *
- * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override
- * onStop() and onStart().
- *
- * Subclasses can expect a call life-cycle like the following:
- *
- *     [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all
- *         goes well. Implementations may override onStart() for additional initialization.
- *
- *     [2] yield, waiting for read event or error notification:
- *
- *             [a] readPacket() && handlePacket()
- *
- *             [b] if (no error):
- *                     goto 2
- *                 else:
- *                     goto 3
- *
- *     [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never
- *         started). Implementations may override onStop() for additional cleanup.
- *
- * The packet receive buffer is recycled on every read call, so subclasses
- * should make any copies they would like inside their handlePacket()
- * implementation.
- *
- * All public methods MUST only be called from the same thread with which
- * the Handler constructor argument is associated.
- *
- * @param <BufferType> the type of the buffer used to read data.
- * @hide
- */
-public abstract class FdEventsReader<BufferType> {
-    private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
-    private static final int UNREGISTER_THIS_FD = 0;
-
-    @NonNull
-    private final Handler mHandler;
-    @NonNull
-    private final MessageQueue mQueue;
-    @NonNull
-    private final BufferType mBuffer;
-    @Nullable
-    private FileDescriptor mFd;
-    private long mPacketsReceived;
-
-    protected static void closeFd(FileDescriptor fd) {
-        try {
-            SocketUtils.closeSocket(fd);
-        } catch (IOException ignored) {
-        }
-    }
-
-    protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) {
-        mHandler = h;
-        mQueue = mHandler.getLooper().getQueue();
-        mBuffer = buffer;
-    }
-
-    /** Start this FdEventsReader. */
-    public void start() {
-        if (onCorrectThread()) {
-            createAndRegisterFd();
-        } else {
-            mHandler.post(() -> {
-                logError("start() called from off-thread", null);
-                createAndRegisterFd();
-            });
-        }
-    }
-
-    /** Stop this FdEventsReader and destroy the file descriptor. */
-    public void stop() {
-        if (onCorrectThread()) {
-            unregisterAndDestroyFd();
-        } else {
-            mHandler.post(() -> {
-                logError("stop() called from off-thread", null);
-                unregisterAndDestroyFd();
-            });
-        }
-    }
-
-    @NonNull
-    public Handler getHandler() {
-        return mHandler;
-    }
-
-    protected abstract int recvBufSize(@NonNull BufferType buffer);
-
-    /** Returns the size of the receive buffer. */
-    public int recvBufSize() {
-        return recvBufSize(mBuffer);
-    }
-
-    /**
-     * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}.
-     *
-     * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0.
-     */
-    public final long numPacketsReceived() {
-        return mPacketsReceived;
-    }
-
-    /**
-     * Subclasses MUST create the listening socket here, including setting all desired socket
-     * options, interface or address/port binding, etc. The socket MUST be created nonblocking.
-     */
-    @Nullable
-    protected abstract FileDescriptor createFd();
-
-    /**
-     * Implementations MUST return the bytes read or throw an Exception.
-     *
-     * <p>The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or
-     * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer
-     * contents and respectively wait for further input or retry the read immediately. For all other
-     * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this
-     * method.
-     */
-    protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer)
-            throws Exception;
-
-    /**
-     * Called by the main loop for every packet.  Any desired copies of
-     * |recvbuf| should be made in here, as the underlying byte array is
-     * reused across all reads.
-     */
-    protected void handlePacket(@NonNull BufferType recvbuf, int length) {}
-
-    /**
-     * Called by the main loop to log errors.  In some cases |e| may be null.
-     */
-    protected void logError(@NonNull String msg, @Nullable Exception e) {}
-
-    /**
-     * Called by start(), if successful, just prior to returning.
-     */
-    protected void onStart() {}
-
-    /**
-     * Called by stop() just prior to returning.
-     */
-    protected void onStop() {}
-
-    private void createAndRegisterFd() {
-        if (mFd != null) return;
-
-        try {
-            mFd = createFd();
-        } catch (Exception e) {
-            logError("Failed to create socket: ", e);
-            closeFd(mFd);
-            mFd = null;
-        }
-
-        if (mFd == null) return;
-
-        mQueue.addOnFileDescriptorEventListener(
-                mFd,
-                FD_EVENTS,
-                (fd, events) -> {
-                    // Always call handleInput() so read/recvfrom are given
-                    // a proper chance to encounter a meaningful errno and
-                    // perhaps log a useful error message.
-                    if (!isRunning() || !handleInput()) {
-                        unregisterAndDestroyFd();
-                        return UNREGISTER_THIS_FD;
-                    }
-                    return FD_EVENTS;
-                });
-        onStart();
-    }
-
-    private boolean isRunning() {
-        return (mFd != null) && mFd.valid();
-    }
-
-    // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error.
-    private boolean handleInput() {
-        while (isRunning()) {
-            final int bytesRead;
-
-            try {
-                bytesRead = readPacket(mFd, mBuffer);
-                if (bytesRead < 1) {
-                    if (isRunning()) logError("Socket closed, exiting", null);
-                    break;
-                }
-                mPacketsReceived++;
-            } catch (ErrnoException e) {
-                if (e.errno == OsConstants.EAGAIN) {
-                    // We've read everything there is to read this time around.
-                    return true;
-                } else if (e.errno == OsConstants.EINTR) {
-                    continue;
-                } else {
-                    if (isRunning()) logError("readPacket error: ", e);
-                    break;
-                }
-            } catch (Exception e) {
-                if (isRunning()) logError("readPacket error: ", e);
-                break;
-            }
-
-            try {
-                handlePacket(mBuffer, bytesRead);
-            } catch (Exception e) {
-                logError("handlePacket error: ", e);
-                break;
-            }
-        }
-
-        return false;
-    }
-
-    private void unregisterAndDestroyFd() {
-        if (mFd == null) return;
-
-        mQueue.removeOnFileDescriptorEventListener(mFd);
-        closeFd(mFd);
-        mFd = null;
-        onStop();
-    }
-
-    private boolean onCorrectThread() {
-        return (mHandler.getLooper() == Looper.myLooper());
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
deleted file mode 100644
index 541f9d8..0000000
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * 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.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.SparseArray;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * Collection of utilities for the network stack.
- */
-public class NetworkStackUtils {
-    // TODO: Refer to DeviceConfig definition.
-    public static final String NAMESPACE_CONNECTIVITY = "connectivity";
-
-    /**
-     * A list of captive portal detection specifications used in addition to the fallback URLs.
-     * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
-     * by "@@,@@".
-     */
-    public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
-            "captive_portal_fallback_probe_specs";
-
-    /**
-     * A comma separated list of URLs used for captive portal detection in addition to the
-     * fallback HTTP url associated with the CAPTIVE_PORTAL_FALLBACK_URL settings.
-     */
-    public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
-            "captive_portal_other_fallback_urls";
-
-    /**
-     * Which User-Agent string to use in the header of the captive portal detection probes.
-     * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
-     */
-    public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
-
-    /**
-     * Whether to use HTTPS for network validation. This is enabled by default and the setting
-     * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
-     * don't actually use HTTPS, but it's consistent with the other settings.
-     */
-    public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
-
-    /**
-     * The URL used for HTTPS captive portal detection upon a new connection.
-     * A 204 response code from the server is used for validation.
-     */
-    public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
-
-    /**
-     * The URL used for HTTP captive portal detection upon a new connection.
-     * A 204 response code from the server is used for validation.
-     */
-    public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
-
-    /**
-     * The URL used for fallback HTTP captive portal detection when previous HTTP
-     * and HTTPS captive portal detection attemps did not return a conclusive answer.
-     */
-    public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
-
-    /**
-     * What to do when connecting a network that presents a captive portal.
-     * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
-     *
-     * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
-     */
-    public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
-
-    /**
-     * Don't attempt to detect captive portals.
-     */
-    public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
-
-    /**
-     * When detecting a captive portal, display a notification that
-     * prompts the user to sign in.
-     */
-    public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
-
-    /**
-     * When detecting a captive portal, immediately disconnect from the
-     * network and do not reconnect to that network in the future.
-     */
-    public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
-
-    static {
-        System.loadLibrary("networkstackutilsjni");
-    }
-
-    /**
-     * @return True if the array is null or 0-length.
-     */
-    public static <T> boolean isEmpty(T[] array) {
-        return array == null || array.length == 0;
-    }
-
-    /**
-     * Close a socket, ignoring any exception while closing.
-     */
-    public static void closeSocketQuietly(FileDescriptor fd) {
-        try {
-            SocketUtils.closeSocket(fd);
-        } catch (IOException ignored) {
-        }
-    }
-
-    /**
-     * Returns an int array from the given Integer list.
-     */
-    public static int[] convertToIntArray(@NonNull List<Integer> list) {
-        int[] array = new int[list.size()];
-        for (int i = 0; i < list.size(); i++) {
-            array[i] = list.get(i);
-        }
-        return array;
-    }
-
-    /**
-     * Returns a long array from the given long list.
-     */
-    public static long[] convertToLongArray(@NonNull List<Long> list) {
-        long[] array = new long[list.size()];
-        for (int i = 0; i < list.size(); i++) {
-            array[i] = list.get(i);
-        }
-        return array;
-    }
-
-    /**
-     * @return True if there exists at least one element in the sparse array for which
-     * condition {@code predicate}
-     */
-    public static <T> boolean any(SparseArray<T> array, Predicate<T> predicate) {
-        for (int i = 0; i < array.size(); ++i) {
-            if (predicate.test(array.valueAt(i))) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
-     * @param namespace The namespace containing the property to look up.
-     * @param name The name of the property to look up.
-     * @param defaultValue The value to return if the property does not exist or has no valid value.
-     * @return the corresponding value, or defaultValue if none exists.
-     */
-    @Nullable
-    public static String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
-            @Nullable String defaultValue) {
-        // TODO: Link to DeviceConfig API once it is ready.
-        return defaultValue;
-    }
-
-    /**
-     * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
-     * @param namespace The namespace containing the property to look up.
-     * @param name The name of the property to look up.
-     * @param defaultValue The value to return if the property does not exist or has no non-null
-     *                     value.
-     * @return the corresponding value, or defaultValue if none exists.
-     */
-    public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
-            int defaultValue) {
-        String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */);
-        try {
-            return (value != null) ? Integer.parseInt(value) : defaultValue;
-        } catch (NumberFormatException e) {
-            return defaultValue;
-        }
-    }
-
-    /**
-     * Attaches a socket filter that accepts DHCP packets to the given socket.
-     */
-    public static native void attachDhcpFilter(FileDescriptor fd) throws SocketException;
-
-    /**
-     * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
-     * @param fd the socket's {@link FileDescriptor}.
-     * @param packetType the hardware address type, one of ARPHRD_*.
-     */
-    public static native void attachRaFilter(FileDescriptor fd, int packetType)
-            throws SocketException;
-
-    /**
-     * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
-     *
-     * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
-     *
-     * @param fd the socket's {@link FileDescriptor}.
-     * @param packetType the hardware address type, one of ARPHRD_*.
-     */
-    public static native void attachControlPacketFilter(FileDescriptor fd, int packetType)
-            throws SocketException;
-
-    /**
-     * Add an entry into the ARP cache.
-     */
-    public static void addArpEntry(Inet4Address ipv4Addr, android.net.MacAddress ethAddr,
-            String ifname, FileDescriptor fd) throws IOException {
-        addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd);
-    }
-
-    private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
-            FileDescriptor fd) throws IOException;
-
-    /**
-     * Return IP address and port in a string format.
-     */
-    public static String addressAndPortToString(InetAddress address, int port) {
-        return String.format(
-                (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d",
-                        address.getHostAddress(), port);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java
deleted file mode 100644
index 4aec6b6..0000000
--- a/packages/NetworkStack/src/android/net/util/PacketReader.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2018 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.util;
-
-import static java.lang.Math.max;
-
-import android.os.Handler;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-
-/**
- * Specialization of {@link FdEventsReader} that reads packets into a byte array.
- *
- * TODO: rename this class to something more correctly descriptive (something
- * like [or less horrible than] FdReadEventsHandler?).
- *
- * @hide
- */
-public abstract class PacketReader extends FdEventsReader<byte[]> {
-
-    public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024;
-
-    protected PacketReader(Handler h) {
-        this(h, DEFAULT_RECV_BUF_SIZE);
-    }
-
-    protected PacketReader(Handler h, int recvBufSize) {
-        super(h, new byte[max(recvBufSize, DEFAULT_RECV_BUF_SIZE)]);
-    }
-
-    @Override
-    protected final int recvBufSize(byte[] buffer) {
-        return buffer.length;
-    }
-
-    /**
-     * Subclasses MAY override this to change the default read() implementation
-     * in favour of, say, recvfrom().
-     *
-     * Implementations MUST return the bytes read or throw an Exception.
-     */
-    @Override
-    protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception {
-        return Os.read(fd, packetBuffer, 0, packetBuffer.length);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/util/SharedLog.java b/packages/NetworkStack/src/android/net/util/SharedLog.java
deleted file mode 100644
index 4fabf10..0000000
--- a/packages/NetworkStack/src/android/net/util/SharedLog.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 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.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.StringJoiner;
-
-
-/**
- * Class to centralize logging functionality for tethering.
- *
- * All access to class methods other than dump() must be on the same thread.
- *
- * @hide
- */
-public class SharedLog {
-    private static final int DEFAULT_MAX_RECORDS = 500;
-    private static final String COMPONENT_DELIMITER = ".";
-
-    private enum Category {
-        NONE,
-        ERROR,
-        MARK,
-        WARN,
-    };
-
-    private final LocalLog mLocalLog;
-    // The tag to use for output to the system log. This is not output to the
-    // LocalLog because that would be redundant.
-    private final String mTag;
-    // The component (or subcomponent) of a system that is sharing this log.
-    // This can grow in depth if components call forSubComponent() to obtain
-    // their SharedLog instance. The tag is not included in the component for
-    // brevity.
-    private final String mComponent;
-
-    public SharedLog(String tag) {
-        this(DEFAULT_MAX_RECORDS, tag);
-    }
-
-    public SharedLog(int maxRecords, String tag) {
-        this(new LocalLog(maxRecords), tag, tag);
-    }
-
-    private SharedLog(LocalLog localLog, String tag, String component) {
-        mLocalLog = localLog;
-        mTag = tag;
-        mComponent = component;
-    }
-
-    public String getTag() {
-        return mTag;
-    }
-
-    /**
-     * Create a SharedLog based on this log with an additional component prefix on each logged line.
-     */
-    public SharedLog forSubComponent(String component) {
-        if (!isRootLogInstance()) {
-            component = mComponent + COMPONENT_DELIMITER + component;
-        }
-        return new SharedLog(mLocalLog, mTag, component);
-    }
-
-    /**
-     * Dump the contents of this log.
-     *
-     * <p>This method may be called on any thread.
-     */
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
-    }
-
-    //////
-    // Methods that both log an entry and emit it to the system log.
-    //////
-
-    /**
-     * Log an error due to an exception. This does not include the exception stacktrace.
-     *
-     * <p>The log entry will be also added to the system log.
-     * @see #e(String, Throwable)
-     */
-    public void e(Exception e) {
-        Log.e(mTag, record(Category.ERROR, e.toString()));
-    }
-
-    /**
-     * Log an error message.
-     *
-     * <p>The log entry will be also added to the system log.
-     */
-    public void e(String msg) {
-        Log.e(mTag, record(Category.ERROR, msg));
-    }
-
-    /**
-     * Log an error due to an exception, with the exception stacktrace if provided.
-     *
-     * <p>The error and exception message appear in the shared log, but the stacktrace is only
-     * logged in general log output (logcat). The log entry will be also added to the system log.
-     */
-    public void e(@NonNull String msg, @Nullable Throwable exception) {
-        if (exception == null) {
-            e(msg);
-            return;
-        }
-        Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
-    }
-
-    /**
-     * Log an informational message.
-     *
-     * <p>The log entry will be also added to the system log.
-     */
-    public void i(String msg) {
-        Log.i(mTag, record(Category.NONE, msg));
-    }
-
-    /**
-     * Log a warning message.
-     *
-     * <p>The log entry will be also added to the system log.
-     */
-    public void w(String msg) {
-        Log.w(mTag, record(Category.WARN, msg));
-    }
-
-    //////
-    // Methods that only log an entry (and do NOT emit to the system log).
-    //////
-
-    /**
-     * Log a general message to be only included in the in-memory log.
-     *
-     * <p>The log entry will *not* be added to the system log.
-     */
-    public void log(String msg) {
-        record(Category.NONE, msg);
-    }
-
-    /**
-     * Log a general, formatted message to be only included in the in-memory log.
-     *
-     * <p>The log entry will *not* be added to the system log.
-     * @see String#format(String, Object...)
-     */
-    public void logf(String fmt, Object... args) {
-        log(String.format(fmt, args));
-    }
-
-    /**
-     * Log a message with MARK level.
-     *
-     * <p>The log entry will *not* be added to the system log.
-     */
-    public void mark(String msg) {
-        record(Category.MARK, msg);
-    }
-
-    private String record(Category category, String msg) {
-        final String entry = logLine(category, msg);
-        mLocalLog.log(entry);
-        return entry;
-    }
-
-    private String logLine(Category category, String msg) {
-        final StringJoiner sj = new StringJoiner(" ");
-        if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
-        if (category != Category.NONE) sj.add(category.toString());
-        return sj.add(msg).toString();
-    }
-
-    // Check whether this SharedLog instance is nominally the top level in
-    // a potential hierarchy of shared logs (the root of a tree),
-    // or is a subcomponent within the hierarchy.
-    private boolean isRootLogInstance() {
-        return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
-    }
-}
diff --git a/packages/NetworkStack/src/android/net/util/Stopwatch.java b/packages/NetworkStack/src/android/net/util/Stopwatch.java
deleted file mode 100644
index c316699..0000000
--- a/packages/NetworkStack/src/android/net/util/Stopwatch.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import android.os.SystemClock;
-
-
-/**
- * @hide
- */
-public class Stopwatch {
-    private long mStartTimeMs;
-    private long mStopTimeMs;
-
-    public boolean isStarted() {
-        return (mStartTimeMs > 0);
-    }
-
-    public boolean isStopped() {
-        return (mStopTimeMs > 0);
-    }
-
-    public boolean isRunning() {
-        return (isStarted() && !isStopped());
-    }
-
-    /**
-     * Start the Stopwatch.
-     */
-    public Stopwatch start() {
-        if (!isStarted()) {
-            mStartTimeMs = SystemClock.elapsedRealtime();
-        }
-        return this;
-    }
-
-    /**
-     * Stop the Stopwatch.
-     * @return the total time recorded, in milliseconds, or 0 if not started.
-     */
-    public long stop() {
-        if (isRunning()) {
-            mStopTimeMs = SystemClock.elapsedRealtime();
-        }
-        // Return either the delta after having stopped, or 0.
-        return (mStopTimeMs - mStartTimeMs);
-    }
-
-    /**
-     * Return the total time recorded to date, in milliseconds.
-     * If the Stopwatch is not running, returns the same value as stop(),
-     * i.e. either the total time recorded before stopping or 0.
-     */
-    public long lap() {
-        if (isRunning()) {
-            return (SystemClock.elapsedRealtime() - mStartTimeMs);
-        } else {
-            return stop();
-        }
-    }
-
-    /**
-     * Reset the Stopwatch. It will be stopped when this method returns.
-     */
-    public void reset() {
-        mStartTimeMs = 0;
-        mStopTimeMs = 0;
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java
deleted file mode 100644
index 2523ecd..0000000
--- a/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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.networkstack.metrics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.util.NetworkStackUtils;
-import android.net.wifi.WifiInfo;
-
-import com.android.internal.util.HexDump;
-import com.android.server.connectivity.nano.CellularData;
-import com.android.server.connectivity.nano.DataStallEventProto;
-import com.android.server.connectivity.nano.DnsEvent;
-import com.android.server.connectivity.nano.WifiData;
-
-import com.google.protobuf.nano.MessageNano;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Class to record the stats of detection level information for data stall.
- *
- * @hide
- */
-public final class DataStallDetectionStats {
-    private static final int UNKNOWN_SIGNAL_STRENGTH = -1;
-    @NonNull
-    final byte[] mCellularInfo;
-    @NonNull
-    final byte[] mWifiInfo;
-    @NonNull
-    final byte[] mDns;
-    final int mEvaluationType;
-    final int mNetworkType;
-
-    public DataStallDetectionStats(@Nullable byte[] cell, @Nullable byte[] wifi,
-                @NonNull int[] returnCode, @NonNull long[] dnsTime, int evalType, int netType) {
-        mCellularInfo = emptyCellDataIfNull(cell);
-        mWifiInfo = emptyWifiInfoIfNull(wifi);
-
-        DnsEvent dns = new DnsEvent();
-        dns.dnsReturnCode = returnCode;
-        dns.dnsTime = dnsTime;
-        mDns = MessageNano.toByteArray(dns);
-        mEvaluationType = evalType;
-        mNetworkType = netType;
-    }
-
-    private byte[] emptyCellDataIfNull(@Nullable byte[] cell) {
-        if (cell != null) return cell;
-
-        CellularData data  = new CellularData();
-        data.ratType = DataStallEventProto.RADIO_TECHNOLOGY_UNKNOWN;
-        data.networkMccmnc = "";
-        data.simMccmnc = "";
-        data.signalStrength = UNKNOWN_SIGNAL_STRENGTH;
-        return MessageNano.toByteArray(data);
-    }
-
-    private byte[] emptyWifiInfoIfNull(@Nullable byte[] wifi) {
-        if (wifi != null) return wifi;
-
-        WifiData data = new WifiData();
-        data.wifiBand = DataStallEventProto.AP_BAND_UNKNOWN;
-        data.signalStrength = UNKNOWN_SIGNAL_STRENGTH;
-        return MessageNano.toByteArray(data);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("type: ").append(mNetworkType)
-          .append(", evaluation type: ")
-          .append(mEvaluationType)
-          .append(", wifi info: ")
-          .append(HexDump.toHexString(mWifiInfo))
-          .append(", cell info: ")
-          .append(HexDump.toHexString(mCellularInfo))
-          .append(", dns: ")
-          .append(HexDump.toHexString(mDns));
-        return sb.toString();
-    }
-
-    @Override
-    public boolean equals(@Nullable final Object o) {
-        if (!(o instanceof DataStallDetectionStats)) return false;
-        final DataStallDetectionStats other = (DataStallDetectionStats) o;
-        return (mNetworkType == other.mNetworkType)
-            && (mEvaluationType == other.mEvaluationType)
-            && Arrays.equals(mWifiInfo, other.mWifiInfo)
-            && Arrays.equals(mCellularInfo, other.mCellularInfo)
-            && Arrays.equals(mDns, other.mDns);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mNetworkType, mEvaluationType, mWifiInfo, mCellularInfo, mDns);
-    }
-
-    /**
-     * Utility to create an instance of {@Link DataStallDetectionStats}
-     *
-     * @hide
-     */
-    public static class Builder {
-        @Nullable
-        private byte[] mCellularInfo;
-        @Nullable
-        private byte[] mWifiInfo;
-        @NonNull
-        private final List<Integer> mDnsReturnCode = new ArrayList<Integer>();
-        @NonNull
-        private final List<Long> mDnsTimeStamp = new ArrayList<Long>();
-        private int mEvaluationType;
-        private int mNetworkType;
-
-        /**
-         * Add a dns event into Builder.
-         *
-         * @param code the return code of the dns event.
-         * @param timeMs the elapsedRealtime in ms that the the dns event was received from netd.
-         * @return {@code this} {@link Builder} instance.
-         */
-        public Builder addDnsEvent(int code, long timeMs) {
-            mDnsReturnCode.add(code);
-            mDnsTimeStamp.add(timeMs);
-            return this;
-        }
-
-        /**
-         * Set the dns evaluation type into Builder.
-         *
-         * @param type the return code of the dns event.
-         * @return {@code this} {@link Builder} instance.
-         */
-        public Builder setEvaluationType(int type) {
-            mEvaluationType = type;
-            return this;
-        }
-
-        /**
-         * Set the network type into Builder.
-         *
-         * @param type the network type of the logged network.
-         * @return {@code this} {@link Builder} instance.
-         */
-        public Builder setNetworkType(int type) {
-            mNetworkType = type;
-            return this;
-        }
-
-        /**
-         * Set the wifi data into Builder.
-         *
-         * @param info a {@link WifiInfo} of the connected wifi network.
-         * @return {@code this} {@link Builder} instance.
-         */
-        public Builder setWiFiData(@Nullable final WifiInfo info) {
-            WifiData data = new WifiData();
-            data.wifiBand = getWifiBand(info);
-            data.signalStrength = (info != null) ? info.getRssi() : UNKNOWN_SIGNAL_STRENGTH;
-            mWifiInfo = MessageNano.toByteArray(data);
-            return this;
-        }
-
-        private static int getWifiBand(@Nullable final WifiInfo info) {
-            if (info == null) return DataStallEventProto.AP_BAND_UNKNOWN;
-
-            int freq = info.getFrequency();
-            // Refer to ScanResult.is5GHz() and ScanResult.is24GHz().
-            if (freq > 4900 && freq < 5900) {
-                return DataStallEventProto.AP_BAND_5GHZ;
-            } else if (freq > 2400 && freq < 2500) {
-                return DataStallEventProto.AP_BAND_2GHZ;
-            } else {
-                return DataStallEventProto.AP_BAND_UNKNOWN;
-            }
-        }
-
-        /**
-         * Set the cellular data into Builder.
-         *
-         * @param radioType the radio technology of the logged cellular network.
-         * @param roaming a boolean indicates if logged cellular network is roaming or not.
-         * @param networkMccmnc the mccmnc of the camped network.
-         * @param simMccmnc the mccmnc of the sim.
-         * @return {@code this} {@link Builder} instance.
-         */
-        public Builder setCellData(int radioType, boolean roaming,
-                @NonNull String networkMccmnc, @NonNull String simMccmnc, int ss) {
-            CellularData data  = new CellularData();
-            data.ratType = radioType;
-            data.isRoaming = roaming;
-            data.networkMccmnc = networkMccmnc;
-            data.simMccmnc = simMccmnc;
-            data.signalStrength = ss;
-            mCellularInfo = MessageNano.toByteArray(data);
-            return this;
-        }
-
-        /**
-         * Create a new {@Link DataStallDetectionStats}.
-         */
-        public DataStallDetectionStats build() {
-            return new DataStallDetectionStats(mCellularInfo, mWifiInfo,
-                    NetworkStackUtils.convertToIntArray(mDnsReturnCode),
-                    NetworkStackUtils.convertToLongArray(mDnsTimeStamp),
-                    mEvaluationType, mNetworkType);
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java
deleted file mode 100644
index 9308901..0000000
--- a/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.networkstack.metrics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.util.Log;
-
-import com.android.internal.util.HexDump;
-import com.android.server.connectivity.nano.DataStallEventProto;
-
-/**
- * Collection of utilities for data stall metrics.
- *
- * To see if the logs are properly sent to statsd, execute following command.
- *
- * $ adb shell cmd stats print-logs
- * $ adb logcat | grep statsd  OR $ adb logcat -b stats
- *
- * @hide
- */
-public class DataStallStatsUtils {
-    private static final String TAG = DataStallStatsUtils.class.getSimpleName();
-    private static final boolean DBG = false;
-
-    private static int probeResultToEnum(@Nullable final CaptivePortalProbeResult result) {
-        if (result == null) return DataStallEventProto.INVALID;
-
-        if (result.isSuccessful()) {
-            return DataStallEventProto.VALID;
-        } else if (result.isPortal()) {
-            return DataStallEventProto.PORTAL;
-        } else if (result.isPartialConnectivity()) {
-            return DataStallEventProto.PARTIAL;
-        } else {
-            return DataStallEventProto.INVALID;
-        }
-    }
-
-    /**
-     * Write the metric to {@link StatsLog}.
-     */
-    public static void write(@NonNull final DataStallDetectionStats stats,
-            @NonNull final CaptivePortalProbeResult result) {
-        int validationResult = probeResultToEnum(result);
-        if (DBG) {
-            Log.d(TAG, "write: " + stats + " with result: " + validationResult
-                    + ", dns: " + HexDump.toHexString(stats.mDns));
-        }
-        NetworkStackStatsLog.write(NetworkStackStatsLog.DATA_STALL_EVENT,
-                stats.mEvaluationType,
-                validationResult,
-                stats.mNetworkType,
-                stats.mWifiInfo,
-                stats.mCellularInfo,
-                stats.mDns);
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/networkstack/util/DnsUtils.java b/packages/NetworkStack/src/com/android/networkstack/util/DnsUtils.java
deleted file mode 100644
index 4767d55..0000000
--- a/packages/NetworkStack/src/com/android/networkstack/util/DnsUtils.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.networkstack.util;
-
-import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
-import static android.net.DnsResolver.TYPE_A;
-import static android.net.DnsResolver.TYPE_AAAA;
-
-import android.annotation.NonNull;
-import android.net.DnsResolver;
-import android.net.Network;
-import android.net.TrafficStats;
-import android.util.Log;
-
-import com.android.internal.util.TrafficStatsConstants;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Collection of utilities for dns query.
- */
-public class DnsUtils {
-    // Decide what queries to make depending on what IP addresses are on the system.
-    public static final int TYPE_ADDRCONFIG = -1;
-    private static final String TAG = DnsUtils.class.getSimpleName();
-
-    /**
-     * Return both A and AAAA query results regardless the ip address type of the giving network.
-     * Used for probing in NetworkMonitor.
-     */
-    @NonNull
-    public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver,
-            @NonNull final Network network, @NonNull String host, int timeout)
-            throws UnknownHostException {
-        final List<InetAddress> result = new ArrayList<InetAddress>();
-
-        try {
-            result.addAll(Arrays.asList(
-                    getAllByName(dnsResolver, network, host, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
-                    timeout)));
-        } catch (UnknownHostException e) {
-            // Might happen if the host is v4-only, still need to query TYPE_A
-        }
-        try {
-            result.addAll(Arrays.asList(
-                    getAllByName(dnsResolver, network, host, TYPE_A, FLAG_NO_CACHE_LOOKUP,
-                    timeout)));
-        } catch (UnknownHostException e) {
-            // Might happen if the host is v6-only, still need to return AAAA answers
-        }
-        if (result.size() == 0) {
-            throw new UnknownHostException(host);
-        }
-        return result.toArray(new InetAddress[0]);
-    }
-
-    /**
-     * Return dns query result based on the given QueryType(TYPE_A, TYPE_AAAA) or TYPE_ADDRCONFIG.
-     * Used for probing in NetworkMonitor.
-     */
-    @NonNull
-    public static InetAddress[] getAllByName(@NonNull final DnsResolver dnsResolver,
-            @NonNull final Network network, @NonNull final String host, int type, int flag,
-            int timeoutMs) throws UnknownHostException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>();
-
-        final DnsResolver.Callback<List<InetAddress>> callback =
-                new DnsResolver.Callback<List<InetAddress>>() {
-            @Override
-            public void onAnswer(List<InetAddress> answer, int rcode) {
-                if (rcode == 0) {
-                    resultRef.set(answer);
-                }
-                latch.countDown();
-            }
-
-            @Override
-            public void onError(@NonNull DnsResolver.DnsException e) {
-                Log.d(TAG, "DNS error resolving " + host + ": " + e.getMessage());
-                latch.countDown();
-            }
-        };
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                TrafficStatsConstants.TAG_SYSTEM_PROBE);
-
-        if (type == TYPE_ADDRCONFIG) {
-            dnsResolver.query(network, host, flag, r -> r.run(), null /* cancellationSignal */,
-                    callback);
-        } else {
-            dnsResolver.query(network, host, type, flag, r -> r.run(),
-                    null /* cancellationSignal */, callback);
-        }
-
-        TrafficStats.setThreadStatsTag(oldTag);
-
-        try {
-            latch.await(timeoutMs, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-        }
-
-        final List<InetAddress> result = resultRef.get();
-        if (result == null || result.size() == 0) {
-            throw new UnknownHostException(host);
-        }
-
-        return result.toArray(new InetAddress[0]);
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserver.java b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
deleted file mode 100644
index cccec0b..0000000
--- a/packages/NetworkStack/src/com/android/server/NetworkObserver.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.LinkAddress;
-import android.net.RouteInfo;
-
-/**
- * Observer for network events, to use with {@link NetworkObserverRegistry}.
- */
-public interface NetworkObserver {
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener#onInterfaceChanged(java.lang.String, boolean)
-     */
-    default void onInterfaceChanged(String ifName, boolean up) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener#onInterfaceRemoved(String)
-     */
-    default void onInterfaceRemoved(String ifName) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener
-     *          #onInterfaceAddressUpdated(String, String, int, int)
-     */
-    default void onInterfaceAddressUpdated(LinkAddress address, String ifName) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener
-     *          #onInterfaceAddressRemoved(String, String, int, int)
-     */
-    default void onInterfaceAddressRemoved(LinkAddress address, String ifName) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener#onInterfaceLinkStateChanged(String, boolean)
-     */
-    default void onInterfaceLinkStateChanged(String ifName, boolean up) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener#onInterfaceAdded(String)
-     */
-    default void onInterfaceAdded(String ifName) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener
-     *          #onInterfaceClassActivityChanged(boolean, int, long, int)
-     */
-    default void onInterfaceClassActivityChanged(
-            boolean isActive, int label, long timestamp, int uid) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener#onQuotaLimitReached(String, String)
-     */
-    default void onQuotaLimitReached(String alertName, String ifName) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener
-     *          #onInterfaceDnsServerInfo(String, long, String[])
-     */
-    default void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener
-     *          #onRouteChanged(boolean, String, String, String)
-     */
-    default void onRouteUpdated(RouteInfo route) {}
-
-    /**
-     * @see android.net.INetdUnsolicitedEventListener
-     *          #onRouteChanged(boolean, String, String, String)
-     */
-    default void onRouteRemoved(RouteInfo route) {}
-}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
deleted file mode 100644
index afe166b..0000000
--- a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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 static android.net.RouteInfo.RTN_UNICAST;
-
-import android.annotation.NonNull;
-import android.net.INetd;
-import android.net.INetdUnsolicitedEventListener;
-import android.net.InetAddresses;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.RouteInfo;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * A class for reporting network events to clients.
- *
- * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to
- * all INetworkManagementEventObserver objects that have registered with it.
- */
-public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub {
-    private static final String TAG = NetworkObserverRegistry.class.getSimpleName();
-
-    /**
-     * Constructs a new NetworkObserverRegistry.
-     *
-     * <p>Only one registry should be used per process since netd will silently ignore multiple
-     * registrations from the same process.
-     */
-    NetworkObserverRegistry() {}
-
-    /**
-     * Start listening for Netd events.
-     *
-     * <p>This should be called before allowing any observer to be registered.
-     */
-    void register(@NonNull INetd netd) throws RemoteException {
-        netd.registerUnsolicitedEventListener(this);
-    }
-
-    private final ConcurrentHashMap<NetworkObserver, Optional<Handler>> mObservers =
-            new ConcurrentHashMap<>();
-
-    /**
-     * Registers the specified observer and start sending callbacks to it.
-     * This method may be called on any thread.
-     */
-    public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) {
-        if (handler == null) {
-            throw new IllegalArgumentException("handler must be non-null");
-        }
-        mObservers.put(observer, Optional.of(handler));
-    }
-
-    /**
-     * Registers the specified observer, and start sending callbacks to it.
-     *
-     * <p>This method must only be called with callbacks that are nonblocking, such as callbacks
-     * that only send a message to a StateMachine.
-     */
-    public void registerObserverForNonblockingCallback(@NonNull NetworkObserver observer) {
-        mObservers.put(observer, Optional.empty());
-    }
-
-    /**
-     * Unregisters the specified observer and stop sending callbacks to it.
-     * This method may be called on any thread.
-     */
-    public void unregisterObserver(@NonNull NetworkObserver observer) {
-        mObservers.remove(observer);
-    }
-
-    @FunctionalInterface
-    private interface NetworkObserverEventCallback {
-        void sendCallback(NetworkObserver o);
-    }
-
-    private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) {
-        // ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before
-        // creation will be processed, those added during traversal may or may not.
-        for (Map.Entry<NetworkObserver, Optional<Handler>> entry : mObservers.entrySet()) {
-            final NetworkObserver observer = entry.getKey();
-            final Optional<Handler> handler = entry.getValue();
-            if (handler.isPresent()) {
-                handler.get().post(() -> callback.sendCallback(observer));
-                return;
-            }
-
-            try {
-                callback.sendCallback(observer);
-            } catch (RuntimeException e) {
-                Log.e(TAG, "Error sending callback to observer", e);
-            }
-        }
-    }
-
-    @Override
-    public void onInterfaceClassActivityChanged(boolean isActive,
-            int label, long timestamp, int uid) {
-        invokeForAllObservers(o -> o.onInterfaceClassActivityChanged(
-                isActive, label, timestamp, uid));
-    }
-
-    /**
-     * Notify our observers of a limit reached.
-     */
-    @Override
-    public void onQuotaLimitReached(String alertName, String ifName) {
-        invokeForAllObservers(o -> o.onQuotaLimitReached(alertName, ifName));
-    }
-
-    @Override
-    public void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {
-        invokeForAllObservers(o -> o.onInterfaceDnsServerInfo(ifName, lifetime, servers));
-    }
-
-    @Override
-    public void onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope) {
-        final LinkAddress address = new LinkAddress(addr, flags, scope);
-        invokeForAllObservers(o -> o.onInterfaceAddressUpdated(address, ifName));
-    }
-
-    @Override
-    public void onInterfaceAddressRemoved(String addr,
-            String ifName, int flags, int scope) {
-        final LinkAddress address = new LinkAddress(addr, flags, scope);
-        invokeForAllObservers(o -> o.onInterfaceAddressRemoved(address, ifName));
-    }
-
-    @Override
-    public void onInterfaceAdded(String ifName) {
-        invokeForAllObservers(o -> o.onInterfaceAdded(ifName));
-    }
-
-    @Override
-    public void onInterfaceRemoved(String ifName) {
-        invokeForAllObservers(o -> o.onInterfaceRemoved(ifName));
-    }
-
-    @Override
-    public void onInterfaceChanged(String ifName, boolean up) {
-        invokeForAllObservers(o -> o.onInterfaceChanged(ifName, up));
-    }
-
-    @Override
-    public void onInterfaceLinkStateChanged(String ifName, boolean up) {
-        invokeForAllObservers(o -> o.onInterfaceLinkStateChanged(ifName, up));
-    }
-
-    @Override
-    public void onRouteChanged(boolean updated, String route, String gateway, String ifName) {
-        final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
-                ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
-                ifName, RTN_UNICAST);
-        if (updated) {
-            invokeForAllObservers(o -> o.onRouteUpdated(processRoute));
-        } else {
-            invokeForAllObservers(o -> o.onRouteRemoved(processRoute));
-        }
-    }
-
-    @Override
-    public void onStrictCleartextDetected(int uid, String hex) {}
-
-    @Override
-    public int getInterfaceVersion() {
-        return INetdUnsolicitedEventListener.VERSION;
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
deleted file mode 100644
index c394d4c..0000000
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2018 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 static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
-import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
-
-import static com.android.server.util.PermissionUtil.checkDumpPermission;
-import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.IIpMemoryStore;
-import android.net.IIpMemoryStoreCallbacks;
-import android.net.INetd;
-import android.net.INetworkMonitor;
-import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkStackConnector;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.PrivateDnsConfigParcel;
-import android.net.dhcp.DhcpServer;
-import android.net.dhcp.DhcpServingParams;
-import android.net.dhcp.DhcpServingParamsParcel;
-import android.net.dhcp.IDhcpServerCallbacks;
-import android.net.ip.IIpClientCallbacks;
-import android.net.ip.IpClient;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.SharedLog;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.connectivity.NetworkMonitor;
-import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Android service used to start the network stack when bound to via an intent.
- *
- * <p>The service returns a binder for the system server to communicate with the network stack.
- */
-public class NetworkStackService extends Service {
-    private static final String TAG = NetworkStackService.class.getSimpleName();
-    private static NetworkStackConnector sConnector;
-
-    /**
-     * Create a binder connector for the system server to communicate with the network stack.
-     *
-     * <p>On platforms where the network stack runs in the system server process, this method may
-     * be called directly instead of obtaining the connector by binding to the service.
-     */
-    public static synchronized IBinder makeConnector(Context context) {
-        if (sConnector == null) {
-            sConnector = new NetworkStackConnector(context);
-        }
-        return sConnector;
-    }
-
-    @NonNull
-    @Override
-    public IBinder onBind(Intent intent) {
-        return makeConnector(this);
-    }
-
-    /**
-     * An interface for internal clients of the network stack service that can return
-     * or create inline instances of the service it manages.
-     */
-    public interface NetworkStackServiceManager {
-        /**
-         * Get an instance of the IpMemoryStoreService.
-         */
-        IIpMemoryStore getIpMemoryStoreService();
-    }
-
-    private static class NetworkStackConnector extends INetworkStackConnector.Stub
-            implements NetworkStackServiceManager {
-        private static final int NUM_VALIDATION_LOG_LINES = 20;
-        private final Context mContext;
-        private final INetd mNetd;
-        private final NetworkObserverRegistry mObserverRegistry;
-        private final ConnectivityManager mCm;
-        @GuardedBy("mIpClients")
-        private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
-        private final IpMemoryStoreService mIpMemoryStoreService;
-
-        private static final int MAX_VALIDATION_LOGS = 10;
-        @GuardedBy("mValidationLogs")
-        private final ArrayDeque<SharedLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
-
-        private static final int VERSION_UNKNOWN = 0;
-        private static final String DUMPSYS_ARG_VERSION = "version";
-
-        /** Version of the AIDL interfaces observed on the system */
-        private final AtomicInteger mSystemAidlVersion = new AtomicInteger(VERSION_UNKNOWN);
-
-        /** Whether different versions have been observed on interfaces provided by the system */
-        private volatile boolean mConflictingSystemAidlVersions = false;
-
-        private SharedLog addValidationLogs(Network network, String name) {
-            final SharedLog log = new SharedLog(NUM_VALIDATION_LOG_LINES, network + " - " + name);
-            synchronized (mValidationLogs) {
-                while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
-                    mValidationLogs.removeLast();
-                }
-                mValidationLogs.addFirst(log);
-            }
-            return log;
-        }
-
-        NetworkStackConnector(Context context) {
-            mContext = context;
-            mNetd = INetd.Stub.asInterface(
-                    (IBinder) context.getSystemService(Context.NETD_SERVICE));
-            mObserverRegistry = new NetworkObserverRegistry();
-            mCm = context.getSystemService(ConnectivityManager.class);
-            mIpMemoryStoreService = new IpMemoryStoreService(context);
-
-            try {
-                mObserverRegistry.register(mNetd);
-            } catch (RemoteException e) {
-                mLog.e("Error registering observer on Netd", e);
-            }
-        }
-
-        private void updateSystemAidlVersion(final int version) {
-            final int previousVersion = mSystemAidlVersion.getAndSet(version);
-            if (previousVersion != VERSION_UNKNOWN && previousVersion != version) {
-                mConflictingSystemAidlVersions = true;
-            }
-        }
-
-        @NonNull
-        private final SharedLog mLog = new SharedLog(TAG);
-
-        @Override
-        public void makeDhcpServer(@NonNull String ifName, @NonNull DhcpServingParamsParcel params,
-                @NonNull IDhcpServerCallbacks cb) throws RemoteException {
-            checkNetworkStackCallingPermission();
-            updateSystemAidlVersion(cb.getInterfaceVersion());
-            final DhcpServer server;
-            try {
-                server = new DhcpServer(
-                        ifName,
-                        DhcpServingParams.fromParcelableObject(params),
-                        mLog.forSubComponent(ifName + ".DHCP"));
-            } catch (DhcpServingParams.InvalidParameterException e) {
-                mLog.e("Invalid DhcpServingParams", e);
-                cb.onDhcpServerCreated(STATUS_INVALID_ARGUMENT, null);
-                return;
-            } catch (Exception e) {
-                mLog.e("Unknown error starting DhcpServer", e);
-                cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
-                return;
-            }
-            cb.onDhcpServerCreated(STATUS_SUCCESS, server);
-        }
-
-        @Override
-        public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb)
-                throws RemoteException {
-            updateSystemAidlVersion(cb.getInterfaceVersion());
-            final SharedLog log = addValidationLogs(network, name);
-            final NetworkMonitor nm = new NetworkMonitor(mContext, cb, network, log);
-            cb.onNetworkMonitorCreated(new NetworkMonitorImpl(nm));
-        }
-
-        @Override
-        public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
-            updateSystemAidlVersion(cb.getInterfaceVersion());
-            final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry, this);
-
-            synchronized (mIpClients) {
-                final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
-                while (it.hasNext()) {
-                    final IpClient ipc = it.next().get();
-                    if (ipc == null) {
-                        it.remove();
-                    }
-                }
-                mIpClients.add(new WeakReference<>(ipClient));
-            }
-
-            cb.onIpClientCreated(ipClient.makeConnector());
-        }
-
-        @Override
-        public IIpMemoryStore getIpMemoryStoreService() {
-            return mIpMemoryStoreService;
-        }
-
-        @Override
-        public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb)
-                throws RemoteException {
-            updateSystemAidlVersion(cb.getInterfaceVersion());
-            cb.onIpMemoryStoreFetched(mIpMemoryStoreService);
-        }
-
-        @Override
-        protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
-                @Nullable String[] args) {
-            checkDumpPermission();
-            if (args != null && args.length >= 1 && DUMPSYS_ARG_VERSION.equals(args[0])) {
-                dumpVersion(fout);
-                return;
-            }
-
-            final IndentingPrintWriter pw = new IndentingPrintWriter(fout, "  ");
-            pw.println("NetworkStack logs:");
-            mLog.dump(fd, pw, args);
-
-            // Dump full IpClient logs for non-GCed clients
-            pw.println();
-            pw.println("Recently active IpClient logs:");
-            final ArrayList<IpClient> ipClients = new ArrayList<>();
-            final HashSet<String> dumpedIpClientIfaces = new HashSet<>();
-            synchronized (mIpClients) {
-                for (WeakReference<IpClient> ipcRef : mIpClients) {
-                    final IpClient ipc = ipcRef.get();
-                    if (ipc != null) {
-                        ipClients.add(ipc);
-                    }
-                }
-            }
-
-            for (IpClient ipc : ipClients) {
-                pw.println(ipc.getName());
-                pw.increaseIndent();
-                ipc.dump(fd, pw, args);
-                pw.decreaseIndent();
-                dumpedIpClientIfaces.add(ipc.getInterfaceName());
-            }
-
-            // State machine and connectivity metrics logs are kept for GCed IpClients
-            pw.println();
-            pw.println("Other IpClient logs:");
-            IpClient.dumpAllLogs(fout, dumpedIpClientIfaces);
-
-            pw.println();
-            pw.println("Validation logs (most recent first):");
-            synchronized (mValidationLogs) {
-                for (SharedLog p : mValidationLogs) {
-                    pw.println(p.getTag());
-                    pw.increaseIndent();
-                    p.dump(fd, pw, args);
-                    pw.decreaseIndent();
-                }
-            }
-        }
-
-        /**
-         * Dump version information of the module and detected system version.
-         */
-        private void dumpVersion(@NonNull PrintWriter fout) {
-            fout.println("NetworkStackConnector: " + this.VERSION);
-            fout.println("SystemServer: " + mSystemAidlVersion);
-            fout.println("SystemServerConflicts: " + mConflictingSystemAidlVersions);
-        }
-
-        @Override
-        public int getInterfaceVersion() {
-            return this.VERSION;
-        }
-    }
-
-    private static class NetworkMonitorImpl extends INetworkMonitor.Stub {
-        private final NetworkMonitor mNm;
-
-        NetworkMonitorImpl(NetworkMonitor nm) {
-            mNm = nm;
-        }
-
-        @Override
-        public void start() {
-            checkNetworkStackCallingPermission();
-            mNm.start();
-        }
-
-        @Override
-        public void launchCaptivePortalApp() {
-            checkNetworkStackCallingPermission();
-            mNm.launchCaptivePortalApp();
-        }
-
-        @Override
-        public void notifyCaptivePortalAppFinished(int response) {
-            checkNetworkStackCallingPermission();
-            mNm.notifyCaptivePortalAppFinished(response);
-        }
-
-        @Override
-        public void setAcceptPartialConnectivity() {
-            checkNetworkStackCallingPermission();
-            mNm.setAcceptPartialConnectivity();
-        }
-
-        @Override
-        public void forceReevaluation(int uid) {
-            checkNetworkStackCallingPermission();
-            mNm.forceReevaluation(uid);
-        }
-
-        @Override
-        public void notifyPrivateDnsChanged(PrivateDnsConfigParcel config) {
-            checkNetworkStackCallingPermission();
-            mNm.notifyPrivateDnsSettingsChanged(PrivateDnsConfig.fromParcel(config));
-        }
-
-        @Override
-        public void notifyDnsResponse(int returnCode) {
-            checkNetworkStackCallingPermission();
-            mNm.notifyDnsResponse(returnCode);
-        }
-
-        @Override
-        public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) {
-            checkNetworkStackCallingPermission();
-            mNm.notifyNetworkConnected(lp, nc);
-        }
-
-        @Override
-        public void notifyNetworkDisconnected() {
-            checkNetworkStackCallingPermission();
-            mNm.notifyNetworkDisconnected();
-        }
-
-        @Override
-        public void notifyLinkPropertiesChanged(LinkProperties lp) {
-            checkNetworkStackCallingPermission();
-            mNm.notifyLinkPropertiesChanged(lp);
-        }
-
-        @Override
-        public void notifyNetworkCapabilitiesChanged(NetworkCapabilities nc) {
-            checkNetworkStackCallingPermission();
-            mNm.notifyNetworkCapabilitiesChanged(nc);
-        }
-
-        @Override
-        public int getInterfaceVersion() {
-            return this.VERSION;
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
deleted file mode 100644
index 4e40ba4..0000000
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ /dev/null
@@ -1,2143 +0,0 @@
-/*
- * Copyright (C) 2014 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.connectivity;
-
-import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
-import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
-import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
-import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
-import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.DnsResolver.FLAG_EMPTY;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.captiveportal.CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs;
-import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
-import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
-import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
-import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
-import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
-import static android.net.util.DataStallUtils.DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
-import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_EVALUATION_TYPES;
-import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
-import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
-import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_URL;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_HTTPS_URL;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_HTTP_URL;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE_IGNORE;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE_PROMPT;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USER_AGENT;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
-import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
-import static android.net.util.NetworkStackUtils.isEmpty;
-
-import static com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.DnsResolver;
-import android.net.INetworkMonitorCallbacks;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.ProxyInfo;
-import android.net.TrafficStats;
-import android.net.Uri;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.captiveportal.CaptivePortalProbeSpec;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.NetworkEvent;
-import android.net.metrics.ValidationProbeEvent;
-import android.net.shared.NetworkMonitorUtils;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.NetworkStackUtils;
-import android.net.util.SharedLog;
-import android.net.util.Stopwatch;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telephony.AccessNetworkConstants;
-import android.telephony.CellSignalStrength;
-import android.telephony.NetworkRegistrationInfo;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import androidx.annotation.ArrayRes;
-import androidx.annotation.StringRes;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.RingBufferIndices;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.internal.util.TrafficStatsConstants;
-import com.android.networkstack.R;
-import com.android.networkstack.metrics.DataStallDetectionStats;
-import com.android.networkstack.metrics.DataStallStatsUtils;
-import com.android.networkstack.util.DnsUtils;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Random;
-import java.util.UUID;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-
-/**
- * {@hide}
- */
-public class NetworkMonitor extends StateMachine {
-    private static final String TAG = NetworkMonitor.class.getSimpleName();
-    private static final boolean DBG  = true;
-    private static final boolean VDBG = false;
-    private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
-    private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
-                                                      + "AppleWebKit/537.36 (KHTML, like Gecko) "
-                                                      + "Chrome/60.0.3112.32 Safari/537.36";
-
-    @VisibleForTesting
-    static final String CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT =
-            "captive_portal_dns_probe_timeout";
-
-    private static final int SOCKET_TIMEOUT_MS = 10000;
-    private static final int PROBE_TIMEOUT_MS  = 3000;
-
-    enum EvaluationResult {
-        VALIDATED(true),
-        CAPTIVE_PORTAL(false);
-        final boolean mIsValidated;
-        EvaluationResult(boolean isValidated) {
-            this.mIsValidated = isValidated;
-        }
-    }
-
-    enum ValidationStage {
-        FIRST_VALIDATION(true),
-        REVALIDATION(false);
-        final boolean mIsFirstValidation;
-        ValidationStage(boolean isFirstValidation) {
-            this.mIsFirstValidation = isFirstValidation;
-        }
-    }
-
-    /**
-     * ConnectivityService has sent a notification to indicate that network has connected.
-     * Initiates Network Validation.
-     */
-    private static final int CMD_NETWORK_CONNECTED = 1;
-
-    /**
-     * Message to self indicating it's time to evaluate a network's connectivity.
-     * arg1 = Token to ignore old messages.
-     */
-    private static final int CMD_REEVALUATE = 6;
-
-    /**
-     * ConnectivityService has sent a notification to indicate that network has disconnected.
-     */
-    private static final int CMD_NETWORK_DISCONNECTED = 7;
-
-    /**
-     * Force evaluation even if it has succeeded in the past.
-     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
-     */
-    private static final int CMD_FORCE_REEVALUATION = 8;
-
-    /**
-     * Message to self indicating captive portal app finished.
-     * arg1 = one of: APP_RETURN_DISMISSED,
-     *                APP_RETURN_UNWANTED,
-     *                APP_RETURN_WANTED_AS_IS
-     * obj = mCaptivePortalLoggedInResponseToken as String
-     */
-    private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = 9;
-
-    /**
-     * Message indicating sign-in app should be launched.
-     * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the
-     * user touches the sign in notification, or sent by
-     * ConnectivityService when the user touches the "sign into
-     * network" button in the wifi access point detail page.
-     */
-    private static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = 11;
-
-    /**
-     * Retest network to see if captive portal is still in place.
-     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
-     *        0 indicates self-initiated, so nobody to blame.
-     */
-    private static final int CMD_CAPTIVE_PORTAL_RECHECK = 12;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor of settings changes to
-     * Private DNS. If a DNS resolution is required, e.g. for DNS-over-TLS in
-     * strict mode, then an event is sent back to ConnectivityService with the
-     * result of the resolution attempt.
-     *
-     * A separate message is used to trigger (re)evaluation of the Private DNS
-     * configuration, so that the message can be handled as needed in different
-     * states, including being ignored until after an ongoing captive portal
-     * validation phase is completed.
-     */
-    private static final int CMD_PRIVATE_DNS_SETTINGS_CHANGED = 13;
-    private static final int CMD_EVALUATE_PRIVATE_DNS = 15;
-
-    /**
-     * Message to self indicating captive portal detection is completed.
-     * obj = CaptivePortalProbeResult for detection result;
-     */
-    private static final int CMD_PROBE_COMPLETE = 16;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor of DNS query responses event.
-     * arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query.
-     */
-    private static final int EVENT_DNS_NOTIFICATION = 17;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
-     * NetworkMonitor should ignore the https probe.
-     */
-    private static final int EVENT_ACCEPT_PARTIAL_CONNECTIVITY = 18;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor of changed LinkProperties.
-     * obj = new LinkProperties.
-     */
-    private static final int EVENT_LINK_PROPERTIES_CHANGED = 19;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor of changed NetworkCapabilities.
-     * obj = new NetworkCapabilities.
-     */
-    private static final int EVENT_NETWORK_CAPABILITIES_CHANGED = 20;
-
-    // Start mReevaluateDelayMs at this value and double.
-    private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
-    private static final int MAX_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
-    // Before network has been evaluated this many times, ignore repeated reevaluate requests.
-    private static final int IGNORE_REEVALUATE_ATTEMPTS = 5;
-    private int mReevaluateToken = 0;
-    private static final int NO_UID = 0;
-    private static final int INVALID_UID = -1;
-    private int mUidResponsibleForReeval = INVALID_UID;
-    // Stop blaming UID that requested re-evaluation after this many attempts.
-    private static final int BLAME_FOR_EVALUATION_ATTEMPTS = 5;
-    // Delay between reevaluations once a captive portal has been found.
-    private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
-    private static final int NETWORK_VALIDATION_RESULT_INVALID = 0;
-    private String mPrivateDnsProviderHostname = "";
-
-    private final Context mContext;
-    private final INetworkMonitorCallbacks mCallback;
-    private final Network mCleartextDnsNetwork;
-    private final Network mNetwork;
-    private final TelephonyManager mTelephonyManager;
-    private final WifiManager mWifiManager;
-    private final ConnectivityManager mCm;
-    private final IpConnectivityLog mMetricsLog;
-    private final Dependencies mDependencies;
-    private final DataStallStatsUtils mDetectionStatsUtils;
-
-    // Configuration values for captive portal detection probes.
-    private final String mCaptivePortalUserAgent;
-    private final URL mCaptivePortalHttpsUrl;
-    private final URL mCaptivePortalHttpUrl;
-    private final URL[] mCaptivePortalFallbackUrls;
-    @Nullable
-    private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;
-
-    private NetworkCapabilities mNetworkCapabilities;
-    private LinkProperties mLinkProperties;
-
-    @VisibleForTesting
-    protected boolean mIsCaptivePortalCheckEnabled;
-
-    private boolean mUseHttps;
-    // The total number of captive portal detection attempts for this NetworkMonitor instance.
-    private int mValidations = 0;
-
-    // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
-    private boolean mUserDoesNotWant = false;
-    // Avoids surfacing "Sign in to network" notification.
-    private boolean mDontDisplaySigninNotification = false;
-
-    private final State mDefaultState = new DefaultState();
-    private final State mValidatedState = new ValidatedState();
-    private final State mMaybeNotifyState = new MaybeNotifyState();
-    private final State mEvaluatingState = new EvaluatingState();
-    private final State mCaptivePortalState = new CaptivePortalState();
-    private final State mEvaluatingPrivateDnsState = new EvaluatingPrivateDnsState();
-    private final State mProbingState = new ProbingState();
-    private final State mWaitingForNextProbeState = new WaitingForNextProbeState();
-
-    private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
-
-    private final SharedLog mValidationLogs;
-
-    private final Stopwatch mEvaluationTimer = new Stopwatch();
-
-    // This variable is set before transitioning to the mCaptivePortalState.
-    private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
-
-    // Random generator to select fallback URL index
-    private final Random mRandom;
-    private int mNextFallbackUrlIndex = 0;
-
-
-    private int mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
-    private int mEvaluateAttempts = 0;
-    private volatile int mProbeToken = 0;
-    private final int mConsecutiveDnsTimeoutThreshold;
-    private final int mDataStallMinEvaluateTime;
-    private final int mDataStallValidDnsTimeThreshold;
-    private final int mDataStallEvaluationType;
-    private final DnsStallDetector mDnsStallDetector;
-    private long mLastProbeTime;
-    // Set to true if data stall is suspected and reset to false after metrics are sent to statsd.
-    private boolean mCollectDataStallMetrics;
-    private boolean mAcceptPartialConnectivity = false;
-    private final EvaluationState mEvaluationState = new EvaluationState();
-
-    public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
-            SharedLog validationLog) {
-        this(context, cb, network, new IpConnectivityLog(), validationLog,
-                Dependencies.DEFAULT, new DataStallStatsUtils());
-    }
-
-    @VisibleForTesting
-    protected NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
-            IpConnectivityLog logger, SharedLog validationLogs,
-            Dependencies deps, DataStallStatsUtils detectionStatsUtils) {
-        // Add suffix indicating which NetworkMonitor we're talking about.
-        super(TAG + "/" + network.toString());
-
-        // Logs with a tag of the form given just above, e.g.
-        //     <timestamp>   862  2402 D NetworkMonitor/NetworkAgentInfo [WIFI () - 100]: ...
-        setDbg(VDBG);
-
-        mContext = context;
-        mMetricsLog = logger;
-        mValidationLogs = validationLogs;
-        mCallback = cb;
-        mDependencies = deps;
-        mDetectionStatsUtils = detectionStatsUtils;
-        mNetwork = network;
-        mCleartextDnsNetwork = deps.getPrivateDnsBypassNetwork(network);
-        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
-
-        // CHECKSTYLE:OFF IndentationCheck
-        addState(mDefaultState);
-        addState(mMaybeNotifyState, mDefaultState);
-            addState(mEvaluatingState, mMaybeNotifyState);
-                addState(mProbingState, mEvaluatingState);
-                addState(mWaitingForNextProbeState, mEvaluatingState);
-            addState(mCaptivePortalState, mMaybeNotifyState);
-        addState(mEvaluatingPrivateDnsState, mDefaultState);
-        addState(mValidatedState, mDefaultState);
-        setInitialState(mDefaultState);
-        // CHECKSTYLE:ON IndentationCheck
-
-        mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
-        mUseHttps = getUseHttpsValidation();
-        mCaptivePortalUserAgent = getCaptivePortalUserAgent();
-        mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
-        mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl());
-        mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
-        mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
-        mRandom = deps.getRandom();
-        // TODO: Evaluate to move data stall configuration to a specific class.
-        mConsecutiveDnsTimeoutThreshold = getConsecutiveDnsTimeoutThreshold();
-        mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold);
-        mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
-        mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
-        mDataStallEvaluationType = getDataStallEvaluationType();
-
-        // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
-        // even before notifyNetworkConnected.
-        mLinkProperties = new LinkProperties();
-        mNetworkCapabilities = new NetworkCapabilities(null);
-    }
-
-    /**
-     * ConnectivityService notifies NetworkMonitor that the user already accepted partial
-     * connectivity previously, so NetworkMonitor can validate the network even if it has partial
-     * connectivity.
-     */
-    public void setAcceptPartialConnectivity() {
-        sendMessage(EVENT_ACCEPT_PARTIAL_CONNECTIVITY);
-    }
-
-    /**
-     * Request the NetworkMonitor to reevaluate the network.
-     */
-    public void forceReevaluation(int responsibleUid) {
-        sendMessage(CMD_FORCE_REEVALUATION, responsibleUid, 0);
-    }
-
-    /**
-     * Send a notification to NetworkMonitor indicating that there was a DNS query response event.
-     * @param returnCode the DNS return code of the response.
-     */
-    public void notifyDnsResponse(int returnCode) {
-        sendMessage(EVENT_DNS_NOTIFICATION, returnCode);
-    }
-
-    /**
-     * Send a notification to NetworkMonitor indicating that private DNS settings have changed.
-     * @param newCfg The new private DNS configuration.
-     */
-    public void notifyPrivateDnsSettingsChanged(PrivateDnsConfig newCfg) {
-        // Cancel any outstanding resolutions.
-        removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED);
-        // Send the update to the proper thread.
-        sendMessage(CMD_PRIVATE_DNS_SETTINGS_CHANGED, newCfg);
-    }
-
-    /**
-     * Send a notification to NetworkMonitor indicating that the network is now connected.
-     */
-    public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) {
-        sendMessage(CMD_NETWORK_CONNECTED, new Pair<>(
-                new LinkProperties(lp), new NetworkCapabilities(nc)));
-    }
-
-    private void updateConnectedNetworkAttributes(Message connectedMsg) {
-        final Pair<LinkProperties, NetworkCapabilities> attrs =
-                (Pair<LinkProperties, NetworkCapabilities>) connectedMsg.obj;
-        mLinkProperties = attrs.first;
-        mNetworkCapabilities = attrs.second;
-    }
-
-    /**
-     * Send a notification to NetworkMonitor indicating that the network is now disconnected.
-     */
-    public void notifyNetworkDisconnected() {
-        sendMessage(CMD_NETWORK_DISCONNECTED);
-    }
-
-    /**
-     * Send a notification to NetworkMonitor indicating that link properties have changed.
-     */
-    public void notifyLinkPropertiesChanged(final LinkProperties lp) {
-        sendMessage(EVENT_LINK_PROPERTIES_CHANGED, new LinkProperties(lp));
-    }
-
-    /**
-     * Send a notification to NetworkMonitor indicating that network capabilities have changed.
-     */
-    public void notifyNetworkCapabilitiesChanged(final NetworkCapabilities nc) {
-        sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, new NetworkCapabilities(nc));
-    }
-
-    /**
-     * Request the captive portal application to be launched.
-     */
-    public void launchCaptivePortalApp() {
-        sendMessage(CMD_LAUNCH_CAPTIVE_PORTAL_APP);
-    }
-
-    /**
-     * Notify that the captive portal app was closed with the provided response code.
-     */
-    public void notifyCaptivePortalAppFinished(int response) {
-        sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
-    }
-
-    @Override
-    protected void log(String s) {
-        if (DBG) Log.d(TAG + "/" + mCleartextDnsNetwork.toString(), s);
-    }
-
-    private void validationLog(int probeType, Object url, String msg) {
-        String probeName = ValidationProbeEvent.getProbeName(probeType);
-        validationLog(String.format("%s %s %s", probeName, url, msg));
-    }
-
-    private void validationLog(String s) {
-        if (DBG) log(s);
-        mValidationLogs.log(s);
-    }
-
-    private ValidationStage validationStage() {
-        return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION;
-    }
-
-    private boolean isValidationRequired() {
-        return NetworkMonitorUtils.isValidationRequired(mNetworkCapabilities);
-    }
-
-    private boolean isPrivateDnsValidationRequired() {
-        return NetworkMonitorUtils.isPrivateDnsValidationRequired(mNetworkCapabilities);
-    }
-
-    private void notifyNetworkTested(int result, @Nullable String redirectUrl) {
-        try {
-            mCallback.notifyNetworkTested(result, redirectUrl);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error sending network test result", e);
-        }
-    }
-
-    private void showProvisioningNotification(String action) {
-        try {
-            mCallback.showProvisioningNotification(action, mContext.getPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error showing provisioning notification", e);
-        }
-    }
-
-    private void hideProvisioningNotification() {
-        try {
-            mCallback.hideProvisioningNotification();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error hiding provisioning notification", e);
-        }
-    }
-
-    // DefaultState is the parent of all States.  It exists only to handle CMD_* messages but
-    // does not entail any real state (hence no enter() or exit() routines).
-    private class DefaultState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_NETWORK_CONNECTED:
-                    updateConnectedNetworkAttributes(message);
-                    logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
-                    transitionTo(mEvaluatingState);
-                    return HANDLED;
-                case CMD_NETWORK_DISCONNECTED:
-                    logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED);
-                    quit();
-                    return HANDLED;
-                case CMD_FORCE_REEVALUATION:
-                case CMD_CAPTIVE_PORTAL_RECHECK:
-                    final int dnsCount = mDnsStallDetector.getConsecutiveTimeoutCount();
-                    validationLog("Forcing reevaluation for UID " + message.arg1
-                            + ". Dns signal count: " + dnsCount);
-                    mUidResponsibleForReeval = message.arg1;
-                    transitionTo(mEvaluatingState);
-                    return HANDLED;
-                case CMD_CAPTIVE_PORTAL_APP_FINISHED:
-                    log("CaptivePortal App responded with " + message.arg1);
-
-                    // If the user has seen and acted on a captive portal notification, and the
-                    // captive portal app is now closed, disable HTTPS probes. This avoids the
-                    // following pathological situation:
-                    //
-                    // 1. HTTP probe returns a captive portal, HTTPS probe fails or times out.
-                    // 2. User opens the app and logs into the captive portal.
-                    // 3. HTTP starts working, but HTTPS still doesn't work for some other reason -
-                    //    perhaps due to the network blocking HTTPS?
-                    //
-                    // In this case, we'll fail to validate the network even after the app is
-                    // dismissed. There is now no way to use this network, because the app is now
-                    // gone, so the user cannot select "Use this network as is".
-                    mUseHttps = false;
-
-                    switch (message.arg1) {
-                        case APP_RETURN_DISMISSED:
-                            sendMessage(CMD_FORCE_REEVALUATION, NO_UID, 0);
-                            break;
-                        case APP_RETURN_WANTED_AS_IS:
-                            mDontDisplaySigninNotification = true;
-                            // TODO: Distinguish this from a network that actually validates.
-                            // Displaying the "x" on the system UI icon may still be a good idea.
-                            transitionTo(mEvaluatingPrivateDnsState);
-                            break;
-                        case APP_RETURN_UNWANTED:
-                            mDontDisplaySigninNotification = true;
-                            mUserDoesNotWant = true;
-                            mEvaluationState.reportEvaluationResult(
-                                    NETWORK_VALIDATION_RESULT_INVALID, null);
-                            // TODO: Should teardown network.
-                            mUidResponsibleForReeval = 0;
-                            transitionTo(mEvaluatingState);
-                            break;
-                    }
-                    return HANDLED;
-                case CMD_PRIVATE_DNS_SETTINGS_CHANGED: {
-                    final PrivateDnsConfig cfg = (PrivateDnsConfig) message.obj;
-                    if (!isPrivateDnsValidationRequired() || cfg == null || !cfg.inStrictMode()) {
-                        // No DNS resolution required.
-                        //
-                        // We don't force any validation in opportunistic mode
-                        // here. Opportunistic mode nameservers are validated
-                        // separately within netd.
-                        //
-                        // Reset Private DNS settings state.
-                        mPrivateDnsProviderHostname = "";
-                        break;
-                    }
-
-                    mPrivateDnsProviderHostname = cfg.hostname;
-
-                    // DNS resolutions via Private DNS strict mode block for a
-                    // few seconds (~4.2) checking for any IP addresses to
-                    // arrive and validate. Initiating a (re)evaluation now
-                    // should not significantly alter the validation outcome.
-                    //
-                    // No matter what: enqueue a validation request; one of
-                    // three things can happen with this request:
-                    //     [1] ignored (EvaluatingState or CaptivePortalState)
-                    //     [2] transition to EvaluatingPrivateDnsState
-                    //         (DefaultState and ValidatedState)
-                    //     [3] handled (EvaluatingPrivateDnsState)
-                    //
-                    // The Private DNS configuration to be evaluated will:
-                    //     [1] be skipped (not in strict mode), or
-                    //     [2] validate (huzzah), or
-                    //     [3] encounter some problem (invalid hostname,
-                    //         no resolved IP addresses, IPs unreachable,
-                    //         port 853 unreachable, port 853 is not running a
-                    //         DNS-over-TLS server, et cetera).
-                    sendMessage(CMD_EVALUATE_PRIVATE_DNS);
-                    break;
-                }
-                case EVENT_DNS_NOTIFICATION:
-                    mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
-                    break;
-                // Set mAcceptPartialConnectivity to true and if network start evaluating or
-                // re-evaluating and get the result of partial connectivity, ProbingState will
-                // disable HTTPS probe and transition to EvaluatingPrivateDnsState.
-                case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
-                    maybeDisableHttpsProbing(true /* acceptPartial */);
-                    break;
-                case EVENT_LINK_PROPERTIES_CHANGED:
-                    mLinkProperties = (LinkProperties) message.obj;
-                    break;
-                case EVENT_NETWORK_CAPABILITIES_CHANGED:
-                    mNetworkCapabilities = (NetworkCapabilities) message.obj;
-                    break;
-                default:
-                    break;
-            }
-            return HANDLED;
-        }
-    }
-
-    // Being in the ValidatedState State indicates a Network is:
-    // - Successfully validated, or
-    // - Wanted "as is" by the user, or
-    // - Does not satisfy the default NetworkRequest and so validation has been skipped.
-    private class ValidatedState extends State {
-        @Override
-        public void enter() {
-            maybeLogEvaluationResult(
-                    networkEventType(validationStage(), EvaluationResult.VALIDATED));
-            // If the user has accepted partial connectivity and HTTPS probing is disabled, then
-            // mark the network as validated and partial so that settings can keep informing the
-            // user that the connection is limited.
-            int result = NETWORK_VALIDATION_RESULT_VALID;
-            if (!mUseHttps && mAcceptPartialConnectivity) {
-                result |= NETWORK_VALIDATION_RESULT_PARTIAL;
-            }
-            mEvaluationState.reportEvaluationResult(result, null /* redirectUrl */);
-            mValidations++;
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_NETWORK_CONNECTED:
-                    updateConnectedNetworkAttributes(message);
-                    transitionTo(mValidatedState);
-                    break;
-                case CMD_EVALUATE_PRIVATE_DNS:
-                    transitionTo(mEvaluatingPrivateDnsState);
-                    break;
-                case EVENT_DNS_NOTIFICATION:
-                    mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
-                    if (isDataStall()) {
-                        mCollectDataStallMetrics = true;
-                        validationLog("Suspecting data stall, reevaluate");
-                        transitionTo(mEvaluatingState);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    private void writeDataStallStats(@NonNull final CaptivePortalProbeResult result) {
-        /*
-         * Collect data stall detection level information for each transport type. Collect type
-         * specific information for cellular and wifi only currently. Generate
-         * DataStallDetectionStats for each transport type. E.g., if a network supports both
-         * TRANSPORT_WIFI and TRANSPORT_VPN, two DataStallDetectionStats will be generated.
-         */
-        final int[] transports = mNetworkCapabilities.getTransportTypes();
-
-        for (int i = 0; i < transports.length; i++) {
-            DataStallStatsUtils.write(buildDataStallDetectionStats(transports[i]), result);
-        }
-        mCollectDataStallMetrics = false;
-    }
-
-    @VisibleForTesting
-    protected DataStallDetectionStats buildDataStallDetectionStats(int transport) {
-        final DataStallDetectionStats.Builder stats = new DataStallDetectionStats.Builder();
-        if (VDBG_STALL) log("collectDataStallMetrics: type=" + transport);
-        stats.setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
-        stats.setNetworkType(transport);
-        switch (transport) {
-            case NetworkCapabilities.TRANSPORT_WIFI:
-                // TODO: Update it if status query in dual wifi is supported.
-                final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-                stats.setWiFiData(wifiInfo);
-                break;
-            case NetworkCapabilities.TRANSPORT_CELLULAR:
-                final boolean isRoaming = !mNetworkCapabilities.hasCapability(
-                        NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
-                final SignalStrength ss = mTelephonyManager.getSignalStrength();
-                // TODO(b/120452078): Support multi-sim.
-                stats.setCellData(
-                        mTelephonyManager.getDataNetworkType(),
-                        isRoaming,
-                        mTelephonyManager.getNetworkOperator(),
-                        mTelephonyManager.getSimOperator(),
-                        (ss != null)
-                        ? ss.getLevel() : CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
-                break;
-            default:
-                // No transport type specific information for the other types.
-                break;
-        }
-        addDnsEvents(stats);
-
-        return stats.build();
-    }
-
-    @VisibleForTesting
-    protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
-        final int size = mDnsStallDetector.mResultIndices.size();
-        for (int i = 1; i <= DEFAULT_DNS_LOG_SIZE && i <= size; i++) {
-            final int index = mDnsStallDetector.mResultIndices.indexOf(size - i);
-            stats.addDnsEvent(mDnsStallDetector.mDnsEvents[index].mReturnCode,
-                    mDnsStallDetector.mDnsEvents[index].mTimeStamp);
-        }
-    }
-
-
-    // Being in the MaybeNotifyState State indicates the user may have been notified that sign-in
-    // is required.  This State takes care to clear the notification upon exit from the State.
-    private class MaybeNotifyState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_LAUNCH_CAPTIVE_PORTAL_APP:
-                    final Bundle appExtras = new Bundle();
-                    // OneAddressPerFamilyNetwork is not parcelable across processes.
-                    final Network network = new Network(mCleartextDnsNetwork);
-                    appExtras.putParcelable(ConnectivityManager.EXTRA_NETWORK, network);
-                    final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
-                    appExtras.putString(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
-                    if (probeRes.probeSpec != null) {
-                        final String encodedSpec = probeRes.probeSpec.getEncodedSpec();
-                        appExtras.putString(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
-                    }
-                    appExtras.putString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
-                            mCaptivePortalUserAgent);
-                    mCm.startCaptivePortalApp(network, appExtras);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
-                mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
-                mLaunchCaptivePortalAppBroadcastReceiver = null;
-            }
-            hideProvisioningNotification();
-        }
-    }
-
-    // Being in the EvaluatingState State indicates the Network is being evaluated for internet
-    // connectivity, or that the user has indicated that this network is unwanted.
-    private class EvaluatingState extends State {
-        @Override
-        public void enter() {
-            // If we have already started to track time spent in EvaluatingState
-            // don't reset the timer due simply to, say, commands or events that
-            // cause us to exit and re-enter EvaluatingState.
-            if (!mEvaluationTimer.isStarted()) {
-                mEvaluationTimer.start();
-            }
-            sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
-            if (mUidResponsibleForReeval != INVALID_UID) {
-                TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
-                mUidResponsibleForReeval = INVALID_UID;
-            }
-            mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
-            mEvaluateAttempts = 0;
-            // Reset all current probe results to zero, but retain current validation state until
-            // validation succeeds or fails.
-            mEvaluationState.clearProbeResults();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_REEVALUATE:
-                    if (message.arg1 != mReevaluateToken || mUserDoesNotWant) {
-                        return HANDLED;
-                    }
-                    // Don't bother validating networks that don't satisfy the default request.
-                    // This includes:
-                    //  - VPNs which can be considered explicitly desired by the user and the
-                    //    user's desire trumps whether the network validates.
-                    //  - Networks that don't provide Internet access.  It's unclear how to
-                    //    validate such networks.
-                    //  - Untrusted networks.  It's unsafe to prompt the user to sign-in to
-                    //    such networks and the user didn't express interest in connecting to
-                    //    such networks (an app did) so the user may be unhappily surprised when
-                    //    asked to sign-in to a network they didn't want to connect to in the
-                    //    first place.  Validation could be done to adjust the network scores
-                    //    however these networks are app-requested and may not be intended for
-                    //    general usage, in which case general validation may not be an accurate
-                    //    measure of the network's quality.  Only the app knows how to evaluate
-                    //    the network so don't bother validating here.  Furthermore sending HTTP
-                    //    packets over the network may be undesirable, for example an extremely
-                    //    expensive metered network, or unwanted leaking of the User Agent string.
-                    //
-                    // On networks that need to support private DNS in strict mode (e.g., VPNs, but
-                    // not networks that don't provide Internet access), we still need to perform
-                    // private DNS server resolution.
-                    if (!isValidationRequired()) {
-                        if (isPrivateDnsValidationRequired()) {
-                            validationLog("Network would not satisfy default request, "
-                                    + "resolving private DNS");
-                            transitionTo(mEvaluatingPrivateDnsState);
-                        } else {
-                            validationLog("Network would not satisfy default request, "
-                                    + "not validating");
-                            transitionTo(mValidatedState);
-                        }
-                        return HANDLED;
-                    }
-                    mEvaluateAttempts++;
-
-                    transitionTo(mProbingState);
-                    return HANDLED;
-                case CMD_FORCE_REEVALUATION:
-                    // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
-                    // ignore any re-evaluation requests. After, restart the
-                    // evaluation process via EvaluatingState#enter.
-                    return (mEvaluateAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
-                // Disable HTTPS probe and transition to EvaluatingPrivateDnsState because:
-                // 1. Network is connected and finish the network validation.
-                // 2. NetworkMonitor detects network is partial connectivity and user accepts it.
-                case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
-                    maybeDisableHttpsProbing(true /* acceptPartial */);
-                    transitionTo(mEvaluatingPrivateDnsState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            TrafficStats.clearThreadStatsUid();
-        }
-    }
-
-    // BroadcastReceiver that waits for a particular Intent and then posts a message.
-    private class CustomIntentReceiver extends BroadcastReceiver {
-        private final int mToken;
-        private final int mWhat;
-        private final String mAction;
-        CustomIntentReceiver(String action, int token, int what) {
-            mToken = token;
-            mWhat = what;
-            mAction = action + "_" + mCleartextDnsNetwork.getNetworkHandle() + "_" + token;
-            mContext.registerReceiver(this, new IntentFilter(mAction));
-        }
-        public PendingIntent getPendingIntent() {
-            final Intent intent = new Intent(mAction);
-            intent.setPackage(mContext.getPackageName());
-            return PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        }
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(mAction)) sendMessage(obtainMessage(mWhat, mToken));
-        }
-    }
-
-    // Being in the CaptivePortalState State indicates a captive portal was detected and the user
-    // has been shown a notification to sign-in.
-    private class CaptivePortalState extends State {
-        private static final String ACTION_LAUNCH_CAPTIVE_PORTAL_APP =
-                "android.net.netmon.launchCaptivePortalApp";
-
-        @Override
-        public void enter() {
-            maybeLogEvaluationResult(
-                    networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL));
-            // Don't annoy user with sign-in notifications.
-            if (mDontDisplaySigninNotification) return;
-            // Create a CustomIntentReceiver that sends us a
-            // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user
-            // touches the notification.
-            if (mLaunchCaptivePortalAppBroadcastReceiver == null) {
-                // Wait for result.
-                mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver(
-                        ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(),
-                        CMD_LAUNCH_CAPTIVE_PORTAL_APP);
-                // Display the sign in notification.
-                // Only do this once for every time we enter MaybeNotifyState. b/122164725
-                showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction);
-            }
-            // Retest for captive portal occasionally.
-            sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
-                    CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
-            mValidations++;
-        }
-
-        @Override
-        public void exit() {
-            removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
-        }
-    }
-
-    private class EvaluatingPrivateDnsState extends State {
-        private int mPrivateDnsReevalDelayMs;
-        private PrivateDnsConfig mPrivateDnsConfig;
-
-        @Override
-        public void enter() {
-            mPrivateDnsReevalDelayMs = INITIAL_REEVALUATE_DELAY_MS;
-            mPrivateDnsConfig = null;
-            sendMessage(CMD_EVALUATE_PRIVATE_DNS);
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_EVALUATE_PRIVATE_DNS:
-                    if (inStrictMode()) {
-                        if (!isStrictModeHostnameResolved()) {
-                            resolveStrictModeHostname();
-
-                            if (isStrictModeHostnameResolved()) {
-                                notifyPrivateDnsConfigResolved();
-                            } else {
-                                handlePrivateDnsEvaluationFailure();
-                                break;
-                            }
-                        }
-
-                        // Look up a one-time hostname, to bypass caching.
-                        //
-                        // Note that this will race with ConnectivityService
-                        // code programming the DNS-over-TLS server IP addresses
-                        // into netd (if invoked, above). If netd doesn't know
-                        // the IP addresses yet, or if the connections to the IP
-                        // addresses haven't yet been validated, netd will block
-                        // for up to a few seconds before failing the lookup.
-                        if (!sendPrivateDnsProbe()) {
-                            handlePrivateDnsEvaluationFailure();
-                            break;
-                        }
-                    }
-
-                    // All good!
-                    transitionTo(mValidatedState);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-
-        private boolean inStrictMode() {
-            return !TextUtils.isEmpty(mPrivateDnsProviderHostname);
-        }
-
-        private boolean isStrictModeHostnameResolved() {
-            return (mPrivateDnsConfig != null)
-                    && mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname)
-                    && (mPrivateDnsConfig.ips.length > 0);
-        }
-
-        private void resolveStrictModeHostname() {
-            try {
-                // Do a blocking DNS resolution using the network-assigned nameservers.
-                final InetAddress[] ips = DnsUtils.getAllByName(mDependencies.getDnsResolver(),
-                        mCleartextDnsNetwork, mPrivateDnsProviderHostname, getDnsProbeTimeout());
-                mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips);
-                validationLog("Strict mode hostname resolved: " + mPrivateDnsConfig);
-            } catch (UnknownHostException uhe) {
-                mPrivateDnsConfig = null;
-                validationLog("Strict mode hostname resolution failed: " + uhe.getMessage());
-            }
-            mEvaluationState.reportProbeResult(NETWORK_VALIDATION_PROBE_PRIVDNS,
-                    (mPrivateDnsConfig != null) /* succeeded */);
-        }
-
-        private void notifyPrivateDnsConfigResolved() {
-            try {
-                mCallback.notifyPrivateDnsConfigResolved(mPrivateDnsConfig.toParcel());
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error sending private DNS config resolved notification", e);
-            }
-        }
-
-        private void handlePrivateDnsEvaluationFailure() {
-            mEvaluationState.reportEvaluationResult(NETWORK_VALIDATION_RESULT_INVALID,
-                    null /* redirectUrl */);
-            // Queue up a re-evaluation with backoff.
-            //
-            // TODO: Consider abandoning this state after a few attempts and
-            // transitioning back to EvaluatingState, to perhaps give ourselves
-            // the opportunity to (re)detect a captive portal or something.
-            //
-            // TODO: distinguish between CMD_EVALUATE_PRIVATE_DNS messages that are caused by server
-            // lookup failures (which should continue to do exponential backoff) and
-            // CMD_EVALUATE_PRIVATE_DNS messages that are caused by user reconfiguration (which
-            // should be processed immediately.
-            sendMessageDelayed(CMD_EVALUATE_PRIVATE_DNS, mPrivateDnsReevalDelayMs);
-            mPrivateDnsReevalDelayMs *= 2;
-            if (mPrivateDnsReevalDelayMs > MAX_REEVALUATE_DELAY_MS) {
-                mPrivateDnsReevalDelayMs = MAX_REEVALUATE_DELAY_MS;
-            }
-        }
-
-        private boolean sendPrivateDnsProbe() {
-            // q.v. system/netd/server/dns/DnsTlsTransport.cpp
-            final String oneTimeHostnameSuffix = "-dnsotls-ds.metric.gstatic.com";
-            final String host = UUID.randomUUID().toString().substring(0, 8)
-                    + oneTimeHostnameSuffix;
-            final Stopwatch watch = new Stopwatch().start();
-            boolean success = false;
-            long time;
-            try {
-                final InetAddress[] ips = mNetwork.getAllByName(host);
-                time = watch.stop();
-                final String strIps = Arrays.toString(ips);
-                success = (ips != null && ips.length > 0);
-                validationLog(PROBE_PRIVDNS, host, String.format("%dms: %s", time, strIps));
-            } catch (UnknownHostException uhe) {
-                time = watch.stop();
-                validationLog(PROBE_PRIVDNS, host,
-                        String.format("%dms - Error: %s", time, uhe.getMessage()));
-            }
-            logValidationProbe(time, PROBE_PRIVDNS, success ? DNS_SUCCESS : DNS_FAILURE);
-            mEvaluationState.reportProbeResult(NETWORK_VALIDATION_PROBE_PRIVDNS, success);
-            return success;
-        }
-    }
-
-    private class ProbingState extends State {
-        private Thread mThread;
-
-        @Override
-        public void enter() {
-            if (mEvaluateAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
-                //Don't continue to blame UID forever.
-                TrafficStats.clearThreadStatsUid();
-            }
-
-            final int token = ++mProbeToken;
-            mThread = new Thread(() -> sendMessage(obtainMessage(CMD_PROBE_COMPLETE, token, 0,
-                    isCaptivePortal())));
-            mThread.start();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_PROBE_COMPLETE:
-                    // Ensure that CMD_PROBE_COMPLETE from stale threads are ignored.
-                    if (message.arg1 != mProbeToken) {
-                        return HANDLED;
-                    }
-
-                    final CaptivePortalProbeResult probeResult =
-                            (CaptivePortalProbeResult) message.obj;
-                    mLastProbeTime = SystemClock.elapsedRealtime();
-
-                    if (mCollectDataStallMetrics) {
-                        writeDataStallStats(probeResult);
-                    }
-
-                    if (probeResult.isSuccessful()) {
-                        // Transit EvaluatingPrivateDnsState to get to Validated
-                        // state (even if no Private DNS validation required).
-                        transitionTo(mEvaluatingPrivateDnsState);
-                    } else if (probeResult.isPortal()) {
-                        mEvaluationState.reportEvaluationResult(NETWORK_VALIDATION_RESULT_INVALID,
-                                probeResult.redirectUrl);
-                        mLastPortalProbeResult = probeResult;
-                        transitionTo(mCaptivePortalState);
-                    } else if (probeResult.isPartialConnectivity()) {
-                        mEvaluationState.reportEvaluationResult(NETWORK_VALIDATION_RESULT_PARTIAL,
-                                null /* redirectUrl */);
-                        // Check if disable https probing needed.
-                        maybeDisableHttpsProbing(mAcceptPartialConnectivity);
-                        if (mAcceptPartialConnectivity) {
-                            transitionTo(mEvaluatingPrivateDnsState);
-                        } else {
-                            transitionTo(mWaitingForNextProbeState);
-                        }
-                    } else {
-                        logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
-                        mEvaluationState.reportEvaluationResult(NETWORK_VALIDATION_RESULT_INVALID,
-                                null /* redirectUrl */);
-                        transitionTo(mWaitingForNextProbeState);
-                    }
-                    return HANDLED;
-                case EVENT_DNS_NOTIFICATION:
-                case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
-                    // Leave the event to DefaultState.
-                    return NOT_HANDLED;
-                default:
-                    // Wait for probe result and defer events to next state by default.
-                    deferMessage(message);
-                    return HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            if (mThread.isAlive()) {
-                mThread.interrupt();
-            }
-            mThread = null;
-        }
-    }
-
-    // Being in the WaitingForNextProbeState indicates that evaluating probes failed and state is
-    // transited from ProbingState. This ensures that the state machine is only in ProbingState
-    // while a probe is in progress, not while waiting to perform the next probe. That allows
-    // ProbingState to defer most messages until the probe is complete, which keeps the code simple
-    // and matches the pre-Q behaviour where probes were a blocking operation performed on the state
-    // machine thread.
-    private class WaitingForNextProbeState extends State {
-        @Override
-        public void enter() {
-            scheduleNextProbe();
-        }
-
-        private void scheduleNextProbe() {
-            final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
-            sendMessageDelayed(msg, mReevaluateDelayMs);
-            mReevaluateDelayMs *= 2;
-            if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) {
-                mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            return NOT_HANDLED;
-        }
-    }
-
-    // Limits the list of IP addresses returned by getAllByName or tried by openConnection to at
-    // most one per address family. This ensures we only wait up to 20 seconds for TCP connections
-    // to complete, regardless of how many IP addresses a host has.
-    private static class OneAddressPerFamilyNetwork extends Network {
-        OneAddressPerFamilyNetwork(Network network) {
-            // Always bypass Private DNS.
-            super(network.getPrivateDnsBypassingCopy());
-        }
-
-        @Override
-        public InetAddress[] getAllByName(String host) throws UnknownHostException {
-            final List<InetAddress> addrs = Arrays.asList(super.getAllByName(host));
-
-            // Ensure the address family of the first address is tried first.
-            LinkedHashMap<Class, InetAddress> addressByFamily = new LinkedHashMap<>();
-            addressByFamily.put(addrs.get(0).getClass(), addrs.get(0));
-            Collections.shuffle(addrs);
-
-            for (InetAddress addr : addrs) {
-                addressByFamily.put(addr.getClass(), addr);
-            }
-
-            return addressByFamily.values().toArray(new InetAddress[addressByFamily.size()]);
-        }
-    }
-
-    private boolean getIsCaptivePortalCheckEnabled() {
-        String symbol = CAPTIVE_PORTAL_MODE;
-        int defaultValue = CAPTIVE_PORTAL_MODE_PROMPT;
-        int mode = mDependencies.getSetting(mContext, symbol, defaultValue);
-        return mode != CAPTIVE_PORTAL_MODE_IGNORE;
-    }
-
-    private boolean getUseHttpsValidation() {
-        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
-                CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
-    }
-
-    private String getCaptivePortalServerHttpsUrl() {
-        return getSettingFromResource(mContext, R.string.config_captive_portal_https_url,
-                R.string.default_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL);
-    }
-
-    private int getDnsProbeTimeout() {
-        return getIntSetting(mContext, R.integer.config_captive_portal_dns_probe_timeout,
-                CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
-                R.integer.default_captive_portal_dns_probe_timeout);
-    }
-
-    /**
-     * Gets an integer setting from resources or device config
-     *
-     * configResource is used if set, followed by device config if set, followed by defaultResource.
-     * If none of these are set then an exception is thrown.
-     *
-     * TODO: move to a common location such as a ConfigUtils class.
-     * TODO(b/130324939): test that the resources can be overlayed by an RRO package.
-     */
-    @VisibleForTesting
-    int getIntSetting(@NonNull final Context context, @StringRes int configResource,
-            @NonNull String symbol, @StringRes int defaultResource) {
-        final Resources res = context.getResources();
-        try {
-            return res.getInteger(configResource);
-        } catch (Resources.NotFoundException e) {
-            return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
-                    symbol, res.getInteger(defaultResource));
-        }
-    }
-
-    /**
-     * Get the captive portal server HTTP URL that is configured on the device.
-     *
-     * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
-     * it has its own updatable strategies to detect captive portals. The framework only advises
-     * on one URL that can be used, while NetworkMonitor may implement more complex logic.
-     */
-    public String getCaptivePortalServerHttpUrl() {
-        return getSettingFromResource(mContext, R.string.config_captive_portal_http_url,
-                R.string.default_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL);
-    }
-
-    private int getConsecutiveDnsTimeoutThreshold() {
-        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
-                CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
-                DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD);
-    }
-
-    private int getDataStallMinEvaluateTime() {
-        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
-                CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL,
-                DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS);
-    }
-
-    private int getDataStallValidDnsTimeThreshold() {
-        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
-                CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD,
-                DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS);
-    }
-
-    private int getDataStallEvaluationType() {
-        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
-                CONFIG_DATA_STALL_EVALUATION_TYPE,
-                DEFAULT_DATA_STALL_EVALUATION_TYPES);
-    }
-
-    private URL[] makeCaptivePortalFallbackUrls() {
-        try {
-            final String firstUrl = mDependencies.getSetting(mContext, CAPTIVE_PORTAL_FALLBACK_URL,
-                    null);
-
-            final URL[] settingProviderUrls;
-            if (!TextUtils.isEmpty(firstUrl)) {
-                final String otherUrls = mDependencies.getDeviceConfigProperty(
-                        NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
-                // otherUrls may be empty, but .split() ignores trailing empty strings
-                final String separator = ",";
-                final String[] urls = (firstUrl + separator + otherUrls).split(separator);
-                settingProviderUrls = convertStrings(urls, this::makeURL, new URL[0]);
-            } else {
-                settingProviderUrls = new URL[0];
-            }
-
-            return getArrayConfig(settingProviderUrls, R.array.config_captive_portal_fallback_urls,
-                    R.array.default_captive_portal_fallback_urls, this::makeURL);
-        } catch (Exception e) {
-            // Don't let a misconfiguration bootloop the system.
-            Log.e(TAG, "Error parsing configured fallback URLs", e);
-            return new URL[0];
-        }
-    }
-
-    private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
-        try {
-            final String settingsValue = mDependencies.getDeviceConfigProperty(
-                    NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
-
-            final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
-            final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
-                    ? emptySpecs
-                    : parseCaptivePortalProbeSpecs(settingsValue).toArray(emptySpecs);
-
-            return getArrayConfig(providerValue, R.array.config_captive_portal_fallback_probe_specs,
-                    R.array.default_captive_portal_fallback_probe_specs,
-                    CaptivePortalProbeSpec::parseSpecOrNull);
-        } catch (Exception e) {
-            // Don't let a misconfiguration bootloop the system.
-            Log.e(TAG, "Error parsing configured fallback probe specs", e);
-            return null;
-        }
-    }
-
-    /**
-     * Read a setting from a resource or the settings provider.
-     *
-     * <p>The configuration resource is prioritized, then the provider value, then the default
-     * resource value.
-     * @param context The context
-     * @param configResource The resource id for the configuration parameter
-     * @param defaultResource The resource id for the default value
-     * @param symbol The symbol in the settings provider
-     * @return The best available value
-     */
-    @NonNull
-    private String getSettingFromResource(@NonNull final Context context,
-            @StringRes int configResource, @StringRes int defaultResource,
-            @NonNull String symbol) {
-        final Resources res = context.getResources();
-        String setting = res.getString(configResource);
-
-        if (!TextUtils.isEmpty(setting)) return setting;
-
-        setting = mDependencies.getSetting(context, symbol, null);
-        if (!TextUtils.isEmpty(setting)) return setting;
-
-        return res.getString(defaultResource);
-    }
-
-    /**
-     * Get an array configuration from resources or the settings provider.
-     *
-     * <p>The configuration resource is prioritized, then the provider values, then the default
-     * resource values.
-     * @param providerValue Values obtained from the setting provider.
-     * @param configResId ID of the configuration resource.
-     * @param defaultResId ID of the default resource.
-     * @param resourceConverter Converter from the resource strings to stored setting class. Null
-     *                          return values are ignored.
-     */
-    private <T> T[] getArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId,
-            @ArrayRes int defaultResId, @NonNull Function<String, T> resourceConverter) {
-        final Resources res = mContext.getResources();
-        String[] configValue = res.getStringArray(configResId);
-
-        if (configValue.length == 0) {
-            if (providerValue.length > 0) {
-                return providerValue;
-            }
-
-            configValue = res.getStringArray(defaultResId);
-        }
-
-        return convertStrings(configValue, resourceConverter, Arrays.copyOf(providerValue, 0));
-    }
-
-    /**
-     * Convert a String array to an array of some other type using the specified converter.
-     *
-     * <p>Any null value, or value for which the converter throws a {@link RuntimeException}, will
-     * not be added to the output array, so the output array may be smaller than the input.
-     */
-    private <T> T[] convertStrings(
-            @NonNull String[] strings, Function<String, T> converter, T[] emptyArray) {
-        final ArrayList<T> convertedValues = new ArrayList<>(strings.length);
-        for (String configString : strings) {
-            T convertedValue = null;
-            try {
-                convertedValue = converter.apply(configString);
-            } catch (Exception e) {
-                Log.e(TAG, "Error parsing configuration", e);
-                // Fall through
-            }
-            if (convertedValue != null) {
-                convertedValues.add(convertedValue);
-            }
-        }
-        return convertedValues.toArray(emptyArray);
-    }
-
-    private String getCaptivePortalUserAgent() {
-        return mDependencies.getDeviceConfigProperty(NAMESPACE_CONNECTIVITY,
-                CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
-    }
-
-    private URL nextFallbackUrl() {
-        if (mCaptivePortalFallbackUrls.length == 0) {
-            return null;
-        }
-        int idx = Math.abs(mNextFallbackUrlIndex) % mCaptivePortalFallbackUrls.length;
-        mNextFallbackUrlIndex += mRandom.nextInt(); // randomly change url without memory.
-        return mCaptivePortalFallbackUrls[idx];
-    }
-
-    private CaptivePortalProbeSpec nextFallbackSpec() {
-        if (isEmpty(mCaptivePortalFallbackSpecs)) {
-            return null;
-        }
-        // Randomly change spec without memory. Also randomize the first attempt.
-        final int idx = Math.abs(mRandom.nextInt()) % mCaptivePortalFallbackSpecs.length;
-        return mCaptivePortalFallbackSpecs[idx];
-    }
-
-    @VisibleForTesting
-    protected CaptivePortalProbeResult isCaptivePortal() {
-        if (!mIsCaptivePortalCheckEnabled) {
-            validationLog("Validation disabled.");
-            return CaptivePortalProbeResult.SUCCESS;
-        }
-
-        URL pacUrl = null;
-        URL httpsUrl = mCaptivePortalHttpsUrl;
-        URL httpUrl = mCaptivePortalHttpUrl;
-
-        // On networks with a PAC instead of fetching a URL that should result in a 204
-        // response, we instead simply fetch the PAC script.  This is done for a few reasons:
-        // 1. At present our PAC code does not yet handle multiple PACs on multiple networks
-        //    until something like https://android-review.googlesource.com/#/c/115180/ lands.
-        //    Network.openConnection() will ignore network-specific PACs and instead fetch
-        //    using NO_PROXY.  If a PAC is in place, the only fetch we know will succeed with
-        //    NO_PROXY is the fetch of the PAC itself.
-        // 2. To proxy the generate_204 fetch through a PAC would require a number of things
-        //    happen before the fetch can commence, namely:
-        //        a) the PAC script be fetched
-        //        b) a PAC script resolver service be fired up and resolve the captive portal
-        //           server.
-        //    Network validation could be delayed until these prerequisities are satisifed or
-        //    could simply be left to race them.  Neither is an optimal solution.
-        // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
-        //    fact block fetching of the generate_204 URL which would lead to false negative
-        //    results for network validation.
-        final ProxyInfo proxyInfo = mLinkProperties.getHttpProxy();
-        if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
-            pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
-            if (pacUrl == null) {
-                return CaptivePortalProbeResult.FAILED;
-            }
-        }
-
-        if ((pacUrl == null) && (httpUrl == null || httpsUrl == null)) {
-            return CaptivePortalProbeResult.FAILED;
-        }
-
-        long startTime = SystemClock.elapsedRealtime();
-
-        final CaptivePortalProbeResult result;
-        if (pacUrl != null) {
-            result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC);
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, result);
-        } else if (mUseHttps) {
-            // Probe results are reported inside sendParallelHttpProbes.
-            result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl);
-        } else {
-            result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP);
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, result);
-        }
-
-        long endTime = SystemClock.elapsedRealtime();
-
-        sendNetworkConditionsBroadcast(true /* response received */,
-                result.isPortal() /* isCaptivePortal */,
-                startTime, endTime);
-
-        log("isCaptivePortal: isSuccessful()=" + result.isSuccessful()
-                + " isPortal()=" + result.isPortal()
-                + " RedirectUrl=" + result.redirectUrl
-                + " isPartialConnectivity()=" + result.isPartialConnectivity()
-                + " Time=" + (endTime - startTime) + "ms");
-
-        return result;
-    }
-
-    /**
-     * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect.
-     * @return a CaptivePortalProbeResult inferred from the HTTP response.
-     */
-    private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {
-        // Pre-resolve the captive portal server host so we can log it.
-        // Only do this if HttpURLConnection is about to, to avoid any potentially
-        // unnecessary resolution.
-        final String host = (proxy != null) ? proxy.getHost() : url.getHost();
-        // This method cannot safely report probe results because it might not be running on the
-        // state machine thread. Reporting results here would cause races and potentially send
-        // information to callers that does not make sense because the state machine has already
-        // changed state.
-        sendDnsProbe(host);
-        return sendHttpProbe(url, probeType, null);
-    }
-
-    /** Do a DNS lookup for the given server, or throw UnknownHostException after timeoutMs */
-    @VisibleForTesting
-    protected InetAddress[] sendDnsProbeWithTimeout(String host, int timeoutMs)
-                throws UnknownHostException {
-        return DnsUtils.getAllByName(mDependencies.getDnsResolver(), mCleartextDnsNetwork, host,
-                TYPE_ADDRCONFIG, FLAG_EMPTY, timeoutMs);
-    }
-
-    /** Do a DNS resolution of the given server. */
-    private void sendDnsProbe(String host) {
-        if (TextUtils.isEmpty(host)) {
-            return;
-        }
-
-        final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
-        final Stopwatch watch = new Stopwatch().start();
-        int result;
-        String connectInfo;
-        try {
-            InetAddress[] addresses = sendDnsProbeWithTimeout(host, getDnsProbeTimeout());
-            StringBuffer buffer = new StringBuffer();
-            for (InetAddress address : addresses) {
-                buffer.append(',').append(address.getHostAddress());
-            }
-            result = ValidationProbeEvent.DNS_SUCCESS;
-            connectInfo = "OK " + buffer.substring(1);
-        } catch (UnknownHostException e) {
-            result = ValidationProbeEvent.DNS_FAILURE;
-            connectInfo = "FAIL";
-        }
-        final long latency = watch.stop();
-        validationLog(ValidationProbeEvent.PROBE_DNS, host,
-                String.format("%dms %s", latency, connectInfo));
-        logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
-    }
-
-    /**
-     * Do a URL fetch on a known web server to see if we get the data we expect.
-     * @return a CaptivePortalProbeResult inferred from the HTTP response.
-     */
-    @VisibleForTesting
-    protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType,
-            @Nullable CaptivePortalProbeSpec probeSpec) {
-        HttpURLConnection urlConnection = null;
-        int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
-        String redirectUrl = null;
-        final Stopwatch probeTimer = new Stopwatch().start();
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
-                TrafficStatsConstants.TAG_SYSTEM_PROBE);
-        try {
-            urlConnection = (HttpURLConnection) mCleartextDnsNetwork.openConnection(url);
-            urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
-            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
-            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
-            urlConnection.setRequestProperty("Connection", "close");
-            urlConnection.setUseCaches(false);
-            if (mCaptivePortalUserAgent != null) {
-                urlConnection.setRequestProperty("User-Agent", mCaptivePortalUserAgent);
-            }
-            // cannot read request header after connection
-            String requestHeader = urlConnection.getRequestProperties().toString();
-
-            // Time how long it takes to get a response to our request
-            long requestTimestamp = SystemClock.elapsedRealtime();
-
-            httpResponseCode = urlConnection.getResponseCode();
-            redirectUrl = urlConnection.getHeaderField("location");
-
-            // Time how long it takes to get a response to our request
-            long responseTimestamp = SystemClock.elapsedRealtime();
-
-            validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms"
-                    + " ret=" + httpResponseCode
-                    + " request=" + requestHeader
-                    + " headers=" + urlConnection.getHeaderFields());
-            // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
-            // portal.  The only example of this seen so far was a captive portal.  For
-            // the time being go with prior behavior of assuming it's not a captive
-            // portal.  If it is considered a captive portal, a different sign-in URL
-            // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
-            // proxy server.
-            if (httpResponseCode == 200) {
-                long contentLength = urlConnection.getContentLengthLong();
-                if (probeType == ValidationProbeEvent.PROBE_PAC) {
-                    validationLog(
-                            probeType, url, "PAC fetch 200 response interpreted as 204 response.");
-                    httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
-                } else if (contentLength == -1) {
-                    // When no Content-length (default value == -1), attempt to read a byte
-                    // from the response. Do not use available() as it is unreliable.
-                    // See http://b/33498325.
-                    if (urlConnection.getInputStream().read() == -1) {
-                        validationLog(probeType, url,
-                                "Empty 200 response interpreted as failed response.");
-                        httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
-                    }
-                } else if (contentLength <= 4) {
-                    // Consider 200 response with "Content-length <= 4" to not be a captive
-                    // portal. There's no point in considering this a captive portal as the
-                    // user cannot sign-in to an empty page. Probably the result of a broken
-                    // transparent proxy. See http://b/9972012 and http://b/122999481.
-                    validationLog(probeType, url, "200 response with Content-length <= 4"
-                            + " interpreted as failed response.");
-                    httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
-                }
-            }
-        } catch (IOException e) {
-            validationLog(probeType, url, "Probe failed with exception " + e);
-            if (httpResponseCode == CaptivePortalProbeResult.FAILED_CODE) {
-                // TODO: Ping gateway and DNS server and log results.
-            }
-        } finally {
-            if (urlConnection != null) {
-                urlConnection.disconnect();
-            }
-            TrafficStats.setThreadStatsTag(oldTag);
-        }
-        logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
-
-        if (probeSpec == null) {
-            return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
-        } else {
-            return probeSpec.getResult(httpResponseCode, redirectUrl);
-        }
-    }
-
-    private CaptivePortalProbeResult sendParallelHttpProbes(
-            ProxyInfo proxy, URL httpsUrl, URL httpUrl) {
-        // Number of probes to wait for. If a probe completes with a conclusive answer
-        // it shortcuts the latch immediately by forcing the count to 0.
-        final CountDownLatch latch = new CountDownLatch(2);
-
-        final class ProbeThread extends Thread {
-            private final boolean mIsHttps;
-            private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
-
-            ProbeThread(boolean isHttps) {
-                mIsHttps = isHttps;
-            }
-
-            public CaptivePortalProbeResult result() {
-                return mResult;
-            }
-
-            @Override
-            public void run() {
-                if (mIsHttps) {
-                    mResult =
-                            sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
-                } else {
-                    mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP);
-                }
-                if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
-                    // Stop waiting immediately if https succeeds or if http finds a portal.
-                    while (latch.getCount() > 0) {
-                        latch.countDown();
-                    }
-                }
-                // Signal this probe has completed.
-                latch.countDown();
-            }
-        }
-
-        final ProbeThread httpsProbe = new ProbeThread(true);
-        final ProbeThread httpProbe = new ProbeThread(false);
-
-        try {
-            httpsProbe.start();
-            httpProbe.start();
-            latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            validationLog("Error: probes wait interrupted!");
-            return CaptivePortalProbeResult.FAILED;
-        }
-
-        final CaptivePortalProbeResult httpsResult = httpsProbe.result();
-        final CaptivePortalProbeResult httpResult = httpProbe.result();
-
-        // Look for a conclusive probe result first.
-        if (httpResult.isPortal()) {
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, httpResult);
-            return httpResult;
-        }
-        // httpsResult.isPortal() is not expected, but check it nonetheless.
-        if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTPS, httpsResult);
-            return httpsResult;
-        }
-        // If a fallback method exists, use it to retry portal detection.
-        // If we have new-style probe specs, use those. Otherwise, use the fallback URLs.
-        final CaptivePortalProbeSpec probeSpec = nextFallbackSpec();
-        final URL fallbackUrl = (probeSpec != null) ? probeSpec.getUrl() : nextFallbackUrl();
-        CaptivePortalProbeResult fallbackProbeResult = null;
-        if (fallbackUrl != null) {
-            fallbackProbeResult = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_FALLBACK, fallbackProbeResult);
-            if (fallbackProbeResult.isPortal()) {
-                return fallbackProbeResult;
-            }
-        }
-        // Otherwise wait until http and https probes completes and use their results.
-        try {
-            httpProbe.join();
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, httpProbe.result());
-
-            if (httpProbe.result().isPortal()) {
-                return httpProbe.result();
-            }
-
-            httpsProbe.join();
-            reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTPS, httpsProbe.result());
-
-            final boolean isHttpSuccessful =
-                    (httpProbe.result().isSuccessful()
-                    || (fallbackProbeResult != null && fallbackProbeResult.isSuccessful()));
-            if (httpsProbe.result().isFailed() && isHttpSuccessful) {
-                return CaptivePortalProbeResult.PARTIAL;
-            }
-            return httpsProbe.result();
-        } catch (InterruptedException e) {
-            validationLog("Error: http or https probe wait interrupted!");
-            return CaptivePortalProbeResult.FAILED;
-        }
-    }
-
-    private URL makeURL(String url) {
-        if (url != null) {
-            try {
-                return new URL(url);
-            } catch (MalformedURLException e) {
-                validationLog("Bad URL: " + url);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * @param responseReceived - whether or not we received a valid HTTP response to our request.
-     * If false, isCaptivePortal and responseTimestampMs are ignored
-     * TODO: This should be moved to the transports.  The latency could be passed to the transports
-     * along with the captive portal result.  Currently the TYPE_MOBILE broadcasts appear unused so
-     * perhaps this could just be added to the WiFi transport only.
-     */
-    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
-            long requestTimestampMs, long responseTimestampMs) {
-        Intent latencyBroadcast =
-                new Intent(NetworkMonitorUtils.ACTION_NETWORK_CONDITIONS_MEASURED);
-        if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI)) {
-            if (!mWifiManager.isScanAlwaysAvailable()) {
-                return;
-            }
-
-            WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
-            if (currentWifiInfo != null) {
-                // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
-                // surrounded by double quotation marks (thus violating the Javadoc), but this
-                // was changed to match the Javadoc in API 17. Since clients may have started
-                // sanitizing the output of this method since API 17 was released, we should
-                // not change it here as it would become impossible to tell whether the SSID is
-                // simply being surrounded by quotes due to the API, or whether those quotes
-                // are actually part of the SSID.
-                latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_SSID,
-                        currentWifiInfo.getSSID());
-                latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_BSSID,
-                        currentWifiInfo.getBSSID());
-            } else {
-                if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
-                return;
-            }
-            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_WIFI);
-        } else if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
-            // TODO(b/123893112): Support multi-sim.
-            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_NETWORK_TYPE,
-                    mTelephonyManager.getNetworkType());
-            final ServiceState dataSs = mTelephonyManager.getServiceState();
-            if (dataSs == null) {
-                logw("failed to retrieve ServiceState");
-                return;
-            }
-            // See if the data sub is registered for PS services on cell.
-            final NetworkRegistrationInfo nri = dataSs.getNetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_PS,
-                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-            latencyBroadcast.putExtra(
-                    NetworkMonitorUtils.EXTRA_CELL_ID,
-                    nri == null ? null : nri.getCellIdentity());
-            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
-        } else {
-            return;
-        }
-        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_RESPONSE_RECEIVED,
-                responseReceived);
-        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_REQUEST_TIMESTAMP_MS,
-                requestTimestampMs);
-
-        if (responseReceived) {
-            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_IS_CAPTIVE_PORTAL,
-                    isCaptivePortal);
-            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_RESPONSE_TIMESTAMP_MS,
-                    responseTimestampMs);
-        }
-        mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
-                NetworkMonitorUtils.PERMISSION_ACCESS_NETWORK_CONDITIONS);
-    }
-
-    private void logNetworkEvent(int evtype) {
-        int[] transports = mNetworkCapabilities.getTransportTypes();
-        mMetricsLog.log(mCleartextDnsNetwork, transports, new NetworkEvent(evtype));
-    }
-
-    private int networkEventType(ValidationStage s, EvaluationResult r) {
-        if (s.mIsFirstValidation) {
-            if (r.mIsValidated) {
-                return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
-            } else {
-                return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
-            }
-        } else {
-            if (r.mIsValidated) {
-                return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
-            } else {
-                return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
-            }
-        }
-    }
-
-    private void maybeLogEvaluationResult(int evtype) {
-        if (mEvaluationTimer.isRunning()) {
-            int[] transports = mNetworkCapabilities.getTransportTypes();
-            mMetricsLog.log(mCleartextDnsNetwork, transports,
-                    new NetworkEvent(evtype, mEvaluationTimer.stop()));
-            mEvaluationTimer.reset();
-        }
-    }
-
-    private void logValidationProbe(long durationMs, int probeType, int probeResult) {
-        int[] transports = mNetworkCapabilities.getTransportTypes();
-        boolean isFirstValidation = validationStage().mIsFirstValidation;
-        ValidationProbeEvent ev = new ValidationProbeEvent.Builder()
-                .setProbeType(probeType, isFirstValidation)
-                .setReturnCode(probeResult)
-                .setDurationMs(durationMs)
-                .build();
-        mMetricsLog.log(mCleartextDnsNetwork, transports, ev);
-    }
-
-    @VisibleForTesting
-    static class Dependencies {
-        public Network getPrivateDnsBypassNetwork(Network network) {
-            return new OneAddressPerFamilyNetwork(network);
-        }
-
-        public DnsResolver getDnsResolver() {
-            return DnsResolver.getInstance();
-        }
-
-        public Random getRandom() {
-            return new Random();
-        }
-
-        /**
-         * Get the value of a global integer setting.
-         * @param symbol Name of the setting
-         * @param defaultValue Value to return if the setting is not defined.
-         */
-        public int getSetting(Context context, String symbol, int defaultValue) {
-            return Settings.Global.getInt(context.getContentResolver(), symbol, defaultValue);
-        }
-
-        /**
-         * Get the value of a global String setting.
-         * @param symbol Name of the setting
-         * @param defaultValue Value to return if the setting is not defined.
-         */
-        public String getSetting(Context context, String symbol, String defaultValue) {
-            final String value = Settings.Global.getString(context.getContentResolver(), symbol);
-            return value != null ? value : defaultValue;
-        }
-
-        /**
-         * Look up the value of a property in DeviceConfig.
-         * @param namespace The namespace containing the property to look up.
-         * @param name The name of the property to look up.
-         * @param defaultValue The value to return if the property does not exist or has no non-null
-         *                     value.
-         * @return the corresponding value, or defaultValue if none exists.
-         */
-        @Nullable
-        public String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
-                @Nullable String defaultValue) {
-            return NetworkStackUtils.getDeviceConfigProperty(namespace, name, defaultValue);
-        }
-
-        /**
-         * Look up the value of a property in DeviceConfig.
-         * @param namespace The namespace containing the property to look up.
-         * @param name The name of the property to look up.
-         * @param defaultValue The value to return if the property does not exist or has no non-null
-         *                     value.
-         * @return the corresponding value, or defaultValue if none exists.
-         */
-        public int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
-                int defaultValue) {
-            return NetworkStackUtils.getDeviceConfigPropertyInt(namespace, name, defaultValue);
-        }
-
-        public static final Dependencies DEFAULT = new Dependencies();
-    }
-
-    /**
-     * Methods in this class perform no locking because all accesses are performed on the state
-     * machine's thread. Need to consider the thread safety if it ever could be accessed outside the
-     * state machine.
-     */
-    @VisibleForTesting
-    protected class DnsStallDetector {
-        private int mConsecutiveTimeoutCount = 0;
-        private int mSize;
-        final DnsResult[] mDnsEvents;
-        final RingBufferIndices mResultIndices;
-
-        DnsStallDetector(int size) {
-            mSize = Math.max(DEFAULT_DNS_LOG_SIZE, size);
-            mDnsEvents = new DnsResult[mSize];
-            mResultIndices = new RingBufferIndices(mSize);
-        }
-
-        @VisibleForTesting
-        protected void accumulateConsecutiveDnsTimeoutCount(int code) {
-            final DnsResult result = new DnsResult(code);
-            mDnsEvents[mResultIndices.add()] = result;
-            if (result.isTimeout()) {
-                mConsecutiveTimeoutCount++;
-            } else {
-                // Keep the event in mDnsEvents without clearing it so that there are logs to do the
-                // simulation and analysis.
-                mConsecutiveTimeoutCount = 0;
-            }
-        }
-
-        private boolean isDataStallSuspected(int timeoutCountThreshold, int validTime) {
-            if (timeoutCountThreshold <= 0) {
-                Log.wtf(TAG, "Timeout count threshold should be larger than 0.");
-                return false;
-            }
-
-            // Check if the consecutive timeout count reach the threshold or not.
-            if (mConsecutiveTimeoutCount < timeoutCountThreshold) {
-                return false;
-            }
-
-            // Check if the target dns event index is valid or not.
-            final int firstConsecutiveTimeoutIndex =
-                    mResultIndices.indexOf(mResultIndices.size() - timeoutCountThreshold);
-
-            // If the dns timeout events happened long time ago, the events are meaningless for
-            // data stall evaluation. Thus, check if the first consecutive timeout dns event
-            // considered in the evaluation happened in defined threshold time.
-            final long now = SystemClock.elapsedRealtime();
-            final long firstTimeoutTime = now - mDnsEvents[firstConsecutiveTimeoutIndex].mTimeStamp;
-            return (firstTimeoutTime < validTime);
-        }
-
-        int getConsecutiveTimeoutCount() {
-            return mConsecutiveTimeoutCount;
-        }
-    }
-
-    private static class DnsResult {
-        // TODO: Need to move the DNS return code definition to a specific class once unify DNS
-        // response code is done.
-        private static final int RETURN_CODE_DNS_TIMEOUT = 255;
-
-        private final long mTimeStamp;
-        private final int mReturnCode;
-
-        DnsResult(int code) {
-            mTimeStamp = SystemClock.elapsedRealtime();
-            mReturnCode = code;
-        }
-
-        private boolean isTimeout() {
-            return mReturnCode == RETURN_CODE_DNS_TIMEOUT;
-        }
-    }
-
-
-    @VisibleForTesting
-    protected DnsStallDetector getDnsStallDetector() {
-        return mDnsStallDetector;
-    }
-
-    private boolean dataStallEvaluateTypeEnabled(int type) {
-        return (mDataStallEvaluationType & type) != 0;
-    }
-
-    @VisibleForTesting
-    protected long getLastProbeTime() {
-        return mLastProbeTime;
-    }
-
-    @VisibleForTesting
-    protected boolean isDataStall() {
-        boolean result = false;
-        // Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the
-        // possible traffic cost in metered network.
-        if (!mNetworkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
-                && (SystemClock.elapsedRealtime() - getLastProbeTime()
-                < mDataStallMinEvaluateTime)) {
-            return false;
-        }
-
-        // Check dns signal. Suspect it may be a data stall if both :
-        // 1. The number of consecutive DNS query timeouts >= mConsecutiveDnsTimeoutThreshold.
-        // 2. Those consecutive DNS queries happened in the last mValidDataStallDnsTimeThreshold ms.
-        if (dataStallEvaluateTypeEnabled(DATA_STALL_EVALUATION_TYPE_DNS)) {
-            if (mDnsStallDetector.isDataStallSuspected(mConsecutiveDnsTimeoutThreshold,
-                    mDataStallValidDnsTimeThreshold)) {
-                result = true;
-                logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND);
-            }
-        }
-
-        if (VDBG_STALL) {
-            log("isDataStall: result=" + result + ", consecutive dns timeout count="
-                    + mDnsStallDetector.getConsecutiveTimeoutCount());
-        }
-
-        return result;
-    }
-
-    // Class to keep state of evaluation results and probe results.
-    // The main purpose is to ensure NetworkMonitor can notify ConnectivityService of probe results
-    // as soon as they happen, without triggering any other changes. This requires keeping state on
-    // the most recent evaluation result. Calling reportProbeResult will ensure that the results
-    // reported to ConnectivityService contain the previous evaluation result, and thus won't
-    // trigger a validation or partial connectivity state change.
-    @VisibleForTesting
-    protected class EvaluationState {
-        // The latest validation result for this network. This is a bitmask of
-        // INetworkMonitor.NETWORK_VALIDATION_RESULT_* constants.
-        private int mEvaluationResult = NETWORK_VALIDATION_RESULT_INVALID;
-        // Indicates which probes have completed since clearProbeResults was called.
-        // This is a bitmask of INetworkMonitor.NETWORK_VALIDATION_PROBE_* constants.
-        private int mProbeResults = 0;
-        // The latest redirect URL.
-        private String mRedirectUrl;
-
-        protected void clearProbeResults() {
-            mProbeResults = 0;
-        }
-
-        // Probe result for http probe should be updated from reportHttpProbeResult().
-        protected void reportProbeResult(int probeResult, boolean succeeded) {
-            if (succeeded) {
-                mProbeResults |= probeResult;
-            } else {
-                mProbeResults &= ~probeResult;
-            }
-            notifyNetworkTested(getNetworkTestResult(), mRedirectUrl);
-        }
-
-        protected void reportEvaluationResult(int result, @Nullable String redirectUrl) {
-            mEvaluationResult = result;
-            mRedirectUrl = redirectUrl;
-            notifyNetworkTested(getNetworkTestResult(), mRedirectUrl);
-        }
-
-        protected int getNetworkTestResult() {
-            return mEvaluationResult | mProbeResults;
-        }
-    }
-
-    @VisibleForTesting
-    protected EvaluationState getEvaluationState() {
-        return mEvaluationState;
-    }
-
-    private void maybeDisableHttpsProbing(boolean acceptPartial) {
-        mAcceptPartialConnectivity = acceptPartial;
-        // Ignore https probe in next validation if user accept partial connectivity on a partial
-        // connectivity network.
-        if (((mEvaluationState.getNetworkTestResult() & NETWORK_VALIDATION_RESULT_PARTIAL) != 0)
-                && mAcceptPartialConnectivity) {
-            mUseHttps = false;
-        }
-    }
-
-    // Report HTTP, HTTP or FALLBACK probe result.
-    @VisibleForTesting
-    protected void reportHttpProbeResult(int probeResult,
-                @NonNull final CaptivePortalProbeResult result) {
-        boolean succeeded = result.isSuccessful();
-        // The success of a HTTP probe does not tell us whether the DNS probe succeeded.
-        // The DNS and HTTP probes run one after the other in sendDnsAndHttpProbes, and that
-        // method cannot report the result of the DNS probe because that it could be running
-        // on a different thread which is racing with the main state machine thread. So, if
-        // an HTTP or HTTPS probe succeeded, assume that the DNS probe succeeded. But if an
-        // HTTP or HTTPS probe failed, don't assume that DNS is not working.
-        // TODO: fix this.
-        if (succeeded) {
-            probeResult |= NETWORK_VALIDATION_PROBE_DNS;
-        }
-        mEvaluationState.reportProbeResult(probeResult, succeeded);
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
deleted file mode 100644
index a538a5b..0000000
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * 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.connectivity.ipmemorystore;
-
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteCursor;
-import android.database.sqlite.SQLiteCursorDriver;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQuery;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.ipmemorystore.Status;
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringJoiner;
-
-/**
- * Encapsulating class for using the SQLite database backing the memory store.
- *
- * This class groups together the contracts and the SQLite helper used to
- * use the database.
- *
- * @hide
- */
-public class IpMemoryStoreDatabase {
-    private static final String TAG = IpMemoryStoreDatabase.class.getSimpleName();
-    // A pair of NetworkAttributes objects is group-close if the confidence that they are
-    // the same is above this cutoff. See NetworkAttributes and SameL3NetworkResponse.
-    private static final float GROUPCLOSE_CONFIDENCE = 0.5f;
-
-    /**
-     * Contract class for the Network Attributes table.
-     */
-    public static class NetworkAttributesContract {
-        public static final String TABLENAME = "NetworkAttributes";
-
-        public static final String COLNAME_L2KEY = "l2Key";
-        public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
-
-        public static final String COLNAME_EXPIRYDATE = "expiryDate";
-        // Milliseconds since the Epoch, in true Java style
-        public static final String COLTYPE_EXPIRYDATE = "BIGINT";
-
-        public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
-        public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
-
-        public static final String COLNAME_ASSIGNEDV4ADDRESSEXPIRY = "assignedV4AddressExpiry";
-        // The lease expiry timestamp in uint of milliseconds
-        public static final String COLTYPE_ASSIGNEDV4ADDRESSEXPIRY = "BIGINT";
-
-        // Please note that the group hint is only a *hint*, hence its name. The client can offer
-        // this information to nudge the grouping in the decision it thinks is right, but it can't
-        // decide for the memory store what is the same L3 network.
-        public static final String COLNAME_GROUPHINT = "groupHint";
-        public static final String COLTYPE_GROUPHINT = "TEXT";
-
-        public static final String COLNAME_DNSADDRESSES = "dnsAddresses";
-        // Stored in marshalled form as is
-        public static final String COLTYPE_DNSADDRESSES = "BLOB";
-
-        public static final String COLNAME_MTU = "mtu";
-        public static final String COLTYPE_MTU = "INTEGER DEFAULT -1";
-
-        public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
-                + TABLENAME                       + " ("
-                + COLNAME_L2KEY                   + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
-                + COLNAME_EXPIRYDATE              + " " + COLTYPE_EXPIRYDATE              + ", "
-                + COLNAME_ASSIGNEDV4ADDRESS       + " " + COLTYPE_ASSIGNEDV4ADDRESS       + ", "
-                + COLNAME_ASSIGNEDV4ADDRESSEXPIRY + " " + COLTYPE_ASSIGNEDV4ADDRESSEXPIRY + ", "
-                + COLNAME_GROUPHINT               + " " + COLTYPE_GROUPHINT               + ", "
-                + COLNAME_DNSADDRESSES            + " " + COLTYPE_DNSADDRESSES            + ", "
-                + COLNAME_MTU                     + " " + COLTYPE_MTU                     + ")";
-        public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
-    }
-
-    /**
-     * Contract class for the Private Data table.
-     */
-    public static class PrivateDataContract {
-        public static final String TABLENAME = "PrivateData";
-
-        public static final String COLNAME_L2KEY = "l2Key";
-        public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
-
-        public static final String COLNAME_CLIENT = "client";
-        public static final String COLTYPE_CLIENT = "TEXT NOT NULL";
-
-        public static final String COLNAME_DATANAME = "dataName";
-        public static final String COLTYPE_DATANAME = "TEXT NOT NULL";
-
-        public static final String COLNAME_DATA = "data";
-        public static final String COLTYPE_DATA = "BLOB NOT NULL";
-
-        public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
-                + TABLENAME        + " ("
-                + COLNAME_L2KEY    + " " + COLTYPE_L2KEY    + ", "
-                + COLNAME_CLIENT   + " " + COLTYPE_CLIENT   + ", "
-                + COLNAME_DATANAME + " " + COLTYPE_DATANAME + ", "
-                + COLNAME_DATA     + " " + COLTYPE_DATA     + ", "
-                + "PRIMARY KEY ("
-                + COLNAME_L2KEY    + ", "
-                + COLNAME_CLIENT   + ", "
-                + COLNAME_DATANAME + "))";
-        public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
-    }
-
-    // To save memory when the DB is not used, close it after 30s of inactivity. This is
-    // determined manually based on what feels right.
-    private static final long IDLE_CONNECTION_TIMEOUT_MS = 30_000;
-
-    /** The SQLite DB helper */
-    public static class DbHelper extends SQLiteOpenHelper {
-        // Update this whenever changing the schema.
-        private static final int SCHEMA_VERSION = 4;
-        private static final String DATABASE_FILENAME = "IpMemoryStore.db";
-        private static final String TRIGGER_NAME = "delete_cascade_to_private";
-
-        public DbHelper(@NonNull final Context context) {
-            super(context, DATABASE_FILENAME, null, SCHEMA_VERSION);
-            setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
-        }
-
-        /** Called when the database is created */
-        @Override
-        public void onCreate(@NonNull final SQLiteDatabase db) {
-            db.execSQL(NetworkAttributesContract.CREATE_TABLE);
-            db.execSQL(PrivateDataContract.CREATE_TABLE);
-            createTrigger(db);
-        }
-
-        /** Called when the database is upgraded */
-        @Override
-        public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
-                final int newVersion) {
-            try {
-                if (oldVersion < 2) {
-                    // upgrade from version 1 to version 2
-                    // since we starts from version 2, do nothing here
-                }
-
-                if (oldVersion < 3) {
-                    // upgrade from version 2 to version 3
-                    final String sqlUpgradeAddressExpiry = "alter table"
-                            + " " + NetworkAttributesContract.TABLENAME + " ADD"
-                            + " " + NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY
-                            + " " + NetworkAttributesContract.COLTYPE_ASSIGNEDV4ADDRESSEXPIRY;
-                    db.execSQL(sqlUpgradeAddressExpiry);
-                }
-
-                if (oldVersion < 4) {
-                    createTrigger(db);
-                }
-            } catch (SQLiteException e) {
-                Log.e(TAG, "Could not upgrade to the new version", e);
-                // create database with new version
-                db.execSQL(NetworkAttributesContract.DROP_TABLE);
-                db.execSQL(PrivateDataContract.DROP_TABLE);
-                onCreate(db);
-            }
-        }
-
-        /** Called when the database is downgraded */
-        @Override
-        public void onDowngrade(@NonNull final SQLiteDatabase db, final int oldVersion,
-                final int newVersion) {
-            // Downgrades always nuke all data and recreate an empty table.
-            db.execSQL(NetworkAttributesContract.DROP_TABLE);
-            db.execSQL(PrivateDataContract.DROP_TABLE);
-            db.execSQL("DROP TRIGGER " + TRIGGER_NAME);
-            onCreate(db);
-        }
-
-        private void createTrigger(@NonNull final SQLiteDatabase db) {
-            final String createTrigger = "CREATE TRIGGER " + TRIGGER_NAME
-                    + " DELETE ON " + NetworkAttributesContract.TABLENAME
-                    + " BEGIN"
-                    + " DELETE FROM " + PrivateDataContract.TABLENAME + " WHERE OLD."
-                    + NetworkAttributesContract.COLNAME_L2KEY
-                    + "=" + PrivateDataContract.COLNAME_L2KEY
-                    + "; END;";
-            db.execSQL(createTrigger);
-        }
-    }
-
-    @NonNull
-    private static byte[] encodeAddressList(@NonNull final List<InetAddress> addresses) {
-        final ByteArrayOutputStream os = new ByteArrayOutputStream();
-        for (final InetAddress address : addresses) {
-            final byte[] b = address.getAddress();
-            os.write(b.length);
-            os.write(b, 0, b.length);
-        }
-        return os.toByteArray();
-    }
-
-    @NonNull
-    private static ArrayList<InetAddress> decodeAddressList(@NonNull final byte[] encoded) {
-        final ByteArrayInputStream is = new ByteArrayInputStream(encoded);
-        final ArrayList<InetAddress> addresses = new ArrayList<>();
-        int d = -1;
-        while ((d = is.read()) != -1) {
-            final byte[] bytes = new byte[d];
-            is.read(bytes, 0, d);
-            try {
-                addresses.add(InetAddress.getByAddress(bytes));
-            } catch (UnknownHostException e) { /* Hopefully impossible */ }
-        }
-        return addresses;
-    }
-
-    @NonNull
-    private static ContentValues toContentValues(@Nullable final NetworkAttributes attributes) {
-        final ContentValues values = new ContentValues();
-        if (null == attributes) return values;
-        if (null != attributes.assignedV4Address) {
-            values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
-                    inet4AddressToIntHTH(attributes.assignedV4Address));
-        }
-        if (null != attributes.assignedV4AddressExpiry) {
-            values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY,
-                    attributes.assignedV4AddressExpiry);
-        }
-        if (null != attributes.groupHint) {
-            values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
-        }
-        if (null != attributes.dnsAddresses) {
-            values.put(NetworkAttributesContract.COLNAME_DNSADDRESSES,
-                    encodeAddressList(attributes.dnsAddresses));
-        }
-        if (null != attributes.mtu) {
-            values.put(NetworkAttributesContract.COLNAME_MTU, attributes.mtu);
-        }
-        return values;
-    }
-
-    // Convert a NetworkAttributes object to content values to store them in a table compliant
-    // with the contract defined in NetworkAttributesContract.
-    @NonNull
-    private static ContentValues toContentValues(@NonNull final String key,
-            @Nullable final NetworkAttributes attributes, final long expiry) {
-        final ContentValues values = toContentValues(attributes);
-        values.put(NetworkAttributesContract.COLNAME_L2KEY, key);
-        values.put(NetworkAttributesContract.COLNAME_EXPIRYDATE, expiry);
-        return values;
-    }
-
-    // Convert a byte array into content values to store it in a table compliant with the
-    // contract defined in PrivateDataContract.
-    @NonNull
-    private static ContentValues toContentValues(@NonNull final String key,
-            @NonNull final String clientId, @NonNull final String name,
-            @NonNull final byte[] data) {
-        final ContentValues values = new ContentValues();
-        values.put(PrivateDataContract.COLNAME_L2KEY, key);
-        values.put(PrivateDataContract.COLNAME_CLIENT, clientId);
-        values.put(PrivateDataContract.COLNAME_DATANAME, name);
-        values.put(PrivateDataContract.COLNAME_DATA, data);
-        return values;
-    }
-
-    @Nullable
-    private static NetworkAttributes readNetworkAttributesLine(@NonNull final Cursor cursor) {
-        // Make sure the data hasn't expired
-        final long expiry = getLong(cursor, NetworkAttributesContract.COLNAME_EXPIRYDATE, -1L);
-        if (expiry < System.currentTimeMillis()) return null;
-
-        final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
-        final int assignedV4AddressInt = getInt(cursor,
-                NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, 0);
-        final long assignedV4AddressExpiry = getLong(cursor,
-                NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY, 0);
-        final String groupHint = getString(cursor, NetworkAttributesContract.COLNAME_GROUPHINT);
-        final byte[] dnsAddressesBlob =
-                getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
-        final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
-        if (0 != assignedV4AddressInt) {
-            builder.setAssignedV4Address(intToInet4AddressHTH(assignedV4AddressInt));
-        }
-        if (0 != assignedV4AddressExpiry) {
-            builder.setAssignedV4AddressExpiry(assignedV4AddressExpiry);
-        }
-        builder.setGroupHint(groupHint);
-        if (null != dnsAddressesBlob) {
-            builder.setDnsAddresses(decodeAddressList(dnsAddressesBlob));
-        }
-        if (mtu >= 0) {
-            builder.setMtu(mtu);
-        }
-        return builder.build();
-    }
-
-    private static final String[] EXPIRY_COLUMN = new String[] {
-        NetworkAttributesContract.COLNAME_EXPIRYDATE
-    };
-    static final int EXPIRY_ERROR = -1; // Legal values for expiry are positive
-
-    static final String SELECT_L2KEY = NetworkAttributesContract.COLNAME_L2KEY + " = ?";
-
-    // Returns the expiry date of the specified row, or one of the error codes above if the
-    // row is not found or some other error
-    static long getExpiry(@NonNull final SQLiteDatabase db, @NonNull final String key) {
-        final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
-                EXPIRY_COLUMN, // columns
-                SELECT_L2KEY, // selection
-                new String[] { key }, // selectionArgs
-                null, // groupBy
-                null, // having
-                null // orderBy
-        );
-        // L2KEY is the primary key ; it should not be possible to get more than one
-        // result here. 0 results means the key was not found.
-        if (cursor.getCount() != 1) return EXPIRY_ERROR;
-        cursor.moveToFirst();
-        final long result = cursor.getLong(0); // index in the EXPIRY_COLUMN array
-        cursor.close();
-        return result;
-    }
-
-    static final int RELEVANCE_ERROR = -1; // Legal values for relevance are positive
-
-    // Returns the relevance of the specified row, or one of the error codes above if the
-    // row is not found or some other error
-    static int getRelevance(@NonNull final SQLiteDatabase db, @NonNull final String key) {
-        final long expiry = getExpiry(db, key);
-        return expiry < 0 ? (int) expiry : RelevanceUtils.computeRelevanceForNow(expiry);
-    }
-
-    // If the attributes are null, this will only write the expiry.
-    // Returns an int out of Status.{SUCCESS, ERROR_*}
-    static int storeNetworkAttributes(@NonNull final SQLiteDatabase db, @NonNull final String key,
-            final long expiry, @Nullable final NetworkAttributes attributes) {
-        final ContentValues cv = toContentValues(key, attributes, expiry);
-        db.beginTransaction();
-        try {
-            // Unfortunately SQLite does not have any way to do INSERT OR UPDATE. Options are
-            // to either insert with on conflict ignore then update (like done here), or to
-            // construct a custom SQL INSERT statement with nested select.
-            final long resultId = db.insertWithOnConflict(NetworkAttributesContract.TABLENAME,
-                    null, cv, SQLiteDatabase.CONFLICT_IGNORE);
-            if (resultId < 0) {
-                db.update(NetworkAttributesContract.TABLENAME, cv, SELECT_L2KEY, new String[]{key});
-            }
-            db.setTransactionSuccessful();
-            return Status.SUCCESS;
-        } catch (SQLiteException e) {
-            // No space left on disk or something
-            Log.e(TAG, "Could not write to the memory store", e);
-        } finally {
-            db.endTransaction();
-        }
-        return Status.ERROR_STORAGE;
-    }
-
-    // Returns an int out of Status.{SUCCESS, ERROR_*}
-    static int storeBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
-            @NonNull final String clientId, @NonNull final String name,
-            @NonNull final byte[] data) {
-        final long res = db.insertWithOnConflict(PrivateDataContract.TABLENAME, null,
-                toContentValues(key, clientId, name, data), SQLiteDatabase.CONFLICT_REPLACE);
-        return (res == -1) ? Status.ERROR_STORAGE : Status.SUCCESS;
-    }
-
-    @Nullable
-    static NetworkAttributes retrieveNetworkAttributes(@NonNull final SQLiteDatabase db,
-            @NonNull final String key) {
-        final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
-                null, // columns, null means everything
-                NetworkAttributesContract.COLNAME_L2KEY + " = ?", // selection
-                new String[] { key }, // selectionArgs
-                null, // groupBy
-                null, // having
-                null); // orderBy
-        // L2KEY is the primary key ; it should not be possible to get more than one
-        // result here. 0 results means the key was not found.
-        if (cursor.getCount() != 1) return null;
-        cursor.moveToFirst();
-        final NetworkAttributes attributes = readNetworkAttributesLine(cursor);
-        cursor.close();
-        return attributes;
-    }
-
-    private static final String[] DATA_COLUMN = new String[] {
-            PrivateDataContract.COLNAME_DATA
-    };
-
-    @Nullable
-    static byte[] retrieveBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
-            @NonNull final String clientId, @NonNull final String name) {
-        final Cursor cursor = db.query(PrivateDataContract.TABLENAME,
-                DATA_COLUMN, // columns
-                PrivateDataContract.COLNAME_L2KEY + " = ? AND " // selection
-                + PrivateDataContract.COLNAME_CLIENT + " = ? AND "
-                + PrivateDataContract.COLNAME_DATANAME + " = ?",
-                new String[] { key, clientId, name }, // selectionArgs
-                null, // groupBy
-                null, // having
-                null); // orderBy
-        // The query above is querying by (composite) primary key, so it should not be possible to
-        // get more than one result here. 0 results means the key was not found.
-        if (cursor.getCount() != 1) return null;
-        cursor.moveToFirst();
-        final byte[] result = cursor.getBlob(0); // index in the DATA_COLUMN array
-        cursor.close();
-        return result;
-    }
-
-    /**
-     * Wipe all data in tables when network factory reset occurs.
-     */
-    static void wipeDataUponNetworkReset(@NonNull final SQLiteDatabase db) {
-        for (int remainingRetries = 3; remainingRetries > 0; --remainingRetries) {
-            db.beginTransaction();
-            try {
-                db.delete(NetworkAttributesContract.TABLENAME, null, null);
-                db.delete(PrivateDataContract.TABLENAME, null, null);
-                final Cursor cursorNetworkAttributes = db.query(
-                        // table name
-                        NetworkAttributesContract.TABLENAME,
-                        // column name
-                        new String[] { NetworkAttributesContract.COLNAME_L2KEY },
-                        null, // selection
-                        null, // selectionArgs
-                        null, // groupBy
-                        null, // having
-                        null, // orderBy
-                        "1"); // limit
-                if (0 != cursorNetworkAttributes.getCount()) {
-                    cursorNetworkAttributes.close();
-                    continue;
-                }
-                cursorNetworkAttributes.close();
-                final Cursor cursorPrivateData = db.query(
-                        // table name
-                        PrivateDataContract.TABLENAME,
-                        // column name
-                        new String[] { PrivateDataContract.COLNAME_L2KEY },
-                        null, // selection
-                        null, // selectionArgs
-                        null, // groupBy
-                        null, // having
-                        null, // orderBy
-                        "1"); // limit
-                if (0 != cursorPrivateData.getCount()) {
-                    cursorPrivateData.close();
-                    continue;
-                }
-                cursorPrivateData.close();
-                db.setTransactionSuccessful();
-                return;
-            } catch (SQLiteException e) {
-                Log.e(TAG, "Could not wipe the data in database", e);
-            } finally {
-                db.endTransaction();
-            }
-        }
-    }
-
-    /**
-     * The following is a horrible hack that is necessary because the Android SQLite API does not
-     * have a way to query a binary blob. This, almost certainly, is an overlook.
-     *
-     * The Android SQLite API has two family of methods : one for query that returns data, and
-     * one for more general SQL statements that can execute any statement but may not return
-     * anything. All the query methods, however, take only String[] for the arguments.
-     *
-     * In principle it is simple to write a function that will encode the binary blob in the
-     * way SQLite expects it. However, because the API forces the argument to be coerced into a
-     * String, the SQLiteQuery object generated by the default query methods will bind all
-     * arguments as Strings and SQL will *sanitize* them. This works okay for numeric types,
-     * but the format for blobs is x'<hex string>'. Note the presence of quotes, which will
-     * be sanitized, changing the contents of the field, and the query will fail to match the
-     * blob.
-     *
-     * As far as I can tell, there are two possible ways around this problem. The first one
-     * is to put the data in the query string and eschew it being an argument. This would
-     * require doing the sanitizing by hand. The other is to call bindBlob directly on the
-     * generated SQLiteQuery object, which not only is a lot less dangerous than rolling out
-     * sanitizing, but also will do the right thing if the underlying format ever changes.
-     *
-     * But none of the methods that take an SQLiteQuery object can return data ; this *must*
-     * be called with SQLiteDatabase#query. This object is not accessible from outside.
-     * However, there is a #query version that accepts a CursorFactory and this is pretty
-     * straightforward to implement as all the arguments are coming in and the SQLiteCursor
-     * class is public API.
-     * With this, it's possible to intercept the SQLiteQuery object, and assuming the args
-     * are available, to bind them directly and work around the API's oblivious coercion into
-     * Strings.
-     *
-     * This is really sad, but I don't see another way of having this work than this or the
-     * hand-rolled sanitizing, and this is the lesser evil.
-     */
-    private static class CustomCursorFactory implements SQLiteDatabase.CursorFactory {
-        @NonNull
-        private final ArrayList<Object> mArgs;
-        CustomCursorFactory(@NonNull final ArrayList<Object> args) {
-            mArgs = args;
-        }
-        @Override
-        public Cursor newCursor(final SQLiteDatabase db, final SQLiteCursorDriver masterQuery,
-                final String editTable,
-                final SQLiteQuery query) {
-            int index = 1; // bind is 1-indexed
-            for (final Object arg : mArgs) {
-                if (arg instanceof String) {
-                    query.bindString(index++, (String) arg);
-                } else if (arg instanceof Long) {
-                    query.bindLong(index++, (Long) arg);
-                } else if (arg instanceof Integer) {
-                    query.bindLong(index++, Long.valueOf((Integer) arg));
-                } else if (arg instanceof byte[]) {
-                    query.bindBlob(index++, (byte[]) arg);
-                } else {
-                    throw new IllegalStateException("Unsupported type CustomCursorFactory "
-                            + arg.getClass().toString());
-                }
-            }
-            return new SQLiteCursor(masterQuery, editTable, query);
-        }
-    }
-
-    // Returns the l2key of the closest match, if and only if it matches
-    // closely enough (as determined by group-closeness).
-    @Nullable
-    static String findClosestAttributes(@NonNull final SQLiteDatabase db,
-            @NonNull final NetworkAttributes attr) {
-        if (attr.isEmpty()) return null;
-        final ContentValues values = toContentValues(attr);
-
-        // Build the selection and args. To cut down on the number of lines to search, limit
-        // the search to those with at least one argument equals to the requested attributes.
-        // This works only because null attributes match only will not result in group-closeness.
-        final StringJoiner sj = new StringJoiner(" OR ");
-        final ArrayList<Object> args = new ArrayList<>();
-        args.add(System.currentTimeMillis());
-        for (final String field : values.keySet()) {
-            sj.add(field + " = ?");
-            args.add(values.get(field));
-        }
-
-        final String selection = NetworkAttributesContract.COLNAME_EXPIRYDATE + " > ? AND ("
-                + sj.toString() + ")";
-        final Cursor cursor = db.queryWithFactory(new CustomCursorFactory(args),
-                false, // distinct
-                NetworkAttributesContract.TABLENAME,
-                null, // columns, null means everything
-                selection, // selection
-                null, // selectionArgs, horrendously passed to the cursor factory instead
-                null, // groupBy
-                null, // having
-                null, // orderBy
-                null); // limit
-        if (cursor.getCount() <= 0) return null;
-        cursor.moveToFirst();
-        String bestKey = null;
-        float bestMatchConfidence = GROUPCLOSE_CONFIDENCE; // Never return a match worse than this.
-        while (!cursor.isAfterLast()) {
-            final NetworkAttributes read = readNetworkAttributesLine(cursor);
-            final float confidence = read.getNetworkGroupSamenessConfidence(attr);
-            if (confidence > bestMatchConfidence) {
-                bestKey = getString(cursor, NetworkAttributesContract.COLNAME_L2KEY);
-                bestMatchConfidence = confidence;
-            }
-            cursor.moveToNext();
-        }
-        cursor.close();
-        return bestKey;
-    }
-
-    // Drops all records that are expired. Relevance has decayed to zero of these records. Returns
-    // an int out of Status.{SUCCESS, ERROR_*}
-    static int dropAllExpiredRecords(@NonNull final SQLiteDatabase db) {
-        db.beginTransaction();
-        try {
-            // Deletes NetworkAttributes that have expired.
-            db.delete(NetworkAttributesContract.TABLENAME,
-                    NetworkAttributesContract.COLNAME_EXPIRYDATE + " < ?",
-                    new String[]{Long.toString(System.currentTimeMillis())});
-            db.setTransactionSuccessful();
-        } catch (SQLiteException e) {
-            Log.e(TAG, "Could not delete data from memory store", e);
-            return Status.ERROR_STORAGE;
-        } finally {
-            db.endTransaction();
-        }
-
-        // Execute vacuuming here if above operation has no exception. If above operation got
-        // exception, vacuuming can be ignored for reducing unnecessary consumption.
-        try {
-            db.execSQL("VACUUM");
-        } catch (SQLiteException e) {
-            // Do nothing.
-        }
-        return Status.SUCCESS;
-    }
-
-    // Drops number of records that start from the lowest expiryDate. Returns an int out of
-    // Status.{SUCCESS, ERROR_*}
-    static int dropNumberOfRecords(@NonNull final SQLiteDatabase db, int number) {
-        if (number <= 0) {
-            return Status.ERROR_ILLEGAL_ARGUMENT;
-        }
-
-        // Queries number of NetworkAttributes that start from the lowest expiryDate.
-        final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
-                new String[] {NetworkAttributesContract.COLNAME_EXPIRYDATE}, // columns
-                null, // selection
-                null, // selectionArgs
-                null, // groupBy
-                null, // having
-                NetworkAttributesContract.COLNAME_EXPIRYDATE, // orderBy
-                Integer.toString(number)); // limit
-        if (cursor == null || cursor.getCount() <= 0) return Status.ERROR_GENERIC;
-        cursor.moveToLast();
-
-        //Get the expiryDate from last record.
-        final long expiryDate = getLong(cursor, NetworkAttributesContract.COLNAME_EXPIRYDATE, 0);
-        cursor.close();
-
-        db.beginTransaction();
-        try {
-            // Deletes NetworkAttributes that expiryDate are lower than given value.
-            db.delete(NetworkAttributesContract.TABLENAME,
-                    NetworkAttributesContract.COLNAME_EXPIRYDATE + " <= ?",
-                    new String[]{Long.toString(expiryDate)});
-            db.setTransactionSuccessful();
-        } catch (SQLiteException e) {
-            Log.e(TAG, "Could not delete data from memory store", e);
-            return Status.ERROR_STORAGE;
-        } finally {
-            db.endTransaction();
-        }
-
-        // Execute vacuuming here if above operation has no exception. If above operation got
-        // exception, vacuuming can be ignored for reducing unnecessary consumption.
-        try {
-            db.execSQL("VACUUM");
-        } catch (SQLiteException e) {
-            // Do nothing.
-        }
-        return Status.SUCCESS;
-    }
-
-    static int getTotalRecordNumber(@NonNull final SQLiteDatabase db) {
-        // Query the total number of NetworkAttributes
-        final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
-                new String[] {"COUNT(*)"}, // columns
-                null, // selection
-                null, // selectionArgs
-                null, // groupBy
-                null, // having
-                null); // orderBy
-        cursor.moveToFirst();
-        return cursor == null ? 0 : cursor.getInt(0);
-    }
-
-    // Helper methods
-    private static String getString(final Cursor cursor, final String columnName) {
-        final int columnIndex = cursor.getColumnIndex(columnName);
-        return (columnIndex >= 0) ? cursor.getString(columnIndex) : null;
-    }
-    private static byte[] getBlob(final Cursor cursor, final String columnName) {
-        final int columnIndex = cursor.getColumnIndex(columnName);
-        return (columnIndex >= 0) ? cursor.getBlob(columnIndex) : null;
-    }
-    private static int getInt(final Cursor cursor, final String columnName,
-            final int defaultValue) {
-        final int columnIndex = cursor.getColumnIndex(columnName);
-        return (columnIndex >= 0) ? cursor.getInt(columnIndex) : defaultValue;
-    }
-    private static long getLong(final Cursor cursor, final String columnName,
-            final long defaultValue) {
-        final int columnIndex = cursor.getColumnIndex(columnName);
-        return (columnIndex >= 0) ? cursor.getLong(columnIndex) : defaultValue;
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
deleted file mode 100644
index 55ab8d4..0000000
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2018 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.connectivity.ipmemorystore;
-
-import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED;
-import static android.net.ipmemorystore.Status.ERROR_GENERIC;
-import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT;
-import static android.net.ipmemorystore.Status.SUCCESS;
-
-import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
-import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.IIpMemoryStore;
-import android.net.ipmemorystore.Blob;
-import android.net.ipmemorystore.IOnBlobRetrievedListener;
-import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener;
-import android.net.ipmemorystore.IOnSameL3NetworkResponseListener;
-import android.net.ipmemorystore.IOnStatusListener;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.ipmemorystore.NetworkAttributesParcelable;
-import android.net.ipmemorystore.SameL3NetworkResponse;
-import android.net.ipmemorystore.Status;
-import android.net.ipmemorystore.StatusParcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Implementation for the IP memory store.
- * This component offers specialized services for network components to store and retrieve
- * knowledge about networks, and provides intelligence that groups level 2 networks together
- * into level 3 networks.
- *
- * @hide
- */
-public class IpMemoryStoreService extends IIpMemoryStore.Stub {
-    private static final String TAG = IpMemoryStoreService.class.getSimpleName();
-    private static final int DATABASE_SIZE_THRESHOLD = 10 * 1024 * 1024; //10MB
-    private static final int MAX_DROP_RECORD_TIMES = 500;
-    private static final int MIN_DELETE_NUM = 5;
-    private static final boolean DBG = true;
-
-    // Error codes below are internal and used for notifying status beteween IpMemoryStore modules.
-    static final int ERROR_INTERNAL_BASE = -1_000_000_000;
-    // This error code is used for maintenance only to notify RegularMaintenanceJobService that
-    // full maintenance job has been interrupted.
-    static final int ERROR_INTERNAL_INTERRUPTED = ERROR_INTERNAL_BASE - 1;
-
-    @NonNull
-    final Context mContext;
-    @Nullable
-    final SQLiteDatabase mDb;
-    @NonNull
-    final ExecutorService mExecutor;
-
-    /**
-     * Construct an IpMemoryStoreService object.
-     * This constructor will block on disk access to open the database.
-     * @param context the context to access storage with.
-     */
-    public IpMemoryStoreService(@NonNull final Context context) {
-        // Note that constructing the service will access the disk and block
-        // for some time, but it should make no difference to the clients. Because
-        // the interface is one-way, clients fire and forget requests, and the callback
-        // will get called eventually in any case, and the framework will wait for the
-        // service to be created to deliver subsequent requests.
-        // Avoiding this would mean the mDb member can't be final, which means the service would
-        // have to test for nullity, care for failure, and allow for a wait at every single access,
-        // which would make the code a lot more complex and require all methods to possibly block.
-        mContext = context;
-        SQLiteDatabase db;
-        final IpMemoryStoreDatabase.DbHelper helper = new IpMemoryStoreDatabase.DbHelper(context);
-        try {
-            db = helper.getWritableDatabase();
-            if (null == db) Log.e(TAG, "Unexpected null return of getWriteableDatabase");
-        } catch (final SQLException e) {
-            Log.e(TAG, "Can't open the Ip Memory Store database", e);
-            db = null;
-        } catch (final Exception e) {
-            Log.wtf(TAG, "Impossible exception Ip Memory Store database", e);
-            db = null;
-        }
-        mDb = db;
-        // The single thread executor guarantees that all work is executed sequentially on the
-        // same thread, and no two tasks can be active at the same time. This is required to
-        // ensure operations from multiple clients don't interfere with each other (in particular,
-        // operations involving a transaction must not run concurrently with other operations
-        // as the other operations might be taken as part of the transaction). By default, the
-        // single thread executor runs off an unbounded queue.
-        // TODO : investigate replacing this scheme with a scheme where each thread has its own
-        // instance of the database, as it may be faster. It is likely however that IpMemoryStore
-        // operations are mostly IO-bound anyway, and additional contention is unlikely to bring
-        // benefits. Alternatively, a read-write lock might increase throughput.
-        mExecutor = Executors.newSingleThreadExecutor();
-        RegularMaintenanceJobService.schedule(mContext, this);
-    }
-
-    /**
-     * Shutdown the memory store service, cancelling running tasks and dropping queued tasks.
-     *
-     * This is provided to give a way to clean up, and is meant to be available in case of an
-     * emergency shutdown.
-     */
-    public void shutdown() {
-        // By contrast with ExecutorService#shutdown, ExecutorService#shutdownNow tries
-        // to cancel the existing tasks, and does not wait for completion. It does not
-        // guarantee the threads can be terminated in any given amount of time.
-        mExecutor.shutdownNow();
-        if (mDb != null) mDb.close();
-        RegularMaintenanceJobService.unschedule(mContext);
-    }
-
-    /** Helper function to make a status object */
-    private StatusParcelable makeStatus(final int code) {
-        return new Status(code).toParcelable();
-    }
-
-    /**
-     * Store network attributes for a given L2 key.
-     *
-     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
-     *              key and only care about grouping can pass a unique ID here like the ones
-     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
-     *              relevance of such a network will lead to it being evicted soon if it's not
-     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
-     * @param attributes The attributes for this network.
-     * @param listener A listener to inform of the completion of this call, or null if the client
-     *        is not interested in learning about success/failure.
-     * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
-     * If the call failed, the L2 key will be null.
-     */
-    // Note that while l2Key and attributes are non-null in spirit, they are received from
-    // another process. If the remote process decides to ignore everything and send null, this
-    // process should still not crash.
-    @Override
-    public void storeNetworkAttributes(@Nullable final String l2Key,
-            @Nullable final NetworkAttributesParcelable attributes,
-            @Nullable final IOnStatusListener listener) {
-        // Because the parcelable is 100% mutable, the thread may not see its members initialized.
-        // Therefore either an immutable object is created on this same thread before it's passed
-        // to the executor, or there need to be a write barrier here and a read barrier in the
-        // remote thread.
-        final NetworkAttributes na = null == attributes ? null : new NetworkAttributes(attributes);
-        mExecutor.execute(() -> {
-            try {
-                final int code = storeNetworkAttributesAndBlobSync(l2Key, na,
-                        null /* clientId */, null /* name */, null /* data */);
-                if (null != listener) listener.onComplete(makeStatus(code));
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    /**
-     * Store a binary blob associated with an L2 key and a name.
-     *
-     * @param l2Key The L2 key for this network.
-     * @param clientId The ID of the client.
-     * @param name The name of this data.
-     * @param blob The data to store.
-     * @param listener The listener that will be invoked to return the answer, or null if the
-     *        is not interested in learning about success/failure.
-     * Through the listener, returns a status to indicate success or failure.
-     */
-    @Override
-    public void storeBlob(@Nullable final String l2Key, @Nullable final String clientId,
-            @Nullable final String name, @Nullable final Blob blob,
-            @Nullable final IOnStatusListener listener) {
-        final byte[] data = null == blob ? null : blob.data;
-        mExecutor.execute(() -> {
-            try {
-                final int code = storeNetworkAttributesAndBlobSync(l2Key,
-                        null /* NetworkAttributes */, clientId, name, data);
-                if (null != listener) listener.onComplete(makeStatus(code));
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    /**
-     * Helper method for storeNetworkAttributes and storeBlob.
-     *
-     * Either attributes or none of clientId, name and data may be null. This will write the
-     * passed data if non-null, and will write attributes if non-null, but in any case it will
-     * bump the relevance up.
-     * Returns a success code from Status.
-     */
-    private int storeNetworkAttributesAndBlobSync(@Nullable final String l2Key,
-            @Nullable final NetworkAttributes attributes,
-            @Nullable final String clientId,
-            @Nullable final String name, @Nullable final byte[] data) {
-        if (null == l2Key) return ERROR_ILLEGAL_ARGUMENT;
-        if (null == attributes && null == data) return ERROR_ILLEGAL_ARGUMENT;
-        if (null != data && (null == clientId || null == name)) return ERROR_ILLEGAL_ARGUMENT;
-        if (null == mDb) return ERROR_DATABASE_CANNOT_BE_OPENED;
-        try {
-            final long oldExpiry = IpMemoryStoreDatabase.getExpiry(mDb, l2Key);
-            final long newExpiry = RelevanceUtils.bumpExpiryDate(
-                    oldExpiry == EXPIRY_ERROR ? System.currentTimeMillis() : oldExpiry);
-            final int errorCode =
-                    IpMemoryStoreDatabase.storeNetworkAttributes(mDb, l2Key, newExpiry, attributes);
-            // If no blob to store, the client is interested in the result of storing the attributes
-            if (null == data) return errorCode;
-            // Otherwise it's interested in the result of storing the blob
-            return IpMemoryStoreDatabase.storeBlob(mDb, l2Key, clientId, name, data);
-        } catch (Exception e) {
-            if (DBG) {
-                Log.e(TAG, "Exception while storing for key {" + l2Key
-                        + "} ; NetworkAttributes {" + (null == attributes ? "null" : attributes)
-                        + "} ; clientId {" + (null == clientId ? "null" : clientId)
-                        + "} ; name {" + (null == name ? "null" : name)
-                        + "} ; data {" + Utils.byteArrayToString(data) + "}", e);
-            }
-        }
-        return ERROR_GENERIC;
-    }
-
-    /**
-     * Returns the best L2 key associated with the attributes.
-     *
-     * This will find a record that would be in the same group as the passed attributes. This is
-     * useful to choose the key for storing a sample or private data when the L2 key is not known.
-     * If multiple records are group-close to these attributes, the closest match is returned.
-     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
-     * order) L2 key is returned.
-     * If no record matches these attributes, null is returned.
-     *
-     * @param attributes The attributes of the network to find.
-     * @param listener The listener that will be invoked to return the answer.
-     * Through the listener, returns the L2 key if one matched, or null.
-     */
-    @Override
-    public void findL2Key(@Nullable final NetworkAttributesParcelable attributes,
-            @Nullable final IOnL2KeyResponseListener listener) {
-        if (null == listener) return;
-        mExecutor.execute(() -> {
-            try {
-                if (null == attributes) {
-                    listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
-                    return;
-                }
-                if (null == mDb) {
-                    listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
-                    return;
-                }
-                final String key = IpMemoryStoreDatabase.findClosestAttributes(mDb,
-                        new NetworkAttributes(attributes));
-                listener.onL2KeyResponse(makeStatus(SUCCESS), key);
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    /**
-     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
-     * to the same L3 network. Group-closeness is used to determine this.
-     *
-     * @param l2Key1 The key for the first network.
-     * @param l2Key2 The key for the second network.
-     * @param listener The listener that will be invoked to return the answer.
-     * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
-     */
-    @Override
-    public void isSameNetwork(@Nullable final String l2Key1, @Nullable final String l2Key2,
-            @Nullable final IOnSameL3NetworkResponseListener listener) {
-        if (null == listener) return;
-        mExecutor.execute(() -> {
-            try {
-                if (null == l2Key1 || null == l2Key2) {
-                    listener.onSameL3NetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
-                    return;
-                }
-                if (null == mDb) {
-                    listener.onSameL3NetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
-                    return;
-                }
-                try {
-                    final NetworkAttributes attr1 =
-                            IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key1);
-                    final NetworkAttributes attr2 =
-                            IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key2);
-                    if (null == attr1 || null == attr2) {
-                        listener.onSameL3NetworkResponse(makeStatus(SUCCESS),
-                                new SameL3NetworkResponse(l2Key1, l2Key2,
-                                        -1f /* never connected */).toParcelable());
-                        return;
-                    }
-                    final float confidence = attr1.getNetworkGroupSamenessConfidence(attr2);
-                    listener.onSameL3NetworkResponse(makeStatus(SUCCESS),
-                            new SameL3NetworkResponse(l2Key1, l2Key2, confidence).toParcelable());
-                } catch (Exception e) {
-                    listener.onSameL3NetworkResponse(makeStatus(ERROR_GENERIC), null);
-                }
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    /**
-     * Retrieve the network attributes for a key.
-     * If no record is present for this key, this will return null attributes.
-     *
-     * @param l2Key The key of the network to query.
-     * @param listener The listener that will be invoked to return the answer.
-     * Through the listener, returns the network attributes and the L2 key associated with
-     *         the query.
-     */
-    @Override
-    public void retrieveNetworkAttributes(@Nullable final String l2Key,
-            @Nullable final IOnNetworkAttributesRetrievedListener listener) {
-        if (null == listener) return;
-        mExecutor.execute(() -> {
-            try {
-                if (null == l2Key) {
-                    listener.onNetworkAttributesRetrieved(
-                            makeStatus(ERROR_ILLEGAL_ARGUMENT), l2Key, null);
-                    return;
-                }
-                if (null == mDb) {
-                    listener.onNetworkAttributesRetrieved(
-                            makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), l2Key, null);
-                    return;
-                }
-                try {
-                    final NetworkAttributes attributes =
-                            IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key);
-                    listener.onNetworkAttributesRetrieved(makeStatus(SUCCESS), l2Key,
-                            null == attributes ? null : attributes.toParcelable());
-                } catch (final Exception e) {
-                    listener.onNetworkAttributesRetrieved(makeStatus(ERROR_GENERIC), l2Key, null);
-                }
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    /**
-     * Retrieve previously stored private data.
-     * If no data was stored for this L2 key and name this will return null.
-     *
-     * @param l2Key The L2 key.
-     * @param clientId The id of the client that stored this data.
-     * @param name The name of the data.
-     * @param listener The listener that will be invoked to return the answer.
-     * Through the listener, returns the private data if any or null if none, with the L2 key
-     *         and the name of the data associated with the query.
-     */
-    @Override
-    public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
-            @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
-        if (null == listener) return;
-        mExecutor.execute(() -> {
-            try {
-                if (null == l2Key) {
-                    listener.onBlobRetrieved(makeStatus(ERROR_ILLEGAL_ARGUMENT), l2Key, name, null);
-                    return;
-                }
-                if (null == mDb) {
-                    listener.onBlobRetrieved(makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), l2Key,
-                            name, null);
-                    return;
-                }
-                try {
-                    final Blob b = new Blob();
-                    b.data = IpMemoryStoreDatabase.retrieveBlob(mDb, l2Key, clientId, name);
-                    listener.onBlobRetrieved(makeStatus(SUCCESS), l2Key, name, b);
-                } catch (final Exception e) {
-                    listener.onBlobRetrieved(makeStatus(ERROR_GENERIC), l2Key, name, null);
-                }
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    /**
-     * Wipe the data in IpMemoryStore database upon network factory reset.
-     */
-    @Override
-    public void factoryReset() {
-        mExecutor.execute(() -> IpMemoryStoreDatabase.wipeDataUponNetworkReset(mDb));
-    }
-
-    /** Get db size threshold. */
-    @VisibleForTesting
-    protected int getDbSizeThreshold() {
-        return DATABASE_SIZE_THRESHOLD;
-    }
-
-    private long getDbSize() {
-        final File dbFile = new File(mDb.getPath());
-        try {
-            return dbFile.length();
-        } catch (final SecurityException e) {
-            if (DBG) Log.e(TAG, "Read db size access deny.", e);
-            // Return zero value if can't get disk usage exactly.
-            return 0;
-        }
-    }
-
-    /** Check if db size is over the threshold. */
-    @VisibleForTesting
-    boolean isDbSizeOverThreshold() {
-        return getDbSize() > getDbSizeThreshold();
-    }
-
-    /**
-     * Full maintenance.
-     *
-     * @param listener A listener to inform of the completion of this call.
-     */
-    void fullMaintenance(@NonNull final IOnStatusListener listener,
-            @NonNull final InterruptMaintenance interrupt) {
-        mExecutor.execute(() -> {
-            try {
-                if (null == mDb) {
-                    listener.onComplete(makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED));
-                    return;
-                }
-
-                // Interrupt maintenance because the scheduling job has been canceled.
-                if (checkForInterrupt(listener, interrupt)) return;
-
-                int result = SUCCESS;
-                // Drop all records whose relevance has decayed to zero.
-                // This is the first step to decrease memory store size.
-                result = IpMemoryStoreDatabase.dropAllExpiredRecords(mDb);
-
-                if (checkForInterrupt(listener, interrupt)) return;
-
-                // Aggregate historical data in passes
-                // TODO : Waiting for historical data implement.
-
-                // Check if db size meets the storage goal(10MB). If not, keep dropping records and
-                // aggregate historical data until the storage goal is met. Use for loop with 500
-                // times restriction to prevent infinite loop (Deleting records always fail and db
-                // size is still over the threshold)
-                for (int i = 0; isDbSizeOverThreshold() && i < MAX_DROP_RECORD_TIMES; i++) {
-                    if (checkForInterrupt(listener, interrupt)) return;
-
-                    final int totalNumber = IpMemoryStoreDatabase.getTotalRecordNumber(mDb);
-                    final long dbSize = getDbSize();
-                    final float decreaseRate = (dbSize == 0)
-                            ? 0 : (float) (dbSize - getDbSizeThreshold()) / (float) dbSize;
-                    final int deleteNumber = Math.max(
-                            (int) (totalNumber * decreaseRate), MIN_DELETE_NUM);
-
-                    result = IpMemoryStoreDatabase.dropNumberOfRecords(mDb, deleteNumber);
-
-                    if (checkForInterrupt(listener, interrupt)) return;
-
-                    // Aggregate historical data
-                    // TODO : Waiting for historical data implement.
-                }
-                listener.onComplete(makeStatus(result));
-            } catch (final RemoteException e) {
-                // Client at the other end died
-            }
-        });
-    }
-
-    private boolean checkForInterrupt(@NonNull final IOnStatusListener listener,
-            @NonNull final InterruptMaintenance interrupt) throws RemoteException {
-        if (!interrupt.isInterrupted()) return false;
-        listener.onComplete(makeStatus(ERROR_INTERNAL_INTERRUPTED));
-        return true;
-    }
-
-    @Override
-    public int getInterfaceVersion() {
-        return this.VERSION;
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
deleted file mode 100644
index bea7052..0000000
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.connectivity.ipmemorystore;
-
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.ipmemorystore.IOnStatusListener;
-import android.net.ipmemorystore.Status;
-import android.net.ipmemorystore.StatusParcelable;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Regular maintenance job service.
- * @hide
- */
-public final class RegularMaintenanceJobService extends JobService {
-    // Must be unique within the system server uid.
-    public static final int REGULAR_MAINTENANCE_ID = 3345678;
-
-    /**
-     * Class for interrupt check of maintenance job.
-     */
-    public static final class InterruptMaintenance {
-        private volatile boolean mIsInterrupted;
-        private final int mJobId;
-
-        public InterruptMaintenance(int jobId) {
-            mJobId = jobId;
-            mIsInterrupted = false;
-        }
-
-        public int getJobId() {
-            return mJobId;
-        }
-
-        public void setInterrupted(boolean interrupt) {
-            mIsInterrupted = interrupt;
-        }
-
-        public boolean isInterrupted() {
-            return mIsInterrupted;
-        }
-    }
-
-    private static final ArrayList<InterruptMaintenance> sInterruptList = new ArrayList<>();
-    private static IpMemoryStoreService sIpMemoryStoreService;
-
-    @Override
-    public boolean onStartJob(JobParameters params) {
-        if (sIpMemoryStoreService == null) {
-            Log.wtf("RegularMaintenanceJobService",
-                    "Can not start job because sIpMemoryStoreService is null.");
-            return false;
-        }
-        final InterruptMaintenance im = new InterruptMaintenance(params.getJobId());
-        sInterruptList.add(im);
-
-        sIpMemoryStoreService.fullMaintenance(new IOnStatusListener() {
-            @Override
-            public void onComplete(final StatusParcelable statusParcelable) throws RemoteException {
-                final Status result = new Status(statusParcelable);
-                if (!result.isSuccess()) {
-                    Log.e("RegularMaintenanceJobService", "Regular maintenance failed."
-                            + " Error is " + result.resultCode);
-                }
-                sInterruptList.remove(im);
-                jobFinished(params, !result.isSuccess());
-            }
-
-            @Override
-            public int getInterfaceVersion() {
-                return this.VERSION;
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-        }, im);
-        return true;
-    }
-
-    @Override
-    public boolean onStopJob(JobParameters params) {
-        final int jobId = params.getJobId();
-        for (InterruptMaintenance im : sInterruptList) {
-            if (im.getJobId() == jobId) {
-                im.setInterrupted(true);
-            }
-        }
-        return true;
-    }
-
-    /** Schedule regular maintenance job */
-    static void schedule(Context context, IpMemoryStoreService ipMemoryStoreService) {
-        final JobScheduler jobScheduler =
-                (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-
-        final ComponentName maintenanceJobName =
-                new ComponentName(context, RegularMaintenanceJobService.class);
-
-        // Regular maintenance is scheduled for when the device is idle with access power and a
-        // minimum interval of one day.
-        final JobInfo regularMaintenanceJob =
-                new JobInfo.Builder(REGULAR_MAINTENANCE_ID, maintenanceJobName)
-                        .setRequiresDeviceIdle(true)
-                        .setRequiresCharging(true)
-                        .setRequiresBatteryNotLow(true)
-                        .setPeriodic(TimeUnit.HOURS.toMillis(24)).build();
-
-        jobScheduler.schedule(regularMaintenanceJob);
-        sIpMemoryStoreService = ipMemoryStoreService;
-    }
-
-    /** Unschedule regular maintenance job */
-    static void unschedule(Context context) {
-        final JobScheduler jobScheduler =
-                (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-        jobScheduler.cancel(REGULAR_MAINTENANCE_ID);
-        sIpMemoryStoreService = null;
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
deleted file mode 100644
index 38d5544..0000000
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (C) 2018 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.connectivity.ipmemorystore;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * A class containing the logic around the relevance value for
- * IP Memory Store.
- *
- * @hide
- */
-public class RelevanceUtils {
-    /**
-     * The relevance is a decaying value that gets lower and lower until it
-     * reaches 0 after some time passes. It follows an exponential decay law,
-     * dropping slowly at first then faster and faster, because a network is
-     * likely to be visited again if it was visited not long ago, and the longer
-     * it hasn't been visited the more likely it is that it won't be visited
-     * again. For example, a network visited on holiday should stay fresh for
-     * the duration of the holiday and persist for a while, but after the venue
-     * hasn't been visited for a while it should quickly be discarded. What
-     * should accelerate forgetting the network is extended periods without
-     * visits, so that occasional venues get discarded but regular visits keep
-     * the network relevant, even if the visits are infrequent.
-     *
-     * This function must be stable by iteration, meaning that adjusting the same value
-     * for different dates iteratively multiple times should give the same result.
-     * Formally, if f is the decay function that associates a relevance x at a date d1
-     * to the value at ulterior date d3, then for any date d2 between d1 and d3 :
-     * f(x, d3 - d1) = f(f(x, d3 - d2), d2 - d1). Intuitively, this property simply
-     * means it should be the same to compute and store back the value after two months,
-     * or to do it once after one month, store it back, and do it again after another
-     * months has passed.
-     * The pair of the relevance and date define the entire curve, so any pair
-     * of values on the curve will define the same curve. Setting one of them to a
-     * constant, so as not to have to store it, means the other one will always suffice
-     * to describe the curve. For example, only storing the date for a known, constant
-     * value of the relevance is an efficient way of remembering this information (and
-     * to compare relevances together, as f is monotonically decreasing).
-     *
-     *** Choosing the function :
-     * Functions of the kind described above are standard exponential decay functions
-     * like the ones that govern atomic decay where the value at any given date can be
-     * computed uniformly from the value at a previous date and the time elapsed since
-     * that date. It is simple to picture this kind of function as one where after a
-     * given period of time called the half-life, the relevance value will have been
-     * halved. Decay of this kind is expressed in function of the previous value by
-     * functions like
-     * f(x, t) = x * F ^ (t / L)
-     * ...where x is the value, t is the elapsed time, L is the half-life (or more
-     * generally the F-th-life) and F the decay factor (typically 0.5, hence why L is
-     * usually called the half-life). The ^ symbol here is used for exponentiation.
-     * Or, starting at a given M for t = 0 :
-     * f(t) = M * F ^ (t / L)
-     *
-     * Because a line in the store needs to become irrelevant at some point but
-     * this class of functions never go to 0, a minimum cutoff has to be chosen to
-     * represent irrelevance. The simpler way of doing this is to simply add this
-     * minimum cutoff to the computation before and removing it after.
-     * Thus the function becomes :
-     * f(x, t) = ((x + K) * F ^ (t / L)) - K
-     * ...where K is the minimum cutoff, L the half-life, and F the factor between
-     * the original x and x after its half-life. Strictly speaking using the word
-     * "half-life" implies that F = 0.5, but the relation works for any value of F.
-     *
-     * It is easy enough to check that this function satisfies the stability
-     * relation that was given above for any value of F, L and K, which become
-     * parameters that can be defined at will.
-     *
-     * relevance
-     *  1.0 |
-     *      |\
-     *      | \
-     *      |  \            (this graph rendered with L = 75 days and K = 1/40)
-     *  0.75|   ',
-     *      |     \
-     *      |      '.
-     *      |        \.
-     *      |          \
-     *  0.5 |           '\
-     *      |             ''.
-     *      |                ''.
-     *      |                   ''.
-     *  0.25|                      '''..
-     *      |                           '''..
-     *      |                                ''''....
-     *      |                                        '''''..........
-     *    0 +-------------------------------------------------------''''''''''----
-     *      0       50       100      150     200      250     300      350     400 days
-     *
-     *** Choosing the parameters
-     * The maximum M is an arbitrary parameter that simply scales the curve.
-     * The tradeoff for M is pretty simple : if the relevance is going to be an
-     * integer, the bigger M is the more precision there is in the relevance.
-     * However, values of M that are easy for humans to read are preferable to
-     * help debugging, and a suitably low value may be enough to ensure there
-     * won't be integer overflows in intermediate computations.
-     * A value of 1_000_000 probably is plenty for precision, while still in the
-     * low range of what ints can represent.
-     *
-     * F and L are parameters to be chosen arbitrarily and have an impact on how
-     * fast the relevance will be decaying at first, keeping in mind that
-     * the 400 days value and the cap stay the same. In simpler words, F and L
-     * define the steepness of the curve.
-     * To keep things simple (and familiar) F is arbitrarily chosen to be 0.5, and
-     * L is set to 200 days visually to achieve the desired effect. Refer to the
-     * illustration above to get a feel of how that feels.
-     *
-     * Moreover, the memory store works on an assumption that the relevance should
-     * be capped, and that an entry with capped relevance should decay in 400 days.
-     * This is on premises that the networks a device will need to remember the
-     * longest should be networks visited about once a year.
-     * For this reason, the relevance is at the maximum M 400 days before expiry :
-     * f(M, 400 days) = 0
-     * From replacing this with the value of the function, K can then be derived
-     * from the values of M, F and L :
-     * (M + K) * F ^ (t / L) - K = 0
-     * K = M * F ^ (400 days / L) / (1 - F ^ (400 days / L))
-     * Replacing with actual values this gives :
-     * K = 1_000_000 * 0.5 ^ (400 / 200) / (1 - 0.5 ^ (400 / 200))
-     *   = 1_000_000 / 3 ≈ 333_333.3
-     * This ensures the function has the desired profile, the desired value at
-     * cap, and the desired value at expiry.
-     *
-     *** Useful relations
-     * Let's define the expiry time for any given relevance x as the interval of
-     * time such as :
-     * f(x, expiry) = 0
-     * which can be rewritten
-     * ((x + K) * F ^ (expiry / L)) = K
-     * ...giving an expression of the expiry in function of the relevance x as
-     * expiry = L * logF(K / (x + K))
-     * Conversely the relevance x can be expressed in function of the expiry as
-     * x = K / F ^ (expiry / L) - K
-     * These relations are useful in utility functions.
-     *
-     *** Bumping things up
-     * The last issue therefore is to decide how to bump up the relevance. The
-     * simple approach is to simply lift up the curve a little bit by a constant
-     * normalized amount, delaying the time of expiry. For example increasing
-     * the relevance by an amount I gives :
-     * x2 = x1 + I
-     * x2 and x1 correspond to two different expiry times expiry2 and expiry1,
-     * and replacing x1 and x2 in the relation above with their expression in
-     * function of the expiry comes :
-     * K / F ^ (expiry2 / L) - K = K / F ^ (expiry1 / L) - K + I
-     * which resolves to :
-     * expiry2 = L * logF(K / (I + K / F ^ (expiry1 / L)))
-     *
-     * In this implementation, the bump is defined as 1/25th of the cap for
-     * the relevance. This means a network will be remembered for the maximum
-     * period of 400 days if connected 25 times in succession not accounting
-     * for decay. Of course decay actually happens so it will take more than 25
-     * connections for any given network to actually reach the cap, but because
-     * decay is slow at first, it is a good estimate of how fast cap happens.
-     *
-     * Specifically, it gives the following four results :
-     * - A network that a device connects to once hits irrelevance about 32.7 days after
-     *   it was first registered if never connected again.
-     * - A network that a device connects to once a day at a fixed hour will hit the cap
-     *   on the 27th connection.
-     * - A network that a device connects to once a week at a fixed hour will hit the cap
-     *   on the 57th connection.
-     * - A network that a device connects to every day for 7 straight days then never again
-     *   expires 144 days after the last connection.
-     * These metrics tend to match pretty well the requirements.
-     */
-
-    // TODO : make these constants configurable at runtime. Don't forget to build it so that
-    // changes will wipe the database, migrate the values, or otherwise make sure the relevance
-    // values are still meaningful.
-
-    // How long, in milliseconds, is a capped relevance valid for, or in other
-    // words how many milliseconds after its relevance was set to RELEVANCE_CAP does
-    // any given line expire. 400 days.
-    @VisibleForTesting
-    public static final long CAPPED_RELEVANCE_LIFETIME_MS = 400L * 24 * 60 * 60 * 1000;
-
-    // The constant that represents a normalized 1.0 value for the relevance. In other words,
-    // the cap for the relevance. This is referred to as M in the explanation above.
-    @VisibleForTesting
-    public static final int CAPPED_RELEVANCE = 1_000_000;
-
-    // The decay factor. After a half-life, the relevance will have decayed by this value.
-    // This is referred to as F in the explanation above.
-    private static final double DECAY_FACTOR = 0.5;
-
-    // The half-life. After this time, the relevance will have decayed by a factor DECAY_FACTOR.
-    // This is referred to as L in the explanation above.
-    private static final long HALF_LIFE_MS = 200L * 24 * 60 * 60 * 1000;
-
-    // The value of the frame change. This is referred to as K in the explanation above.
-    private static final double IRRELEVANCE_FLOOR =
-            CAPPED_RELEVANCE * powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS)
-            / (1 - powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS));
-
-    // How much to bump the relevance by every time a line is written to.
-    @VisibleForTesting
-    public static final int RELEVANCE_BUMP = CAPPED_RELEVANCE / 25;
-
-    // Java doesn't include a function for the logarithm in an arbitrary base, so implement it
-    private static final double LOG_DECAY_FACTOR = Math.log(DECAY_FACTOR);
-    private static double logF(final double value) {
-        return Math.log(value) / LOG_DECAY_FACTOR;
-    }
-
-    // Utility function to get a power of the decay factor, to simplify the code.
-    private static double powF(final double value) {
-        return Math.pow(DECAY_FACTOR, value);
-    }
-
-    /**
-     * Compute the value of the relevance now given an expiry date.
-     *
-     * @param expiry the date at which the column in the database expires.
-     * @return the adjusted value of the relevance for this moment in time.
-     */
-    public static int computeRelevanceForNow(final long expiry) {
-        return computeRelevanceForTargetDate(expiry, System.currentTimeMillis());
-    }
-
-    /**
-     * Compute the value of the relevance at a given date from an expiry date.
-     *
-     * Because relevance decays with time, a relevance in the past corresponds to
-     * a different relevance later.
-     *
-     * Relevance is always a positive value. 0 means not relevant at all.
-     *
-     * See the explanation at the top of this file to get the justification for this
-     * computation.
-     *
-     * @param expiry the date at which the column in the database expires.
-     * @param target the target date to adjust the relevance to.
-     * @return the adjusted value of the relevance for the target moment.
-     */
-    public static int computeRelevanceForTargetDate(final long expiry, final long target) {
-        final long delay = expiry - target;
-        if (delay >= CAPPED_RELEVANCE_LIFETIME_MS) return CAPPED_RELEVANCE;
-        if (delay <= 0) return 0;
-        return (int) (IRRELEVANCE_FLOOR / powF((float) delay / HALF_LIFE_MS) - IRRELEVANCE_FLOOR);
-    }
-
-    /**
-     * Compute the expiry duration adjusted up for a new fresh write.
-     *
-     * Every time data is written to the memory store for a given line, the
-     * relevance is bumped up by a certain amount, which will boost the priority
-     * of this line for computation of group attributes, and delay (possibly
-     * indefinitely, if the line is accessed regularly) forgetting the data stored
-     * in that line.
-     * As opposed to bumpExpiryDate, this function uses a duration from now to expiry.
-     *
-     * See the explanation at the top of this file for a justification of this computation.
-     *
-     * @param oldExpiryDuration the old expiry duration in milliseconds from now.
-     * @return the expiry duration representing a bumped up relevance value.
-     */
-    public static long bumpExpiryDuration(final long oldExpiryDuration) {
-        // L * logF(K / (I + K / F ^ (expiry1 / L))), as documented above
-        final double divisionFactor = powF(((double) oldExpiryDuration) / HALF_LIFE_MS);
-        final double oldRelevance = IRRELEVANCE_FLOOR / divisionFactor;
-        final long newDuration =
-                (long) (HALF_LIFE_MS * logF(IRRELEVANCE_FLOOR / (RELEVANCE_BUMP + oldRelevance)));
-        return Math.min(newDuration, CAPPED_RELEVANCE_LIFETIME_MS);
-    }
-
-    /**
-     * Compute the new expiry date adjusted up for a new fresh write.
-     *
-     * Every time data is written to the memory store for a given line, the
-     * relevance is bumped up by a certain amount, which will boost the priority
-     * of this line for computation of group attributes, and delay (possibly
-     * indefinitely, if the line is accessed regularly) forgetting the data stored
-     * in that line.
-     * As opposed to bumpExpiryDuration, this function takes the old timestamp and returns the
-     * new timestamp.
-     *
-     * {@see bumpExpiryDuration}, and keep in mind that the bump depends on when this is called,
-     * because the relevance decays exponentially, therefore bumping up a high relevance (for a
-     * date far in the future) is less potent than bumping up a low relevance (for a date in
-     * a close future).
-     *
-     * @param oldExpiryDate the old date of expiration.
-     * @return the new expiration date after the relevance bump.
-     */
-    public static long bumpExpiryDate(final long oldExpiryDate) {
-        final long now = System.currentTimeMillis();
-        final long newDuration = bumpExpiryDuration(oldExpiryDate - now);
-        return now + newDuration;
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
deleted file mode 100644
index 9cbf490..0000000
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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.connectivity.ipmemorystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.ipmemorystore.Blob;
-
-/** {@hide} */
-public class Utils {
-    /** Pretty print */
-    public static String blobToString(@Nullable final Blob blob) {
-        return "Blob : " + byteArrayToString(null == blob ? null : blob.data);
-    }
-
-    /** Pretty print */
-    public static String byteArrayToString(@Nullable final byte[] data) {
-        if (null == data) return "null";
-        final StringBuilder sb = new StringBuilder("[");
-        if (data.length <= 24) {
-            appendByteArray(sb, data, 0, data.length);
-        } else {
-            appendByteArray(sb, data, 0, 16);
-            sb.append("...");
-            appendByteArray(sb, data, data.length - 8, data.length);
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    // Adds the hex representation of the array between the specified indices (inclusive, exclusive)
-    private static void appendByteArray(@NonNull final StringBuilder sb, @NonNull final byte[] ar,
-            final int from, final int to) {
-        for (int i = from; i < to; ++i) {
-            sb.append(String.format("%02X", ar[i]));
-        }
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
deleted file mode 100644
index 804765e..0000000
--- a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2018 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.util;
-
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-
-import java.net.Inet4Address;
-
-/**
- * Network constants used by the network stack.
- */
-public final class NetworkStackConstants {
-
-    /**
-     * IPv4 constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc791
-     */
-    public static final int IPV4_ADDR_BITS = 32;
-    public static final int IPV4_MIN_MTU = 68;
-    public static final int IPV4_MAX_MTU = 65_535;
-
-    /**
-     * Ethernet constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc894
-     *     - https://tools.ietf.org/html/rfc2464
-     *     - https://tools.ietf.org/html/rfc7042
-     *     - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml
-     *     - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
-     */
-    public static final int ETHER_DST_ADDR_OFFSET = 0;
-    public static final int ETHER_SRC_ADDR_OFFSET = 6;
-    public static final int ETHER_ADDR_LEN = 6;
-    public static final int ETHER_TYPE_OFFSET = 12;
-    public static final int ETHER_TYPE_LENGTH = 2;
-    public static final int ETHER_TYPE_ARP  = 0x0806;
-    public static final int ETHER_TYPE_IPV4 = 0x0800;
-    public static final int ETHER_TYPE_IPV6 = 0x86dd;
-    public static final int ETHER_HEADER_LEN = 14;
-
-    /**
-     * ARP constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc826
-     *     - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
-     */
-    public static final int ARP_PAYLOAD_LEN = 28;  // For Ethernet+IPv4.
-    public static final int ARP_REQUEST = 1;
-    public static final int ARP_REPLY   = 2;
-    public static final int ARP_HWTYPE_RESERVED_LO = 0;
-    public static final int ARP_HWTYPE_ETHER       = 1;
-    public static final int ARP_HWTYPE_RESERVED_HI = 0xffff;
-
-    /**
-     * IPv4 constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc791
-     */
-    public static final int IPV4_HEADER_MIN_LEN = 20;
-    public static final int IPV4_IHL_MASK = 0xf;
-    public static final int IPV4_FLAGS_OFFSET = 6;
-    public static final int IPV4_FRAGMENT_MASK = 0x1fff;
-    public static final int IPV4_PROTOCOL_OFFSET = 9;
-    public static final int IPV4_SRC_ADDR_OFFSET = 12;
-    public static final int IPV4_DST_ADDR_OFFSET = 16;
-    public static final int IPV4_ADDR_LEN = 4;
-    public static final Inet4Address IPV4_ADDR_ALL = intToInet4AddressHTH(0xffffffff);
-    public static final Inet4Address IPV4_ADDR_ANY = intToInet4AddressHTH(0x0);
-
-    /**
-     * IPv6 constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc2460
-     */
-    public static final int IPV6_ADDR_LEN = 16;
-    public static final int IPV6_HEADER_LEN = 40;
-    public static final int IPV6_PROTOCOL_OFFSET = 6;
-    public static final int IPV6_SRC_ADDR_OFFSET = 8;
-    public static final int IPV6_DST_ADDR_OFFSET = 24;
-
-    /**
-     * ICMPv6 constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc4443
-     *     - https://tools.ietf.org/html/rfc4861
-     */
-    public static final int ICMPV6_HEADER_MIN_LEN = 4;
-    public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
-    public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
-    public static final int ICMPV6_ROUTER_SOLICITATION    = 133;
-    public static final int ICMPV6_ROUTER_ADVERTISEMENT   = 134;
-    public static final int ICMPV6_NEIGHBOR_SOLICITATION  = 135;
-    public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
-    public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8;
-    public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8;
-    public static final int ICMPV6_ND_OPTION_SLLA = 1;
-    public static final int ICMPV6_ND_OPTION_TLLA = 2;
-    public static final int ICMPV6_ND_OPTION_MTU  = 5;
-
-    /**
-     * UDP constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc768
-     */
-    public static final int UDP_HEADER_LEN = 8;
-
-
-    /**
-     * DHCP constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc2131
-     */
-    public static final int INFINITE_LEASE = 0xffffffff;
-    public static final int DHCP4_CLIENT_PORT = 68;
-
-    private NetworkStackConstants() {
-        throw new UnsupportedOperationException("This class is not to be instantiated");
-    }
-}
diff --git a/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
deleted file mode 100644
index 6fbeead..0000000
--- a/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2018 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.util;
-
-import static android.os.Binder.getCallingUid;
-
-import android.os.Process;
-import android.os.UserHandle;
-
-/**
- * Utility class to check calling permissions on the network stack.
- */
-public final class PermissionUtil {
-
-    /**
-     * Check that the caller is allowed to communicate with the network stack.
-     * @throws SecurityException The caller is not allowed to communicate with the network stack.
-     */
-    public static void checkNetworkStackCallingPermission() {
-        // TODO: check that the calling PID is the system server.
-        final int caller = getCallingUid();
-        if (caller != Process.SYSTEM_UID
-                && UserHandle.getAppId(caller) != Process.BLUETOOTH_UID
-                && UserHandle.getAppId(caller) != Process.PHONE_UID) {
-            throw new SecurityException("Invalid caller: " + caller);
-        }
-    }
-
-    /**
-     * Check that the caller is allowed to dump the network stack, e.g. dumpsys.
-     * @throws SecurityException The caller is not allowed to dump the network stack.
-     */
-    public static void checkDumpPermission() {
-        final int caller = getCallingUid();
-        if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID
-                && caller != Process.SHELL_UID) {
-            throw new SecurityException("No dump permissions for caller: " + caller);
-        }
-    }
-
-    private PermissionUtil() {
-        throw new UnsupportedOperationException("This class is not to be instantiated");
-    }
-}
diff --git a/packages/NetworkStack/tests/lib/Android.bp b/packages/NetworkStack/tests/lib/Android.bp
deleted file mode 100644
index f45a81c..0000000
--- a/packages/NetworkStack/tests/lib/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// 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.
-//
-
-java_library {
-    name: "net-tests-utils",
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-    ],
-    static_libs: [
-        "kotlin-test",
-    ],
-}
diff --git a/packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt b/packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt
deleted file mode 100644
index 3dce5a5..0000000
--- a/packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.testutils
-
-import android.os.ConditionVariable
-import android.os.Handler
-import android.os.HandlerThread
-import java.util.concurrent.Executor
-import kotlin.test.fail
-
-/**
- * Block until the specified Handler or HandlerThread becomes idle, or until timeoutMs has passed.
- */
-fun Handler.waitForIdle(timeoutMs: Long) = waitForIdleHandler(this, timeoutMs)
-fun HandlerThread.waitForIdle(timeoutMs: Long) = waitForIdleHandler(this.threadHandler, timeoutMs)
-fun waitForIdleHandler(handler: HandlerThread, timeoutMs: Long) {
-    waitForIdleHandler(handler.threadHandler, timeoutMs)
-}
-fun waitForIdleHandler(handler: Handler, timeoutMs: Long) {
-    val cv = ConditionVariable(false)
-    handler.post(cv::open)
-    if (!cv.block(timeoutMs)) {
-        fail("Handler did not become idle after ${timeoutMs}ms")
-    }
-}
-
-/**
- * Block until the given Serial Executor becomes idle, or until timeoutMs has passed.
- */
-fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) {
-    val cv = ConditionVariable()
-    executor.execute(cv::open)
-    if (!cv.block(timeoutMs)) {
-        fail("Executor did not become idle after ${timeoutMs}ms")
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/Android.bp b/packages/NetworkStack/tests/unit/Android.bp
deleted file mode 100644
index 48b13b0..0000000
--- a/packages/NetworkStack/tests/unit/Android.bp
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// Copyright (C) 2018 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.
-//
-
-android_test {
-    name: "NetworkStackTests",
-    certificate: "platform",
-    srcs: ["src/**/*.java"],
-    test_suites: ["device-tests"],
-    resource_dirs: ["res"],
-    static_libs: [
-        "androidx.test.rules",
-        "mockito-target-extended-minus-junit4",
-        "net-tests-utils",
-        "NetworkStackBase",
-        "testables",
-    ],
-    libs: [
-        "android.test.runner",
-        "android.test.base",
-        "android.test.mock",
-    ],
-    jni_libs: [
-        // For mockito extended
-        "libdexmakerjvmtiagent",
-        "libstaticjvmtiagent",
-        // For ApfTest
-        "libbacktrace",
-        "libbase",
-        "libbinder",
-        "libbinderthreadstate",
-        "libc++",
-        "libcgrouprc",
-        "libcrypto",
-        "libcutils",
-        "ld-android",
-        "libdl_android",
-        "libhidl-gen-utils",
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libjsoncpp",
-        "liblog",
-        "liblzma",
-        "libnativehelper",
-        "libnativehelper_compat_libc++",
-        "libnetworkstacktestsjni",
-        "libnetworkstackutilsjni",
-        "libpackagelistparser",
-        "libpcre2",
-        "libprocessgroup",
-        "libselinux",
-        "libui",
-        "libutils",
-        "libvintf",
-        "libvndksupport",
-        "libtinyxml2",
-        "libunwindstack",
-        "libutilscallstack",
-        "libziparchive",
-        "libz",
-        "netd_aidl_interface-V2-cpp",
-    ],
-}
-
-cc_library_shared {
-    name: "libnetworkstacktestsjni",
-    srcs: [
-        "jni/**/*.cpp"
-    ],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-    include_dirs: [
-        "hardware/google/apf",
-    ],
-    shared_libs: [
-        "libbinder",
-        "liblog",
-        "libcutils",
-        "libnativehelper",
-        "netd_aidl_interface-V2-cpp",
-    ],
-    static_libs: [
-        "libapf",
-        "libpcap",
-    ],
-}
diff --git a/packages/NetworkStack/tests/unit/AndroidManifest.xml b/packages/NetworkStack/tests/unit/AndroidManifest.xml
deleted file mode 100644
index 5dcf6ff..0000000
--- a/packages/NetworkStack/tests/unit/AndroidManifest.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.server.networkstack.tests">
-
-    <uses-permission android:name="android.permission.READ_LOGS" />
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
-    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
-    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
-    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
-    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
-    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
-    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
-    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
-    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
-    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
-    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
-    <uses-permission android:name="android.permission.NETWORK_STACK" />
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.server.networkstack.tests"
-        android:label="Networking service tests">
-    </instrumentation>
-</manifest>
\ No newline at end of file
diff --git a/packages/NetworkStack/tests/unit/AndroidTest.xml b/packages/NetworkStack/tests/unit/AndroidTest.xml
deleted file mode 100644
index 047bc2e..0000000
--- a/packages/NetworkStack/tests/unit/AndroidTest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-<configuration description="Runs Tests for NetworkStack">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="NetworkStackTests.apk" />
-    </target_preparer>
-
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="framework-base-presubmit" />
-    <option name="test-tag" value="NetworkStackTests" />
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.server.networkstack.tests" />
-        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
-        <option name="hidden-api-checks" value="false"/>
-    </test>
-</configuration>
\ No newline at end of file
diff --git a/packages/NetworkStack/tests/unit/jni/apf_jni.cpp b/packages/NetworkStack/tests/unit/jni/apf_jni.cpp
deleted file mode 100644
index 4222adf..0000000
--- a/packages/NetworkStack/tests/unit/jni/apf_jni.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 2018, 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.
- */
-
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <jni.h>
-#include <pcap.h>
-#include <stdlib.h>
-#include <string>
-#include <utils/Log.h>
-#include <vector>
-
-#include "apf_interpreter.h"
-#include "nativehelper/scoped_primitive_array.h"
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-// JNI function acting as simply call-through to native APF interpreter.
-static jint com_android_server_ApfTest_apfSimulate(
-        JNIEnv* env, jclass, jbyteArray jprogram, jbyteArray jpacket,
-        jbyteArray jdata, jint filter_age) {
-
-    ScopedByteArrayRO packet(env, jpacket);
-    uint32_t packet_len = (uint32_t)packet.size();
-    uint32_t program_len = env->GetArrayLength(jprogram);
-    uint32_t data_len = jdata ? env->GetArrayLength(jdata) : 0;
-    std::vector<uint8_t> buf(program_len + data_len, 0);
-
-    env->GetByteArrayRegion(jprogram, 0, program_len, reinterpret_cast<jbyte*>(buf.data()));
-    if (jdata) {
-        // Merge program and data into a single buffer.
-        env->GetByteArrayRegion(jdata, 0, data_len,
-                                reinterpret_cast<jbyte*>(buf.data() + program_len));
-    }
-
-    jint result =
-        accept_packet(buf.data(), program_len, program_len + data_len,
-                        reinterpret_cast<const uint8_t*>(packet.get()), packet_len, filter_age);
-
-    if (jdata) {
-        env->SetByteArrayRegion(jdata, 0, data_len,
-                                reinterpret_cast<jbyte*>(buf.data() + program_len));
-    }
-
-    return result;
-}
-
-class ScopedPcap {
-  public:
-    explicit ScopedPcap(pcap_t* pcap) : pcap_ptr(pcap) {}
-    ~ScopedPcap() {
-        pcap_close(pcap_ptr);
-    }
-
-    pcap_t* get() const { return pcap_ptr; };
-  private:
-    pcap_t* const pcap_ptr;
-};
-
-class ScopedFILE {
-  public:
-    explicit ScopedFILE(FILE* fp) : file(fp) {}
-    ~ScopedFILE() {
-        fclose(file);
-    }
-
-    FILE* get() const { return file; };
-  private:
-    FILE* const file;
-};
-
-static void throwException(JNIEnv* env, const std::string& error) {
-    jclass newExcCls = env->FindClass("java/lang/IllegalStateException");
-    if (newExcCls == 0) {
-      abort();
-      return;
-    }
-    env->ThrowNew(newExcCls, error.c_str());
-}
-
-static jstring com_android_server_ApfTest_compileToBpf(JNIEnv* env, jclass, jstring jfilter) {
-    ScopedUtfChars filter(env, jfilter);
-    std::string bpf_string;
-    ScopedPcap pcap(pcap_open_dead(DLT_EN10MB, 65535));
-    if (pcap.get() == NULL) {
-        throwException(env, "pcap_open_dead failed");
-        return NULL;
-    }
-
-    // Compile "filter" to a BPF program
-    bpf_program bpf;
-    if (pcap_compile(pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) {
-        throwException(env, "pcap_compile failed");
-        return NULL;
-    }
-
-    // Translate BPF program to human-readable format
-    const struct bpf_insn* insn = bpf.bf_insns;
-    for (uint32_t i = 0; i < bpf.bf_len; i++) {
-        bpf_string += bpf_image(insn++, i);
-        bpf_string += "\n";
-    }
-
-    return env->NewStringUTF(bpf_string.c_str());
-}
-
-static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, jstring jfilter,
-        jstring jpcap_filename, jbyteArray japf_program) {
-    ScopedUtfChars filter(env, jfilter);
-    ScopedUtfChars pcap_filename(env, jpcap_filename);
-    ScopedByteArrayRO apf_program(env, japf_program);
-
-    // Open pcap file for BPF filtering
-    ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb"));
-    char pcap_error[PCAP_ERRBUF_SIZE];
-    ScopedPcap bpf_pcap(pcap_fopen_offline(bpf_fp.get(), pcap_error));
-    if (bpf_pcap.get() == NULL) {
-        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
-        return false;
-    }
-
-    // Open pcap file for APF filtering
-    ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb"));
-    ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error));
-    if (apf_pcap.get() == NULL) {
-        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
-        return false;
-    }
-
-    // Compile "filter" to a BPF program
-    bpf_program bpf;
-    if (pcap_compile(bpf_pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) {
-        throwException(env, "pcap_compile failed");
-        return false;
-    }
-
-    // Install BPF filter on bpf_pcap
-    if (pcap_setfilter(bpf_pcap.get(), &bpf)) {
-        throwException(env, "pcap_setfilter failed");
-        return false;
-    }
-
-    while (1) {
-        pcap_pkthdr bpf_header, apf_header;
-        // Run BPF filter to the next matching packet.
-        const uint8_t* bpf_packet = pcap_next(bpf_pcap.get(), &bpf_header);
-
-        // Run APF filter to the next matching packet.
-        const uint8_t* apf_packet;
-        do {
-            apf_packet = pcap_next(apf_pcap.get(), &apf_header);
-        } while (apf_packet != NULL && !accept_packet(
-                reinterpret_cast<uint8_t*>(const_cast<int8_t*>(apf_program.get())),
-                apf_program.size(), 0 /* data_len */,
-                apf_packet, apf_header.len, 0 /* filter_age */));
-
-        // Make sure both filters matched the same packet.
-        if (apf_packet == NULL && bpf_packet == NULL)
-            break;
-        if (apf_packet == NULL || bpf_packet == NULL)
-            return false;
-        if (apf_header.len != bpf_header.len ||
-                apf_header.ts.tv_sec != bpf_header.ts.tv_sec ||
-                apf_header.ts.tv_usec != bpf_header.ts.tv_usec ||
-                memcmp(apf_packet, bpf_packet, apf_header.len))
-            return false;
-    }
-    return true;
-}
-
-static jboolean com_android_server_ApfTest_dropsAllPackets(JNIEnv* env, jclass, jbyteArray jprogram,
-        jbyteArray jdata, jstring jpcap_filename) {
-    ScopedUtfChars pcap_filename(env, jpcap_filename);
-    ScopedByteArrayRO apf_program(env, jprogram);
-    uint32_t apf_program_len = (uint32_t)apf_program.size();
-    uint32_t data_len = env->GetArrayLength(jdata);
-    pcap_pkthdr apf_header;
-    const uint8_t* apf_packet;
-    char pcap_error[PCAP_ERRBUF_SIZE];
-    std::vector<uint8_t> buf(apf_program_len + data_len, 0);
-
-    // Merge program and data into a single buffer.
-    env->GetByteArrayRegion(jprogram, 0, apf_program_len, reinterpret_cast<jbyte*>(buf.data()));
-    env->GetByteArrayRegion(jdata, 0, data_len,
-                            reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
-
-    // Open pcap file
-    ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb"));
-    ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error));
-
-    if (apf_pcap.get() == NULL) {
-        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
-        return false;
-    }
-
-    while ((apf_packet = pcap_next(apf_pcap.get(), &apf_header)) != NULL) {
-        int result = accept_packet(buf.data(), apf_program_len,
-                                    apf_program_len + data_len, apf_packet, apf_header.len, 0);
-
-        // Return false once packet passes the filter
-        if (result) {
-            env->SetByteArrayRegion(jdata, 0, data_len,
-                                    reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
-            return false;
-         }
-    }
-
-    env->SetByteArrayRegion(jdata, 0, data_len,
-                            reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
-    return true;
-}
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
-    JNIEnv *env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        ALOGE("ERROR: GetEnv failed");
-        return -1;
-    }
-
-    static JNINativeMethod gMethods[] = {
-            { "apfSimulate", "([B[B[BI)I",
-                    (void*)com_android_server_ApfTest_apfSimulate },
-            { "compileToBpf", "(Ljava/lang/String;)Ljava/lang/String;",
-                    (void*)com_android_server_ApfTest_compileToBpf },
-            { "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z",
-                    (void*)com_android_server_ApfTest_compareBpfApf },
-            { "dropsAllPackets", "([B[BLjava/lang/String;)Z",
-                    (void*)com_android_server_ApfTest_dropsAllPackets },
-    };
-
-    jniRegisterNativeMethods(env, "android/net/apf/ApfTest",
-            gMethods, ARRAY_SIZE(gMethods));
-
-    return JNI_VERSION_1_6;
-}
diff --git a/packages/NetworkStack/tests/unit/res/raw/apf.pcap b/packages/NetworkStack/tests/unit/res/raw/apf.pcap
deleted file mode 100644
index 963165f..0000000
--- a/packages/NetworkStack/tests/unit/res/raw/apf.pcap
+++ /dev/null
Binary files differ
diff --git a/packages/NetworkStack/tests/unit/res/raw/apfPcap.pcap b/packages/NetworkStack/tests/unit/res/raw/apfPcap.pcap
deleted file mode 100644
index 6f69c4a..0000000
--- a/packages/NetworkStack/tests/unit/res/raw/apfPcap.pcap
+++ /dev/null
Binary files differ
diff --git a/packages/NetworkStack/tests/unit/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/unit/src/android/net/apf/ApfTest.java
deleted file mode 100644
index 8f2b968..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/apf/ApfTest.java
+++ /dev/null
@@ -1,2110 +0,0 @@
-/*
- * Copyright (C) 2012 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.apf;
-
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.ARPHRD_ETHER;
-import static android.system.OsConstants.ETH_P_ARP;
-import static android.system.OsConstants.ETH_P_IP;
-import static android.system.OsConstants.ETH_P_IPV6;
-import static android.system.OsConstants.IPPROTO_ICMPV6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_STREAM;
-
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
-
-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.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NattKeepalivePacketDataParcelable;
-import android.net.TcpKeepalivePacketDataParcelable;
-import android.net.apf.ApfFilter.ApfConfiguration;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IIpClientCallbacks;
-import android.net.ip.IpClient.IpClientCallbacksWrapper;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.RaEvent;
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.ConditionVariable;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.HexDump;
-import com.android.server.networkstack.tests.R;
-import com.android.server.util.NetworkStackConstants;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-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.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Tests for APF program generator and interpreter.
- *
- * Build, install and run with:
- *  runtest frameworks-net -c android.net.apf.ApfTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ApfTest {
-    private static final int TIMEOUT_MS = 500;
-    private static final int MIN_APF_VERSION = 2;
-
-    @Mock IpConnectivityLog mLog;
-    @Mock Context mContext;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        // Load up native shared library containing APF interpreter exposed via JNI.
-        System.loadLibrary("networkstacktestsjni");
-    }
-
-    private static final String TAG = "ApfTest";
-    // Expected return codes from APF interpreter.
-    private static final int PASS = 1;
-    private static final int DROP = 0;
-    // Interpreter will just accept packets without link layer headers, so pad fake packet to at
-    // least the minimum packet size.
-    private static final int MIN_PKT_SIZE = 15;
-
-    private static final ApfCapabilities MOCK_APF_CAPABILITIES =
-      new ApfCapabilities(2, 1700, ARPHRD_ETHER);
-
-    private static final boolean DROP_MULTICAST = true;
-    private static final boolean ALLOW_MULTICAST = false;
-
-    private static final boolean DROP_802_3_FRAMES = true;
-    private static final boolean ALLOW_802_3_FRAMES = false;
-
-    // Constants for opcode encoding
-    private static final byte LI_OP   = (byte)(13 << 3);
-    private static final byte LDDW_OP = (byte)(22 << 3);
-    private static final byte STDW_OP = (byte)(23 << 3);
-    private static final byte SIZE0   = (byte)(0 << 1);
-    private static final byte SIZE8   = (byte)(1 << 1);
-    private static final byte SIZE16  = (byte)(2 << 1);
-    private static final byte SIZE32  = (byte)(3 << 1);
-    private static final byte R1 = 1;
-
-    private static ApfConfiguration getDefaultConfig() {
-        ApfFilter.ApfConfiguration config = new ApfConfiguration();
-        config.apfCapabilities = MOCK_APF_CAPABILITIES;
-        config.multicastFilter = ALLOW_MULTICAST;
-        config.ieee802_3Filter = ALLOW_802_3_FRAMES;
-        config.ethTypeBlackList = new int[0];
-        return config;
-    }
-
-    private static String label(int code) {
-        switch (code) {
-            case PASS: return "PASS";
-            case DROP: return "DROP";
-            default:   return "UNKNOWN";
-        }
-    }
-
-    private static void assertReturnCodesEqual(int expected, int got) {
-        assertEquals(label(expected), label(got));
-    }
-
-    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, filterAge));
-    }
-
-    private void assertVerdict(int expected, byte[] program, byte[] packet) {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, 0));
-    }
-
-    private void assertPass(byte[] program, byte[] packet, int filterAge) {
-        assertVerdict(PASS, program, packet, filterAge);
-    }
-
-    private void assertPass(byte[] program, byte[] packet) {
-        assertVerdict(PASS, program, packet);
-    }
-
-    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
-        assertVerdict(DROP, program, packet, filterAge);
-    }
-
-    private void assertDrop(byte[] program, byte[] packet) {
-        assertVerdict(DROP, program, packet);
-    }
-
-    private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError {
-        // assertArrayEquals() would only print one byte, making debugging difficult.
-        if (!java.util.Arrays.equals(expected, program)) {
-            throw new AssertionError(
-                    "\nexpected: " + HexDump.toHexString(expected) +
-                    "\nactual:   " + HexDump.toHexString(program));
-        }
-    }
-
-    private void assertDataMemoryContents(
-            int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
-            throws IllegalInstructionException, Exception {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
-
-        // assertArrayEquals() would only print one byte, making debugging difficult.
-        if (!java.util.Arrays.equals(expected_data, data)) {
-            throw new Exception(
-                    "\nprogram:     " + HexDump.toHexString(program) +
-                    "\ndata memory: " + HexDump.toHexString(data) +
-                    "\nexpected:    " + HexDump.toHexString(expected_data));
-        }
-    }
-
-    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
-            throws IllegalInstructionException {
-        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
-              filterAge));
-    }
-
-    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
-            throws IllegalInstructionException {
-        assertVerdict(PASS, gen, packet, filterAge);
-    }
-
-    private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
-            throws IllegalInstructionException {
-        assertVerdict(DROP, gen, packet, filterAge);
-    }
-
-    private void assertPass(ApfGenerator gen)
-            throws IllegalInstructionException {
-        assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
-    }
-
-    private void assertDrop(ApfGenerator gen)
-            throws IllegalInstructionException {
-        assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
-    }
-
-    /**
-     * Test each instruction by generating a program containing the instruction,
-     * generating bytecode for that program and running it through the
-     * interpreter to verify it functions correctly.
-     */
-    @Test
-    public void testApfInstructions() throws IllegalInstructionException {
-        // Empty program should pass because having the program counter reach the
-        // location immediately after the program indicates the packet should be
-        // passed to the AP.
-        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
-        assertPass(gen);
-
-        // Test jumping to pass label.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJump(gen.PASS_LABEL);
-        byte[] program = gen.generate();
-        assertEquals(1, program.length);
-        assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
-        assertPass(program, new byte[MIN_PKT_SIZE], 0);
-
-        // Test jumping to drop label.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJump(gen.DROP_LABEL);
-        program = gen.generate();
-        assertEquals(2, program.length);
-        assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
-        assertEquals(1, program[1]);
-        assertDrop(program, new byte[15], 15);
-
-        // Test jumping if equal to 0.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if not equal to 0.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if registers equal.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if registers not equal.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test load immediate.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test add.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addAdd(1234567890);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test subtract.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addAdd(-1234567890);
-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test or.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addOr(1234567890);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test and.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addAnd(123456789);
-        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test left shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLeftShift(1);
-        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test right shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addRightShift(1);
-        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test multiply.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 123456789);
-        gen.addMul(2);
-        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addDiv(2);
-        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide by zero.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addDiv(0);
-        gen.addJump(gen.DROP_LABEL);
-        assertPass(gen);
-
-        // Test add.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addAddR1();
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test subtract.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, -1234567890);
-        gen.addAddR1();
-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test or.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addOrR1();
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test and.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, 123456789);
-        gen.addAndR1();
-        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test left shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLeftShiftR1();
-        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test right shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, -1);
-        gen.addLeftShiftR1();
-        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test multiply.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 123456789);
-        gen.addLoadImmediate(Register.R1, 2);
-        gen.addMulR1();
-        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, 2);
-        gen.addDivR1();
-        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide by zero.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addDivR1();
-        gen.addJump(gen.DROP_LABEL);
-        assertPass(gen);
-
-        // Test byte load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad8(Register.R0, 1);
-        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test out of bounds load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad8(Register.R0, 16);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test half-word load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad16(Register.R0, 1);
-        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test word load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad32(Register.R0, 1);
-        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test byte indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLoad8Indexed(Register.R0, 0);
-        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test out of bounds indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 8);
-        gen.addLoad8Indexed(Register.R0, 8);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test half-word indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLoad16Indexed(Register.R0, 0);
-        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test word indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLoad32Indexed(Register.R0, 0);
-        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test jumping if greater than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if less than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if any bits set.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 3);
-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if register greater than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 2);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if register less than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if any bits set in register.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 3);
-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 3);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 3);
-        gen.addLoadImmediate(Register.R0, 3);
-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test load from memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, 0);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test store to memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addStoreToMemory(Register.R1, 12);
-        gen.addLoadFromMemory(Register.R0, 12);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test filter age pre-filled memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
-
-        // Test packet size pre-filled memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
-        gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test IPv4 header size pre-filled memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-        gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
-
-        // Test not.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addNot(Register.R0);
-        gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test negate.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addNeg(Register.R0);
-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test move.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addMove(Register.R0);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addMove(Register.R1);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test swap.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addSwap();
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addSwap();
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jump if bytes not equal.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        program = gen.generate();
-        assertEquals(6, program.length);
-        assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
-        assertEquals(1, program[1]);
-        assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
-        assertEquals(1, program[3]);
-        assertEquals(1, program[4]);
-        assertEquals(123, program[5]);
-        assertDrop(program, new byte[MIN_PKT_SIZE], 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
-        assertPass(gen, packet123, 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        assertDrop(gen, packet123, 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
-        byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
-        assertDrop(gen, packet12345, 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
-        assertPass(gen, packet12345, 0);
-    }
-
-    @Test(expected = ApfGenerator.IllegalInstructionException.class)
-    public void testApfGeneratorWantsV2OrGreater() throws Exception {
-        // The minimum supported APF version is 2.
-        new ApfGenerator(1);
-    }
-
-    @Test
-    public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
-        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
-        try {
-            gen.addStoreData(Register.R0, 0);
-            fail();
-        } catch (IllegalInstructionException expected) {
-            /* pass */
-        }
-        try {
-            gen.addLoadData(Register.R0, 0);
-            fail();
-        } catch (IllegalInstructionException expected) {
-            /* pass */
-        }
-    }
-
-    /**
-     * Test that the generator emits immediates using the shortest possible encoding.
-     */
-    @Test
-    public void testImmediateEncoding() throws IllegalInstructionException {
-        ApfGenerator gen;
-
-        // 0-byte immediate: li R0, 0
-        gen = new ApfGenerator(4);
-        gen.addLoadImmediate(Register.R0, 0);
-        assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
-
-        // 1-byte immediate: li R0, 42
-        gen = new ApfGenerator(4);
-        gen.addLoadImmediate(Register.R0, 42);
-        assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
-
-        // 2-byte immediate: li R1, 0x1234
-        gen = new ApfGenerator(4);
-        gen.addLoadImmediate(Register.R1, 0x1234);
-        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
-
-        // 4-byte immediate: li R0, 0x12345678
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 0x12345678);
-        assertProgramEquals(
-                new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
-                gen.generate());
-    }
-
-    /**
-     * Test that the generator emits negative immediates using the shortest possible encoding.
-     */
-    @Test
-    public void testNegativeImmediateEncoding() throws IllegalInstructionException {
-        ApfGenerator gen;
-
-        // 1-byte negative immediate: li R0, -42
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, -42);
-        assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
-
-        // 2-byte negative immediate: li R1, -0x1122
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, -0x1122);
-        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
-                gen.generate());
-
-        // 4-byte negative immediate: li R0, -0x11223344
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, -0x11223344);
-        assertProgramEquals(
-                new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
-                gen.generate());
-    }
-
-    /**
-     * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
-     */
-    @Test
-    public void testLoadStoreDataEncoding() throws IllegalInstructionException {
-        ApfGenerator gen;
-
-        // Load data with no offset: lddw R0, [0 + r1]
-        gen = new ApfGenerator(3);
-        gen.addLoadData(Register.R0, 0);
-        assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
-
-        // Store data with 8bit negative offset: lddw r0, [-42 + r1]
-        gen = new ApfGenerator(3);
-        gen.addStoreData(Register.R0, -42);
-        assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
-
-        // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
-        gen = new ApfGenerator(3);
-        gen.addStoreData(Register.R1, -0x1122);
-        assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
-                gen.generate());
-
-        // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
-        gen = new ApfGenerator(3);
-        gen.addLoadData(Register.R1, 0xDEADBEEF);
-        assertProgramEquals(
-                new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
-                gen.generate());
-    }
-
-    /**
-     * Test that the interpreter correctly executes STDW with a negative 8bit offset
-     */
-    @Test
-    public void testApfDataWrite() throws IllegalInstructionException, Exception {
-        byte[] packet = new byte[MIN_PKT_SIZE];
-        byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
-        byte[] expected_data = data.clone();
-
-        // No memory access instructions: should leave the data segment untouched.
-        ApfGenerator gen = new ApfGenerator(3);
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-
-        // Expect value 0x87654321 to be stored starting from address -11 from the end of the
-        // data buffer, in big-endian order.
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 0x87654321);
-        gen.addLoadImmediate(Register.R1, -5);
-        gen.addStoreData(Register.R0, -6);  // -5 + -6 = -11 (offset +5 with data_len=16)
-        expected_data[5] = (byte)0x87;
-        expected_data[6] = (byte)0x65;
-        expected_data[7] = (byte)0x43;
-        expected_data[8] = (byte)0x21;
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-    }
-
-    /**
-     * Test that the interpreter correctly executes LDDW with a negative 16bit offset
-     */
-    @Test
-    public void testApfDataRead() throws IllegalInstructionException, Exception {
-        // Program that DROPs if address 10 (-6) contains 0x87654321.
-        ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, 1000);
-        gen.addLoadData(Register.R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
-        gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
-        byte[] program = gen.generate();
-        byte[] packet = new byte[MIN_PKT_SIZE];
-
-        // Content is incorrect (last byte does not match) -> PASS
-        byte[] data = new byte[16];
-        data[10] = (byte)0x87;
-        data[11] = (byte)0x65;
-        data[12] = (byte)0x43;
-        data[13] = (byte)0x00;  // != 0x21
-        byte[] expected_data = data.clone();
-        assertDataMemoryContents(PASS, program, packet, data, expected_data);
-
-        // Fix the last byte -> conditional jump taken -> DROP
-        data[13] = (byte)0x21;
-        expected_data = data;
-        assertDataMemoryContents(DROP, program, packet, data, expected_data);
-    }
-
-    /**
-     * Test that the interpreter correctly executes LDDW followed by a STDW.
-     * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
-     * offset.
-     */
-    @Test
-    public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
-        ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, -22);
-        gen.addLoadData(Register.R0, 0);  // Load from address 32 -22 + 0 = 10
-        gen.addAdd(0x78453412);  // 87654321 + 78453412 = FFAA7733
-        gen.addStoreData(Register.R0, 4);  // Write back to address 32 -22 + 4 = 14
-
-        byte[] packet = new byte[MIN_PKT_SIZE];
-        byte[] data = new byte[32];
-        data[10] = (byte)0x87;
-        data[11] = (byte)0x65;
-        data[12] = (byte)0x43;
-        data[13] = (byte)0x21;
-        byte[] expected_data = data.clone();
-        expected_data[14] = (byte)0xFF;
-        expected_data[15] = (byte)0xAA;
-        expected_data[16] = (byte)0x77;
-        expected_data[17] = (byte)0x33;
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-    }
-
-    @Test
-    public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
-        byte[] packet = new byte[MIN_PKT_SIZE];
-        byte[] data = new byte[32];
-        byte[] expected_data = data;
-
-        // Program that DROPs unconditionally. This is our the baseline.
-        ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 3);
-        gen.addLoadData(Register.R1, 7);
-        gen.addJump(gen.DROP_LABEL);
-        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
-        // Same program as before, but this time we're trying to load past the end of the data.
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, 15);  // 20 + 15 > 32
-        gen.addJump(gen.DROP_LABEL);  // Not reached.
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-
-        // Subtracting an immediate should work...
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, -4);
-        gen.addJump(gen.DROP_LABEL);
-        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
-        // ...and underflowing simply wraps around to the end of the buffer...
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, -30);
-        gen.addJump(gen.DROP_LABEL);
-        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
-        // ...but doesn't allow accesses before the start of the buffer
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, -1000);
-        gen.addJump(gen.DROP_LABEL);  // Not reached.
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-    }
-
-    /**
-     * Generate some BPF programs, translate them to APF, then run APF and BPF programs
-     * over packet traces and verify both programs filter out the same packets.
-     */
-    @Test
-    public void testApfAgainstBpf() throws Exception {
-        String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
-                "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
-                "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
-                "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
-        String pcap_filename = stageFile(R.raw.apf);
-        for (String tcpdump_filter : tcpdump_filters) {
-            byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
-            assertTrue("Failed to match for filter: " + tcpdump_filter,
-                    compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
-        }
-    }
-
-    /**
-     * Generate APF program, run pcap file though APF filter, then check all the packets in the file
-     * should be dropped.
-     */
-    @Test
-    public void testApfFilterPcapFile() throws Exception {
-        final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
-        String pcapFilename = stageFile(R.raw.apfPcap);
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
-        ApfConfiguration config = getDefaultConfig();
-        ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
-        config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-        byte[] program = ipClientCallback.getApfProgram();
-        byte[] data = new byte[ApfFilter.Counter.totalSize()];
-        final boolean result;
-
-        result = dropsAllPackets(program, data, pcapFilename);
-        Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
-
-        assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
-            HexDump.toHexString(data, false), result);
-    }
-
-    private class MockIpClientCallback extends IpClientCallbacksWrapper {
-        private final ConditionVariable mGotApfProgram = new ConditionVariable();
-        private byte[] mLastApfProgram;
-
-        MockIpClientCallback() {
-            super(mock(IIpClientCallbacks.class), mock(SharedLog.class));
-        }
-
-        @Override
-        public void installPacketFilter(byte[] filter) {
-            mLastApfProgram = filter;
-            mGotApfProgram.open();
-        }
-
-        public void resetApfProgramWait() {
-            mGotApfProgram.close();
-        }
-
-        public byte[] getApfProgram() {
-            assertTrue(mGotApfProgram.block(TIMEOUT_MS));
-            return mLastApfProgram;
-        }
-
-        public void assertNoProgramUpdate() {
-            assertFalse(mGotApfProgram.block(TIMEOUT_MS));
-        }
-    }
-
-    private static class TestApfFilter extends ApfFilter {
-        public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
-
-        private FileDescriptor mWriteSocket;
-        private final long mFixedTimeMs = SystemClock.elapsedRealtime();
-
-        public TestApfFilter(Context context, ApfConfiguration config,
-                IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) throws Exception {
-            super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
-        }
-
-        // Pretend an RA packet has been received and show it to ApfFilter.
-        public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
-            // ApfFilter's ReceiveThread will be waiting to read this.
-            Os.write(mWriteSocket, packet, 0, packet.length);
-        }
-
-        @Override
-        protected long currentTimeSeconds() {
-            return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
-        }
-
-        @Override
-        void maybeStartFilter() {
-            mHardwareAddress = MOCK_MAC_ADDR;
-            installNewProgramLocked();
-
-            // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
-            FileDescriptor readSocket = new FileDescriptor();
-            mWriteSocket = new FileDescriptor();
-            try {
-                Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
-            } catch (ErrnoException e) {
-                fail();
-                return;
-            }
-            // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
-            // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
-            mReceiveThread = new ReceiveThread(readSocket);
-            mReceiveThread.start();
-        }
-
-        @Override
-        public void shutdown() {
-            super.shutdown();
-            IoUtils.closeQuietly(mWriteSocket);
-        }
-    }
-
-    private static final int ETH_HEADER_LEN               = 14;
-    private static final int ETH_DEST_ADDR_OFFSET         = 0;
-    private static final int ETH_ETHERTYPE_OFFSET         = 12;
-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
-            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-
-    private static final int IPV4_HEADER_LEN          = 20;
-    private static final int IPV4_VERSION_IHL_OFFSET  = ETH_HEADER_LEN + 0;
-    private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
-    private static final int IPV4_PROTOCOL_OFFSET     = ETH_HEADER_LEN + 9;
-    private static final int IPV4_SRC_ADDR_OFFSET     = ETH_HEADER_LEN + 12;
-    private static final int IPV4_DEST_ADDR_OFFSET    = ETH_HEADER_LEN + 16;
-
-    private static final int IPV4_TCP_HEADER_LEN           = 20;
-    private static final int IPV4_TCP_HEADER_OFFSET        = ETH_HEADER_LEN + IPV4_HEADER_LEN;
-    private static final int IPV4_TCP_SRC_PORT_OFFSET      = IPV4_TCP_HEADER_OFFSET + 0;
-    private static final int IPV4_TCP_DEST_PORT_OFFSET     = IPV4_TCP_HEADER_OFFSET + 2;
-    private static final int IPV4_TCP_SEQ_NUM_OFFSET       = IPV4_TCP_HEADER_OFFSET + 4;
-    private static final int IPV4_TCP_ACK_NUM_OFFSET       = IPV4_TCP_HEADER_OFFSET + 8;
-    private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
-    private static final int IPV4_TCP_HEADER_FLAG_OFFSET   = IPV4_TCP_HEADER_OFFSET + 13;
-
-    private static final int IPV4_UDP_HEADER_OFFSET    = ETH_HEADER_LEN + IPV4_HEADER_LEN;;
-    private static final int IPV4_UDP_SRC_PORT_OFFSET  = IPV4_UDP_HEADER_OFFSET + 0;
-    private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2;
-    private static final int IPV4_UDP_LENGTH_OFFSET    = IPV4_UDP_HEADER_OFFSET + 4;
-    private static final int IPV4_UDP_PAYLOAD_OFFSET   = IPV4_UDP_HEADER_OFFSET + 8;
-    private static final byte[] IPV4_BROADCAST_ADDRESS =
-            {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
-
-    private static final int IPV6_HEADER_LEN             = 40;
-    private static final int IPV6_NEXT_HEADER_OFFSET     = ETH_HEADER_LEN + 6;
-    private static final int IPV6_SRC_ADDR_OFFSET        = ETH_HEADER_LEN + 8;
-    private static final int IPV6_DEST_ADDR_OFFSET       = ETH_HEADER_LEN + 24;
-    private static final int IPV6_TCP_HEADER_OFFSET      = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-    private static final int IPV6_TCP_SRC_PORT_OFFSET    = IPV6_TCP_HEADER_OFFSET + 0;
-    private static final int IPV6_TCP_DEST_PORT_OFFSET   = IPV6_TCP_HEADER_OFFSET + 2;
-    private static final int IPV6_TCP_SEQ_NUM_OFFSET     = IPV6_TCP_HEADER_OFFSET + 4;
-    private static final int IPV6_TCP_ACK_NUM_OFFSET     = IPV6_TCP_HEADER_OFFSET + 8;
-    // The IPv6 all nodes address ff02::1
-    private static final byte[] IPV6_ALL_NODES_ADDRESS   =
-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-    private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
-
-    private static final int ICMP6_TYPE_OFFSET           = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-    private static final int ICMP6_ROUTER_SOLICITATION   = 133;
-    private static final int ICMP6_ROUTER_ADVERTISEMENT  = 134;
-    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
-    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
-
-    private static final int ICMP6_RA_HEADER_LEN = 16;
-    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
-            ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
-    private static final int ICMP6_RA_CHECKSUM_OFFSET =
-            ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
-    private static final int ICMP6_RA_OPTION_OFFSET =
-            ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
-
-    private static final int ICMP6_PREFIX_OPTION_TYPE                      = 3;
-    private static final int ICMP6_PREFIX_OPTION_LEN                       = 32;
-    private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET     = 4;
-    private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
-
-    // From RFC6106: Recursive DNS Server option
-    private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
-    // From RFC6106: DNS Search List option
-    private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
-
-    // From RFC4191: Route Information option
-    private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
-    // Above three options all have the same format:
-    private static final int ICMP6_4_BYTE_OPTION_LEN      = 8;
-    private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
-    private static final int ICMP6_4_BYTE_LIFETIME_LEN    = 4;
-
-    private static final int UDP_HEADER_LEN              = 8;
-    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
-
-    private static final int DHCP_CLIENT_PORT       = 68;
-    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
-
-    private static final int ARP_HEADER_OFFSET          = ETH_HEADER_LEN;
-    private static final byte[] ARP_IPV4_REQUEST_HEADER = {
-            0, 1, // Hardware type: Ethernet (1)
-            8, 0, // Protocol type: IP (0x0800)
-            6,    // Hardware size: 6
-            4,    // Protocol size: 4
-            0, 1  // Opcode: request (1)
-    };
-    private static final byte[] ARP_IPV4_REPLY_HEADER = {
-            0, 1, // Hardware type: Ethernet (1)
-            8, 0, // Protocol type: IP (0x0800)
-            6,    // Hardware size: 6
-            4,    // Protocol size: 4
-            0, 2  // Opcode: reply (2)
-    };
-    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
-
-    private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
-    private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
-    private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
-    private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
-    private static final byte[] IPV4_SOURCE_ADDR         = {10, 0, 0, 3};
-    private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
-    private static final byte[] BUG_PROBE_SOURCE_ADDR1   = {0, 0, 1, 2};
-    private static final byte[] BUG_PROBE_SOURCE_ADDR2   = {3, 4, 0, 0};
-    private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
-
-    // Helper to initialize a default apfFilter.
-    private ApfFilter setupApfFilter(
-            IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config) throws Exception {
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-        return apfFilter;
-    }
-
-    @Test
-    public void testApfFilterIPv4() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty packet of 100 zero bytes is passed
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array());
-
-        // Verify unicast IPv4 packet is passed
-        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
-        assertPass(program, packet.array());
-
-        // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
-        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
-        assertDrop(program, packet.array());
-
-        // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
-        assertDrop(program, packet.array());
-        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
-        assertDrop(program, packet.array());
-        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
-        assertDrop(program, packet.array());
-        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-        assertDrop(program, packet.array());
-
-        // Verify broadcast IPv4 DHCP to us is passed
-        put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
-        assertPass(program, packet.array());
-
-        // Verify unicast IPv4 DHCP to us is passed
-        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
-        assertPass(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterIPv6() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty IPv6 packet is passed
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Verify empty ICMPv6 packet is passed
-        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        assertPass(program, packet.array());
-
-        // Verify empty ICMPv6 NA packet is passed
-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
-        assertPass(program, packet.array());
-
-        // Verify ICMPv6 NA to ff02::1 is dropped
-        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
-        assertDrop(program, packet.array());
-
-        // Verify ICMPv6 RS to any is dropped
-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
-        assertDrop(program, packet.array());
-        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
-        assertDrop(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterMulticast() throws Exception {
-        final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
-        final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
-        final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
-        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
-
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
-        ApfConfiguration config = getDefaultConfig();
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Construct IPv4 and IPv6 multicast packets.
-        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
-        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
-
-        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
-        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
-        put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
-
-        // Construct IPv4 broadcast packet.
-        ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
-        bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
-        bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
-
-        ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
-        bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
-        bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-
-        // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
-        ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
-        bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
-        bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
-
-        // Verify initially disabled multicast filter is off
-        assertPass(program, mcastv4packet.array());
-        assertPass(program, mcastv6packet.array());
-        assertPass(program, bcastv4packet1.array());
-        assertPass(program, bcastv4packet2.array());
-        assertPass(program, bcastv4unicastl2packet.array());
-
-        // Turn on multicast filter and verify it works
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.setMulticastFilter(true);
-        program = ipClientCallback.getApfProgram();
-        assertDrop(program, mcastv4packet.array());
-        assertDrop(program, mcastv6packet.array());
-        assertDrop(program, bcastv4packet1.array());
-        assertDrop(program, bcastv4packet2.array());
-        assertDrop(program, bcastv4unicastl2packet.array());
-
-        // Turn off multicast filter and verify it's off
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.setMulticastFilter(false);
-        program = ipClientCallback.getApfProgram();
-        assertPass(program, mcastv4packet.array());
-        assertPass(program, mcastv6packet.array());
-        assertPass(program, bcastv4packet1.array());
-        assertPass(program, bcastv4packet2.array());
-        assertPass(program, bcastv4unicastl2packet.array());
-
-        // Verify it can be initialized to on
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-        program = ipClientCallback.getApfProgram();
-        assertDrop(program, mcastv4packet.array());
-        assertDrop(program, mcastv6packet.array());
-        assertDrop(program, bcastv4packet1.array());
-        assertDrop(program, bcastv4unicastl2packet.array());
-
-        // Verify that ICMPv6 multicast is not dropped.
-        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        assertPass(program, mcastv6packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterMulticastPingWhileDozing() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
-
-        // Construct a multicast ICMPv6 ECHO request.
-        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
-        put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
-
-        // Normally, we let multicast pings alone...
-        assertPass(ipClientCallback.getApfProgram(), packet.array());
-
-        // ...and even while dozing...
-        apfFilter.setDozeMode(true);
-        assertPass(ipClientCallback.getApfProgram(), packet.array());
-
-        // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
-        apfFilter.setMulticastFilter(true);
-        assertDrop(ipClientCallback.getApfProgram(), packet.array());
-
-        // However, we should still let through all other ICMPv6 types.
-        ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
-        raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
-        assertPass(ipClientCallback.getApfProgram(), raPacket.array());
-
-        // Now wake up from doze mode to ensure that we no longer drop the packets.
-        // (The multicast filter is still enabled at this point).
-        apfFilter.setDozeMode(false);
-        assertPass(ipClientCallback.getApfProgram(), packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilter802_3() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty packet of 100 zero bytes is passed
-        // Note that eth-type = 0 makes it an IEEE802.3 frame
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array());
-
-        // Verify empty packet with IPv4 is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array());
-
-        // Verify empty IPv6 packet is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Now turn on the filter
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        apfFilter = setupApfFilter(ipClientCallback, config);
-        program = ipClientCallback.getApfProgram();
-
-        // Verify that IEEE802.3 frame is dropped
-        // In this case ethtype is used for payload length
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
-        assertDrop(program, packet.array());
-
-        // Verify that IPv4 (as example of Ethernet II) frame will pass
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array());
-
-        // Verify that IPv6 (as example of Ethernet II) frame will pass
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterEthTypeBL() throws Exception {
-        final int[] emptyBlackList = {};
-        final int[] ipv4BlackList = {ETH_P_IP};
-        final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
-
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty packet of 100 zero bytes is passed
-        // Note that eth-type = 0 makes it an IEEE802.3 frame
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array());
-
-        // Verify empty packet with IPv4 is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array());
-
-        // Verify empty IPv6 packet is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Now add IPv4 to the black list
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.ethTypeBlackList = ipv4BlackList;
-        apfFilter = setupApfFilter(ipClientCallback, config);
-        program = ipClientCallback.getApfProgram();
-
-        // Verify that IPv4 frame will be dropped
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertDrop(program, packet.array());
-
-        // Verify that IPv6 frame will pass
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Now let us have both IPv4 and IPv6 in the black list
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.ethTypeBlackList = ipv4Ipv6BlackList;
-        apfFilter = setupApfFilter(ipClientCallback, config);
-        program = ipClientCallback.getApfProgram();
-
-        // Verify that IPv4 frame will be dropped
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertDrop(program, packet.array());
-
-        // Verify that IPv6 frame will be dropped
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertDrop(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
-        cb.resetApfProgramWait();
-        filter.setLinkProperties(lp);
-        return cb.getApfProgram();
-    }
-
-    private void verifyArpFilter(byte[] program, int filterResult) {
-        // Verify ARP request packet
-        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
-        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
-        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
-
-        // Verify ARP reply packets from different source ip
-        assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
-        assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
-        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
-        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
-
-        // Verify unicast ARP reply packet is always accepted.
-        assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
-        assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
-        assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
-
-        // Verify GARP reply packets are always filtered
-        assertDrop(program, garpReply());
-    }
-
-    @Test
-    public void testApfFilterArp() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-
-        // Verify initially ARP request filter is off, and GARP filter is on.
-        verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
-
-        // Inform ApfFilter of our address and verify ARP filtering is on
-        LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
-        LinkProperties lp = new LinkProperties();
-        assertTrue(lp.addLinkAddress(linkAddress));
-        verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
-
-        // Inform ApfFilter of loss of IP and verify ARP filtering is off
-        verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
-
-        apfFilter.shutdown();
-    }
-
-    private static byte[] arpReply(byte[] sip, byte[] tip) {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
-        put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
-        return packet.array();
-    }
-
-    private static byte[] arpRequestBroadcast(byte[] tip) {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
-        return packet.array();
-    }
-
-    private static byte[] garpReply() {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
-        return packet.array();
-    }
-
-    private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5};
-    private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6};
-    private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7};
-    private static final byte[] IPV6_KEEPALIVE_SRC_ADDR =
-            {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1};
-    private static final byte[] IPV6_KEEPALIVE_DST_ADDR =
-            {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2};
-    private static final byte[] IPV6_ANOTHER_ADDR =
-            {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5};
-
-    @Test
-    public void testApfFilterKeepaliveAck() throws Exception {
-        final MockIpClientCallback cb = new MockIpClientCallback();
-        final ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
-        byte[] program;
-        final int srcPort = 12345;
-        final int dstPort = 54321;
-        final int seqNum = 2123456789;
-        final int ackNum = 1234567890;
-        final int anotherSrcPort = 23456;
-        final int anotherDstPort = 65432;
-        final int anotherSeqNum = 2123456780;
-        final int anotherAckNum = 1123456789;
-        final int slot1 = 1;
-        final int slot2 = 2;
-        final int window = 14480;
-        final int windowScale = 4;
-
-        // src: 10.0.0.5, port: 12345
-        // dst: 10.0.0.6, port: 54321
-        InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
-        InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
-
-        final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
-        parcel.srcAddress = srcAddr.getAddress();
-        parcel.srcPort = srcPort;
-        parcel.dstAddress = dstAddr.getAddress();
-        parcel.dstPort = dstPort;
-        parcel.seq = seqNum;
-        parcel.ack = ackNum;
-
-        apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
-        program = cb.getApfProgram();
-
-        // Verify IPv4 keepalive ack packet is dropped
-        // src: 10.0.0.6, port: 54321
-        // dst: 10.0.0.5, port: 12345
-        assertDrop(program,
-                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
-        // Verify IPv4 non-keepalive ack packet from the same source address is passed
-        assertPass(program,
-                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
-        assertPass(program,
-                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */));
-        // Verify IPv4 packet from another address is passed
-        assertPass(program,
-                ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
-                        anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
-
-        // Remove IPv4 keepalive filter
-        apfFilter.removeKeepalivePacketFilter(slot1);
-
-        try {
-            // src: 2404:0:0:0:0:0:faf1, port: 12345
-            // dst: 2404:0:0:0:0:0:faf2, port: 54321
-            srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR);
-            dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR);
-
-            final TcpKeepalivePacketDataParcelable ipv6Parcel =
-                    new TcpKeepalivePacketDataParcelable();
-            ipv6Parcel.srcAddress = srcAddr.getAddress();
-            ipv6Parcel.srcPort = srcPort;
-            ipv6Parcel.dstAddress = dstAddr.getAddress();
-            ipv6Parcel.dstPort = dstPort;
-            ipv6Parcel.seq = seqNum;
-            ipv6Parcel.ack = ackNum;
-
-            apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel);
-            program = cb.getApfProgram();
-
-            // Verify IPv6 keepalive ack packet is dropped
-            // src: 2404:0:0:0:0:0:faf2, port: 54321
-            // dst: 2404:0:0:0:0:0:faf1, port: 12345
-            assertDrop(program,
-                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
-                            dstPort, srcPort, ackNum, seqNum + 1));
-            // Verify IPv6 non-keepalive ack packet from the same source address is passed
-            assertPass(program,
-                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
-                            dstPort, srcPort, ackNum + 100, seqNum));
-            // Verify IPv6 packet from another address is passed
-            assertPass(program,
-                    ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
-                            anotherDstPort, anotherSeqNum, anotherAckNum));
-
-            // Remove IPv6 keepalive filter
-            apfFilter.removeKeepalivePacketFilter(slot1);
-
-            // Verify multiple filters
-            apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
-            apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel);
-            program = cb.getApfProgram();
-
-            // Verify IPv4 keepalive ack packet is dropped
-            // src: 10.0.0.6, port: 54321
-            // dst: 10.0.0.5, port: 12345
-            assertDrop(program,
-                    ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                            dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
-            // Verify IPv4 non-keepalive ack packet from the same source address is passed
-            assertPass(program,
-                    ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                            dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
-            // Verify IPv4 packet from another address is passed
-            assertPass(program,
-                    ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
-                            anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
-
-            // Verify IPv6 keepalive ack packet is dropped
-            // src: 2404:0:0:0:0:0:faf2, port: 54321
-            // dst: 2404:0:0:0:0:0:faf1, port: 12345
-            assertDrop(program,
-                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
-                            dstPort, srcPort, ackNum, seqNum + 1));
-            // Verify IPv6 non-keepalive ack packet from the same source address is passed
-            assertPass(program,
-                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
-                            dstPort, srcPort, ackNum + 100, seqNum));
-            // Verify IPv6 packet from another address is passed
-            assertPass(program,
-                    ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
-                            anotherDstPort, anotherSeqNum, anotherAckNum));
-
-            // Remove keepalive filters
-            apfFilter.removeKeepalivePacketFilter(slot1);
-            apfFilter.removeKeepalivePacketFilter(slot2);
-        } catch (UnsupportedOperationException e) {
-            // TODO: support V6 packets
-        }
-
-        program = cb.getApfProgram();
-
-        // Verify IPv4, IPv6 packets are passed
-        assertPass(program,
-                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
-        assertPass(program,
-                ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, ackNum, seqNum + 1));
-        assertPass(program,
-                ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
-                        dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
-        assertPass(program,
-                ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
-                        dstPort, anotherSeqNum, anotherAckNum));
-
-        apfFilter.shutdown();
-    }
-
-    private static byte[] ipv4Packet(byte[] sip, byte[] dip, int sport,
-            int dport, int seq, int ack, int dataLength) {
-        final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN;
-
-        ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
-
-        // ether type
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
-
-        // IPv4 header
-        packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
-        packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
-        packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP);
-        put(packet, IPV4_SRC_ADDR_OFFSET, sip);
-        put(packet, IPV4_DEST_ADDR_OFFSET, dip);
-        packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport);
-        packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport);
-        packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq);
-        packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack);
-
-        // TCP header length 5(20 bytes), reserved 3 bits, NS=0
-        packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50);
-        // TCP flags: ACK set
-        packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10);
-        return packet.array();
-    }
-
-    private static byte[] ipv6Packet(byte[] sip, byte[] tip, int sport,
-            int dport, int seq, int ack) {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
-        put(packet, IPV6_SRC_ADDR_OFFSET, sip);
-        put(packet, IPV6_DEST_ADDR_OFFSET, tip);
-        packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport);
-        packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport);
-        packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq);
-        packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack);
-        return packet.array();
-    }
-
-    @Test
-    public void testApfFilterNattKeepalivePacket() throws Exception {
-        final MockIpClientCallback cb = new MockIpClientCallback();
-        final ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
-        byte[] program;
-        final int srcPort = 1024;
-        final int dstPort = 4500;
-        final int slot1 = 1;
-        // NAT-T keepalive
-        final byte[] kaPayload = {(byte) 0xff};
-        final byte[] nonKaPayload = {(byte) 0xfe};
-
-        // src: 10.0.0.5, port: 1024
-        // dst: 10.0.0.6, port: 4500
-        InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
-        InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
-
-        final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
-        parcel.srcAddress = srcAddr.getAddress();
-        parcel.srcPort = srcPort;
-        parcel.dstAddress = dstAddr.getAddress();
-        parcel.dstPort = dstPort;
-
-        apfFilter.addNattKeepalivePacketFilter(slot1, parcel);
-        program = cb.getApfProgram();
-
-        // Verify IPv4 keepalive packet is dropped
-        // src: 10.0.0.6, port: 4500
-        // dst: 10.0.0.5, port: 1024
-        byte[] pkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR,
-                    IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */);
-        System.arraycopy(kaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, kaPayload.length);
-        assertDrop(program, pkt);
-
-        // Verify a packet with payload length 1 byte but it is not 0xff will pass the filter.
-        System.arraycopy(nonKaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, nonKaPayload.length);
-        assertPass(program, pkt);
-
-        // Verify IPv4 non-keepalive response packet from the same source address is passed
-        assertPass(program,
-                ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, 10 /* dataLength */));
-
-        // Verify IPv4 non-keepalive response packet from other source address is passed
-        assertPass(program,
-                ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
-                        dstPort, srcPort, 10 /* dataLength */));
-
-        apfFilter.removeKeepalivePacketFilter(slot1);
-        apfFilter.shutdown();
-    }
-
-    private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport,
-            int dport, int dataLength) {
-        final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN;
-        final int udpLength = UDP_HEADER_LEN + dataLength;
-        ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
-
-        // ether type
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
-
-        // IPv4 header
-        packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
-        packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
-        packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP);
-        put(packet, IPV4_SRC_ADDR_OFFSET, sip);
-        put(packet, IPV4_DEST_ADDR_OFFSET, dip);
-        packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport);
-        packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport);
-        packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength);
-
-        return packet.array();
-    }
-
-    // Verify that the last program pushed to the IpClient.Callback properly filters the
-    // given packet for the given lifetime.
-    private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
-        final int FRACTION_OF_LIFETIME = 6;
-        final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
-
-        // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
-        assertDrop(program, packet.array());
-        assertDrop(program, packet.array(), ageLimit);
-        assertPass(program, packet.array(), ageLimit + 1);
-        assertPass(program, packet.array(), lifetime);
-        // Verify RA checksum is ignored
-        final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
-        assertDrop(program, packet.array());
-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
-        assertDrop(program, packet.array());
-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
-
-        // Verify other changes to RA make it not match filter
-        final byte originalFirstByte = packet.get(0);
-        packet.put(0, (byte)-1);
-        assertPass(program, packet.array());
-        packet.put(0, (byte)0);
-        assertDrop(program, packet.array());
-        packet.put(0, originalFirstByte);
-    }
-
-    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
-    // for the given lifetime.
-    private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
-            ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
-        // Verify new program generated if ApfFilter witnesses RA
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.pretendPacketReceived(packet.array());
-        byte[] program = ipClientCallback.getApfProgram();
-        verifyRaLifetime(program, packet, lifetime);
-    }
-
-    private void verifyRaEvent(RaEvent expected) {
-        ArgumentCaptor<IpConnectivityLog.Event> captor =
-                ArgumentCaptor.forClass(IpConnectivityLog.Event.class);
-        verify(mLog, atLeastOnce()).log(captor.capture());
-        RaEvent got = lastRaEvent(captor.getAllValues());
-        if (!raEventEquals(expected, got)) {
-            assertEquals(expected, got);  // fail for printing an assertion error message.
-        }
-    }
-
-    private RaEvent lastRaEvent(List<IpConnectivityLog.Event> events) {
-        RaEvent got = null;
-        for (Parcelable ev : events) {
-            if (ev instanceof RaEvent) {
-                got = (RaEvent) ev;
-            }
-        }
-        return got;
-    }
-
-    private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
-        return (ev1 != null) && (ev2 != null)
-                && (ev1.routerLifetime == ev2.routerLifetime)
-                && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
-                && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
-                && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
-                && (ev1.rdnssLifetime == ev2.rdnssLifetime)
-                && (ev1.dnsslLifetime == ev2.dnsslLifetime);
-    }
-
-    private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
-            ByteBuffer packet) throws IOException, ErrnoException {
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.pretendPacketReceived(packet.array());
-        ipClientCallback.assertNoProgramUpdate();
-    }
-
-    @Test
-    public void testApfFilterRa() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        final int ROUTER_LIFETIME = 1000;
-        final int PREFIX_VALID_LIFETIME = 200;
-        final int PREFIX_PREFERRED_LIFETIME = 100;
-        final int RDNSS_LIFETIME  = 300;
-        final int ROUTE_LIFETIME  = 400;
-        // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
-        final int DNSSL_LIFETIME  = 2000;
-        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
-        // IPv6, traffic class = 0, flow label = 0x12345
-        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
-
-        // Verify RA is passed the first time
-        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
-        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
-                VERSION_TRAFFIC_CLASS_FLOW_LABEL);
-        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
-        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
-        basePacket.position(IPV6_DEST_ADDR_OFFSET);
-        basePacket.put(IPV6_ALL_NODES_ADDRESS);
-        assertPass(program, basePacket.array());
-
-        verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
-
-        ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
-        basePacket.clear();
-        newFlowLabelPacket.put(basePacket);
-        // Check that changes are ignored in every byte of the flow label.
-        newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
-                VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
-
-        // Ensure zero-length options cause the packet to be silently skipped.
-        // Do this before we test other packets. http://b/29586253
-        ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        zeroLengthOptionPacket.put(basePacket);
-        zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
-        zeroLengthOptionPacket.put((byte)0);
-        assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
-
-        // Generate several RAs with different options and lifetimes, and verify when
-        // ApfFilter is shown these packets, it generates programs to filter them for the
-        // appropriate lifetime.
-        ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
-        basePacket.clear();
-        prefixOptionPacket.put(basePacket);
-        prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
-        prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
-        prefixOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
-                PREFIX_PREFERRED_LIFETIME);
-        prefixOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
-                PREFIX_VALID_LIFETIME);
-        verifyRaLifetime(
-                apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
-        verifyRaEvent(new RaEvent(
-                ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
-
-        ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        rdnssOptionPacket.put(basePacket);
-        rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
-        rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
-        rdnssOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
-        verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
-
-        ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        routeInfoOptionPacket.put(basePacket);
-        routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
-        routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
-        routeInfoOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
-        verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
-
-        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        dnsslOptionPacket.put(basePacket);
-        dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
-        dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
-        dnsslOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
-        verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
-
-        // Verify that current program filters all five RAs:
-        program = ipClientCallback.getApfProgram();
-        verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
-        verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
-        verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
-        verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
-        verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
-        verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
-
-        apfFilter.shutdown();
-    }
-
-    /**
-     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
-     * copy that resource into the app's data directory and return the path to it.
-     */
-    private String stageFile(int rawId) throws Exception {
-        File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
-        new File(file.getParent()).mkdirs();
-        InputStream in = null;
-        OutputStream out = null;
-        try {
-            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
-            out = new FileOutputStream(file);
-            Streams.copy(in, out);
-        } finally {
-            if (in != null) in.close();
-            if (out != null) out.close();
-        }
-        return file.getAbsolutePath();
-    }
-
-    private static void put(ByteBuffer buffer, int position, byte[] bytes) {
-        final int original = buffer.position();
-        buffer.position(position);
-        buffer.put(bytes);
-        buffer.position(original);
-    }
-
-    @Test
-    public void testRaParsing() throws Exception {
-        final int maxRandomPacketSize = 512;
-        final Random r = new Random();
-        MockIpClientCallback cb = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
-        for (int i = 0; i < 1000; i++) {
-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
-            r.nextBytes(packet);
-            try {
-                apfFilter.new Ra(packet, packet.length);
-            } catch (ApfFilter.InvalidRaException e) {
-            } catch (Exception e) {
-                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
-            }
-        }
-    }
-
-    @Test
-    public void testRaProcessing() throws Exception {
-        final int maxRandomPacketSize = 512;
-        final Random r = new Random();
-        MockIpClientCallback cb = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
-        for (int i = 0; i < 1000; i++) {
-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
-            r.nextBytes(packet);
-            try {
-                apfFilter.processRa(packet, packet.length);
-            } catch (Exception e) {
-                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
-            }
-        }
-    }
-
-    /**
-     * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
-     * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
-     */
-    private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
-        int filter_age);
-
-    /**
-     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
-     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
-     */
-    private native static String compileToBpf(String filter);
-
-    /**
-     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
-     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
-     * at the same time using APF program {@code apf_program}.  Return {@code true} if
-     * both APF and BPF programs filter out exactly the same packets.
-     */
-    private native static boolean compareBpfApf(String filter, String pcap_filename,
-            byte[] apf_program);
-
-
-    /**
-     * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
-     * checks whether all the packets are dropped and populates data[] {@code data} with
-     * the APF counters.
-     */
-    private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
-
-    @Test
-    public void testBroadcastAddress() throws Exception {
-        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
-        assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
-        assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
-        assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
-
-        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
-        assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
-        assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
-        assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
-    }
-
-    public void assertEqualsIp(String expected, int got) throws Exception {
-        int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
-        assertEquals(want, got);
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/apf/Bpf2Apf.java b/packages/NetworkStack/tests/unit/src/android/net/apf/Bpf2Apf.java
deleted file mode 100644
index 5d57cde..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/apf/Bpf2Apf.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2015 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.apf;
-
-import android.net.apf.ApfGenerator;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-
-/**
- * BPF to APF translator.
- *
- * Note: This is for testing purposes only and is not guaranteed to support
- *       translation of all BPF programs.
- *
- * Example usage:
- *   javac net/java/android/net/apf/ApfGenerator.java \
- *         tests/servicestests/src/android/net/apf/Bpf2Apf.java
- *   sudo tcpdump -i em1 -d icmp | java -classpath tests/servicestests/src:net/java \
- *                                      android.net.apf.Bpf2Apf
- */
-public class Bpf2Apf {
-    private static int parseImm(String line, String arg) {
-        if (!arg.startsWith("#0x")) {
-            throw new IllegalArgumentException("Unhandled instruction: " + line);
-        }
-        final long val_long = Long.parseLong(arg.substring(3), 16);
-        if (val_long < 0 || val_long > Long.parseLong("ffffffff", 16)) {
-            throw new IllegalArgumentException("Unhandled instruction: " + line);
-        }
-        return new Long((val_long << 32) >> 32).intValue();
-    }
-
-    /**
-     * Convert a single line of "tcpdump -d" (human readable BPF program dump) {@code line} into
-     * APF instruction(s) and append them to {@code gen}. Here's an example line:
-     * (001) jeq      #0x86dd          jt 2    jf 7
-     */
-    private static void convertLine(String line, ApfGenerator gen)
-            throws IllegalInstructionException {
-        if (line.indexOf("(") != 0 || line.indexOf(")") != 4 || line.indexOf(" ") != 5) {
-            throw new IllegalArgumentException("Unhandled instruction: " + line);
-        }
-        int label = Integer.parseInt(line.substring(1, 4));
-        gen.defineLabel(Integer.toString(label));
-        String opcode = line.substring(6, 10).trim();
-        String arg = line.substring(15, Math.min(32, line.length())).trim();
-        switch (opcode) {
-            case "ld":
-            case "ldh":
-            case "ldb":
-            case "ldx":
-            case "ldxb":
-            case "ldxh":
-                Register dest = opcode.contains("x") ? Register.R1 : Register.R0;
-                if (arg.equals("4*([14]&0xf)")) {
-                    if (!opcode.equals("ldxb")) {
-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
-                    }
-                    gen.addLoadFromMemory(dest, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-                    break;
-                }
-                if (arg.equals("#pktlen")) {
-                    if (!opcode.equals("ld")) {
-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
-                    }
-                    gen.addLoadFromMemory(dest, gen.PACKET_SIZE_MEMORY_SLOT);
-                    break;
-                }
-                if (arg.startsWith("#0x")) {
-                    if (!opcode.equals("ld")) {
-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
-                    }
-                    gen.addLoadImmediate(dest, parseImm(line, arg));
-                    break;
-                }
-                if (arg.startsWith("M[")) {
-                    if (!opcode.startsWith("ld")) {
-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
-                    }
-                    int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
-                    if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
-                            // Disallow use of pre-filled slots as BPF programs might
-                            // wrongfully assume they're initialized to 0.
-                            (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
-                                    memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
-                        throw new IllegalArgumentException("Unhandled instruction: " + line);
-                    }
-                    gen.addLoadFromMemory(dest, memory_slot);
-                    break;
-                }
-                if (arg.startsWith("[x + ")) {
-                    int offset = Integer.parseInt(arg.substring(5, arg.length() - 1));
-                    switch (opcode) {
-                        case "ld":
-                        case "ldx":
-                            gen.addLoad32Indexed(dest, offset);
-                            break;
-                        case "ldh":
-                        case "ldxh":
-                            gen.addLoad16Indexed(dest, offset);
-                            break;
-                        case "ldb":
-                        case "ldxb":
-                            gen.addLoad8Indexed(dest, offset);
-                            break;
-                    }
-                } else {
-                    int offset = Integer.parseInt(arg.substring(1, arg.length() - 1));
-                    switch (opcode) {
-                        case "ld":
-                        case "ldx":
-                            gen.addLoad32(dest, offset);
-                            break;
-                        case "ldh":
-                        case "ldxh":
-                            gen.addLoad16(dest, offset);
-                            break;
-                        case "ldb":
-                        case "ldxb":
-                            gen.addLoad8(dest, offset);
-                            break;
-                    }
-                }
-                break;
-            case "st":
-            case "stx":
-                Register src = opcode.contains("x") ? Register.R1 : Register.R0;
-                if (!arg.startsWith("M[")) {
-                    throw new IllegalArgumentException("Unhandled instruction: " + line);
-                }
-                int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
-                if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
-                        // Disallow overwriting pre-filled slots
-                        (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
-                                memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
-                    throw new IllegalArgumentException("Unhandled instruction: " + line);
-                }
-                gen.addStoreToMemory(src, memory_slot);
-                break;
-            case "add":
-            case "and":
-            case "or":
-            case "sub":
-                if (arg.equals("x")) {
-                    switch(opcode) {
-                        case "add":
-                            gen.addAddR1();
-                            break;
-                        case "and":
-                            gen.addAndR1();
-                            break;
-                        case "or":
-                            gen.addOrR1();
-                            break;
-                        case "sub":
-                            gen.addNeg(Register.R1);
-                            gen.addAddR1();
-                            gen.addNeg(Register.R1);
-                            break;
-                    }
-                } else {
-                    int imm = parseImm(line, arg);
-                    switch(opcode) {
-                        case "add":
-                            gen.addAdd(imm);
-                            break;
-                        case "and":
-                            gen.addAnd(imm);
-                            break;
-                        case "or":
-                            gen.addOr(imm);
-                            break;
-                        case "sub":
-                            gen.addAdd(-imm);
-                            break;
-                    }
-                }
-                break;
-            case "jeq":
-            case "jset":
-            case "jgt":
-            case "jge":
-                int val = 0;
-                boolean reg_compare;
-                if (arg.startsWith("x")) {
-                    reg_compare = true;
-                } else {
-                    reg_compare = false;
-                    val = parseImm(line, arg);
-                }
-                int jt_offset = line.indexOf("jt");
-                int jf_offset = line.indexOf("jf");
-                String true_label = line.substring(jt_offset + 2, jf_offset).trim();
-                String false_label = line.substring(jf_offset + 2).trim();
-                boolean true_label_is_fallthrough = Integer.parseInt(true_label) == label + 1;
-                boolean false_label_is_fallthrough = Integer.parseInt(false_label) == label + 1;
-                if (true_label_is_fallthrough && false_label_is_fallthrough)
-                    break;
-                switch (opcode) {
-                    case "jeq":
-                        if (!true_label_is_fallthrough) {
-                            if (reg_compare) {
-                                gen.addJumpIfR0EqualsR1(true_label);
-                            } else {
-                                gen.addJumpIfR0Equals(val, true_label);
-                            }
-                        }
-                        if (!false_label_is_fallthrough) {
-                            if (!true_label_is_fallthrough) {
-                                gen.addJump(false_label);
-                            } else if (reg_compare) {
-                                gen.addJumpIfR0NotEqualsR1(false_label);
-                            } else {
-                                gen.addJumpIfR0NotEquals(val, false_label);
-                            }
-                        }
-                        break;
-                    case "jset":
-                        if (reg_compare) {
-                            gen.addJumpIfR0AnyBitsSetR1(true_label);
-                        } else {
-                            gen.addJumpIfR0AnyBitsSet(val, true_label);
-                        }
-                        if (!false_label_is_fallthrough) {
-                            gen.addJump(false_label);
-                        }
-                        break;
-                    case "jgt":
-                        if (!true_label_is_fallthrough ||
-                                // We have no less-than-or-equal-to register to register
-                                // comparison instruction, so in this case we'll jump
-                                // around an unconditional jump.
-                                (!false_label_is_fallthrough && reg_compare)) {
-                            if (reg_compare) {
-                                gen.addJumpIfR0GreaterThanR1(true_label);
-                            } else {
-                                gen.addJumpIfR0GreaterThan(val, true_label);
-                            }
-                        }
-                        if (!false_label_is_fallthrough) {
-                            if (!true_label_is_fallthrough || reg_compare) {
-                                gen.addJump(false_label);
-                            } else {
-                                gen.addJumpIfR0LessThan(val + 1, false_label);
-                            }
-                        }
-                        break;
-                    case "jge":
-                        if (!false_label_is_fallthrough ||
-                                // We have no greater-than-or-equal-to register to register
-                                // comparison instruction, so in this case we'll jump
-                                // around an unconditional jump.
-                                (!true_label_is_fallthrough && reg_compare)) {
-                            if (reg_compare) {
-                                gen.addJumpIfR0LessThanR1(false_label);
-                            } else {
-                                gen.addJumpIfR0LessThan(val, false_label);
-                            }
-                        }
-                        if (!true_label_is_fallthrough) {
-                            if (!false_label_is_fallthrough || reg_compare) {
-                                gen.addJump(true_label);
-                            } else {
-                                gen.addJumpIfR0GreaterThan(val - 1, true_label);
-                            }
-                        }
-                        break;
-                }
-                break;
-            case "ret":
-                if (arg.equals("#0")) {
-                    gen.addJump(gen.DROP_LABEL);
-                } else {
-                    gen.addJump(gen.PASS_LABEL);
-                }
-                break;
-            case "tax":
-                gen.addMove(Register.R1);
-                break;
-            case "txa":
-                gen.addMove(Register.R0);
-                break;
-            default:
-                throw new IllegalArgumentException("Unhandled instruction: " + line);
-        }
-    }
-
-    /**
-     * Convert the output of "tcpdump -d" (human readable BPF program dump) {@code bpf} into an APF
-     * program and return it.
-     */
-    public static byte[] convert(String bpf) throws IllegalInstructionException {
-        ApfGenerator gen = new ApfGenerator(3);
-        for (String line : bpf.split("\\n")) convertLine(line, gen);
-        return gen.generate();
-    }
-
-    /**
-     * Convert the output of "tcpdump -d" (human readable BPF program dump) piped in stdin into an
-     * APF program and output it via stdout.
-     */
-    public static void main(String[] args) throws Exception {
-        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
-        String line = null;
-        StringBuilder responseData = new StringBuilder();
-        ApfGenerator gen = new ApfGenerator(3);
-        while ((line = in.readLine()) != null) convertLine(line, gen);
-        System.out.write(gen.generate());
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java b/packages/NetworkStack/tests/unit/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
deleted file mode 100644
index f948086..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2018 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.captiveportal;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.MalformedURLException;
-import java.text.ParseException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class CaptivePortalProbeSpecTest {
-
-    @Test
-    public void testGetResult_Regex() throws MalformedURLException, ParseException {
-        // 2xx status or 404, with an empty (match everything) location regex
-        CaptivePortalProbeSpec statusRegexSpec = CaptivePortalProbeSpec.parseSpec(
-                "http://www.google.com@@/@@2[0-9]{2}|404@@/@@");
-
-        // 404, or 301/302 redirect to some HTTPS page under google.com
-        CaptivePortalProbeSpec redirectSpec = CaptivePortalProbeSpec.parseSpec(
-                "http://google.com@@/@@404|30[12]@@/@@https://([0-9a-z]+\\.)*google\\.com.*");
-
-        assertSuccess(statusRegexSpec.getResult(200, null));
-        assertSuccess(statusRegexSpec.getResult(299, "qwer"));
-        assertSuccess(statusRegexSpec.getResult(404, null));
-        assertSuccess(statusRegexSpec.getResult(404, ""));
-
-        assertPortal(statusRegexSpec.getResult(300, null));
-        assertPortal(statusRegexSpec.getResult(399, "qwer"));
-        assertPortal(statusRegexSpec.getResult(500, null));
-
-        assertSuccess(redirectSpec.getResult(404, null));
-        assertSuccess(redirectSpec.getResult(404, ""));
-        assertSuccess(redirectSpec.getResult(301, "https://www.google.com"));
-        assertSuccess(redirectSpec.getResult(301, "https://www.google.com/test?q=3"));
-        assertSuccess(redirectSpec.getResult(302, "https://google.com/test?q=3"));
-
-        assertPortal(redirectSpec.getResult(299, "https://google.com/test?q=3"));
-        assertPortal(redirectSpec.getResult(299, ""));
-        assertPortal(redirectSpec.getResult(499, null));
-        assertPortal(redirectSpec.getResult(301, "http://login.portal.example.com/loginpage"));
-        assertPortal(redirectSpec.getResult(302, "http://www.google.com/test?q=3"));
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_Empty() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("");
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_Null() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec(null);
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_MissingParts() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123");
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_TooManyParts() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@456@@/@@extra");
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_InvalidStatusRegex() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@unmatched(parenthesis@@/@@456");
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_InvalidLocationRegex() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@unmatched[[]bracket");
-    }
-
-    @Test(expected = MalformedURLException.class)
-    public void testParseSpec_EmptyURL() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("@@/@@123@@/@@123");
-    }
-
-    @Test(expected = ParseException.class)
-    public void testParseSpec_NoParts() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("invalid");
-    }
-
-    @Test(expected = MalformedURLException.class)
-    public void testParseSpec_RegexInvalidUrl() throws MalformedURLException, ParseException {
-        CaptivePortalProbeSpec.parseSpec("notaurl@@/@@123@@/@@123");
-    }
-
-    @Test
-    public void testParseSpecOrNull_UsesSpec() {
-        final String specUrl = "http://google.com/probe";
-        final String redirectUrl = "https://google.com/probe";
-        CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(
-                specUrl + "@@/@@302@@/@@" + redirectUrl);
-        assertEquals(specUrl, spec.getUrl().toString());
-
-        assertPortal(spec.getResult(302, "http://portal.example.com"));
-        assertSuccess(spec.getResult(302, redirectUrl));
-    }
-
-    @Test
-    public void testParseSpecOrNull_UsesFallback() throws MalformedURLException {
-        CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(null);
-        assertNull(spec);
-
-        spec = CaptivePortalProbeSpec.parseSpecOrNull("");
-        assertNull(spec);
-
-        spec = CaptivePortalProbeSpec.parseSpecOrNull("@@/@@ @@/@@ @@/@@");
-        assertNull(spec);
-
-        spec = CaptivePortalProbeSpec.parseSpecOrNull("invalid@@/@@123@@/@@456");
-        assertNull(spec);
-    }
-
-    @Test
-    public void testParseSpecOrUseStatusCodeFallback_EmptySpec() throws MalformedURLException {
-        CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull("");
-        assertNull(spec);
-    }
-
-    private void assertIsStatusSpec(CaptivePortalProbeSpec spec) {
-        assertSuccess(spec.getResult(204, null));
-        assertSuccess(spec.getResult(204, "1234"));
-
-        assertPortal(spec.getResult(200, null));
-        assertPortal(spec.getResult(301, null));
-        assertPortal(spec.getResult(302, "1234"));
-        assertPortal(spec.getResult(399, ""));
-
-        assertFailed(spec.getResult(404, null));
-        assertFailed(spec.getResult(500, "1234"));
-    }
-
-    private void assertPortal(CaptivePortalProbeResult result) {
-        assertTrue(result.isPortal());
-    }
-
-    private void assertSuccess(CaptivePortalProbeResult result) {
-        assertTrue(result.isSuccessful());
-    }
-
-    private void assertFailed(CaptivePortalProbeResult result) {
-        assertTrue(result.isFailed());
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
deleted file mode 100644
index 27d7255..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.dhcp.DhcpLease.HOSTNAME_NONE;
-import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC;
-import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC;
-
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.util.SharedLog;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static java.lang.String.format;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpLeaseRepositoryTest {
-    private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247");
-    private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241");
-    private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243");
-    private static final MacAddress TEST_MAC_1 = MacAddress.fromBytes(
-            new byte[] { 5, 4, 3, 2, 1, 0 });
-    private static final MacAddress TEST_MAC_2 = MacAddress.fromBytes(
-            new byte[] { 0, 1, 2, 3, 4, 5 });
-    private static final MacAddress TEST_MAC_3 = MacAddress.fromBytes(
-            new byte[] { 0, 1, 2, 3, 4, 6 });
-    private static final Inet4Address TEST_INETADDR_1 = parseAddr4("192.168.42.248");
-    private static final Inet4Address TEST_INETADDR_2 = parseAddr4("192.168.42.249");
-    private static final String TEST_HOSTNAME_1 = "hostname1";
-    private static final String TEST_HOSTNAME_2 = "hostname2";
-    private static final IpPrefix TEST_IP_PREFIX = new IpPrefix(TEST_SERVER_ADDR, 22);
-    private static final long TEST_TIME = 100L;
-    private static final int TEST_LEASE_TIME_MS = 3_600_000;
-    private static final Set<Inet4Address> TEST_EXCL_SET =
-            Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
-                TEST_SERVER_ADDR, TEST_DEF_ROUTER, TEST_RESERVED_ADDR)));
-
-    @NonNull
-    private SharedLog mLog;
-    @NonNull @Mock
-    private Clock mClock;
-    @NonNull
-    private DhcpLeaseRepository mRepo;
-
-    private static Inet4Address parseAddr4(String inet4Addr) {
-        return (Inet4Address) parseNumericAddress(inet4Addr);
-    }
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mLog = new SharedLog("DhcpLeaseRepositoryTest");
-        when(mClock.elapsedRealtime()).thenReturn(TEST_TIME);
-        mRepo = new DhcpLeaseRepository(
-                TEST_IP_PREFIX, TEST_EXCL_SET, TEST_LEASE_TIME_MS, mLog, mClock);
-    }
-
-    /**
-     * Request a number of addresses through offer/request. Useful to test address exhaustion.
-     * @param nAddr Number of addresses to request.
-     */
-    private void requestAddresses(byte nAddr) throws Exception {
-        final HashSet<Inet4Address> addrs = new HashSet<>();
-        byte[] hwAddrBytes = new byte[] { 8, 4, 3, 2, 1, 0 };
-        for (byte i = 0; i < nAddr; i++) {
-            hwAddrBytes[5] = i;
-            MacAddress newMac = MacAddress.fromBytes(hwAddrBytes);
-            final String hostname = "host_" + i;
-            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac,
-                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
-
-            assertNotNull(lease);
-            assertEquals(newMac, lease.getHwAddr());
-            assertEquals(hostname, lease.getHostname());
-            assertTrue(format("Duplicate address allocated: %s in %s", lease.getNetAddr(), addrs),
-                    addrs.add(lease.getNetAddr()));
-
-            requestLeaseSelecting(newMac, lease.getNetAddr(), hostname);
-        }
-    }
-
-    @Test
-    public void testAddressExhaustion() throws Exception {
-        // Use a /28 to quickly run out of addresses
-        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
-        // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
-        requestAddresses((byte) 11);
-
-        try {
-            mRepo.getOffer(null, TEST_MAC_2,
-                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            fail("Should be out of addresses");
-        } catch (DhcpLeaseRepository.OutOfAddressesException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testUpdateParams_LeaseCleanup() throws Exception {
-        // Inside /28:
-        final Inet4Address reqAddrIn28 = parseAddr4("192.168.42.242");
-        final Inet4Address declinedAddrIn28 = parseAddr4("192.168.42.245");
-
-        // Inside /28, but not available there (first address of the range)
-        final Inet4Address declinedFirstAddrIn28 = parseAddr4("192.168.42.240");
-
-        final DhcpLease reqAddrIn28Lease = requestLeaseSelecting(TEST_MAC_1, reqAddrIn28);
-        mRepo.markLeaseDeclined(declinedAddrIn28);
-        mRepo.markLeaseDeclined(declinedFirstAddrIn28);
-
-        // Inside /22, but outside /28:
-        final Inet4Address reqAddrIn22 = parseAddr4("192.168.42.3");
-        final Inet4Address declinedAddrIn22 = parseAddr4("192.168.42.4");
-
-        final DhcpLease reqAddrIn22Lease = requestLeaseSelecting(TEST_MAC_3, reqAddrIn22);
-        mRepo.markLeaseDeclined(declinedAddrIn22);
-
-        // Address that will be reserved in the updateParams call below
-        final Inet4Address reservedAddr = parseAddr4("192.168.42.244");
-        final DhcpLease reservedAddrLease = requestLeaseSelecting(TEST_MAC_2, reservedAddr);
-
-        // Update from /22 to /28 and add another reserved address
-        Set<Inet4Address> newReserved = new HashSet<>(TEST_EXCL_SET);
-        newReserved.add(reservedAddr);
-        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), newReserved, TEST_LEASE_TIME_MS);
-
-        assertHasLease(reqAddrIn28Lease);
-        assertDeclined(declinedAddrIn28);
-
-        assertNotDeclined(declinedFirstAddrIn28);
-
-        assertNoLease(reqAddrIn22Lease);
-        assertNotDeclined(declinedAddrIn22);
-
-        assertNoLease(reservedAddrLease);
-    }
-
-    @Test
-    public void testGetOffer_StableAddress() throws Exception {
-        for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
-            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
-                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
-            // Same lease is offered twice
-            final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
-                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            assertEquals(lease, newLease);
-        }
-    }
-
-    @Test
-    public void testUpdateParams_UsesNewPrefix() throws Exception {
-        final IpPrefix newPrefix = new IpPrefix(parseAddr4("192.168.123.0"), 24);
-        mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
-        DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertTrue(newPrefix.contains(lease.getNetAddr()));
-    }
-
-    @Test
-    public void testGetOffer_ExistingLease() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1);
-
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
-    }
-
-    @Test
-    public void testGetOffer_ClientIdHasExistingLease() throws Exception {
-        final byte[] clientId = new byte[] { 1, 2 };
-        mRepo.requestLease(clientId, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
-                IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
-                TEST_HOSTNAME_1);
-
-        // Different MAC, but same clientId
-        DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
-    }
-
-    @Test
-    public void testGetOffer_DifferentClientId() throws Exception {
-        final byte[] clientId1 = new byte[] { 1, 2 };
-        final byte[] clientId2 = new byte[] { 3, 4 };
-        mRepo.requestLease(clientId1, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
-                IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
-                TEST_HOSTNAME_1);
-
-        // Same MAC, different client ID
-        DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        // Obtains a different address
-        assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(HOSTNAME_NONE, offer.getHostname());
-        assertEquals(TEST_MAC_1, offer.getHwAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddress() throws Exception {
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
-                TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1);
-        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressInUse() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, IPV4_ADDR_ANY /* relayAddr */,
-                TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressReserved() throws Exception {
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
-                TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressInvalid() throws Exception {
-        final Inet4Address invalidAddr = parseAddr4("192.168.42.0");
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
-                invalidAddr /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(invalidAddr, offer.getNetAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception {
-        final Inet4Address invalidAddr = parseAddr4("192.168.254.2");
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
-                invalidAddr /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(invalidAddr, offer.getNetAddr());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
-    public void testGetOffer_RelayInInvalidSubnet() throws Exception {
-        mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, parseAddr4("192.168.254.2") /* relayAddr */,
-                INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-    }
-
-    @Test
-    public void testRequestLease_SelectingTwice() throws Exception {
-        final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1,
-                TEST_HOSTNAME_1);
-
-        // Second request from same client for a different address
-        final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_2,
-                TEST_HOSTNAME_2);
-
-        assertEquals(TEST_INETADDR_1, lease1.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, lease1.getHostname());
-
-        assertEquals(TEST_INETADDR_2, lease2.getNetAddr());
-        assertEquals(TEST_HOSTNAME_2, lease2.getHostname());
-
-        // First address freed when client requested a different one: another client can request it
-        final DhcpLease lease3 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1, HOSTNAME_NONE);
-        assertEquals(TEST_INETADDR_1, lease3.getNetAddr());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_SelectingInvalid() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, parseAddr4("192.168.254.5"));
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_SelectingInUse() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_SelectingReserved() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_RESERVED_ADDR);
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
-    public void testRequestLease_SelectingRelayInInvalidSubnet() throws  Exception {
-        mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
-                parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */,
-                true /* sidSet */, HOSTNAME_NONE);
-    }
-
-    @Test
-    public void testRequestLease_InitReboot() throws Exception {
-        // Request address once
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
-        final long newTime = TEST_TIME + 100;
-        when(mClock.elapsedRealtime()).thenReturn(newTime);
-
-        // init-reboot (sidSet == false): verify configuration
-        final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_1);
-        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
-        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_InitRebootWrongAddr() throws Exception {
-        // Request address once
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        // init-reboot with different requested address
-        requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
-    }
-
-    @Test
-    public void testRequestLease_InitRebootUnknownAddr() throws Exception {
-        // init-reboot with unknown requested address
-        final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
-        // RFC2131 says we should not reply to accommodate other servers, but since we are
-        // authoritative we allow creating the lease to avoid issues with lost lease DB (same as
-        // dnsmasq behavior)
-        assertEquals(TEST_INETADDR_2, lease.getNetAddr());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_InitRebootWrongSubnet() throws Exception {
-        requestLeaseInitReboot(TEST_MAC_1, parseAddr4("192.168.254.2"));
-    }
-
-    @Test
-    public void testRequestLease_Renewing() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
-        final long newTime = TEST_TIME + 100;
-        when(mClock.elapsedRealtime()).thenReturn(newTime);
-
-        final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-
-        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
-        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
-    }
-
-    @Test
-    public void testRequestLease_RenewingUnknownAddr() throws Exception {
-        final long newTime = TEST_TIME + 100;
-        when(mClock.elapsedRealtime()).thenReturn(newTime);
-        final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-        // Allows renewing an unknown address if available
-        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
-        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_RenewingAddrInUse() throws Exception {
-        requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
-        requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_RenewingInvalidAddr() throws Exception {
-        requestLeaseRenewing(TEST_MAC_1, parseAddr4("192.168.254.2"));
-    }
-
-    @Test
-    public void testReleaseLease() throws Exception {
-        final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
-        assertHasLease(lease1);
-        assertTrue(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
-        assertNoLease(lease1);
-
-        final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
-        assertEquals(TEST_INETADDR_1, lease2.getNetAddr());
-    }
-
-    @Test
-    public void testReleaseLease_UnknownLease() {
-        assertFalse(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
-    }
-
-    @Test
-    public void testReleaseLease_StableOffer() throws Exception {
-        for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
-            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
-                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
-            requestLeaseSelecting(mac, lease.getNetAddr());
-            mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr());
-
-            // Same lease is offered after it was released
-            final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
-                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            assertEquals(lease.getNetAddr(), newLease.getNetAddr());
-        }
-    }
-
-    @Test
-    public void testMarkLeaseDeclined() throws Exception {
-        final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
-        mRepo.markLeaseDeclined(lease.getNetAddr());
-
-        // Same lease is not offered again
-        final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(lease.getNetAddr(), newLease.getNetAddr());
-    }
-
-    @Test
-    public void testMarkLeaseDeclined_UsedIfOutOfAddresses() throws Exception {
-        // Use a /28 to quickly run out of addresses
-        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
-        mRepo.markLeaseDeclined(TEST_INETADDR_1);
-        mRepo.markLeaseDeclined(TEST_INETADDR_2);
-
-        // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
-        requestAddresses((byte) 9);
-
-        // Last 2 addresses: addresses marked declined should be used
-        final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
-        requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr());
-
-        final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2,
-                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
-        requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr());
-
-        // Now out of addresses
-        try {
-            mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, IPV4_ADDR_ANY /* relayAddr */,
-                    INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            fail("Repository should be out of addresses and throw");
-        } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ }
-
-        assertEquals(TEST_INETADDR_1, firstLease.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, firstLease.getHostname());
-        assertEquals(TEST_INETADDR_2, secondLease.getNetAddr());
-        assertEquals(TEST_HOSTNAME_2, secondLease.getHostname());
-    }
-
-    private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr,
-            @Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet)
-            throws DhcpLeaseRepository.DhcpLeaseException {
-        return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr,
-                IPV4_ADDR_ANY /* relayAddr */,
-                reqAddr, sidSet, hostname);
-    }
-
-    /**
-     * Request a lease simulating a client in the SELECTING state.
-     */
-    private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address reqAddr, @Nullable String hostname)
-            throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, hostname,
-                true /* sidSet */);
-    }
-
-    /**
-     * Request a lease simulating a client in the SELECTING state.
-     */
-    private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLeaseSelecting(macAddr, reqAddr, HOSTNAME_NONE);
-    }
-
-    /**
-     * Request a lease simulating a client in the INIT-REBOOT state.
-     */
-    private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
-                false /* sidSet */);
-    }
-
-    /**
-     * Request a lease simulating a client in the RENEWING state.
-     */
-    private DhcpLease requestLeaseRenewing(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address clientAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        // Renewing: clientAddr filled in, no reqAddr
-        return requestLease(macAddr, clientAddr, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE,
-                true /* sidSet */);
-    }
-
-    private void assertNoLease(DhcpLease lease) {
-        assertFalse("Leases contain " + lease, mRepo.getCommittedLeases().contains(lease));
-    }
-
-    private void assertHasLease(DhcpLease lease) {
-        assertTrue("Leases do not contain " + lease, mRepo.getCommittedLeases().contains(lease));
-    }
-
-    private void assertNotDeclined(Inet4Address addr) {
-        assertFalse("Address is declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
-    }
-
-    private void assertDeclined(Inet4Address addr) {
-        assertTrue("Address is not declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
deleted file mode 100644
index a30d3e4..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpPacketTest.java
+++ /dev/null
@@ -1,1117 +0,0 @@
-/*
- * Copyright (C) 2015 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.dhcp;
-
-import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
-import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
-import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
-import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_ACK;
-import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_OFFER;
-import static android.net.dhcp.DhcpPacket.DHCP_MTU;
-import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
-import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
-import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.ENCAP_L2;
-import static android.net.dhcp.DhcpPacket.ENCAP_L3;
-import static android.net.dhcp.DhcpPacket.INADDR_ANY;
-import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
-import static android.net.dhcp.DhcpPacket.ParseException;
-import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
-import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.annotation.Nullable;
-import android.net.DhcpResults;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-import android.net.metrics.DhcpErrorEvent;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.HexDump;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Random;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpPacketTest {
-
-    private static final Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
-    private static final Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
-    private static final int PREFIX_LENGTH = 22;
-    private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
-    private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
-            SERVER_ADDR, PREFIX_LENGTH);
-    private static final String HOSTNAME = "testhostname";
-    private static final short MTU = 1500;
-    // Use our own empty address instead of IPV4_ADDR_ANY or INADDR_ANY to ensure that the code
-    // doesn't use == instead of equals when comparing addresses.
-    private static final Inet4Address ANY = v4Address("0.0.0.0");
-
-    private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-
-    private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException {
-        return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
-    }
-
-    @Before
-    public void setUp() {
-        DhcpPacket.testOverrideVendorId = "android-dhcp-???";
-        DhcpPacket.testOverrideHostname = "android-01234567890abcde";
-    }
-
-    class TestDhcpPacket extends DhcpPacket {
-        private byte mType;
-        // TODO: Make this a map of option numbers to bytes instead.
-        private byte[] mDomainBytes, mVendorInfoBytes, mLeaseTimeBytes, mNetmaskBytes;
-
-        public TestDhcpPacket(byte type, Inet4Address clientIp, Inet4Address yourIp) {
-            super(0xdeadbeef, (short) 0, clientIp, yourIp, INADDR_ANY, INADDR_ANY,
-                  CLIENT_MAC, true);
-            mType = type;
-        }
-
-        public TestDhcpPacket(byte type) {
-            this(type, INADDR_ANY, CLIENT_ADDR);
-        }
-
-        public TestDhcpPacket setDomainBytes(byte[] domainBytes) {
-            mDomainBytes = domainBytes;
-            return this;
-        }
-
-        public TestDhcpPacket setVendorInfoBytes(byte[] vendorInfoBytes) {
-            mVendorInfoBytes = vendorInfoBytes;
-            return this;
-        }
-
-        public TestDhcpPacket setLeaseTimeBytes(byte[] leaseTimeBytes) {
-            mLeaseTimeBytes = leaseTimeBytes;
-            return this;
-        }
-
-        public TestDhcpPacket setNetmaskBytes(byte[] netmaskBytes) {
-            mNetmaskBytes = netmaskBytes;
-            return this;
-        }
-
-        public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
-            ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
-            fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
-                         DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
-            return result;
-        }
-
-        public void finishPacket(ByteBuffer buffer) {
-            addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
-            if (mDomainBytes != null) {
-                addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
-            }
-            if (mVendorInfoBytes != null) {
-                addTlv(buffer, DHCP_VENDOR_INFO, mVendorInfoBytes);
-            }
-            if (mLeaseTimeBytes != null) {
-                addTlv(buffer, DHCP_LEASE_TIME, mLeaseTimeBytes);
-            }
-            if (mNetmaskBytes != null) {
-                addTlv(buffer, DHCP_SUBNET_MASK, mNetmaskBytes);
-            }
-            addTlvEnd(buffer);
-        }
-
-        // Convenience method.
-        public ByteBuffer build() {
-            // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
-            ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
-            pkt.flip();
-            return pkt;
-        }
-    }
-
-    private void assertDomainAndVendorInfoParses(
-            String expectedDomain, byte[] domainBytes,
-            String expectedVendorInfo, byte[] vendorInfoBytes) throws Exception {
-        ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER)
-                .setDomainBytes(domainBytes)
-                .setVendorInfoBytes(vendorInfoBytes)
-                .build();
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
-        assertEquals(expectedDomain, offerPacket.mDomainName);
-        assertEquals(expectedVendorInfo, offerPacket.mVendorInfo);
-    }
-
-    @Test
-    public void testDomainName() throws Exception {
-        byte[] nullByte = new byte[] { 0x00 };
-        byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
-        byte[] nonNullDomain = new byte[] {
-            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
-        };
-        byte[] trailingNullDomain = new byte[] {
-            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
-        };
-        byte[] embeddedNullsDomain = new byte[] {
-            (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
-        };
-        byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
-
-        byte[] meteredEmbeddedNull = metered.clone();
-        meteredEmbeddedNull[7] = (char) 0;
-
-        byte[] meteredTrailingNull = metered.clone();
-        meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
-
-        assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
-        assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
-        assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
-        assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
-                                        "ANDROID\u0000METERED", meteredEmbeddedNull);
-        assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
-                                        "ANDROID_METERE\u0000", meteredTrailingNull);
-    }
-
-    private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime,
-            long leaseTimeMillis, byte[] leaseTimeBytes) throws Exception {
-        TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER);
-        if (leaseTimeBytes != null) {
-            testPacket.setLeaseTimeBytes(leaseTimeBytes);
-        }
-        ByteBuffer packet = testPacket.build();
-        DhcpPacket offerPacket = null;
-
-        if (!expectValid) {
-            try {
-                offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
-                fail("Invalid packet parsed successfully: " + offerPacket);
-            } catch (ParseException expected) {
-            }
-            return;
-        }
-
-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
-        assertNotNull(offerPacket);
-        assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();  // Just check this doesn't crash.
-        assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
-    }
-
-    @Test
-    public void testLeaseTime() throws Exception {
-        byte[] noLease = null;
-        byte[] tooShortLease = new byte[] { 0x00, 0x00 };
-        byte[] tooLongLease = new byte[] { 0x00, 0x00, 0x00, 60, 0x01 };
-        byte[] zeroLease = new byte[] { 0x00, 0x00, 0x00, 0x00 };
-        byte[] tenSecondLease = new byte[] { 0x00, 0x00, 0x00, 10 };
-        byte[] oneMinuteLease = new byte[] { 0x00, 0x00, 0x00, 60 };
-        byte[] fiveMinuteLease = new byte[] { 0x00, 0x00, 0x01, 0x2c };
-        byte[] oneDayLease = new byte[] { 0x00, 0x01, 0x51, (byte) 0x80 };
-        byte[] maxIntPlusOneLease = new byte[] { (byte) 0x80, 0x00, 0x00, 0x01 };
-        byte[] infiniteLease = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-
-        assertLeaseTimeParses(true, null, 0, noLease);
-        assertLeaseTimeParses(false, null, 0, tooShortLease);
-        assertLeaseTimeParses(false, null, 0, tooLongLease);
-        assertLeaseTimeParses(true, 0, 60 * 1000, zeroLease);
-        assertLeaseTimeParses(true, 10, 60 * 1000, tenSecondLease);
-        assertLeaseTimeParses(true, 60, 60 * 1000, oneMinuteLease);
-        assertLeaseTimeParses(true, 300, 300 * 1000, fiveMinuteLease);
-        assertLeaseTimeParses(true, 86400, 86400 * 1000, oneDayLease);
-        assertLeaseTimeParses(true, -2147483647, 2147483649L * 1000, maxIntPlusOneLease);
-        assertLeaseTimeParses(true, DhcpPacket.INFINITE_LEASE, 0, infiniteLease);
-    }
-
-    private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp,
-                                byte[] netmaskBytes) throws Exception {
-        checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes);
-        checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes);
-    }
-
-    private void checkIpAddress(String expected, byte type,
-                                Inet4Address clientIp, Inet4Address yourIp,
-                                byte[] netmaskBytes) throws Exception {
-        ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
-                .setNetmaskBytes(netmaskBytes)
-                .build();
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
-        DhcpResults results = offerPacket.toDhcpResults();
-
-        if (expected != null) {
-            LinkAddress expectedAddress = new LinkAddress(expected);
-            assertEquals(expectedAddress, results.ipAddress);
-        } else {
-            assertNull(results);
-        }
-    }
-
-    @Test
-    public void testIpAddress() throws Exception {
-        byte[] slash11Netmask = new byte[] { (byte) 0xff, (byte) 0xe0, 0x00, 0x00 };
-        byte[] slash24Netmask = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 };
-        byte[] invalidNetmask = new byte[] { (byte) 0xff, (byte) 0xfb, (byte) 0xff, 0x00 };
-        Inet4Address example1 = v4Address("192.0.2.1");
-        Inet4Address example2 = v4Address("192.0.2.43");
-
-        // A packet without any addresses is not valid.
-        checkIpAddress(null, ANY, ANY, slash24Netmask);
-
-        // ClientIP is used iff YourIP is not present.
-        checkIpAddress("192.0.2.1/24", example2, example1, slash24Netmask);
-        checkIpAddress("192.0.2.43/11", example2, ANY, slash11Netmask);
-        checkIpAddress("192.0.2.43/11", ANY, example2, slash11Netmask);
-
-        // Invalid netmasks are ignored.
-        checkIpAddress(null, example2, ANY, invalidNetmask);
-
-        // If there is no netmask, implicit netmasks are used.
-        checkIpAddress("192.0.2.43/24", ANY, example2, null);
-    }
-
-    private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
-            String domains, String serverAddress, String serverHostName, String vendorInfo,
-            int leaseDuration, boolean hasMeteredHint, int mtu, DhcpResults dhcpResults)
-                    throws Exception {
-        assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
-        assertEquals(v4Address(gateway), dhcpResults.gateway);
-
-        String[] dnsServerStrings = dnsServersString.split(",");
-        ArrayList dnsServers = new ArrayList();
-        for (String dnsServerString : dnsServerStrings) {
-            dnsServers.add(v4Address(dnsServerString));
-        }
-        assertEquals(dnsServers, dhcpResults.dnsServers);
-
-        assertEquals(domains, dhcpResults.domains);
-        assertEquals(v4Address(serverAddress), dhcpResults.serverAddress);
-        assertEquals(serverHostName, dhcpResults.serverHostName);
-        assertEquals(vendorInfo, dhcpResults.vendorInfo);
-        assertEquals(leaseDuration, dhcpResults.leaseDuration);
-        assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
-        assertEquals(mtu, dhcpResults.mtu);
-    }
-
-    @Test
-    public void testOffer1() throws Exception {
-        // TODO: Turn all of these into golden files. This will probably require using
-        // androidx.test.InstrumentationRegistry for obtaining a Context object
-        // to read such golden files, along with an appropriate Android.mk.
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // IP header.
-            "451001480000000080118849c0a89003c0a89ff7" +
-            // UDP header.
-            "004300440134dcfa" +
-            // BOOTP header.
-            "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options
-            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
-            "3a0400000e103b040000189cff00000000000000000000"));
-        // CHECKSTYLE:ON Generated code
-
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
-                null, "192.168.144.3", "", null, 7200, false, 0, dhcpResults);
-    }
-
-    @Test
-    public void testOffer2() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name ("dhcp.android.com" plus invalid "AAAA" after null terminator).
-            "646863702e616e64726f69642e636f6d00000000000000000000000000000000" +
-            "0000000000004141414100000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options
-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
-        // CHECKSTYLE:ON Generated code
-
-        assertEquals(337, packet.limit());
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
-                null, "192.168.43.1", "dhcp.android.com", "ANDROID_METERED", 3600, true, 0,
-                dhcpResults);
-        assertTrue(dhcpResults.hasMeteredHint());
-    }
-
-    @Test
-    public void testBadIpPacket() throws Exception {
-        final byte[] packet = HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7");
-
-        try {
-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
-        } catch (DhcpPacket.ParseException expected) {
-            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
-            return;
-        }
-        fail("Dhcp packet parsing should have failed");
-    }
-
-    @Test
-    public void testBadDhcpPacket() throws Exception {
-        final byte[] packet = HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
-
-        try {
-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
-        } catch (DhcpPacket.ParseException expected) {
-            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
-            return;
-        }
-        fail("Dhcp packet parsing should have failed");
-    }
-
-    @Test
-    public void testBadTruncatedOffer() throws Exception {
-        final byte[] packet = HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File, missing one byte
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "00000000000000000000000000000000000000000000000000000000000000");
-
-        try {
-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
-        } catch (DhcpPacket.ParseException expected) {
-            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
-            return;
-        }
-        fail("Dhcp packet parsing should have failed");
-    }
-
-    @Test
-    public void testBadOfferWithoutACookie() throws Exception {
-        final byte[] packet = HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            // No options
-            );
-
-        try {
-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
-        } catch (DhcpPacket.ParseException expected) {
-            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
-            return;
-        }
-        fail("Dhcp packet parsing should have failed");
-    }
-
-    @Test
-    public void testOfferWithBadCookie() throws Exception {
-        final byte[] packet = HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Bad cookie
-            "DEADBEEF3501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
-
-        try {
-            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
-        } catch (DhcpPacket.ParseException expected) {
-            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
-            return;
-        }
-        fail("Dhcp packet parsing should have failed");
-    }
-
-    private void assertDhcpErrorCodes(int expected, int got) {
-        assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
-    }
-
-    @Test
-    public void testTruncatedOfferPackets() throws Exception {
-        final byte[] packet = HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options
-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
-
-        for (int len = 0; len < packet.length; len++) {
-            try {
-                DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
-            } catch (ParseException e) {
-                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
-                    fail(String.format("bad truncated packet of length %d", len));
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testRandomPackets() throws Exception {
-        final int maxRandomPacketSize = 512;
-        final Random r = new Random();
-        for (int i = 0; i < 10000; i++) {
-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
-            r.nextBytes(packet);
-            try {
-                DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
-            } catch (ParseException e) {
-                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
-                    fail("bad packet: " + HexDump.toHexString(packet));
-                }
-            }
-        }
-    }
-
-    private byte[] mtuBytes(int mtu) {
-        // 0x1a02: option 26, length 2. 0xff: no more options.
-        if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
-            throw new IllegalArgumentException(
-                String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
-        }
-        String hexString = String.format("1a02%04xff", mtu);
-        return HexDump.hexStringToByteArray(hexString);
-    }
-
-    private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
-        if (mtuBytes != null) {
-            packet.position(packet.capacity() - mtuBytes.length);
-            packet.put(mtuBytes);
-            packet.clear();
-        }
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
-                null, "192.168.144.3", "", null, 7200, false, expectedMtu, dhcpResults);
-    }
-
-    @Test
-    public void testMtu() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // IP header.
-            "451001480000000080118849c0a89003c0a89ff7" +
-            // UDP header.
-            "004300440134dcfa" +
-            // BOOTP header.
-            "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options
-            "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
-            "3a0400000e103b040000189cff00000000"));
-        // CHECKSTYLE:ON Generated code
-
-        checkMtu(packet, 0, null);
-        checkMtu(packet, 0, mtuBytes(1501));
-        checkMtu(packet, 1500, mtuBytes(1500));
-        checkMtu(packet, 1499, mtuBytes(1499));
-        checkMtu(packet, 1280, mtuBytes(1280));
-        checkMtu(packet, 0, mtuBytes(1279));
-        checkMtu(packet, 0, mtuBytes(576));
-        checkMtu(packet, 0, mtuBytes(68));
-        checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
-        checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
-        checkMtu(packet, 0, mtuBytes(-1));
-    }
-
-    @Test
-    public void testBadHwaddrLength() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // IP header.
-            "450001518d0600004011144dc0a82b01c0a82bf7" +
-            // UDP header.
-            "00430044013d9ac7" +
-            // BOOTP header.
-            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
-            // MAC address.
-            "30766ff2a90c00000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options
-            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
-        // CHECKSTYLE:ON Generated code
-        String expectedClientMac = "30766FF2A90C";
-
-        final int hwAddrLenOffset = 20 + 8 + 2;
-        assertEquals(6, packet.get(hwAddrLenOffset));
-
-        // Expect the expected.
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertNotNull(offerPacket);
-        assertEquals(6, offerPacket.getClientMac().length);
-        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
-
-        // Reduce the hardware address length and verify that it shortens the client MAC.
-        packet.flip();
-        packet.put(hwAddrLenOffset, (byte) 5);
-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertNotNull(offerPacket);
-        assertEquals(5, offerPacket.getClientMac().length);
-        assertEquals(expectedClientMac.substring(0, 10),
-                HexDump.toHexString(offerPacket.getClientMac()));
-
-        packet.flip();
-        packet.put(hwAddrLenOffset, (byte) 3);
-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertNotNull(offerPacket);
-        assertEquals(3, offerPacket.getClientMac().length);
-        assertEquals(expectedClientMac.substring(0, 6),
-                HexDump.toHexString(offerPacket.getClientMac()));
-
-        // Set the the hardware address length to 0xff and verify that we a) don't treat it as -1
-        // and crash, and b) hardcode it to 6.
-        packet.flip();
-        packet.put(hwAddrLenOffset, (byte) -1);
-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertNotNull(offerPacket);
-        assertEquals(6, offerPacket.getClientMac().length);
-        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
-
-        // Set the the hardware address length to a positive invalid value (> 16) and verify that we
-        // hardcode it to 6.
-        packet.flip();
-        packet.put(hwAddrLenOffset, (byte) 17);
-        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertNotNull(offerPacket);
-        assertEquals(6, offerPacket.getClientMac().length);
-        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
-    }
-
-    @Test
-    public void testPadAndOverloadedOptionsOffer() throws Exception {
-        // A packet observed in the real world that is interesting for two reasons:
-        //
-        // 1. It uses pad bytes, which we previously didn't support correctly.
-        // 2. It uses DHCP option overloading, which we don't currently support (but it doesn't
-        //    store any information in the overloaded fields).
-        //
-        // For now, we just check that it parses correctly.
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // Ethernet header.
-            "b4cef6000000e80462236e300800" +
-            // IP header.
-            "4500014c00000000ff11741701010101ac119876" +
-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
-            "004300440138ae5a" +
-            // BOOTP header.
-            "020106000fa0059f0000000000000000ac1198760000000000000000" +
-            // MAC address.
-            "b4cef600000000000000000000000000" +
-            // Server name.
-            "ff00000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "ff00000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options
-            "638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
-            "0000000000000000000000000000000000000000000000ff000000"));
-        // CHECKSTYLE:ON Generated code
-
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
-                null, "1.1.1.1", "", null, 43200, false, 0, dhcpResults);
-    }
-
-    @Test
-    public void testBug2111() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // IP header.
-            "4500014c00000000ff119beac3eaf3880a3f5d04" +
-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
-            "0043004401387464" +
-            // BOOTP header.
-            "0201060002554812000a0000000000000a3f5d040000000000000000" +
-            // MAC address.
-            "00904c00000000000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options.
-            "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
-            "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
-        // CHECKSTYLE:ON Generated code
-
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
-                "domain123.co.uk", "192.0.2.254", "", null, 49094, false, 0, dhcpResults);
-    }
-
-    @Test
-    public void testBug2136() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // Ethernet header.
-            "bcf5ac000000d0c7890000000800" +
-            // IP header.
-            "4500014c00000000ff119beac3eaf3880a3f5d04" +
-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
-            "0043004401387574" +
-            // BOOTP header.
-            "0201060163339a3000050000000000000a209ecd0000000000000000" +
-            // MAC address.
-            "bcf5ac00000000000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options.
-            "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
-            "0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
-        // CHECKSTYLE:ON Generated code
-
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);
-        assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
-                "lancs.ac.uk", "10.32.255.128", "", null, 7200, false, 0, dhcpResults);
-    }
-
-    @Test
-    public void testUdpServerAnySourcePort() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // Ethernet header.
-            "9cd917000000001c2e0000000800" +
-            // IP header.
-            "45a00148000040003d115087d18194fb0a0f7af2" +
-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
-            // NOTE: The server source port is not the canonical port 67.
-            "C29F004401341268" +
-            // BOOTP header.
-            "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
-            // MAC address.
-            "9cd91700000000000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options.
-            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
-            "d18180060f0777766d2e6564751c040a0fffffff000000"));
-        // CHECKSTYLE:ON Generated code
-
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);
-        assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("10.15.122.242/16", "10.15.200.23",
-                "209.129.128.3,209.129.148.3,209.129.128.6",
-                "wvm.edu", "10.1.105.252", "", null, 86400, false, 0, dhcpResults);
-    }
-
-    @Test
-    public void testUdpInvalidDstPort() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // Ethernet header.
-            "9cd917000000001c2e0000000800" +
-            // IP header.
-            "45a00148000040003d115087d18194fb0a0f7af2" +
-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
-            // NOTE: The destination port is a non-DHCP port.
-            "0043aaaa01341268" +
-            // BOOTP header.
-            "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
-            // MAC address.
-            "9cd91700000000000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options.
-            "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
-            "d18180060f0777766d2e6564751c040a0fffffff000000"));
-        // CHECKSTYLE:ON Generated code
-
-        try {
-            DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
-            fail("Packet with invalid dst port did not throw ParseException");
-        } catch (ParseException expected) {}
-    }
-
-    @Test
-    public void testMultipleRouters() throws Exception {
-        // CHECKSTYLE:OFF Generated code
-        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
-            // Ethernet header.
-            "fc3d93000000" + "081735000000" + "0800" +
-            // IP header.
-            "45000148c2370000ff117ac2c0a8bd02ffffffff" +
-            // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
-            "0043004401343beb" +
-            // BOOTP header.
-            "0201060027f518e20000800000000000c0a8bd310000000000000000" +
-            // MAC address.
-            "fc3d9300000000000000000000000000" +
-            // Server name.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // File.
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            "0000000000000000000000000000000000000000000000000000000000000000" +
-            // Options.
-            "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
-            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
-        // CHECKSTYLE:ON Generated code
-
-        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
-        assertTrue(offerPacket instanceof DhcpOfferPacket);
-        assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
-        DhcpResults dhcpResults = offerPacket.toDhcpResults();
-        assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
-                null, "192.171.189.2", "", null, 28800, false, 0, dhcpResults);
-    }
-
-    @Test
-    public void testDiscoverPacket() throws Exception {
-        short secs = 7;
-        int transactionId = 0xdeadbeef;
-        byte[] hwaddr = {
-                (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a
-        };
-
-        ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
-                DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
-                false /* do unicast */, DhcpClient.REQUESTED_PARAMS);
-
-        byte[] headers = new byte[] {
-            // Ethernet header.
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
-            (byte) 0x08, (byte) 0x00,
-            // IP header.
-            (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x56,
-            (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x00,
-            (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x88,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            // UDP header.
-            (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
-            (byte) 0x01, (byte) 0x42, (byte) 0x6a, (byte) 0x4a,
-            // BOOTP.
-            (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00,
-            (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
-            (byte) 0x00, (byte) 0x07, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-            (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b,
-            (byte) 0xb1, (byte) 0x7a
-        };
-        byte[] options = new byte[] {
-            // Magic cookie 0x63825363.
-            (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
-            // Message type DISCOVER.
-            (byte) 0x35, (byte) 0x01, (byte) 0x01,
-            // Client identifier Ethernet, da:01:19:5b:b1:7a.
-            (byte) 0x3d, (byte) 0x07,
-                    (byte) 0x01,
-                    (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
-            // Max message size 1500.
-            (byte) 0x39, (byte) 0x02, (byte) 0x05, (byte) 0xdc,
-            // Version "android-dhcp-???".
-            (byte) 0x3c, (byte) 0x10,
-                    'a', 'n', 'd', 'r', 'o', 'i', 'd', '-', 'd', 'h', 'c', 'p', '-', '?', '?', '?',
-            // Hostname "android-01234567890abcde"
-            (byte) 0x0c, (byte) 0x18,
-                    'a', 'n', 'd', 'r', 'o', 'i', 'd', '-',
-                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e',
-            // Requested parameter list.
-            (byte) 0x37, (byte) 0x0a,
-                DHCP_SUBNET_MASK,
-                DHCP_ROUTER,
-                DHCP_DNS_SERVER,
-                DHCP_DOMAIN_NAME,
-                DHCP_MTU,
-                DHCP_BROADCAST_ADDRESS,
-                DHCP_LEASE_TIME,
-                DHCP_RENEWAL_TIME,
-                DHCP_REBINDING_TIME,
-                DHCP_VENDOR_INFO,
-            // End options.
-            (byte) 0xff,
-            // Our packets are always of even length. TODO: find out why and possibly fix it.
-            (byte) 0x00
-        };
-        byte[] expected = new byte[DhcpPacket.MIN_PACKET_LENGTH_L2 + options.length];
-        assertTrue((expected.length & 1) == 0);
-        System.arraycopy(headers, 0, expected, 0, headers.length);
-        System.arraycopy(options, 0, expected, DhcpPacket.MIN_PACKET_LENGTH_L2, options.length);
-
-        byte[] actual = new byte[packet.limit()];
-        packet.get(actual);
-        String msg =
-                "Expected:\n  " + Arrays.toString(expected) +
-                "\nActual:\n  " + Arrays.toString(actual);
-        assertTrue(msg, Arrays.equals(expected, actual));
-    }
-
-    public void checkBuildOfferPacket(int leaseTimeSecs, @Nullable String hostname)
-            throws Exception {
-        final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2);
-        final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000);
-        final int transactionId = 0xdeadbeef;
-
-        final ByteBuffer packet = DhcpPacket.buildOfferPacket(
-                DhcpPacket.ENCAP_BOOTP, transactionId, false /* broadcast */,
-                SERVER_ADDR, INADDR_ANY /* relayIp */, CLIENT_ADDR /* yourIp */,
-                CLIENT_MAC, leaseTimeSecs, NETMASK /* netMask */,
-                BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */,
-                Collections.singletonList(SERVER_ADDR) /* dnsServers */,
-                SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname,
-                false /* metered */, MTU);
-
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        // BOOTP headers
-        bos.write(new byte[] {
-                (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x00,
-                (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
-                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-                // ciaddr
-                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
-        });
-        // yiaddr
-        bos.write(CLIENT_ADDR.getAddress());
-        // siaddr
-        bos.write(SERVER_ADDR.getAddress());
-        // giaddr
-        bos.write(INADDR_ANY.getAddress());
-        // chaddr
-        bos.write(CLIENT_MAC);
-
-        // Padding
-        bos.write(new byte[202]);
-
-        // Options
-        bos.write(new byte[]{
-                // Magic cookie 0x63825363.
-                (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
-                // Message type OFFER.
-                (byte) 0x35, (byte) 0x01, (byte) 0x02,
-        });
-        // Server ID
-        bos.write(new byte[] { (byte) 0x36, (byte) 0x04 });
-        bos.write(SERVER_ADDR.getAddress());
-        // Lease time
-        bos.write(new byte[] { (byte) 0x33, (byte) 0x04 });
-        bos.write(intToByteArray(leaseTimeSecs));
-        if (leaseTimeSecs != INFINITE_LEASE) {
-            // Renewal time
-            bos.write(new byte[]{(byte) 0x3a, (byte) 0x04});
-            bos.write(intToByteArray(renewalTime));
-            // Rebinding time
-            bos.write(new byte[]{(byte) 0x3b, (byte) 0x04});
-            bos.write(intToByteArray(rebindingTime));
-        }
-        // Subnet mask
-        bos.write(new byte[] { (byte) 0x01, (byte) 0x04 });
-        bos.write(NETMASK.getAddress());
-        // Broadcast address
-        bos.write(new byte[] { (byte) 0x1c, (byte) 0x04 });
-        bos.write(BROADCAST_ADDR.getAddress());
-        // Router
-        bos.write(new byte[] { (byte) 0x03, (byte) 0x04 });
-        bos.write(SERVER_ADDR.getAddress());
-        // Nameserver
-        bos.write(new byte[] { (byte) 0x06, (byte) 0x04 });
-        bos.write(SERVER_ADDR.getAddress());
-        // Hostname
-        if (hostname != null) {
-            bos.write(new byte[]{(byte) 0x0c, (byte) hostname.length()});
-            bos.write(hostname.getBytes(Charset.forName("US-ASCII")));
-        }
-        // MTU
-        bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 });
-        bos.write(shortToByteArray(MTU));
-        // End options.
-        bos.write(0xff);
-
-        if ((bos.size() & 1) != 0) {
-            bos.write(0x00);
-        }
-
-        final byte[] expected = bos.toByteArray();
-        final byte[] actual = new byte[packet.limit()];
-        packet.get(actual);
-        final String msg = "Expected:\n  " + HexDump.dumpHexString(expected) +
-                "\nActual:\n  " + HexDump.dumpHexString(actual);
-        assertTrue(msg, Arrays.equals(expected, actual));
-    }
-
-    @Test
-    public void testOfferPacket() throws Exception {
-        checkBuildOfferPacket(3600, HOSTNAME);
-        checkBuildOfferPacket(Integer.MAX_VALUE, HOSTNAME);
-        checkBuildOfferPacket(0x80000000, HOSTNAME);
-        checkBuildOfferPacket(INFINITE_LEASE, HOSTNAME);
-        checkBuildOfferPacket(3600, null);
-    }
-
-    private static byte[] intToByteArray(int val) {
-        return ByteBuffer.allocate(4).putInt(val).array();
-    }
-
-    private static byte[] shortToByteArray(short val) {
-        return ByteBuffer.allocate(2).putShort(val).array();
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServerTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServerTest.java
deleted file mode 100644
index f0e2f1b..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServerTest.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
-import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.INADDR_ANY;
-import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
-import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.INetworkStackStatusCallback;
-import android.net.LinkAddress;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException;
-import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.dhcp.DhcpServer.Dependencies;
-import android.net.util.SharedLog;
-import android.os.HandlerThread;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-@RunWithLooper
-public class DhcpServerTest {
-    private static final String TEST_IFACE = "testiface";
-
-    private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
-    private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
-    private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
-    private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
-    private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
-    private static final long TEST_LEASE_TIME_SECS = 3600L;
-    private static final int TEST_MTU = 1500;
-    private static final String TEST_HOSTNAME = "testhostname";
-
-    private static final int TEST_TRANSACTION_ID = 123;
-    private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 };
-    private static final MacAddress TEST_CLIENT_MAC = MacAddress.fromBytes(TEST_CLIENT_MAC_BYTES);
-    private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42");
-
-    private static final long TEST_CLOCK_TIME = 1234L;
-    private static final int TEST_LEASE_EXPTIME_SECS = 3600;
-    private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC,
-            TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME,
-            null /* hostname */);
-    private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC,
-            TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME);
-
-    @NonNull @Mock
-    private Dependencies mDeps;
-    @NonNull @Mock
-    private DhcpLeaseRepository mRepository;
-    @NonNull @Mock
-    private Clock mClock;
-    @NonNull @Mock
-    private DhcpPacketListener mPacketListener;
-
-    @NonNull @Captor
-    private ArgumentCaptor<ByteBuffer> mSentPacketCaptor;
-    @NonNull @Captor
-    private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor;
-
-    @NonNull
-    private HandlerThread mHandlerThread;
-    @NonNull
-    private TestableLooper mLooper;
-    @NonNull
-    private DhcpServer mServer;
-
-    @Nullable
-    private String mPrevShareClassloaderProp;
-
-    private final INetworkStackStatusCallback mAssertSuccessCallback =
-            new INetworkStackStatusCallback.Stub() {
-        @Override
-        public void onStatusAvailable(int statusCode) {
-            assertEquals(STATUS_SUCCESS, statusCode);
-        }
-
-        @Override
-        public int getInterfaceVersion() {
-            return this.VERSION;
-        }
-    };
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository);
-        when(mDeps.makeClock()).thenReturn(mClock);
-        when(mDeps.makePacketListener()).thenReturn(mPacketListener);
-        doNothing().when(mDeps)
-                .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture());
-        when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME);
-
-        final DhcpServingParams servingParams = new DhcpServingParams.Builder()
-                .setDefaultRouters(TEST_DEFAULT_ROUTERS)
-                .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
-                .setDnsServers(TEST_DNS_SERVERS)
-                .setServerAddr(TEST_SERVER_LINKADDR)
-                .setLinkMtu(TEST_MTU)
-                .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
-                .build();
-
-        mLooper = TestableLooper.get(this);
-        mHandlerThread = spy(new HandlerThread("TestDhcpServer"));
-        when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
-        mServer = new DhcpServer(mHandlerThread, TEST_IFACE, servingParams,
-                new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps);
-
-        mServer.start(mAssertSuccessCallback);
-        mLooper.processAllMessages();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mServer.stop(mAssertSuccessCallback);
-        mLooper.processMessages(1);
-        verify(mPacketListener, times(1)).stop();
-        verify(mHandlerThread, times(1)).quitSafely();
-    }
-
-    @Test
-    public void testStart() throws Exception {
-        verify(mPacketListener, times(1)).start();
-    }
-
-    @Test
-    public void testDiscover() throws Exception {
-        // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields
-        when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
-                .thenReturn(TEST_LEASE);
-
-        final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
-                (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
-                false /* broadcast */, INADDR_ANY /* srcIp */);
-        mServer.processPacket(discover, DHCP_CLIENT);
-
-        assertResponseSentTo(TEST_CLIENT_ADDR);
-        final DhcpOfferPacket packet = assertOffer(getPacket());
-        assertMatchesTestLease(packet);
-    }
-
-    @Test
-    public void testDiscover_OutOfAddresses() throws Exception {
-        when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
-                .thenThrow(new OutOfAddressesException("Test exception"));
-
-        final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
-                (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
-                false /* broadcast */, INADDR_ANY /* srcIp */);
-        mServer.processPacket(discover, DHCP_CLIENT);
-
-        assertResponseSentTo(INADDR_BROADCAST);
-        final DhcpNakPacket packet = assertNak(getPacket());
-        assertMatchesClient(packet);
-    }
-
-    private DhcpRequestPacket makeRequestSelectingPacket() {
-        final DhcpRequestPacket request = new DhcpRequestPacket(TEST_TRANSACTION_ID,
-                (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* relayIp */,
-                TEST_CLIENT_MAC_BYTES, false /* broadcast */);
-        request.mServerIdentifier = TEST_SERVER_ADDR;
-        request.mRequestedIp = TEST_CLIENT_ADDR;
-        return request;
-    }
-
-    @Test
-    public void testRequest_Selecting_Ack() throws Exception {
-        when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
-                eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME)))
-                .thenReturn(TEST_LEASE_WITH_HOSTNAME);
-
-        final DhcpRequestPacket request = makeRequestSelectingPacket();
-        request.mHostName = TEST_HOSTNAME;
-        request.mRequestedParams = new byte[] { DHCP_HOST_NAME };
-        mServer.processPacket(request, DHCP_CLIENT);
-
-        assertResponseSentTo(TEST_CLIENT_ADDR);
-        final DhcpAckPacket packet = assertAck(getPacket());
-        assertMatchesTestLease(packet, TEST_HOSTNAME);
-    }
-
-    @Test
-    public void testRequest_Selecting_Nak() throws Exception {
-        when(mRepository.requestLease(isNull(), eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
-                eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */))
-                .thenThrow(new InvalidAddressException("Test error"));
-
-        final DhcpRequestPacket request = makeRequestSelectingPacket();
-        mServer.processPacket(request, DHCP_CLIENT);
-
-        assertResponseSentTo(INADDR_BROADCAST);
-        final DhcpNakPacket packet = assertNak(getPacket());
-        assertMatchesClient(packet);
-    }
-
-    @Test
-    public void testRequest_Selecting_WrongClientPort() throws Exception {
-        final DhcpRequestPacket request = makeRequestSelectingPacket();
-        mServer.processPacket(request, 50000);
-
-        verify(mRepository, never())
-                .requestLease(any(), any(), any(), any(), any(), anyBoolean(), any());
-        verify(mDeps, never()).sendPacket(any(), any(), any());
-    }
-
-    @Test
-    public void testRelease() throws Exception {
-        final DhcpReleasePacket release = new DhcpReleasePacket(TEST_TRANSACTION_ID,
-                TEST_SERVER_ADDR, TEST_CLIENT_ADDR,
-                INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES);
-        mServer.processPacket(release, DHCP_CLIENT);
-
-        verify(mRepository, times(1))
-                .releaseLease(isNull(), eq(TEST_CLIENT_MAC), eq(TEST_CLIENT_ADDR));
-    }
-
-    /* TODO: add more tests once packet construction is refactored, including:
-     *  - usage of giaddr
-     *  - usage of broadcast bit
-     *  - other request states (init-reboot/renewing/rebinding)
-     */
-
-    private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) {
-        assertMatchesClient(packet);
-        assertFalse(packet.hasExplicitClientId());
-        assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier);
-        assertEquals(TEST_CLIENT_ADDR, packet.mYourIp);
-        assertNotNull(packet.mLeaseTime);
-        assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime);
-        assertEquals(hostname, packet.mHostName);
-    }
-
-    private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
-        assertMatchesTestLease(packet, null);
-    }
-
-    private void assertMatchesClient(@NonNull DhcpPacket packet) {
-        assertEquals(TEST_TRANSACTION_ID, packet.mTransId);
-        assertEquals(TEST_CLIENT_MAC, MacAddress.fromBytes(packet.mClientMac));
-    }
-
-    private void assertResponseSentTo(@NonNull Inet4Address addr) {
-        assertEquals(addr, mResponseDstAddrCaptor.getValue());
-    }
-
-    private static DhcpNakPacket assertNak(@Nullable DhcpPacket packet) {
-        assertTrue(packet instanceof DhcpNakPacket);
-        return (DhcpNakPacket) packet;
-    }
-
-    private static DhcpAckPacket assertAck(@Nullable DhcpPacket packet) {
-        assertTrue(packet instanceof DhcpAckPacket);
-        return (DhcpAckPacket) packet;
-    }
-
-    private static DhcpOfferPacket assertOffer(@Nullable DhcpPacket packet) {
-        assertTrue(packet instanceof DhcpOfferPacket);
-        return (DhcpOfferPacket) packet;
-    }
-
-    private DhcpPacket getPacket() throws Exception {
-        verify(mDeps, times(1)).sendPacket(any(), any(), any());
-        return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP);
-    }
-
-    private static Inet4Address parseAddr(@Nullable String inet4Addr) {
-        return (Inet4Address) parseNumericAddress(inet4Addr);
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServingParamsTest.java
deleted file mode 100644
index 57a87a4..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/dhcp/DhcpServingParamsTest.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.LinkAddress;
-import android.net.dhcp.DhcpServingParams.InvalidParameterException;
-import android.net.shared.Inet4AddressUtils;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Modifier;
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpServingParamsTest {
-    @NonNull
-    private DhcpServingParams.Builder mBuilder;
-
-    private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
-    private static final long TEST_LEASE_TIME_SECS = 3600L;
-    private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
-    private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
-    private static final LinkAddress TEST_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
-    private static final int TEST_MTU = 1500;
-    private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
-    private static final boolean TEST_METERED = true;
-
-    @Before
-    public void setUp() {
-        mBuilder = new DhcpServingParams.Builder()
-                .setDefaultRouters(TEST_DEFAULT_ROUTERS)
-                .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
-                .setDnsServers(TEST_DNS_SERVERS)
-                .setServerAddr(TEST_LINKADDR)
-                .setLinkMtu(TEST_MTU)
-                .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
-                .setMetered(TEST_METERED);
-    }
-
-    @Test
-    public void testBuild_Immutable() throws InvalidParameterException {
-        final Set<Inet4Address> routers = new HashSet<>(TEST_DEFAULT_ROUTERS);
-        final Set<Inet4Address> dnsServers = new HashSet<>(TEST_DNS_SERVERS);
-        final Set<Inet4Address> excludedAddrs = new HashSet<>(TEST_EXCLUDED_ADDRS);
-
-        final DhcpServingParams params = mBuilder
-                .setDefaultRouters(routers)
-                .setDnsServers(dnsServers)
-                .setExcludedAddrs(excludedAddrs)
-                .build();
-
-        // Modifications to source objects should not affect builder or final parameters
-        final Inet4Address addedAddr = parseAddr("192.168.0.223");
-        routers.add(addedAddr);
-        dnsServers.add(addedAddr);
-        excludedAddrs.add(addedAddr);
-
-        assertEquals(TEST_DEFAULT_ROUTERS, params.defaultRouters);
-        assertEquals(TEST_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
-        assertEquals(TEST_DNS_SERVERS, params.dnsServers);
-        assertEquals(TEST_LINKADDR, params.serverAddr);
-        assertEquals(TEST_MTU, params.linkMtu);
-        assertEquals(TEST_METERED, params.metered);
-
-        assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
-        assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
-        assertContains(params.excludedAddrs, TEST_DNS_SERVERS);
-        assertContains(params.excludedAddrs, TEST_SERVER_ADDR);
-
-        assertFalse("excludedAddrs should not contain " + addedAddr,
-                params.excludedAddrs.contains(addedAddr));
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_NegativeLeaseTime() throws InvalidParameterException {
-        mBuilder.setDhcpLeaseTimeSecs(-1).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_LeaseTimeTooLarge() throws InvalidParameterException {
-        // Set lease time larger than max value for uint32
-        mBuilder.setDhcpLeaseTimeSecs(1L << 32).build();
-    }
-
-    @Test
-    public void testBuild_InfiniteLeaseTime() throws InvalidParameterException {
-        final long infiniteLeaseTime = 0xffffffffL;
-        final DhcpServingParams params = mBuilder
-                .setDhcpLeaseTimeSecs(infiniteLeaseTime).build();
-        assertEquals(infiniteLeaseTime, params.dhcpLeaseTimeSecs);
-        assertTrue(params.dhcpLeaseTimeSecs > 0L);
-    }
-
-    @Test
-    public void testBuild_UnsetMtu() throws InvalidParameterException {
-        final DhcpServingParams params = mBuilder.setLinkMtu(MTU_UNSET).build();
-        assertEquals(MTU_UNSET, params.linkMtu);
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_MtuTooSmall() throws InvalidParameterException {
-        mBuilder.setLinkMtu(20).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_MtuTooLarge() throws InvalidParameterException {
-        mBuilder.setLinkMtu(65_536).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_IPv6Addr() throws InvalidParameterException {
-        mBuilder.setServerAddr(new LinkAddress(parseNumericAddress("fe80::1111"), 120)).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_PrefixTooLarge() throws InvalidParameterException {
-        mBuilder.setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 15)).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_PrefixTooSmall() throws InvalidParameterException {
-        mBuilder.setDefaultRouters(parseAddr("192.168.0.254"))
-                .setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 31))
-                .build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_RouterNotInPrefix() throws InvalidParameterException {
-        mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
-    }
-
-    @Test
-    public void testFromParcelableObject() throws InvalidParameterException {
-        final DhcpServingParams params = mBuilder.build();
-        final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel();
-        parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS);
-        parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS;
-        parcel.dnsServers = toIntArray(TEST_DNS_SERVERS);
-        parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR);
-        parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength();
-        parcel.linkMtu = TEST_MTU;
-        parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS);
-        parcel.metered = TEST_METERED;
-        final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel);
-
-        assertEquals(params.defaultRouters, parceled.defaultRouters);
-        assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs);
-        assertEquals(params.dnsServers, parceled.dnsServers);
-        assertEquals(params.serverAddr, parceled.serverAddr);
-        assertEquals(params.linkMtu, parceled.linkMtu);
-        assertEquals(params.excludedAddrs, parceled.excludedAddrs);
-        assertEquals(params.metered, parceled.metered);
-
-        // Ensure that we do not miss any field if added in the future
-        final long numFields = Arrays.stream(DhcpServingParams.class.getDeclaredFields())
-                .filter(f -> !Modifier.isStatic(f.getModifiers()))
-                .count();
-        assertEquals(7, numFields);
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testFromParcelableObject_NullArgument() throws InvalidParameterException {
-        DhcpServingParams.fromParcelableObject(null);
-    }
-
-    private static int[] toIntArray(Collection<Inet4Address> addrs) {
-        return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray();
-    }
-
-    private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
-        for (final T elem : subset) {
-            assertContains(set, elem);
-        }
-    }
-
-    private static <T> void assertContains(@NonNull Set<T> set, @Nullable T elem) {
-        assertTrue("Set does not contain " + elem, set.contains(elem));
-    }
-
-    @NonNull
-    private static Inet4Address parseAddr(@NonNull String inet4Addr) {
-        return (Inet4Address) parseNumericAddress(inet4Addr);
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/unit/src/android/net/ip/IpClientTest.java
deleted file mode 100644
index 5f80006..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/ip/IpClientTest.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (C) 2017 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.ip;
-
-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.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.AlarmManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.INetd;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MacAddress;
-import android.net.NetworkStackIpMemoryStore;
-import android.net.RouteInfo;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.shared.InitialConfiguration;
-import android.net.shared.ProvisioningConfiguration;
-import android.net.util.InterfaceParams;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.server.NetworkObserver;
-import com.android.server.NetworkObserverRegistry;
-import com.android.server.NetworkStackService;
-
-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.net.InetAddress;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Tests for IpClient.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpClientTest {
-    private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
-
-    private static final String VALID = "VALID";
-    private static final String INVALID = "INVALID";
-    private static final String TEST_IFNAME = "test_wlan0";
-    private static final int TEST_IFINDEX = 1001;
-    // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
-    private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
-    private static final int TEST_TIMEOUT_MS = 400;
-    private static final String TEST_L2KEY = "some l2key";
-    private static final String TEST_GROUPHINT = "some grouphint";
-
-    @Mock private Context mContext;
-    @Mock private ConnectivityManager mCm;
-    @Mock private NetworkObserverRegistry mObserverRegistry;
-    @Mock private INetd mNetd;
-    @Mock private Resources mResources;
-    @Mock private IIpClientCallbacks mCb;
-    @Mock private AlarmManager mAlarm;
-    @Mock private IpClient.Dependencies mDependencies;
-    @Mock private ContentResolver mContentResolver;
-    @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
-    @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
-
-    private NetworkObserver mObserver;
-    private InterfaceParams mIfParams;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
-        when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
-        when(mContext.getResources()).thenReturn(mResources);
-        when(mDependencies.getNetd(any())).thenReturn(mNetd);
-        when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
-                .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
-        when(mContext.getContentResolver()).thenReturn(mContentResolver);
-
-        mIfParams = null;
-    }
-
-    private void setTestInterfaceParams(String ifname) {
-        mIfParams = (ifname != null)
-                ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
-                : null;
-        when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
-    }
-
-    private IpClient makeIpClient(String ifname) throws Exception {
-        setTestInterfaceParams(ifname);
-        final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
-                mNetworkStackServiceManager, mDependencies);
-        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
-        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
-        ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
-        verify(mObserverRegistry, times(1)).registerObserverForNonblockingCallback(arg.capture());
-        mObserver = arg.getValue();
-        reset(mObserverRegistry);
-        reset(mNetd);
-        // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
-        verify(mCb, never()).onLinkPropertiesChange(any());
-        reset(mCb);
-        return ipc;
-    }
-
-    private static LinkProperties makeEmptyLinkProperties(String iface) {
-        final LinkProperties empty = new LinkProperties();
-        empty.setInterfaceName(iface);
-        return empty;
-    }
-
-    private void verifyNetworkAttributesStored(final String l2Key,
-            final NetworkAttributes attributes) {
-        // TODO : when storing is implemented, turn this on
-        // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
-    }
-
-    @Test
-    public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
-        setTestInterfaceParams(null);
-        try {
-            final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
-                    mNetworkStackServiceManager, mDependencies);
-            ipc.shutdown();
-            fail();
-        } catch (NullPointerException npe) {
-            // Phew; null interface names not allowed.
-        }
-    }
-
-    @Test
-    public void testNullCallbackMostDefinitelyThrows() throws Exception {
-        final String ifname = "lo";
-        setTestInterfaceParams(ifname);
-        try {
-            final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
-                    mNetworkStackServiceManager, mDependencies);
-            ipc.shutdown();
-            fail();
-        } catch (NullPointerException npe) {
-            // Phew; null callbacks not allowed.
-        }
-    }
-
-    @Test
-    public void testInvalidInterfaceDoesNotThrow() throws Exception {
-        setTestInterfaceParams(TEST_IFNAME);
-        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
-                mNetworkStackServiceManager, mDependencies);
-        verifyNoMoreInteractions(mIpMemoryStore);
-        ipc.shutdown();
-    }
-
-    @Test
-    public void testInterfaceNotFoundFailsImmediately() throws Exception {
-        setTestInterfaceParams(null);
-        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
-                mNetworkStackServiceManager, mDependencies);
-        ipc.startProvisioning(new ProvisioningConfiguration());
-        verify(mCb, times(1)).onProvisioningFailure(any());
-        verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
-        ipc.shutdown();
-    }
-
-    @Test
-    public void testDefaultProvisioningConfiguration() throws Exception {
-        final String iface = TEST_IFNAME;
-        final IpClient ipc = makeIpClient(iface);
-
-        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
-                .withoutIPv4()
-                // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
-                // and enable it in this test
-                .withoutIpReachabilityMonitor()
-                .build();
-
-        ipc.startProvisioning(config);
-        verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
-        verify(mCb, never()).onProvisioningFailure(any());
-        verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
-
-        ipc.shutdown();
-        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
-        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
-                .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
-    }
-
-    @Test
-    public void testProvisioningWithInitialConfiguration() throws Exception {
-        final String iface = TEST_IFNAME;
-        final IpClient ipc = makeIpClient(iface);
-        final String l2Key = TEST_L2KEY;
-        final String groupHint = TEST_GROUPHINT;
-
-        String[] addresses = {
-            "fe80::a4be:f92:e1f7:22d1/64",
-            "fe80::f04a:8f6:6a32:d756/64",
-            "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
-        };
-        String[] prefixes = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
-
-        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
-                .withoutIPv4()
-                .withoutIpReachabilityMonitor()
-                .withInitialConfiguration(conf(links(addresses), prefixes(prefixes), ips()))
-                .build();
-
-        ipc.startProvisioning(config);
-        verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
-        verify(mCb, never()).onProvisioningFailure(any());
-        ipc.setL2KeyAndGroupHint(l2Key, groupHint);
-
-        for (String addr : addresses) {
-            String[] parts = addr.split("/");
-            verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
-                    .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
-        }
-
-        final int lastAddr = addresses.length - 1;
-
-        // Add N - 1 addresses
-        for (int i = 0; i < lastAddr; i++) {
-            mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[i]), iface);
-            verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
-            reset(mCb);
-        }
-
-        // Add Nth address
-        mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface);
-        LinkProperties want = linkproperties(links(addresses), routes(prefixes));
-        want.setInterfaceName(iface);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
-        verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
-                .setGroupHint(groupHint)
-                .build());
-
-        ipc.shutdown();
-        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
-        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
-                .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
-        verifyNoMoreInteractions(mIpMemoryStore);
-    }
-
-    @Test
-    public void testIsProvisioned() throws Exception {
-        InitialConfiguration empty = conf(links(), prefixes());
-        IsProvisionedTestCase[] testcases = {
-            // nothing
-            notProvisionedCase(links(), routes(), dns(), null),
-            notProvisionedCase(links(), routes(), dns(), empty),
-
-            // IPv4
-            provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
-
-            // IPv6
-            notProvisionedCase(
-                    links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                    routes(), dns(), empty),
-            notProvisionedCase(
-                    links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                    routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
-            provisionedCase(
-                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
-                    routes("::/0"),
-                    dns("2001:db8:dead:beef:f00::02"), empty),
-
-            // Initial configuration
-            provisionedCase(
-                    links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                    routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
-                    dns(),
-                    conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                        prefixes( "fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
-        };
-
-        for (IsProvisionedTestCase testcase : testcases) {
-            if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
-                fail(testcase.errorMessage());
-            }
-        }
-    }
-
-    static class IsProvisionedTestCase {
-        boolean isProvisioned;
-        LinkProperties lp;
-        InitialConfiguration config;
-
-        String errorMessage() {
-            return String.format("expected %s with config %s to be %s, but was %s",
-                     lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
-        }
-
-        static String provisioned(boolean isProvisioned) {
-            return isProvisioned ? "provisioned" : "not provisioned";
-        }
-    }
-
-    static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
-            Set<InetAddress> lpDns, InitialConfiguration config) {
-        return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
-    }
-
-    static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
-            Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
-        return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
-    }
-
-    static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
-            Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
-        IsProvisionedTestCase testcase = new IsProvisionedTestCase();
-        testcase.isProvisioned = isProvisioned;
-        testcase.lp = new LinkProperties();
-        testcase.lp.setLinkAddresses(lpAddrs);
-        for (RouteInfo route : lpRoutes) {
-            testcase.lp.addRoute(route);
-        }
-        for (InetAddress dns : lpDns) {
-            testcase.lp.addDnsServer(dns);
-        }
-        testcase.config = config;
-        return testcase;
-    }
-
-    @Test
-    public void testInitialConfigurations() throws Exception {
-        InitialConfigurationTestCase[] testcases = {
-            validConf("valid IPv4 configuration",
-                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
-            validConf("another valid IPv4 configuration",
-                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
-            validConf("valid IPv6 configurations",
-                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
-                    prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
-                    dns("2001:db8:dead:beef:f00::02")),
-            validConf("valid IPv6 configurations",
-                    links("fe80::1/64"), prefixes("fe80::/64"), dns()),
-            validConf("valid IPv6/v4 configuration",
-                    links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
-                    prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
-                    dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
-            validConf("valid IPv6 configuration without any GUA.",
-                    links("fd00:1234:5678::1/48"),
-                    prefixes("fd00:1234:5678::/48"),
-                    dns("fd00:1234:5678::1000")),
-
-            invalidConf("empty configuration", links(), prefixes(), dns()),
-            invalidConf("v4 addr and dns not in any prefix",
-                    links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
-            invalidConf("v4 addr not in any prefix",
-                    links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
-            invalidConf("v4 dns addr not in any prefix",
-                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
-            invalidConf("v6 addr not in any prefix",
-                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
-                    prefixes("2001:db8:dead:beef::/64"),
-                    dns("2001:db8:dead:beef:f00::02")),
-            invalidConf("v6 dns addr not in any prefix",
-                    links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
-            invalidConf("default ipv6 route and no GUA",
-                    links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
-            invalidConf("invalid v6 prefix length",
-                    links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
-                    dns()),
-            invalidConf("another invalid v6 prefix length",
-                    links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
-                    dns())
-        };
-
-        for (InitialConfigurationTestCase testcase : testcases) {
-            if (testcase.config.isValid() != testcase.isValid) {
-                fail(testcase.errorMessage());
-            }
-        }
-    }
-
-    static class InitialConfigurationTestCase {
-        String descr;
-        boolean isValid;
-        InitialConfiguration config;
-        public String errorMessage() {
-            return String.format("%s: expected configuration %s to be %s, but was %s",
-                    descr, config, validString(isValid), validString(!isValid));
-        }
-        static String validString(boolean isValid) {
-            return isValid ? VALID : INVALID;
-        }
-    }
-
-    static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
-            Set<IpPrefix> prefixes, Set<InetAddress> dns) {
-        return confTestCase(descr, true, conf(links, prefixes, dns));
-    }
-
-    static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
-            Set<IpPrefix> prefixes, Set<InetAddress> dns) {
-        return confTestCase(descr, false, conf(links, prefixes, dns));
-    }
-
-    static InitialConfigurationTestCase confTestCase(
-            String descr, boolean isValid, InitialConfiguration config) {
-        InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
-        testcase.descr = descr;
-        testcase.isValid = isValid;
-        testcase.config = config;
-        return testcase;
-    }
-
-    static LinkProperties linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes) {
-        LinkProperties lp = new LinkProperties();
-        lp.setLinkAddresses(addresses);
-        for (RouteInfo route : routes) {
-            lp.addRoute(route);
-        }
-        return lp;
-    }
-
-    static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
-        return conf(links, prefixes, new HashSet<>());
-    }
-
-    static InitialConfiguration conf(
-            Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
-        InitialConfiguration conf = new InitialConfiguration();
-        conf.ipAddresses.addAll(links);
-        conf.directlyConnectedRoutes.addAll(prefixes);
-        conf.dnsServers.addAll(dns);
-        return conf;
-    }
-
-    static Set<RouteInfo> routes(String... routes) {
-        return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r)));
-    }
-
-    static Set<IpPrefix> prefixes(String... prefixes) {
-        return mapIntoSet(prefixes, IpPrefix::new);
-    }
-
-    static Set<LinkAddress> links(String... addresses) {
-        return mapIntoSet(addresses, LinkAddress::new);
-    }
-
-    static Set<InetAddress> ips(String... addresses) {
-        return mapIntoSet(addresses, InetAddress::getByName);
-    }
-
-    static Set<InetAddress> dns(String... addresses) {
-        return ips(addresses);
-    }
-
-    static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
-        Set<B> out = new HashSet<>(in.length);
-        for (A item : in) {
-            try {
-                out.add(fn.call(item));
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-        return out;
-    }
-
-    interface Fn<A,B> {
-        B call(A a) throws Exception;
-    }
-
-    @Test
-    public void testAll() {
-        List<String> list1 = Arrays.asList();
-        List<String> list2 = Arrays.asList("foo");
-        List<String> list3 = Arrays.asList("bar", "baz");
-        List<String> list4 = Arrays.asList("foo", "bar", "baz");
-
-        assertTrue(InitialConfiguration.all(list1, (x) -> false));
-        assertFalse(InitialConfiguration.all(list2, (x) -> false));
-        assertTrue(InitialConfiguration.all(list3, (x) -> true));
-        assertTrue(InitialConfiguration.all(list2, (x) -> x.charAt(0) == 'f'));
-        assertFalse(InitialConfiguration.all(list4, (x) -> x.charAt(0) == 'f'));
-    }
-
-    @Test
-    public void testAny() {
-        List<String> list1 = Arrays.asList();
-        List<String> list2 = Arrays.asList("foo");
-        List<String> list3 = Arrays.asList("bar", "baz");
-        List<String> list4 = Arrays.asList("foo", "bar", "baz");
-
-        assertFalse(InitialConfiguration.any(list1, (x) -> true));
-        assertTrue(InitialConfiguration.any(list2, (x) -> true));
-        assertTrue(InitialConfiguration.any(list2, (x) -> x.charAt(0) == 'f'));
-        assertFalse(InitialConfiguration.any(list3, (x) -> x.charAt(0) == 'f'));
-        assertTrue(InitialConfiguration.any(list4, (x) -> x.charAt(0) == 'f'));
-    }
-
-    @Test
-    public void testFindAll() {
-        List<String> list1 = Arrays.asList();
-        List<String> list2 = Arrays.asList("foo");
-        List<String> list3 = Arrays.asList("foo", "bar", "baz");
-
-        assertEquals(list1, IpClient.findAll(list1, (x) -> true));
-        assertEquals(list1, IpClient.findAll(list3, (x) -> false));
-        assertEquals(list3, IpClient.findAll(list3, (x) -> true));
-        assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.java b/packages/NetworkStack/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.java
deleted file mode 100644
index 64b168a..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/ip/IpReachabilityMonitorTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 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.ip;
-
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for IpReachabilityMonitor.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpReachabilityMonitorTest {
-
-    @Mock IpReachabilityMonitor.Callback mCallback;
-    @Mock IpReachabilityMonitor.Dependencies mDependencies;
-    @Mock SharedLog mLog;
-    @Mock Context mContext;
-    Handler mHandler;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        when(mLog.forSubComponent(anyString())).thenReturn(mLog);
-        mHandler = new Handler(Looper.getMainLooper());
-    }
-
-    IpReachabilityMonitor makeMonitor() {
-        final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null);
-        return new IpReachabilityMonitor(
-                mContext, ifParams, mHandler, mLog, mCallback, false, mDependencies);
-    }
-
-    @Test
-    public void testNothing() {
-        IpReachabilityMonitor monitor = makeMonitor();
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/util/ConnectivityPacketSummaryTest.java b/packages/NetworkStack/tests/unit/src/android/net/util/ConnectivityPacketSummaryTest.java
deleted file mode 100644
index 71be8b3..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/util/ConnectivityPacketSummaryTest.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.MacAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for ConnectivityPacketSummary.
- *
- * @hide
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityPacketSummaryTest {
-    private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3");
-
-    private String getSummary(String hexBytes) {
-        hexBytes = hexBytes.replaceAll("\\s+", "");
-        final byte[] bytes = HexEncoding.decode(hexBytes.toCharArray(), false);
-        return ConnectivityPacketSummary.summarize(MYHWADDR, bytes);
-    }
-
-    @Test
-    public void testParseICMPv6DADProbe() {
-        final String packet =
-                // Ethernet
-                "3333FF6F48F3 807ABF6F48F3 86DD" +
-                // IPv6
-                "600000000018 3A FF" +
-                "00000000000000000000000000000000" +
-                "FF0200000000000000000001FF6F48F3" +
-                // ICMPv6
-                "87 00 A8E7" +
-                "00000000" +
-                "FE80000000000000827ABFFFFE6F48F3";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > 33:33:ff:6f:48:f3 ipv6" +
-                " :: > ff02::1:ff6f:48f3 icmp6" +
-                " ns fe80::827a:bfff:fe6f:48f3";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6RS() {
-        final String packet =
-                // Ethernet
-                "333300000002 807ABF6F48F3 86DD" +
-                // IPv6
-                "600000000010 3A FF" +
-                "FE80000000000000827ABFFFFE6F48F3" +
-                "FF020000000000000000000000000002" +
-                // ICMPv6 RS
-                "85 00 6973" +
-                "00000000" +
-                "01 01 807ABF6F48F3";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > 33:33:00:00:00:02 ipv6" +
-                " fe80::827a:bfff:fe6f:48f3 > ff02::2 icmp6" +
-                " rs slla 80:7a:bf:6f:48:f3";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6RA() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 100E7E263FC1 86DD" +
-                // IPv6
-                "600000000068 3A FF" +
-                "FE80000000000000FA000004FD000001" +
-                "FE80000000000000827ABFFFFE6F48F3" +
-                // ICMPv6 RA
-                "86 00 8141" +
-                "40 00 0E10" +
-                "00000000" +
-                "00000000" +
-                "01 01 00005E000265" +
-                "05 01 0000000005DC" +
-                "19 05 000000000E10" +
-                "      20014860486000000000000000008844" +
-                "      20014860486000000000000000008888" +
-                "03 04 40 C0" +
-                "      00278D00" +
-                "      00093A80" +
-                "      00000000" +
-                "      2401FA000004FD000000000000000000";
-
-        final String expected =
-                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
-                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
-                " ra slla 00:00:5e:00:02:65 mtu 1500";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6NS() {
-        final String packet =
-                // Ethernet
-                  "807ABF6F48F3 100E7E263FC1 86DD" +
-                  // IPv6
-                  "6C0000000020 3A FF" +
-                  "FE80000000000000FA000004FD000001" +
-                  "FF0200000000000000000001FF01C146" +
-                  // ICMPv6 NS
-                  "87 00 8AD4" +
-                  "00000000" +
-                  "2401FA000004FD0015EA6A5C7B01C146" +
-                  "01 01 00005E000265";
-
-        final String expected =
-                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
-                " fe80::fa00:4:fd00:1 > ff02::1:ff01:c146 icmp6" +
-                " ns 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 slla 00:00:5e:00:02:65";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testInvalidICMPv6NDLength() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 100E7E263FC1 86DD" +
-                // IPv6
-                "600000000068 3A FF" +
-                "FE80000000000000FA000004FD000001" +
-                "FE80000000000000827ABFFFFE6F48F3" +
-                // ICMPv6 RA
-                "86 00 8141" +
-                "40 00 0E10" +
-                "00000000" +
-                "00000000" +
-                "01 01 00005E000265" +
-                "00 00 0102030405D6";
-
-        final String expected =
-                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
-                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
-                " ra slla 00:00:5e:00:02:65 <malformed>";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6NA() {
-        final String packet =
-                // Ethernet
-                "00005E000265 807ABF6F48F3 86DD" +
-                "600000000020 3A FF" +
-                "2401FA000004FD0015EA6A5C7B01C146" +
-                "FE80000000000000FA000004FD000001" +
-                "88 00 E8126" +
-                "0000000" +
-                "2401FA000004FD0015EA6A5C7B01C146" +
-                "02 01 807ABF6F48F3";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > 00:00:5e:00:02:65 ipv6" +
-                " 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 > fe80::fa00:4:fd00:1 icmp6" +
-                " na 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 tlla 80:7a:bf:6f:48:f3";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseARPRequest() {
-        final String packet =
-                // Ethernet
-                  "FFFFFFFFFFFF 807ABF6F48F3 0806" +
-                  // ARP
-                  "0001 0800 06 04" +
-                  // Request
-                  "0001" +
-                  "807ABF6F48F3 64706ADB" +
-                  "000000000000 64706FFD";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff arp" +
-                " who-has 100.112.111.253";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseARPReply() {
-        final String packet =
-                // Ethernet
-                  "807ABF6F48F3 288A1CA8DFC1 0806" +
-                  // ARP
-                  "0001 0800 06 04" +
-                  // Reply
-                  "0002" +
-                  "288A1CA8DFC1 64706FFD"+
-                  "807ABF6F48F3 64706ADB" +
-                  // Ethernet padding to packet min size.
-                  "0000000000000000000000000000";
-
-        final String expected =
-                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 arp" +
-                " reply 100.112.111.253 28:8a:1c:a8:df:c1";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseDHCPv4Discover() {
-        final String packet =
-                // Ethernet
-                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
-                // IPv4
-                "451001580000400040113986" +
-                "00000000" +
-                "FFFFFFFF" +
-                // UDP
-                "0044 0043" +
-                "0144 5559" +
-                // DHCPv4
-                "01 01 06 00" +
-                "79F7ACA4" +
-                "0000 0000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 01" +
-                "3D 07 01807ABF6F48F3" +
-                "39 02 05DC" +
-                "3C 12 616E64726F69642D646863702D372E312E32" +
-                "0C 18 616E64726F69642D36623030366333313333393835343139" +
-                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
-                "FF" +
-                "00";
-
-        final String expectedPrefix =
-                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
-                " 0.0.0.0 > 255.255.255.255 udp" +
-                " 68 > 67 dhcp4" +
-                " 80:7a:bf:6f:48:f3 DISCOVER";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-
-    @Test
-    public void testParseDHCPv4Offer() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 288A1CA8DFC1 0800" +
-                // IPv4
-                "4500013D4D2C0000401188CB" +
-                "64706FFD" +
-                "64706ADB" +
-                // UDP
-                "0043 0044" +
-                "0129 371D" +
-                // DHCPv4
-                "02 01 06 01" +
-                "79F7ACA4" +
-                "0000 0000" +
-                "00000000" +
-                "64706ADB" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 02" +
-                "36 04 AC188A0B" +
-                "33 04 00000708" +
-                "01 04 FFFFF000" +
-                "03 04 64706FFE" +
-                "06 08 08080808" +
-                "      08080404" +
-                "FF0001076165313A363636FF";
-
-        final String expectedPrefix =
-                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
-                " 100.112.111.253 > 100.112.106.219 udp" +
-                " 67 > 68 dhcp4" +
-                " 80:7a:bf:6f:48:f3 OFFER";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-
-    @Test
-    public void testParseDHCPv4Request() {
-        final String packet =
-                // Ethernet
-                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
-                // IPv4
-                "45100164000040004011397A" +
-                "00000000" +
-                "FFFFFFFF" +
-                // UDP
-                "0044 0043" +
-                "0150 E5C7" +
-                // DHCPv4
-                "01 01 06 00" +
-                "79F7ACA4" +
-                "0001 0000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 03" +
-                "3D 07 01807ABF6F48F3" +
-                "32 04 64706ADB" +
-                "36 04 AC188A0B" +
-                "39 02 05DC" +
-                "3C 12 616E64726F69642D646863702D372E312E32" +
-                "0C 18 616E64726F69642D36623030366333313333393835343139" +
-                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
-                "FF" +
-                "00";
-
-        final String expectedPrefix =
-                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
-                " 0.0.0.0 > 255.255.255.255 udp" +
-                " 68 > 67 dhcp4" +
-                " 80:7a:bf:6f:48:f3 REQUEST";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-
-    @Test
-    public void testParseDHCPv4Ack() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 288A1CA8DFC1 0800" +
-                // IPv4
-                "4500013D4D3B0000401188BC" +
-                "64706FFD" +
-                "64706ADB" +
-                // UDP
-                "0043 0044" +
-                "0129 341C" +
-                // DHCPv4
-                "02 01 06 01" +
-                "79F7ACA4" +
-                "0001 0000" +
-                "00000000" +
-                "64706ADB" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 05" +
-                "36 04 AC188A0B" +
-                "33 04 00000708" +
-                "01 04 FFFFF000" +
-                "03 04 64706FFE" +
-                "06 08 08080808" +
-                "      08080404" +
-                "FF0001076165313A363636FF";
-
-        final String expectedPrefix =
-                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
-                " 100.112.111.253 > 100.112.106.219 udp" +
-                " 67 > 68 dhcp4" +
-                " 80:7a:bf:6f:48:f3 ACK";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/android/net/util/PacketReaderTest.java b/packages/NetworkStack/tests/unit/src/android/net/util/PacketReaderTest.java
deleted file mode 100644
index 289dcad..0000000
--- a/packages/NetworkStack/tests/unit/src/android/net/util/PacketReaderTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_NONBLOCK;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_SNDTIMEO;
-
-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 android.os.Handler;
-import android.os.HandlerThread;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for PacketReader.
- *
- * @hide
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class PacketReaderTest {
-    static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
-    static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
-
-    protected CountDownLatch mLatch;
-    protected FileDescriptor mLocalSocket;
-    protected InetSocketAddress mLocalSockName;
-    protected byte[] mLastRecvBuf;
-    protected boolean mStopped;
-    protected HandlerThread mHandlerThread;
-    protected PacketReader mReceiver;
-
-    class UdpLoopbackReader extends PacketReader {
-        public UdpLoopbackReader(Handler h) {
-            super(h);
-        }
-
-        @Override
-        protected FileDescriptor createFd() {
-            FileDescriptor s = null;
-            try {
-                s = Os.socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
-                Os.bind(s, LOOPBACK6, 0);
-                mLocalSockName = (InetSocketAddress) Os.getsockname(s);
-                Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
-            } catch (ErrnoException|SocketException e) {
-                closeFd(s);
-                fail();
-                return null;
-            }
-
-            mLocalSocket = s;
-            return s;
-        }
-
-        @Override
-        protected void handlePacket(byte[] recvbuf, int length) {
-            mLastRecvBuf = Arrays.copyOf(recvbuf, length);
-            mLatch.countDown();
-        }
-
-        @Override
-        protected void onStart() {
-            mStopped = false;
-            mLatch.countDown();
-        }
-
-        @Override
-        protected void onStop() {
-            mStopped = true;
-            mLatch.countDown();
-        }
-    };
-
-    @Before
-    public void setUp() {
-        resetLatch();
-        mLocalSocket = null;
-        mLocalSockName = null;
-        mLastRecvBuf = null;
-        mStopped = false;
-
-        mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
-        mHandlerThread.start();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        if (mReceiver != null) {
-            mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); });
-            waitForActivity();
-        }
-        mReceiver = null;
-        mHandlerThread.quit();
-        mHandlerThread = null;
-    }
-
-    void resetLatch() { mLatch = new CountDownLatch(1); }
-
-    void waitForActivity() throws Exception {
-        try {
-            mLatch.await(1000, TimeUnit.MILLISECONDS);
-        } finally {
-            resetLatch();
-        }
-    }
-
-    void sendPacket(byte[] contents) throws Exception {
-        final DatagramSocket sender = new DatagramSocket();
-        sender.connect(mLocalSockName);
-        sender.send(new DatagramPacket(contents, contents.length));
-        sender.close();
-    }
-
-    @Test
-    public void testBasicWorking() throws Exception {
-        final Handler h = mHandlerThread.getThreadHandler();
-        mReceiver = new UdpLoopbackReader(h);
-
-        h.post(() -> { mReceiver.start(); });
-        waitForActivity();
-        assertTrue(mLocalSockName != null);
-        assertEquals(LOOPBACK6, mLocalSockName.getAddress());
-        assertTrue(0 < mLocalSockName.getPort());
-        assertTrue(mLocalSocket != null);
-        assertFalse(mStopped);
-
-        final byte[] one = "one 1".getBytes("UTF-8");
-        sendPacket(one);
-        waitForActivity();
-        assertEquals(1, mReceiver.numPacketsReceived());
-        assertTrue(Arrays.equals(one, mLastRecvBuf));
-        assertFalse(mStopped);
-
-        final byte[] two = "two 2".getBytes("UTF-8");
-        sendPacket(two);
-        waitForActivity();
-        assertEquals(2, mReceiver.numPacketsReceived());
-        assertTrue(Arrays.equals(two, mLastRecvBuf));
-        assertFalse(mStopped);
-
-        mReceiver.stop();
-        waitForActivity();
-        assertEquals(2, mReceiver.numPacketsReceived());
-        assertTrue(Arrays.equals(two, mLastRecvBuf));
-        assertTrue(mStopped);
-        mReceiver = null;
-    }
-
-    class NullPacketReader extends PacketReader {
-        public NullPacketReader(Handler h, int recvbufsize) {
-            super(h, recvbufsize);
-        }
-
-        @Override
-        public FileDescriptor createFd() { return null; }
-    }
-
-    @Test
-    public void testMinimalRecvBufSize() throws Exception {
-        final Handler h = mHandlerThread.getThreadHandler();
-
-        for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
-            final PacketReader b = new NullPacketReader(h, i);
-            assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
-        }
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
deleted file mode 100644
index e4c1d17..0000000
--- a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ /dev/null
@@ -1,1154 +0,0 @@
-/*
- * Copyright (C) 2017 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.connectivity;
-
-import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
-import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.DnsResolver;
-import android.net.INetworkMonitorCallbacks;
-import android.net.InetAddresses;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.metrics.IpConnectivityLog;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.SharedLog;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.telephony.CellSignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.networkstack.R;
-import com.android.networkstack.metrics.DataStallDetectionStats;
-import com.android.networkstack.metrics.DataStallStatsUtils;
-import com.android.testutils.HandlerUtilsKt;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-import org.mockito.verification.VerificationWithTimeout;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.Executor;
-
-import javax.net.ssl.SSLHandshakeException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkMonitorTest {
-    private static final String LOCATION_HEADER = "location";
-
-    private @Mock Context mContext;
-    private @Mock Resources mResources;
-    private @Mock IpConnectivityLog mLogger;
-    private @Mock SharedLog mValidationLogger;
-    private @Mock NetworkInfo mNetworkInfo;
-    private @Mock DnsResolver mDnsResolver;
-    private @Mock ConnectivityManager mCm;
-    private @Mock TelephonyManager mTelephony;
-    private @Mock WifiManager mWifi;
-    private @Mock HttpURLConnection mHttpConnection;
-    private @Mock HttpURLConnection mHttpsConnection;
-    private @Mock HttpURLConnection mFallbackConnection;
-    private @Mock HttpURLConnection mOtherFallbackConnection;
-    private @Mock Random mRandom;
-    private @Mock NetworkMonitor.Dependencies mDependencies;
-    private @Mock INetworkMonitorCallbacks mCallbacks;
-    private @Spy Network mCleartextDnsNetwork = new Network(TEST_NETID);
-    private @Mock Network mNetwork;
-    private @Mock DataStallStatsUtils mDataStallStatsUtils;
-    private @Mock WifiInfo mWifiInfo;
-    private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
-
-    private HashSet<WrappedNetworkMonitor> mCreatedNetworkMonitors;
-    private HashSet<BroadcastReceiver> mRegisteredReceivers;
-
-    private static final int TEST_NETID = 4242;
-    private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
-    private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
-    private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
-    private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
-    private static final String TEST_MCCMNC = "123456";
-
-    private static final int VALIDATION_RESULT_INVALID = 0;
-    private static final int VALIDATION_RESULT_PORTAL = 0;
-    private static final String TEST_REDIRECT_URL = "android.com";
-    private static final int VALIDATION_RESULT_PARTIAL = NETWORK_VALIDATION_PROBE_DNS
-            | NETWORK_VALIDATION_PROBE_HTTP
-            | NETWORK_VALIDATION_RESULT_PARTIAL;
-    private static final int VALIDATION_RESULT_FALLBACK_PARTIAL = NETWORK_VALIDATION_PROBE_DNS
-            | NETWORK_VALIDATION_PROBE_FALLBACK
-            | NETWORK_VALIDATION_RESULT_PARTIAL;
-    private static final int VALIDATION_RESULT_VALID = NETWORK_VALIDATION_PROBE_DNS
-            | NETWORK_VALIDATION_PROBE_HTTPS
-            | NETWORK_VALIDATION_RESULT_VALID;
-
-    private static final int RETURN_CODE_DNS_SUCCESS = 0;
-    private static final int RETURN_CODE_DNS_TIMEOUT = 255;
-    private static final int DEFAULT_DNS_TIMEOUT_THRESHOLD = 5;
-
-    private static final int HANDLER_TIMEOUT_MS = 1000;
-
-    private static final LinkProperties TEST_LINK_PROPERTIES = new LinkProperties();
-
-    private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-            .addCapability(NET_CAPABILITY_INTERNET);
-
-    private static final NetworkCapabilities NOT_METERED_CAPABILITIES = new NetworkCapabilities()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-            .addCapability(NET_CAPABILITY_INTERNET)
-            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-
-    private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
-    /**
-     * Fakes DNS responses.
-     *
-     * Allows test methods to configure the IP addresses that will be resolved by
-     * Network#getAllByName and by DnsResolver#query.
-     */
-    class FakeDns {
-        private final ArrayMap<String, List<InetAddress>> mAnswers = new ArrayMap<>();
-        private boolean mNonBypassPrivateDnsWorking = true;
-
-        /** Whether DNS queries on mNonBypassPrivateDnsWorking should succeed. */
-        private void setNonBypassPrivateDnsWorking(boolean working) {
-            mNonBypassPrivateDnsWorking = working;
-        }
-
-        /** Clears all DNS entries. */
-        private synchronized void clearAll() {
-            mAnswers.clear();
-        }
-
-        /** Returns the answer for a given name on the given mock network. */
-        private synchronized List<InetAddress> getAnswer(Object mock, String hostname) {
-            if (mock == mNetwork && !mNonBypassPrivateDnsWorking) {
-                return null;
-            }
-            if (mAnswers.containsKey(hostname)) {
-                return mAnswers.get(hostname);
-            }
-            return mAnswers.get("*");
-        }
-
-        /** Sets the answer for a given name. */
-        private synchronized void setAnswer(String hostname, String[] answer)
-                throws UnknownHostException {
-            if (answer == null) {
-                mAnswers.remove(hostname);
-            } else {
-                List<InetAddress> answerList = new ArrayList<>();
-                for (String addr : answer) {
-                    answerList.add(InetAddresses.parseNumericAddress(addr));
-                }
-                mAnswers.put(hostname, answerList);
-            }
-        }
-
-        /** Simulates a getAllByName call for the specified name on the specified mock network. */
-        private InetAddress[] getAllByName(Object mock, String hostname)
-                throws UnknownHostException {
-            List<InetAddress> answer = getAnswer(mock, hostname);
-            if (answer == null || answer.size() == 0) {
-                throw new UnknownHostException(hostname);
-            }
-            return answer.toArray(new InetAddress[0]);
-        }
-
-        /** Starts mocking DNS queries. */
-        private void startMocking() throws UnknownHostException {
-            // Queries on mNetwork using getAllByName.
-            doAnswer(invocation -> {
-                return getAllByName(invocation.getMock(), invocation.getArgument(0));
-            }).when(mNetwork).getAllByName(any());
-
-            // Queries on mCleartextDnsNetwork using DnsResolver#query.
-            doAnswer(invocation -> {
-                String hostname = (String) invocation.getArgument(1);
-                Executor executor = (Executor) invocation.getArgument(3);
-                DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(5);
-
-                List<InetAddress> answer = getAnswer(invocation.getMock(), hostname);
-                if (answer != null && answer.size() > 0) {
-                    new Handler(Looper.getMainLooper()).post(() -> {
-                        executor.execute(() -> callback.onAnswer(answer, 0));
-                    });
-                }
-                // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
-                return null;
-            }).when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any());
-
-            // Queries on mCleartextDnsNetwork using using DnsResolver#query with QueryType.
-            doAnswer(invocation -> {
-                String hostname = (String) invocation.getArgument(1);
-                Executor executor = (Executor) invocation.getArgument(4);
-                DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(6);
-
-                List<InetAddress> answer = getAnswer(invocation.getMock(), hostname);
-                if (answer != null && answer.size() > 0) {
-                    new Handler(Looper.getMainLooper()).post(() -> {
-                        executor.execute(() -> callback.onAnswer(answer, 0));
-                    });
-                }
-                // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
-                return null;
-            }).when(mDnsResolver).query(any(), any(), anyInt(), anyInt(), any(), any(), any());
-        }
-    }
-
-    private FakeDns mFakeDns;
-
-    @Before
-    public void setUp() throws IOException {
-        MockitoAnnotations.initMocks(this);
-        when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mCleartextDnsNetwork);
-        when(mDependencies.getDnsResolver()).thenReturn(mDnsResolver);
-        when(mDependencies.getRandom()).thenReturn(mRandom);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
-                .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
-        when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CAPTIVE_PORTAL_USE_HTTPS),
-                anyInt())).thenReturn(1);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
-                .thenReturn(TEST_HTTP_URL);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any()))
-                .thenReturn(TEST_HTTPS_URL);
-
-        doReturn(mCleartextDnsNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
-
-        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
-        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
-        when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
-        when(mContext.getResources()).thenReturn(mResources);
-
-        when(mResources.getString(anyInt())).thenReturn("");
-        when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
-
-        when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
-        setFallbackUrl(TEST_FALLBACK_URL);
-        setOtherFallbackUrls(TEST_OTHER_FALLBACK_URL);
-        setFallbackSpecs(null); // Test with no fallback spec by default
-        when(mRandom.nextInt()).thenReturn(0);
-
-        // DNS probe timeout should not be defined more than half of HANDLER_TIMEOUT_MS. Otherwise,
-        // it will fail the test because of timeout expired for querying AAAA and A sequentially.
-        when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
-                .thenReturn(200);
-
-        doAnswer((invocation) -> {
-            URL url = invocation.getArgument(0);
-            switch(url.toString()) {
-                case TEST_HTTP_URL:
-                    return mHttpConnection;
-                case TEST_HTTPS_URL:
-                    return mHttpsConnection;
-                case TEST_FALLBACK_URL:
-                    return mFallbackConnection;
-                case TEST_OTHER_FALLBACK_URL:
-                    return mOtherFallbackConnection;
-                default:
-                    fail("URL not mocked: " + url.toString());
-                    return null;
-            }
-        }).when(mCleartextDnsNetwork).openConnection(any());
-        when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-        when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-
-        mFakeDns = new FakeDns();
-        mFakeDns.startMocking();
-        mFakeDns.setAnswer("*", new String[]{"2001:db8::1", "192.0.2.2"});
-
-        when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> {
-            mRegisteredReceivers.add(invocation.getArgument(0));
-            return new Intent();
-        });
-
-        doAnswer((invocation) -> {
-            mRegisteredReceivers.remove(invocation.getArgument(0));
-            return null;
-        }).when(mContext).unregisterReceiver(any());
-
-        setMinDataStallEvaluateInterval(500);
-        setDataStallEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
-        setValidDataStallDnsTimeThreshold(500);
-        setConsecutiveDnsTimeoutThreshold(5);
-
-        mCreatedNetworkMonitors = new HashSet<>();
-        mRegisteredReceivers = new HashSet<>();
-    }
-
-    @After
-    public void tearDown() {
-        mFakeDns.clearAll();
-        assertTrue(mCreatedNetworkMonitors.size() > 0);
-        // Make a local copy of mCreatedNetworkMonitors because during the iteration below,
-        // WrappedNetworkMonitor#onQuitting will delete elements from it on the handler threads.
-        WrappedNetworkMonitor[] networkMonitors = mCreatedNetworkMonitors.toArray(
-                new WrappedNetworkMonitor[0]);
-        for (WrappedNetworkMonitor nm : networkMonitors) {
-            nm.notifyNetworkDisconnected();
-            nm.awaitQuit();
-        }
-        assertEquals("NetworkMonitor still running after disconnect",
-                0, mCreatedNetworkMonitors.size());
-        assertEquals("BroadcastReceiver still registered after disconnect",
-                0, mRegisteredReceivers.size());
-    }
-
-    private class WrappedNetworkMonitor extends NetworkMonitor {
-        private long mProbeTime = 0;
-        private final ConditionVariable mQuitCv = new ConditionVariable(false);
-
-        WrappedNetworkMonitor() {
-            super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
-                    mDependencies, mDataStallStatsUtils);
-        }
-
-        @Override
-        protected long getLastProbeTime() {
-            return mProbeTime;
-        }
-
-        protected void setLastProbeTime(long time) {
-            mProbeTime = time;
-        }
-
-        @Override
-        protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
-            generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-        }
-
-        @Override
-        protected void onQuitting() {
-            assertTrue(mCreatedNetworkMonitors.remove(this));
-            mQuitCv.open();
-        }
-
-        protected void awaitQuit() {
-            assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms",
-                    mQuitCv.block(HANDLER_TIMEOUT_MS));
-        }
-    }
-
-    private WrappedNetworkMonitor makeMonitor(NetworkCapabilities nc) {
-        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor();
-        nm.start();
-        setNetworkCapabilities(nm, nc);
-        HandlerUtilsKt.waitForIdle(nm.getHandler(), HANDLER_TIMEOUT_MS);
-        mCreatedNetworkMonitors.add(nm);
-        return nm;
-    }
-
-    private WrappedNetworkMonitor makeMeteredNetworkMonitor() {
-        final WrappedNetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
-        return nm;
-    }
-
-    private WrappedNetworkMonitor makeNotMeteredNetworkMonitor() {
-        final WrappedNetworkMonitor nm = makeMonitor(NOT_METERED_CAPABILITIES);
-        return nm;
-    }
-
-    private void setNetworkCapabilities(NetworkMonitor nm, NetworkCapabilities nc) {
-        nm.notifyNetworkCapabilitiesChanged(nc);
-        HandlerUtilsKt.waitForIdle(nm.getHandler(), HANDLER_TIMEOUT_MS);
-    }
-
-    @Test
-    public void testGetIntSetting() throws Exception {
-        WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
-
-        // No config resource, no device config. Expect to get default resource.
-        doThrow(new Resources.NotFoundException())
-                .when(mResources).getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout));
-        doAnswer(invocation -> {
-            int defaultValue = invocation.getArgument(2);
-            return defaultValue;
-        }).when(mDependencies).getDeviceConfigPropertyInt(any(),
-                eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT),
-                anyInt());
-        when(mResources.getInteger(eq(R.integer.default_captive_portal_dns_probe_timeout)))
-                .thenReturn(42);
-        assertEquals(42, wnm.getIntSetting(mContext,
-                R.integer.config_captive_portal_dns_probe_timeout,
-                NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
-                R.integer.default_captive_portal_dns_probe_timeout));
-
-        // Set device config. Expect to get device config.
-        when(mDependencies.getDeviceConfigPropertyInt(any(),
-                eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT), anyInt()))
-                        .thenReturn(1234);
-        assertEquals(1234, wnm.getIntSetting(mContext,
-                R.integer.config_captive_portal_dns_probe_timeout,
-                NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
-                R.integer.default_captive_portal_dns_probe_timeout));
-
-        // Set config resource. Expect to get config resource.
-        when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
-                .thenReturn(5678);
-        assertEquals(5678, wnm.getIntSetting(mContext,
-                R.integer.config_captive_portal_dns_probe_timeout,
-                NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
-                R.integer.default_captive_portal_dns_probe_timeout));
-    }
-
-    @Test
-    public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException {
-        setSslException(mHttpsConnection);
-        setPortal302(mHttpConnection);
-        runPortalNetworkTest(VALIDATION_RESULT_PORTAL);
-    }
-
-    @Test
-    public void testIsCaptivePortal_HttpsProbeIsNotPortal() throws IOException {
-        setStatus(mHttpsConnection, 204);
-        setStatus(mHttpConnection, 500);
-
-        runNotPortalNetworkTest();
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackProbeIsPortal() throws IOException {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setPortal302(mFallbackConnection);
-        runPortalNetworkTest(VALIDATION_RESULT_INVALID);
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 500);
-
-        // Fallback probe did not see portal, HTTPS failed -> inconclusive
-        runFailedNetworkTest();
-    }
-
-    @Test
-    public void testIsCaptivePortal_OtherFallbackProbeIsPortal() throws IOException {
-        // Set all fallback probes but one to invalid URLs to verify they are being skipped
-        setFallbackUrl(TEST_FALLBACK_URL);
-        setOtherFallbackUrls(TEST_FALLBACK_URL + "," + TEST_OTHER_FALLBACK_URL);
-
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 500);
-        setPortal302(mOtherFallbackConnection);
-
-        // TEST_OTHER_FALLBACK_URL is third
-        when(mRandom.nextInt()).thenReturn(2);
-
-        // First check always uses the first fallback URL: inconclusive
-        final NetworkMonitor monitor = runNetworkTest(VALIDATION_RESULT_INVALID);
-        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
-        verify(mFallbackConnection, times(1)).getResponseCode();
-        verify(mOtherFallbackConnection, never()).getResponseCode();
-
-        // Second check uses the URL chosen by Random
-        final CaptivePortalProbeResult result = monitor.isCaptivePortal();
-        assertTrue(result.isPortal());
-        verify(mOtherFallbackConnection, times(1)).getResponseCode();
-    }
-
-    @Test
-    public void testIsCaptivePortal_AllProbesFailed() throws IOException {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 404);
-
-        runFailedNetworkTest();
-        verify(mFallbackConnection, times(1)).getResponseCode();
-        verify(mOtherFallbackConnection, never()).getResponseCode();
-    }
-
-    @Test
-    public void testIsCaptivePortal_InvalidUrlSkipped() throws IOException {
-        setFallbackUrl("invalid");
-        setOtherFallbackUrls("otherinvalid," + TEST_OTHER_FALLBACK_URL + ",yetanotherinvalid");
-
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setPortal302(mOtherFallbackConnection);
-        runPortalNetworkTest(VALIDATION_RESULT_INVALID);
-        verify(mOtherFallbackConnection, times(1)).getResponseCode();
-        verify(mFallbackConnection, never()).getResponseCode();
-    }
-
-    private void setupFallbackSpec() throws IOException {
-        setFallbackSpecs("http://example.com@@/@@204@@/@@"
-                + "@@,@@"
-                + TEST_OTHER_FALLBACK_URL + "@@/@@30[12]@@/@@https://(www\\.)?google.com/?.*");
-
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-
-        // Use the 2nd fallback spec
-        when(mRandom.nextInt()).thenReturn(1);
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackSpecIsPartial() throws IOException {
-        setupFallbackSpec();
-        set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
-
-        // HTTPS failed, fallback spec went through -> partial connectivity
-        runPartialConnectivityNetworkTest(VALIDATION_RESULT_FALLBACK_PARTIAL);
-        verify(mOtherFallbackConnection, times(1)).getResponseCode();
-        verify(mFallbackConnection, never()).getResponseCode();
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackSpecIsPortal() throws IOException {
-        setupFallbackSpec();
-        set302(mOtherFallbackConnection, "http://login.portal.example.com");
-        runPortalNetworkTest(VALIDATION_RESULT_INVALID);
-    }
-
-    @Test
-    public void testIsCaptivePortal_IgnorePortals() throws IOException {
-        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
-        setSslException(mHttpsConnection);
-        setPortal302(mHttpConnection);
-
-        runNoValidationNetworkTest();
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDisabled() {
-        setDataStallEvaluationType(0);
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        assertFalse(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-        assertTrue(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        assertFalse(wrappedMonitor.isDataStall());
-
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-        assertTrue(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 3);
-        assertFalse(wrappedMonitor.isDataStall());
-        // Reset consecutive timeout counts.
-        makeDnsSuccessEvent(wrappedMonitor, 1);
-        makeDnsTimeoutEvent(wrappedMonitor, 2);
-        assertFalse(wrappedMonitor.isDataStall());
-
-        makeDnsTimeoutEvent(wrappedMonitor, 3);
-        assertTrue(wrappedMonitor.isDataStall());
-
-        // Set the value to larger than the default dns log size.
-        setConsecutiveDnsTimeoutThreshold(51);
-        wrappedMonitor = makeMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 50);
-        assertFalse(wrappedMonitor.isDataStall());
-
-        makeDnsTimeoutEvent(wrappedMonitor, 1);
-        assertTrue(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
-        // Test dns events happened in valid dns time threshold.
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-        assertFalse(wrappedMonitor.isDataStall());
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        assertTrue(wrappedMonitor.isDataStall());
-
-        // Test dns events happened before valid dns time threshold.
-        setValidDataStallDnsTimeThreshold(0);
-        wrappedMonitor = makeMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-        assertFalse(wrappedMonitor.isDataStall());
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        assertFalse(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testBrokenNetworkNotValidated() throws Exception {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 404);
-
-        runFailedNetworkTest();
-    }
-
-    @Test
-    public void testNoInternetCapabilityValidated() throws Exception {
-        runNetworkTest(NO_INTERNET_CAPABILITIES, NETWORK_VALIDATION_RESULT_VALID,
-                getGeneralVerification());
-        verify(mCleartextDnsNetwork, never()).openConnection(any());
-    }
-
-    @Test
-    public void testLaunchCaptivePortalApp() throws Exception {
-        setSslException(mHttpsConnection);
-        setPortal302(mHttpConnection);
-
-        final NetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
-        nm.notifyNetworkConnected(TEST_LINK_PROPERTIES, METERED_CAPABILITIES);
-
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .showProvisioningNotification(any(), any());
-
-        assertEquals(1, mRegisteredReceivers.size());
-
-        // Check that startCaptivePortalApp sends the expected intent.
-        nm.launchCaptivePortalApp();
-
-        final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
-        final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class);
-        verify(mCm, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .startCaptivePortalApp(networkCaptor.capture(), bundleCaptor.capture());
-        final Bundle bundle = bundleCaptor.getValue();
-        final Network bundleNetwork = bundle.getParcelable(ConnectivityManager.EXTRA_NETWORK);
-        assertEquals(TEST_NETID, bundleNetwork.netId);
-        // network is passed both in bundle and as parameter, as the bundle is opaque to the
-        // framework and only intended for the captive portal app, but the framework needs
-        // the network to identify the right NetworkMonitor.
-        assertEquals(TEST_NETID, networkCaptor.getValue().netId);
-
-        // Have the app report that the captive portal is dismissed, and check that we revalidate.
-        setStatus(mHttpsConnection, 204);
-        setStatus(mHttpConnection, 204);
-
-        reset(mCallbacks);
-        nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP
-                        | NETWORK_VALIDATION_RESULT_VALID), any());
-        assertEquals(0, mRegisteredReceivers.size());
-    }
-
-    @Test
-    public void testPrivateDnsSuccess() throws Exception {
-        setStatus(mHttpsConnection, 204);
-        setStatus(mHttpConnection, 204);
-        mFakeDns.setAnswer("dns.google", new String[]{"2001:db8::53"});
-
-        WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
-        wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
-        wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
-    }
-
-    @Test
-    public void testPrivateDnsResolutionRetryUpdate() throws Exception {
-        // Set a private DNS hostname that doesn't resolve and expect validation to fail.
-        mFakeDns.setAnswer("dns.google", new String[0]);
-        setStatus(mHttpsConnection, 204);
-        setStatus(mHttpConnection, 204);
-
-        WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
-        wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
-        wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(
-                        eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
-                        eq(null));
-
-        // Fix DNS and retry, expect validation to succeed.
-        reset(mCallbacks);
-        mFakeDns.setAnswer("dns.google", new String[]{"2001:db8::1"});
-
-        wnm.forceReevaluation(Process.myUid());
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
-                        eq(null));
-
-        // Change configuration to an invalid DNS name, expect validation to fail.
-        reset(mCallbacks);
-        mFakeDns.setAnswer("dns.bad", new String[0]);
-        wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.bad", new InetAddress[0]));
-        // Strict mode hostname resolve fail. Expect only notification for evaluation fail. No probe
-        // notification.
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
-                .notifyNetworkTested(eq(VALIDATION_RESULT_VALID), eq(null));
-
-        // Change configuration back to working again, but make private DNS not work.
-        // Expect validation to fail.
-        reset(mCallbacks);
-        mFakeDns.setNonBypassPrivateDnsWorking(false);
-        wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google",
-                new InetAddress[0]));
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(
-                        eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
-                        eq(null));
-
-        // Make private DNS work again. Expect validation to succeed.
-        reset(mCallbacks);
-        mFakeDns.setNonBypassPrivateDnsWorking(true);
-        wnm.forceReevaluation(Process.myUid());
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
-                .notifyNetworkTested(
-                        eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null));
-    }
-
-    @Test
-    public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
-        assertTrue(wrappedMonitor.isDataStall());
-        verify(mDataStallStatsUtils, times(1)).write(makeEmptyDataStallDetectionStats(), any());
-    }
-
-    @Test
-    public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 3);
-        assertFalse(wrappedMonitor.isDataStall());
-        verify(mDataStallStatsUtils, never()).write(makeEmptyDataStallDetectionStats(), any());
-    }
-
-    @Test
-    public void testCollectDataStallMetrics() {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
-
-        when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
-        when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
-        when(mTelephony.getSimOperator()).thenReturn(TEST_MCCMNC);
-
-        DataStallDetectionStats.Builder stats =
-                new DataStallDetectionStats.Builder()
-                .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
-                .setNetworkType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                .setCellData(TelephonyManager.NETWORK_TYPE_LTE /* radioType */,
-                        true /* roaming */,
-                        TEST_MCCMNC /* networkMccmnc */,
-                        TEST_MCCMNC /* simMccmnc */,
-                        CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN /* signalStrength */);
-        generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-
-        assertEquals(wrappedMonitor.buildDataStallDetectionStats(
-                 NetworkCapabilities.TRANSPORT_CELLULAR), stats.build());
-
-        when(mWifi.getConnectionInfo()).thenReturn(mWifiInfo);
-
-        stats = new DataStallDetectionStats.Builder()
-                .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
-                .setNetworkType(NetworkCapabilities.TRANSPORT_WIFI)
-                .setWiFiData(mWifiInfo);
-        generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-
-        assertEquals(
-                wrappedMonitor.buildDataStallDetectionStats(NetworkCapabilities.TRANSPORT_WIFI),
-                stats.build());
-    }
-
-    @Test
-    public void testIgnoreHttpsProbe() throws Exception {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 204);
-        // Expect to send HTTP, HTTPS, FALLBACK probe and evaluation result notifications to CS.
-        final NetworkMonitor nm = runNetworkTest(VALIDATION_RESULT_PARTIAL);
-
-        reset(mCallbacks);
-        nm.setAcceptPartialConnectivity();
-        // Expect to update evaluation result notifications to CS.
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(VALIDATION_RESULT_PARTIAL | NETWORK_VALIDATION_RESULT_VALID), eq(null));
-    }
-
-    @Test
-    public void testIsPartialConnectivity() throws IOException {
-        setStatus(mHttpsConnection, 500);
-        setStatus(mHttpConnection, 204);
-        setStatus(mFallbackConnection, 500);
-        runPartialConnectivityNetworkTest(VALIDATION_RESULT_PARTIAL);
-
-        reset(mCallbacks);
-        setStatus(mHttpsConnection, 500);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 204);
-        runPartialConnectivityNetworkTest(VALIDATION_RESULT_FALLBACK_PARTIAL);
-    }
-
-    private void assertIpAddressArrayEquals(String[] expected, InetAddress[] actual) {
-        String[] actualStrings = new String[actual.length];
-        for (int i = 0; i < actual.length; i++) {
-            actualStrings[i] = actual[i].getHostAddress();
-        }
-        assertArrayEquals("Array of IP addresses differs", expected, actualStrings);
-    }
-
-    @Test
-    public void testSendDnsProbeWithTimeout() throws Exception {
-        WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
-        final int shortTimeoutMs = 200;
-
-        // Clear the wildcard DNS response created in setUp.
-        mFakeDns.setAnswer("*", null);
-
-        String[] expected = new String[]{"2001:db8::"};
-        mFakeDns.setAnswer("www.google.com", expected);
-        InetAddress[] actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
-        assertIpAddressArrayEquals(expected, actual);
-
-        expected = new String[]{"2001:db8::", "192.0.2.1"};
-        mFakeDns.setAnswer("www.googleapis.com", expected);
-        actual = wnm.sendDnsProbeWithTimeout("www.googleapis.com", shortTimeoutMs);
-        assertIpAddressArrayEquals(expected, actual);
-
-        mFakeDns.setAnswer("www.google.com", new String[0]);
-        try {
-            wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
-            fail("No DNS results, expected UnknownHostException");
-        } catch (UnknownHostException e) {
-        }
-
-        mFakeDns.setAnswer("www.google.com", null);
-        try {
-            wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
-            fail("DNS query timed out, expected UnknownHostException");
-        } catch (UnknownHostException e) {
-        }
-    }
-
-    @Test
-    public void testNotifyNetwork_WithforceReevaluation() throws Exception {
-        final NetworkMonitor nm = runValidatedNetworkTest();
-        // Verify forceReevalution will not reset the validation result but only probe result until
-        // getting the validation result.
-        reset(mCallbacks);
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 204);
-        nm.forceReevaluation(Process.myUid());
-        final ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
-        // Expect to send HTTP, HTTPs, FALLBACK and evaluation results.
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(4))
-            .notifyNetworkTested(intCaptor.capture(), any());
-        List<Integer> intArgs = intCaptor.getAllValues();
-
-        // None of these exact values can be known in advance except for intArgs.get(0) because the
-        // HTTP and HTTPS probes race and the order in which they complete is non-deterministic.
-        // Thus, check only exact value for intArgs.get(0) and only check the validation result for
-        // the rest ones.
-        assertEquals(Integer.valueOf(NETWORK_VALIDATION_PROBE_DNS
-                | NETWORK_VALIDATION_PROBE_FALLBACK | NETWORK_VALIDATION_RESULT_VALID),
-                intArgs.get(0));
-        assertTrue((intArgs.get(1) & NETWORK_VALIDATION_RESULT_VALID) != 0);
-        assertTrue((intArgs.get(2) & NETWORK_VALIDATION_RESULT_VALID) != 0);
-        assertTrue((intArgs.get(3) & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
-        assertTrue((intArgs.get(3) & NETWORK_VALIDATION_RESULT_VALID) == 0);
-    }
-
-    @Test
-    public void testEvaluationState_clearProbeResults() throws Exception {
-        final NetworkMonitor nm = runValidatedNetworkTest();
-        nm.getEvaluationState().clearProbeResults();
-        // Verify probe results are all reset and only evaluation result left.
-        assertEquals(NETWORK_VALIDATION_RESULT_VALID,
-                nm.getEvaluationState().getNetworkTestResult());
-    }
-
-    @Test
-    public void testEvaluationState_reportProbeResult() throws Exception {
-        final NetworkMonitor nm = runValidatedNetworkTest();
-
-        reset(mCallbacks);
-
-        nm.reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, CaptivePortalProbeResult.SUCCESS);
-        // Verify result should be appended and notifyNetworkTested callback is triggered once.
-        assertEquals(nm.getEvaluationState().getNetworkTestResult(),
-                VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_HTTP);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_HTTP), any());
-
-        nm.reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, CaptivePortalProbeResult.FAILED);
-        // Verify DNS probe result should not be cleared.
-        assertTrue((nm.getEvaluationState().getNetworkTestResult() & NETWORK_VALIDATION_PROBE_DNS)
-                == NETWORK_VALIDATION_PROBE_DNS);
-    }
-
-    @Test
-    public void testEvaluationState_reportEvaluationResult() throws Exception {
-        final NetworkMonitor nm = runValidatedNetworkTest();
-
-        nm.getEvaluationState().reportEvaluationResult(NETWORK_VALIDATION_RESULT_PARTIAL,
-                null /* redirectUrl */);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
-                | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null));
-
-        nm.getEvaluationState().reportEvaluationResult(
-                NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL,
-                null /* redirectUrl */);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null));
-
-        nm.getEvaluationState().reportEvaluationResult(VALIDATION_RESULT_INVALID,
-                TEST_REDIRECT_URL);
-        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
-                eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
-                eq(TEST_REDIRECT_URL));
-    }
-
-    private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
-        for (int i = 0; i < count; i++) {
-            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
-                    RETURN_CODE_DNS_TIMEOUT);
-        }
-    }
-
-    private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
-        for (int i = 0; i < count; i++) {
-            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
-                    RETURN_CODE_DNS_SUCCESS);
-        }
-    }
-
-    private DataStallDetectionStats makeEmptyDataStallDetectionStats() {
-        return new DataStallDetectionStats.Builder().build();
-    }
-
-    private void setDataStallEvaluationType(int type) {
-        when(mDependencies.getDeviceConfigPropertyInt(any(),
-            eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
-    }
-
-    private void setMinDataStallEvaluateInterval(int time) {
-        when(mDependencies.getDeviceConfigPropertyInt(any(),
-            eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
-    }
-
-    private void setValidDataStallDnsTimeThreshold(int time) {
-        when(mDependencies.getDeviceConfigPropertyInt(any(),
-            eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
-    }
-
-    private void setConsecutiveDnsTimeoutThreshold(int num) {
-        when(mDependencies.getDeviceConfigPropertyInt(any(),
-            eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num);
-    }
-
-    private void setFallbackUrl(String url) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url);
-    }
-
-    private void setOtherFallbackUrls(String urls) {
-        when(mDependencies.getDeviceConfigProperty(any(),
-                eq(CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
-    }
-
-    private void setFallbackSpecs(String specs) {
-        when(mDependencies.getDeviceConfigProperty(any(),
-                eq(CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
-    }
-
-    private void setCaptivePortalMode(int mode) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
-    }
-
-    private void runPortalNetworkTest(int result) {
-        // The network test event will be triggered twice with the same result. Expect to capture
-        // the second one with direct url.
-        runPortalNetworkTest(result,
-                (VerificationWithTimeout) timeout(HANDLER_TIMEOUT_MS).times(2));
-    }
-
-    private void runPortalNetworkTest(int result, VerificationWithTimeout mode) {
-        runNetworkTest(result, mode);
-        assertEquals(1, mRegisteredReceivers.size());
-        assertNotNull(mNetworkTestedRedirectUrlCaptor.getValue());
-    }
-
-    private void runNotPortalNetworkTest() {
-        runNetworkTest(VALIDATION_RESULT_VALID);
-        assertEquals(0, mRegisteredReceivers.size());
-        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
-    }
-
-    private void runNoValidationNetworkTest() {
-        runNetworkTest(NETWORK_VALIDATION_RESULT_VALID);
-        assertEquals(0, mRegisteredReceivers.size());
-        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
-    }
-
-    private void runFailedNetworkTest() {
-        runNetworkTest(VALIDATION_RESULT_INVALID);
-        assertEquals(0, mRegisteredReceivers.size());
-        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
-    }
-
-    private void runPartialConnectivityNetworkTest(int result) {
-        runNetworkTest(result);
-        assertEquals(0, mRegisteredReceivers.size());
-        assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
-    }
-
-    private NetworkMonitor runValidatedNetworkTest() throws Exception {
-        setStatus(mHttpsConnection, 204);
-        setStatus(mHttpConnection, 204);
-        // Expect to send HTTPs and evaluation results.
-        return runNetworkTest(VALIDATION_RESULT_VALID);
-    }
-
-    private NetworkMonitor runNetworkTest(int testResult) {
-        return runNetworkTest(METERED_CAPABILITIES, testResult, getGeneralVerification());
-    }
-
-    private NetworkMonitor runNetworkTest(int testResult, VerificationWithTimeout mode) {
-        return runNetworkTest(METERED_CAPABILITIES, testResult, mode);
-    }
-
-    private NetworkMonitor runNetworkTest(NetworkCapabilities nc, int testResult,
-            VerificationWithTimeout mode) {
-        final NetworkMonitor monitor = makeMonitor(nc);
-        monitor.notifyNetworkConnected(TEST_LINK_PROPERTIES, nc);
-        try {
-            verify(mCallbacks, mode)
-                    .notifyNetworkTested(eq(testResult), mNetworkTestedRedirectUrlCaptor.capture());
-        } catch (RemoteException e) {
-            fail("Unexpected exception: " + e);
-        }
-        HandlerUtilsKt.waitForIdle(monitor.getHandler(), HANDLER_TIMEOUT_MS);
-
-        return monitor;
-    }
-
-    private void setSslException(HttpURLConnection connection) throws IOException {
-        doThrow(new SSLHandshakeException("Invalid cert")).when(connection).getResponseCode();
-    }
-
-    private void set302(HttpURLConnection connection, String location) throws IOException {
-        setStatus(connection, 302);
-        doReturn(location).when(connection).getHeaderField(LOCATION_HEADER);
-    }
-
-    private void setPortal302(HttpURLConnection connection) throws IOException {
-        set302(connection, "http://login.example.com");
-    }
-
-    private void setStatus(HttpURLConnection connection, int status) throws IOException {
-        doReturn(status).when(connection).getResponseCode();
-    }
-
-    private void generateTimeoutDnsEvent(DataStallDetectionStats.Builder stats, int num) {
-        for (int i = 0; i < num; i++) {
-            stats.addDnsEvent(RETURN_CODE_DNS_TIMEOUT, 123456789 /* timeMs */);
-        }
-    }
-
-    private VerificationWithTimeout getGeneralVerification() {
-        return (VerificationWithTimeout) timeout(HANDLER_TIMEOUT_MS).atLeastOnce();
-    }
-
-}
-
diff --git a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
deleted file mode 100644
index 64fe3a6..0000000
--- a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2018 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.connectivity.ipmemorystore;
-
-import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
-
-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.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doReturn;
-
-import android.app.job.JobScheduler;
-import android.content.Context;
-import android.net.ipmemorystore.Blob;
-import android.net.ipmemorystore.IOnBlobRetrievedListener;
-import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener;
-import android.net.ipmemorystore.IOnSameL3NetworkResponseListener;
-import android.net.ipmemorystore.IOnStatusListener;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.ipmemorystore.NetworkAttributesParcelable;
-import android.net.ipmemorystore.SameL3NetworkResponse;
-import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
-import android.net.ipmemorystore.Status;
-import android.net.ipmemorystore.StatusParcelable;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.lang.reflect.Modifier;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/** Unit tests for {@link IpMemoryStoreService}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpMemoryStoreServiceTest {
-    private static final String TEST_CLIENT_ID = "testClientId";
-    private static final String TEST_DATA_NAME = "testData";
-
-    private static final int TEST_DATABASE_SIZE_THRESHOLD = 100 * 1024; //100KB
-    private static final int DEFAULT_TIMEOUT_MS = 5000;
-    private static final int LONG_TIMEOUT_MS = 30000;
-    private static final int FAKE_KEY_COUNT = 20;
-    private static final long LEASE_EXPIRY_NULL = -1L;
-    private static final int MTU_NULL = -1;
-    private static final String[] FAKE_KEYS;
-    private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
-            -128, 0, 89, 112, 91, -34 };
-    static {
-        FAKE_KEYS = new String[FAKE_KEY_COUNT];
-        for (int i = 0; i < FAKE_KEYS.length; ++i) {
-            FAKE_KEYS[i] = "fakeKey" + i;
-        }
-    }
-
-    @Mock
-    private Context mMockContext;
-    @Mock
-    private JobScheduler mMockJobScheduler;
-    private File mDbFile;
-
-    private IpMemoryStoreService mService;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        final Context context = InstrumentationRegistry.getContext();
-        final File dir = context.getFilesDir();
-        mDbFile = new File(dir, "test.db");
-        doReturn(mDbFile).when(mMockContext).getDatabasePath(anyString());
-        doReturn(mMockJobScheduler).when(mMockContext)
-                .getSystemService(Context.JOB_SCHEDULER_SERVICE);
-        mService = new IpMemoryStoreService(mMockContext) {
-            @Override
-            protected int getDbSizeThreshold() {
-                return TEST_DATABASE_SIZE_THRESHOLD;
-            }
-
-            @Override
-            boolean isDbSizeOverThreshold() {
-                // Add a 100ms delay here for pausing maintenance job a while. Interrupted flag can
-                // be set at this time.
-                waitForMs(100);
-                return super.isDbSizeOverThreshold();
-            }
-        };
-    }
-
-    @After
-    public void tearDown() {
-        mService.shutdown();
-        mDbFile.delete();
-    }
-
-    /** Helper method to build test network attributes */
-    private static NetworkAttributes.Builder buildTestNetworkAttributes(
-            final Inet4Address ipAddress, final long expiry, final String hint,
-            final List<InetAddress> dnsServers, final int mtu) {
-        final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
-        if (null != ipAddress) {
-            na.setAssignedV4Address(ipAddress);
-        }
-        if (LEASE_EXPIRY_NULL != expiry) {
-            na.setAssignedV4AddressExpiry(expiry);
-        }
-        if (null != hint) {
-            na.setGroupHint(hint);
-        }
-        if (null != dnsServers) {
-            na.setDnsAddresses(dnsServers);
-        }
-        if (MTU_NULL != mtu) {
-            na.setMtu(mtu);
-        }
-        return na;
-    }
-
-    /** Helper method to make a vanilla IOnStatusListener */
-    private IOnStatusListener onStatus(Consumer<Status> functor) {
-        return new IOnStatusListener() {
-            @Override
-            public void onComplete(final StatusParcelable statusParcelable) throws RemoteException {
-                functor.accept(new Status(statusParcelable));
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-
-            @Override
-            public int getInterfaceVersion() {
-                return this.VERSION;
-            }
-        };
-    }
-
-    /** Helper method to make an IOnBlobRetrievedListener */
-    private interface OnBlobRetrievedListener {
-        void onBlobRetrieved(Status status, String l2Key, String name, byte[] data);
-    }
-    private IOnBlobRetrievedListener onBlobRetrieved(final OnBlobRetrievedListener functor) {
-        return new IOnBlobRetrievedListener() {
-            @Override
-            public void onBlobRetrieved(final StatusParcelable statusParcelable,
-                    final String l2Key, final String name, final Blob blob) throws RemoteException {
-                functor.onBlobRetrieved(new Status(statusParcelable), l2Key, name,
-                        null == blob ? null : blob.data);
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-
-            @Override
-            public int getInterfaceVersion() {
-                return this.VERSION;
-            }
-        };
-    }
-
-    /** Helper method to make an IOnNetworkAttributesRetrievedListener */
-    private interface OnNetworkAttributesRetrievedListener  {
-        void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr);
-    }
-    private IOnNetworkAttributesRetrievedListener onNetworkAttributesRetrieved(
-            final OnNetworkAttributesRetrievedListener functor) {
-        return new IOnNetworkAttributesRetrievedListener() {
-            @Override
-            public void onNetworkAttributesRetrieved(final StatusParcelable status,
-                    final String l2Key, final NetworkAttributesParcelable attributes)
-                    throws RemoteException {
-                functor.onNetworkAttributesRetrieved(new Status(status), l2Key,
-                        null == attributes ? null : new NetworkAttributes(attributes));
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-
-            @Override
-            public int getInterfaceVersion() {
-                return this.VERSION;
-            }
-        };
-    }
-
-    /** Helper method to make an IOnSameNetworkResponseListener */
-    private interface OnSameL3NetworkResponseListener {
-        void onSameL3NetworkResponse(Status status, SameL3NetworkResponse answer);
-    }
-    private IOnSameL3NetworkResponseListener onSameResponse(
-            final OnSameL3NetworkResponseListener functor) {
-        return new IOnSameL3NetworkResponseListener() {
-            @Override
-            public void onSameL3NetworkResponse(final StatusParcelable status,
-                    final SameL3NetworkResponseParcelable sameL3Network)
-                    throws RemoteException {
-                functor.onSameL3NetworkResponse(new Status(status),
-                        null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network));
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-
-            @Override
-            public int getInterfaceVersion() {
-                return this.VERSION;
-            }
-        };
-    }
-
-    /** Helper method to make an IOnL2KeyResponseListener */
-    private interface OnL2KeyResponseListener {
-        void onL2KeyResponse(Status status, String key);
-    }
-    private IOnL2KeyResponseListener onL2KeyResponse(final OnL2KeyResponseListener functor) {
-        return new IOnL2KeyResponseListener() {
-            @Override
-            public void onL2KeyResponse(final StatusParcelable status, final String key)
-                    throws RemoteException {
-                functor.onL2KeyResponse(new Status(status), key);
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-
-            @Override
-            public int getInterfaceVersion() {
-                return this.VERSION;
-            }
-        };
-    }
-
-    // Helper method to factorize some boilerplate
-    private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor) {
-        doLatched(timeoutMessage, functor, DEFAULT_TIMEOUT_MS);
-    }
-
-    private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor,
-            final int timeout) {
-        final CountDownLatch latch = new CountDownLatch(1);
-        functor.accept(latch);
-        try {
-            if (!latch.await(timeout, TimeUnit.MILLISECONDS)) {
-                fail(timeoutMessage);
-            }
-        } catch (InterruptedException e) {
-            fail("Thread was interrupted");
-        }
-    }
-
-    // Helper method to store network attributes to database
-    private void storeAttributes(final String l2Key, final NetworkAttributes na) {
-        storeAttributes("Did not complete storing attributes", l2Key, na);
-    }
-    private void storeAttributes(final String timeoutMessage, final String l2Key,
-            final NetworkAttributes na) {
-        doLatched(timeoutMessage, latch -> mService.storeNetworkAttributes(l2Key, na.toParcelable(),
-                onStatus(status -> {
-                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
-                    latch.countDown();
-                })));
-    }
-
-    // Helper method to store blob data to database
-    private void storeBlobOrFail(final String l2Key, final Blob b, final byte[] data) {
-        storeBlobOrFail("Did not complete storing private data", l2Key, b, data);
-    }
-    private void storeBlobOrFail(final String timeoutMessage, final String l2Key, final Blob b,
-            final byte[] data) {
-        b.data = data;
-        doLatched(timeoutMessage, latch -> mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME,
-                b, onStatus(status -> {
-                    assertTrue("Store status not successful : " + status.resultCode,
-                            status.isSuccess());
-                    latch.countDown();
-                })));
-    }
-
-    /** Insert large data that db size will be over threshold for maintenance test usage. */
-    private void insertFakeDataAndOverThreshold() {
-        try {
-            final NetworkAttributes.Builder na = buildTestNetworkAttributes(
-                    (Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
-                    "hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
-                    219);
-            final long time = System.currentTimeMillis() - 1;
-            for (int i = 0; i < 1000; i++) {
-                int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
-                        mService.mDb,
-                        "fakeKey" + i,
-                        // Let first 100 records get expiry.
-                        i < 100 ? time : time + TimeUnit.HOURS.toMillis(i),
-                        na.build());
-                assertEquals(errorCode, Status.SUCCESS);
-
-                errorCode = IpMemoryStoreDatabase.storeBlob(
-                        mService.mDb, "fakeKey" + i, TEST_CLIENT_ID, TEST_DATA_NAME,
-                        TEST_BLOB_DATA);
-                assertEquals(errorCode, Status.SUCCESS);
-            }
-
-            // After added 5000 records, db size is larger than fake threshold(100KB).
-            assertTrue(mService.isDbSizeOverThreshold());
-        } catch (final UnknownHostException e) {
-            fail("Insert fake data fail");
-        }
-    }
-
-    /** Wait for assigned time. */
-    private void waitForMs(long ms) {
-        try {
-            Thread.sleep(ms);
-        } catch (final InterruptedException e) {
-            fail("Thread was interrupted");
-        }
-    }
-
-    @Test
-    public void testNetworkAttributes() throws UnknownHostException {
-        final String l2Key = FAKE_KEYS[0];
-        final NetworkAttributes.Builder na = buildTestNetworkAttributes(
-                (Inet4Address) Inet4Address.getByName("1.2.3.4"),
-                System.currentTimeMillis() + 7_200_000, "hint1", null, 219);
-        NetworkAttributes attributes = na.build();
-        storeAttributes(l2Key, attributes);
-
-        doLatched("Did not complete retrieving attributes", latch ->
-                mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
-                        (status, key, attr) -> {
-                            assertTrue("Retrieve network attributes not successful : "
-                                    + status.resultCode, status.isSuccess());
-                            assertEquals(l2Key, key);
-                            assertEquals(attributes, attr);
-                            latch.countDown();
-                        })));
-
-        final NetworkAttributes.Builder na2 = new NetworkAttributes.Builder();
-        na.setDnsAddresses(Arrays.asList(
-                new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
-        final NetworkAttributes attributes2 = na2.build();
-        storeAttributes("Did not complete storing attributes 2", l2Key, attributes2);
-
-        doLatched("Did not complete retrieving attributes 2", latch ->
-                mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
-                        (status, key, attr) -> {
-                            assertTrue("Retrieve network attributes not successful : "
-                                    + status.resultCode, status.isSuccess());
-                            assertEquals(l2Key, key);
-                            assertEquals(attributes.assignedV4Address, attr.assignedV4Address);
-                            assertEquals(attributes.assignedV4AddressExpiry,
-                                    attr.assignedV4AddressExpiry);
-                            assertEquals(attributes.groupHint, attr.groupHint);
-                            assertEquals(attributes.mtu, attr.mtu);
-                            assertEquals(attributes2.dnsAddresses, attr.dnsAddresses);
-                            latch.countDown();
-                        })));
-
-        doLatched("Did not complete retrieving attributes 3", latch ->
-                mService.retrieveNetworkAttributes(l2Key + "nonexistent",
-                        onNetworkAttributesRetrieved(
-                                (status, key, attr) -> {
-                                    assertTrue("Retrieve network attributes not successful : "
-                                            + status.resultCode, status.isSuccess());
-                                    assertEquals(l2Key + "nonexistent", key);
-                                    assertNull("Retrieved data not stored", attr);
-                                    latch.countDown();
-                                }
-                        )));
-
-        // Verify that this test does not miss any new field added later.
-        // If any field is added to NetworkAttributes it must be tested here for storing
-        // and retrieving.
-        assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
-                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
-    }
-
-    @Test
-    public void testInvalidAttributes() {
-        doLatched("Did not complete storing bad attributes", latch ->
-                mService.storeNetworkAttributes("key", null, onStatus(status -> {
-                    assertFalse("Success storing on a null key",
-                            status.isSuccess());
-                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
-                    latch.countDown();
-                })));
-
-        final NetworkAttributes na = new NetworkAttributes.Builder().setMtu(2).build();
-        doLatched("Did not complete storing bad attributes", latch ->
-                mService.storeNetworkAttributes(null, na.toParcelable(), onStatus(status -> {
-                    assertFalse("Success storing null attributes on a null key",
-                            status.isSuccess());
-                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
-                    latch.countDown();
-                })));
-
-        doLatched("Did not complete storing bad attributes", latch ->
-                mService.storeNetworkAttributes(null, null, onStatus(status -> {
-                    assertFalse("Success storing null attributes on a null key",
-                            status.isSuccess());
-                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
-                    latch.countDown();
-                })));
-
-        doLatched("Did not complete retrieving bad attributes", latch ->
-                mService.retrieveNetworkAttributes(null, onNetworkAttributesRetrieved(
-                        (status, key, attr) -> {
-                            assertFalse("Success retrieving attributes for a null key",
-                                    status.isSuccess());
-                            assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
-                            assertNull(key);
-                            assertNull(attr);
-                            latch.countDown();
-                        })));
-    }
-
-    @Test
-    public void testPrivateData() {
-        final String l2Key = FAKE_KEYS[0];
-        final Blob b = new Blob();
-        storeBlobOrFail(l2Key, b, TEST_BLOB_DATA);
-
-        doLatched("Did not complete retrieving private data", latch ->
-                mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
-                        (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));
-                            latch.countDown();
-                        })));
-
-        // Most puzzling error message ever
-        doLatched("Did not complete retrieving nothing", latch ->
-                mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME + "2", onBlobRetrieved(
-                        (status, key, name, data) -> {
-                            assertTrue("Retrieve blob status not successful : " + status.resultCode,
-                                    status.isSuccess());
-                            assertEquals(l2Key, key);
-                            assertEquals(name, TEST_DATA_NAME + "2");
-                            assertNull(data);
-                            latch.countDown();
-                        })));
-    }
-
-    @Test
-    public void testFindL2Key() throws UnknownHostException {
-        final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
-        na.setGroupHint("hint0");
-        storeAttributes(FAKE_KEYS[0], na.build());
-
-        na.setDnsAddresses(Arrays.asList(
-                new InetAddress[] {Inet6Address.getByName("8D56:9AF1::08EE:20F1")}));
-        na.setMtu(219);
-        storeAttributes(FAKE_KEYS[1], na.build());
-        na.setMtu(null);
-        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
-        na.setDnsAddresses(Arrays.asList(
-                new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
-        na.setGroupHint("hint1");
-        storeAttributes(FAKE_KEYS[2], na.build());
-        na.setMtu(219);
-        storeAttributes(FAKE_KEYS[3], na.build());
-        na.setMtu(240);
-        storeAttributes(FAKE_KEYS[4], na.build());
-        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("5.6.7.8"));
-        storeAttributes(FAKE_KEYS[5], na.build());
-
-        // Matches key 5 exactly
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(FAKE_KEYS[5], key);
-                    latch.countDown();
-                })));
-
-        // MTU matches key 4 but v4 address matches key 5. The latter is stronger.
-        na.setMtu(240);
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(FAKE_KEYS[5], key);
-                    latch.countDown();
-                })));
-
-        // Closest to key 3 (indeed, identical)
-        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
-        na.setMtu(219);
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(FAKE_KEYS[3], key);
-                    latch.countDown();
-                })));
-
-        // Group hint alone must not be strong enough to override the rest
-        na.setGroupHint("hint0");
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(FAKE_KEYS[3], key);
-                    latch.countDown();
-                })));
-
-        // Still closest to key 3, though confidence is lower
-        na.setGroupHint("hint1");
-        na.setDnsAddresses(null);
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(FAKE_KEYS[3], key);
-                    latch.countDown();
-                })));
-
-        // But changing the MTU makes this closer to key 4
-        na.setMtu(240);
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(FAKE_KEYS[4], key);
-                    latch.countDown();
-                })));
-
-        // MTU alone not strong enough to make this group-close
-        na.setGroupHint(null);
-        na.setDnsAddresses(null);
-        na.setAssignedV4Address(null);
-        doLatched("Did not finish finding L2Key", latch ->
-                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertNull(key);
-                    latch.countDown();
-                })));
-    }
-
-    private void assertNetworksSameness(final String key1, final String key2, final int sameness) {
-        doLatched("Did not finish evaluating sameness", latch ->
-                mService.isSameNetwork(key1, key2, onSameResponse((status, answer) -> {
-                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
-                            status.isSuccess());
-                    assertEquals(sameness, answer.getNetworkSameness());
-                    latch.countDown();
-                })));
-    }
-
-    @Test
-    public void testIsSameNetwork() throws UnknownHostException {
-        final NetworkAttributes.Builder na = buildTestNetworkAttributes(
-                (Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
-                "hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
-                219);
-
-        storeAttributes(FAKE_KEYS[0], na.build());
-        // 0 and 1 have identical attributes
-        storeAttributes(FAKE_KEYS[1], na.build());
-
-        // Hopefully only the MTU being different still means it's the same network
-        na.setMtu(200);
-        storeAttributes(FAKE_KEYS[2], na.build());
-
-        // Hopefully different MTU, assigned V4 address and grouphint make a different network,
-        // even with identical DNS addresses
-        na.setAssignedV4Address(null);
-        na.setGroupHint("hint2");
-        storeAttributes(FAKE_KEYS[3], na.build());
-
-        assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[1], SameL3NetworkResponse.NETWORK_SAME);
-        assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
-        assertNetworksSameness(FAKE_KEYS[1], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
-        assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[3], SameL3NetworkResponse.NETWORK_DIFFERENT);
-        assertNetworksSameness(FAKE_KEYS[0], "neverInsertedKey",
-                SameL3NetworkResponse.NETWORK_NEVER_CONNECTED);
-
-        doLatched("Did not finish evaluating sameness", latch ->
-                mService.isSameNetwork(null, null, onSameResponse((status, answer) -> {
-                    assertFalse("Retrieve network sameness suspiciously successful : "
-                            + status.resultCode, status.isSuccess());
-                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
-                    assertNull(answer);
-                    latch.countDown();
-                })));
-    }
-
-    @Test
-    public void testFullMaintenance() {
-        insertFakeDataAndOverThreshold();
-
-        final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
-        // Do full maintenance and then db size should go down and meet the threshold.
-        doLatched("Maintenance unexpectedly completed successfully", latch ->
-                mService.fullMaintenance(onStatus((status) -> {
-                    assertTrue("Execute full maintenance failed: "
-                            + status.resultCode, status.isSuccess());
-                    latch.countDown();
-                }), im), LONG_TIMEOUT_MS);
-
-        // Assume that maintenance is successful, db size shall meet the threshold.
-        assertFalse(mService.isDbSizeOverThreshold());
-    }
-
-    @Test
-    public void testInterruptMaintenance() {
-        insertFakeDataAndOverThreshold();
-
-        final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
-
-        // Test interruption immediately.
-        im.setInterrupted(true);
-        // Do full maintenance and the expectation is not completed by interruption.
-        doLatched("Maintenance unexpectedly completed successfully", latch ->
-                mService.fullMaintenance(onStatus((status) -> {
-                    assertFalse(status.isSuccess());
-                    latch.countDown();
-                }), im), LONG_TIMEOUT_MS);
-
-        // Assume that no data are removed, db size shall be over the threshold.
-        assertTrue(mService.isDbSizeOverThreshold());
-
-        // Reset the flag and test interruption during maintenance.
-        im.setInterrupted(false);
-
-        final ConditionVariable latch = new ConditionVariable();
-        // Do full maintenance and the expectation is not completed by interruption.
-        mService.fullMaintenance(onStatus((status) -> {
-            assertFalse(status.isSuccess());
-            latch.open();
-        }), im);
-
-        // Give a little bit of time for maintenance to start up for realism
-        waitForMs(50);
-        // Interrupt maintenance job.
-        im.setInterrupted(true);
-
-        if (!latch.block(LONG_TIMEOUT_MS)) {
-            fail("Maintenance unexpectedly completed successfully");
-        }
-
-        // Assume that only do dropAllExpiredRecords method in previous maintenance, db size shall
-        // still be over the threshold.
-        assertTrue(mService.isDbSizeOverThreshold());
-    }
-
-    @Test
-    public void testFactoryReset() throws UnknownHostException {
-        final String l2Key = FAKE_KEYS[0];
-
-        // store network attributes
-        final NetworkAttributes.Builder na = buildTestNetworkAttributes(
-                (Inet4Address) Inet4Address.getByName("1.2.3.4"),
-                System.currentTimeMillis() + 7_200_000, "hint1", null, 219);
-        storeAttributes(l2Key, na.build());
-
-        // store private data blob
-        final Blob b = new Blob();
-        storeBlobOrFail(l2Key, b, TEST_BLOB_DATA);
-
-        // wipe all data in Database
-        mService.factoryReset();
-
-        // retrieved network attributes should be null
-        doLatched("Did not complete retrieving attributes", latch ->
-                mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
-                        (status, key, attr) -> {
-                            assertTrue("Retrieve network attributes not successful : "
-                                    + status.resultCode, status.isSuccess());
-                            assertEquals(l2Key, key);
-                            assertNull(attr);
-                            latch.countDown();
-                        })));
-
-        // retrieved private data blob should be null
-        doLatched("Did not complete retrieving private data", latch ->
-                mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
-                        (status, key, name, data) -> {
-                            assertTrue("Retrieve blob status not successful : " + status.resultCode,
-                                    status.isSuccess());
-                            assertEquals(l2Key, key);
-                            assertEquals(name, TEST_DATA_NAME);
-                            assertNull(data);
-                            latch.countDown();
-                        })));
-    }
-
-    public void testTasksAreSerial() {
-        final long sleepTimeMs = 1000;
-        final long startTime = System.currentTimeMillis();
-        mService.retrieveNetworkAttributes("somekey", onNetworkAttributesRetrieved(
-                (status, key, attr) -> {
-                    assertTrue("Unexpected status : " + status.resultCode, status.isSuccess());
-                    try {
-                        Thread.sleep(sleepTimeMs);
-                    } catch (InterruptedException e) {
-                        fail("InterruptedException");
-                    }
-                }));
-        doLatched("Serial tasks timing out", latch ->
-                mService.retrieveNetworkAttributes("somekey", onNetworkAttributesRetrieved(
-                        (status, key, attr) -> {
-                            assertTrue("Unexpected status : " + status.resultCode,
-                                    status.isSuccess());
-                            assertTrue(System.currentTimeMillis() >= startTime + sleepTimeMs);
-                        })), DEFAULT_TIMEOUT_MS);
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
deleted file mode 100644
index 3d3aabc..0000000
--- a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2018 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.connectivity.ipmemorystore;
-
-import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Unit tests for {@link RelevanceUtils}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RelevanceUtilsTests {
-    @Test
-    public void testComputeRelevanceForTargetDate() {
-        final long dayInMillis = 24L * 60 * 60 * 1000;
-        final long base = 1_000_000L; // any given point in time
-        // Relevance when the network expires in 1000 years must be capped
-        assertEquals(CAPPED_RELEVANCE, RelevanceUtils.computeRelevanceForTargetDate(
-                base + 1000L * dayInMillis, base));
-        // Relevance when expiry is before the date must be 0
-        assertEquals(0, RelevanceUtils.computeRelevanceForTargetDate(base - 1, base));
-        // Make sure the relevance for a given target date is higher if the expiry is further
-        // in the future
-        assertTrue(RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base)
-                < RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base));
-
-        // Make sure the relevance falls slower as the expiry is closing in. This is to ensure
-        // the decay is indeed logarithmic.
-        final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(base, base);
-        final int relevance50DaysBeforeExpiry =
-                RelevanceUtils.computeRelevanceForTargetDate(base + 50 * dayInMillis, base);
-        final int relevance100DaysBeforeExpiry =
-                RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base);
-        final int relevance150DaysBeforeExpiry =
-                RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base);
-        assertEquals(0, relevanceAtExpiry);
-        assertTrue(relevance50DaysBeforeExpiry - relevanceAtExpiry
-                < relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry);
-        assertTrue(relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry
-                < relevance150DaysBeforeExpiry - relevance100DaysBeforeExpiry);
-    }
-
-    @Test
-    public void testIncreaseRelevance() {
-        long expiry = System.currentTimeMillis();
-
-        final long firstBump = RelevanceUtils.bumpExpiryDate(expiry);
-        // Though a few milliseconds might have elapsed, the first bump should push the duration
-        // to days in the future, so unless this test takes literal days between these two lines,
-        // this should always pass.
-        assertTrue(firstBump > expiry);
-
-        expiry = 0;
-        long lastDifference = Long.MAX_VALUE;
-        // The relevance should be capped in at most this many steps. Otherwise, fail.
-        final int steps = 1000;
-        for (int i = 0; i < steps; ++i) {
-            final long newExpiry = RelevanceUtils.bumpExpiryDuration(expiry);
-            if (newExpiry == expiry) {
-                // The relevance should be capped. Make sure it is, then exit without failure.
-                assertEquals(newExpiry, RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
-                return;
-            }
-            // Make sure the new expiry is further in the future than last time.
-            assertTrue(newExpiry > expiry);
-            // Also check that it was not bumped as much as the last bump, because the
-            // decay must be exponential.
-            assertTrue(newExpiry - expiry < lastDifference);
-            lastDifference = newExpiry - expiry;
-            expiry = newExpiry;
-        }
-        fail("Relevance failed to go to the maximum value after " + steps + " bumps");
-    }
-
-    @Test
-    public void testContinuity() {
-        final long expiry = System.currentTimeMillis();
-
-        // Relevance at expiry and after expiry should be the cap.
-        final int relevanceBeforeMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
-                expiry - (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1_000_000));
-        assertEquals(relevanceBeforeMaxLifetime, CAPPED_RELEVANCE);
-        final int relevanceForMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
-                expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
-        assertEquals(relevanceForMaxLifetime, CAPPED_RELEVANCE);
-
-        // If the max relevance is reached at the cap lifetime, one millisecond less than this
-        // should be very close. Strictly speaking this is a bit brittle, but it should be
-        // good enough for the purposes of the memory store.
-        final int relevanceForOneMillisecLessThanCap = RelevanceUtils.computeRelevanceForTargetDate(
-                expiry, expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1);
-        assertTrue(relevanceForOneMillisecLessThanCap <= CAPPED_RELEVANCE);
-        assertTrue(relevanceForOneMillisecLessThanCap >= CAPPED_RELEVANCE - 10);
-
-        // Likewise the relevance one millisecond before expiry should be very close to 0. It's
-        // fine if it rounds down to 0.
-        final int relevanceOneMillisecBeforeExpiry = RelevanceUtils.computeRelevanceForTargetDate(
-                expiry, expiry - 1);
-        assertTrue(relevanceOneMillisecBeforeExpiry <= 10);
-        assertTrue(relevanceOneMillisecBeforeExpiry >= 0);
-
-        final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry, expiry);
-        assertEquals(relevanceAtExpiry, 0);
-        final int relevanceAfterExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry,
-                expiry + 1_000_000);
-        assertEquals(relevanceAfterExpiry, 0);
-    }
-
-    // testIncreaseRelevance makes sure bumping the expiry continuously always yields a
-    // monotonically increasing date as a side effect, but this tests that the relevance (as
-    // opposed to the expiry date) increases monotonically with increasing periods.
-    @Test
-    public void testMonotonicity() {
-        // Hopefully the relevance is granular enough to give a different value for every one
-        // of this number of steps.
-        final int steps = 40;
-        final long expiry = System.currentTimeMillis();
-
-        int lastRelevance = -1;
-        for (int i = 0; i < steps; ++i) {
-            final long date = expiry - i * (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS / steps);
-            final int relevance = RelevanceUtils.computeRelevanceForTargetDate(expiry, date);
-            assertTrue(relevance > lastRelevance);
-            lastRelevance = relevance;
-        }
-    }
-}
diff --git a/packages/NetworkStack/tests/unit/src/com/android/server/util/SharedLogTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/util/SharedLogTest.java
deleted file mode 100644
index b1db051..0000000
--- a/packages/NetworkStack/tests/unit/src/com/android/server/util/SharedLogTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 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.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.util.SharedLog;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SharedLogTest {
-    private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
-    private static final String TIMESTAMP = "HH:MM:SS";
-
-    @Test
-    public void testBasicOperation() {
-        final SharedLog logTop = new SharedLog("top");
-        logTop.mark("first post!");
-
-        final SharedLog logLevel2a = logTop.forSubComponent("twoA");
-        final SharedLog logLevel2b = logTop.forSubComponent("twoB");
-        logLevel2b.e("2b or not 2b");
-        logLevel2b.e("No exception", null);
-        logLevel2b.e("Wait, here's one", new Exception("Test"));
-        logLevel2a.w("second post?");
-
-        final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
-        logTop.log("still logging");
-        logLevel3.log("3 >> 2");
-        logLevel2a.mark("ok: last post");
-
-        final String[] expected = {
-            " - MARK first post!",
-            " - [twoB] ERROR 2b or not 2b",
-            " - [twoB] ERROR No exception",
-            // No stacktrace in shared log, only in logcat
-            " - [twoB] ERROR Wait, here's one: Test",
-            " - [twoA] WARN second post?",
-            " - still logging",
-            " - [twoA.three] 3 >> 2",
-            " - [twoA] MARK ok: last post",
-        };
-        // Verify the logs are all there and in the correct order.
-        verifyLogLines(expected, logTop);
-
-        // In fact, because they all share the same underlying LocalLog,
-        // every subcomponent SharedLog's dump() is identical.
-        verifyLogLines(expected, logLevel2a);
-        verifyLogLines(expected, logLevel2b);
-        verifyLogLines(expected, logLevel3);
-    }
-
-    private static void verifyLogLines(String[] expected, SharedLog log) {
-        final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
-        final PrintWriter pw = new PrintWriter(ostream, true);
-        log.dump(null, pw, null);
-
-        final String dumpOutput = ostream.toString();
-        assertTrue(dumpOutput != null);
-        assertTrue(!"".equals(dumpOutput));
-
-        final String[] lines = dumpOutput.split("\n");
-        assertEquals(expected.length, lines.length);
-
-        for (int i = 0; i < expected.length; i++) {
-            String got = lines[i];
-            String want = expected[i];
-            assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
-            assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
-                    got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
-        }
-    }
-}