Merge "Support WAC decoding in UMTS format"
diff --git a/Android.bp b/Android.bp
index 0fb90ce..1d5e858 100644
--- a/Android.bp
+++ b/Android.bp
@@ -26,65 +26,164 @@
 // READ ME: ########################################################
 
 filegroup {
-    name: "framework-defaults-java-srcs",
+    name: "framework-core-sources",
     srcs: [
-        // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
         "core/java/**/*.java",
-        "graphics/java/**/*.java",
-        "location/java/**/*.java",
-        "lowpan/java/**/*.java",
-        "media/java/**/*.java",
-        "media/mca/effect/java/**/*.java",
-        "media/mca/filterfw/java/**/*.java",
-        "media/mca/filterpacks/java/**/*.java",
-        "drm/java/**/*.java",
-        "opengl/java/**/*.java",
-        "sax/java/**/*.java",
-        "telecomm/java/**/*.java",
-        "telephony/java/**/*.java",
-        "wifi/java/**/*.java",
-        "keystore/java/**/*.java",
-        "rs/java/**/*.java",
+        "core/java/**/*.aidl",
     ],
+    path: "core/java",
 }
 
-// TODO(b/70046217): make these as filegroups where the base directory for aidl files
-// is given as 'path'. Eliminate the need for aidl_local_include_dirs.
+filegroup {
+    name: "framework-drm-sources",
+    srcs: [
+        "drm/java/**/*.java",
+    ],
+    path: "drm/java",
+}
+
+filegroup {
+    name: "framework-graphics-sources",
+    srcs: [
+        "graphics/java/**/*.java",
+        "graphics/java/**/*.aidl",
+    ],
+    path: "graphics/java",
+}
+
+filegroup {
+    name: "framework-keystore-sources",
+    srcs: [
+        "keystore/java/**/*.java",
+        "keystore/java/**/*.aidl",
+    ],
+    path: "keystore/java",
+}
+
+filegroup {
+    name: "framework-location-sources",
+    srcs: [
+        "location/java/**/*.java",
+        "location/java/**/*.aidl",
+    ],
+    path: "location/java",
+}
+
+filegroup {
+    name: "framework-lowpan-sources",
+    srcs: [
+        "lowpan/java/**/*.java",
+        "lowpan/java/**/*.aidl",
+    ],
+    path: "lowpan/java",
+}
+
+filegroup {
+    name: "framework-media-sources",
+    srcs: [
+        "media/java/**/*.java",
+        "media/java/**/*.aidl",
+    ],
+    path: "media/java",
+}
+
+filegroup {
+    name: "framework-mca-effect-sources",
+    srcs: [
+        "media/mca/effect/java/**/*.java",
+    ],
+    path: "media/mca/effect/java",
+}
+
+filegroup {
+    name: "framework-mca-filterfw-sources",
+    srcs: [
+        "media/mca/filterfw/java/**/*.java",
+    ],
+    path: "media/mca/filterfw/java",
+}
+
+filegroup {
+    name: "framework-mca-filterpacks-sources",
+    srcs: [
+        "media/mca/filterpacks/java/**/*.java",
+    ],
+    path: "media/mca/filterpacks/java",
+}
+
+filegroup {
+    name: "framework-opengl-sources",
+    srcs: [
+        "opengl/java/**/*.java",
+    ],
+    path: "opengl/java",
+}
+
+filegroup {
+    name: "framework-rs-sources",
+    srcs: [
+        "rs/java/**/*.java",
+    ],
+    path: "rs/java",
+}
+
+filegroup {
+    name: "framework-sax-sources",
+    srcs: [
+        "sax/java/**/*.java",
+    ],
+    path: "sax/java",
+}
+
+filegroup {
+    name: "framework-telecomm-sources",
+    srcs: [
+        "telecomm/java/**/*.java",
+        "telecomm/java/**/*.aidl",
+    ],
+    path: "telecomm/java",
+}
+
+filegroup {
+    name: "framework-telephony-sources",
+    srcs: [
+        "telephony/java/**/*.java",
+        "telephony/java/**/*.aidl",
+    ],
+    path: "telephony/java",
+}
+
+filegroup {
+    name: "framework-wifi-sources",
+    srcs: [
+        "wifi/java/**/*.java",
+        "wifi/java/**/*.aidl",
+    ],
+    path: "wifi/java",
+}
+
 framework_srcs = [
-    // java sources under this directory
-    "core/java/**/*.java",
-    "drm/java/**/*.java",
-    "graphics/java/**/*.java",
-    "keystore/java/**/*.java",
-    "location/java/**/*.java",
-    "lowpan/java/**/*.java",
-    "media/java/**/*.java",
-    "media/mca/effect/java/**/*.java",
-    "media/mca/filterfw/java/**/*.java",
-    "media/mca/filterpacks/java/**/*.java",
-    "opengl/java/**/*.java",
-    "rs/java/**/*.java",
-    "sax/java/**/*.java",
-    "telecomm/java/**/*.java",
-    "telephony/java/**/*.java",
-    "wifi/java/**/*.java",
+    // Java/AIDL sources under frameworks/base
+    ":framework-core-sources",
+    ":framework-drm-sources",
+    ":framework-graphics-sources",
+    ":framework-keystore-sources",
+    ":framework-location-sources",
+    ":framework-lowpan-sources",
+    ":framework-media-sources",
+    ":framework-mca-effect-sources",
+    ":framework-mca-filterfw-sources",
+    ":framework-mca-filterpacks-sources",
+    ":framework-opengl-sources",
+    ":framework-rs-sources",
+    ":framework-sax-sources",
+    ":framework-telecomm-sources",
+    ":framework-telephony-sources",
+    ":framework-wifi-sources",
+    ":PacProcessor-aidl-sources",
+    ":ProxyHandler-aidl-sources",
 
-    // aidl under this directory
-    // b/70046217#comment15 These MUST come after all java srcs.
-    // TODO(b/70046217) remove the above requirement
-    "core/java/**/*.aidl",
-    "graphics/java/**/*.aidl",
-    "keystore/java/**/*.aidl",
-    "location/java/**/*.aidl",
-    "lowpan/java/**/*.aidl",
-    "media/java/**/*.aidl",
-    "packages/services/PacProcessor/**/*.aidl",
-    "packages/services/Proxy/**/*.aidl",
-    "telecomm/java/**/*.aidl",
-    "telephony/java/**/*.aidl",
-    "wifi/java/**/*.aidl",
-
-    // aidl from external directories
+    // AIDL sources from external directories
     ":dumpstate_aidl",
     ":gatekeeper_aidl",
     ":gsiservice_aidl",
@@ -104,49 +203,29 @@
     "core/java/**/*.logtags",
     ":framework-javastream-protos",
     ":framework-statslog-gen",
-    ":platform-properties",
-]
-
-framework_aidl_local_include_dirs = [
-    "core/java",
-    "drm/java",
-    "graphics/java",
-    "keystore/java",
-    "location/java",
-    "lowpan/java",
-    "media/java",
-    "media/mca/effect/java",
-    "media/mca/filterfw/java",
-    "media/mca/filterpacks/java",
-    "opengl/java",
-    "rs/java",
-    "sax/java",
-    "telecomm/java",
-    "telephony/java",
-    "wifi/java",
-]
-
-framework_aidl_external_include_dirs = [
-    "frameworks/av/camera/aidl",
-    "frameworks/av/media/libaudioclient/aidl",
-    "frameworks/native/aidl/binder",
-    "frameworks/native/aidl/gui",
-    "frameworks/native/cmds/dumpstate/binder",
-    "frameworks/native/libs/incidentcompanion/binder",
-    "system/bt/binder",
-    "system/core/gatekeeperd/binder",
-    "system/core/storaged/binder",
-    "system/gsid/aidl",
-    "system/security/keystore/binder",
-    "system/update_engine/binder_bindings",
-    "system/vold/binder",
 ]
 
 java_defaults {
     name: "framework-aidl-export-defaults",
-
     aidl: {
-        export_include_dirs: framework_aidl_local_include_dirs,
+        export_include_dirs: [
+            "core/java",
+            "drm/java",
+            "graphics/java",
+            "keystore/java",
+            "location/java",
+            "lowpan/java",
+            "media/java",
+            "media/mca/effect/java",
+            "media/mca/filterfw/java",
+            "media/mca/filterpacks/java",
+            "opengl/java",
+            "rs/java",
+            "sax/java",
+            "telecomm/java",
+            "telephony/java",
+            "wifi/java",
+        ],
     },
 }
 
