Merge "Update greylist for Conscrypt update"
diff --git a/Android.bp b/Android.bp
index b4ea61a..3a5fcfa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1070,53 +1070,63 @@
      "-federate SupportLib https://developer.android.com " +
      "-federationapi SupportLib $(location current/support-api.txt) "
 
-doc_defaults {
-    name: "api-stubs-default",
-    srcs: [
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
-        ":openjdk_javadoc_files",
-        ":non_openjdk_javadoc_files",
-        ":android_icu4j_src_files_for_docs",
-    ],
-    srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: frameworks_base_subdirs,
-    srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "core-oj",
-        "core-libart",
-        "conscrypt",
-        "bouncycastle",
-        "okhttp",
-        "ext",
-        "framework",
-        "voip-common",
-        "android.test.mock.impl",
-    ],
-    local_sourcepaths: frameworks_base_subdirs,
-    html_dirs: [
-        "docs/html",
-    ],
-    knowntags: [
-        "docs/knowntags.txt",
-        ":known-oj-tags",
-    ],
-    custom_template: "droiddoc-templates-sdk",
-    hdf: [
-        "dac true",
-        "sdk.codename O",
-        "sdk.preview.version 1",
-        "sdk.version 7.0",
-        "sdk.rel.id 1",
-        "sdk.preview 0",
-    ],
-    resourcesdir: "docs/html/reference/images",
-    resourcesoutdir: "reference/android/images",
-    installable: false,
-}
+framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+     "-overview $(location core/java/overview.html) " +
+     // Federate Support Library references against local API file.
+     "-federate SupportLib https://developer.android.com " +
+     "-federationapi SupportLib $(location current/support-api.txt) "
 
-doc_defaults {
-    name: "framework-docs-default",
+framework_docs_only_libs = [
+    "conscrypt",
+    "bouncycastle",
+    "voip-common",
+    "android.test.mock",
+    "android-support-annotations",
+    "android-support-compat",
+    "android-support-core-ui",
+    "android-support-core-utils",
+    "android-support-customtabs",
+    "android-support-design",
+    "android-support-dynamic-animation",
+    "android-support-exifinterface",
+    "android-support-fragment",
+    "android-support-media-compat",
+    "android-support-percent",
+    "android-support-recommendation",
+    "android-support-transition",
+    "android-support-tv-provider",
+    "android-support-v7-cardview",
+    "android-support-v7-gridlayout",
+    "android-support-v7-mediarouter",
+    "android-support-v7-palette",
+    "android-support-v7-preference",
+    "android-support-v13",
+    "android-support-v14-preference",
+    "android-support-v17-leanback",
+    "android-support-v17-preference-leanback",
+    "android-support-wear",
+    "android-support-vectordrawable",
+    "android-support-animatedvectordrawable",
+    "android-support-v7-appcompat",
+    "android-support-v7-recyclerview",
+    "android-support-emoji",
+    "android-support-emoji-appcompat",
+    "android-support-emoji-bundled",
+    "android-support-v8-renderscript",
+    "android-support-multidex",
+    "android-support-multidex-instrumentation",
+]
+
+metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
+    "--hide-package com.android.okhttp " +
+    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
+    "--hide RequiresPermission " +
+    "--hide MissingPermission --hide BroadcastBehavior " +
+    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
+    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
+
+stubs_defaults {
+    name: "framework-doc-stubs-default",
     srcs: [
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
@@ -1130,47 +1140,25 @@
     srcs_lib: "framework",
     srcs_lib_whitelist_dirs: frameworks_base_subdirs,
     srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "conscrypt",
-        "bouncycastle",
-        "voip-common",
-        "android.test.mock",
-        "android-support-annotations",
-        "android-support-compat",
-        "android-support-core-ui",
-        "android-support-core-utils",
-        "android-support-customtabs",
-        "android-support-design",
-        "android-support-dynamic-animation",
-        "android-support-exifinterface",
-        "android-support-fragment",
-        "android-support-media-compat",
-        "android-support-percent",
-        "android-support-recommendation",
-        "android-support-transition",
-        "android-support-tv-provider",
-        "android-support-v7-cardview",
-        "android-support-v7-gridlayout",
-        "android-support-v7-mediarouter",
-        "android-support-v7-palette",
-        "android-support-v7-preference",
-        "android-support-v13",
-        "android-support-v14-preference",
-        "android-support-v17-leanback",
-        "android-support-v17-preference-leanback",
-        "android-support-wear",
-        "android-support-vectordrawable",
-        "android-support-animatedvectordrawable",
-        "android-support-v7-appcompat",
-        "android-support-v7-recyclerview",
-        "android-support-emoji",
-        "android-support-emoji-appcompat",
-        "android-support-emoji-bundled",
-        "android-support-v8-renderscript",
-        "android-support-multidex",
-        "android-support-multidex-instrumentation",
-    ],
+    libs: framework_docs_only_libs,
     local_sourcepaths: frameworks_base_subdirs,
+    create_doc_stubs: true,
+    annotations_enabled: true,
+    api_levels_annotations_enabled: true,
+    api_levels_annotations_dirs: [
+        "sdk-dir",
+        "api-versions-jars-dir",
+    ],
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
+        "metalava-manual",
+        "ojluni-annotated-stubs",
+    ],
+}
+
+doc_defaults {
+    name: "framework-docs-default",
+    libs: framework_docs_only_libs,
     html_dirs: [
         "docs/html",
     ],
@@ -1191,22 +1179,12 @@
     ],
     arg_files: [
         "core/res/AndroidManifest.xml",
-        ":api-version-xml",
         "core/java/overview.html",
         ":current-support-api",
-        "api/current.txt",
     ],
     create_stubs: false,
 }
 
-metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
-    "--hide-package com.android.okhttp " +
-    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
-    "--hide RequiresPermission " +
-    "--hide MissingPermission --hide BroadcastBehavior " +
-    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
-    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
-
 stubs_defaults {
     name: "metalava-api-stubs-default",
     srcs: [
@@ -1240,21 +1218,45 @@
     ],
 }
 
+droidstubs {
+    name: "framework-doc-stubs",
+    defaults: ["framework-doc-stubs-default"],
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args,
+}
+
+droidstubs {
+    name: "framework-doc-system-stubs",
+    defaults: ["framework-doc-stubs-default"],
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ",
+}
+
 droiddoc {
     name: "doc-comment-check-docs",
     defaults: ["framework-docs-default"],
-    args: framework_docs_args + " -referenceonly -parsecomments",
+    srcs: [
+        ":framework-doc-stubs",
+    ],
+    args: framework_docs_only_args + " -referenceonly -parsecomments",
     installable: false,
 }
 
 droiddoc {
     name: "offline-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-sdk-docs-proofrerad.txt",
-    args: framework_docs_args + " -offlinemode -title \"Android SDK\"",
+    args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-preview-index.html",
 }