@@ -158,8 +237,12 @@
     srcs: framework_srcs,
 
     aidl: {
-        local_include_dirs: framework_aidl_local_include_dirs,
-        include_dirs: framework_aidl_external_include_dirs,
+        // TODO(b/70046217) remove this by moving the AIDL files into frameworks/base
+        // so that they are referenced via framework-core-sources
+        include_dirs: [
+            "frameworks/native/aidl/binder",
+            "frameworks/native/aidl/gui",
+        ],
         generate_get_transaction_name: true,
     },
 
@@ -199,6 +282,8 @@
         "android.hardware.vibrator-V1.1-java",
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.wifi-V1.0-java-constants",
+
+        "PlatformProperties",
     ],
 
     required: [
@@ -717,7 +802,6 @@
         "test-runner/src/**/*.java",
     ],
     srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: frameworks_base_subdirs,
     srcs_lib_whitelist_pkgs: packages_to_document,
     libs: framework_docs_only_libs,
     local_sourcepaths: frameworks_base_subdirs,
@@ -773,7 +857,6 @@
         ":core_public_api_files",
     ],
     srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: frameworks_base_subdirs,
     srcs_lib_whitelist_pkgs: packages_to_document,
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
@@ -1095,7 +1178,6 @@
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
     srcs: [
-        ":framework-defaults-java-srcs",
         ":non_openjdk_java_files",
         ":openjdk_java_files",
         ":opt-telephony-common-srcs",
@@ -1215,8 +1297,6 @@
 aidl_mapping {
     name: "framework-aidl-mappings",
     srcs: framework_srcs,
-    local_include_dirs: framework_aidl_local_include_dirs,
-    include_dirs: framework_aidl_external_include_dirs,
     output: "framework-aidl-mappings.txt",
 }
 
diff --git a/core/java/android/content/pm/PackageList.java b/core/java/android/content/pm/PackageList.java
index f781758..e3eb2c5 100644
--- a/core/java/android/content/pm/PackageList.java
+++ b/core/java/android/content/pm/PackageList.java
@@ -52,6 +52,13 @@
     }
 
     @Override
+    public void onPackageChanged(String packageName, int uid) {
+        if (mWrappedObserver != null) {
+            mWrappedObserver.onPackageChanged(packageName, uid);
+        }
+    }
+
+    @Override
     public void onPackageRemoved(String packageName, int uid) {
         if (mWrappedObserver != null) {
             mWrappedObserver.onPackageRemoved(packageName, uid);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index c299369..0694c5f 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -63,6 +63,8 @@
     public interface PackageListObserver {
         /** A package was added to the system. */
         void onPackageAdded(@NonNull String packageName, int uid);
+        /** A package was changed - either installed for a specific user or updated. */
+        default void onPackageChanged(@NonNull String packageName, int uid) {}
         /** A package was removed from the system. */
         void onPackageRemoved(@NonNull String packageName, int uid);
     }
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index ab0a0ef..a839ec1 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -114,7 +114,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public ApduServiceInfo(ResolveInfo info, String description,
+    public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
             ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost) {
@@ -124,7 +124,7 @@
         this.mDynamicAidGroups = new HashMap<String, AidGroup>();
         this.mOffHostName = offHost;
         this.mStaticOffHostName = staticOffHost;
-        this.mOnHost = (offHost == null);
+        this.mOnHost = onHost;
         this.mRequiresDeviceUnlock = requiresUnlock;
         for (AidGroup aidGroup : staticAidGroups) {
             this.mStaticAidGroups.put(aidGroup.category, aidGroup);
@@ -570,7 +570,7 @@
             int bannerResource = source.readInt();
             int uid = source.readInt();
             String settingsActivityName = source.readString();
-            return new ApduServiceInfo(info, description, staticAidGroups,
+            return new ApduServiceInfo(info, onHost, description, staticAidGroups,
                     dynamicAidGroups, requiresUnlock, bannerResource, uid,
                     settingsActivityName, offHostName, staticOffHostName);
         }
diff --git a/core/java/com/android/internal/util/TrafficStatsConstants.java b/core/java/com/android/internal/util/TrafficStatsConstants.java
index 2806ae2..413be48 100644
--- a/core/java/com/android/internal/util/TrafficStatsConstants.java
+++ b/core/java/com/android/internal/util/TrafficStatsConstants.java
@@ -40,4 +40,5 @@
     // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and
     // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}.
     public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81;
+    public static final int TAG_SYSTEM_DNS = 0xFFFFFF82;
 }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 72462ad4..111f937 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3350,8 +3350,10 @@
     <!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
     <bool name="config_allow3rdPartyAppOnInternal">true</bool>
 
-    <!-- Package name of the default cell broadcast receiver -->
-    <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
+    <!-- Package names of the default cell broadcast receivers -->
+    <string-array name="config_defaultCellBroadcastReceiverPkgs" translatable="false">
+        <item>com.android.cellbroadcastreceiver</item>
+    </string-array>
 
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
     <string name="config_icon_mask" translatable="false">"M50,0L92,0C96.42,0 100,4.58 100 8L100,92C100, 96.42 96.42 100 92 100L8 100C4.58, 100 0 96.42 0 92L0 8 C 0 4.42 4.42 0 8 0L50 0Z"</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9f8baf8..00808df 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3036,7 +3036,7 @@
   <java-symbol type="drawable" name="lockscreen_selected" />
 
   <java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
-  <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
+  <java-symbol type="array" name="config_defaultCellBroadcastReceiverPkgs" />
 
   <java-symbol type="color" name="notification_primary_text_color_light" />
   <java-symbol type="color" name="notification_primary_text_color_dark" />
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index 59963de..1bf5221 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -21,6 +21,5 @@
     srcs_lib: "framework",
     // TODO(b/70046217): remove core/java and android below. It was added to provide definitions for
     // types like android.os.Bundle
-    srcs_lib_whitelist_dirs: ["core/java", "location/java"],
     srcs_lib_whitelist_pkgs: ["android", "com.android.internal.location"],
 }
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 44f8725..f04b2fc 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -19,6 +19,5 @@
     srcs: ["java/**/*.java"],
     api_packages: ["com.android.mediadrm.signer"],
     srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: ["media/java"],
     srcs_lib_whitelist_pkgs: ["android.media"],
 }
diff --git a/packages/services/PacProcessor/Android.bp b/packages/services/PacProcessor/Android.bp
index 93b2d95..494a818 100644
--- a/packages/services/PacProcessor/Android.bp
+++ b/packages/services/PacProcessor/Android.bp
@@ -21,3 +21,9 @@
     certificate: "platform",
     jni_libs: ["libjni_pacprocessor"],
 }
+
+filegroup {
+    name: "PacProcessor-aidl-sources",
+    srcs: ["src/**/*.aidl"],
+    path: "src",
+}
diff --git a/packages/services/PacProcessor/com/android/net/IProxyService.aidl b/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
similarity index 100%
rename from packages/services/PacProcessor/com/android/net/IProxyService.aidl
rename to packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
diff --git a/packages/services/Proxy/Android.bp b/packages/services/Proxy/Android.bp
index 87aa763..d93c9f8 100644
--- a/packages/services/Proxy/Android.bp
+++ b/packages/services/Proxy/Android.bp
@@ -5,3 +5,9 @@
     certificate: "platform",
     privileged: true,
 }
+
+filegroup {
+    name: "ProxyHandler-aidl-sources",
+    srcs: ["src/**/*.aidl"],
+    path: "src",
+}
diff --git a/packages/services/Proxy/com/android/net/IProxyCallback.aidl b/packages/services/Proxy/src/com/android/net/IProxyCallback.aidl
similarity index 100%
rename from packages/services/Proxy/com/android/net/IProxyCallback.aidl
rename to packages/services/Proxy/src/com/android/net/IProxyCallback.aidl
diff --git a/packages/services/Proxy/com/android/net/IProxyPortListener.aidl b/packages/services/Proxy/src/com/android/net/IProxyPortListener.aidl
similarity index 100%
rename from packages/services/Proxy/com/android/net/IProxyPortListener.aidl
rename to packages/services/Proxy/src/com/android/net/IProxyPortListener.aidl
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index fbe2589..29c4bad 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -130,6 +130,11 @@
         }
 
         @Override
+        public void onPackageChanged(@NonNull String packageName, int uid) {
+            sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+        }
+
+        @Override
         public void onPackageRemoved(String packageName, int uid) {
             sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
         }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e7a8b13..1bd29e5 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -58,7 +58,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkMisc;