@@ -1262,11 +1264,14 @@
 droiddoc {
     name: "offline-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_args + " -offlinemode -title \"Android SDK\" -referenceonly",
+    args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
@@ -1275,13 +1280,15 @@
 droiddoc {
     name: "offline-system-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-system-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_args + " -hide 101 -hide 104 -hide 108" +
-          " -showAnnotation android.annotation.SystemApi " +
-          " -offlinemode -title \"Android System SDK\" -referenceonly",
+    args: framework_docs_only_args  + " -hide 101 -hide 104 -hide 108" +
+        " -offlinemode -title \"Android System SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
@@ -1290,12 +1297,15 @@
 droiddoc {
     name: "online-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args  +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1316,14 +1326,16 @@
 droiddoc {
     name: "online-system-api-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-system-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-system-api-sdk-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -referenceonly " +
-        " -showAnnotation android.annotation.SystemApi " +
         " -title \"Android SDK - Including system APIs.\" " +
         " -hide 101 " +
         " -hide 104 " +
@@ -1349,12 +1361,15 @@
 droiddoc {
     name: "ds-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "ds-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1375,11 +1390,14 @@
 droiddoc {
     name: "ds-static-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
     ],
     proofread_file: "ds-static-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -staticonly " +
           " -toroot / " +
           " -devsite " +
@@ -1389,11 +1407,14 @@
 droiddoc {
     name: "ds-ref-navtree-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
     ],
     proofread_file: "ds-ref-navtree-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -toroot / " +
           " -atLinksNavtree " +
           " -navtreeonly ",
@@ -1402,12 +1423,15 @@
 droiddoc {
     name: "online-sdk-dev-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-dev-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1428,13 +1452,16 @@
 droiddoc {
     name: "hidden-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     proofread_file: "hidden-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -referenceonly " +
           " -title \"Android SDK - Including hidden APIs.\"",
 }
 
-droiddoc {
+droidstubs {
     name: "hwbinder-stubs-docs",
     srcs: [
         "core/java/android/os/HidlSupport.java",
@@ -1452,10 +1479,15 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
-    custom_template: "droiddoc-templates-sdk",
     installable: false,
     no_framework_libs: true,
-    args: "-showAnnotation android.annotation.SystemApi -nodocs -stubsourceonly",
+    annotations_enabled: true,
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
+        "metalava-manual",
+        "ojluni-annotated-stubs",
+    ],
+    args: " --show-annotation android.annotation.SystemApi",
 }
 
 java_library_static {
@@ -1482,23 +1514,17 @@
 }
 
 
-droiddoc {
+droidstubs {
     name: "hiddenapi-mappings",
-    defaults: ["api-stubs-default"],
+    defaults: ["metalava-api-stubs-default"],
     arg_files: [
         "core/res/AndroidManifest.xml",
-        ":api-version-xml",
-        "core/java/overview.html",
-        ":current-support-api",
-        "api/current.txt",
     ],
     dex_mapping_filename: "dex-mapping.txt",
-    args: framework_docs_args +
-          " -referenceonly" +
-          " -nodocs" +
-          " -showUnannotated" +
-          " -showAnnotation android.annotation.SystemApi" +
-          " -showAnnotation android.annotation.TestApi",
+    args: metalava_framework_docs_args +
+        " --show-unannotated " +
+        " --show-annotation android.annotation.SystemApi " +
+        " --show-annotation android.annotation.TestApi "
 }
 
 filegroup {
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 63c583f..50e97c5 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1436,12 +1436,6 @@
 android.hardware.usb.UsbDeviceConnection
 android.hardware.usb.UsbManager
 android.hardware.usb.UsbRequest
-android.hidl.base.V1_0.DebugInfo
-android.hidl.base.V1_0.IBase
-android.hidl.manager.V1_0.IServiceManager
-android.hidl.manager.V1_0.IServiceManager$Proxy
-android.hidl.manager.V1_0.IServiceNotification
-android.hidl.manager.V1_0.IServiceNotification$Stub
 android.icu.impl.BMPSet
 android.icu.impl.CacheBase
 android.icu.impl.CacheValue
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
new file mode 100644
index 0000000..69cc94f
--- /dev/null
+++ b/core/java/android/content/pm/AndroidHidlUpdater.java
@@ -0,0 +1,43 @@
+/*
+ * 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.content.pm;
+
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.PackageParser.Package;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
+ * and android.hidl.manager-V1.0-java libraries are included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
+
+    @Override
+    public void updatePackage(Package pkg) {
+        // This was the default <= P and is maintained for backwards compatibility.
+        if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.P) {
+            prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
+            prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index a16f81b..03eefed 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -53,6 +53,8 @@
                 "android.content.pm.OrgApacheHttpLegacyUpdater",
                 RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new);
 
+        packageUpdaters.add(new AndroidHidlUpdater());
+
         // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
         // android.test.mock.
         packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 83e8663..387d29e8 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,6 +22,10 @@
  */
 public class SharedLibraryNames {
 
+    static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+
+    static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+
     static final String ANDROID_TEST_BASE = "android.test.base";
 
     static final String ANDROID_TEST_MOCK = "android.test.mock";
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 494a957..08c9678 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -227,7 +227,6 @@
     static_libs: [
         "libgif",
         "libseccomp_policy",
-        "libselinux",
         "libgrallocusage",
         "libscrypt_static",
     ],
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
new file mode 100644
index 0000000..7218b3a2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.content.pm;
+
+import static android.content.pm.PackageBuilder.builder;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O);
+
+        // Should add both HIDL libraries
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(OTHER_LIBRARY);
+
+        // The hidl jars should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        // No change is required because although the HIDL libraries has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
+        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6f52fbd..c4017d15 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -188,6 +188,12 @@
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.impl.jar" />
 
+    <!-- In BOOT_JARS historically, and now added to legacy applications. -->
+    <library name="android.hidl.base-V1.0-java"
+            file="/system/framework/android.hidl.base-V1.0-java.jar" />
+    <library name="android.hidl.manager-V1.0-java"
+            file="/system/framework/android.hidl.manager-V1.0-java.jar" />
+
     <!-- These are the standard packages that are white-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
     <allow-in-power-save package="com.android.providers.downloads" />
diff --git a/packages/SystemUI/res/layout/operator_name.xml b/packages/SystemUI/res/layout/operator_name.xml
index c4f75e9..015e30a 100644
--- a/packages/SystemUI/res/layout/operator_name.xml
+++ b/packages/SystemUI/res/layout/operator_name.xml
@@ -27,5 +27,6 @@
         android:maxLength="20"
         android:gravity="center_vertical|start"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:singleLine="true" />
+        android:singleLine="true"
+        android:paddingEnd="5dp" />
 </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 9435589..f4f2ebc 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -38,6 +38,7 @@
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.systemui.util.EmergencyDialerConstants;
 
 /**
  * This class implements a smart emergency button that updates itself based
@@ -47,11 +48,13 @@
  */
 public class EmergencyButton extends Button {
     private static final Intent INTENT_EMERGENCY_DIAL = new Intent()
-            .setAction("com.android.phone.EmergencyDialer.DIAL")
+            .setAction(EmergencyDialerConstants.ACTION_DIAL)
             .setPackage("com.android.phone")
             .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP)
+            .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+                    EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
 
     private static final String LOG_TAG = "EmergencyButton";
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 8320d32..00758e8 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -89,6 +89,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.util.EmergencyDialerConstants;
 import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
 
 import java.util.ArrayList;
@@ -448,9 +449,6 @@
     }
 
     private class EmergencyDialerAction extends SinglePressAction {
-        private static final String ACTION_EMERGENCY_DIALER_DIAL =
-                "com.android.phone.EmergencyDialer.DIAL";
-
         private EmergencyDialerAction() {
             super(R.drawable.ic_faster_emergency,
                     R.string.global_action_emergency);
@@ -458,8 +456,10 @@
 
         @Override
         public void onPress() {
-            Intent intent = new Intent(ACTION_EMERGENCY_DIALER_DIAL);
+            Intent intent = new Intent(EmergencyDialerConstants.ACTION_DIAL);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+                    EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
             mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
new file mode 100644
index 0000000..d101ccb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
@@ -0,0 +1,38 @@
+/*
+ * 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.systemui.util;
+
+/**
+ * Constants defined and used in emergency dialer.
+ * Please keep these constants being consistent with those in com.android.phone.EmergencyDialer.
+ */
+public class EmergencyDialerConstants {
+    // Intent action for emergency dialer activity.
+    public static final String ACTION_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
+    /**
+     * Extra included in {@link #ACTION_DIAL} to indicate the entry type that user starts
+     * the emergency dialer.
+     */
+    public static final String EXTRA_ENTRY_TYPE =
+            "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE";
+
+    // Indicating the entrance to emergency dialer
+    public static final int ENTRY_TYPE_UNKNOWN = 0;
+    public static final int ENTRY_TYPE_LOCKSCREEN_BUTTON = 1;
+    public static final int ENTRY_TYPE_POWER_MENU = 2;
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d16c277..a8f7259 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -68,6 +68,7 @@
 import android.hardware.usb.UsbManager;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -112,10 +113,8 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.LocalServices;
-import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadController;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringConfiguration;
 import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
@@ -149,7 +148,7 @@
     protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
 
     private static final Class[] messageClasses = {
-            Tethering.class, TetherMasterSM.class, TetherInterfaceStateMachine.class
+            Tethering.class, TetherMasterSM.class, IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
@@ -159,21 +158,21 @@
             .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
 
     private static class TetherState {
-        public final TetherInterfaceStateMachine stateMachine;
+        public final IpServer ipServer;
         public int lastState;
         public int lastError;
 
-        public TetherState(TetherInterfaceStateMachine sm) {
-            stateMachine = sm;
+        public TetherState(IpServer ipServer) {
+            this.ipServer = ipServer;
             // Assume all state machines start out available and with no errors.
-            lastState = IControlsTethering.STATE_AVAILABLE;
+            lastState = IpServer.STATE_AVAILABLE;
             lastError = TETHER_ERROR_NO_ERROR;
         }
 
         public boolean isCurrentlyServing() {
             switch (lastState) {
-                case IControlsTethering.STATE_TETHERED:
-                case IControlsTethering.STATE_LOCAL_ONLY:
+                case IpServer.STATE_TETHERED:
+                case IpServer.STATE_LOCAL_ONLY:
                     return true;
                 default:
                     return false;
@@ -198,7 +197,7 @@
     private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     // TODO: Figure out how to merge this and other downstream-tracking objects
     // into a single coherent structure.
-    private final HashSet<TetherInterfaceStateMachine> mForwardedDownstreams;
+    private final HashSet<IpServer> mForwardedDownstreams;
     private final VersionedBroadcastListener mCarrierConfigChange;
     private final TetheringDependencies mDeps;
 
@@ -604,7 +603,7 @@
     }
 
     public int tether(String iface) {
-        return tether(iface, IControlsTethering.STATE_TETHERED);
+        return tether(iface, IpServer.STATE_TETHERED);
     }
 
     private int tether(String iface, int requestedState) {
@@ -617,7 +616,7 @@
             }
             // Ignore the error status of the interface.  If the interface is available,
             // the errors are referring to past tethering attempts anyway.
-            if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
+            if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
                 Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
@@ -626,8 +625,7 @@
             // return an error.
             //
             // TODO: reexamine the threading and messaging model.
-            tetherState.stateMachine.sendMessage(
-                    TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -644,8 +642,7 @@
                 Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
-            tetherState.stateMachine.sendMessage(
-                    TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -689,11 +686,11 @@
                 String iface = mTetherStates.keyAt(i);
                 if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
                     erroredList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+                } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
                     availableList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) {
+                } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
                     localOnlyList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
                     if (cfg.isUsb(iface)) {
                         usbTethered = true;
                     } else if (cfg.isWifi(iface)) {
@@ -882,10 +879,10 @@
             synchronized (Tethering.this.mPublicSync) {
                 if (!usbConnected && mRndisEnabled) {
                     // Turn off tethering if it was enabled and there is a disconnect.
-                    tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
+                    tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
                 } else if (usbConfigured && rndisEnabled) {
                     // Tether if rndis is enabled and usb is configured.
-                    tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
+                    tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
                 }
                 mRndisEnabled = usbConfigured && rndisEnabled;
             }
@@ -959,15 +956,15 @@
         if (!TextUtils.isEmpty(ifname)) {
             final TetherState ts = mTetherStates.get(ifname);
             if (ts != null) {
-                ts.stateMachine.unwanted();
+                ts.ipServer.unwanted();
                 return;
             }
         }
 
         for (int i = 0; i < mTetherStates.size(); i++) {
-            TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
-            if (tism.interfaceType() == TETHERING_WIFI) {
-                tism.unwanted();
+            final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
+            if (ipServer.interfaceType() == TETHERING_WIFI) {
+                ipServer.unwanted();
                 return;
             }
         }
@@ -978,15 +975,15 @@
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
-        // Map wifiIpMode values to IControlsTethering serving states, inferring
+        // Map wifiIpMode values to IpServer.Callback serving states, inferring
         // from mWifiTetherRequested as a final "best guess".
         final int ipServingMode;
         switch (wifiIpMode) {
             case IFACE_IP_MODE_TETHERED:
-                ipServingMode = IControlsTethering.STATE_TETHERED;
+                ipServingMode = IpServer.STATE_TETHERED;
                 break;
             case IFACE_IP_MODE_LOCAL_ONLY:
-                ipServingMode = IControlsTethering.STATE_LOCAL_ONLY;
+                ipServingMode = IpServer.STATE_LOCAL_ONLY;
                 break;
             default:
                 mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
@@ -1041,12 +1038,12 @@
     private void changeInterfaceState(String ifname, int requestedState) {
         final int result;
         switch (requestedState) {
-            case IControlsTethering.STATE_UNAVAILABLE:
-            case IControlsTethering.STATE_AVAILABLE:
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
                 result = untether(ifname);
                 break;
-            case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_ONLY:
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
                 result = tether(ifname, requestedState);
                 break;
             default:
@@ -1104,7 +1101,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+                if (tetherState.lastState == IpServer.STATE_TETHERED) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1117,7 +1114,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+                if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1177,7 +1174,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState != IControlsTethering.STATE_TETHERED) {
+                if (tetherState.lastState != IpServer.STATE_TETHERED) {
                     continue;  // Skip interfaces that aren't tethered.
                 }
                 String iface = mTetherStates.keyAt(i);
@@ -1231,7 +1228,7 @@
         // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
         // so that the garbage collector does not clean up the state machine before it has a chance
         // to tear itself down.
-        private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+        private final ArrayList<IpServer> mNotifyList;
         private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
         private final OffloadWrapper mOffload;
 
@@ -1268,17 +1265,19 @@
             public boolean processMessage(Message message) {
                 logMessage(this, message.what);
                 switch (message.what) {
-                    case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
                         transitionTo(mTetherModeAliveState);
                         break;
-                    case EVENT_IFACE_SERVING_STATE_INACTIVE:
-                        who = (TetherInterfaceStateMachine) message.obj;
+                    }
+                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         handleInterfaceServingStateInactive(who);
                         break;
+                    }
                     case EVENT_IFACE_UPDATE_LINKPROPERTIES:
                         // Silently ignore these for now.
                         break;
@@ -1410,8 +1409,8 @@
 
         protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
             mCurrentUpstreamIfaceSet = ifaces;
-            for (TetherInterfaceStateMachine sm : mNotifyList) {
-                sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces);
+            for (IpServer ipServer : mNotifyList) {
+                ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
             }
         }
 
@@ -1420,13 +1419,13 @@
             mOffload.updateUpstreamNetworkState(ns);
         }
 
-        private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) {
+        private void handleInterfaceServingStateActive(int mode, IpServer who) {
             if (mNotifyList.indexOf(who) < 0) {
                 mNotifyList.add(who);
                 mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
             }
 
-            if (mode == IControlsTethering.STATE_TETHERED) {
+            if (mode == IpServer.STATE_TETHERED) {
                 // No need to notify OffloadController just yet as there are no
                 // "offload-able" prefixes to pass along. This will handled
                 // when the TISM informs Tethering of its LinkProperties.
@@ -1441,10 +1440,10 @@
                 final WifiManager mgr = getWifiManager();
                 final String iface = who.interfaceName();
                 switch (mode) {
-                    case IControlsTethering.STATE_TETHERED:
+                    case IpServer.STATE_TETHERED:
                         mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
                         break;
-                    case IControlsTethering.STATE_LOCAL_ONLY:
+                    case IpServer.STATE_LOCAL_ONLY:
                         mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
                         break;
                     default:
@@ -1454,7 +1453,7 @@
             }
         }
 
-        private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
+        private void handleInterfaceServingStateInactive(IpServer who) {
             mNotifyList.remove(who);
             mIPv6TetheringCoordinator.removeActiveDownstream(who);
             mOffload.excludeDownstreamInterface(who.interfaceName());
@@ -1563,10 +1562,10 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case EVENT_IFACE_SERVING_STATE_ACTIVE: {
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
-                        who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+                        who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                                 mCurrentUpstreamIfaceSet);
                         // If there has been a change and an upstream is now
                         // desired, kick off the selection process.
@@ -1577,7 +1576,7 @@
                         break;
                     }
                     case EVENT_IFACE_SERVING_STATE_INACTIVE: {
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         handleInterfaceServingStateInactive(who);
 
@@ -1591,7 +1590,7 @@
                         if (DBG) {
                             Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
                                     " live requests:");
-                            for (TetherInterfaceStateMachine o : mNotifyList) {
+                            for (IpServer o : mNotifyList) {
                                 Log.d(TAG, "  " + o);
                             }
                         }
@@ -1605,7 +1604,7 @@
                     }
                     case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
                         final LinkProperties newLp = (LinkProperties) message.obj;
-                        if (message.arg1 == IControlsTethering.STATE_TETHERED) {
+                        if (message.arg1 == IpServer.STATE_TETHERED) {
                             mOffload.updateDownstreamLinkProperties(newLp);
                         } else {
                             mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
@@ -1650,7 +1649,7 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         who.sendMessage(mErrorNotification);
                         break;
                     case CMD_CLEAR_ERROR:
@@ -1665,8 +1664,8 @@
 
             void notify(int msgType) {
                 mErrorNotification = msgType;
-                for (TetherInterfaceStateMachine sm : mNotifyList) {
-                    sm.sendMessage(msgType);
+                for (IpServer ipServer : mNotifyList) {
+                    ipServer.sendMessage(msgType);
                 }
             }
 
@@ -1676,7 +1675,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setIpForwardingEnabled");
-                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR);
+                notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
             }
         }
 
@@ -1684,7 +1683,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setIpForwardingDisabled");
-                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR);
+                notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
             }
         }
 
@@ -1692,7 +1691,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in startTethering");
-                notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR);
+                notify(IpServer.CMD_START_TETHERING_ERROR);
                 try {
                     mNMService.setIpForwardingEnabled(false);
                 } catch (Exception e) {}
@@ -1703,7 +1702,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in stopTethering");
-                notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR);
+                notify(IpServer.CMD_STOP_TETHERING_ERROR);
                 try {
                     mNMService.setIpForwardingEnabled(false);
                 } catch (Exception e) {}
@@ -1714,7 +1713,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setDnsForwarders");
-                notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR);
+                notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
                 try {
                     mNMService.stopTethering();
                 } catch (Exception e) {}
@@ -1771,15 +1770,15 @@
 
                 // Maybe add prefixes or addresses for downstreams, depending on
                 // the IP serving mode of each.
-                for (TetherInterfaceStateMachine tism : mNotifyList) {
-                    final LinkProperties lp = tism.linkProperties();
+                for (IpServer ipServer : mNotifyList) {
+                    final LinkProperties lp = ipServer.linkProperties();
 
-                    switch (tism.servingMode()) {
-                        case IControlsTethering.STATE_UNAVAILABLE:
-                        case IControlsTethering.STATE_AVAILABLE:
+                    switch (ipServer.servingMode()) {
+                        case IpServer.STATE_UNAVAILABLE:
+                        case IpServer.STATE_AVAILABLE:
                             // No usable LinkProperties in these states.
                             continue;
-                        case IControlsTethering.STATE_TETHERED:
+                        case IpServer.STATE_TETHERED:
                             // Only add IPv4 /32 and IPv6 /128 prefixes. The
                             // directly-connected prefixes will be sent as
                             // downstream "offload-able" prefixes.
@@ -1789,7 +1788,7 @@
                                 localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
                             }
                             break;
-                        case IControlsTethering.STATE_LOCAL_ONLY:
+                        case IpServer.STATE_LOCAL_ONLY:
                             // Add prefixes covering all local IPs.
                             localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
                             break;
@@ -1826,16 +1825,16 @@
                 pw.print(iface + " - ");
 
                 switch (tetherState.lastState) {
-                    case IControlsTethering.STATE_UNAVAILABLE:
+                    case IpServer.STATE_UNAVAILABLE:
                         pw.print("UnavailableState");
                         break;
-                    case IControlsTethering.STATE_AVAILABLE:
+                    case IpServer.STATE_AVAILABLE:
                         pw.print("AvailableState");
                         break;
-                    case IControlsTethering.STATE_TETHERED:
+                    case IpServer.STATE_TETHERED:
                         pw.print("TetheredState");
                         break;
-                    case IControlsTethering.STATE_LOCAL_ONLY:
+                    case IpServer.STATE_LOCAL_ONLY:
                         pw.print("LocalHotspotState");
                         break;
                     default:
@@ -1873,28 +1872,26 @@
         return false;
     }
 
-    private IControlsTethering makeControlCallback(String ifname) {
-        return new IControlsTethering() {
+    private IpServer.Callback makeControlCallback() {
+        return new IpServer.Callback() {
             @Override
-            public void updateInterfaceState(
-                    TetherInterfaceStateMachine who, int state, int lastError) {
-                notifyInterfaceStateChange(ifname, who, state, lastError);
+            public void updateInterfaceState(IpServer who, int state, int lastError) {
+                notifyInterfaceStateChange(who, state, lastError);
             }
 
             @Override
-            public void updateLinkProperties(
-                    TetherInterfaceStateMachine who, LinkProperties newLp) {
-                notifyLinkPropertiesChanged(ifname, who, newLp);
+            public void updateLinkProperties(IpServer who, LinkProperties newLp) {
+                notifyLinkPropertiesChanged(who, newLp);
             }
         };
     }
 
     // TODO: Move into TetherMasterSM.
-    private void notifyInterfaceStateChange(
-            String iface, TetherInterfaceStateMachine who, int state, int error) {
+    private void notifyInterfaceStateChange(IpServer who, int state, int error) {
+        final String iface = who.interfaceName();
         synchronized (mPublicSync) {
             final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.stateMachine.equals(who)) {
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
                 tetherState.lastState = state;
                 tetherState.lastError = error;
             } else {
@@ -1908,7 +1905,7 @@
             // Notify that we're tethering (or not) this interface.
             // This is how data saver for instance knows if the user explicitly
             // turned on tethering (thus keeping us from being in data saver mode).
-            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
+            mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
         } catch (RemoteException e) {
             // Not really very much we can do here.
         }
@@ -1921,12 +1918,12 @@
         }
         int which;
         switch (state) {
-            case IControlsTethering.STATE_UNAVAILABLE:
-            case IControlsTethering.STATE_AVAILABLE:
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
                 break;
-            case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_ONLY:
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
                 break;
             default:
@@ -1937,12 +1934,12 @@
         sendTetherStateChangedBroadcast();
     }
 
-    private void notifyLinkPropertiesChanged(String iface, TetherInterfaceStateMachine who,
-                                             LinkProperties newLp) {
+    private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
+        final String iface = who.interfaceName();
         final int state;
         synchronized (mPublicSync) {
             final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.stateMachine.equals(who)) {
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
                 state = tetherState.lastState;
             } else {
                 mLog.log("got notification from stale iface " + iface);
@@ -1952,7 +1949,7 @@
 
         mLog.log(String.format(
                 "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
-                iface, IControlsTethering.getStateString(state), newLp));
+                iface, IpServer.getStateString(state), newLp));
         final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
         mTetherMasterSM.sendMessage(which, state, 0, newLp);
     }
@@ -1976,11 +1973,11 @@
 
         mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
         final TetherState tetherState = new TetherState(
-                new TetherInterfaceStateMachine(
-                    iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
-                    makeControlCallback(iface), mConfig.enableLegacyDhcpServer, mDeps));
+                new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
+                             mDeps.getIpServerDependencies()));
         mTetherStates.put(iface, tetherState);
-        tetherState.stateMachine.start();
+        tetherState.ipServer.start();
     }
 
     private void stopTrackingInterfaceLocked(final String iface) {
@@ -1989,36 +1986,11 @@
             mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
             return;
         }
-        tetherState.stateMachine.stop();
+        tetherState.ipServer.stop();
         mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
         mTetherStates.remove(iface);
     }
 
-    private static String getIPv4DefaultRouteInterface(NetworkState ns) {
-        if (ns == null) return null;
-        return getInterfaceForDestination(ns.linkProperties, Inet4Address.ANY);
-    }
-
-    private static String getIPv6DefaultRouteInterface(NetworkState ns) {
-        if (ns == null) return null;
-        // An upstream network's IPv6 capability is currently only useful if it
-        // can be 64share'd downstream (RFC 7278). For now, that means mobile
-        // upstream networks only.
-        if (ns.networkCapabilities == null ||
-                !ns.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
-            return null;
-        }
-
-        return getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY);
-    }
-
-    private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
-        final RouteInfo ri = (lp != null)
-                ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
-                : null;
-        return (ri != null) ? ri.getInterface() : null;
-    }
-
     private static String[] copy(String[] strarray) {
         return Arrays.copyOf(strarray, strarray.length);
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
deleted file mode 100644
index 2b81347..0000000
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ /dev/null
@@ -1,66 +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 com.android.server.connectivity.tethering;
-
-import android.net.LinkProperties;
-
-/**
- * @hide
- *
- * Interface with methods necessary to notify that a given interface is ready for tethering.
- *
- * Rename to something more representative, e.g. IpServingControlCallback.
- *
- * All methods MUST be called on the TetherMasterSM main Looper's thread.
- */
-public class IControlsTethering {
-    public static final int STATE_UNAVAILABLE = 0;
-    public static final int STATE_AVAILABLE   = 1;
-    public static final int STATE_TETHERED    = 2;
-    public static final int STATE_LOCAL_ONLY  = 3;
-
-    public static String getStateString(int state) {
-        switch (state) {
-            case STATE_UNAVAILABLE: return "UNAVAILABLE";
-            case STATE_AVAILABLE:   return "AVAILABLE";
-            case STATE_TETHERED:    return "TETHERED";
-            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
-        }
-        return "UNKNOWN: " + state;
-    }
-
-    /**
-     * Notify that |who| has changed its tethering state.
-     *
-     * TODO: Remove the need for the |who| argument.
-     *
-     * @param who corresponding instance of a TetherInterfaceStateMachine
-     * @param state one of IControlsTethering.STATE_*
-     * @param lastError one of ConnectivityManager.TETHER_ERROR_*
-     */
-    public void updateInterfaceState(TetherInterfaceStateMachine who, int state, int lastError) {}
-
-    /**
-     * Notify that |who| has new LinkProperties.
-     *
-     * TODO: Remove the need for the |who| argument.
-     *
-     * @param who corresponding instance of a TetherInterfaceStateMachine
-     * @param newLp the new LinkProperties to report
-     */
-    public void updateLinkProperties(TetherInterfaceStateMachine who, LinkProperties newLp) {}
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index ba67c94..1000148 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity.tethering;
 
 import android.net.ConnectivityManager;
+import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -50,19 +51,19 @@
     private static final boolean VDBG = false;
 
     private static class Downstream {
-        public final TetherInterfaceStateMachine tism;
-        public final int mode;  // IControlsTethering.STATE_*
+        public final IpServer ipServer;
+        public final int mode;  // IpServer.STATE_*
         // Used to append to a ULA /48, constructing a ULA /64 for local use.
         public final short subnetId;
 
-        Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) {
-            this.tism = tism;
+        Downstream(IpServer ipServer, int mode, short subnetId) {
+            this.ipServer = ipServer;
             this.mode = mode;
             this.subnetId = subnetId;
         }
     }
 
-    private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+    private final ArrayList<IpServer> mNotifyList;
     private final SharedLog mLog;
     // NOTE: mActiveDownstreams is a list and not a hash data structure because
     // we keep active downstreams in arrival order.  This is done so /64s can
@@ -74,8 +75,7 @@
     private short mNextSubnetId;
     private NetworkState mUpstreamNetworkState;
 
-    public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
-                                    SharedLog log) {
+    public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
         mNotifyList = notifyList;
         mLog = log.forSubComponent(TAG);
         mActiveDownstreams = new LinkedList<>();
@@ -83,7 +83,7 @@
         mNextSubnetId = 0;
     }
 
-    public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) {
+    public void addActiveDownstream(IpServer downstream, int mode) {
         if (findDownstream(downstream) == null) {
             // Adding a new downstream appends it to the list. Adding a
             // downstream a second time without first removing it has no effect.
@@ -98,7 +98,7 @@
         }
     }
 
-    public void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
+    public void removeActiveDownstream(IpServer downstream) {
         stopIPv6TetheringOn(downstream);
         if (mActiveDownstreams.remove(findDownstream(downstream))) {
             updateIPv6TetheringInterfaces();
@@ -133,8 +133,8 @@
     }
 
     private void stopIPv6TetheringOnAllInterfaces() {
-        for (TetherInterfaceStateMachine sm : mNotifyList) {
-            stopIPv6TetheringOn(sm);
+        for (IpServer ipServer : mNotifyList) {
+            stopIPv6TetheringOn(ipServer);
         }
     }
 
@@ -156,28 +156,28 @@
     }
 
     private void updateIPv6TetheringInterfaces() {
-        for (TetherInterfaceStateMachine sm : mNotifyList) {
-            final LinkProperties lp = getInterfaceIPv6LinkProperties(sm);
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
+        for (IpServer ipServer : mNotifyList) {
+            final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
+            ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
             break;
         }
     }
 
-    private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) {
-        if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
+    private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
+        if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
             // TODO: Figure out IPv6 support on PAN interfaces.
             return null;
         }
 
-        final Downstream ds = findDownstream(sm);
+        final Downstream ds = findDownstream(ipServer);
         if (ds == null) return null;
 
-        if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
+        if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
             // Build a Unique Locally-assigned Prefix configuration.
             return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
         }
 
-        // This downstream is in IControlsTethering.STATE_TETHERED mode.
+        // This downstream is in IpServer.STATE_TETHERED mode.
         if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
             return null;
         }
@@ -188,7 +188,7 @@
         // IPv6 toward the oldest (first requested) active downstream.
 
         final Downstream currentActive = mActiveDownstreams.peek();
-        if (currentActive != null && currentActive.tism == sm) {
+        if (currentActive != null && currentActive.ipServer == ipServer) {
             final LinkProperties lp = getIPv6OnlyLinkProperties(
                     mUpstreamNetworkState.linkProperties);
             if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
@@ -199,9 +199,9 @@
         return null;
     }
 
-    Downstream findDownstream(TetherInterfaceStateMachine tism) {
+    Downstream findDownstream(IpServer ipServer) {
         for (Downstream ds : mActiveDownstreams) {
-            if (ds.tism == tism) return ds;
+            if (ds.ipServer == ipServer) return ds;
         }
         return null;
     }
@@ -304,7 +304,7 @@
                 ns.linkProperties);
     }
 
-    private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) {
-        sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+    private static void stopIPv6TetheringOn(IpServer ipServer) {
+        ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index caa867c..8b40069 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,6 +21,7 @@
 import android.net.NetworkRequest;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
+import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetdService;
@@ -49,20 +50,12 @@
     }
 
     public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-            ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+            ArrayList<IpServer> notifyList, SharedLog log) {
         return new IPv6TetheringCoordinator(notifyList, log);
     }
 
-    public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
-        return new RouterAdvertisementDaemon(ifParams);
-    }
-
-    public InterfaceParams getInterfaceParams(String ifName) {
-        return InterfaceParams.getByName(ifName);
-    }
-
-    public INetd getNetdService() {
-        return NetdService.getInstance();
+    public IpServer.Dependencies getIpServerDependencies() {
+        return new IpServer.Dependencies();
     }
 
     public boolean isTetheringSupported() {
@@ -72,9 +65,4 @@
     public NetworkRequest getDefaultNetworkRequest() {
         return null;
     }
-
-    public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, DhcpServingParams params,
-            SharedLog log) {
-        return new DhcpServer(looper, iface, params, log);
-    }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/net/java/android/net/ip/IpServer.java
similarity index 89%
rename from services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
rename to services/net/java/android/net/ip/IpServer.java
index 5accb45..823c0a1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity.tethering;
+package android.net.ip;
 
 import static android.net.NetworkUtils.numericToInetAddress;
 import static android.net.util.NetworkConstants.asByte;
@@ -31,11 +31,10 @@
 import android.net.RouteInfo;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
-import android.net.ip.InterfaceController;
-import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
+import android.net.util.NetdService;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.Looper;
@@ -67,7 +66,22 @@
  *
  * @hide
  */
-public class TetherInterfaceStateMachine extends StateMachine {
+public class IpServer extends StateMachine {
+    public static final int STATE_UNAVAILABLE = 0;
+    public static final int STATE_AVAILABLE   = 1;
+    public static final int STATE_TETHERED    = 2;
+    public static final int STATE_LOCAL_ONLY  = 3;
+
+    public static String getStateString(int state) {
+        switch (state) {
+            case STATE_UNAVAILABLE: return "UNAVAILABLE";
+            case STATE_AVAILABLE:   return "AVAILABLE";
+            case STATE_TETHERED:    return "TETHERED";
+            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
+        }
+        return "UNKNOWN: " + state;
+    }
+
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
     private static final byte DOUG_ADAMS = (byte) 42;
 
@@ -83,15 +97,53 @@
     // TODO: have this configurable
     private static final int DHCP_LEASE_TIME_SECS = 3600;
 
-    private final static String TAG = "TetherInterfaceSM";
+    private final static String TAG = "IpServer";
     private final static boolean DBG = false;
     private final static boolean VDBG = false;
     private static final Class[] messageClasses = {
-            TetherInterfaceStateMachine.class
+            IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
 
+    public static class Callback {
+        /**
+         * Notify that |who| has changed its tethering state.
+         *
+         * @param who the calling instance of IpServer
+         * @param state one of STATE_*
+         * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+         */
+        public void updateInterfaceState(IpServer who, int state, int lastError) {}
+
+        /**
+         * Notify that |who| has new LinkProperties.
+         *
+         * @param who the calling instance of IpServer
+         * @param newLp the new LinkProperties to report
+         */
+        public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
+    }
+
+    public static class Dependencies {
+        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+            return new RouterAdvertisementDaemon(ifParams);
+        }
+
+        public InterfaceParams getInterfaceParams(String ifName) {
+            return InterfaceParams.getByName(ifName);
+        }
+
+        public INetd getNetdService() {
+            return NetdService.getInstance();
+        }
+
+        public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+                DhcpServingParams params, SharedLog log) {
+            return new DhcpServer(looper, iface, params, log);
+        }
+    }
+
     private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
     // request from the user that it wants to tether
     public static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
@@ -123,7 +175,7 @@
     private final INetworkManagementService mNMService;
     private final INetd mNetd;
     private final INetworkStatsService mStatsService;
-    private final IControlsTethering mTetherController;
+    private final Callback mCallback;
     private final InterfaceController mInterfaceCtrl;
 
     private final String mIfaceName;
@@ -131,7 +183,7 @@
     private final LinkProperties mLinkProperties;
     private final boolean mUsingLegacyDhcp;
 
-    private final TetheringDependencies mDeps;
+    private final Dependencies mDeps;
 
     private int mLastError;
     private int mServingMode;
@@ -148,17 +200,16 @@
     private DhcpServer mDhcpServer;
     private RaParams mLastRaParams;
 
-    public TetherInterfaceStateMachine(
+    public IpServer(
             String ifaceName, Looper looper, int interfaceType, SharedLog log,
             INetworkManagementService nMService, INetworkStatsService statsService,
-            IControlsTethering tetherController, boolean usingLegacyDhcp,
-            TetheringDependencies deps) {
+            Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
         super(ifaceName, looper);
         mLog = log.forSubComponent(ifaceName);
         mNMService = nMService;
         mNetd = deps.getNetdService();
         mStatsService = statsService;
-        mTetherController = tetherController;
+        mCallback = callback;
         mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
@@ -167,7 +218,7 @@
         mDeps = deps;
         resetLinkProperties();
         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
-        mServingMode = IControlsTethering.STATE_AVAILABLE;
+        mServingMode = STATE_AVAILABLE;
 
         mInitialState = new InitialState();
         mLocalHotspotState = new LocalHotspotState();
@@ -379,6 +430,8 @@
             params.mtu = v6only.getMtu();
             params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
 
+            if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
+
             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
                 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
 
@@ -498,6 +551,20 @@
         }
     }
 
+    private byte getHopLimit(String upstreamIface) {
+        try {
+            int upstreamHopLimit = Integer.parseUnsignedInt(
+                    mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit"));
+            // Add one hop to account for this forwarding device
+            upstreamHopLimit++;
+            // Cap the hop limit to 255.
+            return (byte) Integer.min(upstreamHopLimit, 255);
+        } catch (Exception e) {
+            mLog.e("Failed to find upstream interface hop limit", e);
+        }
+        return RaParams.DEFAULT_HOPLIMIT;
+    }
+
     private void setRaParams(RaParams newParams) {
         if (mRaDaemon != null) {
             final RaParams deprecatedParams =
@@ -521,14 +588,12 @@
 
     private void sendInterfaceState(int newInterfaceState) {
         mServingMode = newInterfaceState;
-        mTetherController.updateInterfaceState(
-                TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
+        mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
         sendLinkProperties();
     }
 
     private void sendLinkProperties() {
-        mTetherController.updateLinkProperties(
-                TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
+        mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
     }
 
     private void resetLinkProperties() {
@@ -539,7 +604,7 @@
     class InitialState extends State {
         @Override
         public void enter() {
-            sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
+            sendInterfaceState(STATE_AVAILABLE);
         }
 
         @Override
@@ -549,10 +614,10 @@
                 case CMD_TETHER_REQUESTED:
                     mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
                     switch (message.arg1) {
-                        case IControlsTethering.STATE_LOCAL_ONLY:
+                        case STATE_LOCAL_ONLY:
                             transitionTo(mLocalHotspotState);
                             break;
-                        case IControlsTethering.STATE_TETHERED:
+                        case STATE_TETHERED:
                             transitionTo(mTetheredState);
                             break;
                         default:
@@ -649,7 +714,7 @@
     // problematic because transitioning during a multi-state jump yields
     // a Log.wtf(). Ultimately, there should be only one ServingState,
     // and forwarding and NAT rules should be handled by a coordinating
-    // functional element outside of TetherInterfaceStateMachine.
+    // functional element outside of IpServer.
     class LocalHotspotState extends BaseServingState {
         @Override
         public void enter() {
@@ -659,7 +724,7 @@
             }
 
             if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
+            sendInterfaceState(STATE_LOCAL_ONLY);
         }
 
         @Override
@@ -685,7 +750,7 @@
     // problematic because transitioning during a multi-state jump yields
     // a Log.wtf(). Ultimately, there should be only one ServingState,
     // and forwarding and NAT rules should be handled by a coordinating
-    // functional element outside of TetherInterfaceStateMachine.
+    // functional element outside of IpServer.
     class TetheredState extends BaseServingState {
         @Override
         public void enter() {
@@ -695,7 +760,7 @@
             }
 
             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_TETHERED);
+            sendInterfaceState(STATE_TETHERED);
         }
 
         @Override
@@ -817,7 +882,7 @@
         @Override
         public void enter() {
             mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
-            sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
+            sendInterfaceState(STATE_UNAVAILABLE);
         }
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2cc175c..ebe05e8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1498,23 +1498,24 @@
                 Rlog.d(TAG, "getCellLocation returning null because telephony is null");
                 return null;
             }
+
             Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName());
-            if (bundle.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because bundle is empty");
+            if (bundle == null || bundle.isEmpty()) {
+                Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable");
                 return null;
             }
+
             CellLocation cl = CellLocation.newFromBundle(bundle);
-            if (cl.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty");
+            if (cl == null || cl.isEmpty()) {
+                Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
+                        + " phone type doesn't match CellLocation type");
                 return null;
             }
+
             return cl;
         } catch (RemoteException ex) {
             Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex);
             return null;
-        } catch (NullPointerException ex) {
-            Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex);
-            return null;
         }
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/android/net/ip/IpServerTest.java
similarity index 71%
rename from tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
rename to tests/net/java/android/net/ip/IpServerTest.java
index 5934653..cff0b54 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity.tethering;
+package android.net.ip;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -37,9 +37,9 @@
 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
 import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
+import static android.net.ip.IpServer.STATE_AVAILABLE;
+import static android.net.ip.IpServer.STATE_TETHERED;
+import static android.net.ip.IpServer.STATE_UNAVAILABLE;
 
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
@@ -50,7 +50,6 @@
 import android.net.RouteInfo;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
-import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
@@ -74,7 +73,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class TetherInterfaceStateMachineTest {
+public class IpServerTest {
     private static final String IFACE_NAME = "testnet1";
     private static final String UPSTREAM_IFACE = "upstream0";
     private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -85,39 +84,38 @@
 
     @Mock private INetworkManagementService mNMService;
     @Mock private INetworkStatsService mStatsService;
-    @Mock private IControlsTethering mTetherHelper;
+    @Mock private IpServer.Callback mCallback;
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
     @Mock private SharedLog mSharedLog;
     @Mock private DhcpServer mDhcpServer;
     @Mock private RouterAdvertisementDaemon mRaDaemon;
-    @Mock private TetheringDependencies mTetheringDependencies;
+    @Mock private IpServer.Dependencies mDependencies;
 
     @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;
 
     private final TestLooper mLooper = new TestLooper();
     private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
             ArgumentCaptor.forClass(LinkProperties.class);
-    private TetherInterfaceStateMachine mTestedSm;
+    private IpServer mIpServer;
 
     private void initStateMachine(int interfaceType) throws Exception {
         initStateMachine(interfaceType, false /* usingLegacyDhcp */);
     }
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
-        mTestedSm = new TetherInterfaceStateMachine(
+        mIpServer = new IpServer(
                 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
-                mNMService, mStatsService, mTetherHelper, usingLegacyDhcp,
-                mTetheringDependencies);
-        mTestedSm.start();
+                mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
+        mIpServer.start();
         // Starting the state machine always puts us in a consistent state and notifies
         // the rest of the world that we've changed from an unknown to available state.
         mLooper.dispatchAll();
-        reset(mNMService, mStatsService, mTetherHelper);
+        reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
-        when(mTetheringDependencies.makeDhcpServer(
+        when(mDependencies.makeDhcpServer(
                 any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
-        when(mTetheringDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
-        when(mTetheringDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+        when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
+        when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
 
         when(mRaDaemon.start()).thenReturn(true);
     }
@@ -130,11 +128,11 @@
     private void initTetheredStateMachine(int interfaceType, String upstreamIface,
             boolean usingLegacyDhcp) throws Exception {
         initStateMachine(interfaceType, usingLegacyDhcp);
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
         if (upstreamIface != null) {
             dispatchTetherConnectionChanged(upstreamIface);
         }
-        reset(mNMService, mStatsService, mTetherHelper);
+        reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
     }
 
@@ -145,34 +143,34 @@
 
     @Test
     public void startsOutAvailable() {
-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
-                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
-                false /* usingLegacyDhcp */, mTetheringDependencies);
-        mTestedSm.start();
+        mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
+                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
+                false /* usingLegacyDhcp */, mDependencies);
+        mIpServer.start();
         mLooper.dispatchAll();
-        verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
+        verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
     }
 
     @Test
     public void shouldDoNothingUntilRequested() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
         final int [] NOOP_COMMANDS = {
-            TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
-            TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
-            TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
-            TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
-            TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
+            IpServer.CMD_TETHER_UNREQUESTED,
+            IpServer.CMD_IP_FORWARDING_ENABLE_ERROR,
+            IpServer.CMD_IP_FORWARDING_DISABLE_ERROR,
+            IpServer.CMD_START_TETHERING_ERROR,
+            IpServer.CMD_STOP_TETHERING_ERROR,
+            IpServer.CMD_SET_DNS_FORWARDERS_ERROR,
+            IpServer.CMD_TETHER_CONNECTION_CHANGED
         };
         for (int command : NOOP_COMMANDS) {
             // None of these commands should trigger us to request action from
             // the rest of the system.
             dispatchCommand(command);
-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+            verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
         }
     }
 
@@ -180,57 +178,57 @@
     public void handlesImmediateInterfaceDown() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-        verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
-        verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+        verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+        verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canBeTethered() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder inOrder = inOrder(mCallback, mNMService);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canUnrequestTethering() throws Exception {
         initTetheredStateMachine(TETHERING_BLUETOOTH, null);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canBeTetheredAsUsb() throws Exception {
         initStateMachine(TETHERING_USB);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder inOrder = inOrder(mCallback, mNMService);
         inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -243,7 +241,7 @@
         InOrder inOrder = inOrder(mNMService);
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -257,7 +255,7 @@
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -300,18 +298,18 @@
     public void canUnrequestTetheringWithUpstream() throws Exception {
         initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
         inOrder.verify(mStatsService).forceUpdate();
         inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -322,15 +320,15 @@
             if (shouldThrow) {
                 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
             }
-            dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+            dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
             usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
             usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                     IFACE_NAME, mInterfaceConfiguration);
-            usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                    mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
-            usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                    eq(mTestedSm), mLinkPropertiesCaptor.capture());
+            usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                    mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+            usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                    eq(mIpServer), mLinkPropertiesCaptor.capture());
             assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
         }
     }
@@ -340,15 +338,15 @@
         initStateMachine(TETHERING_USB);
 
         doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                 IFACE_NAME, mInterfaceConfiguration);
-        usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
-        usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
+        usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
@@ -358,13 +356,13 @@
 
         doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
-        usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
-        usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
+        usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
@@ -372,11 +370,11 @@
     public void ignoresDuplicateUpstreamNotifications() throws Exception {
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
 
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
 
         for (int i = 0; i < 5; i++) {
             dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+            verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
         }
     }
 
@@ -401,11 +399,11 @@
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
 
-        verify(mTetheringDependencies, never()).makeDhcpServer(any(), any(), any(), any());
+        verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any());
     }
 
     private void assertDhcpStarted(IpPrefix expectedPrefix) {
-        verify(mTetheringDependencies, times(1)).makeDhcpServer(
+        verify(mDependencies, times(1)).makeDhcpServer(
                 eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
         verify(mDhcpServer, times(1)).start();
         final DhcpServingParams params = mDhcpParamsCaptor.getValue();
@@ -422,21 +420,21 @@
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+     * @param command One of the IpServer.CMD_* constants.
      * @param arg1 An additional argument to pass.
      */
     private void dispatchCommand(int command, int arg1) {
-        mTestedSm.sendMessage(command, arg1);
+        mIpServer.sendMessage(command, arg1);
         mLooper.dispatchAll();
     }
 
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+     * @param command One of the IpServer.CMD_* constants.
      */
     private void dispatchCommand(int command) {
-        mTestedSm.sendMessage(command);
+        mIpServer.sendMessage(command);
         mLooper.dispatchAll();
     }
 
@@ -447,7 +445,7 @@
      * @param upstreamIface String name of upstream interface (or null)
      */
     private void dispatchTetherConnectionChanged(String upstreamIface) {
-        mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+        mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                 new InterfaceSet(upstreamIface));
         mLooper.dispatchAll();
     }
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 0d3b8e4..40d5544 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -75,6 +75,7 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetworkConstants;
@@ -99,10 +100,8 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadHardwareInterface;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 
@@ -190,7 +189,7 @@
 
     public class MockTetheringDependencies extends TetheringDependencies {
         StateMachine upstreamNetworkMonitorMasterSM;
-        ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+        ArrayList<IpServer> ipv6CoordinatorNotifyList;
         int isTetheringSupportedCalls;
 
         public void reset() {
@@ -213,29 +212,35 @@
 
         @Override
         public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-                ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+                ArrayList<IpServer> notifyList, SharedLog log) {
             ipv6CoordinatorNotifyList = notifyList;
             return mIPv6TetheringCoordinator;
         }
 
         @Override
-        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
-            return mRouterAdvertisementDaemon;
-        }
+        public IpServer.Dependencies getIpServerDependencies() {
+            return new IpServer.Dependencies() {
+                @Override
+                public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
+                        InterfaceParams ifParams) {
+                    return mRouterAdvertisementDaemon;
+                }
 
-        @Override
-        public INetd getNetdService() {
-            return mNetd;
-        }
+                @Override
+                public InterfaceParams getInterfaceParams(String ifName) {
+                    final String[] ifaces = new String[] {
+                            TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
+                    final int index = ArrayUtils.indexOf(ifaces, ifName);
+                    assertTrue("Non-mocked interface: " + ifName, index >= 0);
+                    return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
+                            MacAddress.ALL_ZEROS_ADDRESS);
+                }
 
-        @Override
-        public InterfaceParams getInterfaceParams(String ifName) {
-            final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
-                    TEST_MOBILE_IFNAME };
-            final int index = ArrayUtils.indexOf(ifaces, ifName);
-            assertTrue("Non-mocked interface: " + ifName, index >= 0);
-            return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
-                    MacAddress.ALL_ZEROS_ADDRESS);
+                @Override
+                public INetd getNetdService() {
+                    return mNetd;
+                }
+            };
         }
 
         @Override
@@ -458,9 +463,9 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        // If, and only if, Tethering received an interface status changed
-        // then it creates a TetherInterfaceStateMachine and sends out a
-        // broadcast indicating that the interface is "available".
+        // If, and only if, Tethering received an interface status changed then
+        // it creates a IpServer and sends out a broadcast indicating that the
+        // interface is "available".
         if (emulateInterfaceStatusChanged) {
             assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
             verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
@@ -557,18 +562,18 @@
     }
 
     /**
-     * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
+     * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
      */
     private void sendIPv6TetherUpdates(NetworkState upstreamState) {
         // IPv6TetheringCoordinator must have been notified of downstream
         verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
                 argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
-                eq(IControlsTethering.STATE_TETHERED));
+                eq(IpServer.STATE_TETHERED));
 
-        for (TetherInterfaceStateMachine tism :
+        for (IpServer ipSrv :
                 mTetheringDependencies.ipv6CoordinatorNotifyList) {
             NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
-            tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
+            ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
                     upstreamState.linkProperties.isIPv6Provisioned()
                             ? ipv6OnlyState.linkProperties
                             : null);
@@ -812,7 +817,7 @@
 
         // We verify get/set called thrice here: once for setup and twice during
         // teardown because all events happen over the course of the single
-        // dispatchAll() above. Note that once the TISM IPv4 address config
+        // dispatchAll() above. Note that once the IpServer IPv4 address config
         // code is refactored the two calls during shutdown will revert to one.
         verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, times(3))
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index bdcc807..76a2f2d 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -12,8 +12,8 @@
 # Sort
 IFS=$'\n'
 # Stash away comments
-C=( $(grep -E '^#' <<< "${A[*]}") )
-A=( $(grep -v -E '^#' <<< "${A[*]}") )
+C=( $(grep -E '^#' <<< "${A[*]}" || :) )
+A=( $(grep -v -E '^#' <<< "${A[*]}" || :) )
 # Sort entries
 A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") )
 A=( $(uniq <<< "${A[*]}") )