-import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.VpnService;
@@ -114,7 +113,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -902,38 +900,6 @@
     }
 
     /**
-     * Analyzes the passed LinkedProperties to figure out whether it routes to most of the IP space.
-     *
-     * This returns true if the passed LinkedProperties contains routes to either most of the IPv4
-     * space or to most of the IPv6 address space, where "most" is defined by the value of the
-     * MOST_IPV{4,6}_ADDRESSES_COUNT constants : if more than this number of addresses are matched
-     * by any of the routes, then it's decided that most of the space is routed.
-     * @hide
-     */
-    @VisibleForTesting
-    static boolean providesRoutesToMostDestinations(LinkProperties lp) {
-        final List<RouteInfo> routes = lp.getAllRoutes();
-        if (routes.size() > MAX_ROUTES_TO_EVALUATE) return true;
-        final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
-        TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
-        TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
-        for (final RouteInfo route : routes) {
-            if (route.getType() == RouteInfo.RTN_UNREACHABLE) continue;
-            IpPrefix destination = route.getDestination();
-            if (destination.isIPv4()) {
-                ipv4Prefixes.add(destination);
-            } else {
-                ipv6Prefixes.add(destination);
-            }
-        }
-        if (NetworkUtils.routedIPv4AddressCount(ipv4Prefixes) > MOST_IPV4_ADDRESSES_COUNT) {
-            return true;
-        }
-        return NetworkUtils.routedIPv6AddressCount(ipv6Prefixes)
-                .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
-    }
-
-    /**
      * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without
      * registering a new NetworkAgent. This is not always possible if the new VPN configuration
      * has certain changes, in which case this method would just return {@code false}.
@@ -1079,7 +1045,8 @@
             // TEMP use the old jni calls until there is support for netd address setting
             StringBuilder builder = new StringBuilder();
             for (LinkAddress address : config.addresses) {
-                builder.append(" " + address);
+                builder.append(" ");
+                builder.append(address);
             }
             if (jniSetAddresses(interfaze, builder.toString()) < 1) {
                 throw new IllegalArgumentException("At least one address must be specified");
@@ -1163,7 +1130,7 @@
 
     // Note: Return type guarantees results are deduped and sorted, which callers require.
     private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) {
-        SortedSet<Integer> uids = new TreeSet<Integer>();
+        SortedSet<Integer> uids = new TreeSet<>();
         for (String app : packageNames) {
             int uid = getAppUid(app, userHandle);
             if (uid != -1) uids.add(uid);
@@ -1266,7 +1233,7 @@
         // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
         // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
         final UidRange userRange = UidRange.createForUser(userHandle);
-        final List<UidRange> ranges = new ArrayList<UidRange>();
+        final List<UidRange> ranges = new ArrayList<>();
         for (UidRange range : existingRanges) {
             if (userRange.containsRange(range)) {
                 ranges.add(range);
@@ -1765,7 +1732,7 @@
             byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
             serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
         }
-        if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
+        if (userCert == null || caCert == null || serverCert == null) {
             throw new IllegalStateException("Cannot load credentials");
         }
 
@@ -1884,7 +1851,7 @@
      * Return the information of the current ongoing legacy VPN.
      * Callers are responsible for checking permissions if needed.
      */
-    public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
+    private synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
         if (mLegacyVpnRunner == null) return null;
 
         final LegacyVpnInfo info = new LegacyVpnInfo();
@@ -2038,7 +2005,6 @@
 
         private void bringup() {
             // Catch all exceptions so we can clean up a few things.
-            boolean initFinished = false;
             try {
                 // Initialize the timer.
                 mBringupStartTime = SystemClock.elapsedRealtime();
@@ -2057,7 +2023,6 @@
                     throw new IllegalStateException("Cannot delete the state");
                 }
                 new File("/data/misc/vpn/abort").delete();
-                initFinished = true;
 
                 // Check if we need to restart any of the daemons.
                 boolean restart = false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 88a1ef3..5b83f44 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2155,6 +2155,8 @@
 
             if (allNewUsers && !update) {
                 notifyPackageAdded(packageName, res.uid);
+            } else {
+                notifyPackageChanged(packageName, res.uid);
             }
 
             // Log current value of "unknown sources" setting
@@ -13762,6 +13764,22 @@
     }
 
     @Override
+    public void notifyPackageChanged(String packageName, int uid) {
+        final PackageListObserver[] observers;
+        synchronized (mPackages) {
+            if (mPackageListObservers.size() == 0) {
+                return;
+            }
+            final PackageListObserver[] observerArray =
+                    new PackageListObserver[mPackageListObservers.size()];
+            observers = mPackageListObservers.toArray(observerArray);
+        }
+        for (int i = observers.length - 1; i >= 0; --i) {
+            observers[i].onPackageChanged(packageName, uid);
+        }
+    }
+
+    @Override
     public void notifyPackageRemoved(String packageName, int uid) {
         final PackageListObserver[] observers;
         synchronized (mPackages) {
@@ -24987,5 +25005,6 @@
     void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
         boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
     void notifyPackageAdded(String packageName, int uid);
+    void notifyPackageChanged(String packageName, int uid);
     void notifyPackageRemoved(String packageName, int uid);
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bbe7456..1ce72c5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -37,6 +37,7 @@
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
 import android.database.sqlite.SQLiteGlobal;
 import android.hardware.display.DisplayManagerInternal;
+import android.net.ConnectivityModuleConnector;
 import android.net.NetworkStackClient;
 import android.os.BaseBundle;
 import android.os.Binder;
@@ -1132,6 +1133,14 @@
             mSystemServiceManager.startService(ClipboardService.class);
             traceEnd();
 
+            traceBeginAndSlog("InitConnectivityModuleConnector");
+            try {
+                ConnectivityModuleConnector.getInstance().init(context);
+            } catch (Throwable e) {
+                reportWtf("initializing ConnectivityModuleConnector", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("InitNetworkStackClient");
             try {
                 NetworkStackClient.getInstance().init();
@@ -1940,7 +1949,7 @@
                 // ActivityManagerService.mSystemReady and ActivityManagerService.mProcessesReady
                 // are set to true. Be careful if moving this to a different place in the
                 // startup sequence.
-                NetworkStackClient.getInstance().start(context);
+                NetworkStackClient.getInstance().start();
             } catch (Throwable e) {
                 reportWtf("starting Network Stack", e);
             }
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
new file mode 100644
index 0000000..e84dac2
--- /dev/null
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.net.util.SharedLog;
+import android.os.Build;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.PrintWriter;
+
+/**
+ * Class used to communicate to the various networking mainline modules running in the network stack
+ * process from {@link com.android.server.SystemServer}.
+ * @hide
+ */
+public class ConnectivityModuleConnector {
+    private static final String TAG = ConnectivityModuleConnector.class.getSimpleName();
+    private static final String IN_PROCESS_SUFFIX = ".InProcess";
+
+    private static final String PREFS_FILE = "ConnectivityModuleConnector.xml";
+    private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time";
+    private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval";
+    private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash";
+    private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH =
+            "always_ratelimit_networkstack_crash";
+
+    // Even if the network stack is lost, do not crash the system more often than this.
+    // Connectivity would be broken, but if the user needs the device for something urgent
+    // (like calling emergency services) we should not bootloop the device.
+    // This is the default value: the actual value can be adjusted via device config.
+    private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS;
+
+    // Even if the network stack is lost, do not crash the system server if it was less than
+    // this much after boot. This avoids bootlooping the device, and crashes should address very
+    // infrequent failures, not failures on boot.
+    private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+
+    private static ConnectivityModuleConnector sInstance;
+
+    private Context mContext;
+    @GuardedBy("mLog")
+    private final SharedLog mLog = new SharedLog(TAG);
+    @GuardedBy("mHealthListeners")
+    private final ArraySet<ConnectivityModuleHealthListener> mHealthListeners = new ArraySet<>();
+
+    private ConnectivityModuleConnector() { }
+
+    /**
+     * Get the {@link ConnectivityModuleConnector} singleton instance.
+     */
+    public static synchronized ConnectivityModuleConnector getInstance() {
+        if (sInstance == null) {
+            sInstance = new ConnectivityModuleConnector();
+        }
+        return sInstance;
+    }
+
+    /**
+     * Initialize the network stack connector. Should be called only once on device startup, before
+     * any client attempts to use the network stack.
+     */
+    public void init(Context context) {
+        log("Network stack init");
+        mContext = context;
+    }
+
+    /**
+     * Callback interface for severe failures of the NetworkStack.
+     *
+     * <p>Useful for health monitors such as PackageWatchdog.
+     */
+    public interface ConnectivityModuleHealthListener {
+        /**
+         * Called when there is a severe failure of the network stack.
+         * @param packageName Package name of the network stack.
+         */
+        void onNetworkStackFailure(@NonNull String packageName);
+    }
+
+    /**
+     * Callback invoked by the connector once the connection to the corresponding module is
+     * established.
+     */
+    public interface ModuleServiceCallback {
+        /**
+         * Invoked when the corresponding service has connected.
+         *
+         * @param iBinder Binder object for the service.
+         */
+        void onModuleServiceConnected(@NonNull IBinder iBinder);
+    }
+
+
+    /**
+     * Add a {@link ConnectivityModuleHealthListener} to listen to network stack health events.
+     */
+    public void registerHealthListener(@NonNull ConnectivityModuleHealthListener listener) {
+        synchronized (mHealthListeners) {
+            mHealthListeners.add(listener);
+        }
+    }
+
+    /**
+     * Start a module running in the network stack or system_server process. Should be called only
+     * once for each module per device startup.
+     *
+     * <p>This method will start a networking module either in the network stack
+     * process, or inside the system server on devices that do not support the corresponding
+     * mainline network . The corresponding networking module service's binder
+     * object will then be delivered asynchronously via the provided {@link ModuleServiceCallback}.
+     *
+     * @param serviceIntentBaseAction Base action to use for constructing the intent needed to
+     *                                bind to the corresponding module.
+     * @param servicePermissionName Permission to be held by the corresponding module.
+     */
+    public void startModuleService(
+            @NonNull String serviceIntentBaseAction,
+            @NonNull String servicePermissionName,
+            @NonNull ModuleServiceCallback callback) {
+        log("Starting networking module " + serviceIntentBaseAction);
+
+        final PackageManager pm = mContext.getPackageManager();
+
+        // Try to bind in-process if the device was shipped with an in-process version
+        Intent intent = getModuleServiceIntent(pm, serviceIntentBaseAction, servicePermissionName,
+                true /* inSystemProcess */);
+
+        // Otherwise use the updatable module version
+        if (intent == null) {
+            intent = getModuleServiceIntent(pm, serviceIntentBaseAction, servicePermissionName,
+                false /* inSystemProcess */);
+            log("Starting networking module in network_stack process");
+        } else {
+            log("Starting networking module in system_server process");
+        }
+
+        if (intent == null) {
+            maybeCrashWithTerribleFailure("Could not resolve the networking module", null);
+            return;
+        }
+
+        final String packageName = intent.getComponent().getPackageName();
+
+        // Start the network stack. The service will be added to the service manager by the
+        // corresponding client in ModuleServiceCallback.onModuleServiceConnected().
+        if (!mContext.bindServiceAsUser(
+                intent, new ModuleServiceConnection(packageName, callback),
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+            maybeCrashWithTerribleFailure(
+                    "Could not bind to networking module in-process, or in app with "
+                            + intent, packageName);
+            return;
+        }
+
+        log("Networking module service start requested");
+    }
+
+    private class ModuleServiceConnection implements ServiceConnection {
+        @NonNull
+        private final String mPackageName;
+        @NonNull
+        private final ModuleServiceCallback mModuleServiceCallback;
+
+        private ModuleServiceConnection(
+                @NonNull String packageName,
+                @NonNull ModuleServiceCallback moduleCallback) {
+            mPackageName = packageName;
+            mModuleServiceCallback = moduleCallback;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            logi("Networking module service connected");
+            mModuleServiceCallback.onModuleServiceConnected(service);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // onServiceDisconnected is not being called on device shutdown, so this method being
+            // called always indicates a bad state for the system server.
+            // This code path is only run by the system server: only the system server binds
+            // to the NetworkStack as a service. Other processes get the NetworkStack from
+            // the ServiceManager.
+            maybeCrashWithTerribleFailure("Lost network stack", mPackageName);
+        }
+    }
+
+    @Nullable
+    private Intent getModuleServiceIntent(
+            @NonNull PackageManager pm, @NonNull String serviceIntentBaseAction,
+            @NonNull String servicePermissionName, boolean inSystemProcess) {
+        final Intent intent =
+                new Intent(inSystemProcess
+                        ? serviceIntentBaseAction + IN_PROCESS_SUFFIX
+                        : serviceIntentBaseAction);
+        final ComponentName comp = intent.resolveSystemService(pm, 0);
+        if (comp == null) {
+            return null;
+        }
+        intent.setComponent(comp);
+
+        int uid = -1;
+        try {
+            uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
+        } catch (PackageManager.NameNotFoundException e) {
+            logWtf("Networking module package not found", e);
+            // Fall through
+        }
+
+        final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
+        if (uid != expectedUid) {
+            throw new SecurityException("Invalid network stack UID: " + uid);
+        }
+
+        if (!inSystemProcess) {
+            checkModuleServicePermission(pm, comp, servicePermissionName);
+        }
+
+        return intent;
+    }
+
+    private void checkModuleServicePermission(
+            @NonNull PackageManager pm, @NonNull ComponentName comp,
+            @NonNull String servicePermissionName) {
+        final int hasPermission =
+                pm.checkPermission(servicePermissionName, comp.getPackageName());
+        if (hasPermission != PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "Networking module does not have permission " + servicePermissionName);
+        }
+    }
+
+    private synchronized void maybeCrashWithTerribleFailure(@NonNull String message,
+            @Nullable String packageName) {
+        logWtf(message, null);
+        // Called DeviceConfig to minimize merge conflicts
+        final DeviceConfigStub DeviceConfig = new DeviceConfigStub(mContext);
+        // uptime is monotonic even after a framework restart
+        final long uptime = SystemClock.elapsedRealtime();
+        final long now = System.currentTimeMillis();
+        final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
+                CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS);
+        final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
+                CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS);
+        final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY,
+                CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false);
+
+        final SharedPreferences prefs = getSharedPreferences();
+        final long lastCrashTime = tryGetLastCrashTime(prefs);
+
+        // Only crash if there was enough time since boot, and (if known) enough time passed since
+        // the last crash.
+        // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they
+        // are only used to limit the number of crashes compared to only using the time since boot,
+        // which would also be OK behavior by itself.
+        // - If lastCrashTime is incorrectly more than the current time, only look at uptime
+        // - If it is much less than current time, only look at uptime
+        // - If current time is during the next few hours after last crash time, don't crash.
+        //   Considering that this only matters if last boot was some time ago, it's likely that
+        //   time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being
+        //   in this last state would also not last for long since the window is only a few hours.
+        final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit;
+        final boolean justBooted = uptime < minUptimeBeforeCrash;
+        final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now);
+        final boolean haveKnownRecentCrash =
+                haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs);
+        if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) {
+            // The system is not bound to its network stack (for example due to a crash in the
+            // network stack process): better crash rather than stay in a bad state where all
+            // networking is broken.
+            // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous
+            // API to persist settings before a crash.
+            tryWriteLastCrashTime(prefs, now);
+            throw new IllegalStateException(message);
+        }
+
+        // Here the system crashed recently already. Inform listeners that something is
+        // definitely wrong.
+        if (packageName != null) {
+            final ArraySet<ConnectivityModuleHealthListener> listeners;
+            synchronized (mHealthListeners) {
+                listeners = new ArraySet<>(mHealthListeners);
+            }
+            for (ConnectivityModuleHealthListener listener : listeners) {
+                listener.onNetworkStackFailure(packageName);
+            }
+        }
+    }
+
+    @Nullable
+    private SharedPreferences getSharedPreferences() {
+        try {
+            final File prefsFile = new File(
+                    Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE);
+            return mContext.createDeviceProtectedStorageContext()
+                    .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+        } catch (Throwable e) {
+            logWtf("Error loading shared preferences", e);
+            return null;
+        }
+    }
+
+    private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) {
+        if (prefs == null) return 0L;
+        try {
+            return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L);
+        } catch (Throwable e) {
+            logWtf("Error getting last crash time", e);
+            return 0L;
+        }
+    }
+
+    private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) {
+        if (prefs == null) return;
+        try {
+            prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit();
+        } catch (Throwable e) {
+            logWtf("Error writing last crash time", e);
+        }
+    }
+
+    private void log(@NonNull String message) {
+        Slog.d(TAG, message);
+        synchronized (mLog) {
+            mLog.log(message);
+        }
+    }
+
+    private void logWtf(@NonNull String message, @Nullable Throwable e) {
+        Slog.wtf(TAG, message, e);
+        synchronized (mLog) {
+            mLog.e(message);
+        }
+    }
+
+    private void loge(@NonNull String message, @Nullable Throwable e) {
+        Slog.e(TAG, message, e);
+        synchronized (mLog) {
+            mLog.e(message);
+        }
+    }
+
+    private void logi(@NonNull String message) {
+        Slog.i(TAG, message);
+        synchronized (mLog) {
+            mLog.i(message);
+        }
+    }
+
+    /**
+     * Dump ConnectivityModuleConnector logs to the specified {@link PrintWriter}.
+     */
+    public void dump(PrintWriter pw) {
+        // dump is thread-safe on SharedLog
+        mLog.dump(null, pw, null);
+    }
+
+    /**
+     * Stub class to replicate DeviceConfig behavior with minimal merge conflicts.
+     */
+    private class DeviceConfigStub {
+        private final Context mContext;
+
+        // Namespace is actually unused, but is here to replicate the final API.
+        private static final String NAMESPACE_CONNECTIVITY = "connectivity";
+
+        private DeviceConfigStub(Context context) {
+            mContext = context;
+        }
+
+        private long getLong(
+                @NonNull String namespace, @NonNull String key, long defaultVal) {
+            // Temporary solution until DeviceConfig is available
+            try {
+                return Settings.Global.getLong(
+                        mContext.getContentResolver(), TAG + "_" + key, defaultVal);
+            } catch (Throwable e) {
+                logWtf("Could not obtain setting " + key, e);
+                return defaultVal;
+            }
+        }
+
+        private boolean getBoolean(
+                @NonNull String namespace, @NonNull String key, boolean defaultVal) {
+            // Temporary solution until DeviceConfig is available
+            return getLong(namespace, key, defaultVal ? 1 : 0) != 0;
+        }
+    }
+}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 787fda3..5a8e1e6 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -15,40 +15,27 @@
  */
 package android.net;
 
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServerCallbacks;
 import android.net.ip.IIpClientCallbacks;
 import android.net.util.SharedLog;
 import android.os.Binder;
-import android.os.Build;
-import android.os.Environment;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 
-import java.io.File;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -60,24 +47,6 @@
     private static final String TAG = NetworkStackClient.class.getSimpleName();
 
     private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
-    private static final String IN_PROCESS_SUFFIX = ".InProcess";
-    private static final String PREFS_FILE = "NetworkStackClientPrefs.xml";
-    private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time";
-    private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval";
-    private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash";
-    private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH =
-            "always_ratelimit_networkstack_crash";
-
-    // Even if the network stack is lost, do not crash the system more often than this.
-    // Connectivity would be broken, but if the user needs the device for something urgent
-    // (like calling emergency services) we should not bootloop the device.
-    // This is the default value: the actual value can be adjusted via device config.
-    private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS;
-
-    // Even if the network stack is lost, do not crash the system server if it was less than
-    // this much after boot. This avoids bootlooping the device, and crashes should address very
-    // infrequent failures, not failures on boot.
-    private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
 
     private static NetworkStackClient sInstance;
 
@@ -93,26 +62,10 @@
 
     private volatile boolean mWasSystemServerInitialized = false;
 
-    @GuardedBy("mHealthListeners")
-    private final ArraySet<NetworkStackHealthListener> mHealthListeners = new ArraySet<>();
-
     private interface NetworkStackCallback {
         void onNetworkStackConnected(INetworkStackConnector connector);
     }
 
-    /**
-     * Callback interface for severe failures of the NetworkStack.
-     *
-     * <p>Useful for health monitors such as PackageWatchdog.
-     */
-    public interface NetworkStackHealthListener {
-        /**
-         * Called when there is a severe failure of the network stack.
-         * @param packageName Package name of the network stack.
-         */
-        void onNetworkStackFailure(@NonNull String packageName);
-    }
-
     private NetworkStackClient() { }
 
     /**
@@ -126,15 +79,6 @@
     }
 
     /**
-     * Add a {@link NetworkStackHealthListener} to listen to network stack health events.
-     */
-    public void registerHealthListener(@NonNull NetworkStackHealthListener listener) {
-        synchronized (mHealthListeners) {
-            mHealthListeners.add(listener);
-        }
-    }
-
-    /**
      * Create a DHCP server according to the specified parameters.
      *
      * <p>The server will be returned asynchronously through the provided callbacks.
@@ -195,32 +139,13 @@
         });
     }
 
-    private class NetworkStackConnection implements ServiceConnection {
-        @NonNull
-        private final Context mContext;
-        @NonNull
-        private final String mPackageName;
-
-        private NetworkStackConnection(@NonNull Context context, @NonNull String packageName) {
-            mContext = context;
-            mPackageName = packageName;
-        }
-
+    private class NetworkStackConnection implements
+            ConnectivityModuleConnector.ModuleServiceCallback {
         @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
+        public void onModuleServiceConnected(IBinder service) {
             logi("Network stack service connected");
             registerNetworkStackService(service);
         }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            // onServiceDisconnected is not being called on device shutdown, so this method being
-            // called always indicates a bad state for the system server.
-            // This code path is only run by the system server: only the system server binds
-            // to the NetworkStack as a service. Other processes get the NetworkStack from
-            // the ServiceManager.
-            maybeCrashWithTerribleFailure("Lost network stack", mContext, mPackageName);
-        }
     }
 
     private void registerNetworkStackService(@NonNull IBinder service) {
@@ -259,174 +184,14 @@
      * connector will then be delivered asynchronously to clients that requested it before it was
      * started.
      */
-    public void start(Context context) {
-        log("Starting network stack");
-
-        final PackageManager pm = context.getPackageManager();
-
-        // Try to bind in-process if the device was shipped with an in-process version
-        Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */);
-
-        // Otherwise use the updatable module version
-        if (intent == null) {
-            intent = getNetworkStackIntent(pm, false /* inSystemProcess */);
-            log("Starting network stack process");
-        } else {
-            log("Starting network stack in-process");
-        }
-
-        if (intent == null) {
-            maybeCrashWithTerribleFailure("Could not resolve the network stack", context, null);
-            return;
-        }
-
-        final String packageName = intent.getComponent().getPackageName();
-
-        // Start the network stack. The service will be added to the service manager in
-        // NetworkStackConnection.onServiceConnected().
-        if (!context.bindServiceAsUser(intent, new NetworkStackConnection(context, packageName),
-                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
-            maybeCrashWithTerribleFailure(
-                    "Could not bind to network stack in-process, or in app with " + intent,
-                    context, packageName);
-            return;
-        }
-
+    public void start() {
+        ConnectivityModuleConnector.getInstance().startModuleService(
+                INetworkStackConnector.class.getName(), PERMISSION_MAINLINE_NETWORK_STACK,
+                new NetworkStackConnection());
         log("Network stack service start requested");
     }
 
-    @Nullable
-    private Intent getNetworkStackIntent(@NonNull PackageManager pm, boolean inSystemProcess) {
-        final String baseAction = INetworkStackConnector.class.getName();
-        final Intent intent =
-                new Intent(inSystemProcess ? baseAction + IN_PROCESS_SUFFIX : baseAction);
-        final ComponentName comp = intent.resolveSystemService(pm, 0);
-
-        if (comp == null) {
-            return null;
-        }
-        intent.setComponent(comp);
-
-        int uid = -1;
-        try {
-            uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
-        } catch (PackageManager.NameNotFoundException e) {
-            logWtf("Network stack package not found", e);
-            // Fall through
-        }
-
-        final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
-        if (uid != expectedUid) {
-            throw new SecurityException("Invalid network stack UID: " + uid);
-        }
-
-        if (!inSystemProcess) {
-            checkNetworkStackPermission(pm, comp);
-        }
-
-        return intent;
-    }
-
-    private void checkNetworkStackPermission(
-            @NonNull PackageManager pm, @NonNull ComponentName comp) {
-        final int hasPermission =
-                pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
-        if (hasPermission != PERMISSION_GRANTED) {
-            throw new SecurityException(
-                    "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
-        }
-    }
-
-    private void maybeCrashWithTerribleFailure(@NonNull String message,
-            @NonNull Context context, @Nullable String packageName) {
-        logWtf(message, null);
-        // Called DeviceConfig to minimize merge conflicts
-        final DeviceConfigStub DeviceConfig = new DeviceConfigStub(context);
-        // uptime is monotonic even after a framework restart
-        final long uptime = SystemClock.elapsedRealtime();
-        final long now = System.currentTimeMillis();
-        final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
-                CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS);
-        final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
-                CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS);
-        final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY,
-                CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false);
-
-        final SharedPreferences prefs = getSharedPreferences(context);
-        final long lastCrashTime = tryGetLastCrashTime(prefs);
-
-        // Only crash if there was enough time since boot, and (if known) enough time passed since
-        // the last crash.
-        // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they
-        // are only used to limit the number of crashes compared to only using the time since boot,
-        // which would also be OK behavior by itself.
-        // - If lastCrashTime is incorrectly more than the current time, only look at uptime
-        // - If it is much less than current time, only look at uptime
-        // - If current time is during the next few hours after last crash time, don't crash.
-        //   Considering that this only matters if last boot was some time ago, it's likely that
-        //   time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being
-        //   in this last state would also not last for long since the window is only a few hours.
-        final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit;
-        final boolean justBooted = uptime < minUptimeBeforeCrash;
-        final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now);
-        final boolean haveKnownRecentCrash =
-                haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs);
-        if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) {
-            // The system is not bound to its network stack (for example due to a crash in the
-            // network stack process): better crash rather than stay in a bad state where all
-            // networking is broken.
-            // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous
-            // API to persist settings before a crash.
-            tryWriteLastCrashTime(prefs, now);
-            throw new IllegalStateException(message);
-        }
-
-        // Here the system crashed recently already. Inform listeners that something is
-        // definitely wrong.
-        if (packageName != null) {
-            final ArraySet<NetworkStackHealthListener> listeners;
-            synchronized (mHealthListeners) {
-                listeners = new ArraySet<>(mHealthListeners);
-            }
-            for (NetworkStackHealthListener listener : listeners) {
-                listener.onNetworkStackFailure(packageName);
-            }
-        }
-    }
-
-    @Nullable
-    private SharedPreferences getSharedPreferences(@NonNull Context context) {
-        try {
-            final File prefsFile = new File(
-                    Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE);
-            return context.createDeviceProtectedStorageContext()
-                    .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
-        } catch (Throwable e) {
-            logWtf("Error loading shared preferences", e);
-            return null;
-        }
-    }
-
-    private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) {
-        if (prefs == null) return 0L;
-        try {
-            return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L);
-        } catch (Throwable e) {
-            logWtf("Error getting last crash time", e);
-            return 0L;
-        }
-    }
-
-    private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) {
-        if (prefs == null) return;
-        try {
-            prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit();
-        } catch (Throwable e) {
-            logWtf("Error writing last crash time", e);
-        }
-    }
-
-    /**
+   /**
      * Log a message in the local log.
      */
     private void log(@NonNull String message) {
@@ -526,6 +291,8 @@
     public void dump(PrintWriter pw) {
         // dump is thread-safe on SharedLog
         mLog.dump(null, pw, null);
+        // dump connectivity module connector logs.
+        ConnectivityModuleConnector.getInstance().dump(pw);
 
         final int requestsQueueLength;
         synchronized (mPendingNetStackRequests) {
@@ -536,35 +303,4 @@
         pw.println("pendingNetStackRequests length: " + requestsQueueLength);
     }
 
-    /**
-     * Stub class to replicate DeviceConfig behavior with minimal merge conflicts.
-     */
-    private class DeviceConfigStub {
-        private final Context mContext;
-
-        // Namespace is actually unused, but is here to replicate the final API.
-        private static final String NAMESPACE_CONNECTIVITY = "connectivity";
-
-        private DeviceConfigStub(Context context) {
-            mContext = context;
-        }
-
-        private long getLong(
-                @NonNull String namespace, @NonNull String key, long defaultVal) {
-            // Temporary solution until DeviceConfig is available
-            try {
-                return Settings.Global.getLong(
-                        mContext.getContentResolver(), TAG + "_" + key, defaultVal);
-            } catch (Throwable e) {
-                logWtf("Could not obtain setting " + key, e);
-                return defaultVal;
-            }
-        }
-
-        private boolean getBoolean(
-                @NonNull String namespace, @NonNull String key, boolean defaultVal) {
-            // Temporary solution until DeviceConfig is available
-            return getLong(namespace, key, defaultVal ? 1 : 0) != 0;
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 68728af..6a03aed 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -60,6 +60,11 @@
             }
 
             @Override
+            public void notifyPackageChanged(String packageName, int uid) {
+
+            }
+
+            @Override
             public void notifyPackageRemoved(String packageName, int uid) {
             }
         }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index f03a9dc..af3ba5e 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -217,6 +217,9 @@
         }
 
         String scheme = uri.getScheme();
+        if (scheme == null) {
+            return null;
+        }
 
         if (scheme.equals("tel") || scheme.equals("sip")) {
             return uri.getSchemeSpecificPart();
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index a5cd175..fd469a0 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -26,7 +26,6 @@
     ],
 
     srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: ["core/java"],
     srcs_lib_whitelist_pkgs: ["android"],
     compile_dex: true,
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2aed2de0..70e5160 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2563,6 +2563,7 @@
 
         private final CloseGuard mCloseGuard = CloseGuard.get();
         private final WifiConfiguration mConfig;
+        private boolean mClosed = false;
 
         /** @hide */
         @VisibleForTesting
@@ -2578,8 +2579,13 @@
         @Override
         public void close() {
             try {
-                stopLocalOnlyHotspot();
-                mCloseGuard.close();
+                synchronized (mLock) {
+                    if (!mClosed) {
+                        mClosed = true;
+                        stopLocalOnlyHotspot();
+                        mCloseGuard.close();
+                    }
+                }
             } catch (Exception e) {
                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
             }