Merge "Disable hidden API checks on unit tests"
diff --git a/Android.bp b/Android.bp
index 7c5ffcc..f11b6fe 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,8 +97,10 @@
         "core/java/android/app/backup/IRestoreObserver.aidl",
         "core/java/android/app/backup/IRestoreSession.aidl",
         "core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
+        "core/java/android/app/timedetector/ITimeDetectorService.aidl",
         "core/java/android/app/timezone/ICallback.aidl",
         "core/java/android/app/timezone/IRulesManager.aidl",
+        "core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl",
         "core/java/android/app/usage/ICacheQuotaService.aidl",
         "core/java/android/app/usage/IStorageStatsManager.aidl",
         "core/java/android/app/usage/IUsageStatsManager.aidl",
@@ -1037,6 +1039,7 @@
         "core/java/overview.html",
         ":current-support-api",
     ],
+    dex_api_filename: "public-dex.txt",
     private_dex_api_filename: "private-dex.txt",
     removed_dex_api_filename: "removed-dex.txt",
     args: framework_docs_args +
@@ -1070,3 +1073,90 @@
         "core/java/com/android/internal/util/HexDump.java",
     ],
 }
+
+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"
+
+doc_defaults {
+    name: "metalava-framework-docs-default",
+    srcs: [
+        // test mock src files.
+        "test-mock/src/android/test/mock/**/*.java",
+        // test runner excluding mock src files.
+        "test-runner/src/**/*.java",
+        "test-base/src/**/*.java",
+        ":opt-telephony-srcs",
+        ":opt-net-voip-srcs",
+        ":openjdk_javadoc_files",
+        ":non_openjdk_javadoc_files",
+        ":android_icu4j_src_files_for_docs",
+        ":gen-ojluni-jaif-annotated-srcs",
+    ],
+    exclude_srcs: [
+        ":annotated_ojluni_files",
+    ],
+    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",
+    ],
+    local_sourcepaths: frameworks_base_subdirs,
+    installable: false,
+    metalava_enabled: true,
+    metalava_annotations_enabled: true,
+    metalava_previous_api: ":public-api-for-metalava-annotations",
+    metalava_merge_annotations_dir: "tools/metalava/manual",
+}
+
+droiddoc {
+    name: "metalava-api-stubs-docs",
+    defaults: ["metalava-framework-docs-default"],
+    api_tag_name: "METALAVA_PUBLIC",
+    api_filename: "public_api.txt",
+    private_api_filename: "private.txt",
+    removed_api_filename: "removed.txt",
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args,
+}
+
+droiddoc {
+    name: "metalava-system-api-stubs-docs",
+    defaults: ["metalava-framework-docs-default"],
+    api_tag_name: "METALAVA_SYSTEM",
+    api_filename: "system-api.txt",
+    private_api_filename: "system-private.txt",
+    private_dex_api_filename: "system-private-dex.txt",
+    removed_api_filename: "system-removed.txt",
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi",
+}
+
+droiddoc {
+    name: "metalava-test-api-stubs-docs",
+    defaults: ["metalava-framework-docs-default"],
+    api_tag_name: "METALAVA_TEST",
+    api_filename: "test-api.txt",
+    removed_api_filename: "test-removed.txt",
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.TestApi",
+}
diff --git a/Android.mk b/Android.mk
index a6566eb..eddcada 100644
--- a/Android.mk
+++ b/Android.mk
@@ -594,6 +594,7 @@
 LOCAL_SRC_GREYLIST := frameworks/base/config/hiddenapi-light-greylist.txt
 LOCAL_SRC_VENDOR_LIST := frameworks/base/config/hiddenapi-vendor-list.txt
 LOCAL_SRC_FORCE_BLACKLIST := frameworks/base/config/hiddenapi-force-blacklist.txt
+LOCAL_SRC_PUBLIC_API := $(INTERNAL_PLATFORM_DEX_API_FILE)
 LOCAL_SRC_PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
 LOCAL_SRC_REMOVED_API := $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)
 
@@ -601,6 +602,7 @@
 	$(LOCAL_SRC_GREYLIST) \
 	$(LOCAL_SRC_VENDOR_LIST) \
 	$(LOCAL_SRC_FORCE_BLACKLIST) \
+	$(LOCAL_SRC_PUBLIC_API) \
 	$(LOCAL_SRC_PRIVATE_API) \
 	$(LOCAL_SRC_REMOVED_API)
 
@@ -673,7 +675,8 @@
 #   (4) subtract entries shared with LOCAL_LIGHT_GREYLIST
 $(LOCAL_DARK_GREYLIST): $(LOCAL_SRC_ALL) $(LOCAL_LIGHT_GREYLIST)
 	comm -13 <(sort $(LOCAL_LIGHT_GREYLIST) $(LOCAL_SRC_FORCE_BLACKLIST)) \
-	         <(sed 's/\->.*//' $(LOCAL_LIGHT_GREYLIST) | sed 's/\(.*\/\).*/\1/' | sort | uniq | \
+	         <(cat $(LOCAL_SRC_PUBLIC_API) $(LOCAL_LIGHT_GREYLIST) | \
+	               sed 's/\->.*//' | sed 's/\(.*\/\).*/\1/' | sort | uniq | \
 	               while read PKG_NAME; do \
 	                   grep -E "^$${PKG_NAME}[^/;]*;" $(LOCAL_SRC_PRIVATE_API); \
 	               done | sort | uniq) \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index e728897..1f6860b 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -243,6 +243,8 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/os/storage/*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/host/common/obj/JAVA_LIBRARIES/platformprotos_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.mediadrm.signer.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.location.provider.jar)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/api/current.txt b/api/current.txt
index 07dc4d2..1ae46d5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20097,6 +20097,7 @@
     field public static final android.icu.util.MeasureUnit PICOMETER;
     field public static final android.icu.util.MeasureUnit PINT;
     field public static final android.icu.util.MeasureUnit PINT_METRIC;
+    field public static final android.icu.util.MeasureUnit POINT;
     field public static final android.icu.util.MeasureUnit POUND;
     field public static final android.icu.util.MeasureUnit POUND_PER_SQUARE_INCH;
     field public static final android.icu.util.MeasureUnit QUART;
@@ -26057,6 +26058,8 @@
 
   public class NetworkRequest implements android.os.Parcelable {
     method public int describeContents();
+    method public boolean hasCapability(int);
+    method public boolean hasTransport(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
   }
@@ -40173,6 +40176,7 @@
     field public static final java.lang.String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
     field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
+    field public static final java.lang.String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
     field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
@@ -41062,7 +41066,8 @@
     method public int getAuthType();
     method public java.lang.String getEntryName();
     method public int getId();
-    method public java.net.InetAddress getMmsProxyAddress();
+    method public deprecated java.net.InetAddress getMmsProxyAddress();
+    method public java.lang.String getMmsProxyAddressAsString();
     method public int getMmsProxyPort();
     method public android.net.Uri getMmsc();
     method public int getMvnoType();
@@ -41070,7 +41075,8 @@
     method public java.lang.String getOperatorNumeric();
     method public java.lang.String getPassword();
     method public int getProtocol();
-    method public java.net.InetAddress getProxyAddress();
+    method public deprecated java.net.InetAddress getProxyAddress();
+    method public java.lang.String getProxyAddressAsString();
     method public int getProxyPort();
     method public int getRoamingProtocol();
     method public java.lang.String getUser();
@@ -41090,7 +41096,7 @@
     field public static final int PROTOCOL_IPV6 = 1; // 0x1
     field public static final int PROTOCOL_PPP = 3; // 0x3
     field public static final int TYPE_CBS = 128; // 0x80
-    field public static final int TYPE_DEFAULT = 17; // 0x11
+    field public static final int TYPE_DEFAULT = 1; // 0x1
     field public static final int TYPE_DUN = 8; // 0x8
     field public static final int TYPE_EMERGENCY = 512; // 0x200
     field public static final int TYPE_FOTA = 32; // 0x20
@@ -41109,7 +41115,8 @@
     method public android.telephony.data.ApnSetting.Builder setAuthType(int);
     method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
     method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
+    method public deprecated android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
     method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
     method public android.telephony.data.ApnSetting.Builder setMvnoType(int);
@@ -41117,7 +41124,8 @@
     method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setProtocol(int);
-    method public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
+    method public deprecated android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setProxyAddress(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setProxyPort(int);
     method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
     method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String);
@@ -68706,7 +68714,7 @@
     method public java.util.regex.Matcher reset();
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
     method public int start();
-    method public int start(int) throws java.lang.IllegalStateException;
+    method public int start(int);
     method public int start(java.lang.String);
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
@@ -68717,7 +68725,7 @@
   public final class Pattern implements java.io.Serializable {
     method public java.util.function.Predicate<java.lang.String> asPredicate();
     method public static java.util.regex.Pattern compile(java.lang.String);
-    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
+    method public static java.util.regex.Pattern compile(java.lang.String, int);
     method public int flags();
     method public java.util.regex.Matcher matcher(java.lang.CharSequence);
     method public static boolean matches(java.lang.String, java.lang.CharSequence);
diff --git a/api/system-current.txt b/api/system-current.txt
index 184ed44..9a54ac6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -90,6 +90,7 @@
     field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+    field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
     field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
     field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS";
@@ -2611,10 +2612,10 @@
   }
 
   public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
-    method public void addAddress(android.net.LinkAddress) throws java.io.IOException;
+    method public void addAddress(java.net.InetAddress, int) throws java.io.IOException;
     method public void close();
     method public java.lang.String getInterfaceName();
-    method public void removeAddress(android.net.LinkAddress) throws java.io.IOException;
+    method public void removeAddress(java.net.InetAddress, int) throws java.io.IOException;
   }
 
   public final class IpSecTransform implements java.lang.AutoCloseable {
@@ -2636,6 +2637,10 @@
     field public static final int ERROR_INVALID_NETWORK = 1; // 0x1
   }
 
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
+  }
+
   public class NetworkKey implements android.os.Parcelable {
     ctor public NetworkKey(android.net.WifiKey);
     method public int describeContents();
@@ -4724,6 +4729,7 @@
 package android.telephony.ims {
 
   public final class ImsCallForwardInfo implements android.os.Parcelable {
+    ctor public ImsCallForwardInfo(int, int, int, int, java.lang.String, int);
     method public int describeContents();
     method public int getCondition();
     method public java.lang.String getNumber();
@@ -4969,6 +4975,28 @@
     field public static final int CODE_RADIO_SETUP_FAILURE = 1509; // 0x5e5
     field public static final int CODE_RADIO_UPLINK_FAILURE = 1508; // 0x5e4
     field public static final int CODE_REGISTRATION_ERROR = 1000; // 0x3e8
+    field public static final int CODE_REJECT_1X_COLLISION = 1603; // 0x643
+    field public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602; // 0x642
+    field public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605; // 0x645
+    field public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617; // 0x651
+    field public static final int CODE_REJECT_INTERNAL_ERROR = 1612; // 0x64c
+    field public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608; // 0x648
+    field public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607; // 0x647
+    field public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611; // 0x64b
+    field public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616; // 0x650
+    field public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601; // 0x641
+    field public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618; // 0x652
+    field public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; // 0x655
+    field public static final int CODE_REJECT_ONGOING_E911_CALL = 1606; // 0x646
+    field public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620; // 0x654
+    field public static final int CODE_REJECT_ONGOING_HANDOVER = 1614; // 0x64e
+    field public static final int CODE_REJECT_QOS_FAILURE = 1613; // 0x64d
+    field public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604; // 0x644
+    field public static final int CODE_REJECT_UNKNOWN = 1600; // 0x640
+    field public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610; // 0x64a
+    field public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609; // 0x649
+    field public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619; // 0x653
+    field public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615; // 0x64f
     field public static final int CODE_REMOTE_CALL_DECLINE = 1404; // 0x57c
     field public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; // 0x5ea
     field public static final int CODE_SIP_BAD_ADDRESS = 337; // 0x151
@@ -5033,7 +5061,7 @@
   }
 
   public final class ImsSsData implements android.os.Parcelable {
-    ctor public ImsSsData();
+    ctor public ImsSsData(int, int, int, int, int);
     method public int describeContents();
     method public boolean isTypeBarring();
     method public boolean isTypeCf();
@@ -5084,7 +5112,7 @@
   }
 
   public final class ImsSsInfo implements android.os.Parcelable {
-    ctor public ImsSsInfo();
+    ctor public ImsSsInfo(int, java.lang.String);
     method public int describeContents();
     method public java.lang.String getIcbNum();
     method public int getStatus();
@@ -5240,6 +5268,7 @@
     method public android.telephony.ims.stub.ImsUtImplBase getUt();
     method public final void notifyCapabilitiesStatusChanged(android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
     method public final void notifyIncomingCall(android.telephony.ims.stub.ImsCallSessionImplBase, android.os.Bundle);
+    method public final void notifyRejectedCall(android.telephony.ims.ImsCallProfile, android.telephony.ims.ImsReasonInfo);
     method public final void notifyVoiceMessageCountUpdate(int);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
diff --git a/api/test-current.txt b/api/test-current.txt
index 709b37e..24c22df 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -253,6 +253,11 @@
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    method public int[] getCapabilities();
+    method public int[] getTransportTypes();
+  }
+
   public class TrafficStats {
     method public static long getLoopbackRxBytes();
     method public static long getLoopbackRxPackets();
@@ -426,6 +431,14 @@
 
 }
 
+package android.telecom {
+
+  public final class CallAudioState implements android.os.Parcelable {
+    ctor public CallAudioState(boolean, int, int, android.bluetooth.BluetoothDevice, java.util.Collection<android.bluetooth.BluetoothDevice>);
+  }
+
+}
+
 package android.telephony {
 
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
index e36e148..0ad3a02 100755
--- a/config/generate-preloaded-classes.sh
+++ b/config/generate-preloaded-classes.sh
@@ -36,4 +36,4 @@
 extra_classes_files=("$@")
 
 # Disable locale to enable lexicographical sorting
-LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x
+LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x | grep -v "\$NoPreloadHolder"
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index b7d3f57..6e37525 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -189,7 +189,7 @@
      */
     public interface OnFinished {
         /**
-         * Called when a send operation as completed.
+         * Called when a send operation has completed.
          *
          * @param pendingIntent The PendingIntent this operation was sent through.
          * @param intent The original Intent that was sent.
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 4a09214..3d1b73b 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -121,9 +121,10 @@
      */
     public void disable(int what) {
         try {
+            final int userId = Binder.getCallingUserHandle().getIdentifier();
             final IStatusBarService svc = getService();
             if (svc != null) {
-                svc.disable(what, mToken, mContext.getPackageName());
+                svc.disableForUser(what, mToken, mContext.getPackageName(), userId);
             }
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
@@ -138,9 +139,10 @@
      */
     public void disable2(@Disable2Flags int what) {
         try {
+            final int userId = Binder.getCallingUserHandle().getIdentifier();
             final IStatusBarService svc = getService();
             if (svc != null) {
-                svc.disable2(what, mToken, mContext.getPackageName());
+                svc.disable2ForUser(what, mToken, mContext.getPackageName(), userId);
             }
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 97c6681..26ea068 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -22,7 +22,9 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.job.IJobScheduler;
 import android.app.job.JobScheduler;
+import android.app.timedetector.TimeDetector;
 import android.app.timezone.RulesManager;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.app.trust.TrustManager;
 import android.app.usage.IStorageStatsManager;
 import android.app.usage.IUsageStatsManager;
@@ -271,12 +273,12 @@
             }});
 
         registerService(Context.IPSEC_SERVICE, IpSecManager.class,
-                new StaticServiceFetcher<IpSecManager>() {
+                new CachedServiceFetcher<IpSecManager>() {
             @Override
-            public IpSecManager createService() {
+            public IpSecManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                 IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
                 IIpSecService service = IIpSecService.Stub.asInterface(b);
-                return new IpSecManager(service);
+                return new IpSecManager(ctx, service);
             }});
 
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
@@ -905,6 +907,21 @@
             public RulesManager createService(ContextImpl ctx) {
                 return new RulesManager(ctx.getOuterContext());
             }});
+
+        registerService(Context.TIME_DETECTOR_SERVICE, TimeDetector.class,
+                new CachedServiceFetcher<TimeDetector>() {
+                    @Override
+                    public TimeDetector createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        return new TimeDetector();
+                    }});
+        registerService(Context.TIME_ZONE_DETECTOR_SERVICE, TimeZoneDetector.class,
+                new CachedServiceFetcher<TimeZoneDetector>() {
+                    @Override
+                    public TimeZoneDetector createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        return new TimeZoneDetector();
+                    }});
     }
 
     /**
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
new file mode 100644
index 0000000..f624446
--- /dev/null
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.app.timedetector;
+
+import android.app.timedetector.TimeSignal;
+
+/**
+ * System private API to comunicate with time detector service.
+ *
+ * <p>Used by parts of the Android system with signals associated with the device's time to provide
+ * information to the Time Detector Service.
+ *
+ * <p>Use the {@link android.app.timedetector.TimeDetector} class rather than going through
+ * this Binder interface directly. See {@link android.app.timedetector.TimeDetectorService} for
+ * more complete documentation.
+ *
+ *
+ * {@hide}
+ */
+interface ITimeDetectorService {
+  void suggestTime(in TimeSignal timeSignal);
+}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
new file mode 100644
index 0000000..052050d
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -0,0 +1,59 @@
+/*
+ * 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.app.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The interface through which system components can send signals to the TimeDetectorService.
+ * @hide
+ */
+@SystemService(Context.TIME_DETECTOR_SERVICE)
+public final class TimeDetector {
+    private static final String TAG = "timedetector.TimeDetector";
+    private static final boolean DEBUG = false;
+
+    private final ITimeDetectorService mITimeDetectorService;
+
+    public TimeDetector() throws ServiceNotFoundException {
+        mITimeDetectorService = ITimeDetectorService.Stub.asInterface(
+                ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE));
+    }
+
+    /**
+     * Suggests the current time to the detector. The detector may ignore the signal if better
+     * signals are available such as those that come from more reliable sources or were
+     * determined more recently.
+     */
+    public void suggestTime(@NonNull TimeSignal timeSignal) {
+        if (DEBUG) {
+            Log.d(TAG, "suggestTime called: " + timeSignal);
+        }
+        try {
+            mITimeDetectorService.suggestTime(timeSignal);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+}
diff --git a/core/java/android/app/timedetector/TimeSignal.aidl b/core/java/android/app/timedetector/TimeSignal.aidl
new file mode 100644
index 0000000..d2ec357
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeSignal.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+parcelable TimeSignal;
\ No newline at end of file
diff --git a/core/java/android/app/timedetector/TimeSignal.java b/core/java/android/app/timedetector/TimeSignal.java
new file mode 100644
index 0000000..7ba03cc
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeSignal.java
@@ -0,0 +1,110 @@
+/*
+ * 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.app.timedetector;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.Objects;
+
+/**
+ * A time signal from a named source. The value consists of the number of milliseconds elapsed since
+ * 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number was
+ * established. The elapsed realtime clock is considered accurate but volatile, so time signals
+ * must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class TimeSignal implements Parcelable {
+
+    public static final Parcelable.Creator<TimeSignal> CREATOR =
+            new Parcelable.Creator<TimeSignal>() {
+                public TimeSignal createFromParcel(Parcel in) {
+                    return TimeSignal.createFromParcel(in);
+                }
+
+                public TimeSignal[] newArray(int size) {
+                    return new TimeSignal[size];
+                }
+            };
+
+    public static final String SOURCE_ID_NITZ = "nitz";
+
+    private final String mSourceId;
+    private final TimestampedValue<Long> mUtcTime;
+
+    public TimeSignal(String sourceId, TimestampedValue<Long> utcTime) {
+        mSourceId = Objects.requireNonNull(sourceId);
+        mUtcTime = Objects.requireNonNull(utcTime);
+    }
+
+    private static TimeSignal createFromParcel(Parcel in) {
+        String sourceId = in.readString();
+        TimestampedValue<Long> utcTime =
+                TimestampedValue.readFromParcel(in, null /* classLoader */, Long.class);
+        return new TimeSignal(sourceId, utcTime);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mSourceId);
+        TimestampedValue.writeToParcel(dest, mUtcTime);
+    }
+
+    @NonNull
+    public String getSourceId() {
+        return mSourceId;
+    }
+
+    @NonNull
+    public TimestampedValue<Long> getUtcTime() {
+        return mUtcTime;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        TimeSignal that = (TimeSignal) o;
+        return Objects.equals(mSourceId, that.mSourceId)
+                && Objects.equals(mUtcTime, that.mUtcTime);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSourceId, mUtcTime);
+    }
+
+    @Override
+    public String toString() {
+        return "TimeSignal{"
+                + "mSourceId='" + mSourceId + '\''
+                + ", mUtcTime=" + mUtcTime
+                + '}';
+    }
+}
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
new file mode 100644
index 0000000..ef2cbab
--- /dev/null
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.app.timezonedetector;
+
+/**
+ * System private API to comunicate with time zone detector service.
+ *
+ * <p>Used by parts of the Android system with signals associated with the device's time zone to
+ * provide information to the Time Zone Detector Service.
+ *
+ * <p>Use the {@link android.app.timezonedetector.TimeZoneDetector} class rather than going through
+ * this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
+ * for more complete documentation.
+ *
+ *
+ * {@hide}
+ */
+interface ITimeZoneDetectorService {
+  void stubbedCall();
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
new file mode 100644
index 0000000..be3c764
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -0,0 +1,57 @@
+/*
+ * 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.app.timezonedetector;
+
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The interface through which system components can send signals to the TimeZoneDetectorService.
+ * @hide
+ */
+@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
+public final class TimeZoneDetector {
+
+    private static final String TAG = "timezonedetector.TimeZoneDetector";
+    private static final boolean DEBUG = false;
+
+    private final ITimeZoneDetectorService mITimeZoneDetectorService;
+
+    public TimeZoneDetector() throws ServiceNotFoundException {
+        mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
+                ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+
+    }
+    /**
+     * Does nothing.
+     * TODO: Remove this when the service implementation is built out.
+     */
+    public void stubbedCall() {
+        if (DEBUG) {
+            Log.d(TAG, "stubbedCall called");
+        }
+        try {
+            mITimeZoneDetectorService.stubbedCall();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index f8aaba9..04dd060 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -117,7 +117,7 @@
      */
     @Nullable
     public byte[] getServiceData(ParcelUuid serviceDataUuid) {
-        if (serviceDataUuid == null) {
+        if (serviceDataUuid == null || mServiceData == null) {
             return null;
         }
         return mServiceData.get(serviceDataUuid);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fcf7dbfeaf..9c47672 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3019,7 +3019,9 @@
             //@hide: CONTEXTHUB_SERVICE,
             SYSTEM_HEALTH_SERVICE,
             //@hide: INCIDENT_SERVICE,
-            COMPANION_DEVICE_SERVICE
+            COMPANION_DEVICE_SERVICE,
+            //@hide: TIME_DETECTOR_SERVICE,
+            //@hide: TIME_ZONE_DETECTOR_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -4097,6 +4099,24 @@
     public static final String SECURE_ELEMENT_SERVICE = "secure_element";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.app.timedetector.ITimeDetectorService}.
+     * @hide
+     *
+     * @see #getSystemService(String)
+     */
+    public static final String TIME_DETECTOR_SERVICE = "time_detector";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.app.timezonedetector.ITimeZoneDetectorService}.
+     * @hide
+     *
+     * @see #getSystemService(String)
+     */
+    public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0e74d9e..a22f6d6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -96,8 +96,8 @@
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
-
 import libcore.util.EmptyArray;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -2340,10 +2340,10 @@
                             com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
                     if (val != null) {
                         if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                            targetCode = minCode = val.string.toString();
+                            minCode = val.string.toString();
                         } else {
                             // If it's not a string, it's an integer.
-                            targetVers = minVers = val.data;
+                            minVers = val.data;
                         }
                     }
 
@@ -2359,6 +2359,9 @@
                             // If it's not a string, it's an integer.
                             targetVers = val.data;
                         }
+                    } else {
+                        targetVers = minVers;
+                        targetCode = minCode;
                     }
 
                     sa.recycle();
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index f0adcd6..97284fb 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -67,7 +67,7 @@
     public static final int ACCESS_BUFFER = 3;
 
     private static final String TAG = "AssetManager";
-    private static final boolean localLOGV = false || false;
+    private static final boolean localLOGV = false;
     
     private static final boolean DEBUG_REFS = false;
     
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4ccfea2..7be708a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -125,8 +125,8 @@
     /**
      * A temporary hack until SUPL system can get off the legacy APIS.
      * They do too many network requests and the long list of apps listening
-     * and waking due to the CONNECTIVITY_ACTION bcast makes it expensive.
-     * Use this bcast intent instead for SUPL requests.
+     * and waking due to the CONNECTIVITY_ACTION broadcast makes it expensive.
+     * Use this broadcast intent instead for SUPL requests.
      * @hide
      */
     public static final String CONNECTIVITY_ACTION_SUPL =
@@ -152,7 +152,7 @@
      * call {@link CaptivePortal#reportCaptivePortalDismissed} so the system can
      * reevaluate the network. If reevaluation finds the network no longer
      * subject to a captive portal, the network may become the default active
-     * data network. </li>
+     * data network.</li>
      * <li> When the app handling this action believes the user explicitly wants
      * to ignore the captive portal and the network, the app should call
      * {@link CaptivePortal#ignoreNetwork}. </li>
@@ -260,7 +260,8 @@
      * {@hide}
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_DATA_ACTIVITY_CHANGE = "android.net.conn.DATA_ACTIVITY_CHANGE";
+    public static final String ACTION_DATA_ACTIVITY_CHANGE =
+            "android.net.conn.DATA_ACTIVITY_CHANGE";
     /**
      * The lookup key for an enum that indicates the network device type on which this data activity
      * change happens.
@@ -391,14 +392,14 @@
 
     /**
      * Invalid tethering type.
-     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @see #startTethering(int, boolean, OnStartTetheringCallback)
      * @hide
      */
     public static final int TETHERING_INVALID   = -1;
 
     /**
      * Wifi tethering type.
-     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @see #startTethering(int, boolean, OnStartTetheringCallback)
      * @hide
      */
     @SystemApi
@@ -406,7 +407,7 @@
 
     /**
      * USB tethering type.
-     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @see #startTethering(int, boolean, OnStartTetheringCallback)
      * @hide
      */
     @SystemApi
@@ -414,7 +415,7 @@
 
     /**
      * Bluetooth tethering type.
-     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @see #startTethering(int, boolean, OnStartTetheringCallback)
      * @hide
      */
     @SystemApi
@@ -664,7 +665,7 @@
     /**
      * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered.
      * This allows to distinguish when unregistering NetworkCallbacks those that were never
-     * registered and those that were already unregistered.
+     * registered from those that were already unregistered.
      * @hide
      */
     private static final NetworkRequest ALREADY_UNREGISTERED =
@@ -1494,8 +1495,8 @@
         };
     }
 
-    private static HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
-            new HashMap<NetworkCapabilities, LegacyRequest>();
+    private static final HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
+            new HashMap<>();
 
     private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) {
         synchronized (sLegacyRequests) {
@@ -1635,8 +1636,9 @@
      * {@code onStarted} method will be called. If an error occurs, {@code onError} will be called,
      * specifying one of the {@code ERROR_*} constants in this class.
      *
-     * To stop an existing keepalive, call {@link stop}. The system will call {@code onStopped} if
-     * the operation was successfull or {@code onError} if an error occurred.
+     * To stop an existing keepalive, call {@link PacketKeepalive#stop}. The system will call
+     * {@link PacketKeepaliveCallback#onStopped} if the operation was successful or
+     * {@link PacketKeepaliveCallback#onError} if an error occurred.
      *
      * @hide
      */
@@ -1897,7 +1899,7 @@
          * to initiate network traffic), you can retrieve its instantaneous state with
          * {@link ConnectivityManager#isDefaultNetworkActive}.
          */
-        public void onNetworkActive();
+        void onNetworkActive();
     }
 
     private INetworkManagementService getNetworkManagementService() {
@@ -1912,8 +1914,7 @@
     }
 
     private final ArrayMap<OnNetworkActiveListener, INetworkActivityListener>
-            mNetworkActivityListeners
-                    = new ArrayMap<OnNetworkActiveListener, INetworkActivityListener>();
+            mNetworkActivityListeners = new ArrayMap<>();
 
     /**
      * Start listening to reports when the system's default data network is active, meaning it is
@@ -2216,12 +2217,12 @@
         /**
          * Called when tethering has been successfully started.
          */
-        public void onTetheringStarted() {};
+        public void onTetheringStarted() {}
 
         /**
          * Called when starting tethering failed.
          */
-        public void onTetheringFailed() {};
+        public void onTetheringFailed() {}
     }
 
     /**
@@ -2658,9 +2659,6 @@
     /**
      * Set sign in error notification to visible or in visible
      *
-     * @param visible
-     * @param networkType
-     *
      * {@hide}
      * @deprecated Doesn't properly deal with multiple connected networks of the same type.
      */
@@ -2869,7 +2867,7 @@
      * @hide
      */
     public interface Errors {
-        static int TOO_MANY_REQUESTS = 1;
+        int TOO_MANY_REQUESTS = 1;
     }
 
     /** @hide */
@@ -3126,7 +3124,7 @@
      * as these {@code NetworkCapabilities} represent states that a particular
      * network may never attain, and whether a network will attain these states
      * is unknown prior to bringing up the network so the framework does not
-     * know how to go about satisfing a request with these capabilities.
+     * know how to go about satisfying a request with these capabilities.
      *
      * <p>This method requires the caller to hold either the
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3186,7 +3184,7 @@
      * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
      * by a timeout.
      *
-     * This function behaves identically to the non-timedout version, but if a suitable
+     * This function behaves identically to the version without timeout, but if a suitable
      * network is not found within the given time (in milliseconds) the
      * {@link NetworkCallback#onUnavailable} callback is called. The request can still be
      * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
@@ -3267,7 +3265,7 @@
      * as these {@code NetworkCapabilities} represent states that a particular
      * network may never attain, and whether a network will attain these states
      * is unknown prior to bringing up the network so the framework does not
-     * know how to go about satisfing a request with these capabilities.
+     * know how to go about satisfying a request with these capabilities.
      *
      * <p>This method requires the caller to hold either the
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3432,9 +3430,9 @@
         // capabilities, this request is guaranteed, at all times, to be
         // satisfied by the same network, if any, that satisfies the default
         // request, i.e., the system default network.
-        NetworkCapabilities nullCapabilities = null;
         CallbackHandler cbHandler = new CallbackHandler(handler);
-        sendRequestForNetwork(nullCapabilities, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
+        sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+                REQUEST, TYPE_NONE, cbHandler);
     }
 
     /**
@@ -3669,7 +3667,7 @@
      * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
      */
     public boolean bindProcessToNetwork(Network network) {
-        // Forcing callers to call thru non-static function ensures ConnectivityManager
+        // Forcing callers to call through non-static function ensures ConnectivityManager
         // instantiated.
         return setProcessDefaultNetwork(network);
     }
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index 3a3ddcc..d6774d4 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -45,25 +45,31 @@
             in String localAddr,
             in String remoteAddr,
             in Network underlyingNetwork,
-            in IBinder binder);
+            in IBinder binder,
+            in String callingPackage);
 
     void addAddressToTunnelInterface(
             int tunnelResourceId,
-            in LinkAddress localAddr);
+            in LinkAddress localAddr,
+            in String callingPackage);
 
     void removeAddressFromTunnelInterface(
             int tunnelResourceId,
-            in LinkAddress localAddr);
+            in LinkAddress localAddr,
+            in String callingPackage);
 
-    void deleteTunnelInterface(int resourceId);
+    void deleteTunnelInterface(int resourceId, in String callingPackage);
 
-    IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder);
+    IpSecTransformResponse createTransform(
+            in IpSecConfig c, in IBinder binder, in String callingPackage);
 
     void deleteTransform(int transformId);
 
-    void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId);
+    void applyTransportModeTransform(
+            in ParcelFileDescriptor socket, int direction, int transformId);
 
-    void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId);
+    void applyTunnelModeTransform(
+            int tunnelResourceId, int direction, int transformResourceId, in String callingPackage);
 
     void removeTransportModeTransforms(in ParcelFileDescriptor socket);
 }
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index cc22771..1145d5b 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -27,6 +27,9 @@
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.system.ErrnoException;
+import android.system.OsConstants;
 import android.util.AndroidException;
 import android.util.Log;
 
@@ -140,6 +143,7 @@
         }
     }
 
+    private final Context mContext;
     private final IIpSecService mService;
 
     /**
@@ -172,11 +176,16 @@
         public void close() {
             try {
                 mService.releaseSecurityParameterIndex(mResourceId);
-                mResourceId = INVALID_RESOURCE_ID;
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
+            } catch (Exception e) {
+                // On close we swallow all random exceptions since failure to close is not
+                // actionable by the user.
+                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
+            } finally {
+                mResourceId = INVALID_RESOURCE_ID;
+                mCloseGuard.close();
             }
-            mCloseGuard.close();
         }
 
         /** Check that the SPI was closed properly. */
@@ -227,7 +236,6 @@
                     throw new RuntimeException(
                             "Invalid Resource ID returned by IpSecService: " + status);
                 }
-
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -239,6 +247,17 @@
         public int getResourceId() {
             return mResourceId;
         }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                .append("SecurityParameterIndex{spi=")
+                .append(mSpi)
+                .append(",resourceId=")
+                .append(mResourceId)
+                .append("}")
+                .toString();
+        }
     }
 
     /**
@@ -261,7 +280,11 @@
                     mService,
                     destinationAddress,
                     IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+        } catch (ServiceSpecificException e) {
+            throw rethrowUncheckedExceptionFromServiceSpecificException(e);
         } catch (SpiUnavailableException unlikely) {
+            // Because this function allocates a totally random SPI, it really shouldn't ever
+            // fail to allocate an SPI; we simply need this because the exception is checked.
             throw new ResourceUnavailableException("No SPIs available");
         }
     }
@@ -274,8 +297,8 @@
      *
      * @param destinationAddress the destination address for traffic bearing the requested SPI.
      *     For inbound traffic, the destination should be an address currently assigned on-device.
-     * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is
-     *     reserved and may not be used. See RFC 4303 Section 2.1.
+     * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See
+     *     RFC 4303 Section 2.1.
      * @return the reserved SecurityParameterIndex
      * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
      *     currently allocated for this user
@@ -289,7 +312,11 @@
         if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
             throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
         }
-        return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
+        try {
+            return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
+        } catch (ServiceSpecificException e) {
+            throw rethrowUncheckedExceptionFromServiceSpecificException(e);
+        }
     }
 
     /**
@@ -424,6 +451,8 @@
         // constructor takes control and closes the user's FD when we exit the method.
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
             mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
+        } catch (ServiceSpecificException e) {
+            throw rethrowCheckedExceptionFromServiceSpecificException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -482,6 +511,8 @@
     public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
             mService.removeTransportModeTransforms(pfd);
+        } catch (ServiceSpecificException e) {
+            throw rethrowCheckedExceptionFromServiceSpecificException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -575,6 +606,13 @@
                 mResourceId = INVALID_RESOURCE_ID;
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
+            } catch (Exception e) {
+                // On close we swallow all random exceptions since failure to close is not
+                // actionable by the user.
+                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
+            } finally {
+                mResourceId = INVALID_RESOURCE_ID;
+                mCloseGuard.close();
             }
 
             try {
@@ -583,7 +621,6 @@
                 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
                 throw e;
             }
-            mCloseGuard.close();
         }
 
         /** Check that the socket was closed properly. */
@@ -600,6 +637,17 @@
         public int getResourceId() {
             return mResourceId;
         }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                .append("UdpEncapsulationSocket{port=")
+                .append(mPort)
+                .append(",resourceId=")
+                .append(mResourceId)
+                .append("}")
+                .toString();
+        }
     };
 
     /**
@@ -627,7 +675,11 @@
         if (port == 0) {
             throw new IllegalArgumentException("Specified port must be a valid port number!");
         }
-        return new UdpEncapsulationSocket(mService, port);
+        try {
+            return new UdpEncapsulationSocket(mService, port);
+        } catch (ServiceSpecificException e) {
+            throw rethrowCheckedExceptionFromServiceSpecificException(e);
+        }
     }
 
     /**
@@ -650,7 +702,11 @@
     @NonNull
     public UdpEncapsulationSocket openUdpEncapsulationSocket()
             throws IOException, ResourceUnavailableException {
-        return new UdpEncapsulationSocket(mService, 0);
+        try {
+            return new UdpEncapsulationSocket(mService, 0);
+        } catch (ServiceSpecificException e) {
+            throw rethrowCheckedExceptionFromServiceSpecificException(e);
+        }
     }
 
     /**
@@ -667,6 +723,7 @@
      */
     @SystemApi
     public static final class IpSecTunnelInterface implements AutoCloseable {
+        private final String mOpPackageName;
         private final IIpSecService mService;
         private final InetAddress mRemoteAddress;
         private final InetAddress mLocalAddress;
@@ -688,12 +745,17 @@
          * tunneled traffic.
          *
          * @param address the local address for traffic inside the tunnel
+         * @param prefixLen length of the InetAddress prefix
          * @hide
          */
         @SystemApi
-        public void addAddress(@NonNull LinkAddress address) throws IOException {
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+        public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
             try {
-                mService.addAddressToTunnelInterface(mResourceId, address);
+                mService.addAddressToTunnelInterface(
+                        mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
+            } catch (ServiceSpecificException e) {
+                throw rethrowCheckedExceptionFromServiceSpecificException(e);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -705,21 +767,27 @@
          * <p>Remove an address which was previously added to the IpSecTunnelInterface
          *
          * @param address to be removed
+         * @param prefixLen length of the InetAddress prefix
          * @hide
          */
         @SystemApi
-        public void removeAddress(@NonNull LinkAddress address) throws IOException {
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+        public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
             try {
-                mService.removeAddressFromTunnelInterface(mResourceId, address);
+                mService.removeAddressFromTunnelInterface(
+                        mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
+            } catch (ServiceSpecificException e) {
+                throw rethrowCheckedExceptionFromServiceSpecificException(e);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
 
-        private IpSecTunnelInterface(@NonNull IIpSecService service,
+        private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
                 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
                 @NonNull Network underlyingNetwork)
                 throws ResourceUnavailableException, IOException {
+            mOpPackageName = ctx.getOpPackageName();
             mService = service;
             mLocalAddress = localAddress;
             mRemoteAddress = remoteAddress;
@@ -731,7 +799,8 @@
                                 localAddress.getHostAddress(),
                                 remoteAddress.getHostAddress(),
                                 underlyingNetwork,
-                                new Binder());
+                                new Binder(),
+                                mOpPackageName);
                 switch (result.status) {
                     case Status.OK:
                         break;
@@ -760,12 +829,17 @@
         @Override
         public void close() {
             try {
-                mService.deleteTunnelInterface(mResourceId);
-                mResourceId = INVALID_RESOURCE_ID;
+                mService.deleteTunnelInterface(mResourceId, mOpPackageName);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
+            } catch (Exception e) {
+                // On close we swallow all random exceptions since failure to close is not
+                // actionable by the user.
+                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
+            } finally {
+                mResourceId = INVALID_RESOURCE_ID;
+                mCloseGuard.close();
             }
-            mCloseGuard.close();
         }
 
         /** Check that the Interface was closed properly. */
@@ -782,6 +856,17 @@
         public int getResourceId() {
             return mResourceId;
         }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                .append("IpSecTunnelInterface{ifname=")
+                .append(mInterfaceName)
+                .append(",resourceId=")
+                .append(mResourceId)
+                .append("}")
+                .toString();
+        }
     }
 
     /**
@@ -801,11 +886,16 @@
      */
     @SystemApi
     @NonNull
-    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
     public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
             @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
             throws ResourceUnavailableException, IOException {
-        return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork);
+        try {
+            return new IpSecTunnelInterface(
+                    mContext, mService, localAddress, remoteAddress, underlyingNetwork);
+        } catch (ServiceSpecificException e) {
+            throw rethrowCheckedExceptionFromServiceSpecificException(e);
+        }
     }
 
     /**
@@ -826,12 +916,15 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
     public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
             @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         try {
             mService.applyTunnelModeTransform(
-                    tunnel.getResourceId(), direction, transform.getResourceId());
+                    tunnel.getResourceId(), direction,
+                    transform.getResourceId(), mContext.getOpPackageName());
+        } catch (ServiceSpecificException e) {
+            throw rethrowCheckedExceptionFromServiceSpecificException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -843,7 +936,48 @@
      * @param context the application context for this manager
      * @hide
      */
-    public IpSecManager(IIpSecService service) {
+    public IpSecManager(Context ctx, IIpSecService service) {
+        mContext = ctx;
         mService = checkNotNull(service, "missing service");
     }
+
+    private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
+        // OsConstants are late binding, so switch statements can't be used.
+        if (sse.errorCode == OsConstants.EINVAL) {
+            throw new IllegalArgumentException(sse);
+        } else if (sse.errorCode == OsConstants.EAGAIN) {
+            throw new IllegalStateException(sse);
+        } else if (sse.errorCode == OsConstants.EOPNOTSUPP) {
+            throw new UnsupportedOperationException(sse);
+        }
+    }
+
+    /**
+     * Convert an Errno SSE to the correct Unchecked exception type.
+     *
+     * This method never actually returns.
+     */
+    // package
+    static RuntimeException
+            rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) {
+        maybeHandleServiceSpecificException(sse);
+        throw new RuntimeException(sse);
+    }
+
+    /**
+     * Convert an Errno SSE to the correct Checked or Unchecked exception type.
+     *
+     * This method may throw IOException, or it may throw an unchecked exception; it will never
+     * actually return.
+     */
+    // package
+    static IOException rethrowCheckedExceptionFromServiceSpecificException(
+            ServiceSpecificException sse) throws IOException {
+        // First see if this is an unchecked exception of a type we know.
+        // If so, then we prefer the unchecked (specific) type of exception.
+        maybeHandleServiceSpecificException(sse);
+        // If not, then all we can do is provide the SSE in the form of an IOException.
+        throw new ErrnoException(
+                "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException();
+    }
 }
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index cf58647..23c8aa3 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -130,12 +131,15 @@
         synchronized (this) {
             try {
                 IIpSecService svc = getIpSecService();
-                IpSecTransformResponse result = svc.createTransform(mConfig, new Binder());
+                IpSecTransformResponse result = svc.createTransform(
+                        mConfig, new Binder(), mContext.getOpPackageName());
                 int status = result.status;
                 checkResultStatus(status);
                 mResourceId = result.resourceId;
                 Log.d(TAG, "Added Transform with Id " + mResourceId);
                 mCloseGuard.open("build");
+            } catch (ServiceSpecificException e) {
+                throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e);
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             }
@@ -180,6 +184,10 @@
             stopNattKeepalive();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
+        } catch (Exception e) {
+            // On close we swallow all random exceptions since failure to close is not
+            // actionable by the user.
+            Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
         } finally {
             mResourceId = INVALID_RESOURCE_ID;
             mCloseGuard.close();
@@ -282,7 +290,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
             android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
     })
     public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
@@ -325,7 +333,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
             android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
     })
     public void stopNattKeepalive() {
@@ -478,7 +486,7 @@
          */
         @SystemApi
         @NonNull
-        @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public IpSecTransform buildTunnelModeTransform(
                 @NonNull InetAddress sourceAddress,
                 @NonNull IpSecManager.SecurityParameterIndex spi)
@@ -506,4 +514,13 @@
             mConfig = new IpSecConfig();
         }
     }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+            .append("IpSecTransform{resourceId=")
+            .append(mResourceId)
+            .append("}")
+            .toString();
+    }
 }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 300a78b..bd2db92 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -32,6 +32,7 @@
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Objects;
+import java.util.StringJoiner;
 
 /**
  * Describes the properties of a network link.
@@ -48,13 +49,13 @@
 public final class LinkProperties implements Parcelable {
     // The interface described by the network link.
     private String mIfaceName;
-    private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
-    private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
-    private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<InetAddress>();
+    private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
+    private ArrayList<InetAddress> mDnses = new ArrayList<>();
+    private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
     private boolean mUsePrivateDns;
     private String mPrivateDnsServerName;
     private String mDomains;
-    private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+    private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
     private ProxyInfo mHttpProxy;
     private int mMtu;
     // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
@@ -66,15 +67,14 @@
 
     // Stores the properties of links that are "stacked" above this link.
     // Indexed by interface name to allow modification and to prevent duplicates being added.
-    private Hashtable<String, LinkProperties> mStackedLinks =
-        new Hashtable<String, LinkProperties>();
+    private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
 
     /**
      * @hide
      */
     public static class CompareResult<T> {
-        public final List<T> removed = new ArrayList<T>();
-        public final List<T> added = new ArrayList<T>();
+        public final List<T> removed = new ArrayList<>();
+        public final List<T> added = new ArrayList<>();
 
         public CompareResult() {}
 
@@ -93,12 +93,9 @@
 
         @Override
         public String toString() {
-            String retVal = "removed=[";
-            for (T addr : removed) retVal += addr.toString() + ",";
-            retVal += "] added=[";
-            for (T addr : added) retVal += addr.toString() + ",";
-            retVal += "]";
-            return retVal;
+            return "removed=[" + TextUtils.join(",", removed)
+                    + "] added=[" + TextUtils.join(",", added)
+                    + "]";
         }
     }
 
@@ -120,7 +117,7 @@
     public static ProvisioningChange compareProvisioning(
             LinkProperties before, LinkProperties after) {
         if (before.isProvisioned() && after.isProvisioned()) {
-            // On dualstack networks, DHCPv4 renewals can occasionally fail.
+            // On dual-stack networks, DHCPv4 renewals can occasionally fail.
             // When this happens, IPv6-reachable services continue to function
             // normally but IPv4-only services (naturally) fail.
             //
@@ -131,7 +128,7 @@
             //
             // For users, this is confusing and unexpected behaviour, and is
             // not necessarily easy to diagnose.  Therefore, we treat changing
-            // from a dualstack network to an IPv6-only network equivalent to
+            // from a dual-stack network to an IPv6-only network equivalent to
             // a total loss of provisioning.
             //
             // For one such example of this, see b/18867306.
@@ -139,7 +136,7 @@
             // Additionally, losing IPv6 provisioning can result in TCP
             // connections getting stuck until timeouts fire and other
             // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
-            // previously dualstack network is deemed a lost of provisioning.
+            // previously dual-stack network is deemed a lost of provisioning.
             if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) ||
                 (before.isIPv6Provisioned() && !after.isIPv6Provisioned())) {
                 return ProvisioningChange.LOST_PROVISIONING;
@@ -165,22 +162,19 @@
      */
     public LinkProperties(LinkProperties source) {
         if (source != null) {
-            mIfaceName = source.getInterfaceName();
-            for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
-            for (InetAddress i : source.getDnsServers()) mDnses.add(i);
-            for (InetAddress i : source.getValidatedPrivateDnsServers()) {
-                mValidatedPrivateDnses.add(i);
-            }
+            mIfaceName = source.mIfaceName;
+            mLinkAddresses.addAll(source.mLinkAddresses);
+            mDnses.addAll(source.mDnses);
+            mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
             mUsePrivateDns = source.mUsePrivateDns;
             mPrivateDnsServerName = source.mPrivateDnsServerName;
-            mDomains = source.getDomains();
-            for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
-            mHttpProxy = (source.getHttpProxy() == null)  ?
-                    null : new ProxyInfo(source.getHttpProxy());
+            mDomains = source.mDomains;
+            mRoutes.addAll(source.mRoutes);
+            mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
             for (LinkProperties l: source.mStackedLinks.values()) {
                 addStackedLink(l);
             }
-            setMtu(source.getMtu());
+            setMtu(source.mMtu);
             mTcpBufferSizes = source.mTcpBufferSizes;
         }
     }
@@ -194,7 +188,7 @@
      */
     public void setInterfaceName(String iface) {
         mIfaceName = iface;
-        ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
+        ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
         for (RouteInfo route : mRoutes) {
             newRoutes.add(routeWithInterface(route));
         }
@@ -214,8 +208,8 @@
      * @hide
      */
     public List<String> getAllInterfaceNames() {
-        List<String> interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
-        if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
+        List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
+        if (mIfaceName != null) interfaceNames.add(mIfaceName);
         for (LinkProperties stacked: mStackedLinks.values()) {
             interfaceNames.addAll(stacked.getAllInterfaceNames());
         }
@@ -229,11 +223,11 @@
      * prefix lengths for each address.  This is a simplified utility alternative to
      * {@link LinkProperties#getLinkAddresses}.
      *
-     * @return An umodifiable {@link List} of {@link InetAddress} for this link.
+     * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
      * @hide
      */
     public List<InetAddress> getAddresses() {
-        List<InetAddress> addresses = new ArrayList<InetAddress>();
+        List<InetAddress> addresses = new ArrayList<>();
         for (LinkAddress linkAddress : mLinkAddresses) {
             addresses.add(linkAddress.getAddress());
         }
@@ -245,7 +239,7 @@
      * @hide
      */
     public List<InetAddress> getAllAddresses() {
-        List<InetAddress> addresses = new ArrayList<InetAddress>();
+        List<InetAddress> addresses = new ArrayList<>();
         for (LinkAddress linkAddress : mLinkAddresses) {
             addresses.add(linkAddress.getAddress());
         }
@@ -322,8 +316,7 @@
      * @hide
      */
     public List<LinkAddress> getAllLinkAddresses() {
-        List<LinkAddress> addresses = new ArrayList<LinkAddress>();
-        addresses.addAll(mLinkAddresses);
+        List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
         for (LinkProperties stacked: mStackedLinks.values()) {
             addresses.addAll(stacked.getAllLinkAddresses());
         }
@@ -391,7 +384,7 @@
     /**
      * Returns all the {@link InetAddress} for DNS servers on this link.
      *
-     * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on
+     * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
      *         this link.
      */
     public List<InetAddress> getDnsServers() {
@@ -643,7 +636,7 @@
      * @hide
      */
     public void ensureDirectlyConnectedRoutes() {
-        for (LinkAddress addr: mLinkAddresses) {
+        for (LinkAddress addr : mLinkAddresses) {
             addRoute(new RouteInfo(addr, null, mIfaceName));
         }
     }
@@ -653,8 +646,7 @@
      * @hide
      */
     public List<RouteInfo> getAllRoutes() {
-        List<RouteInfo> routes = new ArrayList<>();
-        routes.addAll(mRoutes);
+        List<RouteInfo> routes = new ArrayList<>(mRoutes);
         for (LinkProperties stacked: mStackedLinks.values()) {
             routes.addAll(stacked.getAllRoutes());
         }
@@ -685,7 +677,7 @@
     /**
      * Adds a stacked link.
      *
-     * If there is already a stacked link with the same interfacename as link,
+     * If there is already a stacked link with the same interface name as link,
      * that link is replaced with link. Otherwise, link is added to the list
      * of stacked links. If link is null, nothing changes.
      *
@@ -725,9 +717,9 @@
      */
     public @NonNull List<LinkProperties> getStackedLinks() {
         if (mStackedLinks.isEmpty()) {
-            return Collections.EMPTY_LIST;
+            return Collections.emptyList();
         }
-        List<LinkProperties> stacked = new ArrayList<LinkProperties>();
+        List<LinkProperties> stacked = new ArrayList<>();
         for (LinkProperties link : mStackedLinks.values()) {
             stacked.add(new LinkProperties(link));
         }
@@ -761,57 +753,76 @@
 
     @Override
     public String toString() {
-        String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
+        // Space as a separator, so no need for spaces at start/end of the individual fragments.
+        final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
 
-        String linkAddresses = "LinkAddresses: [";
-        for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
-        linkAddresses += "] ";
-
-        String dns = "DnsAddresses: [";
-        for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
-        dns += "] ";
-
-        String usePrivateDns = "UsePrivateDns: " + mUsePrivateDns + " ";
-
-        String privateDnsServerName = "";
-        if (privateDnsServerName != null) {
-            privateDnsServerName = "PrivateDnsServerName: " + mPrivateDnsServerName + " ";
+        if (mIfaceName != null) {
+            resultJoiner.add("InterfaceName:");
+            resultJoiner.add(mIfaceName);
         }
 
-        String validatedPrivateDns = "";
+        resultJoiner.add("LinkAddresses: [");
+        if (!mLinkAddresses.isEmpty()) {
+            resultJoiner.add(TextUtils.join(",", mLinkAddresses));
+        }
+        resultJoiner.add("]");
+
+        resultJoiner.add("DnsAddresses: [");
+        if (!mDnses.isEmpty()) {
+            resultJoiner.add(TextUtils.join(",", mDnses));
+        }
+        resultJoiner.add("]");
+
+        if (mUsePrivateDns) {
+            resultJoiner.add("UsePrivateDns: true");
+        }
+
+        if (mPrivateDnsServerName != null) {
+            resultJoiner.add("PrivateDnsServerName:");
+            resultJoiner.add(mPrivateDnsServerName);
+        }
+
         if (!mValidatedPrivateDnses.isEmpty()) {
-            validatedPrivateDns = "ValidatedPrivateDnsAddresses: [";
-            for (InetAddress addr : mValidatedPrivateDnses) {
-                validatedPrivateDns += addr.getHostAddress() + ",";
+            final StringJoiner validatedPrivateDnsesJoiner =
+                    new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
+            for (final InetAddress addr : mValidatedPrivateDnses) {
+                validatedPrivateDnsesJoiner.add(addr.getHostAddress());
             }
-            validatedPrivateDns += "] ";
+            resultJoiner.add(validatedPrivateDnsesJoiner.toString());
         }
 
-        String domainName = "Domains: " + mDomains;
+        resultJoiner.add("Domains:");
+        resultJoiner.add(mDomains);
 
-        String mtu = " MTU: " + mMtu;
+        resultJoiner.add("MTU:");
+        resultJoiner.add(Integer.toString(mMtu));
 
-        String tcpBuffSizes = "";
         if (mTcpBufferSizes != null) {
-            tcpBuffSizes = " TcpBufferSizes: " + mTcpBufferSizes;
+            resultJoiner.add("TcpBufferSizes:");
+            resultJoiner.add(mTcpBufferSizes);
         }
 
-        String routes = " Routes: [";
-        for (RouteInfo route : mRoutes) routes += route.toString() + ",";
-        routes += "] ";
-        String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " ");
+        resultJoiner.add("Routes: [");
+        if (!mRoutes.isEmpty()) {
+            resultJoiner.add(TextUtils.join(",", mRoutes));
+        }
+        resultJoiner.add("]");
 
-        String stacked = "";
-        if (mStackedLinks.values().size() > 0) {
-            stacked += " Stacked: [";
-            for (LinkProperties link: mStackedLinks.values()) {
-                stacked += " [" + link.toString() + " ],";
+        if (mHttpProxy != null) {
+            resultJoiner.add("HttpProxy:");
+            resultJoiner.add(mHttpProxy.toString());
+        }
+
+        final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
+        if (!stackedLinksValues.isEmpty()) {
+            final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
+            for (final LinkProperties lp : stackedLinksValues) {
+                stackedLinksJoiner.add("[ " + lp + " ]");
             }
-            stacked += "] ";
+            resultJoiner.add(stackedLinksJoiner.toString());
         }
-        return "{" + ifaceName + linkAddresses + routes + dns + usePrivateDns
-            + privateDnsServerName + domainName + mtu + tcpBuffSizes + proxy
-            + stacked + "}";
+
+        return resultJoiner.toString();
     }
 
     /**
@@ -1028,7 +1039,7 @@
         if (mDomains == null) {
             if (targetDomains != null) return false;
         } else {
-            if (mDomains.equals(targetDomains) == false) return false;
+            if (!mDomains.equals(targetDomains)) return false;
         }
         return (mDnses.size() == targetDnses.size()) ?
                 mDnses.containsAll(targetDnses) : false;
@@ -1130,7 +1141,6 @@
         return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
     }
 
-    @Override
     /**
      * Compares this {@code LinkProperties} instance against the target
      * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
@@ -1145,13 +1155,14 @@
      * @param obj the object to be tested for equality.
      * @return {@code true} if both objects are equal, {@code false} otherwise.
      */
+    @Override
     public boolean equals(Object obj) {
         if (this == obj) return true;
 
         if (!(obj instanceof LinkProperties)) return false;
 
         LinkProperties target = (LinkProperties) obj;
-        /**
+        /*
          * This method does not check that stacked interfaces are equal, because
          * stacked interfaces are not so much a property of the link as a
          * description of connections between links.
@@ -1258,12 +1269,13 @@
     }
 
 
-    @Override
     /**
-     * generate hashcode based on significant fields
+     * Generate hashcode based on significant fields
+     *
      * Equal objects must produce the same hash code, while unequal objects
      * may have the same hash codes.
      */
+    @Override
     public int hashCode() {
         return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
                 + mLinkAddresses.size() * 31
@@ -1313,7 +1325,7 @@
         } else {
             dest.writeByte((byte)0);
         }
-        ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
+        ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
         dest.writeList(stackedLinks);
     }
 
@@ -1331,7 +1343,7 @@
                 }
                 int addressCount = in.readInt();
                 for (int i = 0; i < addressCount; i++) {
-                    netProp.addLinkAddress((LinkAddress) in.readParcelable(null));
+                    netProp.addLinkAddress(in.readParcelable(null));
                 }
                 addressCount = in.readInt();
                 for (int i = 0; i < addressCount; i++) {
@@ -1353,10 +1365,10 @@
                 netProp.setTcpBufferSizes(in.readString());
                 addressCount = in.readInt();
                 for (int i = 0; i < addressCount; i++) {
-                    netProp.addRoute((RouteInfo) in.readParcelable(null));
+                    netProp.addRoute(in.readParcelable(null));
                 }
                 if (in.readByte() == 1) {
-                    netProp.setHttpProxy((ProxyInfo) in.readParcelable(null));
+                    netProp.setHttpProxy(in.readParcelable(null));
                 }
                 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
                 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
@@ -1377,10 +1389,9 @@
      */
     public static boolean isValidMtu(int mtu, boolean ipv6) {
         if (ipv6) {
-            if (mtu >= MIN_MTU_V6 && mtu <= MAX_MTU) return true;
+            return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
         } else {
-            if (mtu >= MIN_MTU && mtu <= MAX_MTU) return true;
+            return mtu >= MIN_MTU && mtu <= MAX_MTU;
         }
-        return false;
     }
 }
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 8f95607..d1cccac 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -136,7 +136,7 @@
 
     /**
      * Specify whether or not Private DNS should be bypassed when attempting
-     * to use {@link getAllByName()}/{@link getByName()} methods on the given
+     * to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given
      * instance for hostname resolution.
      *
      * @hide
@@ -163,13 +163,6 @@
      * A {@code SocketFactory} that produces {@code Socket}'s bound to this network.
      */
     private class NetworkBoundSocketFactory extends SocketFactory {
-        private final int mNetId;
-
-        public NetworkBoundSocketFactory(int netId) {
-            super();
-            mNetId = netId;
-        }
-
         private Socket connectToHost(String host, int port, SocketAddress localAddress)
                 throws IOException {
             // Lookup addresses only on this Network.
@@ -195,7 +188,8 @@
         }
 
         @Override
-        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
+        public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+                throws IOException {
             return connectToHost(host, port, new InetSocketAddress(localHost, localPort));
         }
 
@@ -259,7 +253,7 @@
         if (mNetworkBoundSocketFactory == null) {
             synchronized (mLock) {
                 if (mNetworkBoundSocketFactory == null) {
-                    mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
+                    mNetworkBoundSocketFactory = new NetworkBoundSocketFactory();
                 }
             }
         }
@@ -454,7 +448,7 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (obj instanceof Network == false) return false;
+        if (!(obj instanceof Network)) return false;
         Network other = (Network)obj;
         return this.netId == other.netId;
     }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 19f0c90..83553df 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,8 @@
 package android.net;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -60,15 +62,7 @@
 
     public NetworkCapabilities(NetworkCapabilities nc) {
         if (nc != null) {
-            mNetworkCapabilities = nc.mNetworkCapabilities;
-            mTransportTypes = nc.mTransportTypes;
-            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
-            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
-            mNetworkSpecifier = nc.mNetworkSpecifier;
-            mSignalStrength = nc.mSignalStrength;
-            mUids = nc.mUids;
-            mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
-            mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
+            set(nc);
         }
     }
 
@@ -84,6 +78,24 @@
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
         mUids = null;
         mEstablishingVpnAppUid = INVALID_UID;
+        mSSID = null;
+    }
+
+    /**
+     * Set all contents of this object to the contents of a NetworkCapabilities.
+     * @hide
+     */
+    public void set(NetworkCapabilities nc) {
+        mNetworkCapabilities = nc.mNetworkCapabilities;
+        mTransportTypes = nc.mTransportTypes;
+        mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+        mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+        mNetworkSpecifier = nc.mNetworkSpecifier;
+        mSignalStrength = nc.mSignalStrength;
+        setUids(nc.mUids); // Will make the defensive copy
+        mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
+        mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
+        mSSID = nc.mSSID;
     }
 
     /**
@@ -275,6 +287,7 @@
      * this network can be used by system apps to upload telemetry data.
      * @hide
      */
+    @SystemApi
     public static final int NET_CAPABILITY_OEM_PAID = 22;
 
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
@@ -423,6 +436,7 @@
      * @return an array of capability values for this instance.
      * @hide
      */
+    @TestApi
     public @NetCapability int[] getCapabilities() {
         return BitUtils.unpackBits(mNetworkCapabilities);
     }
@@ -687,6 +701,7 @@
      * @return an array of transport type values for this instance.
      * @hide
      */
+    @TestApi
     public @Transport int[] getTransportTypes() {
         return BitUtils.unpackBits(mTransportTypes);
     }
@@ -920,7 +935,7 @@
     /**
      * Sets the signal strength. This is a signed integer, with higher values indicating a stronger
      * signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units
-     * reported by WifiManager.
+     * reported by wifi code.
      * <p>
      * Note that when used to register a network callback, this specifies the minimum acceptable
      * signal strength. When received as the state of an existing network it specifies the current
@@ -1052,7 +1067,7 @@
     }
 
     /**
-     * Tests if the set of UIDs that this network applies to is the same of the passed set of UIDs.
+     * Tests if the set of UIDs that this network applies to is the same as the passed network.
      * <p>
      * This test only checks whether equal range objects are in both sets. It will
      * return false if the ranges are not exactly the same, even if the covered UIDs
@@ -1142,6 +1157,62 @@
         mUids.addAll(nc.mUids);
     }
 
+
+    /**
+     * The SSID of the network, or null if not applicable or unknown.
+     * <p>
+     * This is filled in by wifi code.
+     * @hide
+     */
+    private String mSSID;
+
+    /**
+     * Sets the SSID of this network.
+     * @hide
+     */
+    public NetworkCapabilities setSSID(String ssid) {
+        mSSID = ssid;
+        return this;
+    }
+
+    /**
+     * Gets the SSID of this network, or null if none or unknown.
+     * @hide
+     */
+    public String getSSID() {
+        return mSSID;
+    }
+
+    /**
+     * Tests if the SSID of this network is the same as the SSID of the passed network.
+     * @hide
+     */
+    public boolean equalsSSID(NetworkCapabilities nc) {
+        return Objects.equals(mSSID, nc.mSSID);
+    }
+
+    /**
+     * Check if the SSID requirements of this object are matched by the passed object.
+     * @hide
+     */
+    public boolean satisfiedBySSID(NetworkCapabilities nc) {
+        return mSSID == null || mSSID.equals(nc.mSSID);
+    }
+
+    /**
+     * Combine SSIDs of the capabilities.
+     * <p>
+     * This is only legal if either the SSID of this object is null, or both SSIDs are
+     * equal.
+     * @hide
+     */
+    private void combineSSIDs(NetworkCapabilities nc) {
+        if (mSSID != null && !mSSID.equals(nc.mSSID)) {
+            throw new IllegalStateException("Can't combine two SSIDs");
+        }
+        setSSID(nc.mSSID);
+    }
+
     /**
      * Combine a set of Capabilities to this one.  Useful for coming up with the complete set.
      * <p>
@@ -1157,6 +1228,7 @@
         combineSpecifiers(nc);
         combineSignalStrength(nc);
         combineUids(nc);
+        combineSSIDs(nc);
     }
 
     /**
@@ -1175,7 +1247,8 @@
                 && (onlyImmutable || satisfiedByLinkBandwidths(nc))
                 && satisfiedBySpecifier(nc)
                 && (onlyImmutable || satisfiedBySignalStrength(nc))
-                && (onlyImmutable || satisfiedByUids(nc)));
+                && (onlyImmutable || satisfiedByUids(nc))
+                && (onlyImmutable || satisfiedBySSID(nc)));
     }
 
     /**
@@ -1264,7 +1337,8 @@
                 && equalsLinkBandwidths(that)
                 && equalsSignalStrength(that)
                 && equalsSpecifier(that)
-                && equalsUids(that));
+                && equalsUids(that)
+                && equalsSSID(that));
     }
 
     @Override
@@ -1279,7 +1353,8 @@
                 + (mLinkDownBandwidthKbps * 19)
                 + Objects.hashCode(mNetworkSpecifier) * 23
                 + (mSignalStrength * 29)
-                + Objects.hashCode(mUids) * 31;
+                + Objects.hashCode(mUids) * 31
+                + Objects.hashCode(mSSID) * 37;
     }
 
     @Override
@@ -1296,6 +1371,7 @@
         dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
         dest.writeInt(mSignalStrength);
         dest.writeArraySet(mUids);
+        dest.writeString(mSSID);
     }
 
     public static final Creator<NetworkCapabilities> CREATOR =
@@ -1313,6 +1389,7 @@
                 netCap.mSignalStrength = in.readInt();
                 netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
                         null /* ClassLoader, null for default */);
+                netCap.mSSID = in.readString();
                 return netCap;
             }
             @Override
@@ -1363,6 +1440,10 @@
             sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
         }
 
+        if (null != mSSID) {
+            sb.append(" SSID: ").append(mSSID);
+        }
+
         sb.append("]");
         return sb.toString();
     }
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 1ee0ed7d..f3669fb3 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -17,6 +17,8 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.net.NetworkCapabilities.NetCapability;
+import android.net.NetworkCapabilities.Transport;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
@@ -165,9 +167,6 @@
          * the requested network's required capabilities.  Note that when searching
          * for a network to satisfy a request, all capabilities requested must be
          * satisfied.
-         * <p>
-         * If the given capability was previously added to the list of unwanted capabilities
-         * then the capability will also be removed from the list of unwanted capabilities.
          *
          * @param capability The capability to add.
          * @return The builder to facilitate chaining
@@ -179,8 +178,7 @@
         }
 
         /**
-         * Removes (if found) the given capability from this builder instance from both required
-         * and unwanted capabilities lists.
+         * Removes (if found) the given capability from this builder instance.
          *
          * @param capability The capability to remove.
          * @return The builder to facilitate chaining.
@@ -199,8 +197,7 @@
          * @hide
          */
         public Builder setCapabilities(NetworkCapabilities nc) {
-            mNetworkCapabilities.clearAll();
-            mNetworkCapabilities.combineCapabilities(nc);
+            mNetworkCapabilities.set(nc);
             return this;
         }
 
@@ -228,6 +225,7 @@
          *
          * @param capability The capability to add to unwanted capability list.
          * @return The builder to facilitate chaining.
+         *
          * @hide
          */
         public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
@@ -426,6 +424,29 @@
         return type == Type.BACKGROUND_REQUEST;
     }
 
+    /**
+     * @see Builder#addCapability(int)
+     */
+    public boolean hasCapability(@NetCapability int capability) {
+        return networkCapabilities.hasCapability(capability);
+    }
+
+    /**
+     * @see Builder#addUnwantedCapability(int)
+     *
+     * @hide
+     */
+    public boolean hasUnwantedCapability(@NetCapability int capability) {
+        return networkCapabilities.hasUnwantedCapability(capability);
+    }
+
+    /**
+     * @see Builder#addTransportType(int)
+     */
+    public boolean hasTransport(@Transport int transportType) {
+        return networkCapabilities.hasTransport(transportType);
+    }
+
     public String toString() {
         return "NetworkRequest [ " + type + " id=" + requestId +
                 (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 1bb4adc..e1556b4 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -384,7 +384,7 @@
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
-                    || scheme.equalsIgnoreCase("mailto")) {
+                    || scheme.equalsIgnoreCase("mailto") || scheme.equalsIgnoreCase("nfc")) {
                 StringBuilder builder = new StringBuilder(64);
                 builder.append(scheme);
                 builder.append(':');
diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java
deleted file mode 100644
index 2ecf317..0000000
--- a/core/java/android/os/CommonClock.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.os;
-
-import java.net.InetSocketAddress;
-import java.util.NoSuchElementException;
-import android.os.Binder;
-import android.os.CommonTimeUtils;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-/**
- * Used for accessing the android common time service's common clock and receiving notifications
- * about common time synchronization status changes.
- * @hide
- */
-public class CommonClock {
-    /**
-     * Sentinel value returned by {@link #getTime()} and {@link #getEstimatedError()} when the
-     * common time service is not able to determine the current common time due to a lack of
-     * synchronization.
-     */
-    public static final long TIME_NOT_SYNCED = -1;
-
-    /**
-     * Sentinel value returned by {@link #getTimelineId()} when the common time service is not
-     * currently synced to any timeline.
-     */
-    public static final long INVALID_TIMELINE_ID = 0;
-
-    /**
-     * Sentinel value returned by {@link #getEstimatedError()} when the common time service is not
-     * currently synced to any timeline.
-     */
-    public static final int ERROR_ESTIMATE_UNKNOWN = 0x7FFFFFFF;
-
-    /**
-     * Value used by {@link #getState()} to indicate that there was an internal error while
-     * attempting to determine the state of the common time service.
-     */
-    public static final int STATE_INVALID = -1;
-
-    /**
-     * Value used by {@link #getState()} to indicate that the common time service is in its initial
-     * state and attempting to find the current timeline master, if any.  The service will
-     * transition to either {@link #STATE_CLIENT} if it finds an active master, or to
-     * {@link #STATE_MASTER} if no active master is found and this client becomes the master of a
-     * new timeline.
-     */
-    public static final int STATE_INITIAL = 0;
-
-    /**
-     * Value used by {@link #getState()} to indicate that the common time service is in its client
-     * state and is synchronizing its time to a different timeline master on the network.
-     */
-    public static final int STATE_CLIENT = 1;
-
-    /**
-     * Value used by {@link #getState()} to indicate that the common time service is in its master
-     * state and is serving as the timeline master for other common time service clients on the
-     * network.
-     */
-    public static final int STATE_MASTER = 2;
-
-    /**
-     * Value used by {@link #getState()} to indicate that the common time service is in its Ronin
-     * state.  Common time service instances in the client state enter the Ronin state after their
-     * timeline master becomes unreachable on the network.  Common time services who enter the Ronin
-     * state will begin a new master election for the timeline they were recently clients of.  As
-     * clients detect they are not the winner and drop out of the election, they will transition to
-     * the {@link #STATE_WAIT_FOR_ELECTION} state.  When there is only one client remaining in the
-     * election, it will assume ownership of the timeline and transition to the
-     * {@link #STATE_MASTER} state.  During the election, all clients will allow their timeline to
-     * drift without applying correction.
-     */
-    public static final int STATE_RONIN = 3;
-
-    /**
-     * Value used by {@link #getState()} to indicate that the common time service is waiting for a
-     * master election to conclude and for the new master to announce itself before transitioning to
-     * the {@link #STATE_CLIENT} state.  If no new master announces itself within the timeout
-     * threshold, the time service will transition back to the {@link #STATE_RONIN} state in order
-     * to restart the election.
-     */
-    public static final int STATE_WAIT_FOR_ELECTION = 4;
-
-    /**
-     * Name of the underlying native binder service
-     */
-    public static final String SERVICE_NAME = "common_time.clock";
-
-    /**
-     * Class constructor.
-     * @throws android.os.RemoteException
-     */
-    public CommonClock()
-    throws RemoteException {
-        mRemote = ServiceManager.getService(SERVICE_NAME);
-        if (null == mRemote)
-            throw new RemoteException();
-
-        mInterfaceDesc = mRemote.getInterfaceDescriptor();
-        mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
-        mRemote.linkToDeath(mDeathHandler, 0);
-        registerTimelineChangeListener();
-    }
-
-    /**
-     * Handy class factory method.
-     */
-    static public CommonClock create() {
-        CommonClock retVal;
-
-        try {
-            retVal = new CommonClock();
-        }
-        catch (RemoteException e) {
-            retVal = null;
-        }
-
-        return retVal;
-    }
-
-    /**
-     * Release all native resources held by this {@link android.os.CommonClock} instance.  Once
-     * resources have been released, the {@link android.os.CommonClock} instance is disconnected from
-     * the native service and will throw a {@link android.os.RemoteException} if any of its
-     * methods are called.  Clients should always call release on their client instances before
-     * releasing their last Java reference to the instance.  Failure to do this will cause
-     * non-deterministic native resource reclamation and may cause the common time service to remain
-     * active on the network for longer than it should.
-     */
-    public void release() {
-        unregisterTimelineChangeListener();
-        if (null != mRemote) {
-            try {
-                mRemote.unlinkToDeath(mDeathHandler, 0);
-            }
-            catch (NoSuchElementException e) { }
-            mRemote = null;
-        }
-        mUtils = null;
-    }
-
-    /**
-     * Gets the common clock's current time.
-     *
-     * @return a signed 64-bit value representing the current common time in microseconds, or the
-     * special value {@link #TIME_NOT_SYNCED} if the common time service is currently not
-     * synchronized.
-     * @throws android.os.RemoteException
-     */
-    public long getTime()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetLong(METHOD_GET_COMMON_TIME, TIME_NOT_SYNCED);
-    }
-
-    /**
-     * Gets the current estimation of common clock's synchronization accuracy from the common time
-     * service.
-     *
-     * @return a signed 32-bit value representing the common time service's estimation of
-     * synchronization accuracy in microseconds, or the special value
-     * {@link #ERROR_ESTIMATE_UNKNOWN} if the common time service is currently not synchronized.
-     * Negative values indicate that the local server estimates that the nominal common time is
-     * behind the local server's time (in other words, the local clock is running fast) Positive
-     * values indicate that the local server estimates that the nominal common time is ahead of the
-     * local server's time (in other words, the local clock is running slow)
-     * @throws android.os.RemoteException
-     */
-    public int getEstimatedError()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetInt(METHOD_GET_ESTIMATED_ERROR, ERROR_ESTIMATE_UNKNOWN);
-    }
-
-    /**
-     * Gets the ID of the timeline the common time service is currently synchronizing its clock to.
-     *
-     * @return a long representing the unique ID of the timeline the common time service is
-     * currently synchronizing with, or {@link #INVALID_TIMELINE_ID} if the common time service is
-     * currently not synchronized.
-     * @throws android.os.RemoteException
-     */
-    public long getTimelineId()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetLong(METHOD_GET_TIMELINE_ID, INVALID_TIMELINE_ID);
-    }
-
-    /**
-     * Gets the current state of this clock's common time service in the the master election
-     * algorithm.
-     *
-     * @return a integer indicating the current state of the this clock's common time service in the
-     * master election algorithm or {@link #STATE_INVALID} if there is an internal error.
-     * @throws android.os.RemoteException
-     */
-    public int getState()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetInt(METHOD_GET_STATE, STATE_INVALID);
-    }
-
-    /**
-     * Gets the IP address and UDP port of the current timeline master.
-     *
-     * @return an InetSocketAddress containing the IP address and UDP port of the current timeline
-     * master, or null if there is no current master.
-     * @throws android.os.RemoteException
-     */
-    public InetSocketAddress getMasterAddr()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ADDRESS);
-    }
-
-    /**
-     * The OnTimelineChangedListener interface defines a method called by the
-     * {@link android.os.CommonClock} instance to indicate that the time synchronization service has
-     * either synchronized with a new timeline, or is no longer a member of any timeline.  The
-     * client application can implement this interface and register the listener with the
-     * {@link #setTimelineChangedListener(OnTimelineChangedListener)} method.
-     */
-    public interface OnTimelineChangedListener  {
-        /**
-         * Method called when the time service's timeline has changed.
-         *
-         * @param newTimelineId a long which uniquely identifies the timeline the time
-         * synchronization service is now a member of, or {@link #INVALID_TIMELINE_ID} if the the
-         * service is not synchronized to any timeline.
-         */
-        void onTimelineChanged(long newTimelineId);
-    }
-
-    /**
-     * Registers an OnTimelineChangedListener interface.
-     * <p>Call this method with a null listener to stop receiving server death notifications.
-     */
-    public void setTimelineChangedListener(OnTimelineChangedListener listener) {
-        synchronized (mListenerLock) {
-            mTimelineChangedListener = listener;
-        }
-    }
-
-    /**
-     * The OnServerDiedListener interface defines a method called by the
-     * {@link android.os.CommonClock} instance to indicate that the connection to the native media
-     * server has been broken and that the {@link android.os.CommonClock} instance will need to be
-     * released and re-created.  The client application can implement this interface and register
-     * the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
-     */
-    public interface OnServerDiedListener  {
-        /**
-         * Method called when the native media server has died.  <p>If the native common time
-         * service encounters a fatal error and needs to restart, the binder connection from the
-         * {@link android.os.CommonClock} instance to the common time service will be broken.  To
-         * restore functionality, clients should {@link #release()} their old visualizer and create
-         * a new instance.
-         */
-        void onServerDied();
-    }
-
-    /**
-     * Registers an OnServerDiedListener interface.
-     * <p>Call this method with a null listener to stop receiving server death notifications.
-     */
-    public void setServerDiedListener(OnServerDiedListener listener) {
-        synchronized (mListenerLock) {
-            mServerDiedListener = listener;
-        }
-    }
-
-    protected void finalize() throws Throwable { release(); }
-
-    private void throwOnDeadServer() throws RemoteException {
-        if ((null == mRemote) || (null == mUtils))
-            throw new RemoteException();
-    }
-
-    private final Object mListenerLock = new Object();
-    private OnTimelineChangedListener mTimelineChangedListener = null;
-    private OnServerDiedListener mServerDiedListener = null;
-
-    private IBinder mRemote = null;
-    private String mInterfaceDesc = "";
-    private CommonTimeUtils mUtils;
-
-    private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
-        public void binderDied() {
-            synchronized (mListenerLock) {
-                if (null != mServerDiedListener)
-                    mServerDiedListener.onServerDied();
-            }
-        }
-    };
-
-    private class TimelineChangedListener extends Binder {
-        @Override
-        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-        throws RemoteException {
-            switch (code) {
-                case METHOD_CBK_ON_TIMELINE_CHANGED:
-                    data.enforceInterface(DESCRIPTOR);
-                    long timelineId = data.readLong();
-                    synchronized (mListenerLock) {
-                        if (null != mTimelineChangedListener)
-                            mTimelineChangedListener.onTimelineChanged(timelineId);
-                    }
-                    return true;
-            }
-
-            return super.onTransact(code, data, reply, flags);
-        }
-
-        private static final String DESCRIPTOR = "android.os.ICommonClockListener";
-    };
-
-    private TimelineChangedListener mCallbackTgt = null;
-
-    private void registerTimelineChangeListener() throws RemoteException {
-        if (null != mCallbackTgt)
-            return;
-
-        boolean success = false;
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-        mCallbackTgt = new TimelineChangedListener();
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-            data.writeStrongBinder(mCallbackTgt);
-            mRemote.transact(METHOD_REGISTER_LISTENER, data, reply, 0);
-            success = (0 == reply.readInt());
-        }
-        catch (RemoteException e) {
-            success = false;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-
-        // Did we catch a remote exception or fail to register our callback target?  If so, our
-        // object must already be dead (or be as good as dead).  Clear out all of our state so that
-        // our other methods will properly indicate a dead object.
-        if (!success) {
-            mCallbackTgt = null;
-            mRemote = null;
-            mUtils = null;
-        }
-    }
-
-    private void unregisterTimelineChangeListener() {
-        if (null == mCallbackTgt)
-            return;
-
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-            data.writeStrongBinder(mCallbackTgt);
-            mRemote.transact(METHOD_UNREGISTER_LISTENER, data, reply, 0);
-        }
-        catch (RemoteException e) { }
-        finally {
-            reply.recycle();
-            data.recycle();
-            mCallbackTgt = null;
-        }
-    }
-
-    private static final int METHOD_IS_COMMON_TIME_VALID = IBinder.FIRST_CALL_TRANSACTION;
-    private static final int METHOD_COMMON_TIME_TO_LOCAL_TIME = METHOD_IS_COMMON_TIME_VALID + 1;
-    private static final int METHOD_LOCAL_TIME_TO_COMMON_TIME = METHOD_COMMON_TIME_TO_LOCAL_TIME + 1;
-    private static final int METHOD_GET_COMMON_TIME = METHOD_LOCAL_TIME_TO_COMMON_TIME + 1;
-    private static final int METHOD_GET_COMMON_FREQ = METHOD_GET_COMMON_TIME + 1;
-    private static final int METHOD_GET_LOCAL_TIME = METHOD_GET_COMMON_FREQ + 1;
-    private static final int METHOD_GET_LOCAL_FREQ = METHOD_GET_LOCAL_TIME + 1;
-    private static final int METHOD_GET_ESTIMATED_ERROR = METHOD_GET_LOCAL_FREQ + 1;
-    private static final int METHOD_GET_TIMELINE_ID = METHOD_GET_ESTIMATED_ERROR + 1;
-    private static final int METHOD_GET_STATE = METHOD_GET_TIMELINE_ID + 1;
-    private static final int METHOD_GET_MASTER_ADDRESS = METHOD_GET_STATE + 1;
-    private static final int METHOD_REGISTER_LISTENER = METHOD_GET_MASTER_ADDRESS + 1;
-    private static final int METHOD_UNREGISTER_LISTENER = METHOD_REGISTER_LISTENER + 1;
-
-    private static final int METHOD_CBK_ON_TIMELINE_CHANGED = IBinder.FIRST_CALL_TRANSACTION;
-}
diff --git a/core/java/android/os/CommonTimeConfig.java b/core/java/android/os/CommonTimeConfig.java
deleted file mode 100644
index 1f9fab5..0000000
--- a/core/java/android/os/CommonTimeConfig.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.os;
-
-import java.net.InetSocketAddress;
-import java.util.NoSuchElementException;
-
-import android.os.CommonTimeUtils;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-/**
- * Used for configuring and controlling the status of the android common time service.
- * @hide
- */
-public class CommonTimeConfig {
-    /**
-     * Successful operation.
-     */
-    public static final int SUCCESS = 0;
-    /**
-     * Unspecified error.
-     */
-    public static final int ERROR = -1;
-    /**
-     * Operation failed due to bad parameter value.
-     */
-    public static final int ERROR_BAD_VALUE = -4;
-    /**
-     * Operation failed due to dead remote object.
-     */
-    public static final int ERROR_DEAD_OBJECT = -7;
-
-    /**
-     * Sentinel value returned by {@link #getMasterElectionGroupId()} when an error occurs trying to
-     * fetch the master election group.
-     */
-    public static final long INVALID_GROUP_ID = -1;
-
-    /**
-     * Name of the underlying native binder service
-     */
-    public static final String SERVICE_NAME = "common_time.config";
-
-    /**
-     * Class constructor.
-     * @throws android.os.RemoteException
-     */
-    public CommonTimeConfig()
-    throws RemoteException {
-        mRemote = ServiceManager.getService(SERVICE_NAME);
-        if (null == mRemote)
-            throw new RemoteException();
-
-        mInterfaceDesc = mRemote.getInterfaceDescriptor();
-        mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
-        mRemote.linkToDeath(mDeathHandler, 0);
-    }
-
-    /**
-     * Handy class factory method.
-     */
-    static public CommonTimeConfig create() {
-        CommonTimeConfig retVal;
-
-        try {
-            retVal = new CommonTimeConfig();
-        }
-        catch (RemoteException e) {
-            retVal = null;
-        }
-
-        return retVal;
-    }
-
-    /**
-     * Release all native resources held by this {@link android.os.CommonTimeConfig} instance.  Once
-     * resources have been released, the {@link android.os.CommonTimeConfig} instance is
-     * disconnected from the native service and will throw a {@link android.os.RemoteException} if
-     * any of its methods are called.  Clients should always call release on their client instances
-     * before releasing their last Java reference to the instance.  Failure to do this will cause
-     * non-deterministic native resource reclamation and may cause the common time service to remain
-     * active on the network for longer than it should.
-     */
-    public void release() {
-        if (null != mRemote) {
-            try {
-                mRemote.unlinkToDeath(mDeathHandler, 0);
-            }
-            catch (NoSuchElementException e) { }
-            mRemote = null;
-        }
-        mUtils = null;
-    }
-
-    /**
-     * Gets the current priority of the common time service used in the master election protocol.
-     *
-     * @return an 8 bit value indicating the priority of this common time service relative to other
-     * common time services operating in the same domain.
-     * @throws android.os.RemoteException
-     */
-    public byte getMasterElectionPriority()
-    throws RemoteException {
-        throwOnDeadServer();
-        return (byte)mUtils.transactGetInt(METHOD_GET_MASTER_ELECTION_PRIORITY, -1);
-    }
-
-    /**
-     * Sets the current priority of the common time service used in the master election protocol.
-     *
-     * @param priority priority of the common time service used in the master election protocol.
-     * Lower numbers are lower priority.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setMasterElectionPriority(byte priority) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-        return mUtils.transactSetInt(METHOD_SET_MASTER_ELECTION_PRIORITY, priority);
-    }
-
-    /**
-     * Gets the IP endpoint used by the time service to participate in the master election protocol.
-     *
-     * @return an InetSocketAddress containing the IP address and UDP port being used by the
-     * system's common time service to participate in the master election protocol.
-     * @throws android.os.RemoteException
-     */
-    public InetSocketAddress getMasterElectionEndpoint()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ELECTION_ENDPOINT);
-    }
-
-    /**
-     * Sets the IP endpoint used by the common time service to participate in the master election
-     * protocol.
-     *
-     * @param ep The IP address and UDP port to be used by the common time service to participate in
-     * the master election protocol.  The supplied IP address must be either the broadcast or
-     * multicast address, unicast addresses are considered to be illegal values.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setMasterElectionEndpoint(InetSocketAddress ep) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-        return mUtils.transactSetSockaddr(METHOD_SET_MASTER_ELECTION_ENDPOINT, ep);
-    }
-
-    /**
-     * Gets the current group ID used by the common time service in the master election protocol.
-     *
-     * @return The 64-bit group ID of the common time service.
-     * @throws android.os.RemoteException
-     */
-    public long getMasterElectionGroupId()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetLong(METHOD_GET_MASTER_ELECTION_GROUP_ID, INVALID_GROUP_ID);
-    }
-
-    /**
-     * Sets the current group ID used by the common time service in the master election protocol.
-     *
-     * @param id The 64-bit group ID of the common time service.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setMasterElectionGroupId(long id) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-        return mUtils.transactSetLong(METHOD_SET_MASTER_ELECTION_GROUP_ID, id);
-    }
-
-    /**
-     * Gets the name of the network interface which the common time service attempts to bind to.
-     *
-     * @return a string with the network interface name which the common time service is bound to,
-     * or null if the service is currently unbound.  Examples of interface names are things like
-     * "eth0", or "wlan0".
-     * @throws android.os.RemoteException
-     */
-    public String getInterfaceBinding()
-    throws RemoteException {
-        throwOnDeadServer();
-
-        String ifaceName = mUtils.transactGetString(METHOD_GET_INTERFACE_BINDING, null);
-
-        if ((null != ifaceName) && (0 == ifaceName.length()))
-                return null;
-
-        return ifaceName;
-    }
-
-    /**
-     * Sets the name of the network interface which the common time service should attempt to bind
-     * to.
-     *
-     * @param ifaceName The name of the network interface ("eth0", "wlan0", etc...) wich the common
-     * time service should attempt to bind to, or null to force the common time service to unbind
-     * from the network and run in networkless mode.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setNetworkBinding(String ifaceName) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-
-        return mUtils.transactSetString(METHOD_SET_INTERFACE_BINDING,
-                                       (null == ifaceName) ? "" : ifaceName);
-    }
-
-    /**
-     * Gets the amount of time the common time service will wait between master announcements when
-     * it is the timeline master.
-     *
-     * @return The time (in milliseconds) between master announcements.
-     * @throws android.os.RemoteException
-     */
-    public int getMasterAnnounceInterval()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetInt(METHOD_GET_MASTER_ANNOUNCE_INTERVAL, -1);
-    }
-
-    /**
-     * Sets the amount of time the common time service will wait between master announcements when
-     * it is the timeline master.
-     *
-     * @param interval The time (in milliseconds) between master announcements.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setMasterAnnounceInterval(int interval) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-        return mUtils.transactSetInt(METHOD_SET_MASTER_ANNOUNCE_INTERVAL, interval);
-    }
-
-    /**
-     * Gets the amount of time the common time service will wait between time synchronization
-     * requests when it is the client of another common time service on the network.
-     *
-     * @return The time (in milliseconds) between time sync requests.
-     * @throws android.os.RemoteException
-     */
-    public int getClientSyncInterval()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetInt(METHOD_GET_CLIENT_SYNC_INTERVAL, -1);
-    }
-
-    /**
-     * Sets the amount of time the common time service will wait between time synchronization
-     * requests when it is the client of another common time service on the network.
-     *
-     * @param interval The time (in milliseconds) between time sync requests.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setClientSyncInterval(int interval) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-        return mUtils.transactSetInt(METHOD_SET_CLIENT_SYNC_INTERVAL, interval);
-    }
-
-    /**
-     * Gets the panic threshold for the estimated error level of the common time service.  When the
-     * common time service's estimated error rises above this level, the service will panic and
-     * reset, causing a discontinuity in the currently synchronized timeline.
-     *
-     * @return The threshold (in microseconds) past which the common time service will panic.
-     * @throws android.os.RemoteException
-     */
-    public int getPanicThreshold()
-    throws RemoteException {
-        throwOnDeadServer();
-        return mUtils.transactGetInt(METHOD_GET_PANIC_THRESHOLD, -1);
-    }
-
-    /**
-     * Sets the panic threshold for the estimated error level of the common time service.  When the
-     * common time service's estimated error rises above this level, the service will panic and
-     * reset, causing a discontinuity in the currently synchronized timeline.
-     *
-     * @param threshold The threshold (in microseconds) past which the common time service will
-     * panic.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setPanicThreshold(int threshold) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-        return mUtils.transactSetInt(METHOD_SET_PANIC_THRESHOLD, threshold);
-    }
-
-    /**
-     * Gets the current state of the common time service's auto disable flag.
-     *
-     * @return The current state of the common time service's auto disable flag.
-     * @throws android.os.RemoteException
-     */
-    public boolean getAutoDisable()
-    throws RemoteException {
-        throwOnDeadServer();
-        return (1 == mUtils.transactGetInt(METHOD_GET_AUTO_DISABLE, 1));
-    }
-
-    /**
-     * Sets the current state of the common time service's auto disable flag.  When the time
-     * service's auto disable flag is set, it will automatically cease all network activity when
-     * it has no active local clients, resuming activity the next time the service has interested
-     * local clients.  When the auto disabled flag is cleared, the common time service will continue
-     * to participate the time synchronization group even when it has no active local clients.
-     *
-     * @param autoDisable The desired state of the common time service's auto disable flag.
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int setAutoDisable(boolean autoDisable) {
-        if (checkDeadServer())
-            return ERROR_DEAD_OBJECT;
-
-        return mUtils.transactSetInt(METHOD_SET_AUTO_DISABLE, autoDisable ? 1 : 0);
-    }
-
-    /**
-     * At startup, the time service enters the initial state and remains there until it is given a
-     * network interface to bind to.  Common time will be unavailable to clients of the common time
-     * service until the service joins a network (even an empty network).  Devices may use the
-     * {@link #forceNetworklessMasterMode()} method to force a time service in the INITIAL state
-     * with no network configuration to assume MASTER status for a brand new timeline in order to
-     * allow clients of the common time service to operate, even though the device is isolated and
-     * not on any network.  When a networkless master does join a network, it will defer to any
-     * masters already on the network, or continue to maintain the timeline it made up during its
-     * networkless state if no other masters are detected.  Attempting to force a client into master
-     * mode while it is actively bound to a network will fail with the status code {@link #ERROR}
-     *
-     * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
-     */
-    public int forceNetworklessMasterMode() {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-            mRemote.transact(METHOD_FORCE_NETWORKLESS_MASTER_MODE, data, reply, 0);
-
-            return reply.readInt();
-        }
-        catch (RemoteException e) {
-            return ERROR_DEAD_OBJECT;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    /**
-     * The OnServerDiedListener interface defines a method called by the
-     * {@link android.os.CommonTimeConfig} instance to indicate that the connection to the native
-     * media server has been broken and that the {@link android.os.CommonTimeConfig} instance will
-     * need to be released and re-created.  The client application can implement this interface and
-     * register the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
-     */
-    public interface OnServerDiedListener  {
-        /**
-         * Method called when the native common time service has died.  <p>If the native common time
-         * service encounters a fatal error and needs to restart, the binder connection from the
-         * {@link android.os.CommonTimeConfig} instance to the common time service will be broken.
-         */
-        void onServerDied();
-    }
-
-    /**
-     * Registers an OnServerDiedListener interface.
-     * <p>Call this method with a null listener to stop receiving server death notifications.
-     */
-    public void setServerDiedListener(OnServerDiedListener listener) {
-        synchronized (mListenerLock) {
-            mServerDiedListener = listener;
-        }
-    }
-
-    protected void finalize() throws Throwable { release(); }
-
-    private boolean checkDeadServer() {
-        return ((null == mRemote) || (null == mUtils));
-    }
-
-    private void throwOnDeadServer() throws RemoteException {
-        if (checkDeadServer())
-            throw new RemoteException();
-    }
-
-    private final Object mListenerLock = new Object();
-    private OnServerDiedListener mServerDiedListener = null;
-
-    private IBinder mRemote = null;
-    private String mInterfaceDesc = "";
-    private CommonTimeUtils mUtils;
-
-    private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
-        public void binderDied() {
-            synchronized (mListenerLock) {
-                if (null != mServerDiedListener)
-                    mServerDiedListener.onServerDied();
-            }
-        }
-    };
-
-    private static final int METHOD_GET_MASTER_ELECTION_PRIORITY = IBinder.FIRST_CALL_TRANSACTION;
-    private static final int METHOD_SET_MASTER_ELECTION_PRIORITY = METHOD_GET_MASTER_ELECTION_PRIORITY + 1;
-    private static final int METHOD_GET_MASTER_ELECTION_ENDPOINT = METHOD_SET_MASTER_ELECTION_PRIORITY + 1;
-    private static final int METHOD_SET_MASTER_ELECTION_ENDPOINT = METHOD_GET_MASTER_ELECTION_ENDPOINT + 1;
-    private static final int METHOD_GET_MASTER_ELECTION_GROUP_ID = METHOD_SET_MASTER_ELECTION_ENDPOINT + 1;
-    private static final int METHOD_SET_MASTER_ELECTION_GROUP_ID = METHOD_GET_MASTER_ELECTION_GROUP_ID + 1;
-    private static final int METHOD_GET_INTERFACE_BINDING = METHOD_SET_MASTER_ELECTION_GROUP_ID + 1;
-    private static final int METHOD_SET_INTERFACE_BINDING = METHOD_GET_INTERFACE_BINDING + 1;
-    private static final int METHOD_GET_MASTER_ANNOUNCE_INTERVAL = METHOD_SET_INTERFACE_BINDING + 1;
-    private static final int METHOD_SET_MASTER_ANNOUNCE_INTERVAL = METHOD_GET_MASTER_ANNOUNCE_INTERVAL + 1;
-    private static final int METHOD_GET_CLIENT_SYNC_INTERVAL = METHOD_SET_MASTER_ANNOUNCE_INTERVAL + 1;
-    private static final int METHOD_SET_CLIENT_SYNC_INTERVAL = METHOD_GET_CLIENT_SYNC_INTERVAL + 1;
-    private static final int METHOD_GET_PANIC_THRESHOLD = METHOD_SET_CLIENT_SYNC_INTERVAL + 1;
-    private static final int METHOD_SET_PANIC_THRESHOLD = METHOD_GET_PANIC_THRESHOLD + 1;
-    private static final int METHOD_GET_AUTO_DISABLE = METHOD_SET_PANIC_THRESHOLD + 1;
-    private static final int METHOD_SET_AUTO_DISABLE = METHOD_GET_AUTO_DISABLE + 1;
-    private static final int METHOD_FORCE_NETWORKLESS_MASTER_MODE = METHOD_SET_AUTO_DISABLE + 1;
-}
diff --git a/core/java/android/os/CommonTimeUtils.java b/core/java/android/os/CommonTimeUtils.java
deleted file mode 100644
index ba060b8..0000000
--- a/core/java/android/os/CommonTimeUtils.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.os;
-
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetSocketAddress;
-import java.util.Locale;
-import static android.system.OsConstants.*;
-
-class CommonTimeUtils {
-    /**
-     * Successful operation.
-     */
-    public static final int SUCCESS = 0;
-    /**
-     * Unspecified error.
-     */
-    public static final int ERROR = -1;
-    /**
-     * Operation failed due to bad parameter value.
-     */
-    public static final int ERROR_BAD_VALUE = -4;
-    /**
-     * Operation failed due to dead remote object.
-     */
-    public static final int ERROR_DEAD_OBJECT = -7;
-
-    public CommonTimeUtils(IBinder remote, String interfaceDesc) {
-        mRemote = remote;
-        mInterfaceDesc = interfaceDesc;
-    }
-
-    public int transactGetInt(int method_code, int error_ret_val)
-    throws RemoteException {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-        int ret_val;
-
-        try {
-            int res;
-            data.writeInterfaceToken(mInterfaceDesc);
-            mRemote.transact(method_code, data, reply, 0);
-
-            res = reply.readInt();
-            ret_val = (0 == res) ? reply.readInt() : error_ret_val;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-
-        return ret_val;
-    }
-
-    public int transactSetInt(int method_code, int val) {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-            data.writeInt(val);
-            mRemote.transact(method_code, data, reply, 0);
-
-            return reply.readInt();
-        }
-        catch (RemoteException e) {
-            return ERROR_DEAD_OBJECT;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    public long transactGetLong(int method_code, long error_ret_val)
-    throws RemoteException {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-        long ret_val;
-
-        try {
-            int res;
-            data.writeInterfaceToken(mInterfaceDesc);
-            mRemote.transact(method_code, data, reply, 0);
-
-            res = reply.readInt();
-            ret_val = (0 == res) ? reply.readLong() : error_ret_val;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-
-        return ret_val;
-    }
-
-    public int transactSetLong(int method_code, long val) {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-            data.writeLong(val);
-            mRemote.transact(method_code, data, reply, 0);
-
-            return reply.readInt();
-        }
-        catch (RemoteException e) {
-            return ERROR_DEAD_OBJECT;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    public String transactGetString(int method_code, String error_ret_val)
-    throws RemoteException {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-        String ret_val;
-
-        try {
-            int res;
-            data.writeInterfaceToken(mInterfaceDesc);
-            mRemote.transact(method_code, data, reply, 0);
-
-            res = reply.readInt();
-            ret_val = (0 == res) ? reply.readString() : error_ret_val;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-
-        return ret_val;
-    }
-
-    public int transactSetString(int method_code, String val) {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-            data.writeString(val);
-            mRemote.transact(method_code, data, reply, 0);
-
-            return reply.readInt();
-        }
-        catch (RemoteException e) {
-            return ERROR_DEAD_OBJECT;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    public InetSocketAddress transactGetSockaddr(int method_code)
-    throws RemoteException {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-        InetSocketAddress ret_val = null;
-
-        try {
-            int res;
-            data.writeInterfaceToken(mInterfaceDesc);
-            mRemote.transact(method_code, data, reply, 0);
-
-            res = reply.readInt();
-            if (0 == res) {
-                int type;
-                int port = 0;
-                String addrStr = null;
-
-                type = reply.readInt();
-
-                if (AF_INET == type) {
-                    int addr = reply.readInt();
-                    port = reply.readInt();
-                    addrStr = String.format(Locale.US, "%d.%d.%d.%d",
-                                                       (addr >> 24) & 0xFF,
-                                                       (addr >> 16) & 0xFF,
-                                                       (addr >>  8) & 0xFF,
-                                                        addr        & 0xFF);
-                } else if (AF_INET6 == type) {
-                    int addr1 = reply.readInt();
-                    int addr2 = reply.readInt();
-                    int addr3 = reply.readInt();
-                    int addr4 = reply.readInt();
-
-                    port = reply.readInt();
-
-                    int flowinfo = reply.readInt();
-                    int scope_id = reply.readInt();
-
-                    addrStr = String.format(Locale.US, "[%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X]",
-                                                       (addr1 >> 16) & 0xFFFF, addr1 & 0xFFFF,
-                                                       (addr2 >> 16) & 0xFFFF, addr2 & 0xFFFF,
-                                                       (addr3 >> 16) & 0xFFFF, addr3 & 0xFFFF,
-                                                       (addr4 >> 16) & 0xFFFF, addr4 & 0xFFFF);
-                }
-
-                if (null != addrStr) {
-                    ret_val = new InetSocketAddress(addrStr, port);
-                }
-            }
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-
-        return ret_val;
-    }
-
-    public int transactSetSockaddr(int method_code, InetSocketAddress addr) {
-        android.os.Parcel data  = android.os.Parcel.obtain();
-        android.os.Parcel reply = android.os.Parcel.obtain();
-        int ret_val = ERROR;
-
-        try {
-            data.writeInterfaceToken(mInterfaceDesc);
-
-            if (null == addr) {
-                data.writeInt(0);
-            } else {
-                data.writeInt(1);
-                final InetAddress a = addr.getAddress();
-                final byte[]      b = a.getAddress();
-                final int         p = addr.getPort();
-
-                if (a instanceof Inet4Address) {
-                    int v4addr = (((int)b[0] & 0xFF) << 24) |
-                                 (((int)b[1] & 0xFF) << 16) |
-                                 (((int)b[2] & 0xFF) << 8) |
-                                  ((int)b[3] & 0xFF);
-
-                    data.writeInt(AF_INET);
-                    data.writeInt(v4addr);
-                    data.writeInt(p);
-                } else
-                if (a instanceof Inet6Address) {
-                    int i;
-                    Inet6Address v6 = (Inet6Address)a;
-                    data.writeInt(AF_INET6);
-                    for (i = 0; i < 4; ++i) {
-                        int aword = (((int)b[(i*4) + 0] & 0xFF) << 24) |
-                                    (((int)b[(i*4) + 1] & 0xFF) << 16) |
-                                    (((int)b[(i*4) + 2] & 0xFF) << 8) |
-                                     ((int)b[(i*4) + 3] & 0xFF);
-                        data.writeInt(aword);
-                    }
-                    data.writeInt(p);
-                    data.writeInt(0);   // flow info
-                    data.writeInt(v6.getScopeId());
-                } else {
-                    return ERROR_BAD_VALUE;
-                }
-            }
-
-            mRemote.transact(method_code, data, reply, 0);
-            ret_val = reply.readInt();
-        }
-        catch (RemoteException e) {
-            ret_val = ERROR_DEAD_OBJECT;
-        }
-        finally {
-            reply.recycle();
-            data.recycle();
-        }
-
-        return ret_val;
-    }
-
-    private IBinder mRemote;
-    private String mInterfaceDesc;
-};
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/core/java/android/os/ParcelFileDescriptor.aidl
index 6bbd99e..c07b980 100644
--- a/core/java/android/os/ParcelFileDescriptor.aidl
+++ b/core/java/android/os/ParcelFileDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.os;
 
-parcelable ParcelFileDescriptor cpp_header "android/os/parcel_file_descriptor.h";
+parcelable ParcelFileDescriptor cpp_header "binder/ParcelFileDescriptor.h";
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index a21e05e..932f0c2 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -318,7 +318,9 @@
      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
      */
     public File getInternalPathForUser(int userId) {
-        if (type == TYPE_PUBLIC) {
+        if (path == null) {
+            return null;
+        } else if (type == TYPE_PUBLIC) {
             // TODO: plumb through cleaner path from vold
             return new File(path.replace("/storage/", "/mnt/media_rw/"));
         } else {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 3e64af4..aca2bb8 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -333,8 +333,16 @@
     }
 
     /**
-     * String.split() returns [''] when the string to be split is empty. This returns []. This does
-     * not remove any empty strings from the result. For example split("a,", ","  ) returns {"a", ""}.
+     *
+     * This method yields the same result as {@code text.split(expression, -1)} except that if
+     * {@code text.isEmpty()} then this method returns an empty array whereas
+     * {@code "".split(expression, -1)} would have returned an array with a single {@code ""}.
+     *
+     * The {@code -1} means that trailing empty Strings are not removed from the result; for
+     * example split("a,", ","  ) returns {"a", ""}. Note that whether a leading zero-width match
+     * can result in a leading {@code ""} depends on whether your app
+     * {@link android.content.pm.ApplicationInfo#targetSdkVersion targets an SDK version}
+     * {@code <= 28}; see {@link Pattern#split(CharSequence, int)}.
      *
      * @param text the string to split
      * @param expression the regular expression to match
@@ -351,8 +359,16 @@
     }
 
     /**
-     * Splits a string on a pattern. String.split() returns [''] when the string to be
-     * split is empty. This returns []. This does not remove any empty strings from the result.
+     * Splits a string on a pattern. This method yields the same result as
+     * {@code pattern.split(text, -1)} except that if {@code text.isEmpty()} then this method
+     * returns an empty array whereas {@code pattern.split("", -1)} would have returned an array
+     * with a single {@code ""}.
+     *
+     * The {@code -1} means that trailing empty Strings are not removed from the result;
+     * Note that whether a leading zero-width match can result in a leading {@code ""} depends
+     * on whether your app {@link android.content.pm.ApplicationInfo#targetSdkVersion targets
+     * an SDK version} {@code <= 28}; see {@link Pattern#split(CharSequence, int)}.
+     *
      * @param text the string to split
      * @param pattern the regular expression to match
      * @return an array of strings. The array will be empty if text is empty
diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/util/TimestampedValue.java
new file mode 100644
index 0000000..1289e4d
--- /dev/null
+++ b/core/java/android/util/TimestampedValue.java
@@ -0,0 +1,137 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.SystemClock;
+
+import java.util.Objects;
+
+/**
+ * A value with an associated reference time. The reference time will typically be provided by the
+ * elapsed realtime clock. The elapsed realtime clock can be obtained using methods like
+ * {@link SystemClock#elapsedRealtime()} or {@link SystemClock#elapsedRealtimeClock()}.
+ * If a suitable clock is used the reference time can be used to identify the age of a value or
+ * ordering between values.
+ *
+ * <p>To read and write a timestamped value from / to a Parcel see
+ * {@link #readFromParcel(Parcel, ClassLoader, Class)} and
+ * {@link #writeToParcel(Parcel, TimestampedValue)}.
+ *
+ * @param <T> the type of the value with an associated timestamp
+ * @hide
+ */
+public final class TimestampedValue<T> {
+    private final long mReferenceTimeMillis;
+    private final T mValue;
+
+    public TimestampedValue(long referenceTimeMillis, T value) {
+        mReferenceTimeMillis = referenceTimeMillis;
+        mValue = value;
+    }
+
+    public long getReferenceTimeMillis() {
+        return mReferenceTimeMillis;
+    }
+
+    public T getValue() {
+        return mValue;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        TimestampedValue<?> that = (TimestampedValue<?>) o;
+        return mReferenceTimeMillis == that.mReferenceTimeMillis
+                && Objects.equals(mValue, that.mValue);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mReferenceTimeMillis, mValue);
+    }
+
+    @Override
+    public String toString() {
+        return "TimestampedValue{"
+                + "mReferenceTimeMillis=" + mReferenceTimeMillis
+                + ", mValue=" + mValue
+                + '}';
+    }
+
+    /**
+     * Read a {@link TimestampedValue} from a parcel that was stored using
+     * {@link #writeToParcel(Parcel, TimestampedValue)}.
+     *
+     * <p>The marshalling/unmarshalling of the value relies upon {@link Parcel#writeValue(Object)}
+     * and {@link Parcel#readValue(ClassLoader)} and so this method can only be used with types
+     * supported by those methods.
+     *
+     * @param in the Parcel to read from
+     * @param classLoader the ClassLoader to pass to {@link Parcel#readValue(ClassLoader)}
+     * @param valueClass the expected type of the value, typically the same as {@code <T>} but can
+     *     also be a subclass
+     * @throws RuntimeException if the value read is not compatible with {@code valueClass} or the
+     *     object could not be read
+     */
+    @SuppressWarnings("unchecked")
+    @NonNull
+    public static <T> TimestampedValue<T> readFromParcel(
+            @NonNull Parcel in, @Nullable ClassLoader classLoader, Class<? extends T> valueClass) {
+        long referenceTimeMillis = in.readLong();
+        T value = (T) in.readValue(classLoader);
+        // Equivalent to static code: if (!(value.getClass() instanceof {valueClass})) {
+        if (value != null && !valueClass.isAssignableFrom(value.getClass())) {
+            throw new RuntimeException("Value was of type " + value.getClass()
+                    + " is not assignable to " + valueClass);
+        }
+        return new TimestampedValue<>(referenceTimeMillis, value);
+    }
+
+    /**
+     * Write a {@link TimestampedValue} to a parcel so that it can be read using
+     * {@link #readFromParcel(Parcel, ClassLoader, Class)}.
+     *
+     * <p>The marshalling/unmarshalling of the value relies upon {@link Parcel#writeValue(Object)}
+     * and {@link Parcel#readValue(ClassLoader)} and so this method can only be used with types
+     * supported by those methods.
+     *
+     * @param dest the Parcel
+     * @param timestampedValue the value
+     * @throws RuntimeException if the value could not be written to the Parcel
+     */
+    public static void writeToParcel(
+            @NonNull Parcel dest, @NonNull TimestampedValue<?> timestampedValue) {
+        dest.writeLong(timestampedValue.mReferenceTimeMillis);
+        dest.writeValue(timestampedValue.mValue);
+    }
+
+    /**
+     * Returns the difference in milliseconds between two instance's reference times.
+     */
+    public static long referenceTimeDifference(
+            @NonNull TimestampedValue<?> one, @NonNull TimestampedValue<?> two) {
+        return one.mReferenceTimeMillis - two.mReferenceTimeMillis;
+    }
+}
diff --git a/core/java/com/android/internal/util/HexDump.java b/core/java/com/android/internal/util/HexDump.java
index 7be95d8..af00400 100644
--- a/core/java/com/android/internal/util/HexDump.java
+++ b/core/java/com/android/internal/util/HexDump.java
@@ -16,18 +16,21 @@
 
 package com.android.internal.util;
 
+import android.annotation.Nullable;
+
 public class HexDump
 {
     private final static char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
     private final static char[] HEX_LOWER_CASE_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-    public static String dumpHexString(byte[] array)
-    {
+    public static String dumpHexString(@Nullable byte[] array) {
+        if (array == null) return "(null)";
         return dumpHexString(array, 0, array.length);
     }
 
-    public static String dumpHexString(byte[] array, int offset, int length)
+    public static String dumpHexString(@Nullable byte[] array, int offset, int length)
     {
+        if (array == null) return "(null)";
         StringBuilder result = new StringBuilder();
 
         byte[] line = new byte[16];
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index b1e1dd3..a7e0fec 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -907,10 +907,13 @@
     }
 
     // Native bridge library. "0" means that native bridge is disabled.
+    //
+    // Note: bridging is only enabled for the zygote. Other runs of
+    //       app_process may not have the permissions to mount etc.
     property_get("ro.dalvik.vm.native.bridge", propBuf, "");
     if (propBuf[0] == '\0') {
         ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
-    } else if (strcmp(propBuf, "0") != 0) {
+    } else if (zygote && strcmp(propBuf, "0") != 0) {
         snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
                  "-XX:NativeBridge=%s", propBuf);
         addOption(nativeBridgeLibrary);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index d3da21b..b35d92f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -902,146 +902,6 @@
 jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
 jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
 
-
-/* pulled out of bionic */
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
-    size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
-extern "C" void free_malloc_leak_info(uint8_t* info);
-#define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
-
-static size_t gNumBacktraceElements;
-
-/*
- * This is a qsort() callback.
- *
- * See dumpNativeHeap() for comments about the data format and sort order.
- */
-static int compareHeapRecords(const void* vrec1, const void* vrec2)
-{
-    const size_t* rec1 = (const size_t*) vrec1;
-    const size_t* rec2 = (const size_t*) vrec2;
-    size_t size1 = *rec1;
-    size_t size2 = *rec2;
-
-    if (size1 < size2) {
-        return 1;
-    } else if (size1 > size2) {
-        return -1;
-    }
-
-    uintptr_t* bt1 = (uintptr_t*)(rec1 + 2);
-    uintptr_t* bt2 = (uintptr_t*)(rec2 + 2);
-    for (size_t idx = 0; idx < gNumBacktraceElements; idx++) {
-        uintptr_t addr1 = bt1[idx];
-        uintptr_t addr2 = bt2[idx];
-        if (addr1 == addr2) {
-            if (addr1 == 0)
-                break;
-            continue;
-        }
-        if (addr1 < addr2) {
-            return -1;
-        } else if (addr1 > addr2) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/*
- * The get_malloc_leak_info() call returns an array of structs that
- * look like this:
- *
- *   size_t size
- *   size_t allocations
- *   intptr_t backtrace[32]
- *
- * "size" is the size of the allocation, "backtrace" is a fixed-size
- * array of function pointers, and "allocations" is the number of
- * allocations with the exact same size and backtrace.
- *
- * The entries are sorted by descending total size (i.e. size*allocations)
- * then allocation count.  For best results with "diff" we'd like to sort
- * primarily by individual size then stack trace.  Since the entries are
- * fixed-size, and we're allowed (by the current implementation) to mangle
- * them, we can do this in place.
- */
-static void dumpNativeHeap(FILE* fp)
-{
-    uint8_t* info = NULL;
-    size_t overallSize, infoSize, totalMemory, backtraceSize;
-
-    get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory,
-        &backtraceSize);
-    if (info == NULL) {
-        fprintf(fp, "Native heap dump not available. To enable, run these"
-                    " commands (requires root):\n");
-        fprintf(fp, "# adb shell stop\n");
-        fprintf(fp, "# adb shell setprop libc.debug.malloc.options "
-                    "backtrace\n");
-        fprintf(fp, "# adb shell start\n");
-        return;
-    }
-    assert(infoSize != 0);
-    assert(overallSize % infoSize == 0);
-
-    fprintf(fp, "Android Native Heap Dump v1.0\n\n");
-
-    size_t recordCount = overallSize / infoSize;
-    fprintf(fp, "Total memory: %zu\n", totalMemory);
-    fprintf(fp, "Allocation records: %zd\n", recordCount);
-    fprintf(fp, "Backtrace size: %zd\n", backtraceSize);
-    fprintf(fp, "\n");
-
-    /* re-sort the entries */
-    gNumBacktraceElements = backtraceSize;
-    qsort(info, recordCount, infoSize, compareHeapRecords);
-
-    /* dump the entries to the file */
-    const uint8_t* ptr = info;
-    for (size_t idx = 0; idx < recordCount; idx++) {
-        size_t size = *(size_t*) ptr;
-        size_t allocations = *(size_t*) (ptr + sizeof(size_t));
-        uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2);
-
-        fprintf(fp, "z %d  sz %8zu  num %4zu  bt",
-                (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
-                size & ~SIZE_FLAG_ZYGOTE_CHILD,
-                allocations);
-        for (size_t bt = 0; bt < backtraceSize; bt++) {
-            if (backtrace[bt] == 0) {
-                break;
-            } else {
-#ifdef __LP64__
-                fprintf(fp, " %016" PRIxPTR, backtrace[bt]);
-#else
-                fprintf(fp, " %08" PRIxPTR, backtrace[bt]);
-#endif
-            }
-        }
-        fprintf(fp, "\n");
-
-        ptr += infoSize;
-    }
-
-    free_malloc_leak_info(info);
-
-    fprintf(fp, "MAPS\n");
-    const char* maps = "/proc/self/maps";
-    UniqueFile in = MakeUniqueFile(maps, "re");
-    if (in == nullptr) {
-        fprintf(fp, "Could not open %s\n", maps);
-        return;
-    }
-    char buf[BUFSIZ];
-    while (size_t n = fread(buf, sizeof(char), BUFSIZ, in.get())) {
-        fwrite(buf, sizeof(char), n, fp);
-    }
-
-    fprintf(fp, "END\n");
-}
-
 static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp)
 {
     if (fileDescriptor == NULL) {
@@ -1072,6 +932,9 @@
     return true;
 }
 
+/* pulled out of bionic */
+extern "C" void write_malloc_leak_info(FILE* fp);
+
 /*
  * Dump the native heap, writing human-readable output to the specified
  * file descriptor.
@@ -1085,7 +948,9 @@
     }
 
     ALOGD("Native heap dump starting...\n");
-    dumpNativeHeap(fp.get());
+    // Formatting of the native heap dump is handled by malloc debug itself.
+    // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format
+    write_malloc_leak_info(fp.get());
     ALOGD("Native heap dump complete.\n");
 }
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 8d6a280..8cb2dcd 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -535,17 +535,207 @@
   return true;
 }
 
+// Utility routine to specialize a zygote child process.
+static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+                             jint runtime_flags, jobjectArray javaRlimits,
+                             jlong permittedCapabilities, jlong effectiveCapabilities,
+                             jint mount_external, jstring java_se_info, jstring java_se_name,
+                             bool is_system_server, bool is_child_zygote, jstring instructionSet,
+                             jstring dataDir) {
+  std::string error_msg;
+
+  auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
+      __attribute__ ((noreturn)) {
+    const char* se_name_c_str = nullptr;
+    std::unique_ptr<ScopedUtfChars> se_name;
+    if (java_se_name != nullptr) {
+      se_name.reset(new ScopedUtfChars(env, java_se_name));
+      se_name_c_str = se_name->c_str();
+    }
+    if (se_name_c_str == nullptr && is_system_server) {
+      se_name_c_str = "system_server";
+    }
+    const std::string& error_msg = (se_name_c_str == nullptr)
+        ? msg
+        : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
+    env->FatalError(error_msg.c_str());
+    __builtin_unreachable();
+  };
+
+  // Keep capabilities across UID change, unless we're staying root.
+  if (uid != 0) {
+    if (!EnableKeepCapabilities(&error_msg)) {
+      fail_fn(error_msg);
+    }
+  }
+
+  if (!SetInheritable(permittedCapabilities, &error_msg)) {
+    fail_fn(error_msg);
+  }
+  if (!DropCapabilitiesBoundingSet(&error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  bool use_native_bridge = !is_system_server && (instructionSet != NULL)
+      && android::NativeBridgeAvailable();
+  if (use_native_bridge) {
+    ScopedUtfChars isa_string(env, instructionSet);
+    use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
+  }
+  if (use_native_bridge && dataDir == NULL) {
+    // dataDir should never be null if we need to use a native bridge.
+    // In general, dataDir will never be null for normal applications. It can only happen in
+    // special cases (for isolated processes which are not associated with any app). These are
+    // launched by the framework and should not be emulated anyway.
+    use_native_bridge = false;
+    ALOGW("Native bridge will not be used because dataDir == NULL.");
+  }
+
+  if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
+    ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
+    if (errno == ENOTCONN || errno == EROFS) {
+      // When device is actively encrypting, we get ENOTCONN here
+      // since FUSE was mounted before the framework restarted.
+      // When encrypted device is booting, we get EROFS since
+      // FUSE hasn't been created yet by init.
+      // In either case, continue without external storage.
+    } else {
+      fail_fn(error_msg);
+    }
+  }
+
+  if (!is_system_server) {
+      int rc = createProcessGroup(uid, getpid());
+      if (rc != 0) {
+          if (rc == -EROFS) {
+              ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
+          } else {
+              ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0/*pid*/, strerror(-rc));
+          }
+      }
+  }
+
+  if (!SetGids(env, javaGids, &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (!SetRLimits(env, javaRlimits, &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (use_native_bridge) {
+    ScopedUtfChars isa_string(env, instructionSet);
+    ScopedUtfChars data_dir(env, dataDir);
+    android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
+  }
+
+  int rc = setresgid(gid, gid, gid);
+  if (rc == -1) {
+    fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
+  }
+
+  // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
+  // uid from 0, which clears capabilities.  The other alternative is to call
+  // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
+  // b/71859146).  As the result, privileged syscalls used below still need to be accessible in
+  // app process.
+  SetUpSeccompFilter(uid);
+
+  rc = setresuid(uid, uid, uid);
+  if (rc == -1) {
+    fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
+  }
+
+  // The "dumpable" flag of a process, which controls core dump generation, is
+  // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
+  // user or group ID changes. See proc(5) for possible values. In most cases,
+  // the value is 0, so core dumps are disabled for zygote children. However,
+  // when running in a Chrome OS container, the value is already set to 2,
+  // which allows the external crash reporter to collect all core dumps. Since
+  // only system crashes are interested, core dump is disabled for app
+  // processes. This also ensures compliance with CTS.
+  int dumpable = prctl(PR_GET_DUMPABLE);
+  if (dumpable == -1) {
+      ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
+      RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
+  }
+  if (dumpable == 2 && uid >= AID_APP) {
+    if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
+      ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
+      RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
+    }
+  }
+
+  if (NeedsNoRandomizeWorkaround()) {
+      // Work around ARM kernel ASLR lossage (http://b/5817320).
+      int old_personality = personality(0xffffffff);
+      int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+      if (new_personality == -1) {
+          ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
+      }
+  }
+
+  if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
+                       &error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  if (!SetSchedulerPolicy(&error_msg)) {
+    fail_fn(error_msg);
+  }
+
+  const char* se_info_c_str = NULL;
+  ScopedUtfChars* se_info = NULL;
+  if (java_se_info != NULL) {
+      se_info = new ScopedUtfChars(env, java_se_info);
+      se_info_c_str = se_info->c_str();
+      if (se_info_c_str == NULL) {
+        fail_fn("se_info_c_str == NULL");
+      }
+  }
+  const char* se_name_c_str = NULL;
+  ScopedUtfChars* se_name = NULL;
+  if (java_se_name != NULL) {
+      se_name = new ScopedUtfChars(env, java_se_name);
+      se_name_c_str = se_name->c_str();
+      if (se_name_c_str == NULL) {
+        fail_fn("se_name_c_str == NULL");
+      }
+  }
+  rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+  if (rc == -1) {
+    fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+          is_system_server, se_info_c_str, se_name_c_str));
+  }
+
+  // Make it easier to debug audit logs by setting the main thread's name to the
+  // nice name rather than "app_process".
+  if (se_name_c_str == NULL && is_system_server) {
+    se_name_c_str = "system_server";
+  }
+  if (se_name_c_str != NULL) {
+    SetThreadName(se_name_c_str);
+  }
+
+  delete se_info;
+  delete se_name;
+
+  // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
+  UnsetChldSignalHandler();
+
+  env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
+                            is_system_server, is_child_zygote, instructionSet);
+  if (env->ExceptionCheck()) {
+    fail_fn("Error calling post fork hooks.");
+  }
+}
+
 // Utility routine to fork zygote and specialize the child process.
-static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
-                                     jint runtime_flags, jobjectArray javaRlimits,
-                                     jlong permittedCapabilities, jlong effectiveCapabilities,
-                                     jint mount_external,
-                                     jstring java_se_info, jstring java_se_name,
-                                     bool is_system_server, jintArray fdsToClose,
-                                     jintArray fdsToIgnore, bool is_child_zygote,
-                                     jstring instructionSet, jstring dataDir) {
+static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server,
+                        jintArray fdsToClose, jintArray fdsToIgnore) {
   SetSignalHandlers();
 
+  // Block SIGCHLD prior to fork.
   sigset_t sigchld;
   sigemptyset(&sigchld);
   sigaddset(&sigchld, SIGCHLD);
@@ -602,6 +792,7 @@
   pid_t pid = fork();
 
   if (pid == 0) {
+    // The child process.
     PreApplicationInit();
 
     // Clean up any descriptors which must be closed immediately
@@ -614,186 +805,13 @@
     if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
       fail_fn(error_msg);
     }
-
-    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
-      fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
-    }
-
-    // Keep capabilities across UID change, unless we're staying root.
-    if (uid != 0) {
-      if (!EnableKeepCapabilities(&error_msg)) {
-        fail_fn(error_msg);
-      }
-    }
-
-    if (!SetInheritable(permittedCapabilities, &error_msg)) {
-      fail_fn(error_msg);
-    }
-    if (!DropCapabilitiesBoundingSet(&error_msg)) {
-      fail_fn(error_msg);
-    }
-
-    bool use_native_bridge = !is_system_server && (instructionSet != NULL)
-        && android::NativeBridgeAvailable();
-    if (use_native_bridge) {
-      ScopedUtfChars isa_string(env, instructionSet);
-      use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
-    }
-    if (use_native_bridge && dataDir == NULL) {
-      // dataDir should never be null if we need to use a native bridge.
-      // In general, dataDir will never be null for normal applications. It can only happen in
-      // special cases (for isolated processes which are not associated with any app). These are
-      // launched by the framework and should not be emulated anyway.
-      use_native_bridge = false;
-      ALOGW("Native bridge will not be used because dataDir == NULL.");
-    }
-
-    if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
-      ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
-      if (errno == ENOTCONN || errno == EROFS) {
-        // When device is actively encrypting, we get ENOTCONN here
-        // since FUSE was mounted before the framework restarted.
-        // When encrypted device is booting, we get EROFS since
-        // FUSE hasn't been created yet by init.
-        // In either case, continue without external storage.
-      } else {
-        fail_fn(error_msg);
-      }
-    }
-
-    if (!is_system_server) {
-        int rc = createProcessGroup(uid, getpid());
-        if (rc != 0) {
-            if (rc == -EROFS) {
-                ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
-            } else {
-                ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
-            }
-        }
-    }
-
-    std::string error_msg;
-    if (!SetGids(env, javaGids, &error_msg)) {
-      fail_fn(error_msg);
-    }
-
-    if (!SetRLimits(env, javaRlimits, &error_msg)) {
-      fail_fn(error_msg);
-    }
-
-    if (use_native_bridge) {
-      ScopedUtfChars isa_string(env, instructionSet);
-      ScopedUtfChars data_dir(env, dataDir);
-      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
-    }
-
-    int rc = setresgid(gid, gid, gid);
-    if (rc == -1) {
-      fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
-    }
-
-    // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
-    // uid from 0, which clears capabilities.  The other alternative is to call
-    // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
-    // b/71859146).  As the result, privileged syscalls used below still need to be accessible in
-    // app process.
-    SetUpSeccompFilter(uid);
-
-    rc = setresuid(uid, uid, uid);
-    if (rc == -1) {
-      fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
-    }
-
-    // The "dumpable" flag of a process, which controls core dump generation, is
-    // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
-    // user or group ID changes. See proc(5) for possible values. In most cases,
-    // the value is 0, so core dumps are disabled for zygote children. However,
-    // when running in a Chrome OS container, the value is already set to 2,
-    // which allows the external crash reporter to collect all core dumps. Since
-    // only system crashes are interested, core dump is disabled for app
-    // processes. This also ensures compliance with CTS.
-    int dumpable = prctl(PR_GET_DUMPABLE);
-    if (dumpable == -1) {
-        ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
-        RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
-    }
-    if (dumpable == 2 && uid >= AID_APP) {
-      if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
-        ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
-        RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
-      }
-    }
-
-    if (NeedsNoRandomizeWorkaround()) {
-        // Work around ARM kernel ASLR lossage (http://b/5817320).
-        int old_personality = personality(0xffffffff);
-        int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
-        if (new_personality == -1) {
-            ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
-        }
-    }
-
-    if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
-                         &error_msg)) {
-      fail_fn(error_msg);
-    }
-
-    if (!SetSchedulerPolicy(&error_msg)) {
-      fail_fn(error_msg);
-    }
-
-    const char* se_info_c_str = NULL;
-    ScopedUtfChars* se_info = NULL;
-    if (java_se_info != NULL) {
-        se_info = new ScopedUtfChars(env, java_se_info);
-        se_info_c_str = se_info->c_str();
-        if (se_info_c_str == NULL) {
-          fail_fn("se_info_c_str == NULL");
-        }
-    }
-    const char* se_name_c_str = NULL;
-    ScopedUtfChars* se_name = NULL;
-    if (java_se_name != NULL) {
-        se_name = new ScopedUtfChars(env, java_se_name);
-        se_name_c_str = se_name->c_str();
-        if (se_name_c_str == NULL) {
-          fail_fn("se_name_c_str == NULL");
-        }
-    }
-    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
-    if (rc == -1) {
-      fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
-            is_system_server, se_info_c_str, se_name_c_str));
-    }
-
-    // Make it easier to debug audit logs by setting the main thread's name to the
-    // nice name rather than "app_process".
-    if (se_name_c_str == NULL && is_system_server) {
-      se_name_c_str = "system_server";
-    }
-    if (se_name_c_str != NULL) {
-      SetThreadName(se_name_c_str);
-    }
-
-    delete se_info;
-    delete se_name;
-
-    // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
-    UnsetChldSignalHandler();
-
-    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
-                              is_system_server, is_child_zygote, instructionSet);
-    if (env->ExceptionCheck()) {
-      fail_fn("Error calling post fork hooks.");
-    }
-  } else if (pid > 0) {
-    // the parent process
-
-    // We blocked SIGCHLD prior to a fork, we unblock it here.
-    if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
-      fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
-    }
   }
+
+  // We blocked SIGCHLD prior to a fork, we unblock it here.
+  if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
+    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
+  }
+
   return pid;
 }
 
@@ -879,22 +897,27 @@
     // available.
     capabilities &= GetEffectiveCapabilityMask(env);
 
-    return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags,
-            rlimits, capabilities, capabilities, mount_external, se_info,
-            se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE,
-            instructionSet, appDataDir);
+    pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
+    if (pid == 0) {
+      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
+                       capabilities, capabilities,
+                       mount_external, se_info, se_name, false,
+                       is_child_zygote == JNI_TRUE, instructionSet, appDataDir);
+    }
+    return pid;
 }
 
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
         jlong effectiveCapabilities) {
-  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
-                                      runtime_flags, rlimits,
-                                      permittedCapabilities, effectiveCapabilities,
-                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
-                                      NULL, false, NULL, NULL);
-  if (pid > 0) {
+  pid_t pid = ForkCommon(env, NULL, true, NULL, NULL);
+  if (pid == 0) {
+      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
+                       permittedCapabilities, effectiveCapabilities,
+                       MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
+                       false, NULL, NULL);
+  } else if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
       gSystemServerPid = pid;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 64949ce..6087229 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1311,6 +1311,13 @@
         android:label="@string/permlab_changeWifiState"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi @hide Allows apps to create and manage IPsec tunnels.
+         <p>Only granted to applications that are currently bound by the
+         system for creating and managing IPsec-based interfaces.
+    -->
+    <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
+        android:protectionLevel="signature|appop" />
+
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6d55d0b..12c734b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -368,12 +368,14 @@
                [Network Capabilities] Optional. A comma seprated list of network capabilities.
                    Values must be from NetworkCapabilities#NET_CAPABILITIES_* constants.
                [IP config] Optional. If empty or not specified - DHCP will be used, otherwise
-                    static IP address with the mask.
+                   use the following format to specify static IP configuration:
+		       ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
+                       domains=<comma-sep-domains> 
          -->
     <string-array translatable="false" name="config_ethernet_interfaces">
         <!--
-        <item>eth1;12,13,14,15;192.168.0.10/24</item>
-        <item>eth2;;192.168.0.11/24</item>
+        <item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
+        <item>eth2;;ip=192.168.0.11/24</item>
         -->
     </string-array>
 
@@ -486,13 +488,21 @@
 
          Note also: the order of this is important. The first upstream type
          for which a satisfying network exists is used.
-      -->
+    -->
     <integer-array translatable="false" name="config_tether_upstream_types">
         <item>1</item>
         <item>7</item>
         <item>0</item>
     </integer-array>
 
+    <!-- When true, the tethering upstream network follows the current default
+         Internet network (except when the current default network is mobile,
+         in which case a DUN network will be used if required).
+
+         When true, overrides the config_tether_upstream_types setting above.
+    -->
+    <bool translatable="false" name="config_tether_upstream_automatic">true</bool>
+
     <!-- If the DUN connection for this CDMA device supports more than just DUN -->
     <!-- traffic you should list them here. -->
     <!-- If this device is not CDMA this is ignored.  If this list is empty on -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e52f0f8..39cf364 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1732,6 +1732,7 @@
   <java-symbol type="array" name="config_tether_bluetooth_regexs" />
   <java-symbol type="array" name="config_tether_dhcp_range" />
   <java-symbol type="array" name="config_tether_upstream_types" />
+  <java-symbol type="bool" name="config_tether_upstream_automatic" />
   <java-symbol type="array" name="config_tether_apndata" />
   <java-symbol type="array" name="config_tether_usb_regexs" />
   <java-symbol type="array" name="config_tether_wifi_regexs" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 8947bf0..fb78b3b 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -61,7 +61,7 @@
     <shortcode country="bh" pattern="\\d{1,5}" free="81181" />
 
     <!-- Brazil: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963" />
+    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000" />
 
     <!-- Belarus: 4 digits -->
     <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
@@ -73,7 +73,7 @@
     <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765" />
 
     <!-- Chile: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="cl" pattern="\\d{4,5}" free="9963" />
+    <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240" />
 
     <!-- China: premium shortcodes start with "1066", free shortcodes start with "1065":
          http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements -->
@@ -104,7 +104,7 @@
     <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}|22791|222145|22189" />
 
     <!-- Finland: 5-6 digits, premium 0600, 0700: http://en.wikipedia.org/wiki/Telephone_numbers_in_Finland -->
-    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}|14789" />
+    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}|14789|17110" />
 
     <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
          http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
@@ -136,7 +136,7 @@
     <shortcode country="in" pattern="\\d{1,5}" free="59336|53969" />
 
     <!-- Indonesia: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645" />
+    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363" />
 
     <!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
          http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
@@ -190,7 +190,7 @@
     <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
 
     <!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" />
+    <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
 
     <!-- New Zealand: 3-4 digits, known premium codes listed -->
     <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="3067|3068|4053" />
@@ -240,7 +240,7 @@
     <shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
 
     <!-- Thailand: 4186001 used by AIS_TH_DCB -->
-    <shortcode country="th" pattern="\\d{1,5}" free="4186001" />
+    <shortcode country="th" pattern="\\d{1,5}" premium="4\\d{6}" free="4186001" />
 
     <!-- Tajikistan: 4 digits, known premium codes listed -->
     <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/util/TimestampedValueTest.java
new file mode 100644
index 0000000..03b4abd
--- /dev/null
+++ b/core/tests/coretests/src/android/util/TimestampedValueTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class TimestampedValueTest {
+
+    @Test
+    public void testEqualsAndHashcode() {
+        TimestampedValue<String> one1000one = new TimestampedValue<>(1000, "one");
+        assertEqualsAndHashCode(one1000one, one1000one);
+
+        TimestampedValue<String> one1000two = new TimestampedValue<>(1000, "one");
+        assertEqualsAndHashCode(one1000one, one1000two);
+
+        TimestampedValue<String> two1000 = new TimestampedValue<>(1000, "two");
+        assertNotEquals(one1000one, two1000);
+
+        TimestampedValue<String> one2000 = new TimestampedValue<>(2000, "one");
+        assertNotEquals(one1000one, one2000);
+    }
+
+    private static void assertEqualsAndHashCode(Object one, Object two) {
+        assertEquals(one, two);
+        assertEquals(one.hashCode(), two.hashCode());
+    }
+
+    @Test
+    public void testParceling() {
+        TimestampedValue<String> stringValue = new TimestampedValue<>(1000, "Hello");
+        Parcel parcel = Parcel.obtain();
+        try {
+            TimestampedValue.writeToParcel(parcel, stringValue);
+
+            parcel.setDataPosition(0);
+
+            TimestampedValue<String> stringValueCopy =
+                    TimestampedValue.readFromParcel(parcel, null /* classLoader */, String.class);
+            assertEquals(stringValue, stringValueCopy);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    @Test
+    public void testParceling_valueClassOk() {
+        TimestampedValue<String> stringValue = new TimestampedValue<>(1000, "Hello");
+        Parcel parcel = Parcel.obtain();
+        try {
+            TimestampedValue.writeToParcel(parcel, stringValue);
+
+            parcel.setDataPosition(0);
+
+            TimestampedValue<Object> stringValueCopy =
+                    TimestampedValue.readFromParcel(parcel, null /* classLoader */, Object.class);
+            assertEquals(stringValue, stringValueCopy);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    @Test
+    public void testParceling_valueClassIncompatible() {
+        TimestampedValue<String> stringValue = new TimestampedValue<>(1000, "Hello");
+        Parcel parcel = Parcel.obtain();
+        try {
+            TimestampedValue.writeToParcel(parcel, stringValue);
+
+            parcel.setDataPosition(0);
+
+            TimestampedValue.readFromParcel(parcel, null /* classLoader */, Double.class);
+            fail();
+        } catch (RuntimeException expected) {
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    @Test
+    public void testParceling_nullValue() {
+        TimestampedValue<String> nullValue = new TimestampedValue<>(1000, null);
+        Parcel parcel = Parcel.obtain();
+        try {
+            TimestampedValue.writeToParcel(parcel, nullValue);
+
+            parcel.setDataPosition(0);
+
+            TimestampedValue<Object> nullValueCopy =
+                    TimestampedValue.readFromParcel(parcel, null /* classLoader */, String.class);
+            assertEquals(nullValue, nullValueCopy);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    @Test
+    public void testReferenceTimeDifference() {
+        TimestampedValue<Long> value1 = new TimestampedValue<>(1000, 123L);
+        assertEquals(0, TimestampedValue.referenceTimeDifference(value1, value1));
+
+        TimestampedValue<Long> value2 = new TimestampedValue<>(1, 321L);
+        assertEquals(999, TimestampedValue.referenceTimeDifference(value1, value2));
+        assertEquals(-999, TimestampedValue.referenceTimeDifference(value2, value1));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
index 951e87a..359bd5e 100644
--- a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
@@ -25,4 +25,7 @@
         assertEquals("ABCDEF", HexDump.toHexString(
                 new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef }, true));
     }
+    public void testNullArray() {
+        assertEquals("(null)", HexDump.toHexString(null));
+    }
 }
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 434dfdf..64085ea 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -167,8 +167,6 @@
             file="/system/framework/android.test.mock.jar" />
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.jar" />
-    <library name="javax.obex"
-            file="/system/framework/javax.obex.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. -->
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index edfd380..bf8067c 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -232,4 +232,5 @@
     $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
     $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
     $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-
+    $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \
+    $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index c5222af..72aa7fe 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -32,6 +32,8 @@
 	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \
+	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \
 	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index 43c83b9..665ce52 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -32,6 +32,8 @@
 	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \.
+	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \
 	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage12.mk b/data/sounds/AudioPackage12.mk
index cd4d35b..44a8f9e 100644
--- a/data/sounds/AudioPackage12.mk
+++ b/data/sounds/AudioPackage12.mk
@@ -12,7 +12,7 @@
 NOTIFICATION_FILES := Ariel Ceres Carme Elara Europa Iapetus Io Rhea Salacia Titan Tethys
 RINGTONE_FILES := Callisto Dione Ganymede Luna Oberon Phobos Sedna Titania Triton Umbriel
 EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
-	camera_focus Dock Undock Lock Unlock Trusted
+	camera_focus Dock Undock Lock Unlock Trusted ChargingStarted InCallNotification
 MATERIAL_EFFECT_FILES := camera_click VideoRecord LowBattery WirelessChargingStarted VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
diff --git a/data/sounds/AudioPackage12_48.mk b/data/sounds/AudioPackage12_48.mk
index 80758f4..09fab04 100644
--- a/data/sounds/AudioPackage12_48.mk
+++ b/data/sounds/AudioPackage12_48.mk
@@ -12,7 +12,7 @@
 NOTIFICATION_FILES := Ariel Ceres Carme Elara Europa Iapetus Io Rhea Salacia Titan Tethys
 RINGTONE_FILES := Callisto Dione Ganymede Luna Oberon Phobos Sedna Titania Triton Umbriel
 EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
-	Lock Unlock Trusted
+	Lock Unlock Trusted ChargingStarted InCallNotification
 MATERIAL_EFFECT_FILES := camera_click VideoRecord LowBattery WirelessChargingStarted VideoStop
 
 # Alarms not yet available in 48 kHz
diff --git a/data/sounds/AudioPackage13.mk b/data/sounds/AudioPackage13.mk
index d33a4af..de4ee04 100644
--- a/data/sounds/AudioPackage13.mk
+++ b/data/sounds/AudioPackage13.mk
@@ -13,7 +13,7 @@
 RINGTONE_FILES := Atria Callisto Dione Ganymede Luna Oberon Phobos Pyxis Sedna Titania Triton \
 	Umbriel
 EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
-	camera_focus Dock Undock Lock Unlock Trusted
+	camera_focus Dock Undock Lock Unlock Trusted ChargingStarted InCallNotification
 MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
diff --git a/data/sounds/AudioPackage13_48.mk b/data/sounds/AudioPackage13_48.mk
index 9c320ae..889d581 100644
--- a/data/sounds/AudioPackage13_48.mk
+++ b/data/sounds/AudioPackage13_48.mk
@@ -13,7 +13,7 @@
 RINGTONE_FILES := Atria Callisto Dione Ganymede Luna Oberon Phobos Pyxis Sedna Titania Triton \
 	Umbriel
 EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete KeypressSpacebar KeypressStandard \
-	Lock Unlock Trusted
+	Lock Unlock Trusted ChargingStarted InCallNotification
 MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
diff --git a/data/sounds/effects/ChargingStarted.ogg b/data/sounds/effects/ChargingStarted.ogg
new file mode 100644
index 0000000..f09e273
--- /dev/null
+++ b/data/sounds/effects/ChargingStarted.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/ChargingStarted.ogg b/data/sounds/effects/ogg/ChargingStarted.ogg
new file mode 100644
index 0000000..f09e273
--- /dev/null
+++ b/data/sounds/effects/ogg/ChargingStarted.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/ChargingStarted_48k.ogg b/data/sounds/effects/ogg/ChargingStarted_48k.ogg
new file mode 100644
index 0000000..f09e273
--- /dev/null
+++ b/data/sounds/effects/ogg/ChargingStarted_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/InCallNotification_48k.ogg b/data/sounds/effects/ogg/InCallNotification_48k.ogg
new file mode 100644
index 0000000..4481ccb2
--- /dev/null
+++ b/data/sounds/effects/ogg/InCallNotification_48k.ogg
Binary files differ
diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk
deleted file mode 100644
index 636f057..0000000
--- a/libs/common_time/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# common_time_service
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    common_clock_service.cpp \
-    common_time_config_service.cpp \
-    common_time_server.cpp \
-    common_time_server_api.cpp \
-    common_time_server_packets.cpp \
-    clock_recovery.cpp \
-    common_clock.cpp \
-    main.cpp \
-    utils.cpp \
-    LinearTransform.cpp
-
-# Uncomment to enable vesbose logging and debug service.
-#TIME_SERVICE_DEBUG=true
-ifeq ($(TIME_SERVICE_DEBUG), true)
-LOCAL_SRC_FILES += diag_thread.cpp
-LOCAL_CFLAGS += -DTIME_SERVICE_DEBUG
-endif
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libcommon_time_client \
-    libutils \
-    liblog
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := common_time
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
diff --git a/libs/common_time/LinearTransform.cpp b/libs/common_time/LinearTransform.cpp
deleted file mode 100644
index 6730855..0000000
--- a/libs/common_time/LinearTransform.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define __STDC_LIMIT_MACROS
-
-#include "LinearTransform.h"
-#include <assert.h>
-
-
-// disable sanitize as these functions may intentionally overflow (see comments below).
-// the ifdef can be removed when host builds use clang.
-#if defined(__clang__)
-#define ATTRIBUTE_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer")))
-#else
-#define ATTRIBUTE_NO_SANITIZE_INTEGER
-#endif
-
-namespace android {
-
-// sanitize failure with T = int32_t and x = 0x80000000
-template<class T>
-ATTRIBUTE_NO_SANITIZE_INTEGER
-static inline T ABS(T x) { return (x < 0) ? -x : x; }
-
-// Static math methods involving linear transformations
-// remote sanitize failure on overflow case.
-ATTRIBUTE_NO_SANITIZE_INTEGER
-static bool scale_u64_to_u64(
-        uint64_t val,
-        uint32_t N,
-        uint32_t D,
-        uint64_t* res,
-        bool round_up_not_down) {
-    uint64_t tmp1, tmp2;
-    uint32_t r;
-
-    assert(res);
-    assert(D);
-
-    // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
-    // integer X.
-    // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
-    // integer X.
-    // Let X[A, B] with A <= B denote bits A through B of the integer X.
-    // Let (A | B) denote the concatination of two 32 bit ints, A and B.
-    // IOW X = (A | B) => U32(X) == A && L32(X) == B
-    //
-    // compute M = val * N (a 96 bit int)
-    // ---------------------------------
-    // tmp2 = U32(val) * N (a 64 bit int)
-    // tmp1 = L32(val) * N (a 64 bit int)
-    // which means
-    // M = val * N = (tmp2 << 32) + tmp1
-    tmp2 = (val >> 32) * N;
-    tmp1 = (val & UINT32_MAX) * N;
-
-    // compute M[32, 95]
-    // tmp2 = tmp2 + U32(tmp1)
-    //      = (U32(val) * N) + U32(L32(val) * N)
-    //      = M[32, 95]
-    tmp2 += tmp1 >> 32;
-
-    // if M[64, 95] >= D, then M/D has bits > 63 set and we have
-    // an overflow.
-    if ((tmp2 >> 32) >= D) {
-        *res = UINT64_MAX;
-        return false;
-    }
-
-    // Divide.  Going in we know
-    // tmp2 = M[32, 95]
-    // U32(tmp2) < D
-    r = tmp2 % D;
-    tmp2 /= D;
-
-    // At this point
-    // tmp1      = L32(val) * N
-    // tmp2      = M[32, 95] / D
-    //           = (M / D)[32, 95]
-    // r         = M[32, 95] % D
-    // U32(tmp2) = 0
-    //
-    // compute tmp1 = (r | M[0, 31])
-    tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
-
-    // Divide again.  Keep the remainder around in order to round properly.
-    r = tmp1 % D;
-    tmp1 /= D;
-
-    // At this point
-    // tmp2      = (M / D)[32, 95]
-    // tmp1      = (M / D)[ 0, 31]
-    // r         =  M % D
-    // U32(tmp1) = 0
-    // U32(tmp2) = 0
-
-    // Pack the result and deal with the round-up case (As well as the
-    // remote possiblility over overflow in such a case).
-    *res = (tmp2 << 32) | tmp1;
-    if (r && round_up_not_down) {
-        ++(*res);
-        if (!(*res)) {
-            *res = UINT64_MAX;
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// at least one known sanitize failure (see comment below)
-ATTRIBUTE_NO_SANITIZE_INTEGER
-static bool linear_transform_s64_to_s64(
-        int64_t  val,
-        int64_t  basis1,
-        int32_t  N,
-        uint32_t D,
-        bool     invert_frac,
-        int64_t  basis2,
-        int64_t* out) {
-    uint64_t scaled, res;
-    uint64_t abs_val;
-    bool is_neg;
-
-    if (!out)
-        return false;
-
-    // Compute abs(val - basis_64). Keep track of whether or not this delta
-    // will be negative after the scale opertaion.
-    if (val < basis1) {
-        is_neg = true;
-        abs_val = basis1 - val;
-    } else {
-        is_neg = false;
-        abs_val = val - basis1;
-    }
-
-    if (N < 0)
-        is_neg = !is_neg;
-
-    if (!scale_u64_to_u64(abs_val,
-                          invert_frac ? D : ABS(N),
-                          invert_frac ? ABS(N) : D,
-                          &scaled,
-                          is_neg))
-        return false; // overflow/undeflow
-
-    // if scaled is >= 0x8000<etc>, then we are going to overflow or
-    // underflow unless ABS(basis2) is large enough to pull us back into the
-    // non-overflow/underflow region.
-    if (scaled & INT64_MIN) {
-        if (is_neg && (basis2 < 0))
-            return false; // certain underflow
-
-        if (!is_neg && (basis2 >= 0))
-            return false; // certain overflow
-
-        if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
-            return false; // not enough
-
-        // Looks like we are OK
-        *out = (is_neg ? (-scaled) : scaled) + basis2;
-    } else {
-        // Scaled fits within signed bounds, so we just need to check for
-        // over/underflow for two signed integers.  Basically, if both scaled
-        // and basis2 have the same sign bit, and the result has a different
-        // sign bit, then we have under/overflow.  An easy way to compute this
-        // is
-        // (scaled_signbit XNOR basis_signbit) &&
-        // (scaled_signbit XOR res_signbit)
-        // ==
-        // (scaled_signbit XOR basis_signbit XOR 1) &&
-        // (scaled_signbit XOR res_signbit)
-
-        if (is_neg)
-            scaled = -scaled; // known sanitize failure
-        res = scaled + basis2;
-
-        if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
-            return false;
-
-        *out = res;
-    }
-
-    return true;
-}
-
-bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
-    if (0 == a_to_b_denom)
-        return false;
-
-    return linear_transform_s64_to_s64(a_in,
-                                       a_zero,
-                                       a_to_b_numer,
-                                       a_to_b_denom,
-                                       false,
-                                       b_zero,
-                                       b_out);
-}
-
-bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
-    if (0 == a_to_b_numer)
-        return false;
-
-    return linear_transform_s64_to_s64(b_in,
-                                       b_zero,
-                                       a_to_b_numer,
-                                       a_to_b_denom,
-                                       true,
-                                       a_zero,
-                                       a_out);
-}
-
-template <class T> void LinearTransform::reduce(T* N, T* D) {
-    T a, b;
-    if (!N || !D || !(*D)) {
-        assert(false);
-        return;
-    }
-
-    a = *N;
-    b = *D;
-
-    if (a == 0) {
-        *D = 1;
-        return;
-    }
-
-    // This implements Euclid's method to find GCD.
-    if (a < b) {
-        T tmp = a;
-        a = b;
-        b = tmp;
-    }
-
-    while (1) {
-        // a is now the greater of the two.
-        const T remainder = a % b;
-        if (remainder == 0) {
-            *N /= b;
-            *D /= b;
-            return;
-        }
-        // by swapping remainder and b, we are guaranteeing that a is
-        // still the greater of the two upon entrance to the loop.
-        a = b;
-        b = remainder;
-    }
-};
-
-template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
-template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
-
-// sanitize failure if *N = 0x80000000
-ATTRIBUTE_NO_SANITIZE_INTEGER
-void LinearTransform::reduce(int32_t* N, uint32_t* D) {
-    if (N && D && *D) {
-        if (*N < 0) {
-            *N = -(*N);
-            reduce(reinterpret_cast<uint32_t*>(N), D);
-            *N = -(*N);
-        } else {
-            reduce(reinterpret_cast<uint32_t*>(N), D);
-        }
-    }
-}
-
-}  // namespace android
diff --git a/libs/common_time/LinearTransform.h b/libs/common_time/LinearTransform.h
deleted file mode 100644
index bf6ab8e..0000000
--- a/libs/common_time/LinearTransform.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef _LINEAR_TRANSFORM_H
-#define _LINEAR_TRANSFORM_H
-
-#include <stdint.h>
-
-namespace android {
-
-// LinearTransform defines a structure which hold the definition of a
-// transformation from single dimensional coordinate system A into coordinate
-// system B (and back again).  Values in A and in B are 64 bit, the linear
-// scale factor is expressed as a rational number using two 32 bit values.
-//
-// Specifically, let
-// f(a) = b
-// F(b) = f^-1(b) = a
-// then
-//
-// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
-//
-// and
-//
-// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
-//
-struct LinearTransform {
-  int64_t  a_zero;
-  int64_t  b_zero;
-  int32_t  a_to_b_numer;
-  uint32_t a_to_b_denom;
-
-  // Transform from A->B
-  // Returns true on success, or false in the case of a singularity or an
-  // overflow.
-  bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
-
-  // Transform from B->A
-  // Returns true on success, or false in the case of a singularity or an
-  // overflow.
-  bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
-
-  // Helpers which will reduce the fraction N/D using Euclid's method.
-  template <class T> static void reduce(T* N, T* D);
-  static void reduce(int32_t* N, uint32_t* D);
-};
-
-
-}
-
-#endif  // _LINEAR_TRANSFORM_H
diff --git a/libs/common_time/clock_recovery.cpp b/libs/common_time/clock_recovery.cpp
deleted file mode 100644
index 392caa0..0000000
--- a/libs/common_time/clock_recovery.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * A service that exchanges time synchronization information between
- * a master that defines a timeline and clients that follow the timeline.
- */
-
-#define __STDC_LIMIT_MACROS
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-#include <inttypes.h>
-#include <stdint.h>
-
-#include <common_time/local_clock.h>
-#include <assert.h>
-
-#include "clock_recovery.h"
-#include "common_clock.h"
-#ifdef TIME_SERVICE_DEBUG
-#include "diag_thread.h"
-#endif
-
-// Define log macro so we can make LOGV into LOGE when we are exclusively
-// debugging this code.
-#ifdef TIME_SERVICE_DEBUG
-#define LOG_TS ALOGE
-#else
-#define LOG_TS ALOGV
-#endif
-
-namespace android {
-
-ClockRecoveryLoop::ClockRecoveryLoop(LocalClock* local_clock,
-                                     CommonClock* common_clock) {
-    assert(NULL != local_clock);
-    assert(NULL != common_clock);
-
-    local_clock_  = local_clock;
-    common_clock_ = common_clock;
-
-    local_clock_can_slew_ = local_clock_->initCheck() &&
-                           (local_clock_->setLocalSlew(0) == OK);
-    tgt_correction_ = 0;
-    cur_correction_ = 0;
-
-    // Precompute the max rate at which we are allowed to change the VCXO
-    // control.
-    uint64_t N = 0x10000ull * 1000ull;
-    uint64_t D = local_clock_->getLocalFreq() * kMinFullRangeSlewChange_mSec;
-    LinearTransform::reduce(&N, &D);
-    while ((N > INT32_MAX) || (D > UINT32_MAX)) {
-        N >>= 1;
-        D >>= 1;
-        LinearTransform::reduce(&N, &D);
-    }
-    time_to_cur_slew_.a_to_b_numer = static_cast<int32_t>(N);
-    time_to_cur_slew_.a_to_b_denom = static_cast<uint32_t>(D);
-
-    reset(true, true);
-
-#ifdef TIME_SERVICE_DEBUG
-    diag_thread_ = new DiagThread(common_clock_, local_clock_);
-    if (diag_thread_ != NULL) {
-        status_t res = diag_thread_->startWorkThread();
-        if (res != OK)
-            ALOGW("Failed to start A@H clock recovery diagnostic thread.");
-    } else
-        ALOGW("Failed to allocate diagnostic thread.");
-#endif
-}
-
-ClockRecoveryLoop::~ClockRecoveryLoop() {
-#ifdef TIME_SERVICE_DEBUG
-    diag_thread_->stopWorkThread();
-#endif
-}
-
-// Constants.
-const float ClockRecoveryLoop::dT = 1.0;
-const float ClockRecoveryLoop::Kc = 1.0f;
-const float ClockRecoveryLoop::Ti = 15.0f;
-const float ClockRecoveryLoop::Tf = 0.05;
-const float ClockRecoveryLoop::bias_Fc = 0.01;
-const float ClockRecoveryLoop::bias_RC = (dT / (2 * 3.14159f * bias_Fc));
-const float ClockRecoveryLoop::bias_Alpha = (dT / (bias_RC + dT));
-const int64_t ClockRecoveryLoop::panic_thresh_ = 50000;
-const int64_t ClockRecoveryLoop::control_thresh_ = 10000;
-const float ClockRecoveryLoop::COmin = -100.0f;
-const float ClockRecoveryLoop::COmax = 100.0f;
-const uint32_t ClockRecoveryLoop::kMinFullRangeSlewChange_mSec = 300;
-const int ClockRecoveryLoop::kSlewChangeStepPeriod_mSec = 10;
-
-
-void ClockRecoveryLoop::reset(bool position, bool frequency) {
-    Mutex::Autolock lock(&lock_);
-    reset_l(position, frequency);
-}
-
-uint32_t ClockRecoveryLoop::findMinRTTNdx(DisciplineDataPoint* data,
-                                          uint32_t count) {
-    uint32_t min_rtt = 0;
-    for (uint32_t i = 1; i < count; ++i)
-        if (data[min_rtt].rtt > data[i].rtt)
-            min_rtt = i;
-
-    return min_rtt;
-}
-
-bool ClockRecoveryLoop::pushDisciplineEvent(int64_t local_time,
-                                            int64_t nominal_common_time,
-                                            int64_t rtt) {
-    Mutex::Autolock lock(&lock_);
-
-    int64_t local_common_time = 0;
-    common_clock_->localToCommon(local_time, &local_common_time);
-    int64_t raw_delta = nominal_common_time - local_common_time;
-
-#ifdef TIME_SERVICE_DEBUG
-    ALOGE("local=%lld, common=%lld, delta=%lld, rtt=%lld\n",
-         local_common_time, nominal_common_time,
-         raw_delta, rtt);
-#endif
-
-    // If we have not defined a basis for common time, then we need to use these
-    // initial points to do so.  In order to avoid significant initial error
-    // from a particularly bad startup data point, we collect the first N data
-    // points and choose the best of them before moving on.
-    if (!common_clock_->isValid()) {
-        if (startup_filter_wr_ < kStartupFilterSize) {
-            DisciplineDataPoint& d =  startup_filter_data_[startup_filter_wr_];
-            d.local_time = local_time;
-            d.nominal_common_time = nominal_common_time;
-            d.rtt = rtt;
-            startup_filter_wr_++;
-        }
-
-        if (startup_filter_wr_ == kStartupFilterSize) {
-            uint32_t min_rtt = findMinRTTNdx(startup_filter_data_,
-                    kStartupFilterSize);
-
-            common_clock_->setBasis(
-                    startup_filter_data_[min_rtt].local_time,
-                    startup_filter_data_[min_rtt].nominal_common_time);
-        }
-
-        return true;
-    }
-
-    int64_t observed_common;
-    int64_t delta;
-    float delta_f, dCO;
-    int32_t tgt_correction;
-
-    if (OK != common_clock_->localToCommon(local_time, &observed_common)) {
-        // Since we just checked to make certain that this conversion was valid,
-        // and no one else in the system should be messing with it, if this
-        // conversion is suddenly invalid, it is a good reason to panic.
-        ALOGE("Failed to convert local time to common time in %s:%d",
-                __PRETTY_FUNCTION__, __LINE__);
-        return false;
-    }
-
-    // Implement a filter which should match NTP filtering behavior when a
-    // client is associated with only one peer of lower stratum.  Basically,
-    // always use the best of the N last data points, where best is defined as
-    // lowest round trip time.  NTP uses an N of 8; we use a value of 6.
-    //
-    // TODO(johngro) : experiment with other filter strategies.  The goal here
-    // is to mitigate the effects of high RTT data points which typically have
-    // large asymmetries in the TX/RX legs.  Downside of the existing NTP
-    // approach (particularly because of the PID controller we are using to
-    // produce the control signal from the filtered data) are that the rate at
-    // which discipline events are actually acted upon becomes irregular and can
-    // become drawn out (the time between actionable event can go way up).  If
-    // the system receives a strong high quality data point, the proportional
-    // component of the controller can produce a strong correction which is left
-    // in place for too long causing overshoot.  In addition, the integral
-    // component of the system currently is an approximation based on the
-    // assumption of a more or less homogeneous sampling of the error.  Its
-    // unclear what the effect of undermining this assumption would be right
-    // now.
-
-    // Two ideas which come to mind immediately would be to...
-    // 1) Keep a history of more data points (32 or so) and ignore data points
-    //    whose RTT is more than a certain number of standard deviations outside
-    //    of the norm.
-    // 2) Eliminate the PID controller portion of this system entirely.
-    //    Instead, move to a system which uses a very wide filter (128 data
-    //    points or more) with a sum-of-least-squares line fitting approach to
-    //    tracking the long term drift.  This would take the place of the I
-    //    component in the current PID controller.  Also use a much more narrow
-    //    outlier-rejector filter (as described in #1) to drive a short term
-    //    correction factor similar to the P component of the PID controller.
-    assert(filter_wr_ < kFilterSize);
-    filter_data_[filter_wr_].local_time           = local_time;
-    filter_data_[filter_wr_].observed_common_time = observed_common;
-    filter_data_[filter_wr_].nominal_common_time  = nominal_common_time;
-    filter_data_[filter_wr_].rtt                  = rtt;
-    filter_data_[filter_wr_].point_used           = false;
-    uint32_t current_point = filter_wr_;
-    filter_wr_ = (filter_wr_ + 1) % kFilterSize;
-    if (!filter_wr_)
-        filter_full_ = true;
-
-    uint32_t scan_end = filter_full_ ? kFilterSize : filter_wr_;
-    uint32_t min_rtt = findMinRTTNdx(filter_data_, scan_end);
-    // We only use packets with low RTTs for control. If the packet RTT
-    // is less than the panic threshold, we can probably eat the jitter with the
-    // control loop. Otherwise, take the packet only if it better than all
-    // of the packets we have in the history. That way we try to track
-    // something, even if it is noisy.
-    if (current_point == min_rtt || rtt < control_thresh_) {
-        delta_f = delta = nominal_common_time - observed_common;
-
-        last_error_est_valid_ = true;
-        last_error_est_usec_ = delta;
-
-        // Compute the error then clamp to the panic threshold.  If we ever
-        // exceed this amt of error, its time to panic and reset the system.
-        // Given that the error in the measurement of the error could be as
-        // high as the RTT of the data point, we don't actually panic until
-        // the implied error (delta) is greater than the absolute panic
-        // threashold plus the RTT.  IOW - we don't panic until we are
-        // absoluely sure that our best case sync is worse than the absolute
-        // panic threshold.
-        int64_t effective_panic_thresh = panic_thresh_ + rtt;
-        if ((delta > effective_panic_thresh) ||
-            (delta < -effective_panic_thresh)) {
-            // PANIC!!!
-            reset_l(false, true);
-            return false;
-        }
-
-    } else {
-        // We do not have a good packet to look at, but we also do not want to
-        // free-run the clock at some crazy slew rate. So we guess the
-        // trajectory of the clock based on the last controller output and the
-        // estimated bias of our clock against the master.
-        // The net effect of this is that CO == CObias after some extended
-        // period of no feedback.
-        delta_f = last_delta_f_ - dT*(CO - CObias);
-        delta = delta_f;
-    }
-
-    // Velocity form PI control equation.
-    dCO = Kc * (1.0f + dT/Ti) * delta_f - Kc * last_delta_f_;
-    CO += dCO * Tf; // Filter CO by applying gain <1 here.
-
-    // Save error terms for later.
-    last_delta_f_ = delta_f;
-
-    // Clamp CO to +/- 100ppm.
-    if (CO < COmin)
-        CO = COmin;
-    else if (CO > COmax)
-        CO = COmax;
-
-    // Update the controller bias.
-    CObias = bias_Alpha * CO + (1.0f - bias_Alpha) * lastCObias;
-    lastCObias = CObias;
-
-    // Convert PPM to 16-bit int range. Add some guard band (-0.01) so we
-    // don't get fp weirdness.
-    tgt_correction = CO * 327.66;
-
-    // If there was a change in the amt of correction to use, update the
-    // system.
-    setTargetCorrection_l(tgt_correction);
-
-    LOG_TS("clock_loop %" PRId64 " %f %f %f %d\n", raw_delta, delta_f, CO, CObias, tgt_correction);
-
-#ifdef TIME_SERVICE_DEBUG
-    diag_thread_->pushDisciplineEvent(
-            local_time,
-            observed_common,
-            nominal_common_time,
-            tgt_correction,
-            rtt);
-#endif
-
-    return true;
-}
-
-int32_t ClockRecoveryLoop::getLastErrorEstimate() {
-    Mutex::Autolock lock(&lock_);
-
-    if (last_error_est_valid_)
-        return last_error_est_usec_;
-    else
-        return ICommonClock::kErrorEstimateUnknown;
-}
-
-void ClockRecoveryLoop::reset_l(bool position, bool frequency) {
-    assert(NULL != common_clock_);
-
-    if (position) {
-        common_clock_->resetBasis();
-        startup_filter_wr_ = 0;
-    }
-
-    if (frequency) {
-        last_error_est_valid_ = false;
-        last_error_est_usec_ = 0;
-        last_delta_f_ = 0.0;
-        CO = 0.0f;
-        lastCObias = CObias = 0.0f;
-        setTargetCorrection_l(0);
-        applySlew_l();
-    }
-
-    filter_wr_   = 0;
-    filter_full_ = false;
-}
-
-void ClockRecoveryLoop::setTargetCorrection_l(int32_t tgt) {
-    // When we make a change to the slew rate, we need to be careful to not
-    // change it too quickly as it can anger some HDMI sinks out there, notably
-    // some Sony panels from the 2010-2011 timeframe.  From experimenting with
-    // some of these sinks, it seems like swinging from one end of the range to
-    // another in less that 190mSec or so can start to cause trouble.  Adding in
-    // a hefty margin, we limit the system to a full range sweep in no less than
-    // 300mSec.
-    if (tgt_correction_ != tgt) {
-        int64_t now = local_clock_->getLocalTime();
-
-        tgt_correction_ = tgt;
-
-        // Set up the transformation to figure out what the slew should be at
-        // any given point in time in the future.
-        time_to_cur_slew_.a_zero = now;
-        time_to_cur_slew_.b_zero = cur_correction_;
-
-        // Make sure the sign of the slope is headed in the proper direction.
-        bool needs_increase = (cur_correction_ < tgt_correction_);
-        bool is_increasing  = (time_to_cur_slew_.a_to_b_numer > 0);
-        if (( needs_increase && !is_increasing) ||
-            (!needs_increase &&  is_increasing)) {
-            time_to_cur_slew_.a_to_b_numer = -time_to_cur_slew_.a_to_b_numer;
-        }
-
-        // Finally, figure out when the change will be finished and start the
-        // slew operation.
-        time_to_cur_slew_.doReverseTransform(tgt_correction_,
-                                             &slew_change_end_time_);
-
-        applySlew_l();
-    }
-}
-
-bool ClockRecoveryLoop::applySlew_l() {
-    bool ret = true;
-
-    // If cur == tgt, there is no ongoing sleq rate change and we are already
-    // finished.
-    if (cur_correction_ == tgt_correction_)
-        goto bailout;
-
-    if (local_clock_can_slew_) {
-        int64_t now = local_clock_->getLocalTime();
-        int64_t tmp;
-
-        if (now >= slew_change_end_time_) {
-            cur_correction_ = tgt_correction_;
-            next_slew_change_timeout_.setTimeout(-1);
-        } else {
-            time_to_cur_slew_.doForwardTransform(now, &tmp);
-
-            if (tmp > INT16_MAX)
-                cur_correction_ = INT16_MAX;
-            else if (tmp < INT16_MIN)
-                cur_correction_ = INT16_MIN;
-            else
-                cur_correction_ = static_cast<int16_t>(tmp);
-
-            next_slew_change_timeout_.setTimeout(kSlewChangeStepPeriod_mSec);
-            ret = false;
-        }
-
-        local_clock_->setLocalSlew(cur_correction_);
-    } else {
-        // Since we are not actually changing the rate of a HW clock, we don't
-        // need to worry to much about changing the slew rate so fast that we
-        // anger any downstream HDMI devices.
-        cur_correction_ = tgt_correction_;
-        next_slew_change_timeout_.setTimeout(-1);
-
-        // The SW clock recovery implemented by the common clock class expects
-        // values expressed in PPM. CO is in ppm.
-        common_clock_->setSlew(local_clock_->getLocalTime(), CO);
-    }
-
-bailout:
-    return ret;
-}
-
-int ClockRecoveryLoop::applyRateLimitedSlew() {
-    Mutex::Autolock lock(&lock_);
-
-    int ret = next_slew_change_timeout_.msecTillTimeout();
-    if (!ret) {
-        if (applySlew_l())
-            next_slew_change_timeout_.setTimeout(-1);
-        ret = next_slew_change_timeout_.msecTillTimeout();
-    }
-
-    return ret;
-}
-
-}  // namespace android
diff --git a/libs/common_time/clock_recovery.h b/libs/common_time/clock_recovery.h
deleted file mode 100644
index 8066a39..0000000
--- a/libs/common_time/clock_recovery.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __CLOCK_RECOVERY_H__
-#define __CLOCK_RECOVERY_H__
-
-#include <stdint.h>
-#include <common_time/ICommonClock.h>
-#include <utils/threads.h>
-
-#include "LinearTransform.h"
-
-#ifdef TIME_SERVICE_DEBUG
-#include "diag_thread.h"
-#endif
-
-#include "utils.h"
-
-namespace android {
-
-class CommonClock;
-class LocalClock;
-
-class ClockRecoveryLoop {
-  public:
-     ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock);
-    ~ClockRecoveryLoop();
-
-    void reset(bool position, bool frequency);
-    bool pushDisciplineEvent(int64_t local_time,
-                             int64_t nominal_common_time,
-                             int64_t data_point_rtt);
-    int32_t getLastErrorEstimate();
-
-    // Applies the next step in any ongoing slew change operation.  Returns a
-    // timeout suitable for use with poll/select indicating the number of mSec
-    // until the next change should be applied.
-    int applyRateLimitedSlew();
-
-  private:
-
-    // Tuned using the "Good Gain" method.
-    // See:
-    // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf
-
-    // Controller period (1Hz for now).
-    static const float dT;
-
-    // Controller gain, positive and unitless. Larger values converge faster,
-    // but can cause instability.
-    static const float Kc;
-
-    // Integral reset time. Smaller values cause loop to track faster, but can
-    // also cause instability.
-    static const float Ti;
-
-    // Controller output filter time constant. Range (0-1). Smaller values make
-    // output smoother, but slow convergence.
-    static const float Tf;
-
-    // Low-pass filter for bias tracker.
-    static const float bias_Fc; // HZ
-    static const float bias_RC; // Computed in constructor.
-    static const float bias_Alpha; // Computed inconstructor.
-
-    // The maximum allowed error (as indicated by a  pushDisciplineEvent) before
-    // we panic.
-    static const int64_t panic_thresh_;
-
-    // The maximum allowed error rtt time for packets to be used for control
-    // feedback, unless the packet is the best in recent memory.
-    static const int64_t control_thresh_;
-
-    typedef struct {
-        int64_t local_time;
-        int64_t observed_common_time;
-        int64_t nominal_common_time;
-        int64_t rtt;
-        bool point_used;
-    } DisciplineDataPoint;
-
-    static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count);
-
-    void reset_l(bool position, bool frequency);
-    void setTargetCorrection_l(int32_t tgt);
-    bool applySlew_l();
-
-    // The local clock HW abstraction we use as the basis for common time.
-    LocalClock* local_clock_;
-    bool local_clock_can_slew_;
-
-    // The common clock we end up controlling along with the lock used to
-    // serialize operations.
-    CommonClock* common_clock_;
-    Mutex lock_;
-
-    // parameters maintained while running and reset during a reset
-    // of the frequency correction.
-    bool    last_error_est_valid_;
-    int32_t last_error_est_usec_;
-    float last_delta_f_;
-    int32_t tgt_correction_;
-    int32_t cur_correction_;
-    LinearTransform time_to_cur_slew_;
-    int64_t slew_change_end_time_;
-    Timeout next_slew_change_timeout_;
-
-    // Contoller Output.
-    float CO;
-
-    // Bias tracking for trajectory estimation.
-    float CObias;
-    float lastCObias;
-
-    // Controller output bounds. The controller will not try to
-    // slew faster that +/-100ppm offset from center per interation.
-    static const float COmin;
-    static const float COmax;
-
-    // State kept for filtering the discipline data.
-    static const uint32_t kFilterSize = 16;
-    DisciplineDataPoint filter_data_[kFilterSize];
-    uint32_t filter_wr_;
-    bool filter_full_;
-
-    static const uint32_t kStartupFilterSize = 4;
-    DisciplineDataPoint startup_filter_data_[kStartupFilterSize];
-    uint32_t startup_filter_wr_;
-
-    // Minimum number of milliseconds over which we allow a full range change
-    // (from rail to rail) of the VCXO control signal.  This is the rate
-    // limiting factor which keeps us from changing the clock rate so fast that
-    // we get in trouble with certain HDMI sinks.
-    static const uint32_t kMinFullRangeSlewChange_mSec;
-
-    // How much time (in msec) to wait 
-    static const int kSlewChangeStepPeriod_mSec;
-
-#ifdef TIME_SERVICE_DEBUG
-    sp<DiagThread> diag_thread_;
-#endif
-};
-
-}  // namespace android
-
-#endif  // __CLOCK_RECOVERY_H__
diff --git a/libs/common_time/common_clock.cpp b/libs/common_time/common_clock.cpp
deleted file mode 100644
index aed52f1..0000000
--- a/libs/common_time/common_clock.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define __STDC_LIMIT_MACROS
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include <inttypes.h>
-#include <stdint.h>
-
-#include <utils/Errors.h>
-
-#include "common_clock.h"
-
-namespace android {
-
-CommonClock::CommonClock() {
-    cur_slew_        = 0;
-    cur_trans_valid_ = false;
-
-    cur_trans_.a_zero = 0;
-    cur_trans_.b_zero = 0;
-    cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = 1;
-    cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = 1;
-    duration_trans_ = cur_trans_;
-}
-
-bool CommonClock::init(uint64_t local_freq) {
-    Mutex::Autolock lock(&lock_);
-
-    if (!local_freq)
-        return false;
-
-    uint64_t numer = kCommonFreq;
-    uint64_t denom = local_freq;
-
-    LinearTransform::reduce(&numer, &denom);
-    if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) {
-        ALOGE("Overflow in CommonClock::init while trying to reduce %" PRIu64 "/%" PRIu64,
-             kCommonFreq, local_freq);
-        return false;
-    }
-
-    cur_trans_.a_to_b_numer = local_to_common_freq_numer_ =
-        static_cast<uint32_t>(numer);
-    cur_trans_.a_to_b_denom = local_to_common_freq_denom_ =
-        static_cast<uint32_t>(denom);
-    duration_trans_ = cur_trans_;
-
-    return true;
-}
-
-status_t CommonClock::localToCommon(int64_t local, int64_t *common_out) const {
-    Mutex::Autolock lock(&lock_);
-
-    if (!cur_trans_valid_)
-        return INVALID_OPERATION;
-
-    if (!cur_trans_.doForwardTransform(local, common_out))
-        return INVALID_OPERATION;
-
-    return OK;
-}
-
-status_t CommonClock::commonToLocal(int64_t common, int64_t *local_out) const {
-    Mutex::Autolock lock(&lock_);
-
-    if (!cur_trans_valid_)
-        return INVALID_OPERATION;
-
-    if (!cur_trans_.doReverseTransform(common, local_out))
-        return INVALID_OPERATION;
-
-    return OK;
-}
-
-int64_t CommonClock::localDurationToCommonDuration(int64_t localDur) const {
-    int64_t ret;
-    duration_trans_.doForwardTransform(localDur, &ret);
-    return ret;
-}
-
-void CommonClock::setBasis(int64_t local, int64_t common) {
-    Mutex::Autolock lock(&lock_);
-
-    cur_trans_.a_zero = local;
-    cur_trans_.b_zero = common;
-    cur_trans_valid_ = true;
-}
-
-void CommonClock::resetBasis() {
-    Mutex::Autolock lock(&lock_);
-
-    cur_trans_.a_zero = 0;
-    cur_trans_.b_zero = 0;
-    cur_trans_valid_ = false;
-}
-
-status_t CommonClock::setSlew(int64_t change_time, int32_t ppm) {
-    Mutex::Autolock lock(&lock_);
-
-    int64_t new_local_basis;
-    int64_t new_common_basis;
-
-    if (cur_trans_valid_) {
-        new_local_basis = change_time;
-        if (!cur_trans_.doForwardTransform(change_time, &new_common_basis)) {
-            ALOGE("Overflow when attempting to set slew rate to %d", ppm);
-            return INVALID_OPERATION;
-        }
-    } else {
-        new_local_basis = 0;
-        new_common_basis = 0;
-    }
-
-    cur_slew_ = ppm;
-    uint32_t n1 = local_to_common_freq_numer_;
-    uint32_t n2 = 1000000 + cur_slew_;
-
-    uint32_t d1 = local_to_common_freq_denom_;
-    uint32_t d2 = 1000000;
-
-    // n1/d1 has already been reduced, no need to do so here.
-    LinearTransform::reduce(&n1, &d2);
-    LinearTransform::reduce(&n2, &d1);
-    LinearTransform::reduce(&n2, &d2);
-
-    cur_trans_.a_zero = new_local_basis;
-    cur_trans_.b_zero = new_common_basis;
-    cur_trans_.a_to_b_numer = n1 * n2;
-    cur_trans_.a_to_b_denom = d1 * d2;
-
-    return OK;
-}
-
-}  // namespace android
diff --git a/libs/common_time/common_clock.h b/libs/common_time/common_clock.h
deleted file mode 100644
index 5e4e5f5..0000000
--- a/libs/common_time/common_clock.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __COMMON_CLOCK_H__
-#define __COMMON_CLOCK_H__
-
-#include <stdint.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-
-#include "LinearTransform.h"
-
-namespace android {
-
-class CommonClock {
-  public:
-    CommonClock();
-
-    bool      init(uint64_t local_freq);
-
-    status_t  localToCommon(int64_t local, int64_t *common_out) const;
-    status_t  commonToLocal(int64_t common, int64_t *local_out) const;
-    int64_t   localDurationToCommonDuration(int64_t localDur) const;
-    uint64_t  getCommonFreq() const { return kCommonFreq; }
-    bool      isValid() const { return cur_trans_valid_; }
-    status_t  setSlew(int64_t change_time, int32_t ppm);
-    void      setBasis(int64_t local, int64_t common);
-    void      resetBasis();
-  private:
-    mutable Mutex lock_;
-
-    int32_t  cur_slew_;
-    uint32_t local_to_common_freq_numer_;
-    uint32_t local_to_common_freq_denom_;
-
-    LinearTransform duration_trans_;
-    LinearTransform cur_trans_;
-    bool cur_trans_valid_;
-
-    static const uint64_t kCommonFreq = 1000000ull;
-};
-
-}  // namespace android
-#endif  // __COMMON_CLOCK_H__
diff --git a/libs/common_time/common_clock_service.cpp b/libs/common_time/common_clock_service.cpp
deleted file mode 100644
index 592ab1d..0000000
--- a/libs/common_time/common_clock_service.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <common_time/local_clock.h>
-#include <utils/String8.h>
-
-#include "common_clock_service.h"
-#include "common_clock.h"
-#include "common_time_server.h"
-
-namespace android {
-
-sp<CommonClockService> CommonClockService::instantiate(
-        CommonTimeServer& timeServer) {
-    sp<CommonClockService> tcc = new CommonClockService(timeServer);
-    if (tcc == NULL)
-        return NULL;
-
-    defaultServiceManager()->addService(ICommonClock::kServiceName, tcc);
-    return tcc;
-}
-
-status_t CommonClockService::dump(int fd, const Vector<String16>& args) {
-    Mutex::Autolock lock(mRegistrationLock);
-    return mTimeServer.dumpClockInterface(fd, args, mListeners.size());
-}
-
-status_t CommonClockService::isCommonTimeValid(bool* valid,
-                                               uint32_t* timelineID) {
-    return mTimeServer.isCommonTimeValid(valid, timelineID);
-}
-
-status_t CommonClockService::commonTimeToLocalTime(int64_t  commonTime,
-                                                   int64_t* localTime) {
-    return mTimeServer.getCommonClock().commonToLocal(commonTime, localTime);
-}
-
-status_t CommonClockService::localTimeToCommonTime(int64_t  localTime,
-                                                   int64_t* commonTime) {
-    return mTimeServer.getCommonClock().localToCommon(localTime, commonTime);
-}
-
-status_t CommonClockService::getCommonTime(int64_t* commonTime) {
-    return localTimeToCommonTime(mTimeServer.getLocalClock().getLocalTime(), commonTime);
-}
-
-status_t CommonClockService::getCommonFreq(uint64_t* freq) {
-    *freq = mTimeServer.getCommonClock().getCommonFreq();
-    return OK;
-}
-
-status_t CommonClockService::getLocalTime(int64_t* localTime) {
-    *localTime = mTimeServer.getLocalClock().getLocalTime();
-    return OK;
-}
-
-status_t CommonClockService::getLocalFreq(uint64_t* freq) {
-    *freq = mTimeServer.getLocalClock().getLocalFreq();
-    return OK;
-}
-
-status_t CommonClockService::getEstimatedError(int32_t* estimate) {
-    *estimate = mTimeServer.getEstimatedError();
-    return OK;
-}
-
-status_t CommonClockService::getTimelineID(uint64_t* id) {
-    *id = mTimeServer.getTimelineID();
-    return OK;
-}
-
-status_t CommonClockService::getState(State* state) {
-    *state = mTimeServer.getState();
-    return OK;
-}
-
-status_t CommonClockService::getMasterAddr(struct sockaddr_storage* addr) {
-    return mTimeServer.getMasterAddr(addr);
-}
-
-status_t CommonClockService::registerListener(
-        const sp<ICommonClockListener>& listener) {
-    Mutex::Autolock lock(mRegistrationLock);
-
-    {   // scoping for autolock pattern
-        Mutex::Autolock lock(mCallbackLock);
-        // check whether this is a duplicate
-        for (size_t i = 0; i < mListeners.size(); i++) {
-            if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener))
-                return ALREADY_EXISTS;
-        }
-    }
-
-    mListeners.add(listener);
-    mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
-    return IInterface::asBinder(listener)->linkToDeath(this);
-}
-
-status_t CommonClockService::unregisterListener(
-        const sp<ICommonClockListener>& listener) {
-    Mutex::Autolock lock(mRegistrationLock);
-    status_t ret_val = NAME_NOT_FOUND;
-
-    {   // scoping for autolock pattern
-        Mutex::Autolock lock(mCallbackLock);
-        for (size_t i = 0; i < mListeners.size(); i++) {
-            if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
-                IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
-                mListeners.removeAt(i);
-                ret_val = OK;
-                break;
-            }
-        }
-    }
-
-    mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
-    return ret_val;
-}
-
-void CommonClockService::binderDied(const wp<IBinder>& who) {
-    Mutex::Autolock lock(mRegistrationLock);
-
-    {   // scoping for autolock pattern
-        Mutex::Autolock lock(mCallbackLock);
-        for (size_t i = 0; i < mListeners.size(); i++) {
-            if (IInterface::asBinder(mListeners[i]) == who) {
-                mListeners.removeAt(i);
-                break;
-            }
-        }
-    }
-
-    mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
-}
-
-void CommonClockService::notifyOnTimelineChanged(uint64_t timelineID) {
-    Mutex::Autolock lock(mCallbackLock);
-
-    for (size_t i = 0; i < mListeners.size(); i++) {
-        mListeners[i]->onTimelineChanged(timelineID);
-    }
-}
-
-}; // namespace android
diff --git a/libs/common_time/common_clock_service.h b/libs/common_time/common_clock_service.h
deleted file mode 100644
index aea507e..0000000
--- a/libs/common_time/common_clock_service.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef ANDROID_COMMON_CLOCK_SERVICE_H
-#define ANDROID_COMMON_CLOCK_SERVICE_H
-
-#include <sys/socket.h>
-#include <common_time/ICommonClock.h>
-
-namespace android {
-
-class CommonTimeServer;
-
-class CommonClockService : public BnCommonClock,
-                           public android::IBinder::DeathRecipient {
-  public:
-    static sp<CommonClockService> instantiate(CommonTimeServer& timeServer);
-
-    virtual status_t dump(int fd, const Vector<String16>& args);
-
-    virtual status_t isCommonTimeValid(bool* valid, uint32_t *timelineID);
-    virtual status_t commonTimeToLocalTime(int64_t  common_time,
-                                           int64_t* local_time);
-    virtual status_t localTimeToCommonTime(int64_t  local_time,
-                                           int64_t* common_time);
-    virtual status_t getCommonTime(int64_t* common_time);
-    virtual status_t getCommonFreq(uint64_t* freq);
-    virtual status_t getLocalTime(int64_t* local_time);
-    virtual status_t getLocalFreq(uint64_t* freq);
-    virtual status_t getEstimatedError(int32_t* estimate);
-    virtual status_t getTimelineID(uint64_t* id);
-    virtual status_t getState(ICommonClock::State* state);
-    virtual status_t getMasterAddr(struct sockaddr_storage* addr);
-
-    virtual status_t registerListener(
-            const sp<ICommonClockListener>& listener);
-    virtual status_t unregisterListener(
-            const sp<ICommonClockListener>& listener);
-
-    void notifyOnTimelineChanged(uint64_t timelineID);
-
-  private:
-    explicit CommonClockService(CommonTimeServer& timeServer)
-        : mTimeServer(timeServer) { };
-
-    virtual void binderDied(const wp<IBinder>& who);
-
-    CommonTimeServer& mTimeServer;
-
-    // locks used to synchronize access to the list of registered listeners.
-    // The callback lock is held whenever the list is used to perform callbacks
-    // or while the list is being modified.  The registration lock used to
-    // serialize access across registerListener, unregisterListener, and
-    // binderDied.
-    //
-    // The reason for two locks is that registerListener, unregisterListener,
-    // and binderDied each call into the core service and obtain the core
-    // service thread lock when they call reevaluateAutoDisableState.  The core
-    // service thread obtains the main thread lock whenever its thread is
-    // running, and sometimes needs to call notifyOnTimelineChanged which then
-    // obtains the callback lock.  If callers of registration functions were
-    // holding the callback lock when they called into the core service, we
-    // would have a classic A/B, B/A ordering deadlock.  To avoid this, the
-    // registration functions hold the registration lock for the duration of
-    // their call, but hold the callback lock only while they mutate the list.
-    // This way, the list's size cannot change (because of the registration
-    // lock) during the call into reevaluateAutoDisableState, but the core work
-    // thread can still safely call notifyOnTimelineChanged while holding the
-    // main thread lock.
-    Mutex mCallbackLock;
-    Mutex mRegistrationLock;
-
-    Vector<sp<ICommonClockListener> > mListeners;
-};
-
-};  // namespace android
-
-#endif  // ANDROID_COMMON_CLOCK_SERVICE_H
diff --git a/libs/common_time/common_time_config_service.cpp b/libs/common_time/common_time_config_service.cpp
deleted file mode 100644
index 9585618..0000000
--- a/libs/common_time/common_time_config_service.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/String8.h>
-
-#include "common_time_config_service.h"
-#include "common_time_server.h"
-
-namespace android {
-
-sp<CommonTimeConfigService> CommonTimeConfigService::instantiate(
-        CommonTimeServer& timeServer) {
-    sp<CommonTimeConfigService> ctcs = new CommonTimeConfigService(timeServer);
-    if (ctcs == NULL)
-        return NULL;
-
-    defaultServiceManager()->addService(ICommonTimeConfig::kServiceName, ctcs);
-    return ctcs;
-}
-
-status_t CommonTimeConfigService::dump(int fd, const Vector<String16>& args) {
-    return mTimeServer.dumpConfigInterface(fd, args);
-}
-
-status_t CommonTimeConfigService::getMasterElectionPriority(uint8_t *priority) {
-    return mTimeServer.getMasterElectionPriority(priority);
-}
-
-status_t CommonTimeConfigService::setMasterElectionPriority(uint8_t priority) {
-    return mTimeServer.setMasterElectionPriority(priority);
-}
-
-status_t CommonTimeConfigService::getMasterElectionEndpoint(
-        struct sockaddr_storage *addr) {
-    return mTimeServer.getMasterElectionEndpoint(addr);
-}
-
-status_t CommonTimeConfigService::setMasterElectionEndpoint(
-        const struct sockaddr_storage *addr) {
-    return mTimeServer.setMasterElectionEndpoint(addr);
-}
-
-status_t CommonTimeConfigService::getMasterElectionGroupId(uint64_t *id) {
-    return mTimeServer.getMasterElectionGroupId(id);
-}
-
-status_t CommonTimeConfigService::setMasterElectionGroupId(uint64_t id) {
-    return mTimeServer.setMasterElectionGroupId(id);
-}
-
-status_t CommonTimeConfigService::getInterfaceBinding(String16& ifaceName) {
-    String8 tmp;
-    status_t ret = mTimeServer.getInterfaceBinding(tmp);
-    ifaceName = String16(tmp);
-    return ret;
-}
-
-status_t CommonTimeConfigService::setInterfaceBinding(const String16& ifaceName) {
-    String8 tmp(ifaceName);
-    return mTimeServer.setInterfaceBinding(tmp);
-}
-
-status_t CommonTimeConfigService::getMasterAnnounceInterval(int *interval) {
-    return mTimeServer.getMasterAnnounceInterval(interval);
-}
-
-status_t CommonTimeConfigService::setMasterAnnounceInterval(int interval) {
-    return mTimeServer.setMasterAnnounceInterval(interval);
-}
-
-status_t CommonTimeConfigService::getClientSyncInterval(int *interval) {
-    return mTimeServer.getClientSyncInterval(interval);
-}
-
-status_t CommonTimeConfigService::setClientSyncInterval(int interval) {
-    return mTimeServer.setClientSyncInterval(interval);
-}
-
-status_t CommonTimeConfigService::getPanicThreshold(int *threshold) {
-    return mTimeServer.getPanicThreshold(threshold);
-}
-
-status_t CommonTimeConfigService::setPanicThreshold(int threshold) {
-    return mTimeServer.setPanicThreshold(threshold);
-}
-
-status_t CommonTimeConfigService::getAutoDisable(bool *autoDisable) {
-    return mTimeServer.getAutoDisable(autoDisable);
-}
-
-status_t CommonTimeConfigService::setAutoDisable(bool autoDisable) {
-    return mTimeServer.setAutoDisable(autoDisable);
-}
-
-status_t CommonTimeConfigService::forceNetworklessMasterMode() {
-    return mTimeServer.forceNetworklessMasterMode();
-}
-
-}; // namespace android
diff --git a/libs/common_time/common_time_config_service.h b/libs/common_time/common_time_config_service.h
deleted file mode 100644
index 23abb1a..0000000
--- a/libs/common_time/common_time_config_service.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_COMMON_TIME_CONFIG_SERVICE_H
-#define ANDROID_COMMON_TIME_CONFIG_SERVICE_H
-
-#include <sys/socket.h>
-#include <common_time/ICommonTimeConfig.h>
-
-namespace android {
-
-class String16;
-class CommonTimeServer;
-
-class CommonTimeConfigService : public BnCommonTimeConfig {
-  public:
-    static sp<CommonTimeConfigService> instantiate(CommonTimeServer& timeServer);
-
-    virtual status_t dump(int fd, const Vector<String16>& args);
-
-    virtual status_t getMasterElectionPriority(uint8_t *priority);
-    virtual status_t setMasterElectionPriority(uint8_t priority);
-    virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr);
-    virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr);
-    virtual status_t getMasterElectionGroupId(uint64_t *id);
-    virtual status_t setMasterElectionGroupId(uint64_t id);
-    virtual status_t getInterfaceBinding(String16& ifaceName);
-    virtual status_t setInterfaceBinding(const String16& ifaceName);
-    virtual status_t getMasterAnnounceInterval(int *interval);
-    virtual status_t setMasterAnnounceInterval(int interval);
-    virtual status_t getClientSyncInterval(int *interval);
-    virtual status_t setClientSyncInterval(int interval);
-    virtual status_t getPanicThreshold(int *threshold);
-    virtual status_t setPanicThreshold(int threshold);
-    virtual status_t getAutoDisable(bool *autoDisable);
-    virtual status_t setAutoDisable(bool autoDisable);
-    virtual status_t forceNetworklessMasterMode();
-
-  private:
-    explicit CommonTimeConfigService(CommonTimeServer& timeServer)
-        : mTimeServer(timeServer) { }
-    CommonTimeServer& mTimeServer;
-
-};
-
-};  // namespace android
-
-#endif  // ANDROID_COMMON_TIME_CONFIG_SERVICE_H
diff --git a/libs/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp
deleted file mode 100644
index b1495ef..0000000
--- a/libs/common_time/common_time_server.cpp
+++ /dev/null
@@ -1,1507 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * A service that exchanges time synchronization information between
- * a master that defines a timeline and clients that follow the timeline.
- */
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include <arpa/inet.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/if_ether.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/ip.h>
-#include <poll.h>
-#include <stdio.h>
-#include <sys/eventfd.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <common_time/local_clock.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <utils/Timers.h>
-
-#include "common_clock_service.h"
-#include "common_time_config_service.h"
-#include "common_time_server.h"
-#include "common_time_server_packets.h"
-#include "clock_recovery.h"
-#include "common_clock.h"
-
-#define MAX_INT ((int)0x7FFFFFFF)
-
-namespace android {
-
-const char*    CommonTimeServer::kDefaultMasterElectionAddr = "255.255.255.255";
-const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8886;
-const uint64_t CommonTimeServer::kDefaultSyncGroupID = 1;
-const uint8_t  CommonTimeServer::kDefaultMasterPriority = 1;
-const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000;
-const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000;
-const uint32_t CommonTimeServer::kDefaultPanicThresholdUsec = 50000;
-const bool     CommonTimeServer::kDefaultAutoDisable = true;
-const int      CommonTimeServer::kSetupRetryTimeoutMs = 30000;
-const int64_t  CommonTimeServer::kNoGoodDataPanicThresholdUsec = 600000000ll;
-const uint32_t CommonTimeServer::kRTTDiscardPanicThreshMultiplier = 5;
-
-// timeout value representing an infinite timeout
-const int CommonTimeServer::kInfiniteTimeout = -1;
-
-/*** Initial state constants ***/
-
-// number of WhoIsMaster attempts sent before giving up
-const int CommonTimeServer::kInitial_NumWhoIsMasterRetries = 6;
-
-// timeout used when waiting for a response to a WhoIsMaster request
-const int CommonTimeServer::kInitial_WhoIsMasterTimeoutMs = 500;
-
-/*** Client state constants ***/
-
-// number of sync requests that can fail before a client assumes its master
-// is dead
-const int CommonTimeServer::kClient_NumSyncRequestRetries = 10;
-
-/*** Master state constants ***/
-
-/*** Ronin state constants ***/
-
-// number of WhoIsMaster attempts sent before declaring ourselves master
-const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 20;
-
-// timeout used when waiting for a response to a WhoIsMaster request
-const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500;
-
-/*** WaitForElection state constants ***/
-
-// how long do we wait for an announcement from a master before
-// trying another election?
-const int CommonTimeServer::kWaitForElection_TimeoutMs = 12500;
-
-CommonTimeServer::CommonTimeServer()
-    : Thread(false)
-    , mState(ICommonClock::STATE_INITIAL)
-    , mClockRecovery(&mLocalClock, &mCommonClock)
-    , mSocket(-1)
-    , mLastPacketRxLocalTime(0)
-    , mTimelineID(ICommonClock::kInvalidTimelineID)
-    , mClockSynced(false)
-    , mCommonClockHasClients(false)
-    , mStateChangeLog("Recent State Change Events", 30)
-    , mElectionLog("Recent Master Election Traffic", 30)
-    , mBadPktLog("Recent Bad Packet RX Info", 8)
-    , mInitial_WhoIsMasterRequestTimeouts(0)
-    , mClient_MasterDeviceID(0)
-    , mClient_MasterDevicePriority(0)
-    , mRonin_WhoIsMasterRequestTimeouts(0) {
-    // zero out sync stats
-    resetSyncStats();
-
-    // Setup the master election endpoint to use the default.
-    struct sockaddr_in* meep =
-        reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP);
-    memset(&mMasterElectionEP, 0, sizeof(mMasterElectionEP));
-    inet_aton(kDefaultMasterElectionAddr, &meep->sin_addr);
-    meep->sin_family = AF_INET;
-    meep->sin_port   = htons(kDefaultMasterElectionPort);
-
-    // Zero out the master endpoint.
-    memset(&mMasterEP, 0, sizeof(mMasterEP));
-    mMasterEPValid    = false;
-    mBindIfaceValid   = false;
-    setForceLowPriority(false);
-
-    // Set all remaining configuration parameters to their defaults.
-    mDeviceID                 = 0;
-    mSyncGroupID              = kDefaultSyncGroupID;
-    mMasterPriority           = kDefaultMasterPriority;
-    mMasterAnnounceIntervalMs = kDefaultMasterAnnounceIntervalMs;
-    mSyncRequestIntervalMs    = kDefaultSyncRequestIntervalMs;
-    mPanicThresholdUsec       = kDefaultPanicThresholdUsec;
-    mAutoDisable              = kDefaultAutoDisable;
-
-    // Create the eventfd we will use to signal our thread to wake up when
-    // needed.
-    mWakeupThreadFD = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
-
-    // seed the random number generator (used to generated timeline IDs)
-    srand48(static_cast<unsigned int>(systemTime()));
-}
-
-CommonTimeServer::~CommonTimeServer() {
-    shutdownThread();
-
-    // No need to grab the lock here.  We are in the destructor; if the the user
-    // has a thread in any of the APIs while the destructor is being called,
-    // there is a threading problem a the application level we cannot reasonably
-    // do anything about.
-    cleanupSocket_l();
-
-    if (mWakeupThreadFD >= 0) {
-        close(mWakeupThreadFD);
-        mWakeupThreadFD = -1;
-    }
-}
-
-bool CommonTimeServer::startServices() {
-    // start the ICommonClock service
-    mICommonClock = CommonClockService::instantiate(*this);
-    if (mICommonClock == NULL)
-        return false;
-
-    // start the ICommonTimeConfig service
-    mICommonTimeConfig = CommonTimeConfigService::instantiate(*this);
-    if (mICommonTimeConfig == NULL)
-        return false;
-
-    return true;
-}
-
-bool CommonTimeServer::threadLoop() {
-    // Register our service interfaces.
-    if (!startServices())
-        return false;
-
-    // Hold the lock while we are in the main thread loop.  It will release the
-    // lock when it blocks, and hold the lock at all other times.
-    mLock.lock();
-    runStateMachine_l();
-    mLock.unlock();
-
-    IPCThreadState::self()->stopProcess();
-    return false;
-}
-
-bool CommonTimeServer::runStateMachine_l() {
-    if (!mLocalClock.initCheck())
-        return false;
-
-    if (!mCommonClock.init(mLocalClock.getLocalFreq()))
-        return false;
-
-    // Enter the initial state.
-    becomeInitial("startup");
-
-    // run the state machine
-    while (!exitPending()) {
-        struct pollfd pfds[2];
-        int rc, timeout;
-        int eventCnt = 0;
-        int64_t wakeupTime;
-        uint32_t t1, t2;
-        bool needHandleTimeout = false;
-
-        // We are always interested in our wakeup FD.
-        pfds[eventCnt].fd      = mWakeupThreadFD;
-        pfds[eventCnt].events  = POLLIN;
-        pfds[eventCnt].revents = 0;
-        eventCnt++;
-
-        // If we have a valid socket, then we are interested in what it has to
-        // say as well.
-        if (mSocket >= 0) {
-            pfds[eventCnt].fd      = mSocket;
-            pfds[eventCnt].events  = POLLIN;
-            pfds[eventCnt].revents = 0;
-            eventCnt++;
-        }
-
-        t1 = static_cast<uint32_t>(mCurTimeout.msecTillTimeout());
-        t2 = static_cast<uint32_t>(mClockRecovery.applyRateLimitedSlew());
-        timeout = static_cast<int>(t1 < t2 ? t1 : t2);
-
-        // Note, we were holding mLock when this function was called.  We
-        // release it only while we are blocking and hold it at all other times.
-        mLock.unlock();
-        rc          = poll(pfds, eventCnt, timeout);
-        wakeupTime  = mLocalClock.getLocalTime();
-        mLock.lock();
-
-        // Is it time to shutdown?  If so, don't hesitate... just do it.
-        if (exitPending())
-            break;
-
-        // Did the poll fail?  This should never happen and is fatal if it does.
-        if (rc < 0) {
-            ALOGE("%s:%d poll failed", __PRETTY_FUNCTION__, __LINE__);
-            return false;
-        }
-
-        if (rc == 0) {
-            needHandleTimeout = !mCurTimeout.msecTillTimeout();
-            if (needHandleTimeout)
-                mCurTimeout.setTimeout(kInfiniteTimeout);
-        }
-
-        // Were we woken up on purpose?  If so, clear the eventfd with a read.
-        if (pfds[0].revents)
-            clearPendingWakeupEvents_l();
-
-        // Is out bind address dirty?  If so, clean up our socket (if any).
-        // Alternatively, do we have an active socket but should be auto
-        // disabled?  If so, release the socket and enter the proper sync state.
-        bool droppedSocket = false;
-        if (mBindIfaceDirty || ((mSocket >= 0) && shouldAutoDisable())) {
-            cleanupSocket_l();
-            mBindIfaceDirty = false;
-            droppedSocket = true;
-        }
-
-        // Do we not have a socket but should have one?  If so, try to set one
-        // up.
-        if ((mSocket < 0) && mBindIfaceValid && !shouldAutoDisable()) {
-            if (setupSocket_l()) {
-                // Success!  We are now joining a new network (either coming
-                // from no network, or coming from a potentially different
-                // network).  Force our priority to be lower so that we defer to
-                // any other masters which may already be on the network we are
-                // joining.  Later, when we enter either the client or the
-                // master state, we will clear this flag and go back to our
-                // normal election priority.
-                setForceLowPriority(true);
-                switch (mState) {
-                    // If we were in initial (whether we had a immediately
-                    // before this network or not) we want to simply reset the
-                    // system and start again.  Forcing a transition from
-                    // INITIAL to INITIAL should do the job.
-                    case CommonClockService::STATE_INITIAL:
-                        becomeInitial("bound interface");
-                        break;
-
-                    // If we were in the master state, then either we were the
-                    // master in a no-network situation, or we were the master
-                    // of a different network and have moved to a new interface.
-                    // In either case, immediately transition to Ronin at low
-                    // priority.  If there is no one in the network we just
-                    // joined, we will become master soon enough.  If there is,
-                    // we want to be certain to defer master status to the
-                    // existing timeline currently running on the network.
-                    //
-                    case CommonClockService::STATE_MASTER:
-                        becomeRonin("leaving networkless mode");
-                        break;
-
-                    // If we were in any other state (CLIENT, RONIN, or
-                    // WAIT_FOR_ELECTION) then we must be moving from one
-                    // network to another.  We have lost our old master;
-                    // transition to RONIN in an attempt to find a new master.
-                    // If there are none out there, we will just assume
-                    // responsibility for the timeline we used to be a client
-                    // of.
-                    default:
-                        becomeRonin("bound interface");
-                        break;
-                }
-            } else {
-                // That's odd... we failed to set up our socket.  This could be
-                // due to some transient network change which will work itself
-                // out shortly; schedule a retry attempt in the near future.
-                mCurTimeout.setTimeout(kSetupRetryTimeoutMs);
-            }
-
-            // One way or the other, we don't have any data to process at this
-            // point (since we just tried to bulid a new socket).  Loop back
-            // around and wait for the next thing to do.
-            continue;
-        } else if (droppedSocket) {
-            // We just lost our socket, and for whatever reason (either no
-            // config, or auto disable engaged) we are not supposed to rebuild
-            // one at this time.  We are not going to rebuild our socket until
-            // something about our config/auto-disabled status changes, so we
-            // are basically in network-less mode.  If we are already in either
-            // INITIAL or MASTER, just stay there until something changes.  If
-            // we are in any other state (CLIENT, RONIN or WAIT_FOR_ELECTION),
-            // then transition to either INITIAL or MASTER depending on whether
-            // or not our timeline is valid.
-            mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-                    "Entering networkless mode interface is %s, "
-                    "shouldAutoDisable = %s",
-                    mBindIfaceValid ? "valid" : "invalid",
-                    shouldAutoDisable() ? "true" : "false");
-            if ((mState != ICommonClock::STATE_INITIAL) &&
-                (mState != ICommonClock::STATE_MASTER)) {
-                if (mTimelineID == ICommonClock::kInvalidTimelineID)
-                    becomeInitial("network-less mode");
-                else
-                    becomeMaster("network-less mode");
-            }
-
-            continue;
-        }
-
-        // Time to handle the timeouts?
-        if (needHandleTimeout) {
-            if (!handleTimeout())
-                ALOGE("handleTimeout failed");
-            continue;
-        }
-
-        // Does our socket have data for us (assuming we still have one, we
-        // may have RXed a packet at the same time as a config change telling us
-        // to shut our socket down)?  If so, process its data.
-        if ((mSocket >= 0) && (eventCnt > 1) && (pfds[1].revents)) {
-            mLastPacketRxLocalTime = wakeupTime;
-            if (!handlePacket())
-                ALOGE("handlePacket failed");
-        }
-    }
-
-    cleanupSocket_l();
-    return true;
-}
-
-void CommonTimeServer::clearPendingWakeupEvents_l() {
-    int64_t tmp;
-    read(mWakeupThreadFD, &tmp, sizeof(tmp));
-}
-
-void CommonTimeServer::wakeupThread_l() {
-    int64_t tmp = 1;
-    write(mWakeupThreadFD, &tmp, sizeof(tmp));
-}
-
-void CommonTimeServer::cleanupSocket_l() {
-    if (mSocket >= 0) {
-        close(mSocket);
-        mSocket = -1;
-    }
-}
-
-void CommonTimeServer::shutdownThread() {
-    // Flag the work thread for shutdown.
-    this->requestExit();
-
-    // Signal the thread in case its sleeping.
-    mLock.lock();
-    wakeupThread_l();
-    mLock.unlock();
-
-    // Wait for the thread to exit.
-    this->join();
-}
-
-bool CommonTimeServer::setupSocket_l() {
-    int rc;
-    bool ret_val = false;
-    struct sockaddr_in* ipv4_addr = NULL;
-    char masterElectionEPStr[64];
-    const int one = 1;
-
-    // This should never be needed, but if we happened to have an old socket
-    // lying around, be sure to not leak it before proceeding.
-    cleanupSocket_l();
-
-    // If we don't have a valid endpoint to bind to, then how did we get here in
-    // the first place?  Regardless, we know that we are going to fail to bind,
-    // so don't even try.
-    if (!mBindIfaceValid)
-        return false;
-
-    sockaddrToString(mMasterElectionEP, true, masterElectionEPStr,
-                     sizeof(masterElectionEPStr));
-    mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-                        "Building socket :: bind = %s master election = %s",
-                        mBindIface.string(), masterElectionEPStr);
-
-    // TODO: add proper support for IPv6.  Right now, we block IPv6 addresses at
-    // the configuration interface level.
-    if (AF_INET != mMasterElectionEP.ss_family) {
-        mStateChangeLog.log(ANDROID_LOG_WARN, LOG_TAG,
-                            "TODO: add proper IPv6 support");
-        goto bailout;
-    }
-
-    // open a UDP socket for the timeline serivce
-    mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-    if (mSocket < 0) {
-        mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG,
-                            "Failed to create socket (errno = %d)", errno);
-        goto bailout;
-    }
-
-    // Bind to the selected interface using Linux's spiffy SO_BINDTODEVICE.
-    struct ifreq ifr;
-    memset(&ifr, 0, sizeof(ifr));
-    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", mBindIface.string());
-    ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0;
-    rc = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE,
-                    (void *)&ifr, sizeof(ifr));
-    if (rc) {
-        mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG,
-                            "Failed to bind socket at to interface %s "
-                            "(errno = %d)", ifr.ifr_name, errno);
-        goto bailout;
-    }
-
-    // Bind our socket to INADDR_ANY and the master election port.  The
-    // interface binding we made using SO_BINDTODEVICE should limit us to
-    // traffic only on the interface we are interested in.  We need to bind to
-    // INADDR_ANY and the specific master election port in order to be able to
-    // receive both unicast traffic and master election multicast traffic with
-    // just a single socket.
-    struct sockaddr_in bindAddr;
-    ipv4_addr = reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP);
-    memcpy(&bindAddr, ipv4_addr, sizeof(bindAddr));
-    bindAddr.sin_addr.s_addr = INADDR_ANY;
-    rc = bind(mSocket,
-              reinterpret_cast<const sockaddr *>(&bindAddr),
-              sizeof(bindAddr));
-    if (rc) {
-        mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG,
-                            "Failed to bind socket to port %hu (errno = %d)",
-                            ntohs(bindAddr.sin_port), errno);
-        goto bailout;
-    }
-
-    if (0xE0000000 == (ntohl(ipv4_addr->sin_addr.s_addr) & 0xF0000000)) {
-        // If our master election endpoint is a multicast address, be sure to join
-        // the multicast group.
-        struct ip_mreq mreq;
-        mreq.imr_multiaddr = ipv4_addr->sin_addr;
-        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
-        rc = setsockopt(mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-                        &mreq, sizeof(mreq));
-        if (rc == -1) {
-            ALOGE("Failed to join multicast group at %s.  (errno = %d)",
-                 masterElectionEPStr, errno);
-            goto bailout;
-        }
-
-        // disable loopback of multicast packets
-        const int zero = 0;
-        rc = setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
-                        &zero, sizeof(zero));
-        if (rc == -1) {
-            mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG,
-                                "Failed to disable multicast loopback "
-                                "(errno = %d)", errno);
-            goto bailout;
-        }
-    } else
-    if (ntohl(ipv4_addr->sin_addr.s_addr) == 0xFFFFFFFF) {
-        // If the master election address is the broadcast address, then enable
-        // the broadcast socket option
-        rc = setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
-        if (rc == -1) {
-            mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG,
-                                "Failed to enable broadcast (errno = %d)",
-                                errno);
-            goto bailout;
-        }
-    } else {
-        // If the master election address is neither broadcast, nor multicast,
-        // then we are misconfigured.  The config API layer should prevent this
-        // from ever happening.
-        goto bailout;
-    }
-
-    // Set the TTL of sent packets to 1.  (Time protocol sync should never leave
-    // the local subnet)
-    rc = setsockopt(mSocket, IPPROTO_IP, IP_TTL, &one, sizeof(one));
-    if (rc == -1) {
-        mStateChangeLog.log(ANDROID_LOG_ERROR, LOG_TAG,
-                            "Failed to set TTL to %d (errno = %d)", one, errno);
-        goto bailout;
-    }
-
-    // get the device's unique ID
-    if (!assignDeviceID())
-        goto bailout;
-
-    ret_val = true;
-
-bailout:
-    if (!ret_val)
-        cleanupSocket_l();
-    return ret_val;
-}
-
-// generate a unique device ID that can be used for arbitration
-bool CommonTimeServer::assignDeviceID() {
-    if (!mBindIfaceValid)
-        return false;
-
-    struct ifreq ifr;
-    memset(&ifr, 0, sizeof(ifr));
-    ifr.ifr_addr.sa_family = AF_INET;
-    strlcpy(ifr.ifr_name, mBindIface.string(), IFNAMSIZ);
-
-    int rc = ioctl(mSocket, SIOCGIFHWADDR, &ifr);
-    if (rc) {
-        ALOGE("%s:%d ioctl failed", __PRETTY_FUNCTION__, __LINE__);
-        return false;
-    }
-
-    if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) {
-        ALOGE("%s:%d got non-Ethernet address", __PRETTY_FUNCTION__, __LINE__);
-        return false;
-    }
-
-    mDeviceID = 0;
-    for (int i = 0; i < ETH_ALEN; i++) {
-        mDeviceID = (mDeviceID << 8) | ifr.ifr_hwaddr.sa_data[i];
-    }
-
-    return true;
-}
-
-// generate a new timeline ID
-void CommonTimeServer::assignTimelineID() {
-    do {
-        mTimelineID = (static_cast<uint64_t>(lrand48()) << 32)
-                    |  static_cast<uint64_t>(lrand48());
-    } while (mTimelineID == ICommonClock::kInvalidTimelineID);
-}
-
-// Select a preference between the device IDs of two potential masters.
-// Returns true if the first ID wins, or false if the second ID wins.
-bool CommonTimeServer::arbitrateMaster(
-        uint64_t deviceID1, uint8_t devicePrio1,
-        uint64_t deviceID2, uint8_t devicePrio2) {
-    return ((devicePrio1 >  devicePrio2) ||
-           ((devicePrio1 == devicePrio2) && (deviceID1 > deviceID2)));
-}
-
-static void hexDumpToString(const uint8_t* src, size_t src_len,
-                            char* dst, size_t dst_len) {
-    size_t offset = 0;
-    size_t i;
-
-    for (i = 0; (i < src_len) && (offset < dst_len); ++i) {
-        int res;
-        if (0 == (i % 16)) {
-            res = snprintf(dst + offset, dst_len - offset, "\n%04zx :", i);
-            if (res < 0)
-                break;
-            offset += res;
-            if (offset >= dst_len)
-                break;
-        }
-
-        res = snprintf(dst + offset, dst_len - offset, " %02x", src[i]);
-        if (res < 0)
-            break;
-        offset += res;
-    }
-
-    dst[dst_len - 1] = 0;
-}
-
-bool CommonTimeServer::handlePacket() {
-    uint8_t buf[256];
-    struct sockaddr_storage srcAddr;
-    socklen_t srcAddrLen = sizeof(srcAddr);
-
-    ssize_t recvBytes = recvfrom(
-            mSocket, buf, sizeof(buf), 0,
-            reinterpret_cast<sockaddr *>(&srcAddr), &srcAddrLen);
-
-    if (recvBytes < 0) {
-        mBadPktLog.log(ANDROID_LOG_ERROR, LOG_TAG, "recvfrom failed (%s)",
-                       strerror(errno));
-        return false;
-    }
-
-    UniversalTimeServicePacket pkt;
-    if (pkt.deserializePacket(buf, recvBytes, mSyncGroupID) < 0) {
-        char hex[256];
-        char srcEPStr[64];
-
-        hexDumpToString(buf, static_cast<size_t>(recvBytes), hex, sizeof(hex));
-        sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
-
-        mBadPktLog.log("Failed to parse %d byte packet from %s.%s",
-                       recvBytes, srcEPStr, hex);
-        return false;
-    }
-
-    bool result;
-    switch (pkt.packetType) {
-        case TIME_PACKET_WHO_IS_MASTER_REQUEST:
-            result = handleWhoIsMasterRequest(&pkt.p.who_is_master_request,
-                                              srcAddr);
-            break;
-
-        case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
-            result = handleWhoIsMasterResponse(&pkt.p.who_is_master_response,
-                                               srcAddr);
-            break;
-
-        case TIME_PACKET_SYNC_REQUEST:
-            result = handleSyncRequest(&pkt.p.sync_request, srcAddr);
-            break;
-
-        case TIME_PACKET_SYNC_RESPONSE:
-            result = handleSyncResponse(&pkt.p.sync_response, srcAddr);
-            break;
-
-        case TIME_PACKET_MASTER_ANNOUNCEMENT:
-            result = handleMasterAnnouncement(&pkt.p.master_announcement,
-                                              srcAddr);
-            break;
-
-        default: {
-            char srcEPStr[64];
-            sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
-
-            mBadPktLog.log(ANDROID_LOG_WARN, LOG_TAG,
-                           "unknown packet type (%d) from %s",
-                           pkt.packetType, srcEPStr);
-
-            result = false;
-        } break;
-    }
-
-    return result;
-}
-
-bool CommonTimeServer::handleTimeout() {
-    // If we have no socket, then this must be a timeout to retry socket setup.
-    if (mSocket < 0)
-        return true;
-
-    switch (mState) {
-        case ICommonClock::STATE_INITIAL:
-            return handleTimeoutInitial();
-        case ICommonClock::STATE_CLIENT:
-            return handleTimeoutClient();
-        case ICommonClock::STATE_MASTER:
-            return handleTimeoutMaster();
-        case ICommonClock::STATE_RONIN:
-            return handleTimeoutRonin();
-        case ICommonClock::STATE_WAIT_FOR_ELECTION:
-            return handleTimeoutWaitForElection();
-    }
-
-    return false;
-}
-
-bool CommonTimeServer::handleTimeoutInitial() {
-    if (++mInitial_WhoIsMasterRequestTimeouts ==
-            kInitial_NumWhoIsMasterRetries) {
-        // none of our attempts to discover a master succeeded, so make
-        // this device the master
-        return becomeMaster("initial timeout");
-    } else {
-        // retry the WhoIsMaster request
-        return sendWhoIsMasterRequest();
-    }
-}
-
-bool CommonTimeServer::handleTimeoutClient() {
-    if (shouldPanicNotGettingGoodData())
-        return becomeInitial("timeout panic, no good data");
-
-    if (mClient_SyncRequestPending) {
-        mClient_SyncRequestPending = false;
-
-        if (++mClient_SyncRequestTimeouts < kClient_NumSyncRequestRetries) {
-            // a sync request has timed out, so retry
-            return sendSyncRequest();
-        } else {
-            // The master has failed to respond to a sync request for too many
-            // times in a row.  Assume the master is dead and start electing
-            // a new master.
-            return becomeRonin("master not responding");
-        }
-    } else {
-        // initiate the next sync request
-        return sendSyncRequest();
-    }
-}
-
-bool CommonTimeServer::handleTimeoutMaster() {
-    // send another announcement from the master
-    return sendMasterAnnouncement();
-}
-
-bool CommonTimeServer::handleTimeoutRonin() {
-    if (++mRonin_WhoIsMasterRequestTimeouts == kRonin_NumWhoIsMasterRetries) {
-        // no other master is out there, so we won the election
-        return becomeMaster("no better masters detected");
-    } else {
-        return sendWhoIsMasterRequest();
-    }
-}
-
-bool CommonTimeServer::handleTimeoutWaitForElection() {
-    return becomeRonin("timeout waiting for election conclusion");
-}
-
-bool CommonTimeServer::handleWhoIsMasterRequest(
-        const WhoIsMasterRequestPacket* request,
-        const sockaddr_storage& srcAddr) {
-    // Skip our own messages which come back via broadcast loopback.
-    if (request->senderDeviceID == mDeviceID)
-        return true;
-
-    char srcEPStr[64];
-    sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
-    mElectionLog.log("RXed WhoIs master request while in state %s.  "
-                     "src %s reqTID %016llx ourTID %016llx",
-                     stateToString(mState), srcEPStr,
-                     request->timelineID, mTimelineID);
-
-    if (mState == ICommonClock::STATE_MASTER) {
-        // is this request related to this master's timeline?
-        if (request->timelineID != ICommonClock::kInvalidTimelineID &&
-            request->timelineID != mTimelineID)
-            return true;
-
-        WhoIsMasterResponsePacket pkt;
-        pkt.initHeader(mTimelineID, mSyncGroupID);
-        pkt.deviceID = mDeviceID;
-        pkt.devicePriority = effectivePriority();
-
-        mElectionLog.log("TXing WhoIs master resp to %s while in state %s.  "
-                         "ourTID %016llx ourGID %016llx ourDID %016llx "
-                         "ourPrio %u",
-                         srcEPStr, stateToString(mState),
-                         mTimelineID, mSyncGroupID,
-                         pkt.deviceID, pkt.devicePriority);
-
-        uint8_t buf[256];
-        ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
-        if (bufSz < 0)
-            return false;
-
-        ssize_t sendBytes = sendto(
-                mSocket, buf, bufSz, 0,
-                reinterpret_cast<const sockaddr *>(&srcAddr),
-                sizeof(srcAddr));
-        if (sendBytes == -1) {
-            ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__);
-            return false;
-        }
-    } else if (mState == ICommonClock::STATE_RONIN) {
-        // if we hear a WhoIsMaster request from another device following
-        // the same timeline and that device wins arbitration, then we will stop
-        // trying to elect ourselves master and will instead wait for an
-        // announcement from the election winner
-        if (request->timelineID != mTimelineID)
-            return true;
-
-        if (arbitrateMaster(request->senderDeviceID,
-                            request->senderDevicePriority,
-                            mDeviceID,
-                            effectivePriority()))
-            return becomeWaitForElection("would lose election");
-
-        return true;
-    } else if (mState == ICommonClock::STATE_INITIAL) {
-        // If a group of devices booted simultaneously (e.g. after a power
-        // outage) and all of them are in the initial state and there is no
-        // master, then each device may time out and declare itself master at
-        // the same time.  To avoid this, listen for
-        // WhoIsMaster(InvalidTimeline) requests from peers.  If we would lose
-        // arbitration against that peer, reset our timeout count so that the
-        // peer has a chance to become master before we time out.
-        if (request->timelineID == ICommonClock::kInvalidTimelineID &&
-                arbitrateMaster(request->senderDeviceID,
-                                request->senderDevicePriority,
-                                mDeviceID,
-                                effectivePriority())) {
-            mInitial_WhoIsMasterRequestTimeouts = 0;
-        }
-    }
-
-    return true;
-}
-
-bool CommonTimeServer::handleWhoIsMasterResponse(
-        const WhoIsMasterResponsePacket* response,
-        const sockaddr_storage& srcAddr) {
-    // Skip our own messages which come back via broadcast loopback.
-    if (response->deviceID == mDeviceID)
-        return true;
-
-    char srcEPStr[64];
-    sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
-    mElectionLog.log("RXed WhoIs master response while in state %s.  "
-                     "src %s respTID %016llx respDID %016llx respPrio %u "
-                     "ourTID %016llx",
-                     stateToString(mState), srcEPStr,
-                     response->timelineID,
-                     response->deviceID,
-                     static_cast<uint32_t>(response->devicePriority),
-                     mTimelineID);
-
-    if (mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN) {
-        return becomeClient(srcAddr,
-                            response->deviceID,
-                            response->devicePriority,
-                            response->timelineID,
-                            "heard whois response");
-    } else if (mState == ICommonClock::STATE_CLIENT) {
-        // if we get multiple responses because there are multiple devices
-        // who believe that they are master, then follow the master that
-        // wins arbitration
-        if (arbitrateMaster(response->deviceID,
-                            response->devicePriority,
-                            mClient_MasterDeviceID,
-                            mClient_MasterDevicePriority)) {
-            return becomeClient(srcAddr,
-                                response->deviceID,
-                                response->devicePriority,
-                                response->timelineID,
-                                "heard whois response");
-        }
-    }
-
-    return true;
-}
-
-bool CommonTimeServer::handleSyncRequest(const SyncRequestPacket* request,
-                                         const sockaddr_storage& srcAddr) {
-    SyncResponsePacket pkt;
-    pkt.initHeader(mTimelineID, mSyncGroupID);
-
-    if ((mState == ICommonClock::STATE_MASTER) &&
-        (mTimelineID == request->timelineID)) {
-        int64_t rxLocalTime = mLastPacketRxLocalTime;
-        int64_t rxCommonTime;
-
-        // If we are master on an actual network and have actual clients, then
-        // we are no longer low priority.
-        setForceLowPriority(false);
-
-        if (OK != mCommonClock.localToCommon(rxLocalTime, &rxCommonTime)) {
-            return false;
-        }
-
-        int64_t txLocalTime = mLocalClock.getLocalTime();;
-        int64_t txCommonTime;
-        if (OK != mCommonClock.localToCommon(txLocalTime, &txCommonTime)) {
-            return false;
-        }
-
-        pkt.nak = 0;
-        pkt.clientTxLocalTime  = request->clientTxLocalTime;
-        pkt.masterRxCommonTime = rxCommonTime;
-        pkt.masterTxCommonTime = txCommonTime;
-    } else {
-        pkt.nak = 1;
-        pkt.clientTxLocalTime  = 0;
-        pkt.masterRxCommonTime = 0;
-        pkt.masterTxCommonTime = 0;
-    }
-
-    uint8_t buf[256];
-    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
-    if (bufSz < 0)
-        return false;
-
-    ssize_t sendBytes = sendto(
-            mSocket, &buf, bufSz, 0,
-            reinterpret_cast<const sockaddr *>(&srcAddr),
-            sizeof(srcAddr));
-    if (sendBytes == -1) {
-        ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__);
-        return false;
-    }
-
-    return true;
-}
-
-bool CommonTimeServer::handleSyncResponse(
-        const SyncResponsePacket* response,
-        const sockaddr_storage& srcAddr) {
-    if (mState != ICommonClock::STATE_CLIENT)
-        return true;
-
-    assert(mMasterEPValid);
-    if (!sockaddrMatch(srcAddr, mMasterEP, true)) {
-        char srcEP[64], expectedEP[64];
-        sockaddrToString(srcAddr, true, srcEP, sizeof(srcEP));
-        sockaddrToString(mMasterEP, true, expectedEP, sizeof(expectedEP));
-        ALOGI("Dropping sync response from unexpected address."
-             " Expected %s Got %s", expectedEP, srcEP);
-        return true;
-    }
-
-    if (response->nak) {
-        // if our master is no longer accepting requests, then we need to find
-        // a new master
-        return becomeRonin("master NAK'ed");
-    }
-
-    mClient_SyncRequestPending = 0;
-    mClient_SyncRequestTimeouts = 0;
-    mClient_PacketRTTLog.logRX(response->clientTxLocalTime,
-                               mLastPacketRxLocalTime);
-
-    bool result;
-    if (!(mClient_SyncRespsRXedFromCurMaster++)) {
-        // the first request/response exchange between a client and a master
-        // may take unusually long due to ARP, so discard it.
-        result = true;
-    } else {
-        int64_t clientTxLocalTime  = response->clientTxLocalTime;
-        int64_t clientRxLocalTime  = mLastPacketRxLocalTime;
-        int64_t masterTxCommonTime = response->masterTxCommonTime;
-        int64_t masterRxCommonTime = response->masterRxCommonTime;
-
-        int64_t rtt       = (clientRxLocalTime - clientTxLocalTime);
-        int64_t avgLocal  = (clientTxLocalTime + clientRxLocalTime) >> 1;
-        int64_t avgCommon = (masterTxCommonTime + masterRxCommonTime) >> 1;
-
-        // if the RTT of the packet is significantly larger than the panic
-        // threshold, we should simply discard it.  Its better to do nothing
-        // than to take cues from a packet like that.
-        int64_t rttCommon = mCommonClock.localDurationToCommonDuration(rtt);
-        if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) * 
-                         kRTTDiscardPanicThreshMultiplier)) {
-            ALOGV("Dropping sync response with RTT of %" PRId64 " uSec", rttCommon);
-            mClient_ExpiredSyncRespsRXedFromCurMaster++;
-            if (shouldPanicNotGettingGoodData())
-                return becomeInitial("RX panic, no good data");
-            return true;
-        } else {
-            result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon);
-            mClient_LastGoodSyncRX = clientRxLocalTime;
-
-            if (result) {
-                // indicate to listeners that we've synced to the common timeline
-                notifyClockSync();
-            } else {
-                ALOGE("Panic!  Observed clock sync error is too high to tolerate,"
-                        " resetting state machine and starting over.");
-                notifyClockSyncLoss();
-                return becomeInitial("panic");
-            }
-        }
-    }
-
-    mCurTimeout.setTimeout(mSyncRequestIntervalMs);
-    return result;
-}
-
-bool CommonTimeServer::handleMasterAnnouncement(
-        const MasterAnnouncementPacket* packet,
-        const sockaddr_storage& srcAddr) {
-    uint64_t newDeviceID   = packet->deviceID;
-    uint8_t  newDevicePrio = packet->devicePriority;
-    uint64_t newTimelineID = packet->timelineID;
-
-    // Skip our own messages which come back via broadcast loopback.
-    if (newDeviceID == mDeviceID)
-        return true;
-
-    char srcEPStr[64];
-    sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
-    mElectionLog.log("RXed master announcement while in state %s.  "
-                     "src %s srcDevID %lld srcPrio %u srcTID %016llx",
-                     stateToString(mState), srcEPStr,
-                     newDeviceID, static_cast<uint32_t>(newDevicePrio),
-                     newTimelineID);
-
-    if (mState == ICommonClock::STATE_INITIAL ||
-        mState == ICommonClock::STATE_RONIN ||
-        mState == ICommonClock::STATE_WAIT_FOR_ELECTION) {
-        // if we aren't currently following a master, then start following
-        // this new master
-        return becomeClient(srcAddr,
-                            newDeviceID,
-                            newDevicePrio,
-                            newTimelineID,
-                            "heard master announcement");
-    } else if (mState == ICommonClock::STATE_CLIENT) {
-        // if the new master wins arbitration against our current master,
-        // then become a client of the new master
-        if (arbitrateMaster(newDeviceID,
-                            newDevicePrio,
-                            mClient_MasterDeviceID,
-                            mClient_MasterDevicePriority))
-            return becomeClient(srcAddr,
-                                newDeviceID,
-                                newDevicePrio,
-                                newTimelineID,
-                                "heard master announcement");
-    } else if (mState == ICommonClock::STATE_MASTER) {
-        // two masters are competing - if the new one wins arbitration, then
-        // cease acting as master
-        if (arbitrateMaster(newDeviceID, newDevicePrio,
-                            mDeviceID, effectivePriority()))
-            return becomeClient(srcAddr, newDeviceID,
-                                newDevicePrio, newTimelineID,
-                                "heard master announcement");
-    }
-
-    return true;
-}
-
-bool CommonTimeServer::sendWhoIsMasterRequest() {
-    assert(mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN);
-
-    // If we have no socket, then we must be in the unconfigured initial state.
-    // Don't report any errors, just don't try to send the initial who-is-master
-    // query.  Eventually, our network will either become configured, or we will
-    // be forced into network-less master mode by higher level code.
-    if (mSocket < 0) {
-        assert(mState == ICommonClock::STATE_INITIAL);
-        return true;
-    }
-
-    bool ret = false;
-    WhoIsMasterRequestPacket pkt;
-    pkt.initHeader(mSyncGroupID);
-    pkt.senderDeviceID = mDeviceID;
-    pkt.senderDevicePriority = effectivePriority();
-
-    uint8_t buf[256];
-    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
-    if (bufSz >= 0) {
-        char dstEPStr[64];
-        sockaddrToString(mMasterElectionEP, true, dstEPStr, sizeof(dstEPStr));
-        mElectionLog.log("TXing WhoIs master request to %s while in state %s.  "
-                         "ourTID %016llx ourGID %016llx ourDID %016llx "
-                         "ourPrio %u",
-                         dstEPStr, stateToString(mState),
-                         mTimelineID, mSyncGroupID,
-                         pkt.senderDeviceID, pkt.senderDevicePriority);
-
-        ssize_t sendBytes = sendto(
-                mSocket, buf, bufSz, 0,
-                reinterpret_cast<const sockaddr *>(&mMasterElectionEP),
-                sizeof(mMasterElectionEP));
-        if (sendBytes < 0)
-            ALOGE("WhoIsMaster sendto failed (errno %d)", errno);
-        ret = true;
-    }
-
-    if (mState == ICommonClock::STATE_INITIAL) {
-        mCurTimeout.setTimeout(kInitial_WhoIsMasterTimeoutMs);
-    } else {
-        mCurTimeout.setTimeout(kRonin_WhoIsMasterTimeoutMs);
-    }
-
-    return ret;
-}
-
-bool CommonTimeServer::sendSyncRequest() {
-    // If we are sending sync requests, then we must be in the client state and
-    // we must have a socket (when we have no network, we are only supposed to
-    // be in INITIAL or MASTER)
-    assert(mState == ICommonClock::STATE_CLIENT);
-    assert(mSocket >= 0);
-
-    bool ret = false;
-    SyncRequestPacket pkt;
-    pkt.initHeader(mTimelineID, mSyncGroupID);
-    pkt.clientTxLocalTime = mLocalClock.getLocalTime();
-
-    if (!mClient_FirstSyncTX)
-        mClient_FirstSyncTX = pkt.clientTxLocalTime;
-
-    mClient_PacketRTTLog.logTX(pkt.clientTxLocalTime);
-
-    uint8_t buf[256];
-    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
-    if (bufSz >= 0) {
-        ssize_t sendBytes = sendto(
-                mSocket, buf, bufSz, 0,
-                reinterpret_cast<const sockaddr *>(&mMasterEP),
-                sizeof(mMasterEP));
-        if (sendBytes < 0)
-            ALOGE("SyncRequest sendto failed (errno %d)", errno);
-        ret = true;
-    }
-
-    mClient_SyncsSentToCurMaster++;
-    mCurTimeout.setTimeout(mSyncRequestIntervalMs);
-    mClient_SyncRequestPending = true;
-
-    return ret;
-}
-
-bool CommonTimeServer::sendMasterAnnouncement() {
-    bool ret = false;
-    assert(mState == ICommonClock::STATE_MASTER);
-
-    // If we are being asked to send a master announcement, but we have no
-    // socket, we must be in network-less master mode.  Don't bother to send the
-    // announcement, and don't bother to schedule a timeout.  When the network
-    // comes up, the work thread will get poked and start the process of
-    // figuring out who the current master should be.
-    if (mSocket < 0) {
-        mCurTimeout.setTimeout(kInfiniteTimeout);
-        return true;
-    }
-
-    MasterAnnouncementPacket pkt;
-    pkt.initHeader(mTimelineID, mSyncGroupID);
-    pkt.deviceID = mDeviceID;
-    pkt.devicePriority = effectivePriority();
-
-    uint8_t buf[256];
-    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
-    if (bufSz >= 0) {
-        char dstEPStr[64];
-        sockaddrToString(mMasterElectionEP, true, dstEPStr, sizeof(dstEPStr));
-        mElectionLog.log("TXing Master announcement to %s while in state %s.  "
-                         "ourTID %016llx ourGID %016llx ourDID %016llx "
-                         "ourPrio %u",
-                         dstEPStr, stateToString(mState),
-                         mTimelineID, mSyncGroupID,
-                         pkt.deviceID, pkt.devicePriority);
-
-        ssize_t sendBytes = sendto(
-                mSocket, buf, bufSz, 0,
-                reinterpret_cast<const sockaddr *>(&mMasterElectionEP),
-                sizeof(mMasterElectionEP));
-        if (sendBytes < 0)
-            ALOGE("MasterAnnouncement sendto failed (errno %d)", errno);
-        ret = true;
-    }
-
-    mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
-    return ret;
-}
-
-bool CommonTimeServer::becomeClient(const sockaddr_storage& masterEP,
-                                    uint64_t masterDeviceID,
-                                    uint8_t  masterDevicePriority,
-                                    uint64_t timelineID,
-                                    const char* cause) {
-    char newEPStr[64], oldEPStr[64];
-    sockaddrToString(masterEP, true, newEPStr, sizeof(newEPStr));
-    sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr));
-
-    mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-            "%s --> CLIENT (%s) :%s"
-            " OldMaster: %02x-%014llx::%016llx::%s"
-            " NewMaster: %02x-%014llx::%016llx::%s",
-            stateToString(mState), cause,
-            (mTimelineID != timelineID) ? " (new timeline)" : "",
-            mClient_MasterDevicePriority, mClient_MasterDeviceID,
-            mTimelineID, oldEPStr,
-            masterDevicePriority, masterDeviceID,
-            timelineID, newEPStr);
-
-    if (mTimelineID != timelineID) {
-        // start following a new timeline
-        mTimelineID = timelineID;
-        mClockRecovery.reset(true, true);
-        notifyClockSyncLoss();
-    } else {
-        // start following a new master on the existing timeline
-        mClockRecovery.reset(false, true);
-    }
-
-    mMasterEP = masterEP;
-    mMasterEPValid = true;
-
-    // If we are on a real network as a client of a real master, then we should
-    // no longer force low priority.  If our master disappears, we should have
-    // the high priority bit set during the election to replace the master
-    // because this group was a real group and not a singleton created in
-    // networkless mode.
-    setForceLowPriority(false);
-
-    mClient_MasterDeviceID = masterDeviceID;
-    mClient_MasterDevicePriority = masterDevicePriority;
-    resetSyncStats();
-
-    setState(ICommonClock::STATE_CLIENT);
-
-    // add some jitter to when the various clients send their requests
-    // in order to reduce the likelihood that a group of clients overload
-    // the master after receiving a master announcement
-    usleep((lrand48() % 100) * 1000);
-
-    return sendSyncRequest();
-}
-
-bool CommonTimeServer::becomeMaster(const char* cause) {
-    uint64_t oldTimelineID = mTimelineID;
-    if (mTimelineID == ICommonClock::kInvalidTimelineID) {
-        // this device has not been following any existing timeline,
-        // so it will create a new timeline and declare itself master
-        assert(!mCommonClock.isValid());
-
-        // set the common time basis
-        mCommonClock.setBasis(mLocalClock.getLocalTime(), 0);
-
-        // assign an arbitrary timeline iD
-        assignTimelineID();
-
-        // notify listeners that we've created a common timeline
-        notifyClockSync();
-    }
-
-    mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-            "%s --> MASTER (%s) : %s timeline %016llx",
-            stateToString(mState), cause,
-            (oldTimelineID == mTimelineID) ? "taking ownership of"
-                                           : "creating new",
-            mTimelineID);
-
-    memset(&mMasterEP, 0, sizeof(mMasterEP));
-    mMasterEPValid = false;
-    mClient_MasterDevicePriority = effectivePriority();
-    mClient_MasterDeviceID = mDeviceID;
-    mClockRecovery.reset(false, true);
-    resetSyncStats();
-
-    setState(ICommonClock::STATE_MASTER);
-    return sendMasterAnnouncement();
-}
-
-bool CommonTimeServer::becomeRonin(const char* cause) {
-    // If we were the client of a given timeline, but had never received even a
-    // single time sync packet, then we transition back to Initial instead of
-    // Ronin.  If we transition to Ronin and end up becoming the new Master, we
-    // will be unable to service requests for other clients because we never
-    // actually knew what time it was.  By going to initial, we ensure that
-    // other clients who know what time it is, but would lose master arbitration
-    // in the Ronin case, will step up and become the proper new master of the
-    // old timeline.
-
-    char oldEPStr[64];
-    sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr));
-    memset(&mMasterEP, 0, sizeof(mMasterEP));
-    mMasterEPValid = false;
-
-    if (mCommonClock.isValid()) {
-        mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-             "%s --> RONIN (%s) : lost track of previously valid timeline "
-             "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)",
-             stateToString(mState), cause,
-             mClient_MasterDevicePriority, mClient_MasterDeviceID,
-             mTimelineID, oldEPStr,
-             mClient_SyncsSentToCurMaster,
-             mClient_SyncRespsRXedFromCurMaster,
-             mClient_ExpiredSyncRespsRXedFromCurMaster);
-
-        mRonin_WhoIsMasterRequestTimeouts = 0;
-        setState(ICommonClock::STATE_RONIN);
-        return sendWhoIsMasterRequest();
-    } else {
-        mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-             "%s --> INITIAL (%s) : never synced timeline "
-             "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)",
-             stateToString(mState), cause,
-             mClient_MasterDevicePriority, mClient_MasterDeviceID,
-             mTimelineID, oldEPStr,
-             mClient_SyncsSentToCurMaster,
-             mClient_SyncRespsRXedFromCurMaster,
-             mClient_ExpiredSyncRespsRXedFromCurMaster);
-
-        return becomeInitial("ronin, no timeline");
-    }
-}
-
-bool CommonTimeServer::becomeWaitForElection(const char* cause) {
-    mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-         "%s --> WAIT_FOR_ELECTION (%s) : dropping out of election,"
-         " waiting %d mSec for completion.",
-         stateToString(mState), cause, kWaitForElection_TimeoutMs);
-
-    setState(ICommonClock::STATE_WAIT_FOR_ELECTION);
-    mCurTimeout.setTimeout(kWaitForElection_TimeoutMs);
-    return true;
-}
-
-bool CommonTimeServer::becomeInitial(const char* cause) {
-    mStateChangeLog.log(ANDROID_LOG_INFO, LOG_TAG,
-                        "Entering INITIAL (%s), total reset.",
-                        cause);
-
-    setState(ICommonClock::STATE_INITIAL);
-
-    // reset clock recovery
-    mClockRecovery.reset(true, true);
-
-    // reset internal state bookkeeping.
-    mCurTimeout.setTimeout(kInfiniteTimeout);
-    memset(&mMasterEP, 0, sizeof(mMasterEP));
-    mMasterEPValid = false;
-    mLastPacketRxLocalTime = 0;
-    mTimelineID = ICommonClock::kInvalidTimelineID;
-    mClockSynced = false;
-    mInitial_WhoIsMasterRequestTimeouts = 0;
-    mClient_MasterDeviceID = 0;
-    mClient_MasterDevicePriority = 0;
-    mRonin_WhoIsMasterRequestTimeouts = 0;
-    resetSyncStats();
-
-    // send the first request to discover the master
-    return sendWhoIsMasterRequest();
-}
-
-void CommonTimeServer::notifyClockSync() {
-    if (!mClockSynced) {
-        mClockSynced = true;
-        mICommonClock->notifyOnTimelineChanged(mTimelineID);
-    }
-}
-
-void CommonTimeServer::notifyClockSyncLoss() {
-    if (mClockSynced) {
-        mClockSynced = false;
-        mICommonClock->notifyOnTimelineChanged(
-                ICommonClock::kInvalidTimelineID);
-    }
-}
-
-void CommonTimeServer::setState(ICommonClock::State s) {
-    mState = s;
-}
-
-const char* CommonTimeServer::stateToString(ICommonClock::State s) {
-    switch(s) {
-        case ICommonClock::STATE_INITIAL:
-            return "INITIAL";
-        case ICommonClock::STATE_CLIENT:
-            return "CLIENT";
-        case ICommonClock::STATE_MASTER:
-            return "MASTER";
-        case ICommonClock::STATE_RONIN:
-            return "RONIN";
-        case ICommonClock::STATE_WAIT_FOR_ELECTION:
-            return "WAIT_FOR_ELECTION";
-        default:
-            return "unknown";
-    }
-}
-
-void CommonTimeServer::sockaddrToString(const sockaddr_storage& addr,
-                                        bool addrValid,
-                                        char* buf, size_t bufLen) {
-    if (!bufLen || !buf)
-        return;
-
-    if (addrValid) {
-        switch (addr.ss_family) {
-            case AF_INET: {
-                const struct sockaddr_in* sa =
-                    reinterpret_cast<const struct sockaddr_in*>(&addr);
-                unsigned long a = ntohl(sa->sin_addr.s_addr);
-                uint16_t      p = ntohs(sa->sin_port);
-                snprintf(buf, bufLen, "%lu.%lu.%lu.%lu:%hu",
-                        ((a >> 24) & 0xFF), ((a >> 16) & 0xFF),
-                        ((a >>  8) & 0xFF),  (a        & 0xFF), p);
-            } break;
-
-            case AF_INET6: {
-                const struct sockaddr_in6* sa =
-                    reinterpret_cast<const struct sockaddr_in6*>(&addr);
-                const uint8_t* a = sa->sin6_addr.s6_addr;
-                uint16_t       p = ntohs(sa->sin6_port);
-                snprintf(buf, bufLen,
-                        "%02X%02X:%02X%02X:%02X%02X:%02X%02X:"
-                        "%02X%02X:%02X%02X:%02X%02X:%02X%02X port %hd",
-                        a[0], a[1], a[ 2], a[ 3], a[ 4], a[ 5], a[ 6], a[ 7],
-                        a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15],
-                        p);
-            } break;
-
-            default:
-                snprintf(buf, bufLen,
-                         "<unknown sockaddr family %d>", addr.ss_family);
-                break;
-        }
-    } else {
-        snprintf(buf, bufLen, "<none>");
-    }
-
-    buf[bufLen - 1] = 0;
-}
-
-bool CommonTimeServer::sockaddrMatch(const sockaddr_storage& a1,
-                                     const sockaddr_storage& a2,
-                                     bool matchAddressOnly) {
-    if (a1.ss_family != a2.ss_family)
-        return false;
-
-    switch (a1.ss_family) {
-        case AF_INET: {
-            const struct sockaddr_in* sa1 =
-                reinterpret_cast<const struct sockaddr_in*>(&a1);
-            const struct sockaddr_in* sa2 =
-                reinterpret_cast<const struct sockaddr_in*>(&a2);
-
-            if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr)
-                return false;
-
-            return (matchAddressOnly || (sa1->sin_port == sa2->sin_port));
-        } break;
-
-        case AF_INET6: {
-            const struct sockaddr_in6* sa1 =
-                reinterpret_cast<const struct sockaddr_in6*>(&a1);
-            const struct sockaddr_in6* sa2 =
-                reinterpret_cast<const struct sockaddr_in6*>(&a2);
-
-            if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa2->sin6_addr)))
-                return false;
-
-            return (matchAddressOnly || (sa1->sin6_port == sa2->sin6_port));
-        } break;
-
-        // Huh?  We don't deal in non-IPv[46] addresses.  Not sure how we got
-        // here, but we don't know how to comapre these addresses and simply
-        // default to a no-match decision.
-        default: return false;
-    }
-}
-
-bool CommonTimeServer::shouldPanicNotGettingGoodData() {
-    if (mClient_FirstSyncTX) {
-        int64_t now = mLocalClock.getLocalTime();
-        int64_t delta = now - (mClient_LastGoodSyncRX
-                             ? mClient_LastGoodSyncRX
-                             : mClient_FirstSyncTX);
-        int64_t deltaUsec = mCommonClock.localDurationToCommonDuration(delta);
-
-        if (deltaUsec >= kNoGoodDataPanicThresholdUsec)
-            return true;
-    }
-
-    return false;
-}
-
-void CommonTimeServer::PacketRTTLog::logTX(int64_t txTime) {
-    txTimes[wrPtr] = txTime;
-    rxTimes[wrPtr] = 0;
-    wrPtr = (wrPtr + 1) % RTT_LOG_SIZE;
-    if (!wrPtr)
-        logFull = true;
-}
-
-void CommonTimeServer::PacketRTTLog::logRX(int64_t txTime, int64_t rxTime) {
-    if (!logFull && !wrPtr)
-        return;
-
-    uint32_t i = logFull ? wrPtr : 0;
-    do {
-        if (txTimes[i] == txTime) {
-            rxTimes[i] = rxTime;
-            break;
-        }
-        i = (i + 1) % RTT_LOG_SIZE;
-    } while (i != wrPtr);
-}
-
-}  // namespace android
diff --git a/libs/common_time/common_time_server.h b/libs/common_time/common_time_server.h
deleted file mode 100644
index 6e18050..0000000
--- a/libs/common_time/common_time_server.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_COMMON_TIME_SERVER_H
-#define ANDROID_COMMON_TIME_SERVER_H
-
-#include <arpa/inet.h>
-#include <stdint.h>
-#include <sys/socket.h>
-
-#include <common_time/ICommonClock.h>
-#include <common_time/local_clock.h>
-#include <utils/String8.h>
-
-#include "clock_recovery.h"
-#include "common_clock.h"
-#include "common_time_server_packets.h"
-#include "utils.h"
-
-#define RTT_LOG_SIZE 30
-
-namespace android {
-
-class CommonClockService;
-class CommonTimeConfigService;
-
-/***** time service implementation *****/
-
-class CommonTimeServer : public Thread {
-  public:
-    CommonTimeServer();
-    ~CommonTimeServer();
-
-    bool startServices();
-
-    // Common Clock API methods
-    CommonClock&        getCommonClock()        { return mCommonClock; }
-    LocalClock&         getLocalClock()         { return mLocalClock; }
-    uint64_t            getTimelineID();
-    int32_t             getEstimatedError();
-    ICommonClock::State getState();
-    status_t            getMasterAddr(struct sockaddr_storage* addr);
-    status_t            isCommonTimeValid(bool* valid, uint32_t* timelineID);
-
-    // Config API methods
-    status_t getMasterElectionPriority(uint8_t *priority);
-    status_t setMasterElectionPriority(uint8_t priority);
-    status_t getMasterElectionEndpoint(struct sockaddr_storage *addr);
-    status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr);
-    status_t getMasterElectionGroupId(uint64_t *id);
-    status_t setMasterElectionGroupId(uint64_t id);
-    status_t getInterfaceBinding(String8& ifaceName);
-    status_t setInterfaceBinding(const String8& ifaceName);
-    status_t getMasterAnnounceInterval(int *interval);
-    status_t setMasterAnnounceInterval(int interval);
-    status_t getClientSyncInterval(int *interval);
-    status_t setClientSyncInterval(int interval);
-    status_t getPanicThreshold(int *threshold);
-    status_t setPanicThreshold(int threshold);
-    status_t getAutoDisable(bool *autoDisable);
-    status_t setAutoDisable(bool autoDisable);
-    status_t forceNetworklessMasterMode();
-
-    // Method used by the CommonClockService to notify the core service about
-    // changes in the number of active common clock clients.
-    void reevaluateAutoDisableState(bool commonClockHasClients);
-
-    status_t dumpClockInterface(int fd, const Vector<String16>& args,
-                                size_t activeClients);
-    status_t dumpConfigInterface(int fd, const Vector<String16>& args);
-
-  private:
-    class PacketRTTLog {
-      public:
-        PacketRTTLog() {
-            resetLog();
-        }
-
-        void resetLog() {
-            wrPtr = 0;
-            logFull = 0;
-        }
-
-        void logTX(int64_t txTime);
-        void logRX(int64_t txTime, int64_t rxTime);
-        void dumpLog(int fd, const CommonClock& cclk);
-
-      private:
-        uint32_t wrPtr;
-        bool logFull;
-        int64_t txTimes[RTT_LOG_SIZE];
-        int64_t rxTimes[RTT_LOG_SIZE];
-    };
-
-    bool threadLoop();
-
-    bool runStateMachine_l();
-    bool setupSocket_l();
-
-    void assignTimelineID();
-    bool assignDeviceID();
-
-    static bool arbitrateMaster(uint64_t deviceID1, uint8_t devicePrio1,
-                                uint64_t deviceID2, uint8_t devicePrio2);
-
-    bool handlePacket();
-    bool handleWhoIsMasterRequest (const WhoIsMasterRequestPacket* request,
-                                   const sockaddr_storage& srcAddr);
-    bool handleWhoIsMasterResponse(const WhoIsMasterResponsePacket* response,
-                                   const sockaddr_storage& srcAddr);
-    bool handleSyncRequest        (const SyncRequestPacket* request,
-                                   const sockaddr_storage& srcAddr);
-    bool handleSyncResponse       (const SyncResponsePacket* response,
-                                   const sockaddr_storage& srcAddr);
-    bool handleMasterAnnouncement (const MasterAnnouncementPacket* packet,
-                                   const sockaddr_storage& srcAddr);
-
-    bool handleTimeout();
-    bool handleTimeoutInitial();
-    bool handleTimeoutClient();
-    bool handleTimeoutMaster();
-    bool handleTimeoutRonin();
-    bool handleTimeoutWaitForElection();
-
-    bool sendWhoIsMasterRequest();
-    bool sendSyncRequest();
-    bool sendMasterAnnouncement();
-
-    bool becomeClient(const sockaddr_storage& masterAddr,
-                      uint64_t masterDeviceID,
-                      uint8_t  masterDevicePriority,
-                      uint64_t timelineID,
-                      const char* cause);
-    bool becomeMaster(const char* cause);
-    bool becomeRonin(const char* cause);
-    bool becomeWaitForElection(const char* cause);
-    bool becomeInitial(const char* cause);
-
-    void notifyClockSync();
-    void notifyClockSyncLoss();
-
-    ICommonClock::State mState;
-    void setState(ICommonClock::State s);
-
-    void clearPendingWakeupEvents_l();
-    void wakeupThread_l();
-    void cleanupSocket_l();
-    void shutdownThread();
-
-    inline uint8_t effectivePriority() const {
-        return (mMasterPriority & 0x7F) |
-               (mForceLowPriority ? 0x00 : 0x80);
-    }
-
-    inline bool shouldAutoDisable() const {
-        return (mAutoDisable && !mCommonClockHasClients);
-    }
-
-    inline void resetSyncStats() {
-        mClient_SyncRequestPending = false;
-        mClient_SyncRequestTimeouts = 0;
-        mClient_SyncsSentToCurMaster = 0;
-        mClient_SyncRespsRXedFromCurMaster = 0;
-        mClient_ExpiredSyncRespsRXedFromCurMaster = 0;
-        mClient_FirstSyncTX = 0;
-        mClient_LastGoodSyncRX = 0;
-        mClient_PacketRTTLog.resetLog();
-    }
-
-    bool shouldPanicNotGettingGoodData();
-
-    // Helper to keep track of the state machine's current timeout
-    Timeout mCurTimeout;
-
-    // common clock, local clock abstraction, and clock recovery loop
-    CommonClock mCommonClock;
-    LocalClock mLocalClock;
-    ClockRecoveryLoop mClockRecovery;
-
-    // implementation of ICommonClock
-    sp<CommonClockService> mICommonClock;
-
-    // implementation of ICommonTimeConfig
-    sp<CommonTimeConfigService> mICommonTimeConfig;
-
-    // UDP socket for the time sync protocol
-    int mSocket;
-
-    // eventfd used to wakeup the work thread in response to configuration
-    // changes.
-    int mWakeupThreadFD;
-
-    // timestamp captured when a packet is received
-    int64_t mLastPacketRxLocalTime;
-
-    // ID of the timeline that this device is following
-    uint64_t mTimelineID;
-
-    // flag for whether the clock has been synced to a timeline
-    bool mClockSynced;
-
-    // flag used to indicate that clients should be considered to be lower
-    // priority than all of their peers during elections.  This flag is set and
-    // cleared by the state machine.  It is set when the client joins a new
-    // network.  If the client had been a master in the old network (or an
-    // isolated master with no network connectivity) it should defer to any
-    // masters which may already be on the network.  It will be cleared whenever
-    // the state machine transitions to the master state.
-    bool mForceLowPriority;
-    inline void setForceLowPriority(bool val) {
-        mForceLowPriority = val;
-        if (mState == ICommonClock::STATE_MASTER)
-            mClient_MasterDevicePriority = effectivePriority();
-    }
-
-    // Lock to synchronize access to internal state and configuration.
-    Mutex mLock;
-
-    // Flag updated by the common clock service to indicate that it does or does
-    // not currently have registered clients.  When the the auto disable flag is
-    // cleared on the common time service, the service will participate in
-    // network synchronization whenever it has a valid network interface to bind
-    // to.  When the auto disable flag is set on the common time service, it
-    // will only participate in network synchronization when it has both a valid
-    // interface AND currently active common clock clients.
-    bool mCommonClockHasClients;
-
-    // Internal logs used for dumpsys.
-    LogRing                 mStateChangeLog;
-    LogRing                 mElectionLog;
-    LogRing                 mBadPktLog;
-
-    // Configuration info
-    struct sockaddr_storage mMasterElectionEP;          // Endpoint over which we conduct master election
-    String8                 mBindIface;                 // Endpoint for the service to bind to.
-    bool                    mBindIfaceValid;            // whether or not the bind Iface is valid.
-    bool                    mBindIfaceDirty;            // whether or not the bind Iface is valid.
-    struct sockaddr_storage mMasterEP;                  // Endpoint of our current master (if any)
-    bool                    mMasterEPValid;
-    uint64_t                mDeviceID;                  // unique ID of this device
-    uint64_t                mSyncGroupID;               // synchronization group ID of this device.
-    uint8_t                 mMasterPriority;            // Priority of this device in master election.
-    uint32_t                mMasterAnnounceIntervalMs;
-    uint32_t                mSyncRequestIntervalMs;
-    uint32_t                mPanicThresholdUsec;
-    bool                    mAutoDisable;
-
-    // Config defaults.
-    static const char*      kDefaultMasterElectionAddr;
-    static const uint16_t   kDefaultMasterElectionPort;
-    static const uint64_t   kDefaultSyncGroupID;
-    static const uint8_t    kDefaultMasterPriority;
-    static const uint32_t   kDefaultMasterAnnounceIntervalMs;
-    static const uint32_t   kDefaultSyncRequestIntervalMs;
-    static const uint32_t   kDefaultPanicThresholdUsec;
-    static const bool       kDefaultAutoDisable;
-
-    // Priority mask and shift fields.
-    static const uint64_t kDeviceIDMask;
-    static const uint8_t  kDevicePriorityMask;
-    static const uint8_t  kDevicePriorityHiLowBit;
-    static const uint32_t kDevicePriorityShift;
-
-    // Unconfgurable constants
-    static const int      kSetupRetryTimeoutMs;
-    static const int64_t  kNoGoodDataPanicThresholdUsec;
-    static const uint32_t kRTTDiscardPanicThreshMultiplier;
-
-    /*** status while in the Initial state ***/
-    int mInitial_WhoIsMasterRequestTimeouts;
-    static const int kInitial_NumWhoIsMasterRetries;
-    static const int kInitial_WhoIsMasterTimeoutMs;
-
-    /*** status while in the Client state ***/
-    uint64_t mClient_MasterDeviceID;
-    uint8_t mClient_MasterDevicePriority;
-    bool mClient_SyncRequestPending;
-    int mClient_SyncRequestTimeouts;
-    uint32_t mClient_SyncsSentToCurMaster;
-    uint32_t mClient_SyncRespsRXedFromCurMaster;
-    uint32_t mClient_ExpiredSyncRespsRXedFromCurMaster;
-    int64_t mClient_FirstSyncTX;
-    int64_t mClient_LastGoodSyncRX;
-    PacketRTTLog mClient_PacketRTTLog;
-    static const int kClient_NumSyncRequestRetries;
-
-
-    /*** status while in the Master state ***/
-    static const uint32_t kDefaultMaster_AnnouncementIntervalMs;
-
-    /*** status while in the Ronin state ***/
-    int mRonin_WhoIsMasterRequestTimeouts;
-    static const int kRonin_NumWhoIsMasterRetries;
-    static const int kRonin_WhoIsMasterTimeoutMs;
-
-    /*** status while in the WaitForElection state ***/
-    static const int kWaitForElection_TimeoutMs;
-
-    static const int kInfiniteTimeout;
-
-    static const char* stateToString(ICommonClock::State s);
-    static void sockaddrToString(const sockaddr_storage& addr, bool addrValid,
-                                 char* buf, size_t bufLen);
-    static bool sockaddrMatch(const sockaddr_storage& a1,
-                              const sockaddr_storage& a2,
-                              bool matchAddressOnly);
-};
-
-}  // namespace android
-
-#endif  // ANDROID_COMMON_TIME_SERVER_H
diff --git a/libs/common_time/common_time_server_api.cpp b/libs/common_time/common_time_server_api.cpp
deleted file mode 100644
index 60e6567..0000000
--- a/libs/common_time/common_time_server_api.cpp
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * A service that exchanges time synchronization information between
- * a master that defines a timeline and clients that follow the timeline.
- */
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-
-#include "common_time_server.h"
-
-#include <inttypes.h>
-
-namespace android {
-
-//
-// Clock API
-//
-uint64_t CommonTimeServer::getTimelineID() {
-    AutoMutex _lock(&mLock);
-    return mTimelineID;
-}
-
-ICommonClock::State CommonTimeServer::getState() {
-    AutoMutex _lock(&mLock);
-    return mState;
-}
-
-status_t CommonTimeServer::getMasterAddr(struct sockaddr_storage* addr) {
-    AutoMutex _lock(&mLock);
-    if (mMasterEPValid) {
-        memcpy(addr, &mMasterEP, sizeof(*addr));
-        return OK;
-    }
-
-    return UNKNOWN_ERROR;
-}
-
-int32_t CommonTimeServer::getEstimatedError() {
-    AutoMutex _lock(&mLock);
-
-    if (ICommonClock::STATE_MASTER == mState)
-        return 0;
-
-    if (!mClockSynced)
-        return ICommonClock::kErrorEstimateUnknown;
-
-    return mClockRecovery.getLastErrorEstimate();
-}
-
-status_t CommonTimeServer::isCommonTimeValid(bool* valid,
-                                             uint32_t* timelineID) {
-    AutoMutex _lock(&mLock);
-    *valid = mCommonClock.isValid();
-    *timelineID = mTimelineID;
-    return OK;
-}
-
-//
-// Config API
-//
-status_t CommonTimeServer::getMasterElectionPriority(uint8_t *priority) {
-    AutoMutex _lock(&mLock);
-    *priority = mMasterPriority;
-    return OK;
-}
-
-status_t CommonTimeServer::setMasterElectionPriority(uint8_t priority) {
-    AutoMutex _lock(&mLock);
-
-    if (priority > 0x7F)
-        return BAD_VALUE;
-
-    mMasterPriority = priority;
-    return OK;
-}
-
-status_t CommonTimeServer::getMasterElectionEndpoint(
-        struct sockaddr_storage *addr) {
-    AutoMutex _lock(&mLock);
-    memcpy(addr, &mMasterElectionEP, sizeof(*addr));
-    return OK;
-}
-
-status_t CommonTimeServer::setMasterElectionEndpoint(
-        const struct sockaddr_storage *addr) {
-    AutoMutex _lock(&mLock);
-
-    if (!addr)
-        return BAD_VALUE;
-
-    // TODO: add proper support for IPv6
-    if (addr->ss_family != AF_INET)
-        return BAD_VALUE;
-
-    // Only multicast and broadcast endpoints with explicit ports are allowed.
-    uint16_t ipv4Port = ntohs(
-        reinterpret_cast<const struct sockaddr_in*>(addr)->sin_port);
-    if (!ipv4Port)
-        return BAD_VALUE;
-
-    uint32_t ipv4Addr = ntohl(
-        reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr.s_addr);
-    if ((ipv4Addr != 0xFFFFFFFF) && (0xE0000000 != (ipv4Addr & 0xF0000000)))
-        return BAD_VALUE;
-
-    memcpy(&mMasterElectionEP, addr, sizeof(mMasterElectionEP));
-
-    // Force a rebind in order to change election enpoints.
-    mBindIfaceDirty = true;
-    wakeupThread_l();
-    return OK;
-}
-
-status_t CommonTimeServer::getMasterElectionGroupId(uint64_t *id) {
-    AutoMutex _lock(&mLock);
-    *id = mSyncGroupID;
-    return OK;
-}
-
-status_t CommonTimeServer::setMasterElectionGroupId(uint64_t id) {
-    AutoMutex _lock(&mLock);
-    mSyncGroupID = id;
-    return OK;
-}
-
-status_t CommonTimeServer::getInterfaceBinding(String8& ifaceName) {
-    AutoMutex _lock(&mLock);
-    if (!mBindIfaceValid)
-        return INVALID_OPERATION;
-    ifaceName = mBindIface;
-    return OK;
-}
-
-status_t CommonTimeServer::setInterfaceBinding(const String8& ifaceName) {
-    AutoMutex _lock(&mLock);
-
-    mBindIfaceDirty = true;
-    if (ifaceName.size()) {
-        mBindIfaceValid = true;
-        mBindIface = ifaceName;
-    } else {
-        mBindIfaceValid = false;
-        mBindIface.clear();
-    }
-
-    wakeupThread_l();
-    return OK;
-}
-
-status_t CommonTimeServer::getMasterAnnounceInterval(int *interval) {
-    AutoMutex _lock(&mLock);
-    *interval = mMasterAnnounceIntervalMs;
-    return OK;
-}
-
-status_t CommonTimeServer::setMasterAnnounceInterval(int interval) {
-    AutoMutex _lock(&mLock);
-
-    if (interval > (6 *3600000)) // Max interval is once every 6 hrs
-        return BAD_VALUE;
-
-    if (interval < 500) // Min interval is once per 0.5 seconds
-        return BAD_VALUE;
-
-    mMasterAnnounceIntervalMs = interval;
-    if (ICommonClock::STATE_MASTER == mState) {
-        int pendingTimeout = mCurTimeout.msecTillTimeout();
-        if ((kInfiniteTimeout == pendingTimeout) ||
-            (pendingTimeout > interval)) {
-            mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
-            wakeupThread_l();
-        }
-    }
-
-    return OK;
-}
-
-status_t CommonTimeServer::getClientSyncInterval(int *interval) {
-    AutoMutex _lock(&mLock);
-    *interval = mSyncRequestIntervalMs;
-    return OK;
-}
-
-status_t CommonTimeServer::setClientSyncInterval(int interval) {
-    AutoMutex _lock(&mLock);
-
-    if (interval > (3600000)) // Max interval is once every 60 min
-        return BAD_VALUE;
-
-    if (interval < 250) // Min interval is once per 0.25 seconds
-        return BAD_VALUE;
-
-    mSyncRequestIntervalMs = interval;
-    if (ICommonClock::STATE_CLIENT == mState) {
-        int pendingTimeout = mCurTimeout.msecTillTimeout();
-        if ((kInfiniteTimeout == pendingTimeout) ||
-            (pendingTimeout > interval)) {
-            mCurTimeout.setTimeout(mSyncRequestIntervalMs);
-            wakeupThread_l();
-        }
-    }
-
-    return OK;
-}
-
-status_t CommonTimeServer::getPanicThreshold(int *threshold) {
-    AutoMutex _lock(&mLock);
-    *threshold = mPanicThresholdUsec;
-    return OK;
-}
-
-status_t CommonTimeServer::setPanicThreshold(int threshold) {
-    AutoMutex _lock(&mLock);
-
-    if (threshold < 1000) // Min threshold is 1mSec
-        return BAD_VALUE;
-
-    mPanicThresholdUsec = threshold;
-    return OK;
-}
-
-status_t CommonTimeServer::getAutoDisable(bool *autoDisable) {
-    AutoMutex _lock(&mLock);
-    *autoDisable = mAutoDisable;
-    return OK;
-}
-
-status_t CommonTimeServer::setAutoDisable(bool autoDisable) {
-    AutoMutex _lock(&mLock);
-    mAutoDisable = autoDisable;
-    wakeupThread_l();
-    return OK;
-}
-
-status_t CommonTimeServer::forceNetworklessMasterMode() {
-    AutoMutex _lock(&mLock);
-
-    // Can't force networkless master mode if we are currently bound to a
-    // network.
-    if (mSocket >= 0)
-        return INVALID_OPERATION;
-
-    becomeMaster("force networkless");
-
-    return OK;
-}
-
-void CommonTimeServer::reevaluateAutoDisableState(bool commonClockHasClients) {
-    AutoMutex _lock(&mLock);
-    bool needWakeup = (mAutoDisable && mMasterEPValid &&
-                      (commonClockHasClients != mCommonClockHasClients));
-
-    mCommonClockHasClients = commonClockHasClients;
-
-    if (needWakeup) {
-        ALOGI("Waking up service, auto-disable is engaged and service now has%s"
-             " clients", mCommonClockHasClients ? "" : " no");
-        wakeupThread_l();
-    }
-}
-
-#define dump_printf(a, b...) do {                 \
-    int res;                                      \
-    res = snprintf(buffer, sizeof(buffer), a, b); \
-    buffer[sizeof(buffer) - 1] = 0;               \
-    if (res > 0)                                  \
-        write(fd, buffer, res);                   \
-} while (0)
-#define checked_percentage(a, b) ((0 == (b)) ? 0.0f : ((100.0f * (a)) / (b)))
-
-status_t CommonTimeServer::dumpClockInterface(int fd,
-                                              const Vector<String16>& /* args */,
-                                              size_t activeClients) {
-    AutoMutex _lock(&mLock);
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
-                 "can't dump CommonClockService from pid=%d, uid=%d\n",
-                 IPCThreadState::self()->getCallingPid(),
-                 IPCThreadState::self()->getCallingUid());
-        write(fd, buffer, strlen(buffer));
-    } else {
-        int64_t commonTime;
-        int64_t localTime;
-        bool    synced;
-        char maStr[64];
-
-        localTime  = mLocalClock.getLocalTime();
-        synced     = (OK == mCommonClock.localToCommon(localTime, &commonTime));
-        sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr));
-
-        dump_printf("Common Clock Service Status\nLocal time     : %" PRId64 "\n",
-                    localTime);
-
-        if (synced)
-            dump_printf("Common time    : %" PRId64 "\n", commonTime);
-        else
-            dump_printf("Common time    : %s\n", "not synced");
-
-        dump_printf("Timeline ID    : %016" PRIu64 "\n", mTimelineID);
-        dump_printf("State          : %s\n", stateToString(mState));
-        dump_printf("Master Addr    : %s\n", maStr);
-
-
-        if (synced) {
-            int32_t est = (ICommonClock::STATE_MASTER != mState)
-                        ? mClockRecovery.getLastErrorEstimate()
-                        : 0;
-            dump_printf("Error Est.     : %.3f msec\n",
-                        static_cast<float>(est) / 1000.0);
-        } else {
-            dump_printf("Error Est.     : %s\n", "unknown");
-        }
-
-        dump_printf("Syncs TXes     : %u\n", mClient_SyncsSentToCurMaster);
-        dump_printf("Syncs RXes     : %u (%.2f%%)\n",
-                    mClient_SyncRespsRXedFromCurMaster,
-                    checked_percentage(
-                        mClient_SyncRespsRXedFromCurMaster,
-                        mClient_SyncsSentToCurMaster));
-        dump_printf("RXs Expired    : %u (%.2f%%)\n",
-                    mClient_ExpiredSyncRespsRXedFromCurMaster,
-                    checked_percentage(
-                        mClient_ExpiredSyncRespsRXedFromCurMaster,
-                        mClient_SyncsSentToCurMaster));
-
-        if (!mClient_LastGoodSyncRX) {
-            dump_printf("Last Good RX   : %s\n", "unknown");
-        } else {
-            int64_t localDelta, usecDelta;
-            localDelta = localTime - mClient_LastGoodSyncRX;
-            usecDelta  = mCommonClock.localDurationToCommonDuration(localDelta);
-            dump_printf("Last Good RX   : %" PRId64 " uSec ago\n", usecDelta);
-        }
-
-        dump_printf("Active Clients : %zu\n", activeClients);
-        mClient_PacketRTTLog.dumpLog(fd, mCommonClock);
-        mStateChangeLog.dumpLog(fd);
-        mElectionLog.dumpLog(fd);
-        mBadPktLog.dumpLog(fd);
-    }
-
-    return NO_ERROR;
-}
-
-status_t CommonTimeServer::dumpConfigInterface(int fd,
-                                               const Vector<String16>& /* args */) {
-    AutoMutex _lock(&mLock);
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-
-    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
-                 "can't dump CommonTimeConfigService from pid=%d, uid=%d\n",
-                 IPCThreadState::self()->getCallingPid(),
-                 IPCThreadState::self()->getCallingUid());
-        write(fd, buffer, strlen(buffer));
-    } else {
-        char meStr[64];
-
-        sockaddrToString(mMasterElectionEP, true, meStr, sizeof(meStr));
-
-        dump_printf("Common Time Config Service Status\n"
-                    "Bound Interface           : %s\n",
-                    mBindIfaceValid ? mBindIface.string() : "<unbound>");
-        dump_printf("Master Election Endpoint  : %s\n", meStr);
-        dump_printf("Master Election Group ID  : %016" PRIu64 "\n", mSyncGroupID);
-        dump_printf("Master Announce Interval  : %d mSec\n",
-                    mMasterAnnounceIntervalMs);
-        dump_printf("Client Sync Interval      : %d mSec\n",
-                    mSyncRequestIntervalMs);
-        dump_printf("Panic Threshold           : %d uSec\n",
-                    mPanicThresholdUsec);
-        dump_printf("Base ME Prio              : 0x%02x\n",
-                    static_cast<uint32_t>(mMasterPriority));
-        dump_printf("Effective ME Prio         : 0x%02x\n",
-                    static_cast<uint32_t>(effectivePriority()));
-        dump_printf("Auto Disable Allowed      : %s\n",
-                    mAutoDisable ? "yes" : "no");
-        dump_printf("Auto Disable Engaged      : %s\n",
-                    shouldAutoDisable() ? "yes" : "no");
-    }
-
-    return NO_ERROR;
-}
-
-void CommonTimeServer::PacketRTTLog::dumpLog(int fd, const CommonClock& cclk) {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    uint32_t avail = !logFull ? wrPtr : RTT_LOG_SIZE;
-
-    if (!avail)
-        return;
-
-    dump_printf("\nPacket Log (%d entries)\n", avail);
-
-    uint32_t ndx = 0;
-    uint32_t i = logFull ? wrPtr : 0;
-    do {
-        if (rxTimes[i]) {
-            int64_t delta = rxTimes[i] - txTimes[i];
-            int64_t deltaUsec = cclk.localDurationToCommonDuration(delta);
-            dump_printf("pkt[%2d] : localTX %12" PRId64 " localRX %12" PRId64 " "
-                        "(%.3f msec RTT)\n",
-                        ndx, txTimes[i], rxTimes[i],
-                        static_cast<float>(deltaUsec) / 1000.0);
-        } else {
-            dump_printf("pkt[%2d] : localTX %12" PRId64 " localRX never\n",
-                        ndx, txTimes[i]);
-        }
-        i = (i + 1) % RTT_LOG_SIZE;
-        ndx++;
-    } while (i != wrPtr);
-}
-
-#undef dump_printf
-#undef checked_percentage
-
-}  // namespace android
diff --git a/libs/common_time/common_time_server_packets.cpp b/libs/common_time/common_time_server_packets.cpp
deleted file mode 100644
index c7c893d..0000000
--- a/libs/common_time/common_time_server_packets.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * A service that exchanges time synchronization information between
- * a master that defines a timeline and clients that follow the timeline.
- */
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include <arpa/inet.h>
-#include <stdint.h>
-
-#include "common_time_server_packets.h"
-
-namespace android {
-
-const uint32_t TimeServicePacketHeader::kMagic =
-    (static_cast<uint32_t>('c') << 24) |
-    (static_cast<uint32_t>('c') << 16) |
-    (static_cast<uint32_t>('l') <<  8) |
-     static_cast<uint32_t>('k');
-
-const uint16_t TimeServicePacketHeader::kCurVersion = 1;
-
-#define SERIALIZE_FIELD(field_name, type, converter)        \
-    do {                                                    \
-        if ((offset + sizeof(field_name)) > length)         \
-            return -1;                                      \
-        *((type*)(data + offset)) = converter(field_name);  \
-        offset += sizeof(field_name);                       \
-    } while (0)
-#define SERIALIZE_INT16(field_name) SERIALIZE_FIELD(field_name, int16_t, htons)
-#define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl)
-#define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq)
-
-#define DESERIALIZE_FIELD(field_name, type, converter)       \
-    do {                                                     \
-        if ((offset + sizeof(field_name)) > length)          \
-            return -1;                                       \
-        (field_name) = converter(*((type*)(data + offset))); \
-        offset += sizeof(field_name);                        \
-    } while (0)
-#define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs)
-#define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl)
-#define DESERIALIZE_INT64(field_name) DESERIALIZE_FIELD(field_name, int64_t, ntohq)
-
-#define kDevicePriorityShift 56
-#define kDeviceIDMask ((static_cast<uint64_t>(1) << kDevicePriorityShift) - 1)
-
-inline uint64_t packDeviceID(uint64_t devID, uint8_t prio) {
-    return (devID & kDeviceIDMask) |
-           (static_cast<uint64_t>(prio) << kDevicePriorityShift);
-}
-
-inline uint64_t unpackDeviceID(uint64_t packed) {
-    return (packed & kDeviceIDMask);
-}
-
-inline uint8_t unpackDevicePriority(uint64_t packed) {
-    return static_cast<uint8_t>(packed >> kDevicePriorityShift);
-}
-
-ssize_t TimeServicePacketHeader::serializeHeader(uint8_t* data,
-                                                 uint32_t length) {
-    ssize_t offset = 0;
-    int16_t pktType = static_cast<int16_t>(packetType);
-    SERIALIZE_INT32(magic);
-    SERIALIZE_INT16(version);
-    SERIALIZE_INT16(pktType);
-    SERIALIZE_INT64(timelineID);
-    SERIALIZE_INT64(syncGroupID);
-    return offset;
-}
-
-ssize_t TimeServicePacketHeader::deserializeHeader(const uint8_t* data,
-                                                   uint32_t length) {
-    ssize_t offset = 0;
-    int16_t tmp;
-    DESERIALIZE_INT32(magic);
-    DESERIALIZE_INT16(version);
-    DESERIALIZE_INT16(tmp);
-    DESERIALIZE_INT64(timelineID);
-    DESERIALIZE_INT64(syncGroupID);
-    packetType = static_cast<TimeServicePacketType>(tmp);
-    return offset;
-}
-
-ssize_t TimeServicePacketHeader::serializePacket(uint8_t* data,
-                                                 uint32_t length) {
-    ssize_t ret, tmp;
-
-    ret = serializeHeader(data, length);
-    if (ret < 0)
-        return ret;
-
-    data += ret;
-    length -= ret;
-
-    switch (packetType) {
-        case TIME_PACKET_WHO_IS_MASTER_REQUEST:
-            tmp =((WhoIsMasterRequestPacket*)(this))->serializePacket(data,
-                                                                      length);
-            break;
-        case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
-            tmp =((WhoIsMasterResponsePacket*)(this))->serializePacket(data,
-                                                                       length);
-            break;
-        case TIME_PACKET_SYNC_REQUEST:
-            tmp =((SyncRequestPacket*)(this))->serializePacket(data, length);
-            break;
-        case TIME_PACKET_SYNC_RESPONSE:
-            tmp =((SyncResponsePacket*)(this))->serializePacket(data, length);
-            break;
-        case TIME_PACKET_MASTER_ANNOUNCEMENT:
-            tmp =((MasterAnnouncementPacket*)(this))->serializePacket(data,
-                                                                      length);
-            break;
-        default:
-            return -1;
-    }
-
-    if (tmp < 0)
-        return tmp;
-
-    return ret + tmp;
-}
-
-ssize_t UniversalTimeServicePacket::deserializePacket(
-        const uint8_t* data,
-        uint32_t length,
-        uint64_t expectedSyncGroupID) {
-    ssize_t ret;
-    TimeServicePacketHeader* header;
-    if (length < 8)
-        return -1;
-
-    packetType = ntohs(*((uint16_t*)(data + 6)));
-    switch (packetType) {
-        case TIME_PACKET_WHO_IS_MASTER_REQUEST:
-            ret = p.who_is_master_request.deserializePacket(data, length);
-            header = &p.who_is_master_request;
-            break;
-        case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
-            ret = p.who_is_master_response.deserializePacket(data, length);
-            header = &p.who_is_master_response;
-            break;
-        case TIME_PACKET_SYNC_REQUEST:
-            ret = p.sync_request.deserializePacket(data, length);
-            header = &p.sync_request;
-            break;
-        case TIME_PACKET_SYNC_RESPONSE:
-            ret = p.sync_response.deserializePacket(data, length);
-            header = &p.sync_response;
-            break;
-        case TIME_PACKET_MASTER_ANNOUNCEMENT:
-            ret = p.master_announcement.deserializePacket(data, length);
-            header = &p.master_announcement;
-            break;
-        default:
-            return -1;
-    }
-
-    if ((ret >= 0) && !header->checkPacket(expectedSyncGroupID))
-        ret = -1;
-
-    return ret;
-}
-
-ssize_t WhoIsMasterRequestPacket::serializePacket(uint8_t* data,
-                                                  uint32_t length) {
-    ssize_t offset = serializeHeader(data, length);
-    if (offset > 0) {
-        uint64_t packed = packDeviceID(senderDeviceID, senderDevicePriority);
-        SERIALIZE_INT64(packed);
-    }
-    return offset;
-}
-
-ssize_t WhoIsMasterRequestPacket::deserializePacket(const uint8_t* data,
-                                                    uint32_t length) {
-    ssize_t offset = deserializeHeader(data, length);
-    if (offset > 0) {
-        uint64_t packed;
-        DESERIALIZE_INT64(packed);
-        senderDeviceID       = unpackDeviceID(packed);
-        senderDevicePriority = unpackDevicePriority(packed);
-    }
-    return offset;
-}
-
-ssize_t WhoIsMasterResponsePacket::serializePacket(uint8_t* data,
-                                                   uint32_t length) {
-    ssize_t offset = serializeHeader(data, length);
-    if (offset > 0) {
-        uint64_t packed = packDeviceID(deviceID, devicePriority);
-        SERIALIZE_INT64(packed);
-    }
-    return offset;
-}
-
-ssize_t WhoIsMasterResponsePacket::deserializePacket(const uint8_t* data,
-                                                     uint32_t length) {
-    ssize_t offset = deserializeHeader(data, length);
-    if (offset > 0) {
-        uint64_t packed;
-        DESERIALIZE_INT64(packed);
-        deviceID       = unpackDeviceID(packed);
-        devicePriority = unpackDevicePriority(packed);
-    }
-    return offset;
-}
-
-ssize_t SyncRequestPacket::serializePacket(uint8_t* data,
-                                           uint32_t length) {
-    ssize_t offset = serializeHeader(data, length);
-    if (offset > 0) {
-        SERIALIZE_INT64(clientTxLocalTime);
-    }
-    return offset;
-}
-
-ssize_t SyncRequestPacket::deserializePacket(const uint8_t* data,
-                                             uint32_t length) {
-    ssize_t offset = deserializeHeader(data, length);
-    if (offset > 0) {
-        DESERIALIZE_INT64(clientTxLocalTime);
-    }
-    return offset;
-}
-
-ssize_t SyncResponsePacket::serializePacket(uint8_t* data,
-                                            uint32_t length) {
-    ssize_t offset = serializeHeader(data, length);
-    if (offset > 0) {
-        SERIALIZE_INT64(clientTxLocalTime);
-        SERIALIZE_INT64(masterRxCommonTime);
-        SERIALIZE_INT64(masterTxCommonTime);
-        SERIALIZE_INT32(nak);
-    }
-    return offset;
-}
-
-ssize_t SyncResponsePacket::deserializePacket(const uint8_t* data,
-                                              uint32_t length) {
-    ssize_t offset = deserializeHeader(data, length);
-    if (offset > 0) {
-        DESERIALIZE_INT64(clientTxLocalTime);
-        DESERIALIZE_INT64(masterRxCommonTime);
-        DESERIALIZE_INT64(masterTxCommonTime);
-        DESERIALIZE_INT32(nak);
-    }
-    return offset;
-}
-
-ssize_t MasterAnnouncementPacket::serializePacket(uint8_t* data,
-                                                  uint32_t length) {
-    ssize_t offset = serializeHeader(data, length);
-    if (offset > 0) {
-        uint64_t packed = packDeviceID(deviceID, devicePriority);
-        SERIALIZE_INT64(packed);
-    }
-    return offset;
-}
-
-ssize_t MasterAnnouncementPacket::deserializePacket(const uint8_t* data,
-                                                    uint32_t length) {
-    ssize_t offset = deserializeHeader(data, length);
-    if (offset > 0) {
-        uint64_t packed;
-        DESERIALIZE_INT64(packed);
-        deviceID       = unpackDeviceID(packed);
-        devicePriority = unpackDevicePriority(packed);
-    }
-    return offset;
-}
-
-}  // namespace android
-
diff --git a/libs/common_time/common_time_server_packets.h b/libs/common_time/common_time_server_packets.h
deleted file mode 100644
index 57ba8a2..0000000
--- a/libs/common_time/common_time_server_packets.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_COMMON_TIME_SERVER_PACKETS_H
-#define ANDROID_COMMON_TIME_SERVER_PACKETS_H
-
-#include <stdint.h>
-#include <common_time/ICommonClock.h>
-
-namespace android {
-
-/***** time sync protocol packets *****/
-
-enum TimeServicePacketType {
-    TIME_PACKET_WHO_IS_MASTER_REQUEST = 1,
-    TIME_PACKET_WHO_IS_MASTER_RESPONSE,
-    TIME_PACKET_SYNC_REQUEST,
-    TIME_PACKET_SYNC_RESPONSE,
-    TIME_PACKET_MASTER_ANNOUNCEMENT,
-};
-
-class TimeServicePacketHeader {
-  public:
-    friend class UniversalTimeServicePacket;
-    // magic number identifying the protocol
-    uint32_t magic;
-
-    // protocol version of the packet
-    uint16_t version;
-
-    // type of the packet
-    TimeServicePacketType packetType;
-
-    // the timeline ID
-    uint64_t timelineID;
-
-    // synchronization group this packet belongs to (used to operate multiple
-    // synchronization domains which all use the same master election endpoint)
-    uint64_t syncGroupID;
-
-    ssize_t serializePacket(uint8_t* data, uint32_t length);
-
-  protected:
-    void initHeader(TimeServicePacketType type,
-                    const uint64_t tlID,
-                    const uint64_t groupID) {
-        magic              = kMagic;
-        version            = kCurVersion;
-        packetType         = type;
-        timelineID         = tlID;
-        syncGroupID        = groupID;
-    }
-
-    bool checkPacket(uint64_t expectedSyncGroupID) const {
-        return ((magic       == kMagic) &&
-                (version     == kCurVersion) &&
-                (!expectedSyncGroupID || (syncGroupID == expectedSyncGroupID)));
-    }
-
-    ssize_t serializeHeader(uint8_t* data, uint32_t length);
-    ssize_t deserializeHeader(const uint8_t* data, uint32_t length);
-
-  private:
-    static const uint32_t kMagic;
-    static const uint16_t kCurVersion;
-};
-
-// packet querying for a suitable master
-class WhoIsMasterRequestPacket : public TimeServicePacketHeader {
-  public:
-    uint64_t senderDeviceID;
-    uint8_t senderDevicePriority;
-
-    void initHeader(const uint64_t groupID) {
-        TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_REQUEST,
-                                            ICommonClock::kInvalidTimelineID,
-                                            groupID);
-    }
-
-    ssize_t serializePacket(uint8_t* data, uint32_t length);
-    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
-};
-
-// response to a WhoIsMaster request
-class WhoIsMasterResponsePacket : public TimeServicePacketHeader {
-  public:
-    uint64_t deviceID;
-    uint8_t devicePriority;
-
-    void initHeader(const uint64_t tlID, const uint64_t groupID) {
-        TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_RESPONSE,
-                                            tlID, groupID);
-    }
-
-    ssize_t serializePacket(uint8_t* data, uint32_t length);
-    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
-};
-
-// packet sent by a client requesting correspondence between local
-// and common time
-class SyncRequestPacket : public TimeServicePacketHeader {
-  public:
-    // local time when this request was transmitted
-    int64_t clientTxLocalTime;
-
-    void initHeader(const uint64_t tlID, const uint64_t groupID) {
-        TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_REQUEST,
-                                            tlID, groupID);
-    }
-
-    ssize_t serializePacket(uint8_t* data, uint32_t length);
-    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
-};
-
-// response to a sync request sent by the master
-class SyncResponsePacket : public TimeServicePacketHeader {
-  public:
-    // local time when this request was transmitted by the client
-    int64_t clientTxLocalTime;
-
-    // common time when the master received the request
-    int64_t masterRxCommonTime;
-
-    // common time when the master transmitted the response
-    int64_t masterTxCommonTime;
-
-    // flag that is set if the recipient of the sync request is not acting
-    // as a master for the requested timeline
-    uint32_t nak;
-
-    void initHeader(const uint64_t tlID, const uint64_t groupID) {
-        TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_RESPONSE,
-                                            tlID, groupID);
-    }
-
-    ssize_t serializePacket(uint8_t* data, uint32_t length);
-    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
-};
-
-// announcement of the master's presence
-class MasterAnnouncementPacket : public TimeServicePacketHeader {
-  public:
-    // the master's device ID
-    uint64_t deviceID;
-    uint8_t devicePriority;
-
-    void initHeader(const uint64_t tlID, const uint64_t groupID) {
-        TimeServicePacketHeader::initHeader(TIME_PACKET_MASTER_ANNOUNCEMENT,
-                                            tlID, groupID);
-    }
-
-    ssize_t serializePacket(uint8_t* data, uint32_t length);
-    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
-};
-
-class UniversalTimeServicePacket {
-  public:
-    uint16_t packetType;
-    union {
-        WhoIsMasterRequestPacket  who_is_master_request;
-        WhoIsMasterResponsePacket who_is_master_response;
-        SyncRequestPacket         sync_request;
-        SyncResponsePacket        sync_response;
-        MasterAnnouncementPacket  master_announcement;
-    } p;
-
-    ssize_t deserializePacket(const uint8_t* data,
-                              uint32_t       length,
-                              uint64_t       expectedSyncGroupID);
-};
-
-};  // namespace android
-
-#endif  // ANDROID_COMMON_TIME_SERVER_PACKETS_H
-
-
diff --git a/libs/common_time/diag_thread.cpp b/libs/common_time/diag_thread.cpp
deleted file mode 100644
index 4cb9551..0000000
--- a/libs/common_time/diag_thread.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include <fcntl.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <utils/Errors.h>
-#include <utils/misc.h>
-
-#include <common_time/local_clock.h>
-
-#include "common_clock.h"
-#include "diag_thread.h"
-
-#define kMaxEvents 16
-#define kListenPort 9876
-
-static bool setNonblocking(int fd) {
-    int flags = fcntl(fd, F_GETFL);
-    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
-        ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
-             fd, errno);
-        return false;
-    }
-
-    return true;
-}
-
-static bool setNodelay(int fd) {
-    int tmp = 1;
-    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)) < 0) {
-        ALOGE("Failed to set socket (%d) to no-delay mode (errno %d)",
-             fd, errno);
-        return false;
-    }
-
-    return true;
-}
-
-namespace android {
-
-DiagThread::DiagThread(CommonClock* common_clock, LocalClock* local_clock) {
-    common_clock_ = common_clock;
-    local_clock_ = local_clock;
-    listen_fd_ = -1;
-    data_fd_ = -1;
-    kernel_logID_basis_known_ = false;
-    discipline_log_ID_ = 0;
-}
-
-DiagThread::~DiagThread() {
-}
-
-status_t DiagThread::startWorkThread() {
-    status_t res;
-    stopWorkThread();
-    res = run("Diag");
-
-    if (res != OK)
-        ALOGE("Failed to start work thread (res = %d)", res);
-
-    return res;
-}
-
-void DiagThread::stopWorkThread() {
-    status_t res;
-    res = requestExitAndWait(); // block until thread exit.
-    if (res != OK)
-        ALOGE("Failed to stop work thread (res = %d)", res);
-}
-
-bool DiagThread::openListenSocket() {
-    bool ret = false;
-    int flags;
-    cleanupListenSocket();
-
-    if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
-        ALOGE("Socket failed.");
-        goto bailout;
-    }
-
-    // Set non-blocking operation
-    if (!setNonblocking(listen_fd_))
-        goto bailout;
-
-    struct sockaddr_in addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = INADDR_ANY;
-    addr.sin_port = htons(kListenPort);
-
-    if (bind(listen_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
-        ALOGE("Bind failed.");
-        goto bailout;
-    }
-
-    if (listen(listen_fd_, 1) < 0) {
-        ALOGE("Listen failed.");
-        goto bailout;
-    }
-
-    ret = true;
-bailout:
-    if (!ret)
-        cleanupListenSocket();
-
-    return ret;
-}
-
-void DiagThread::cleanupListenSocket() {
-    if (listen_fd_ >= 0) {
-        int res;
-
-        struct linger l;
-        l.l_onoff  = 1;
-        l.l_linger = 0;
-
-        setsockopt(listen_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
-        shutdown(listen_fd_, SHUT_RDWR);
-        close(listen_fd_);
-        listen_fd_ = -1;
-    }
-}
-
-void DiagThread::cleanupDataSocket() {
-    if (data_fd_ >= 0) {
-        int res;
-
-        struct linger l;
-        l.l_onoff  = 1;
-        l.l_linger = 0;
-
-        setsockopt(data_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
-        shutdown(data_fd_, SHUT_RDWR);
-        close(data_fd_);
-        data_fd_ = -1;
-    }
-}
-
-void DiagThread::resetLogIDs() {
-    // Drain and discard all of the events from the kernel
-    struct local_time_debug_event events[kMaxEvents];
-    while(local_clock_->getDebugLog(events, kMaxEvents) > 0)
-        ;
-
-    {
-        Mutex::Autolock lock(&discipline_log_lock_);
-        discipline_log_.clear();
-        discipline_log_ID_ = 0;
-    }
-
-    kernel_logID_basis_known_ = false;
-}
-
-void DiagThread::pushDisciplineEvent(int64_t observed_local_time,
-                                     int64_t observed_common_time,
-                                     int64_t nominal_common_time,
-                                     int32_t total_correction,
-                                     int32_t rtt) {
-    Mutex::Autolock lock(&discipline_log_lock_);
-
-    DisciplineEventRecord evt;
-
-    evt.event_id = discipline_log_ID_++;
-
-    evt.action_local_time = local_clock_->getLocalTime();
-    common_clock_->localToCommon(evt.action_local_time,
-            &evt.action_common_time);
-
-    evt.observed_local_time  = observed_local_time;
-    evt.observed_common_time = observed_common_time;
-    evt.nominal_common_time  = nominal_common_time;
-    evt.total_correction     = total_correction;
-    evt.rtt                  = rtt;
-
-    discipline_log_.push_back(evt);
-    while (discipline_log_.size() > kMaxDisciplineLogSize)
-        discipline_log_.erase(discipline_log_.begin());
-}
-
-bool DiagThread::threadLoop() {
-    struct pollfd poll_fds[1];
-
-    if (!openListenSocket()) {
-        ALOGE("Failed to open listen socket");
-        goto bailout;
-    }
-
-    while (!exitPending()) {
-        memset(&poll_fds, 0, sizeof(poll_fds));
-
-        if (data_fd_ < 0) {
-            poll_fds[0].fd     = listen_fd_;
-            poll_fds[0].events = POLLIN;
-        } else {
-            poll_fds[0].fd     = data_fd_;
-            poll_fds[0].events = POLLRDHUP | POLLIN;
-        }
-
-        int poll_res = poll(poll_fds, NELEM(poll_fds), 50);
-        if (poll_res < 0) {
-            ALOGE("Fatal error (%d,%d) while waiting on events",
-                 poll_res, errno);
-            goto bailout;
-        }
-
-        if (exitPending())
-            break;
-
-        if (poll_fds[0].revents) {
-            if (poll_fds[0].fd == listen_fd_) {
-                data_fd_ = accept(listen_fd_, NULL, NULL);
-
-                if (data_fd_ < 0) {
-                    ALOGW("Failed accept on socket %d with err %d",
-                         listen_fd_, errno);
-                } else {
-                    if (!setNonblocking(data_fd_))
-                        cleanupDataSocket();
-                    if (!setNodelay(data_fd_))
-                        cleanupDataSocket();
-                }
-            } else
-                if (poll_fds[0].fd == data_fd_) {
-                    if (poll_fds[0].revents & POLLRDHUP) {
-                        // Connection hung up; time to clean up.
-                        cleanupDataSocket();
-                    } else
-                        if (poll_fds[0].revents & POLLIN) {
-                            uint8_t cmd;
-                            if (read(data_fd_, &cmd, sizeof(cmd)) > 0) {
-                                switch(cmd) {
-                                    case 'r':
-                                    case 'R':
-                                        resetLogIDs();
-                                        break;
-                                }
-                            }
-                        }
-                }
-        }
-
-        struct local_time_debug_event events[kMaxEvents];
-        int amt = local_clock_->getDebugLog(events, kMaxEvents);
-
-        if (amt > 0) {
-            for (int i = 0; i < amt; i++) {
-                struct local_time_debug_event& e = events[i];
-
-                if (!kernel_logID_basis_known_) {
-                    kernel_logID_basis_ = e.local_timesync_event_id;
-                    kernel_logID_basis_known_ = true;
-                }
-
-                char buf[1024];
-                int64_t common_time;
-                status_t res = common_clock_->localToCommon(e.local_time,
-                                                            &common_time);
-                snprintf(buf, sizeof(buf), "E,%lld,%lld,%lld,%d\n",
-                         e.local_timesync_event_id - kernel_logID_basis_,
-                         e.local_time,
-                         common_time,
-                         (OK == res) ? 1 : 0);
-                buf[sizeof(buf) - 1] = 0;
-
-                if (data_fd_ >= 0)
-                    write(data_fd_, buf, strlen(buf));
-            }
-        }
-
-        { // scope for autolock pattern
-            Mutex::Autolock lock(&discipline_log_lock_);
-
-            while (discipline_log_.size() > 0) {
-                char buf[1024];
-                DisciplineEventRecord& e = *discipline_log_.begin();
-                snprintf(buf, sizeof(buf),
-                         "D,%lld,%lld,%lld,%lld,%lld,%lld,%d,%d\n",
-                         e.event_id,
-                         e.action_local_time,
-                         e.action_common_time,
-                         e.observed_local_time,
-                         e.observed_common_time,
-                         e.nominal_common_time,
-                         e.total_correction,
-                         e.rtt);
-                buf[sizeof(buf) - 1] = 0;
-
-                if (data_fd_ >= 0)
-                    write(data_fd_, buf, strlen(buf));
-
-                discipline_log_.erase(discipline_log_.begin());
-            }
-        }
-    }
-
-bailout:
-    cleanupDataSocket();
-    cleanupListenSocket();
-    return false;
-}
-
-}  // namespace android
diff --git a/libs/common_time/diag_thread.h b/libs/common_time/diag_thread.h
deleted file mode 100644
index c630e0d..0000000
--- a/libs/common_time/diag_thread.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __DIAG_THREAD_H__
-#define __DIAG_THREAD_H__
-
-#include <utils/List.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class CommonClock;
-class LocalClock;
-
-class DiagThread : public Thread {
-  public:
-    DiagThread(CommonClock* common_clock, LocalClock* local_clock);
-    ~DiagThread();
-
-    status_t      startWorkThread();
-    void          stopWorkThread();
-    virtual bool  threadLoop();
-
-    void pushDisciplineEvent(int64_t observed_local_time,
-                             int64_t observed_common_time,
-                             int64_t nominal_common_time,
-                             int32_t total_correction,
-                             int32_t rtt);
-
-  private:
-    typedef struct {
-        int64_t event_id;
-        int64_t action_local_time;
-        int64_t action_common_time;
-        int64_t observed_local_time;
-        int64_t observed_common_time;
-        int64_t nominal_common_time;
-        int32_t total_correction;
-        int32_t rtt;
-    } DisciplineEventRecord;
-
-    bool            openListenSocket();
-    void            cleanupListenSocket();
-    void            cleanupDataSocket();
-    void            resetLogIDs();
-
-    CommonClock*    common_clock_;
-    LocalClock*     local_clock_;
-    int             listen_fd_;
-    int             data_fd_;
-
-    int64_t         kernel_logID_basis_;
-    bool            kernel_logID_basis_known_;
-
-    static const size_t         kMaxDisciplineLogSize = 16;
-    Mutex                       discipline_log_lock_;
-    List<DisciplineEventRecord> discipline_log_;
-    int64_t                     discipline_log_ID_;
-};
-
-}  // namespace android
-
-#endif  //__ DIAG_THREAD_H__
diff --git a/libs/common_time/main.cpp b/libs/common_time/main.cpp
deleted file mode 100644
index ac52c85..0000000
--- a/libs/common_time/main.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * A service that exchanges time synchronization information between
- * a master that defines a timeline and clients that follow the timeline.
- */
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-
-#include "common_time_server.h"
-
-int main() {
-    using namespace android;
-
-    sp<CommonTimeServer> service = new CommonTimeServer();
-    if (service == NULL)
-        return 1;
-
-    ProcessState::self()->startThreadPool();
-    service->run("CommonTimeServer", ANDROID_PRIORITY_NORMAL);
-
-    IPCThreadState::self()->joinThreadPool();
-    return 0;
-}
-
diff --git a/libs/common_time/utils.cpp b/libs/common_time/utils.cpp
deleted file mode 100644
index ddcdfe7..0000000
--- a/libs/common_time/utils.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "common_time"
-#include <utils/Log.h>
-
-#include "utils.h"
-
-namespace android {
-
-void Timeout::setTimeout(int msec) {
-    if (msec < 0) {
-        mSystemEndTime = 0;
-        return;
-    }
-
-    mSystemEndTime = systemTime() + (static_cast<nsecs_t>(msec) * 1000000);
-}
-
-int Timeout::msecTillTimeout(nsecs_t nowTime) {
-    if (!mSystemEndTime) {
-        return -1;
-    }
-
-    if (mSystemEndTime < nowTime) {
-        return 0;
-    }
-
-    nsecs_t delta = mSystemEndTime - nowTime;
-    delta += 999999;
-    delta /= 1000000;
-    if (delta > 0x7FFFFFFF) {
-        return 0x7FFFFFFF;
-    }
-
-    return static_cast<int>(delta);
-}
-
-LogRing::LogRing(const char* header, size_t entries)
-    : mSize(entries)
-    , mWr(0)
-    , mIsFull(false)
-    , mHeader(header) {
-    mRingBuffer = new Entry[mSize];
-    if (NULL == mRingBuffer)
-        ALOGE("Failed to allocate log ring with %zu entries.", mSize);
-}
-
-LogRing::~LogRing() {
-    if (NULL != mRingBuffer)
-        delete[] mRingBuffer;
-}
-
-void LogRing::log(int prio, const char* tag, const char* fmt, ...) {
-    va_list argp;
-    va_start(argp, fmt);
-    internalLog(prio, tag, fmt, argp);
-    va_end(argp);
-}
-
-void LogRing::log(const char* fmt, ...) {
-    va_list argp;
-    va_start(argp, fmt);
-    internalLog(0, NULL, fmt, argp);
-    va_end(argp);
-}
-
-void LogRing::internalLog(int prio,
-                          const char* tag,
-                          const char* fmt,
-                          va_list argp) {
-    if (NULL != mRingBuffer) {
-        Mutex::Autolock lock(&mLock);
-        String8 s(String8::formatV(fmt, argp));
-        Entry* last = NULL;
-
-        if (mIsFull || mWr)
-            last = &(mRingBuffer[(mWr + mSize - 1) % mSize]);
-
-
-        if ((NULL != last) && !last->s.compare(s)) {
-            gettimeofday(&(last->last_ts), NULL);
-            ++last->count;
-        } else {
-            gettimeofday(&mRingBuffer[mWr].first_ts, NULL);
-            mRingBuffer[mWr].last_ts = mRingBuffer[mWr].first_ts;
-            mRingBuffer[mWr].count = 1;
-            mRingBuffer[mWr].s.setTo(s);
-
-            mWr = (mWr + 1) % mSize;
-            if (!mWr)
-                mIsFull = true;
-        }
-    }
-
-    if (NULL != tag)
-        LOG_PRI_VA(prio, tag, fmt, argp);
-}
-
-void LogRing::dumpLog(int fd) {
-    if (NULL == mRingBuffer)
-        return;
-
-    Mutex::Autolock lock(&mLock);
-
-    if (!mWr && !mIsFull)
-        return;
-
-    char buf[1024];
-    int res;
-    size_t start = mIsFull ? mWr : 0;
-    size_t count = mIsFull ? mSize : mWr;
-    static const char* kTimeFmt = "%a %b %d %Y %H:%M:%S";
-
-    res = snprintf(buf, sizeof(buf), "\n%s\n", mHeader);
-    if (res > 0)
-        write(fd, buf, res);
-
-    for (size_t i = 0; i < count; ++i) {
-        struct tm t;
-        char timebuf[64];
-        char repbuf[96];
-        size_t ndx = (start + i) % mSize;
-
-        if (1 != mRingBuffer[ndx].count) {
-            localtime_r(&mRingBuffer[ndx].last_ts.tv_sec, &t);
-            strftime(timebuf, sizeof(timebuf), kTimeFmt, &t);
-            snprintf(repbuf, sizeof(repbuf),
-                    " (repeated %d times, last was %s.%03ld)",
-                     mRingBuffer[ndx].count,
-                     timebuf,
-                     mRingBuffer[ndx].last_ts.tv_usec / 1000);
-            repbuf[sizeof(repbuf) - 1] = 0;
-        } else {
-            repbuf[0] = 0;
-        }
-
-        localtime_r(&mRingBuffer[ndx].first_ts.tv_sec, &t);
-        strftime(timebuf, sizeof(timebuf), kTimeFmt, &t);
-        res = snprintf(buf, sizeof(buf), "[%2zu] %s.%03ld :: %s%s\n",
-                       i, timebuf,
-                       mRingBuffer[ndx].first_ts.tv_usec / 1000,
-                       mRingBuffer[ndx].s.string(),
-                       repbuf);
-
-        if (res > 0)
-            write(fd, buf, res);
-    }
-}
-
-}  // namespace android
diff --git a/libs/common_time/utils.h b/libs/common_time/utils.h
deleted file mode 100644
index c28cf0a..0000000
--- a/libs/common_time/utils.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTILS_H__
-#define __UTILS_H__
-
-#include <stdint.h>
-#include <unistd.h>
-
-#include <utils/String8.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-class Timeout {
-  public:
-    Timeout() : mSystemEndTime(0) { }
-
-    // Set a timeout which should occur msec milliseconds from now.
-    // Negative values will cancel any current timeout;
-    void setTimeout(int msec);
-
-    // Return the number of milliseconds until the timeout occurs, or -1 if
-    // no timeout is scheduled.
-    int msecTillTimeout(nsecs_t nowTime);
-    int msecTillTimeout() { return msecTillTimeout(systemTime()); }
-
-  private:
-    // The systemTime() at which the timeout will be complete, or 0 if no
-    // timeout is currently scheduled.
-    nsecs_t mSystemEndTime;
-};
-
-class LogRing {
-  public:
-    LogRing(const char* header, size_t entries);
-    ~LogRing();
-
-    // Send a log message to logcat as well as storing it in the ring buffer.
-    void log(int prio, const char* tag, const char* fmt, ...);
-
-    // Add a log message the ring buffer, do not send the message to logcat.
-    void log(const char* fmt, ...);
-
-    // Dump the log to an fd (dumpsys style)
-    void dumpLog(int fd);
-
-  private:
-    class Entry {
-      public:
-        uint32_t count;
-        struct timeval first_ts;
-        struct timeval last_ts;
-        String8 s;
-    };
-
-    Mutex  mLock;
-    Entry* mRingBuffer;
-    size_t mSize;
-    size_t mWr;
-    bool   mIsFull;
-    const char* mHeader;
-
-    void internalLog(int prio, const char* tag, const char* fmt, va_list va);
-};
-
-}  // namespace android
-
-#endif  // __UTILS_H__
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 1e71cb0..69d5130 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -59,6 +59,7 @@
     mHas1BitStencil = extensions.has("GL_OES_stencil1");
     mHas4BitStencil = extensions.has("GL_OES_stencil4");
     mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage");
+    mHasRenderableFloatTexture = extensions.has("GL_OES_texture_half_float");
 
     mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB");
     mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control");
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 0ecfdb1..7af7f79 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -38,6 +38,9 @@
     inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
     inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
     inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
+    inline bool hasRenderableFloatTextures() const {
+        return (mVersionMajor >= 3 && mVersionMinor >= 2) || mHasRenderableFloatTexture;
+    }
     inline bool hasSRGB() const { return mHasSRGB; }
     inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; }
     inline bool hasLinearBlending() const { return hasSRGB() && mHasLinearBlending; }
@@ -56,6 +59,7 @@
     bool mHasSRGB;
     bool mHasSRGBWriteControl;
     bool mHasLinearBlending;
+    bool mHasRenderableFloatTexture;
 
     int mVersionMajor;
     int mVersionMinor;
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 2687410..751e203 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -128,7 +128,8 @@
         return CopyResult::DestinationInvalid;
     }
 
-    if (bitmap->colorType() == kRGBA_F16_SkColorType && !caches.extensions().hasFloatTextures()) {
+    if (bitmap->colorType() == kRGBA_F16_SkColorType &&
+            !caches.extensions().hasRenderableFloatTextures()) {
         ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
         return CopyResult::DestinationInvalid;
     }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5d7f594..b8815b5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -295,7 +295,7 @@
 
         // If there's a multi-frameInterval gap we effectively already dropped a frame,
         // so consider the queue healthy.
-        if (swapA.swapCompletedTime - swapB.swapCompletedTime > frameInterval * 3) {
+        if (std::abs(swapA.swapCompletedTime - swapB.swapCompletedTime) > frameInterval * 3) {
             return false;
         }
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 72a428f..bd34eb8 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -236,10 +236,8 @@
             break;
     }
 
-    FILE *file = fdopen(fd, "a");
-    fprintf(file, "\n%s\n", cachesOutput.string());
-    fprintf(file, "\nPipeline=%s\n", pipeline.string());
-    fflush(file);
+    dprintf(fd, "\n%s\n", cachesOutput.string());
+    dprintf(fd, "\nPipeline=%s\n", pipeline.string());
 }
 
 Readback& RenderThread::readback() {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index f7a90b0..32b5132 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -134,7 +134,7 @@
         return false;
     }
     void* addr = mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
-    if (!addr) {
+    if (addr == MAP_FAILED) {
         int err = errno;
         // The file not existing is normal for addToDump(), so only log if
         // we get an unexpected error
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
new file mode 100644
index 0000000..447195d
--- /dev/null
+++ b/location/lib/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_sdk_library {
+    name: "com.android.location.provider",
+    srcs: ["java/**/*.java"],
+    api_packages: ["com.android.location.provider"],
+}
diff --git a/location/lib/Android.mk b/location/lib/Android.mk
deleted file mode 100644
index 6642134..0000000
--- a/location/lib/Android.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= com.android.location.provider
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-# ====  com.google.location.xml lib def  ========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.location.provider.xml
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-# ==== Stub library  ===========================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := com.android.location.provider-stubs-gen
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_SRC_FILES := $(call all-java-files-under,java)
-LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.location.provider.stubs_intermediates/src
-LOCAL_DROIDDOC_OPTIONS:= \
-    -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
-    -stubpackages com.android.location.provider \
-    -nodocs
-LOCAL_UNINSTALLABLE_MODULE := true
-include $(BUILD_DROIDDOC)
-com_android_nfc_extras_gen_stamp := $(full_target)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := com.android.location.provider.stubs
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-LOCAL_SDK_VERSION := current
-LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_nfc_extras_gen_stamp)
-com_android_nfc_extras_gen_stamp :=
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
new file mode 100644
index 0000000..1e69f16
--- /dev/null
+++ b/location/lib/api/current.txt
@@ -0,0 +1,47 @@
+package com.android.location.provider {
+
+  public abstract deprecated class FusedProvider {
+    ctor public FusedProvider();
+    method public android.os.IBinder getBinder();
+  }
+
+  public abstract class LocationProviderBase {
+    ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled);
+    method public android.os.IBinder getBinder();
+    method public abstract void onDisable();
+    method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public abstract void onEnable();
+    method public abstract int onGetStatus(android.os.Bundle);
+    method public abstract long onGetStatusUpdateTime();
+    method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
+    method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
+    method public final void reportLocation(android.location.Location);
+    field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
+    field public static final java.lang.String FUSED_PROVIDER = "fused";
+  }
+
+  public final class LocationRequestUnbundled {
+    method public long getFastestInterval();
+    method public long getInterval();
+    method public int getQuality();
+    method public float getSmallestDisplacement();
+    field public static final int ACCURACY_BLOCK = 102; // 0x66
+    field public static final int ACCURACY_CITY = 104; // 0x68
+    field public static final int ACCURACY_FINE = 100; // 0x64
+    field public static final int POWER_HIGH = 203; // 0xcb
+    field public static final int POWER_LOW = 201; // 0xc9
+    field public static final int POWER_NONE = 200; // 0xc8
+  }
+
+  public final class ProviderPropertiesUnbundled {
+    method public static com.android.location.provider.ProviderPropertiesUnbundled create(boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
+  }
+
+  public final class ProviderRequestUnbundled {
+    method public long getInterval();
+    method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+    method public boolean getReportLocation();
+  }
+
+}
+
diff --git a/location/lib/api/removed.txt b/location/lib/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/location/lib/api/removed.txt
diff --git a/location/lib/api/system-current.txt b/location/lib/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/location/lib/api/system-current.txt
diff --git a/location/lib/api/system-removed.txt b/location/lib/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/location/lib/api/system-removed.txt
diff --git a/location/lib/api/test-current.txt b/location/lib/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/location/lib/api/test-current.txt
diff --git a/location/lib/api/test-removed.txt b/location/lib/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/location/lib/api/test-removed.txt
diff --git a/location/lib/com.android.location.provider.xml b/location/lib/com.android.location.provider.xml
deleted file mode 100644
index 000e68f..0000000
--- a/location/lib/com.android.location.provider.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     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.
--->
-
-<permissions>
-    <library name="com.android.location.provider"
-            file="/system/framework/com.android.location.provider.jar" />
-</permissions>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b110ccf..29d7dee 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3664,6 +3664,7 @@
      * @param device Bluetooth device connected/disconnected
      * @param state  new connection state (BluetoothProfile.STATE_xxx)
      * @param profile profile for the A2DP device
+     * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
      * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
      * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
      * @param suppressNoisyIntent if true the
@@ -3673,12 +3674,13 @@
      * {@hide}
      */
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent) {
+                BluetoothDevice device, int state, int profile,
+                boolean suppressNoisyIntent, int a2dpVolume) {
         final IAudioService service = getService();
         int delay = 0;
         try {
             delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
-                state, profile, suppressNoisyIntent);
+                state, profile, suppressNoisyIntent, a2dpVolume);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 07b6bbd..d757b81 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -206,7 +206,7 @@
     oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
 
     int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
-            int state, int profile, boolean suppressNoisyIntent);
+            int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
 
     // WARNING: read warning at top of file, it is recommended to add new methods at the end
 }
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
new file mode 100644
index 0000000..3b25787
--- /dev/null
+++ b/media/lib/signer/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_sdk_library {
+    name: "com.android.mediadrm.signer",
+    srcs: ["java/**/*.java"],
+    api_packages: ["com.android.mediadrm.signer"],
+}
diff --git a/media/lib/signer/Android.mk b/media/lib/signer/Android.mk
deleted file mode 100644
index 69ca4d2..0000000
--- a/media/lib/signer/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (C) 2013 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-# the mediadrm signer library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= com.android.mediadrm.signer
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-# ====  com.android.mediadrm.signer.xml lib def  ========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.mediadrm.signer.xml
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
diff --git a/media/lib/signer/api/current.txt b/media/lib/signer/api/current.txt
new file mode 100644
index 0000000..4aa912d
--- /dev/null
+++ b/media/lib/signer/api/current.txt
@@ -0,0 +1,21 @@
+package com.android.mediadrm.signer {
+
+  public final class MediaDrmSigner {
+    method public static com.android.mediadrm.signer.MediaDrmSigner.CertificateRequest getCertificateRequest(android.media.MediaDrm, int, java.lang.String);
+    method public static com.android.mediadrm.signer.MediaDrmSigner.Certificate provideCertificateResponse(android.media.MediaDrm, byte[]) throws android.media.DeniedByServerException;
+    method public static byte[] signRSA(android.media.MediaDrm, byte[], java.lang.String, byte[], byte[]);
+    field public static final int CERTIFICATE_TYPE_X509 = 1; // 0x1
+  }
+
+  public static final class MediaDrmSigner.Certificate {
+    method public byte[] getContent();
+    method public byte[] getWrappedPrivateKey();
+  }
+
+  public static final class MediaDrmSigner.CertificateRequest {
+    method public byte[] getData();
+    method public java.lang.String getDefaultUrl();
+  }
+
+}
+
diff --git a/media/lib/signer/api/removed.txt b/media/lib/signer/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/signer/api/removed.txt
diff --git a/media/lib/signer/api/system-current.txt b/media/lib/signer/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/signer/api/system-current.txt
diff --git a/media/lib/signer/api/system-removed.txt b/media/lib/signer/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/signer/api/system-removed.txt
diff --git a/media/lib/signer/api/test-current.txt b/media/lib/signer/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/signer/api/test-current.txt
diff --git a/media/lib/signer/api/test-removed.txt b/media/lib/signer/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/signer/api/test-removed.txt
diff --git a/media/lib/signer/com.android.mediadrm.signer.xml b/media/lib/signer/com.android.mediadrm.signer.xml
deleted file mode 100644
index fd3a115..0000000
--- a/media/lib/signer/com.android.mediadrm.signer.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-
-<permissions>
-    <library name="com.android.mediadrm.signer"
-            file="/system/framework/com.android.mediadrm.signer.jar" />
-</permissions>
diff --git a/media/lib/tvremote/Android.bp b/media/lib/tvremote/Android.bp
new file mode 100644
index 0000000..5f101a3
--- /dev/null
+++ b/media/lib/tvremote/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_sdk_library {
+    name: "com.android.media.tv.remoteprovider",
+    srcs: ["java/**/*.java"],
+    api_packages: ["com.android.media.tv.remoteprovider"],
+    dex_preopt: {
+        enabled: false,
+    }
+}
diff --git a/media/lib/tvremote/Android.mk b/media/lib/tvremote/Android.mk
deleted file mode 100644
index 1ffdd62..0000000
--- a/media/lib/tvremote/Android.mk
+++ /dev/null
@@ -1,46 +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.
-#
-LOCAL_PATH := $(call my-dir)
-
-# the tvremoteprovider library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= com.android.media.tv.remoteprovider
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-# ====  com.android.media.tvremote.xml lib def  ========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.media.tv.remoteprovider.xml
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
diff --git a/media/lib/tvremote/api/current.txt b/media/lib/tvremote/api/current.txt
new file mode 100644
index 0000000..eea9e9c
--- /dev/null
+++ b/media/lib/tvremote/api/current.txt
@@ -0,0 +1,21 @@
+package com.android.media.tv.remoteprovider {
+
+  public abstract class TvRemoteProvider {
+    ctor public TvRemoteProvider(android.content.Context);
+    method public void clearInputBridge(android.os.IBinder) throws java.lang.RuntimeException;
+    method public void closeInputBridge(android.os.IBinder) throws java.lang.RuntimeException;
+    method public android.os.IBinder getBinder();
+    method public final android.content.Context getContext();
+    method public void onInputBridgeConnected(android.os.IBinder);
+    method public void openRemoteInputBridge(android.os.IBinder, java.lang.String, int, int, int) throws java.lang.RuntimeException;
+    method public void sendKeyDown(android.os.IBinder, int) throws java.lang.RuntimeException;
+    method public void sendKeyUp(android.os.IBinder, int) throws java.lang.RuntimeException;
+    method public void sendPointerDown(android.os.IBinder, int, int, int) throws java.lang.RuntimeException;
+    method public void sendPointerSync(android.os.IBinder) throws java.lang.RuntimeException;
+    method public void sendPointerUp(android.os.IBinder, int) throws java.lang.RuntimeException;
+    method public void sendTimestamp(android.os.IBinder, long) throws java.lang.RuntimeException;
+    field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.tv.remoteprovider.TvRemoteProvider";
+  }
+
+}
+
diff --git a/media/lib/tvremote/api/removed.txt b/media/lib/tvremote/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/removed.txt
diff --git a/media/lib/tvremote/api/system-current.txt b/media/lib/tvremote/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/system-current.txt
diff --git a/media/lib/tvremote/api/system-removed.txt b/media/lib/tvremote/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/system-removed.txt
diff --git a/media/lib/tvremote/api/test-current.txt b/media/lib/tvremote/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/test-current.txt
diff --git a/media/lib/tvremote/api/test-removed.txt b/media/lib/tvremote/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/test-removed.txt
diff --git a/media/lib/tvremote/com.android.media.tv.remoteprovider.xml b/media/lib/tvremote/com.android.media.tv.remoteprovider.xml
deleted file mode 100644
index dcf479a..0000000
--- a/media/lib/tvremote/com.android.media.tv.remoteprovider.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<permissions>
-    <library name="com.android.media.tv.remoteprovider"
-        file="/system/framework/com.android.media.tv.remoteprovider.jar" />
-</permissions>
\ No newline at end of file
diff --git a/obex/Android.bp b/obex/Android.bp
new file mode 100644
index 0000000..6558eb3
--- /dev/null
+++ b/obex/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_sdk_library {
+    name: "javax.obex",
+    srcs: ["javax/**/*.java"],
+    api_packages: ["javax.obex"],
+}
diff --git a/obex/Android.mk b/obex/Android.mk
deleted file mode 100644
index e7c1fd3..0000000
--- a/obex/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obex
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obexstatic
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/obex/CleanSpec.mk b/obex/CleanSpec.mk
new file mode 100644
index 0000000..c104234
--- /dev/null
+++ b/obex/CleanSpec.mk
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+# runtime lib is renamed from javax.obex.jar to javax.obex.impl.jar
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/javax.obex.jar)
diff --git a/obex/api/current.txt b/obex/api/current.txt
new file mode 100644
index 0000000..1cd562f
--- /dev/null
+++ b/obex/api/current.txt
@@ -0,0 +1,12 @@
+package javax.obex {
+
+  public class ObexPacket {
+    method public static javax.obex.ObexPacket read(java.io.InputStream) throws java.io.IOException;
+    method public static javax.obex.ObexPacket read(int, java.io.InputStream) throws java.io.IOException;
+    field public int mHeaderId;
+    field public int mLength;
+    field public byte[] mPayload;
+  }
+
+}
+
diff --git a/obex/api/removed.txt b/obex/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/removed.txt
diff --git a/obex/api/system-current.txt b/obex/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-current.txt
diff --git a/obex/api/system-removed.txt b/obex/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-removed.txt
diff --git a/obex/api/test-current.txt b/obex/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-current.txt
diff --git a/obex/api/test-removed.txt b/obex/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-removed.txt
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index e01e95b..9ecaa03 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -23,8 +23,10 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
 
-    <application android:label="@string/app_name" >
+    <application android:label="@string/app_name"
+                 android:usesCleartextTraffic="true">
         <activity
             android:name="com.android.captiveportallogin.CaptivePortalLoginActivity"
             android:label="@string/action_bar_label"
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 495d889..3630005 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -29,17 +29,18 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.Proxy;
 import android.net.Uri;
 import android.net.captiveportal.CaptivePortalProbeSpec;
 import android.net.dns.ResolvUtil;
 import android.net.http.SslError;
+import android.net.wifi.WifiInfo;
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.support.v4.widget.SwipeRefreshLayout;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.TypedValue;
@@ -556,15 +557,12 @@
     }
 
     private String getHeaderTitle() {
-        NetworkInfo info = mCm.getNetworkInfo(mNetwork);
-        if (info == null) {
-            return getString(R.string.action_bar_label);
-        }
         NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
-        if (!nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+        if (nc == null || TextUtils.isEmpty(nc.getSSID())
+            || !nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
             return getString(R.string.action_bar_label);
         }
-        return getString(R.string.action_bar_title, info.getExtraInfo().replaceAll("^\"|\"$", ""));
+        return getString(R.string.action_bar_title, WifiInfo.removeDoubleQuotes(nc.getSSID()));
     }
 
     private String getHeaderSubtitle(URL url) {
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 425df71..4d9aaec 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -30,7 +30,8 @@
 
     <application
         android:label="@string/app_name"
-        android:directBootAware="true">
+        android:directBootAware="true"
+        android:usesCleartextTraffic="true">
         <receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
             <intent-filter>
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 6186a78..e645adc 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -66,10 +66,11 @@
 LOCAL_MULTILIB := both
 LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
@@ -111,10 +112,11 @@
 
 LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index fd7c87e..c9f9972 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -21,6 +21,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_MIN_SDK_VERSION := 21
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # For the test package.
diff --git a/services/core/java/com/android/server/CommonTimeManagementService.java b/services/core/java/com/android/server/CommonTimeManagementService.java
deleted file mode 100644
index 5cebfa5..0000000
--- a/services/core/java/com/android/server/CommonTimeManagementService.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.INetworkManagementEventObserver;
-import android.net.InterfaceConfiguration;
-import android.os.Binder;
-import android.os.CommonTimeConfig;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.util.Log;
-
-import com.android.internal.util.DumpUtils;
-import com.android.server.net.BaseNetworkObserver;
-
-/**
- * @hide
- * <p>CommonTimeManagementService manages the configuration of the native Common Time service,
- * reconfiguring the native service as appropriate in response to changes in network configuration.
- */
-class CommonTimeManagementService extends Binder {
-    /*
-     * Constants and globals.
-     */
-    private static final String TAG = CommonTimeManagementService.class.getSimpleName();
-    private static final int NATIVE_SERVICE_RECONNECT_TIMEOUT = 5000;
-    private static final String AUTO_DISABLE_PROP = "ro.common_time.auto_disable";
-    private static final String ALLOW_WIFI_PROP = "ro.common_time.allow_wifi";
-    private static final String SERVER_PRIO_PROP = "ro.common_time.server_prio";
-    private static final String NO_INTERFACE_TIMEOUT_PROP = "ro.common_time.no_iface_timeout";
-    private static final boolean AUTO_DISABLE;
-    private static final boolean ALLOW_WIFI;
-    private static final byte BASE_SERVER_PRIO;
-    private static final int NO_INTERFACE_TIMEOUT;
-    private static final InterfaceScoreRule[] IFACE_SCORE_RULES;
-
-    static {
-        int tmp;
-        AUTO_DISABLE         = (0 != SystemProperties.getInt(AUTO_DISABLE_PROP, 1));
-        ALLOW_WIFI           = (0 != SystemProperties.getInt(ALLOW_WIFI_PROP, 0));
-        tmp                  = SystemProperties.getInt(SERVER_PRIO_PROP, 1);
-        NO_INTERFACE_TIMEOUT = SystemProperties.getInt(NO_INTERFACE_TIMEOUT_PROP, 60000);
-
-        if (tmp < 1)
-            BASE_SERVER_PRIO = 1;
-        else
-        if (tmp > 30)
-            BASE_SERVER_PRIO = 30;
-        else
-            BASE_SERVER_PRIO = (byte)tmp;
-
-        if (ALLOW_WIFI) {
-            IFACE_SCORE_RULES = new InterfaceScoreRule[] {
-                new InterfaceScoreRule("wlan", (byte)1),
-                new InterfaceScoreRule("eth", (byte)2),
-            };
-        } else {
-            IFACE_SCORE_RULES = new InterfaceScoreRule[] {
-                new InterfaceScoreRule("eth", (byte)2),
-            };
-        }
-    };
-
-    /*
-     * Internal state
-     */
-    private final Context mContext;
-    private final Object mLock = new Object();
-    private INetworkManagementService mNetMgr;
-    private CommonTimeConfig mCTConfig;
-    private String mCurIface;
-    private Handler mReconnectHandler = new Handler();
-    private Handler mNoInterfaceHandler = new Handler();
-    private boolean mDetectedAtStartup = false;
-    private byte mEffectivePrio = BASE_SERVER_PRIO;
-
-    /*
-     * Callback handler implementations.
-     */
-    private INetworkManagementEventObserver mIfaceObserver = new BaseNetworkObserver() {
-        @Override
-        public void interfaceStatusChanged(String iface, boolean up) {
-            reevaluateServiceState();
-        }
-        @Override
-        public void interfaceLinkStateChanged(String iface, boolean up) {
-            reevaluateServiceState();
-        }
-        @Override
-        public void interfaceAdded(String iface) {
-            reevaluateServiceState();
-        }
-        @Override
-        public void interfaceRemoved(String iface) {
-            reevaluateServiceState();
-        }
-    };
-
-    private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            reevaluateServiceState();
-        }
-    };
-
-    private CommonTimeConfig.OnServerDiedListener mCTServerDiedListener =
-            () -> scheduleTimeConfigReconnect();
-
-    private Runnable mReconnectRunnable = () -> connectToTimeConfig();
-
-    private Runnable mNoInterfaceRunnable = () -> handleNoInterfaceTimeout();
-
-    /*
-     * Public interface (constructor, systemReady and dump)
-     */
-    public CommonTimeManagementService(Context context) {
-        mContext = context;
-    }
-
-    void systemRunning() {
-        if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) {
-            Log.i(TAG, "No common time service detected on this platform.  " +
-                       "Common time services will be unavailable.");
-            return;
-        }
-
-        mDetectedAtStartup = true;
-
-        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-        mNetMgr = INetworkManagementService.Stub.asInterface(b);
-
-        // Network manager is running along-side us, so we should never receiver a remote exception
-        // while trying to register this observer.
-        try {
-            mNetMgr.registerObserver(mIfaceObserver);
-        }
-        catch (RemoteException e) { }
-
-        // Register with the connectivity manager for connectivity changed intents.
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        mContext.registerReceiver(mConnectivityMangerObserver, filter);
-
-        // Connect to the common time config service and apply the initial configuration.
-        connectToTimeConfig();
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-
-        if (!mDetectedAtStartup) {
-            pw.println("Native Common Time service was not detected at startup.  " +
-                       "Service is unavailable");
-            return;
-        }
-
-        synchronized (mLock) {
-            pw.println("Current Common Time Management Service Config:");
-            pw.println(String.format("  Native service     : %s",
-                                     (null == mCTConfig) ? "reconnecting"
-                                                         : "alive"));
-            pw.println(String.format("  Bound interface    : %s",
-                                     (null == mCurIface ? "unbound" : mCurIface)));
-            pw.println(String.format("  Allow WiFi         : %s", ALLOW_WIFI ? "yes" : "no"));
-            pw.println(String.format("  Allow Auto Disable : %s", AUTO_DISABLE ? "yes" : "no"));
-            pw.println(String.format("  Server Priority    : %d", mEffectivePrio));
-            pw.println(String.format("  No iface timeout   : %d", NO_INTERFACE_TIMEOUT));
-        }
-    }
-
-    /*
-     * Inner helper classes
-     */
-    private static class InterfaceScoreRule {
-        public final String mPrefix;
-        public final byte mScore;
-        public InterfaceScoreRule(String prefix, byte score) {
-            mPrefix = prefix;
-            mScore = score;
-        }
-    };
-
-    /*
-     * Internal implementation
-     */
-    private void cleanupTimeConfig() {
-        mReconnectHandler.removeCallbacks(mReconnectRunnable);
-        mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
-        if (null != mCTConfig) {
-            mCTConfig.release();
-            mCTConfig = null;
-        }
-    }
-
-    private void connectToTimeConfig() {
-        // Get access to the common time service configuration interface.  If we catch a remote
-        // exception in the process (service crashed or no running for w/e reason), schedule an
-        // attempt to reconnect in the future.
-        cleanupTimeConfig();
-        try {
-            synchronized (mLock) {
-                mCTConfig = new CommonTimeConfig();
-                mCTConfig.setServerDiedListener(mCTServerDiedListener);
-                mCurIface = mCTConfig.getInterfaceBinding();
-                mCTConfig.setAutoDisable(AUTO_DISABLE);
-                mCTConfig.setMasterElectionPriority(mEffectivePrio);
-            }
-
-            if (NO_INTERFACE_TIMEOUT >= 0)
-                mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
-
-            reevaluateServiceState();
-        }
-        catch (RemoteException e) {
-            scheduleTimeConfigReconnect();
-        }
-    }
-
-    private void scheduleTimeConfigReconnect() {
-        cleanupTimeConfig();
-        Log.w(TAG, String.format("Native service died, will reconnect in %d mSec",
-                                 NATIVE_SERVICE_RECONNECT_TIMEOUT));
-        mReconnectHandler.postDelayed(mReconnectRunnable,
-                                      NATIVE_SERVICE_RECONNECT_TIMEOUT);
-    }
-
-    private void handleNoInterfaceTimeout() {
-        if (null != mCTConfig) {
-            Log.i(TAG, "Timeout waiting for interface to come up.  " +
-                       "Forcing networkless master mode.");
-            if (CommonTimeConfig.ERROR_DEAD_OBJECT == mCTConfig.forceNetworklessMasterMode())
-                scheduleTimeConfigReconnect();
-        }
-    }
-
-    private void reevaluateServiceState() {
-        String bindIface = null;
-        byte bestScore = -1;
-        try {
-            // Check to see if this interface is suitable to use for time synchronization.
-            //
-            // TODO : This selection algorithm needs to be enhanced for use with mobile devices.  In
-            // particular, the choice of whether to a wireless interface or not should not be an all
-            // or nothing thing controlled by properties.  It would probably be better if the
-            // platform had some concept of public wireless networks vs. home or friendly wireless
-            // networks (something a user would configure in settings or when a new interface is
-            // added).  Then this algorithm could pick only wireless interfaces which were flagged
-            // as friendly, and be dormant when on public wireless networks.
-            //
-            // Another issue which needs to be dealt with is the use of driver supplied interface
-            // name to determine the network type.  The fact that the wireless interface on a device
-            // is named "wlan0" is just a matter of convention; its not a 100% rule.  For example,
-            // there are devices out there where the wireless is name "tiwlan0", not "wlan0".  The
-            // internal network management interfaces in Android have all of the information needed
-            // to make a proper classification, there is just no way (currently) to fetch an
-            // interface's type (available from the ConnectionManager) as well as its address
-            // (available from either the java.net interfaces or from the NetworkManagment service).
-            // Both can enumerate interfaces, but that is no way to correlate their results (no
-            // common shared key; although using the interface name in the connection manager would
-            // be a good start).  Until this gets resolved, we resort to substring searching for
-            // tags like wlan and eth.
-            //
-            String ifaceList[] = mNetMgr.listInterfaces();
-            if (null != ifaceList) {
-                for (String iface : ifaceList) {
-
-                    byte thisScore = -1;
-                    for (InterfaceScoreRule r : IFACE_SCORE_RULES) {
-                        if (iface.contains(r.mPrefix)) {
-                            thisScore = r.mScore;
-                            break;
-                        }
-                    }
-
-                    if (thisScore <= bestScore)
-                        continue;
-
-                    InterfaceConfiguration config = mNetMgr.getInterfaceConfig(iface);
-                    if (null == config)
-                        continue;
-
-                    if (config.isActive()) {
-                        bindIface = iface;
-                        bestScore = thisScore;
-                    }
-                }
-            }
-        }
-        catch (RemoteException e) {
-            // Bad news; we should not be getting remote exceptions from the connectivity manager
-            // since it is running in SystemServer along side of us.  It probably does not matter
-            // what we do here, but go ahead and unbind the common time service in this case, just
-            // so we have some defined behavior.
-            bindIface = null;
-        }
-
-        boolean doRebind = true;
-        synchronized (mLock) {
-            if ((null != bindIface) && (null == mCurIface)) {
-                Log.e(TAG, String.format("Binding common time service to %s.", bindIface));
-                mCurIface = bindIface;
-            } else
-            if ((null == bindIface) && (null != mCurIface)) {
-                Log.e(TAG, "Unbinding common time service.");
-                mCurIface = null;
-            } else
-            if ((null != bindIface) && (null != mCurIface) && !bindIface.equals(mCurIface)) {
-                Log.e(TAG, String.format("Switching common time service binding from %s to %s.",
-                                         mCurIface, bindIface));
-                mCurIface = bindIface;
-            } else {
-                doRebind = false;
-            }
-        }
-
-        if (doRebind && (null != mCTConfig)) {
-            byte newPrio = (bestScore > 0)
-                         ? (byte)(bestScore * BASE_SERVER_PRIO)
-                         : BASE_SERVER_PRIO;
-            if (newPrio != mEffectivePrio) {
-                mEffectivePrio = newPrio;
-                mCTConfig.setMasterElectionPriority(mEffectivePrio);
-            }
-
-            int res = mCTConfig.setNetworkBinding(mCurIface);
-            if (res != CommonTimeConfig.SUCCESS)
-                scheduleTimeConfigReconnect();
-
-            else if (NO_INTERFACE_TIMEOUT >= 0) {
-                mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
-                if (null == mCurIface)
-                    mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9838de1..0b24db0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -102,6 +102,8 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -125,7 +127,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
 import com.android.internal.net.VpnProfile;
@@ -152,6 +153,7 @@
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.PermissionMonitor;
+import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.connectivity.tethering.TetheringDependencies;
@@ -194,14 +196,13 @@
         implements PendingIntent.OnFinished {
     private static final String TAG = ConnectivityService.class.getSimpleName();
 
-    public static final String DIAG_ARG = "--diag";
+    private static final String DIAG_ARG = "--diag";
     public static final String SHORT_ARG = "--short";
-    public static final String TETHERING_ARG = "tethering";
+    private static final String TETHERING_ARG = "tethering";
 
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    private static final boolean LOGD_RULES = false;
     private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
 
     // TODO: create better separation between radio types and network types
@@ -234,8 +235,9 @@
 
     private KeyStore mKeyStore;
 
+    @VisibleForTesting
     @GuardedBy("mVpns")
-    private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
+    protected final SparseArray<Vpn> mVpns = new SparseArray<>();
 
     // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
     // a direct call to LockdownVpnTracker.isEnabled().
@@ -245,24 +247,16 @@
     private LockdownVpnTracker mLockdownTracker;
 
     final private Context mContext;
-    private int mNetworkPreference;
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
-    private boolean mTestMode;
-    private static ConnectivityService sServiceInstance;
-
     private INetworkManagementService mNetd;
     private INetworkStatsService mStatsService;
     private INetworkPolicyManager mPolicyManager;
     private NetworkPolicyManagerInternal mPolicyManagerInternal;
-    private IIpConnectivityMetrics mIpConnectivityMetrics;
 
     private String mCurrentTcpBufferSizes;
 
-    private static final int ENABLED  = 1;
-    private static final int DISABLED = 0;
-
     private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
             new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class,
                     NetworkAgentInfo.class });
@@ -275,7 +269,7 @@
         // Don't reap networks.  This should be passed when some networks have not yet been
         // rematched against all NetworkRequests.
         DONT_REAP
-    };
+    }
 
     private enum UnneededFor {
         LINGER,    // Determine whether this network is unneeded and should be lingered.
@@ -283,11 +277,6 @@
     }
 
     /**
-     * used internally to change our mobile data enabled flag
-     */
-    private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
-
-    /**
      * used internally to clear a wakelock when transitioning
      * from one net to another.  Clear happens when we get a new
      * network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
@@ -438,29 +427,21 @@
     private int mNetTransitionWakeLockTimeout;
     private final PowerManager.WakeLock mPendingIntentWakeLock;
 
-    // track the current default http proxy - tell the world if we get a new one (real change)
-    private volatile ProxyInfo mDefaultProxy = null;
-    private Object mProxyLock = new Object();
-    private boolean mDefaultProxyDisabled = false;
-
-    // track the global proxy.
-    private ProxyInfo mGlobalProxy = null;
-
-    private PacManager mPacManager = null;
+    // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
+    // the world when it changes.
+    private final ProxyTracker mProxyTracker;
 
     final private SettingsObserver mSettingsObserver;
 
     private UserManager mUserManager;
 
-    NetworkConfig[] mNetConfigs;
-    int mNetworksDefined;
+    private NetworkConfig[] mNetConfigs;
+    private int mNetworksDefined;
 
     // the set of network types that can only be enabled by system/sig apps
-    List mProtectedNetworks;
+    private List mProtectedNetworks;
 
-    private DataConnectionStats mDataConnectionStats;
-
-    TelephonyManager mTelephonyManager;
+    private TelephonyManager mTelephonyManager;
 
     private KeepaliveTracker mKeepaliveTracker;
     private NetworkNotificationManager mNotifier;
@@ -494,24 +475,23 @@
     private static final int MAX_VALIDATION_LOGS = 10;
     private static class ValidationLog {
         final Network mNetwork;
-        final String mNetworkExtraInfo;
+        final String mName;
         final ReadOnlyLocalLog mLog;
 
-        ValidationLog(Network network, String networkExtraInfo, ReadOnlyLocalLog log) {
+        ValidationLog(Network network, String name, ReadOnlyLocalLog log) {
             mNetwork = network;
-            mNetworkExtraInfo = networkExtraInfo;
+            mName = name;
             mLog = log;
         }
     }
-    private final ArrayDeque<ValidationLog> mValidationLogs =
-            new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS);
+    private final ArrayDeque<ValidationLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
 
-    private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) {
+    private void addValidationLogs(ReadOnlyLocalLog log, Network network, String name) {
         synchronized (mValidationLogs) {
             while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
                 mValidationLogs.removeLast();
             }
-            mValidationLogs.addFirst(new ValidationLog(network, networkExtraInfo, log));
+            mValidationLogs.addFirst(new ValidationLog(network, name, log));
         }
     }
 
@@ -574,7 +554,7 @@
                 throw new IllegalStateException(
                         "legacy list for type " + type + "already initialized");
             }
-            mTypeLists[type] = new ArrayList<NetworkAgentInfo>();
+            mTypeLists[type] = new ArrayList<>();
         }
 
         public boolean isTypeSupported(int type) {
@@ -677,7 +657,7 @@
         }
 
         private String naiToString(NetworkAgentInfo nai) {
-            String name = (nai != null) ? nai.name() : "null";
+            String name = nai.name();
             String state = (nai.networkInfo != null) ?
                     nai.networkInfo.getState() + "/" + nai.networkInfo.getDetailedState() :
                     "???/???";
@@ -748,6 +728,7 @@
         mPolicyManagerInternal = checkNotNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
+        mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED);
 
         mKeyStore = KeyStore.getInstance();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -829,9 +810,6 @@
             }
         }
 
-        mTestMode = mSystemProperties.get("cm.test.mode").equals("true")
-                && mSystemProperties.get("ro.build.type").equals("eng");
-
         mTethering = makeTethering();
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -858,10 +836,8 @@
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
 
-        mDataConnectionStats = new DataConnectionStats(mContext);
-        mDataConnectionStats.startMonitoring();
-
-        mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
+        final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext);
+        dataConnectionStats.startMonitoring();
 
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
@@ -892,15 +868,28 @@
             public boolean isTetheringSupported() {
                 return ConnectivityService.this.isTetheringSupported();
             }
+            @Override
+            public NetworkRequest getDefaultNetworkRequest() {
+                return mDefaultRequest;
+            }
         };
         return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
                 IoThread.get().getLooper(), new MockableSystemProperties(),
                 deps);
     }
 
+    private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
+        final NetworkCapabilities netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
+        netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
+        netCap.setSingleUid(uid);
+        return netCap;
+    }
+
     private NetworkRequest createDefaultInternetRequestForTransport(
             int transportType, NetworkRequest.Type type) {
-        NetworkCapabilities netCap = new NetworkCapabilities();
+        final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
         netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
         if (transportType > -1) {
@@ -980,7 +969,7 @@
         throw new IllegalStateException("No free netIds");
     }
 
-    private NetworkState getFilteredNetworkState(int networkType, int uid, boolean ignoreBlocked) {
+    private NetworkState getFilteredNetworkState(int networkType, int uid) {
         if (mLegacyTypeTracker.isTypeSupported(networkType)) {
             final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
             final NetworkState state;
@@ -998,14 +987,15 @@
                 state = new NetworkState(info, new LinkProperties(), capabilities,
                         null, null, null);
             }
-            filterNetworkStateForUid(state, uid, ignoreBlocked);
+            filterNetworkStateForUid(state, uid, false);
             return state;
         } else {
             return NetworkState.EMPTY;
         }
     }
 
-    private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
+    @VisibleForTesting
+    protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
         if (network == null) {
             return null;
         }
@@ -1150,12 +1140,20 @@
         int vpnNetId = NETID_UNSET;
         synchronized (mVpns) {
             final Vpn vpn = mVpns.get(user);
+            // TODO : now that capabilities contain the UID, the appliesToUid test should
+            // be removed as the satisfying test below should be enough.
             if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId();
         }
         NetworkAgentInfo nai;
         if (vpnNetId != NETID_UNSET) {
             nai = getNetworkAgentInfoForNetId(vpnNetId);
-            if (nai != null) return nai.network;
+            if (nai != null) {
+                final NetworkCapabilities requiredCaps =
+                    createDefaultNetworkCapabilitiesForUid(uid);
+                if (requiredCaps.satisfiedByNetworkCapabilities(nai.networkCapabilities)) {
+                    return nai.network;
+                }
+            }
         }
         nai = getDefaultNetwork();
         if (nai != null
@@ -1195,7 +1193,7 @@
                 return state.networkInfo;
             }
         }
-        final NetworkState state = getFilteredNetworkState(networkType, uid, false);
+        final NetworkState state = getFilteredNetworkState(networkType, uid);
         return state.networkInfo;
     }
 
@@ -1230,7 +1228,7 @@
     public Network getNetworkForType(int networkType) {
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
-        NetworkState state = getFilteredNetworkState(networkType, uid, false);
+        NetworkState state = getFilteredNetworkState(networkType, uid);
         if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) {
             return state.network;
         }
@@ -1267,7 +1265,7 @@
         // default.
         enforceAccessPermission();
 
-        HashMap<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
+        HashMap<Network, NetworkCapabilities> result = new HashMap<>();
 
         NetworkAgentInfo nai = getDefaultNetwork();
         NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
@@ -1352,7 +1350,8 @@
         if (nai != null) {
             synchronized (nai) {
                 if (nai.networkCapabilities != null) {
-                    return networkCapabilitiesWithoutUidsUnlessAllowed(nai.networkCapabilities,
+                    return networkCapabilitiesRestrictedForCallerPermissions(
+                            nai.networkCapabilities,
                             Binder.getCallingPid(), Binder.getCallingUid());
                 }
             }
@@ -1366,10 +1365,14 @@
         return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
     }
 
-    private NetworkCapabilities networkCapabilitiesWithoutUidsUnlessAllowed(
+    private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
             NetworkCapabilities nc, int callerPid, int callerUid) {
-        if (checkSettingsPermission(callerPid, callerUid)) return new NetworkCapabilities(nc);
-        return new NetworkCapabilities(nc).setUids(null);
+        final NetworkCapabilities newNc = new NetworkCapabilities(nc);
+        if (!checkSettingsPermission(callerPid, callerUid)) {
+            newNc.setUids(null);
+            newNc.setSSID(null);
+        }
+        return newNc;
     }
 
     private void restrictRequestUidsForCaller(NetworkCapabilities nc) {
@@ -1415,7 +1418,8 @@
     public boolean isActiveNetworkMetered() {
         enforceAccessPermission();
 
-        final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+        final int uid = Binder.getCallingUid();
+        final NetworkCapabilities caps = getUnfilteredActiveNetworkState(uid).networkCapabilities;
         if (caps != null) {
             return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         } else {
@@ -1548,15 +1552,16 @@
 
     @VisibleForTesting
     protected void registerNetdEventCallback() {
-        mIpConnectivityMetrics =
-                (IIpConnectivityMetrics) IIpConnectivityMetrics.Stub.asInterface(
-                ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
-        if (mIpConnectivityMetrics == null) {
+        final IIpConnectivityMetrics ipConnectivityMetrics =
+                IIpConnectivityMetrics.Stub.asInterface(
+                        ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+        if (ipConnectivityMetrics == null) {
             Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
+            return;
         }
 
         try {
-            mIpConnectivityMetrics.addNetdEventCallback(
+            ipConnectivityMetrics.addNetdEventCallback(
                     INetdEventCallback.CALLBACK_CALLER_CONNECTIVITY_SERVICE,
                     mNetdEventCallback);
         } catch (Exception e) {
@@ -1734,9 +1739,10 @@
                 try {
                     bs.noteConnectivityChanged(intent.getIntExtra(
                             ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
-                            ni != null ? ni.getState().toString() : "?");
+                            ni.getState().toString());
                 } catch (RemoteException e) {
                 }
+                intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
             }
             try {
                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options);
@@ -1821,7 +1827,7 @@
         if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                               caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
             try {
-                // the call fails silently if no idletimer setup for this interface
+                // the call fails silently if no idle timer setup for this interface
                 mNetd.removeIdleTimer(iface);
             } catch (Exception e) {
                 loge("Exception in removeDataActivityTracking " + e);
@@ -1830,7 +1836,7 @@
     }
 
     /**
-     * Reads the network specific MTU size from reources.
+     * Reads the network specific MTU size from resources.
      * and set it on it's iface.
      */
     private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
@@ -2032,7 +2038,7 @@
             synchronized (mValidationLogs) {
                 pw.println("mValidationLogs (most recent first):");
                 for (ValidationLog p : mValidationLogs) {
-                    pw.println(p.mNetwork + " - " + p.mNetworkExtraInfo);
+                    pw.println(p.mNetwork + " - " + p.mName);
                     pw.increaseIndent();
                     p.mLog.dump(fd, pw, args);
                     pw.decreaseIndent();
@@ -2377,94 +2383,107 @@
         }
     }
 
+    // This is a no-op if it's called with a message designating a network that has
+    // already been destroyed, because its reference will not be found in the relevant
+    // maps.
     private void handleAsyncChannelDisconnected(Message msg) {
         NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
         if (nai != null) {
-            if (DBG) {
-                log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
-            }
-            // A network agent has disconnected.
-            // TODO - if we move the logic to the network agent (have them disconnect
-            // because they lost all their requests or because their score isn't good)
-            // then they would disconnect organically, report their new state and then
-            // disconnect the channel.
-            if (nai.networkInfo.isConnected()) {
-                nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
-                        null, null);
-            }
-            final boolean wasDefault = isDefaultNetwork(nai);
-            if (wasDefault) {
-                mDefaultInetConditionPublished = 0;
-                // Log default network disconnection before required book-keeping.
-                // Let rematchAllNetworksAndRequests() below record a new default network event
-                // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
-                // whose timestamps tell how long it takes to recover a default network.
-                long now = SystemClock.elapsedRealtime();
-                metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
-            }
-            notifyIfacesChangedForNetworkStats();
-            // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
-            // by other networks that are already connected. Perhaps that can be done by
-            // sending all CALLBACK_LOST messages (for requests, not listens) at the end
-            // of rematchAllNetworksAndRequests
-            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
-            mKeepaliveTracker.handleStopAllKeepalives(nai,
-                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
-            for (String iface : nai.linkProperties.getAllInterfaceNames()) {
-                // Disable wakeup packet monitoring for each interface.
-                wakeupModifyInterface(iface, nai.networkCapabilities, false);
-            }
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
-            mNetworkAgentInfos.remove(msg.replyTo);
-            nai.maybeStopClat();
-            synchronized (mNetworkForNetId) {
-                // Remove the NetworkAgent, but don't mark the netId as
-                // available until we've told netd to delete it below.
-                mNetworkForNetId.remove(nai.network.netId);
-            }
-            // Remove all previously satisfied requests.
-            for (int i = 0; i < nai.numNetworkRequests(); i++) {
-                NetworkRequest request = nai.requestAt(i);
-                NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
-                if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
-                    clearNetworkForRequest(request.requestId);
-                    sendUpdatedScoreToFactories(request, 0);
-                }
-            }
-            nai.clearLingerState();
-            if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
-                removeDataActivityTracking(nai);
-                notifyLockdownVpn(nai);
-                ensureNetworkTransitionWakelock(nai.name());
-            }
-            mLegacyTypeTracker.remove(nai, wasDefault);
-            rematchAllNetworksAndRequests(null, 0);
-            mLingerMonitor.noteDisconnect(nai);
-            if (nai.created) {
-                // Tell netd to clean up the configuration for this network
-                // (routing rules, DNS, etc).
-                // This may be slow as it requires a lot of netd shelling out to ip and
-                // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
-                // after we've rematched networks with requests which should make a potential
-                // fallback network the default or requested a new network from the
-                // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
-                // long time.
-                try {
-                    mNetd.removeNetwork(nai.network.netId);
-                } catch (Exception e) {
-                    loge("Exception removing network: " + e);
-                }
-                mDnsManager.removeNetwork(nai.network);
-            }
-            synchronized (mNetworkForNetId) {
-                mNetIdInUse.delete(nai.network.netId);
-            }
+            disconnectAndDestroyNetwork(nai);
         } else {
             NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo);
             if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name);
         }
     }
 
+    // Destroys a network, remove references to it from the internal state managed by
+    // ConnectivityService, free its interfaces and clean up.
+    // Must be called on the Handler thread.
+    private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
+        if (DBG) {
+            log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
+        }
+        // A network agent has disconnected.
+        // TODO - if we move the logic to the network agent (have them disconnect
+        // because they lost all their requests or because their score isn't good)
+        // then they would disconnect organically, report their new state and then
+        // disconnect the channel.
+        if (nai.networkInfo.isConnected()) {
+            nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
+                    null, null);
+        }
+        final boolean wasDefault = isDefaultNetwork(nai);
+        if (wasDefault) {
+            mDefaultInetConditionPublished = 0;
+            // Log default network disconnection before required book-keeping.
+            // Let rematchAllNetworksAndRequests() below record a new default network event
+            // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
+            // whose timestamps tell how long it takes to recover a default network.
+            long now = SystemClock.elapsedRealtime();
+            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
+        }
+        notifyIfacesChangedForNetworkStats();
+        // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
+        // by other networks that are already connected. Perhaps that can be done by
+        // sending all CALLBACK_LOST messages (for requests, not listens) at the end
+        // of rematchAllNetworksAndRequests
+        notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
+        mKeepaliveTracker.handleStopAllKeepalives(nai,
+                ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+        for (String iface : nai.linkProperties.getAllInterfaceNames()) {
+            // Disable wakeup packet monitoring for each interface.
+            wakeupModifyInterface(iface, nai.networkCapabilities, false);
+        }
+        nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+        mNetworkAgentInfos.remove(nai.messenger);
+        nai.maybeStopClat();
+        synchronized (mNetworkForNetId) {
+            // Remove the NetworkAgent, but don't mark the netId as
+            // available until we've told netd to delete it below.
+            mNetworkForNetId.remove(nai.network.netId);
+        }
+        // Remove all previously satisfied requests.
+        for (int i = 0; i < nai.numNetworkRequests(); i++) {
+            NetworkRequest request = nai.requestAt(i);
+            NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
+            if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+                clearNetworkForRequest(request.requestId);
+                sendUpdatedScoreToFactories(request, 0);
+            }
+        }
+        nai.clearLingerState();
+        if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
+            removeDataActivityTracking(nai);
+            notifyLockdownVpn(nai);
+            ensureNetworkTransitionWakelock(nai.name());
+        }
+        mLegacyTypeTracker.remove(nai, wasDefault);
+        if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+            updateAllVpnsCapabilities();
+        }
+        rematchAllNetworksAndRequests(null, 0);
+        mLingerMonitor.noteDisconnect(nai);
+        if (nai.created) {
+            // Tell netd to clean up the configuration for this network
+            // (routing rules, DNS, etc).
+            // This may be slow as it requires a lot of netd shelling out to ip and
+            // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
+            // after we've rematched networks with requests which should make a potential
+            // fallback network the default or requested a new network from the
+            // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
+            // long time.
+            try {
+                mNetd.removeNetwork(nai.network.netId);
+            } catch (Exception e) {
+                loge("Exception removing network: " + e);
+            }
+            mDnsManager.removeNetwork(nai.network);
+        }
+        synchronized (mNetworkForNetId) {
+            mNetIdInUse.delete(nai.network.netId);
+        }
+    }
+
     // If this method proves to be too slow then we can maintain a separate
     // pendingIntent => NetworkRequestInfo map.
     // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
@@ -2755,7 +2774,7 @@
         if (!accept) {
             // Tell the NetworkAgent to not automatically reconnect to the network.
             nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
-            // Teardown the nework.
+            // Teardown the network.
             teardownUnneededNetwork(nai);
         }
 
@@ -3017,8 +3036,7 @@
     public int tether(String iface, String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         if (isTetheringSupported()) {
-            final int status = mTethering.tether(iface);
-            return status;
+            return mTethering.tether(iface);
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -3030,8 +3048,7 @@
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
 
         if (isTetheringSupported()) {
-            final int status = mTethering.untether(iface);
-            return status;
+            return mTethering.untether(iface);
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -3263,22 +3280,10 @@
         nai.networkMonitor.forceReevaluation(uid);
     }
 
-    private ProxyInfo getDefaultProxy() {
-        // this information is already available as a world read/writable jvm property
-        // so this API change wouldn't have a benifit.  It also breaks the passing
-        // of proxy info to all the JVMs.
-        // enforceAccessPermission();
-        synchronized (mProxyLock) {
-            ProxyInfo ret = mGlobalProxy;
-            if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
-            return ret;
-        }
-    }
-
     @Override
     public ProxyInfo getProxyForNetwork(Network network) {
-        if (network == null) return getDefaultProxy();
-        final ProxyInfo globalProxy = getGlobalProxy();
+        if (network == null) return mProxyTracker.getDefaultProxy();
+        final ProxyInfo globalProxy = mProxyTracker.getGlobalProxy();
         if (globalProxy != null) return globalProxy;
         if (!NetworkUtils.queryUserAccess(Binder.getCallingUid(), network.netId)) return null;
         // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
@@ -3292,80 +3297,10 @@
         }
     }
 
-    // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
-    // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
-    // proxy is null then there is no proxy in place).
-    private ProxyInfo canonicalizeProxyInfo(ProxyInfo proxy) {
-        if (proxy != null && TextUtils.isEmpty(proxy.getHost())
-                && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
-            proxy = null;
-        }
-        return proxy;
-    }
-
-    // ProxyInfo equality function with a couple modifications over ProxyInfo.equals() to make it
-    // better for determining if a new proxy broadcast is necessary:
-    // 1. Canonicalize empty ProxyInfos to null so an empty proxy compares equal to null so as to
-    //    avoid unnecessary broadcasts.
-    // 2. Make sure all parts of the ProxyInfo's compare true, including the host when a PAC URL
-    //    is in place.  This is important so legacy PAC resolver (see com.android.proxyhandler)
-    //    changes aren't missed.  The legacy PAC resolver pretends to be a simple HTTP proxy but
-    //    actually uses the PAC to resolve; this results in ProxyInfo's with PAC URL, host and port
-    //    all set.
-    private boolean proxyInfoEqual(ProxyInfo a, ProxyInfo b) {
-        a = canonicalizeProxyInfo(a);
-        b = canonicalizeProxyInfo(b);
-        // ProxyInfo.equals() doesn't check hosts when PAC URLs are present, but we need to check
-        // hosts even when PAC URLs are present to account for the legacy PAC resolver.
-        return Objects.equals(a, b) && (a == null || Objects.equals(a.getHost(), b.getHost()));
-    }
-
-    public void setGlobalProxy(ProxyInfo proxyProperties) {
+    @Override
+    public void setGlobalProxy(final ProxyInfo proxyProperties) {
         enforceConnectivityInternalPermission();
-
-        synchronized (mProxyLock) {
-            if (proxyProperties == mGlobalProxy) return;
-            if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
-            if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
-
-            String host = "";
-            int port = 0;
-            String exclList = "";
-            String pacFileUrl = "";
-            if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
-                    !Uri.EMPTY.equals(proxyProperties.getPacFileUrl()))) {
-                if (!proxyProperties.isValid()) {
-                    if (DBG)
-                        log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
-                    return;
-                }
-                mGlobalProxy = new ProxyInfo(proxyProperties);
-                host = mGlobalProxy.getHost();
-                port = mGlobalProxy.getPort();
-                exclList = mGlobalProxy.getExclusionListAsString();
-                if (!Uri.EMPTY.equals(proxyProperties.getPacFileUrl())) {
-                    pacFileUrl = proxyProperties.getPacFileUrl().toString();
-                }
-            } else {
-                mGlobalProxy = null;
-            }
-            ContentResolver res = mContext.getContentResolver();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
-                Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
-                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
-                        exclList);
-                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-
-            if (mGlobalProxy == null) {
-                proxyProperties = mDefaultProxy;
-            }
-            sendProxyBroadcast(proxyProperties);
-        }
+        mProxyTracker.setGlobalProxy(proxyProperties);
     }
 
     private void loadGlobalProxy() {
@@ -3387,20 +3322,16 @@
                 return;
             }
 
-            synchronized (mProxyLock) {
-                mGlobalProxy = proxyProperties;
+            synchronized (mProxyTracker.mProxyLock) {
+                mProxyTracker.mGlobalProxy = proxyProperties;
             }
         }
     }
 
+    @Override
+    @Nullable
     public ProxyInfo getGlobalProxy() {
-        // this information is already available as a world read/writable jvm property
-        // so this API change wouldn't have a benifit.  It also breaks the passing
-        // of proxy info to all the JVMs.
-        // enforceAccessPermission();
-        synchronized (mProxyLock) {
-            return mGlobalProxy;
-        }
+        return mProxyTracker.getGlobalProxy();
     }
 
     private void handleApplyDefaultProxy(ProxyInfo proxy) {
@@ -3408,33 +3339,7 @@
                 && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             proxy = null;
         }
-        synchronized (mProxyLock) {
-            if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
-            if (mDefaultProxy == proxy) return; // catches repeated nulls
-            if (proxy != null &&  !proxy.isValid()) {
-                if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
-                return;
-            }
-
-            // This call could be coming from the PacManager, containing the port of the local
-            // proxy.  If this new proxy matches the global proxy then copy this proxy to the
-            // global (to get the correct local port), and send a broadcast.
-            // TODO: Switch PacManager to have its own message to send back rather than
-            // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
-            if ((mGlobalProxy != null) && (proxy != null)
-                    && (!Uri.EMPTY.equals(proxy.getPacFileUrl()))
-                    && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
-                mGlobalProxy = proxy;
-                sendProxyBroadcast(mGlobalProxy);
-                return;
-            }
-            mDefaultProxy = proxy;
-
-            if (mGlobalProxy != null) return;
-            if (!mDefaultProxyDisabled) {
-                sendProxyBroadcast(proxy);
-            }
-        }
+        mProxyTracker.setDefaultProxy(proxy);
     }
 
     // If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy.
@@ -3442,17 +3347,17 @@
     // the default proxy (even if it hasn't changed).
     // TODO: Deprecate the broadcast extras as they aren't necessarily applicable in a multi-network
     // world where an app might be bound to a non-default network.
-    private void updateProxy(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo nai) {
+    private void updateProxy(LinkProperties newLp, LinkProperties oldLp) {
         ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
         ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
 
-        if (!proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
-            sendProxyBroadcast(getDefaultProxy());
+        if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
+            mProxyTracker.sendProxyBroadcast(mProxyTracker.getDefaultProxy());
         }
     }
 
     private void handleDeprecatedGlobalHttpProxy() {
-        String proxy = Settings.Global.getString(mContext.getContentResolver(),
+        final String proxy = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.HTTP_PROXY);
         if (!TextUtils.isEmpty(proxy)) {
             String data[] = proxy.split(":");
@@ -3460,7 +3365,7 @@
                 return;
             }
 
-            String proxyHost =  data[0];
+            final String proxyHost = data[0];
             int proxyPort = 8080;
             if (data.length > 1) {
                 try {
@@ -3469,27 +3374,11 @@
                     return;
                 }
             }
-            ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
+            final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
             setGlobalProxy(p);
         }
     }
 
-    private void sendProxyBroadcast(ProxyInfo proxy) {
-        if (proxy == null) proxy = new ProxyInfo("", 0, "");
-        if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
-        if (DBG) log("sending Proxy Broadcast for " + proxy);
-        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
-            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private static class SettingsObserver extends ContentObserver {
         final private HashMap<Uri, Integer> mUriEventMap;
         final private Context mContext;
@@ -3497,7 +3386,7 @@
 
         SettingsObserver(Context context, Handler handler) {
             super(null);
-            mUriEventMap = new HashMap<Uri, Integer>();
+            mUriEventMap = new HashMap<>();
             mContext = context;
             mHandler = handler;
         }
@@ -3707,6 +3596,26 @@
         }
     }
 
+    /**
+     * Ask all VPN objects to recompute and update their capabilities.
+     *
+     * When underlying networks change, VPNs may have to update capabilities to reflect things
+     * like the metered bit, their transports, and so on. This asks the VPN objects to update
+     * their capabilities, and as this will cause them to send messages to the ConnectivityService
+     * handler thread through their agent, this is asynchronous. When the capabilities objects
+     * are computed they will be up-to-date as they are computed synchronously from here and
+     * this is running on the ConnectivityService thread.
+     * TODO : Fix this and call updateCapabilities inline to remove out-of-order events.
+     */
+    private void updateAllVpnsCapabilities() {
+        synchronized (mVpns) {
+            for (int i = 0; i < mVpns.size(); i++) {
+                final Vpn vpn = mVpns.valueAt(i);
+                vpn.updateCapabilities();
+            }
+        }
+    }
+
     @Override
     public boolean updateLockdownVpn() {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -3783,7 +3692,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                // Shouldn't happen as all codepaths that point here should have checked the Vpn
+                // Shouldn't happen as all code paths that point here should have checked the Vpn
                 // exists already.
                 Slog.wtf(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
@@ -3947,7 +3856,7 @@
             url = String.format(url,
                     mTelephonyManager.getSimSerialNumber() /* ICCID */,
                     mTelephonyManager.getDeviceId() /* IMEI */,
-                    phoneNumber /* Phone numer */);
+                    phoneNumber /* Phone number */);
         }
 
         return url;
@@ -4074,10 +3983,8 @@
         }
     };
 
-    private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
-            new HashMap<Messenger, NetworkFactoryInfo>();
-    private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
-            new HashMap<NetworkRequest, NetworkRequestInfo>();
+    private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = new HashMap<>();
+    private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
 
     private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
     // Map from UID to number of NetworkRequests that UID has filed.
@@ -4181,8 +4088,17 @@
         }
     }
 
+    // This checks that the passed capabilities either do not request a specific SSID, or the
+    // calling app has permission to do so.
+    private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
+            int callerPid, int callerUid) {
+        if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
+            throw new SecurityException("Insufficient permissions to request a specific SSID");
+        }
+    }
+
     private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
-        final SortedSet<Integer> thresholds = new TreeSet();
+        final SortedSet<Integer> thresholds = new TreeSet<>();
         synchronized (nai) {
             for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                 if (nri.request.networkCapabilities.hasSignalStrength() &&
@@ -4191,7 +4107,7 @@
                 }
             }
         }
-        return new ArrayList<Integer>(thresholds);
+        return new ArrayList<>(thresholds);
     }
 
     private void updateSignalStrengthThresholds(
@@ -4238,8 +4154,7 @@
         // the default network request. This allows callers to keep track of
         // the system default network.
         if (type == NetworkRequest.Type.TRACK_DEFAULT) {
-            networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
-            networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
+            networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid());
             enforceAccessPermission();
         } else {
             networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -4250,6 +4165,8 @@
             enforceMeteredApnPolicy(networkCapabilities);
         }
         ensureRequestableCapabilities(networkCapabilities);
+        ensureSufficientPermissionsForRequest(networkCapabilities,
+                Binder.getCallingPid(), Binder.getCallingUid());
         // Set the UID range for this request to the single UID of the requester, or to an empty
         // set of UIDs if the caller has the appropriate permission and UIDs have not been set.
         // This will overwrite any allowed UIDs in the requested capabilities. Though there
@@ -4328,6 +4245,8 @@
         enforceNetworkRequestPermissions(networkCapabilities);
         enforceMeteredApnPolicy(networkCapabilities);
         ensureRequestableCapabilities(networkCapabilities);
+        ensureSufficientPermissionsForRequest(networkCapabilities,
+                Binder.getCallingPid(), Binder.getCallingUid());
         ensureValidNetworkSpecifier(networkCapabilities);
         restrictRequestUidsForCaller(networkCapabilities);
 
@@ -4383,6 +4302,8 @@
         }
 
         NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+        ensureSufficientPermissionsForRequest(networkCapabilities,
+                Binder.getCallingPid(), Binder.getCallingUid());
         restrictRequestUidsForCaller(nc);
         // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
         // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
@@ -4409,6 +4330,8 @@
             enforceAccessPermission();
         }
         ensureValidNetworkSpecifier(networkCapabilities);
+        ensureSufficientPermissionsForRequest(networkCapabilities,
+                Binder.getCallingPid(), Binder.getCallingUid());
 
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         restrictRequestUidsForCaller(nc);
@@ -4464,13 +4387,11 @@
      */
     // NOTE: Accessed on multiple threads, must be synchronized on itself.
     @GuardedBy("mNetworkForRequestId")
-    private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
-            new SparseArray<NetworkAgentInfo>();
+    private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = new SparseArray<>();
 
     // NOTE: Accessed on multiple threads, must be synchronized on itself.
     @GuardedBy("mNetworkForNetId")
-    private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
-            new SparseArray<NetworkAgentInfo>();
+    private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
     // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
     // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
     // there may not be a strict 1:1 correlation between the two.
@@ -4480,11 +4401,10 @@
     // NetworkAgentInfo keyed off its connecting messenger
     // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
     // NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
-    private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
-            new HashMap<Messenger, NetworkAgentInfo>();
+    private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos = new HashMap<>();
 
     @GuardedBy("mBlockedAppUids")
-    private final HashSet<Integer> mBlockedAppUids = new HashSet();
+    private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
 
     // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
     private final NetworkRequest mDefaultRequest;
@@ -4541,8 +4461,10 @@
         synchronized (this) {
             nai.networkMonitor.systemReady = mSystemReady;
         }
-        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network,
-                networkInfo.getExtraInfo());
+        final String extraInfo = networkInfo.getExtraInfo();
+        final String name = TextUtils.isEmpty(extraInfo)
+                ? nai.networkCapabilities.getSSID() : extraInfo;
+        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
         if (DBG) log("registerNetworkAgent " + nai);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
         return nai.network.netId;
@@ -4562,13 +4484,13 @@
     }
 
     private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
-        LinkProperties newLp = networkAgent.linkProperties;
+        LinkProperties newLp = new LinkProperties(networkAgent.linkProperties);
         int netId = networkAgent.network.netId;
 
         // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
         // we do anything else, make sure its LinkProperties are accurate.
         if (networkAgent.clatd != null) {
-            networkAgent.clatd.fixupLinkProperties(oldLp);
+            networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
         }
 
         updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
@@ -4592,10 +4514,13 @@
         if (isDefaultNetwork(networkAgent)) {
             handleApplyDefaultProxy(newLp.getHttpProxy());
         } else {
-            updateProxy(newLp, oldLp, networkAgent);
+            updateProxy(newLp, oldLp);
         }
         // TODO - move this check to cover the whole function
         if (!Objects.equals(newLp, oldLp)) {
+            synchronized (networkAgent) {
+                networkAgent.linkProperties = newLp;
+            }
             notifyIfacesChangedForNetworkStats();
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
         }
@@ -4604,7 +4529,7 @@
     }
 
     private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
-        // Marks are only available on WiFi interaces. Checking for
+        // Marks are only available on WiFi interfaces. Checking for
         // marks on unsupported interfaces is harmless.
         if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
             return;
@@ -4636,7 +4561,7 @@
 
     private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
                                   NetworkCapabilities caps) {
-        CompareResult<String> interfaceDiff = new CompareResult<String>(
+        CompareResult<String> interfaceDiff = new CompareResult<>(
                 oldLp != null ? oldLp.getAllInterfaceNames() : null,
                 newLp != null ? newLp.getAllInterfaceNames() : null);
         for (String iface : interfaceDiff.added) {
@@ -4671,7 +4596,7 @@
 
         // add routes before removing old in case it helps with continuous connectivity
 
-        // do this twice, adding non-nexthop routes first, then routes they are dependent on
+        // do this twice, adding non-next-hop routes first, then routes they are dependent on
         for (RouteInfo route : routeDiff.added) {
             if (route.hasGateway()) continue;
             if (VDBG) log("Adding Route [" + route + "] to network " + netId);
@@ -4846,12 +4771,7 @@
         if (!newNc.hasTransport(TRANSPORT_VPN)) {
             // Tell VPNs about updated capabilities, since they may need to
             // bubble those changes through.
-            synchronized (mVpns) {
-                for (int i = 0; i < mVpns.size(); i++) {
-                    final Vpn vpn = mVpns.valueAt(i);
-                    vpn.updateCapabilities();
-                }
-            }
+            updateAllVpnsCapabilities();
         }
     }
 
@@ -4980,7 +4900,7 @@
             }
             case ConnectivityManager.CALLBACK_CAP_CHANGED: {
                 // networkAgent can't be null as it has been accessed a few lines above.
-                final NetworkCapabilities nc = networkCapabilitiesWithoutUidsUnlessAllowed(
+                final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(
                         networkAgent.networkCapabilities, nri.mPid, nri.mUid);
                 putParcelable(bundle, nc);
                 break;
@@ -5124,8 +5044,8 @@
 
         // Find and migrate to this Network any NetworkRequests for
         // which this network is now the best.
-        ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
-        ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
+        ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<>();
+        ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
         NetworkCapabilities nc = newNetwork.networkCapabilities;
         if (VDBG) log(" network has: " + nc);
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -5175,7 +5095,7 @@
                     keep = true;
                     // Tell NetworkFactories about the new score, so they can stop
                     // trying to connect if they know they cannot match it.
-                    // TODO - this could get expensive if we have alot of requests for this
+                    // TODO - this could get expensive if we have a lot of requests for this
                     // network.  Think about if there is a way to reduce this.  Push
                     // netid->request mapping to each factory?
                     sendUpdatedScoreToFactories(nri.request, score);
@@ -5296,7 +5216,7 @@
 
             // This has to happen after the notifyNetworkCallbacks as that tickles each
             // ConnectivityManager instance so that legacy requests correctly bind dns
-            // requests to this network.  The legacy users are listening for this bcast
+            // requests to this network.  The legacy users are listening for this broadcast
             // and will generally do a dns request so they can ensureRouteToHost and if
             // they do that before the callbacks happen they'll use the default network.
             //
@@ -5361,7 +5281,7 @@
         // TODO: This may get slow.  The "changed" parameter is provided for future optimization
         // to avoid the slowness.  It is not simply enough to process just "changed", for
         // example in the case where "changed"'s score decreases and another network should begin
-        // satifying a NetworkRequest that "changed" currently satisfies.
+        // satisfying a NetworkRequest that "changed" currently satisfies.
 
         // Optimization: Only reprocess "changed" if its score improved.  This is safe because it
         // can only add more NetworkRequests satisfied by "changed", and this is exactly what
@@ -5472,11 +5392,12 @@
 
             if (networkAgent.isVPN()) {
                 // Temporarily disable the default proxy (not global).
-                synchronized (mProxyLock) {
-                    if (!mDefaultProxyDisabled) {
-                        mDefaultProxyDisabled = true;
-                        if (mGlobalProxy == null && mDefaultProxy != null) {
-                            sendProxyBroadcast(null);
+                synchronized (mProxyTracker.mProxyLock) {
+                    if (!mProxyTracker.mDefaultProxyDisabled) {
+                        mProxyTracker.mDefaultProxyDisabled = true;
+                        if (mProxyTracker.mGlobalProxy == null
+                                && mProxyTracker.mDefaultProxy != null) {
+                            mProxyTracker.sendProxyBroadcast(null);
                         }
                     }
                 }
@@ -5501,19 +5422,21 @@
         } else if (state == NetworkInfo.State.DISCONNECTED) {
             networkAgent.asyncChannel.disconnect();
             if (networkAgent.isVPN()) {
-                synchronized (mProxyLock) {
-                    if (mDefaultProxyDisabled) {
-                        mDefaultProxyDisabled = false;
-                        if (mGlobalProxy == null && mDefaultProxy != null) {
-                            sendProxyBroadcast(mDefaultProxy);
+                synchronized (mProxyTracker.mProxyLock) {
+                    if (mProxyTracker.mDefaultProxyDisabled) {
+                        mProxyTracker.mDefaultProxyDisabled = false;
+                        if (mProxyTracker.mGlobalProxy == null
+                                && mProxyTracker.mDefaultProxy != null) {
+                            mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
                         }
                     }
                 }
                 updateUids(networkAgent, networkAgent.networkCapabilities, null);
             }
+            disconnectAndDestroyNetwork(networkAgent);
         } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
                 state == NetworkInfo.State.SUSPENDED) {
-            // going into or coming out of SUSPEND: rescore and notify
+            // going into or coming out of SUSPEND: re-score and notify
             if (networkAgent.getCurrentScore() != oldScore) {
                 rematchAllNetworksAndRequests(networkAgent, oldScore);
             }
@@ -5812,4 +5735,61 @@
     private static int encodeBool(boolean b) {
         return b ? 1 : 0;
     }
-}
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+    }
+
+    private class ShellCmd extends ShellCommand {
+
+        @Override
+        public int onCommand(String cmd) {
+            if (cmd == null) {
+                return handleDefaultCommands(cmd);
+            }
+            final PrintWriter pw = getOutPrintWriter();
+            try {
+                switch (cmd) {
+                    case "airplane-mode":
+                        final String action = getNextArg();
+                        if ("enable".equals(action)) {
+                            setAirplaneMode(true);
+                            return 0;
+                        } else if ("disable".equals(action)) {
+                            setAirplaneMode(false);
+                            return 0;
+                        } else if (action == null) {
+                            final ContentResolver cr = mContext.getContentResolver();
+                            final int enabled = Settings.Global.getInt(cr,
+                                    Settings.Global.AIRPLANE_MODE_ON);
+                            pw.println(enabled == 0 ? "disabled" : "enabled");
+                            return 0;
+                        } else {
+                            onHelp();
+                            return -1;
+                        }
+                    default:
+                        return handleDefaultCommands(cmd);
+                }
+            } catch (Exception e) {
+                pw.println(e);
+            }
+            return -1;
+        }
+
+        @Override
+        public void onHelp() {
+            PrintWriter pw = getOutPrintWriter();
+            pw.println("Connectivity service commands:");
+            pw.println("  help");
+            pw.println("    Print this help text.");
+            pw.println("  airplane-mode [enable|disable]");
+            pw.println("    Turn airplane mode on or off.");
+            pw.println("  airplane-mode");
+            pw.println("    Get airplane mode.");
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 35bde8e..744ed25 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -24,6 +24,8 @@
 import static android.system.OsConstants.SOCK_DGRAM;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.IIpSecService;
@@ -42,6 +44,7 @@
 import android.net.TrafficStats;
 import android.net.util.NetdService;
 import android.os.Binder;
+import android.os.DeadSystemException;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -973,6 +976,13 @@
         return service;
     }
 
+    @NonNull
+    private AppOpsManager getAppOpsManager() {
+        AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps");
+        return appOps;
+    }
+
     /** @hide */
     @VisibleForTesting
     public IpSecService(Context context, IpSecServiceConfiguration config) {
@@ -1090,9 +1100,11 @@
                     new RefcountedResource<SpiRecord>(
                             new SpiRecord(resourceId, "", destinationAddress, spi), binder));
         } catch (ServiceSpecificException e) {
-            // TODO: Add appropriate checks when other ServiceSpecificException types are supported
-            return new IpSecSpiResponse(
-                    IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
+            if (e.errorCode == OsConstants.ENOENT) {
+                return new IpSecSpiResponse(
+                        IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
+            }
+            throw e;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1104,7 +1116,6 @@
      */
     private void releaseResource(RefcountedResourceArray resArray, int resourceId)
             throws RemoteException {
-
         resArray.getRefcountedResourceOrThrow(resourceId).userRelease();
     }
 
@@ -1239,7 +1250,9 @@
      */
     @Override
     public synchronized IpSecTunnelInterfaceResponse createTunnelInterface(
-            String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) {
+            String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
+            String callingPackage) {
+        enforceTunnelPermissions(callingPackage);
         checkNotNull(binder, "Null Binder passed to createTunnelInterface");
         checkNotNull(underlyingNetwork, "No underlying network was specified");
         checkInetAddress(localAddr);
@@ -1302,15 +1315,12 @@
             releaseNetId(ikey);
             releaseNetId(okey);
             throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            // FIXME: get the error code and throw is at an IOException from Errno Exception
+        } catch (Throwable t) {
+            // Release keys if we got an error.
+            releaseNetId(ikey);
+            releaseNetId(okey);
+            throw t;
         }
-
-        // If we make it to here, then something has gone wrong and we couldn't create a VTI.
-        // Release the keys that we reserved, and return an error status.
-        releaseNetId(ikey);
-        releaseNetId(okey);
-        return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
     }
 
     /**
@@ -1319,8 +1329,8 @@
      */
     @Override
     public synchronized void addAddressToTunnelInterface(
-            int tunnelResourceId, LinkAddress localAddr) {
-        enforceNetworkStackPermission();
+            int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
+        enforceTunnelPermissions(callingPackage);
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
 
         // Get tunnelInterface record; if no such interface is found, will throw
@@ -1339,9 +1349,6 @@
                             localAddr.getPrefixLength());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
-            throw new IllegalArgumentException(e);
         }
     }
 
@@ -1351,10 +1358,10 @@
      */
     @Override
     public synchronized void removeAddressFromTunnelInterface(
-            int tunnelResourceId, LinkAddress localAddr) {
-        enforceNetworkStackPermission();
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+            int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
+        enforceTunnelPermissions(callingPackage);
 
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
         // Get tunnelInterface record; if no such interface is found, will throw
         // IllegalArgumentException
         TunnelInterfaceRecord tunnelInterfaceInfo =
@@ -1371,9 +1378,6 @@
                             localAddr.getPrefixLength());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
-            throw new IllegalArgumentException(e);
         }
     }
 
@@ -1382,7 +1386,9 @@
      * server
      */
     @Override
-    public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException {
+    public synchronized void deleteTunnelInterface(
+            int resourceId, String callingPackage) throws RemoteException {
+        enforceTunnelPermissions(callingPackage);
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
         releaseResource(userRecord.mTunnelInterfaceRecords, resourceId);
     }
@@ -1468,7 +1474,6 @@
             case IpSecTransform.MODE_TRANSPORT:
                 break;
             case IpSecTransform.MODE_TUNNEL:
-                enforceNetworkStackPermission();
                 break;
             default:
                 throw new IllegalArgumentException(
@@ -1476,9 +1481,24 @@
         }
     }
 
-    private void enforceNetworkStackPermission() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
-                "IpSecService");
+    private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS;
+
+    private void enforceTunnelPermissions(String callingPackage) {
+        checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
+        if (false) { // STOPSHIP if this line is present
+            switch (getAppOpsManager().noteOp(
+                        TUNNEL_OP,
+                        Binder.getCallingUid(), callingPackage)) {
+                case AppOpsManager.MODE_DEFAULT:
+                    mContext.enforceCallingOrSelfPermission(
+                            android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
+                    break;
+                case AppOpsManager.MODE_ALLOWED:
+                    return;
+                default:
+                    throw new SecurityException("Request to ignore AppOps for non-legacy API");
+            }
+        }
     }
 
     private void createOrUpdateTransform(
@@ -1534,8 +1554,12 @@
      * result in all of those sockets becoming unable to send or receive data.
      */
     @Override
-    public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
-            throws RemoteException {
+    public synchronized IpSecTransformResponse createTransform(
+            IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
+        checkNotNull(c);
+        if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
+            enforceTunnelPermissions(callingPackage);
+        }
         checkIpSecConfig(c);
         checkNotNull(binder, "Null Binder passed to createTransform");
         final int resourceId = mNextResourceId++;
@@ -1561,12 +1585,7 @@
         dependencies.add(refcountedSpiRecord);
         SpiRecord spiRecord = refcountedSpiRecord.getResource();
 
-        try {
-            createOrUpdateTransform(c, resourceId, spiRecord, socketRecord);
-        } catch (ServiceSpecificException e) {
-            // FIXME: get the error code and throw is at an IOException from Errno Exception
-            return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
-        }
+        createOrUpdateTransform(c, resourceId, spiRecord, socketRecord);
 
         // SA was created successfully, time to construct a record and lock it away
         userRecord.mTransformRecords.put(
@@ -1613,23 +1632,15 @@
                 c.getMode() == IpSecTransform.MODE_TRANSPORT,
                 "Transform mode was not Transport mode; cannot be applied to a socket");
 
-        try {
-            mSrvConfig
-                    .getNetdInstance()
-                    .ipSecApplyTransportModeTransform(
-                            socket.getFileDescriptor(),
-                            resourceId,
-                            direction,
-                            c.getSourceAddress(),
-                            c.getDestinationAddress(),
-                            info.getSpiRecord().getSpi());
-        } catch (ServiceSpecificException e) {
-            if (e.errorCode == EINVAL) {
-                throw new IllegalArgumentException(e.toString());
-            } else {
-                throw e;
-            }
-        }
+        mSrvConfig
+                .getNetdInstance()
+                .ipSecApplyTransportModeTransform(
+                        socket.getFileDescriptor(),
+                        resourceId,
+                        direction,
+                        c.getSourceAddress(),
+                        c.getDestinationAddress(),
+                        info.getSpiRecord().getSpi());
     }
 
     /**
@@ -1641,13 +1652,9 @@
     @Override
     public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket)
             throws RemoteException {
-        try {
-            mSrvConfig
-                    .getNetdInstance()
-                    .ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
-        } catch (ServiceSpecificException e) {
-            // FIXME: get the error code and throw is at an IOException from Errno Exception
-        }
+        mSrvConfig
+                .getNetdInstance()
+                .ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
     }
 
     /**
@@ -1656,8 +1663,9 @@
      */
     @Override
     public synchronized void applyTunnelModeTransform(
-            int tunnelResourceId, int direction, int transformResourceId) throws RemoteException {
-        enforceNetworkStackPermission();
+            int tunnelResourceId, int direction,
+            int transformResourceId, String callingPackage) throws RemoteException {
+        enforceTunnelPermissions(callingPackage);
         checkDirection(direction);
 
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1ad1404..1ff455ea 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -16,324 +16,15 @@
 
 package com.android.server;
 
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.os.PowerManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.NtpTrustedTime;
-import android.util.TimeUtils;
-import android.util.TrustedTime;
-
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.DumpUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+import android.os.IBinder;
 
 /**
- * Monitors the network time and updates the system time if it is out of sync
- * and there hasn't been any NITZ update from the carrier recently.
- * If looking up the network time fails for some reason, it tries a few times with a short
- * interval and then resets to checking on longer intervals.
- * <p>
- * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
- * available.
- * </p>
+ * An interface for NetworkTimeUpdateService implementations. Eventually part or all of this service
+ * will be subsumed into {@link com.android.server.timedetector.TimeDetectorService}. In the
+ * meantime this interface allows Android to use either the old or new implementation.
  */
-public class NetworkTimeUpdateService extends Binder {
-
-    private static final String TAG = "NetworkTimeUpdateService";
-    private static final boolean DBG = false;
-
-    private static final int EVENT_AUTO_TIME_CHANGED = 1;
-    private static final int EVENT_POLL_NETWORK_TIME = 2;
-    private static final int EVENT_NETWORK_CHANGED = 3;
-
-    private static final String ACTION_POLL =
-            "com.android.server.NetworkTimeUpdateService.action.POLL";
-
-    private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000;
-    private static int POLL_REQUEST = 0;
-
-    private static final long NOT_SET = -1;
-    private long mNitzTimeSetTime = NOT_SET;
-    // TODO: Have a way to look up the timezone we are in
-    private long mNitzZoneSetTime = NOT_SET;
-    private Network mDefaultNetwork = null;
-
-    private Context mContext;
-    private TrustedTime mTime;
-
-    // NTP lookup is done on this thread and handler
-    private Handler mHandler;
-    private AlarmManager mAlarmManager;
-    private PendingIntent mPendingPollIntent;
-    private SettingsObserver mSettingsObserver;
-    private ConnectivityManager mCM;
-    private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
-    // The last time that we successfully fetched the NTP time.
-    private long mLastNtpFetchTime = NOT_SET;
-    private final PowerManager.WakeLock mWakeLock;
-
-    // Normal polling frequency
-    private final long mPollingIntervalMs;
-    // Try-again polling interval, in case the network request failed
-    private final long mPollingIntervalShorterMs;
-    // Number of times to try again
-    private final int mTryAgainTimesMax;
-    // If the time difference is greater than this threshold, then update the time.
-    private final int mTimeErrorThresholdMs;
-    // Keeps track of how many quick attempts were made to fetch NTP time.
-    // During bootup, the network may not have been up yet, or it's taking time for the
-    // connection to happen.
-    private int mTryAgainCounter;
-
-    public NetworkTimeUpdateService(Context context) {
-        mContext = context;
-        mTime = NtpTrustedTime.getInstance(context);
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-        Intent pollIntent = new Intent(ACTION_POLL, null);
-        mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
-
-        mPollingIntervalMs = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_ntpPollingInterval);
-        mPollingIntervalShorterMs = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_ntpPollingIntervalShorter);
-        mTryAgainTimesMax = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_ntpRetry);
-        mTimeErrorThresholdMs = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_ntpThreshold);
-
-        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
-                PowerManager.PARTIAL_WAKE_LOCK, TAG);
-    }
+public interface NetworkTimeUpdateService extends IBinder {
 
     /** Initialize the receivers and initiate the first NTP request */
-    public void systemRunning() {
-        registerForTelephonyIntents();
-        registerForAlarms();
-
-        HandlerThread thread = new HandlerThread(TAG);
-        thread.start();
-        mHandler = new MyHandler(thread.getLooper());
-        mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
-        mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
-
-        mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
-        mSettingsObserver.observe(mContext);
-    }
-
-    private void registerForTelephonyIntents() {
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
-        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
-        mContext.registerReceiver(mNitzReceiver, intentFilter);
-    }
-
-    private void registerForAlarms() {
-        mContext.registerReceiver(
-            new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
-                }
-            }, new IntentFilter(ACTION_POLL));
-    }
-
-    private void onPollNetworkTime(int event) {
-        // If Automatic time is not set, don't bother. Similarly, if we don't
-        // have any default network, don't bother.
-        if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
-        mWakeLock.acquire();
-        try {
-            onPollNetworkTimeUnderWakeLock(event);
-        } finally {
-            mWakeLock.release();
-        }
-    }
-
-    private void onPollNetworkTimeUnderWakeLock(int event) {
-        final long refTime = SystemClock.elapsedRealtime();
-        // If NITZ time was received less than mPollingIntervalMs time ago,
-        // no need to sync to NTP.
-        if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
-            resetAlarm(mPollingIntervalMs);
-            return;
-        }
-        final long currentTime = System.currentTimeMillis();
-        if (DBG) Log.d(TAG, "System time = " + currentTime);
-        // Get the NTP time
-        if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
-                || event == EVENT_AUTO_TIME_CHANGED) {
-            if (DBG) Log.d(TAG, "Before Ntp fetch");
-
-            // force refresh NTP cache when outdated
-            if (mTime.getCacheAge() >= mPollingIntervalMs) {
-                mTime.forceRefresh();
-            }
-
-            // only update when NTP time is fresh
-            if (mTime.getCacheAge() < mPollingIntervalMs) {
-                final long ntp = mTime.currentTimeMillis();
-                mTryAgainCounter = 0;
-                // If the clock is more than N seconds off or this is the first time it's been
-                // fetched since boot, set the current time.
-                if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
-                        || mLastNtpFetchTime == NOT_SET) {
-                    // Set the system time
-                    if (DBG && mLastNtpFetchTime == NOT_SET
-                            && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
-                        Log.d(TAG, "For initial setup, rtc = " + currentTime);
-                    }
-                    if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
-                    // Make sure we don't overflow, since it's going to be converted to an int
-                    if (ntp / 1000 < Integer.MAX_VALUE) {
-                        SystemClock.setCurrentTimeMillis(ntp);
-                    }
-                } else {
-                    if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
-                }
-                mLastNtpFetchTime = SystemClock.elapsedRealtime();
-            } else {
-                // Try again shortly
-                mTryAgainCounter++;
-                if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
-                    resetAlarm(mPollingIntervalShorterMs);
-                } else {
-                    // Try much later
-                    mTryAgainCounter = 0;
-                    resetAlarm(mPollingIntervalMs);
-                }
-                return;
-            }
-        }
-        resetAlarm(mPollingIntervalMs);
-    }
-
-    /**
-     * Cancel old alarm and starts a new one for the specified interval.
-     *
-     * @param interval when to trigger the alarm, starting from now.
-     */
-    private void resetAlarm(long interval) {
-        mAlarmManager.cancel(mPendingPollIntent);
-        long now = SystemClock.elapsedRealtime();
-        long next = now + interval;
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
-    }
-
-    /**
-     * Checks if the user prefers to automatically set the time.
-     */
-    private boolean isAutomaticTimeRequested() {
-        return Settings.Global.getInt(
-                mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
-    }
-
-    /** Receiver for Nitz time events */
-    private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (DBG) Log.d(TAG, "Received " + action);
-            if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
-                mNitzTimeSetTime = SystemClock.elapsedRealtime();
-            } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
-                mNitzZoneSetTime = SystemClock.elapsedRealtime();
-            }
-        }
-    };
-
-    /** Handler to do the network accesses on */
-    private class MyHandler extends Handler {
-
-        public MyHandler(Looper l) {
-            super(l);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case EVENT_AUTO_TIME_CHANGED:
-                case EVENT_POLL_NETWORK_TIME:
-                case EVENT_NETWORK_CHANGED:
-                    onPollNetworkTime(msg.what);
-                    break;
-            }
-        }
-    }
-
-    private class NetworkTimeUpdateCallback extends NetworkCallback {
-        @Override
-        public void onAvailable(Network network) {
-            Log.d(TAG, String.format("New default network %s; checking time.", network));
-            mDefaultNetwork = network;
-            // Running on mHandler so invoke directly.
-            onPollNetworkTime(EVENT_NETWORK_CHANGED);
-        }
-
-        @Override
-        public void onLost(Network network) {
-            if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
-        }
-    }
-
-    /** Observer to watch for changes to the AUTO_TIME setting */
-    private static class SettingsObserver extends ContentObserver {
-
-        private int mMsg;
-        private Handler mHandler;
-
-        SettingsObserver(Handler handler, int msg) {
-            super(handler);
-            mHandler = handler;
-            mMsg = msg;
-        }
-
-        void observe(Context context) {
-            ContentResolver resolver = context.getContentResolver();
-            resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
-                    false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            mHandler.obtainMessage(mMsg).sendToTarget();
-        }
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-        pw.print("PollingIntervalMs: ");
-        TimeUtils.formatDuration(mPollingIntervalMs, pw);
-        pw.print("\nPollingIntervalShorterMs: ");
-        TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
-        pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
-        pw.print("TimeErrorThresholdMs: ");
-        TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
-        pw.println("\nTryAgainCounter: " + mTryAgainCounter);
-        pw.print("LastNtpFetchTime: ");
-        TimeUtils.formatDuration(mLastNtpFetchTime, pw);
-        pw.println();
-    }
+    void systemRunning();
 }
diff --git a/services/core/java/com/android/server/NewNetworkTimeUpdateService.java b/services/core/java/com/android/server/NewNetworkTimeUpdateService.java
new file mode 100644
index 0000000..e918c1d
--- /dev/null
+++ b/services/core/java/com/android/server/NewNetworkTimeUpdateService.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
+import android.util.TrustedTime;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Monitors the network time and updates the system time if it is out of sync
+ * and there hasn't been any NITZ update from the carrier recently.
+ * If looking up the network time fails for some reason, it tries a few times with a short
+ * interval and then resets to checking on longer intervals.
+ * <p>
+ * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
+ * available.
+ * </p>
+ */
+public class NewNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
+
+    private static final String TAG = "NetworkTimeUpdateService";
+    private static final boolean DBG = false;
+
+    private static final int EVENT_AUTO_TIME_CHANGED = 1;
+    private static final int EVENT_POLL_NETWORK_TIME = 2;
+    private static final int EVENT_NETWORK_CHANGED = 3;
+
+    private static final String ACTION_POLL =
+            "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+    private static final int POLL_REQUEST = 0;
+
+    private static final long NOT_SET = -1;
+    private long mNitzTimeSetTime = NOT_SET;
+    private Network mDefaultNetwork = null;
+
+    private Context mContext;
+    private TrustedTime mTime;
+
+    // NTP lookup is done on this thread and handler
+    private Handler mHandler;
+    private AlarmManager mAlarmManager;
+    private PendingIntent mPendingPollIntent;
+    private SettingsObserver mSettingsObserver;
+    private ConnectivityManager mCM;
+    private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
+    // The last time that we successfully fetched the NTP time.
+    private long mLastNtpFetchTime = NOT_SET;
+    private final PowerManager.WakeLock mWakeLock;
+
+    // Normal polling frequency
+    private final long mPollingIntervalMs;
+    // Try-again polling interval, in case the network request failed
+    private final long mPollingIntervalShorterMs;
+    // Number of times to try again
+    private final int mTryAgainTimesMax;
+    // If the time difference is greater than this threshold, then update the time.
+    private final int mTimeErrorThresholdMs;
+    // Keeps track of how many quick attempts were made to fetch NTP time.
+    // During bootup, the network may not have been up yet, or it's taking time for the
+    // connection to happen.
+    private int mTryAgainCounter;
+
+    public NewNetworkTimeUpdateService(Context context) {
+        mContext = context;
+        mTime = NtpTrustedTime.getInstance(context);
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        Intent pollIntent = new Intent(ACTION_POLL, null);
+        mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+
+        mPollingIntervalMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpPollingInterval);
+        mPollingIntervalShorterMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpPollingIntervalShorter);
+        mTryAgainTimesMax = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpRetry);
+        mTimeErrorThresholdMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpThreshold);
+
+        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK, TAG);
+    }
+
+    /** Initialize the receivers and initiate the first NTP request */
+    public void systemRunning() {
+        registerForTelephonyIntents();
+        registerForAlarms();
+
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mHandler = new MyHandler(thread.getLooper());
+        mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+        mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
+
+        mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
+        mSettingsObserver.observe(mContext);
+    }
+
+    private void registerForTelephonyIntents() {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+        mContext.registerReceiver(mNitzReceiver, intentFilter);
+    }
+
+    private void registerForAlarms() {
+        mContext.registerReceiver(
+            new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+                }
+            }, new IntentFilter(ACTION_POLL));
+    }
+
+    private void onPollNetworkTime(int event) {
+        // If Automatic time is not set, don't bother. Similarly, if we don't
+        // have any default network, don't bother.
+        if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
+        mWakeLock.acquire();
+        try {
+            onPollNetworkTimeUnderWakeLock(event);
+        } finally {
+            mWakeLock.release();
+        }
+    }
+
+    private void onPollNetworkTimeUnderWakeLock(int event) {
+        final long refTime = SystemClock.elapsedRealtime();
+        // If NITZ time was received less than mPollingIntervalMs time ago,
+        // no need to sync to NTP.
+        if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
+            resetAlarm(mPollingIntervalMs);
+            return;
+        }
+        final long currentTime = System.currentTimeMillis();
+        if (DBG) Log.d(TAG, "System time = " + currentTime);
+        // Get the NTP time
+        if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
+                || event == EVENT_AUTO_TIME_CHANGED) {
+            if (DBG) Log.d(TAG, "Before Ntp fetch");
+
+            // force refresh NTP cache when outdated
+            if (mTime.getCacheAge() >= mPollingIntervalMs) {
+                mTime.forceRefresh();
+            }
+
+            // only update when NTP time is fresh
+            if (mTime.getCacheAge() < mPollingIntervalMs) {
+                final long ntp = mTime.currentTimeMillis();
+                mTryAgainCounter = 0;
+                // If the clock is more than N seconds off or this is the first time it's been
+                // fetched since boot, set the current time.
+                if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
+                        || mLastNtpFetchTime == NOT_SET) {
+                    // Set the system time
+                    if (DBG && mLastNtpFetchTime == NOT_SET
+                            && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
+                        Log.d(TAG, "For initial setup, rtc = " + currentTime);
+                    }
+                    if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
+                    // Make sure we don't overflow, since it's going to be converted to an int
+                    if (ntp / 1000 < Integer.MAX_VALUE) {
+                        SystemClock.setCurrentTimeMillis(ntp);
+                    }
+                } else {
+                    if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
+                }
+                mLastNtpFetchTime = SystemClock.elapsedRealtime();
+            } else {
+                // Try again shortly
+                mTryAgainCounter++;
+                if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+                    resetAlarm(mPollingIntervalShorterMs);
+                } else {
+                    // Try much later
+                    mTryAgainCounter = 0;
+                    resetAlarm(mPollingIntervalMs);
+                }
+                return;
+            }
+        }
+        resetAlarm(mPollingIntervalMs);
+    }
+
+    /**
+     * Cancel old alarm and starts a new one for the specified interval.
+     *
+     * @param interval when to trigger the alarm, starting from now.
+     */
+    private void resetAlarm(long interval) {
+        mAlarmManager.cancel(mPendingPollIntent);
+        long now = SystemClock.elapsedRealtime();
+        long next = now + interval;
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
+    }
+
+    /**
+     * Checks if the user prefers to automatically set the time.
+     */
+    private boolean isAutomaticTimeRequested() {
+        return Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
+    }
+
+    /** Receiver for Nitz time events */
+    private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DBG) Log.d(TAG, "Received " + action);
+            if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
+                mNitzTimeSetTime = SystemClock.elapsedRealtime();
+            }
+        }
+    };
+
+    /** Handler to do the network accesses on */
+    private class MyHandler extends Handler {
+
+        public MyHandler(Looper l) {
+            super(l);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_AUTO_TIME_CHANGED:
+                case EVENT_POLL_NETWORK_TIME:
+                case EVENT_NETWORK_CHANGED:
+                    onPollNetworkTime(msg.what);
+                    break;
+            }
+        }
+    }
+
+    private class NetworkTimeUpdateCallback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            Log.d(TAG, String.format("New default network %s; checking time.", network));
+            mDefaultNetwork = network;
+            // Running on mHandler so invoke directly.
+            onPollNetworkTime(EVENT_NETWORK_CHANGED);
+        }
+
+        @Override
+        public void onLost(Network network) {
+            if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+        }
+    }
+
+    /** Observer to watch for changes to the AUTO_TIME setting */
+    private static class SettingsObserver extends ContentObserver {
+
+        private int mMsg;
+        private Handler mHandler;
+
+        SettingsObserver(Handler handler, int msg) {
+            super(handler);
+            mHandler = handler;
+            mMsg = msg;
+        }
+
+        void observe(Context context) {
+            ContentResolver resolver = context.getContentResolver();
+            resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
+                    false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            mHandler.obtainMessage(mMsg).sendToTarget();
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+        pw.print("PollingIntervalMs: ");
+        TimeUtils.formatDuration(mPollingIntervalMs, pw);
+        pw.print("\nPollingIntervalShorterMs: ");
+        TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+        pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+        pw.print("TimeErrorThresholdMs: ");
+        TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+        pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+        pw.print("LastNtpFetchTime: ");
+        TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/OldNetworkTimeUpdateService.java b/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
new file mode 100644
index 0000000..d127b67
--- /dev/null
+++ b/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
+import android.util.TrustedTime;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Monitors the network time and updates the system time if it is out of sync
+ * and there hasn't been any NITZ update from the carrier recently.
+ * If looking up the network time fails for some reason, it tries a few times with a short
+ * interval and then resets to checking on longer intervals.
+ * <p>
+ * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
+ * available.
+ * </p>
+ */
+public class OldNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
+
+    private static final String TAG = "NetworkTimeUpdateService";
+    private static final boolean DBG = false;
+
+    private static final int EVENT_AUTO_TIME_CHANGED = 1;
+    private static final int EVENT_POLL_NETWORK_TIME = 2;
+    private static final int EVENT_NETWORK_CHANGED = 3;
+
+    private static final String ACTION_POLL =
+            "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+    private static final int POLL_REQUEST = 0;
+
+    private static final long NOT_SET = -1;
+    private long mNitzTimeSetTime = NOT_SET;
+    private Network mDefaultNetwork = null;
+
+    private Context mContext;
+    private TrustedTime mTime;
+
+    // NTP lookup is done on this thread and handler
+    private Handler mHandler;
+    private AlarmManager mAlarmManager;
+    private PendingIntent mPendingPollIntent;
+    private SettingsObserver mSettingsObserver;
+    private ConnectivityManager mCM;
+    private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
+    // The last time that we successfully fetched the NTP time.
+    private long mLastNtpFetchTime = NOT_SET;
+    private final PowerManager.WakeLock mWakeLock;
+
+    // Normal polling frequency
+    private final long mPollingIntervalMs;
+    // Try-again polling interval, in case the network request failed
+    private final long mPollingIntervalShorterMs;
+    // Number of times to try again
+    private final int mTryAgainTimesMax;
+    // If the time difference is greater than this threshold, then update the time.
+    private final int mTimeErrorThresholdMs;
+    // Keeps track of how many quick attempts were made to fetch NTP time.
+    // During bootup, the network may not have been up yet, or it's taking time for the
+    // connection to happen.
+    private int mTryAgainCounter;
+
+    public OldNetworkTimeUpdateService(Context context) {
+        mContext = context;
+        mTime = NtpTrustedTime.getInstance(context);
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        Intent pollIntent = new Intent(ACTION_POLL, null);
+        mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+
+        mPollingIntervalMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpPollingInterval);
+        mPollingIntervalShorterMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpPollingIntervalShorter);
+        mTryAgainTimesMax = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpRetry);
+        mTimeErrorThresholdMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_ntpThreshold);
+
+        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK, TAG);
+    }
+
+    /** Initialize the receivers and initiate the first NTP request */
+    public void systemRunning() {
+        registerForTelephonyIntents();
+        registerForAlarms();
+
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mHandler = new MyHandler(thread.getLooper());
+        mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+        mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
+
+        mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
+        mSettingsObserver.observe(mContext);
+    }
+
+    private void registerForTelephonyIntents() {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+        mContext.registerReceiver(mNitzReceiver, intentFilter);
+    }
+
+    private void registerForAlarms() {
+        mContext.registerReceiver(
+            new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+                }
+            }, new IntentFilter(ACTION_POLL));
+    }
+
+    private void onPollNetworkTime(int event) {
+        // If Automatic time is not set, don't bother. Similarly, if we don't
+        // have any default network, don't bother.
+        if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
+        mWakeLock.acquire();
+        try {
+            onPollNetworkTimeUnderWakeLock(event);
+        } finally {
+            mWakeLock.release();
+        }
+    }
+
+    private void onPollNetworkTimeUnderWakeLock(int event) {
+        final long refTime = SystemClock.elapsedRealtime();
+        // If NITZ time was received less than mPollingIntervalMs time ago,
+        // no need to sync to NTP.
+        if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
+            resetAlarm(mPollingIntervalMs);
+            return;
+        }
+        final long currentTime = System.currentTimeMillis();
+        if (DBG) Log.d(TAG, "System time = " + currentTime);
+        // Get the NTP time
+        if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
+                || event == EVENT_AUTO_TIME_CHANGED) {
+            if (DBG) Log.d(TAG, "Before Ntp fetch");
+
+            // force refresh NTP cache when outdated
+            if (mTime.getCacheAge() >= mPollingIntervalMs) {
+                mTime.forceRefresh();
+            }
+
+            // only update when NTP time is fresh
+            if (mTime.getCacheAge() < mPollingIntervalMs) {
+                final long ntp = mTime.currentTimeMillis();
+                mTryAgainCounter = 0;
+                // If the clock is more than N seconds off or this is the first time it's been
+                // fetched since boot, set the current time.
+                if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
+                        || mLastNtpFetchTime == NOT_SET) {
+                    // Set the system time
+                    if (DBG && mLastNtpFetchTime == NOT_SET
+                            && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
+                        Log.d(TAG, "For initial setup, rtc = " + currentTime);
+                    }
+                    if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
+                    // Make sure we don't overflow, since it's going to be converted to an int
+                    if (ntp / 1000 < Integer.MAX_VALUE) {
+                        SystemClock.setCurrentTimeMillis(ntp);
+                    }
+                } else {
+                    if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
+                }
+                mLastNtpFetchTime = SystemClock.elapsedRealtime();
+            } else {
+                // Try again shortly
+                mTryAgainCounter++;
+                if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+                    resetAlarm(mPollingIntervalShorterMs);
+                } else {
+                    // Try much later
+                    mTryAgainCounter = 0;
+                    resetAlarm(mPollingIntervalMs);
+                }
+                return;
+            }
+        }
+        resetAlarm(mPollingIntervalMs);
+    }
+
+    /**
+     * Cancel old alarm and starts a new one for the specified interval.
+     *
+     * @param interval when to trigger the alarm, starting from now.
+     */
+    private void resetAlarm(long interval) {
+        mAlarmManager.cancel(mPendingPollIntent);
+        long now = SystemClock.elapsedRealtime();
+        long next = now + interval;
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
+    }
+
+    /**
+     * Checks if the user prefers to automatically set the time.
+     */
+    private boolean isAutomaticTimeRequested() {
+        return Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
+    }
+
+    /** Receiver for Nitz time events */
+    private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DBG) Log.d(TAG, "Received " + action);
+            if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
+                mNitzTimeSetTime = SystemClock.elapsedRealtime();
+            }
+        }
+    };
+
+    /** Handler to do the network accesses on */
+    private class MyHandler extends Handler {
+
+        public MyHandler(Looper l) {
+            super(l);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_AUTO_TIME_CHANGED:
+                case EVENT_POLL_NETWORK_TIME:
+                case EVENT_NETWORK_CHANGED:
+                    onPollNetworkTime(msg.what);
+                    break;
+            }
+        }
+    }
+
+    private class NetworkTimeUpdateCallback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            Log.d(TAG, String.format("New default network %s; checking time.", network));
+            mDefaultNetwork = network;
+            // Running on mHandler so invoke directly.
+            onPollNetworkTime(EVENT_NETWORK_CHANGED);
+        }
+
+        @Override
+        public void onLost(Network network) {
+            if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+        }
+    }
+
+    /** Observer to watch for changes to the AUTO_TIME setting */
+    private static class SettingsObserver extends ContentObserver {
+
+        private int mMsg;
+        private Handler mHandler;
+
+        SettingsObserver(Handler handler, int msg) {
+            super(handler);
+            mHandler = handler;
+            mMsg = msg;
+        }
+
+        void observe(Context context) {
+            ContentResolver resolver = context.getContentResolver();
+            resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
+                    false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            mHandler.obtainMessage(mMsg).sendToTarget();
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+        pw.print("PollingIntervalMs: ");
+        TimeUtils.formatDuration(mPollingIntervalMs, pw);
+        pw.print("\nPollingIntervalShorterMs: ");
+        TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+        pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+        pw.print("TimeErrorThresholdMs: ");
+        TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+        pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+        pw.print("LastNtpFetchTime: ");
+        TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8399ee2..5491f77 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2986,6 +2986,9 @@
                 .append(Binder.getCallingPid()).toString();
 
         synchronized (mBluetoothA2dpEnabledLock) {
+            if (mBluetoothA2dpEnabled == on) {
+                return;
+            }
             mBluetoothA2dpEnabled = on;
             sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
                     AudioSystem.FOR_MEDIA,
@@ -3473,7 +3476,7 @@
                             queueMsgUnderWakeLock(mAudioHandler,
                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
                                     state,
-                                    0 /* arg2 unused */,
+                                    -1,
                                     btDevice,
                                     delay);
                         }
@@ -4159,22 +4162,22 @@
     public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
     {
         return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                device, state, profile, false /* suppressNoisyIntent */);
+                device, state, profile, false /* suppressNoisyIntent */, -1 /* a2dpVolume */);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
-                int state, int profile, boolean suppressNoisyIntent)
+                int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
     {
         if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
             return 0;
         }
         return setBluetoothA2dpDeviceConnectionStateInt(
-                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE);
+                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateInt(
             BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
-            int musicDevice)
+            int musicDevice, int a2dpVolume)
     {
         int delay;
         if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
@@ -4192,7 +4195,7 @@
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
                     state,
-                    0 /* arg2 unused */,
+                    a2dpVolume,
                     device,
                     delay);
         }
@@ -4690,41 +4693,41 @@
         }
     }
 
-    /** Handles internal volume messages in separate volume thread. */
-    private class AudioHandler extends Handler {
+    private void setDeviceVolume(VolumeStreamState streamState, int device) {
 
-        private void setDeviceVolume(VolumeStreamState streamState, int device) {
+        synchronized (VolumeStreamState.class) {
+            // Apply volume
+            streamState.applyDeviceVolume_syncVSS(device);
 
-            synchronized (VolumeStreamState.class) {
-                // Apply volume
-                streamState.applyDeviceVolume_syncVSS(device);
-
-                // Apply change to all streams using this one as alias
-                int numStreamTypes = AudioSystem.getNumStreamTypes();
-                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                    if (streamType != streamState.mStreamType &&
-                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
-                        // Make sure volume is also maxed out on A2DP device for aliased stream
-                        // that may have a different device selected
-                        int streamDevice = getDeviceForStream(streamType);
-                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
-                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
-                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
-                        }
-                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
+            // Apply change to all streams using this one as alias
+            int numStreamTypes = AudioSystem.getNumStreamTypes();
+            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                if (streamType != streamState.mStreamType &&
+                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
+                    // Make sure volume is also maxed out on A2DP device for aliased stream
+                    // that may have a different device selected
+                    int streamDevice = getDeviceForStream(streamType);
+                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
+                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+                        mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                     }
+                    mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
                 }
             }
-            // Post a persist volume msg
-            sendMsg(mAudioHandler,
-                    MSG_PERSIST_VOLUME,
-                    SENDMSG_QUEUE,
-                    device,
-                    0,
-                    streamState,
-                    PERSIST_DELAY);
-
         }
+        // Post a persist volume msg
+        sendMsg(mAudioHandler,
+                MSG_PERSIST_VOLUME,
+                SENDMSG_QUEUE,
+                device,
+                0,
+                streamState,
+                PERSIST_DELAY);
+
+    }
+
+    /** Handles internal volume messages in separate volume thread. */
+    private class AudioHandler extends Handler {
 
         private void setAllVolumes(VolumeStreamState streamState) {
 
@@ -5071,7 +5074,7 @@
                     break;
 
                 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
-                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1, msg.arg2);
                     mAudioEventWakeLock.release();
                     break;
 
@@ -5309,7 +5312,7 @@
         return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
     }
 
-    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
+    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
     {
         if (DEBUG_DEVICES) {
             Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
@@ -5360,6 +5363,14 @@
                         makeA2dpDeviceUnavailableNow(mDockAddress);
                     }
                 }
+                if (a2dpVolume != -1) {
+                    VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+                    // Convert index to internal representation in VolumeStreamState
+                    a2dpVolume = a2dpVolume * 10;
+                    streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                            "onSetA2dpSinkConnectionState");
+                    setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+                }
                 makeA2dpDeviceAvailable(address, btDevice.getName(),
                         "onSetA2dpSinkConnectionState");
                 synchronized (mCurAudioRoutes) {
@@ -5429,7 +5440,7 @@
                    // consistent with audio policy manager state
                    setBluetoothA2dpDeviceConnectionStateInt(
                            btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
-                           false /* suppressNoisyIntent */, musicDevice);
+                           false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
                }
             }
         }
@@ -5439,6 +5450,9 @@
         // address is not used for now, but may be used when multiple a2dp devices are supported
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = support;
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index fceacba..f523d59 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -224,15 +224,14 @@
     }
 
     /**
-     * Copies the stacked clat link in oldLp, if any, to the LinkProperties in mNetwork.
+     * Copies the stacked clat link in oldLp, if any, to the passed LinkProperties.
      * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
      * has no idea that 464xlat is running on top of it.
      */
-    public void fixupLinkProperties(LinkProperties oldLp) {
+    public void fixupLinkProperties(LinkProperties oldLp, LinkProperties lp) {
         if (!isRunning()) {
             return;
         }
-        LinkProperties lp = mNetwork.linkProperties;
         if (lp == null || lp.getAllInterfaceNames().contains(mIface)) {
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 0d935db..36a2476 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -23,8 +23,10 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.net.NetworkCapabilities;
+import android.net.wifi.WifiInfo;
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -130,16 +132,17 @@
         final String tag = tagFor(id);
         final int eventId = notifyType.eventId;
         final int transportType;
-        final String extraInfo;
+        final String name;
         if (nai != null) {
             transportType = getFirstTransportType(nai);
-            extraInfo = nai.networkInfo.getExtraInfo();
+            final String extraInfo = nai.networkInfo.getExtraInfo();
+            name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
             // Only notify for Internet-capable networks.
             if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
         } else {
             // Legacy notifications.
             transportType = TRANSPORT_CELLULAR;
-            extraInfo = null;
+            name = null;
         }
 
         // Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -156,9 +159,8 @@
 
         if (DBG) {
             Slog.d(TAG, String.format(
-                    "showNotification tag=%s event=%s transport=%s extraInfo=%s highPrioriy=%s",
-                    tag, nameOf(eventId), getTransportName(transportType), extraInfo,
-                    highPriority));
+                    "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
+                    tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
 
         Resources r = Resources.getSystem();
@@ -176,7 +178,8 @@
             switch (transportType) {
                 case TRANSPORT_WIFI:
                     title = r.getString(R.string.wifi_available_sign_in, 0);
-                    details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+                    details = r.getString(R.string.network_available_sign_in_detailed,
+                            WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
                     break;
                 case TRANSPORT_CELLULAR:
                     title = r.getString(R.string.network_available_sign_in, 0);
@@ -186,7 +189,7 @@
                     break;
                 default:
                     title = r.getString(R.string.network_available_sign_in, 0);
-                    details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+                    details = r.getString(R.string.network_available_sign_in_detailed, name);
                     break;
             }
         } else if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3a27fcb3..c370959 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -90,7 +90,7 @@
     private volatile boolean mHasDownloaded;
 
     private Handler mConnectivityHandler;
-    private int mProxyMessage;
+    private final int mProxyMessage;
 
     /**
      * Used for locking when setting mProxyService and all references to mCurrentPac.
@@ -99,7 +99,7 @@
 
     /**
      * Runnable to download PAC script.
-     * The behavior relies on the assamption it always run on mNetThread to guarantee that the
+     * The behavior relies on the assumption it always runs on mNetThread to guarantee that the
      * latest data fetched from mPacUrl is stored in mProxyService.
      */
     private Runnable mPacDownloader = new Runnable() {
@@ -133,8 +133,6 @@
         }
     };
 
-    private final HandlerThread mNetThread = new HandlerThread("android.pacmanager",
-            android.os.Process.THREAD_PRIORITY_DEFAULT);
     private final Handler mNetThreadHandler;
 
     class PacRefreshIntentReceiver extends BroadcastReceiver {
@@ -146,8 +144,10 @@
     public PacManager(Context context, Handler handler, int proxyMessage) {
         mContext = context;
         mLastPort = -1;
-        mNetThread.start();
-        mNetThreadHandler = new Handler(mNetThread.getLooper());
+        final HandlerThread netThread = new HandlerThread("android.pacmanager",
+                android.os.Process.THREAD_PRIORITY_DEFAULT);
+        netThread.start();
+        mNetThreadHandler = new Handler(netThread.getLooper());
 
         mPacRefreshIntent = PendingIntent.getBroadcast(
                 context, 0, new Intent(ACTION_PAC_REFRESH), 0);
@@ -166,14 +166,14 @@
 
     /**
      * Updates the PAC Manager with current Proxy information. This is called by
-     * the ConnectivityService directly before a broadcast takes place to allow
+     * the ProxyTracker directly before a broadcast takes place to allow
      * the PacManager to indicate that the broadcast should not be sent and the
      * PacManager will trigger a new broadcast when it is ready.
      *
      * @param proxy Proxy information that is about to be broadcast.
      * @return Returns true when the broadcast should not be sent
      */
-    public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+    synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
         if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
                 // Allow to send broadcast, nothing to do.
@@ -208,7 +208,7 @@
     /**
      * Does a post and reports back the status code.
      *
-     * @throws IOException
+     * @throws IOException if the URL is malformed, or the PAC file is too big.
      */
     private static String get(Uri pacUri) throws IOException {
         URL url = new URL(pacUri.toString());
@@ -254,7 +254,7 @@
     private String getPacChangeDelay() {
         final ContentResolver cr = mContext.getContentResolver();
 
-        /** Check system properties for the default value then use secure settings value, if any. */
+        // Check system properties for the default value then use secure settings value, if any.
         String defaultDelay = SystemProperties.get(
                 "conn." + Settings.Global.PAC_CHANGE_DELAY,
                 DEFAULT_DELAYS);
@@ -276,10 +276,9 @@
         getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
     }
 
-    private boolean setCurrentProxyScript(String script) {
+    private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
-            return false;
         }
         try {
             mProxyService.setPacFile(script);
@@ -287,7 +286,6 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to set PAC file", e);
         }
-        return true;
     }
 
     private void bind() {
@@ -351,7 +349,7 @@
                     try {
                         callbackService.getProxyPort(new IProxyPortListener.Stub() {
                             @Override
-                            public void setProxyPort(int port) throws RemoteException {
+                            public void setProxyPort(int port) {
                                 if (mLastPort != -1) {
                                     // Always need to send if port changed
                                     mHasSentBroadcast = false;
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
new file mode 100644
index 0000000..dc65e1e
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -0,0 +1,256 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Proxy;
+import android.net.ProxyInfo;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Objects;
+
+/**
+ * A class to handle proxy for ConnectivityService.
+ *
+ * @hide
+ */
+public class ProxyTracker {
+    private static final String TAG = ProxyTracker.class.getSimpleName();
+    private static final boolean DBG = true;
+
+    @NonNull
+    private final Context mContext;
+
+    // TODO : make this private and import as much managing logic from ConnectivityService as
+    // possible
+    @NonNull
+    public final Object mProxyLock = new Object();
+    // The global proxy is the proxy that is set device-wide, overriding any network-specific
+    // proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
+    // this value is only for querying.
+    @Nullable
+    @GuardedBy("mProxyLock")
+    public ProxyInfo mGlobalProxy = null;
+    // The default proxy is the proxy that applies to no particular network if the global proxy
+    // is not set. Individual networks have their own settings that override this. This member
+    // is set through setDefaultProxy, which is called when the default network changes proxies
+    // in its LinkProperties, or when ConnectivityService switches to a new default network, or
+    // when PacManager resolves the proxy.
+    @Nullable
+    @GuardedBy("mProxyLock")
+    public volatile ProxyInfo mDefaultProxy = null;
+    // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+    @GuardedBy("mProxyLock")
+    public boolean mDefaultProxyDisabled = false;
+
+    // The object responsible for Proxy Auto Configuration (PAC).
+    @NonNull
+    private final PacManager mPacManager;
+
+    public ProxyTracker(@NonNull final Context context,
+            @NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) {
+        mContext = context;
+        mPacManager = new PacManager(context, connectivityServiceInternalHandler, pacChangedEvent);
+    }
+
+    // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
+    // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
+    // proxy is null then there is no proxy in place).
+    @Nullable
+    private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
+        if (proxy != null && TextUtils.isEmpty(proxy.getHost())
+                && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+            return null;
+        }
+        return proxy;
+    }
+
+    // ProxyInfo equality functions with a couple modifications over ProxyInfo.equals() to make it
+    // better for determining if a new proxy broadcast is necessary:
+    // 1. Canonicalize empty ProxyInfos to null so an empty proxy compares equal to null so as to
+    //    avoid unnecessary broadcasts.
+    // 2. Make sure all parts of the ProxyInfo's compare true, including the host when a PAC URL
+    //    is in place.  This is important so legacy PAC resolver (see com.android.proxyhandler)
+    //    changes aren't missed.  The legacy PAC resolver pretends to be a simple HTTP proxy but
+    //    actually uses the PAC to resolve; this results in ProxyInfo's with PAC URL, host and port
+    //    all set.
+    public static boolean proxyInfoEqual(@Nullable final ProxyInfo a, @Nullable final ProxyInfo b) {
+        final ProxyInfo pa = canonicalizeProxyInfo(a);
+        final ProxyInfo pb = canonicalizeProxyInfo(b);
+        // ProxyInfo.equals() doesn't check hosts when PAC URLs are present, but we need to check
+        // hosts even when PAC URLs are present to account for the legacy PAC resolver.
+        return Objects.equals(pa, pb) && (pa == null || Objects.equals(pa.getHost(), pb.getHost()));
+    }
+
+    /**
+     * Gets the default system-wide proxy.
+     *
+     * This will return the global proxy if set, otherwise the default proxy if in use. Note
+     * that this is not necessarily the proxy that any given process should use, as the right
+     * proxy for a process is the proxy for the network this process will use, which may be
+     * different from this value. This value is simply the default in case there is no proxy set
+     * in the network that will be used by a specific process.
+     * @return The default system-wide proxy or null if none.
+     */
+    @Nullable
+    public ProxyInfo getDefaultProxy() {
+        // This information is already available as a world read/writable jvm property.
+        synchronized (mProxyLock) {
+            final ProxyInfo ret = mGlobalProxy;
+            if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
+            return ret;
+        }
+    }
+
+    /**
+     * Gets the global proxy.
+     *
+     * @return The global proxy or null if none.
+     */
+    @Nullable
+    public ProxyInfo getGlobalProxy() {
+        // This information is already available as a world read/writable jvm property.
+        synchronized (mProxyLock) {
+            return mGlobalProxy;
+        }
+    }
+
+    /**
+     * Sends the system broadcast informing apps about a new proxy configuration.
+     *
+     * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
+     * to do in a "sendProxyBroadcast" method.
+     * @param proxyInfo the proxy spec, or null for no proxy.
+     */
+    // TODO : make the argument NonNull final and the method private
+    public void sendProxyBroadcast(@Nullable ProxyInfo proxyInfo) {
+        if (proxyInfo == null) proxyInfo = new ProxyInfo("", 0, "");
+        if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return;
+        if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
+        Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxyInfo);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Sets the global proxy in memory. Also writes the values to the global settings of the device.
+     *
+     * @param proxyInfo the proxy spec, or null for no proxy.
+     */
+    public void setGlobalProxy(@Nullable ProxyInfo proxyInfo) {
+        synchronized (mProxyLock) {
+            // ProxyInfo#equals is not commutative :( and is public API, so it can't be fixed.
+            if (proxyInfo == mGlobalProxy) return;
+            if (proxyInfo != null && proxyInfo.equals(mGlobalProxy)) return;
+            if (mGlobalProxy != null && mGlobalProxy.equals(proxyInfo)) return;
+
+            final String host;
+            final int port;
+            final String exclList;
+            final String pacFileUrl;
+            if (proxyInfo != null && (!TextUtils.isEmpty(proxyInfo.getHost()) ||
+                    !Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))) {
+                if (!proxyInfo.isValid()) {
+                    if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+                    return;
+                }
+                mGlobalProxy = new ProxyInfo(proxyInfo);
+                host = mGlobalProxy.getHost();
+                port = mGlobalProxy.getPort();
+                exclList = mGlobalProxy.getExclusionListAsString();
+                pacFileUrl = Uri.EMPTY.equals(proxyInfo.getPacFileUrl())
+                        ? "" : proxyInfo.getPacFileUrl().toString();
+            } else {
+                host = "";
+                port = 0;
+                exclList = "";
+                pacFileUrl = "";
+                mGlobalProxy = null;
+            }
+            final ContentResolver res = mContext.getContentResolver();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
+                Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
+                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+                        exclList);
+                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            sendProxyBroadcast(mGlobalProxy == null ? mDefaultProxy : proxyInfo);
+        }
+    }
+
+    /**
+     * Sets the default proxy for the device.
+     *
+     * The default proxy is the proxy used for networks that do not have a specific proxy.
+     * @param proxyInfo the proxy spec, or null for no proxy.
+     */
+    public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
+        synchronized (mProxyLock) {
+            if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
+                return;
+            }
+            if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+            if (proxyInfo != null &&  !proxyInfo.isValid()) {
+                if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+                return;
+            }
+
+            // This call could be coming from the PacManager, containing the port of the local
+            // proxy. If this new proxy matches the global proxy then copy this proxy to the
+            // global (to get the correct local port), and send a broadcast.
+            // TODO: Switch PacManager to have its own message to send back rather than
+            // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
+            if ((mGlobalProxy != null) && (proxyInfo != null)
+                    && (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
+                    && proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
+                mGlobalProxy = proxyInfo;
+                sendProxyBroadcast(mGlobalProxy);
+                return;
+            }
+            mDefaultProxy = proxyInfo;
+
+            if (mGlobalProxy != null) return;
+            if (!mDefaultProxyDisabled) {
+                sendProxyBroadcast(proxyInfo);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 62fe218..0230f75 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1349,8 +1349,11 @@
             // do not currently know how to watch for changes in DUN settings.
             maybeUpdateConfiguration();
 
-            final NetworkState ns = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
-                    mConfig.preferredUpstreamIfaceTypes);
+            final TetheringConfiguration config = mConfig;
+            final NetworkState ns = (config.chooseUpstreamAutomatically)
+                    ? mUpstreamNetworkMonitor.getCurrentPreferredUpstream()
+                    : mUpstreamNetworkMonitor.selectPreferredUpstreamType(
+                            config.preferredUpstreamIfaceTypes);
             if (ns == null) {
                 if (tryCell) {
                     mUpstreamNetworkMonitor.registerMobileNetworkRequest();
@@ -1379,9 +1382,7 @@
             }
             notifyDownstreamsOfNewUpstreamIface(ifaces);
             if (ns != null && pertainsToCurrentUpstream(ns)) {
-                // If we already have NetworkState for this network examine
-                // it immediately, because there likely will be no second
-                // EVENT_ON_AVAILABLE (it was already received).
+                // If we already have NetworkState for this network update it immediately.
                 handleNewUpstreamNetworkState(ns);
             } else if (mCurrentUpstreamIfaceSet == null) {
                 // There are no available upstream networks.
@@ -1497,15 +1498,6 @@
             }
 
             switch (arg1) {
-                case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
-                    // The default network changed, or DUN connected
-                    // before this callback was processed. Updates
-                    // for the current NetworkCapabilities and
-                    // LinkProperties have been requested (default
-                    // request) or are being sent shortly (DUN). Do
-                    // nothing until they arrive; if no updates
-                    // arrive there's nothing to do.
-                    break;
                 case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
                     handleNewUpstreamNetworkState(ns);
                     break;
@@ -1538,7 +1530,7 @@
                 }
 
                 mSimChange.startListening();
-                mUpstreamNetworkMonitor.start();
+                mUpstreamNetworkMonitor.start(mDeps.getDefaultNetworkRequest());
 
                 // TODO: De-duplicate with updateUpstreamWanted() below.
                 if (upstreamWanted()) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2fda08e..2a80f0e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -100,8 +100,6 @@
 import com.android.server.LocalServices;
 import com.android.server.net.BaseNetworkObserver;
 
-import libcore.io.IoUtils;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -117,11 +115,14 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import libcore.io.IoUtils;
+
 /**
  * @hide
  */
@@ -172,10 +173,13 @@
     private PendingIntent mStatusIntent;
     private volatile boolean mEnableTeardown = true;
     private final INetworkManagementService mNetd;
-    private VpnConfig mConfig;
-    private NetworkAgent mNetworkAgent;
+    @VisibleForTesting
+    protected VpnConfig mConfig;
+    @VisibleForTesting
+    protected NetworkAgent mNetworkAgent;
     private final Looper mLooper;
-    private final NetworkCapabilities mNetworkCapabilities;
+    @VisibleForTesting
+    protected final NetworkCapabilities mNetworkCapabilities;
     private final SystemServices mSystemServices;
 
     /**
@@ -316,15 +320,12 @@
         boolean roaming = false;
         boolean congested = false;
 
-        if (ArrayUtils.isEmpty(underlyingNetworks)) {
-            // No idea what the underlying networks are; assume sane defaults
-            metered = true;
-            roaming = false;
-            congested = false;
-        } else {
+        boolean hadUnderlyingNetworks = false;
+        if (null != underlyingNetworks) {
             for (Network underlying : underlyingNetworks) {
                 final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
                 if (underlyingCaps == null) continue;
+                hadUnderlyingNetworks = true;
                 for (int underlyingType : underlyingCaps.getTransportTypes()) {
                     transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
                 }
@@ -340,6 +341,12 @@
                 congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
             }
         }
+        if (!hadUnderlyingNetworks) {
+            // No idea what the underlying networks are; assume sane defaults
+            metered = true;
+            roaming = false;
+            congested = false;
+        }
 
         caps.setTransportTypes(transportTypes);
         caps.setLinkDownstreamBandwidthKbps(downKbps);
@@ -889,6 +896,42 @@
                 .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}.
+     */
+    private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
+        // NetworkMisc cannot be updated without registering a new NetworkAgent.
+        if (oldConfig.allowBypass != mConfig.allowBypass) {
+            Log.i(TAG, "Handover not possible due to changes to allowBypass");
+            return false;
+        }
+
+        // TODO: we currently do not support seamless handover if the allowed or disallowed
+        // applications have changed. Consider diffing UID ranges and only applying the delta.
+        if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) ||
+                !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) {
+            Log.i(TAG, "Handover not possible due to changes to whitelisted/blacklisted apps");
+            return false;
+        }
+
+        LinkProperties lp = makeLinkProperties();
+        final boolean hadInternetCapability = mNetworkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        final boolean willHaveInternetCapability = providesRoutesToMostDestinations(lp);
+        if (hadInternetCapability != willHaveInternetCapability) {
+            // A seamless handover would have led to a change to INTERNET capability, which
+            // is supposed to be immutable for a given network. In this case bail out and do not
+            // perform handover.
+            Log.i(TAG, "Handover not possible due to changes to INTERNET capability");
+            return false;
+        }
+
+        agent.sendLinkProperties(lp);
+        return true;
+    }
+
     private void agentConnect() {
         LinkProperties lp = makeLinkProperties();
 
@@ -997,13 +1040,11 @@
         String oldInterface = mInterface;
         Connection oldConnection = mConnection;
         NetworkAgent oldNetworkAgent = mNetworkAgent;
-        mNetworkAgent = null;
         Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
 
         // Configure the interface. Abort if any of these steps fails.
         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
         try {
-            updateState(DetailedState.CONNECTING, "establish");
             String interfaze = jniGetName(tun.getFd());
 
             // TEMP use the old jni calls until there is support for netd address setting
@@ -1031,15 +1072,26 @@
             mConfig = config;
 
             // Set up forwarding and DNS rules.
-            agentConnect();
+            // First attempt to do a seamless handover that only changes the interface name and
+            // parameters. If that fails, disconnect.
+            if (oldConfig != null
+                    && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
+                // Keep mNetworkAgent unchanged
+            } else {
+                mNetworkAgent = null;
+                updateState(DetailedState.CONNECTING, "establish");
+                // Set up forwarding and DNS rules.
+                agentConnect();
+                // Remove the old tun's user forwarding rules
+                // The new tun's user rules have already been added above so they will take over
+                // as rules are deleted. This prevents data leakage as the rules are moved over.
+                agentDisconnect(oldNetworkAgent);
+            }
 
             if (oldConnection != null) {
                 mContext.unbindService(oldConnection);
             }
-            // Remove the old tun's user forwarding rules
-            // The new tun's user rules have already been added so they will take over
-            // as rules are deleted. This prevents data leakage as the rules are moved over.
-            agentDisconnect(oldNetworkAgent);
+
             if (oldInterface != null && !oldInterface.equals(interfaze)) {
                 jniReset(oldInterface);
             }
@@ -1071,7 +1123,8 @@
 
     // Returns true if the VPN has been established and the calling UID is its owner. Used to check
     // that a call to mutate VPN state is admissible.
-    private boolean isCallerEstablishedOwnerLocked() {
+    @VisibleForTesting
+    protected boolean isCallerEstablishedOwnerLocked() {
         return isRunningLocked() && Binder.getCallingUid() == mOwnerUID;
     }
 
@@ -1274,6 +1327,18 @@
                     /* allowedApplications */ null,
                     /* disallowedApplications */ exemptedPackages);
 
+            // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
+            // directly from the kernel and is marked as uid=0. So we adjust the range to allow
+            // it through (b/69873852).
+            for (UidRange range : addedRanges) {
+                if (range.start == 0) {
+                    addedRanges.remove(range);
+                    if (range.stop != 0) {
+                        addedRanges.add(new UidRange(1, range.stop));
+                    }
+                }
+            }
+
             removedRanges.removeAll(addedRanges);
             addedRanges.removeAll(mBlockedUsers);
         }
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index cff216c..a3c2998 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -282,6 +282,7 @@
             return stats;
         }
 
+        @Override
         public void setInterfaceQuota(String iface, long quotaBytes) {
             mHandler.post(() -> {
                 if (quotaBytes == ITetheringStatsProvider.QUOTA_UNLIMITED) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 76195c4..207f867 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -355,6 +355,7 @@
         boolean success;
         String errMsg;
 
+        @Override
         public String toString() {
             if (success) {
                 return "ok";
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 5ed14a0..fbee86a 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.util.NetworkConstants.asByte;
+import static android.net.util.NetworkConstants.FF;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
 
 import android.net.ConnectivityManager;
@@ -64,6 +66,7 @@
  */
 public class TetherInterfaceStateMachine extends StateMachine {
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
+    private static final byte DOUG_ADAMS = (byte) 42;
 
     private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
     private static final int USB_PREFIX_LENGTH = 24;
@@ -185,7 +188,12 @@
 
     private boolean startIPv4() { return configureIPv4(true); }
 
-    private void stopIPv4() { configureIPv4(false); }
+    private void stopIPv4() {
+        configureIPv4(false);
+        // NOTE: All of configureIPv4() will be refactored out of existence
+        // into calls to InterfaceController, shared with startIPv4().
+        mInterfaceCtrl.clearIPv4Address();
+    }
 
     // TODO: Refactor this in terms of calls to InterfaceController.
     private boolean configureIPv4(boolean enabled) {
@@ -199,7 +207,7 @@
             ipAsString = USB_NEAR_IFACE_ADDR;
             prefixLen = USB_PREFIX_LENGTH;
         } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
-            ipAsString = WIFI_HOST_IFACE_ADDR;
+            ipAsString = getRandomWifiIPv4Address();
             prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
         } else {
             // Nothing to do, BT does this elsewhere.
@@ -248,6 +256,16 @@
         return true;
     }
 
+    private String getRandomWifiIPv4Address() {
+        try {
+            byte[] bytes = NetworkUtils.numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
+            bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
+            return InetAddress.getByAddress(bytes).getHostAddress();
+        } catch (Exception e) {
+            return WIFI_HOST_IFACE_ADDR;
+        }
+    }
+
     private boolean startIPv6() {
         mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
         if (mInterfaceParams == null) {
@@ -752,7 +770,7 @@
     // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
         final byte[] dnsBytes = localPrefix.getRawAddress();
-        dnsBytes[dnsBytes.length - 1] = getRandomNonZeroByte();
+        dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1));
         try {
             return Inet6Address.getByAddress(null, dnsBytes, 0);
         } catch (UnknownHostException e) {
@@ -761,10 +779,11 @@
         }
     }
 
-    private static byte getRandomNonZeroByte() {
+    private static byte getRandomSanitizedByte(byte dflt, byte... excluded) {
         final byte random = (byte) (new Random()).nextInt();
-        // Don't pick the subnet-router anycast address, since that might be
-        // in use on the upstream already.
-        return (random != 0) ? random : 0x1;
+        for (int value : excluded) {
+            if (random == value) return dflt;
+        }
+        return random;
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 454c579..dd9fe05 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -27,6 +27,7 @@
 import static com.android.internal.R.array.config_tether_usb_regexs;
 import static com.android.internal.R.array.config_tether_upstream_types;
 import static com.android.internal.R.array.config_tether_wifi_regexs;
+import static com.android.internal.R.bool.config_tether_upstream_automatic;
 import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;
 
 import android.content.Context;
@@ -86,6 +87,7 @@
     public final String[] tetherableBluetoothRegexs;
     public final int dunCheck;
     public final boolean isDunRequired;
+    public final boolean chooseUpstreamAutomatically;
     public final Collection<Integer> preferredUpstreamIfaceTypes;
     public final String[] dhcpRanges;
     public final String[] defaultIPv4DNS;
@@ -106,6 +108,7 @@
         dunCheck = checkDunRequired(ctx);
         configLog.log("DUN check returned: " + dunCheckString(dunCheck));
 
+        chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic);
         preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
         isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
 
@@ -142,6 +145,8 @@
         pw.print("isDunRequired: ");
         pw.println(isDunRequired);
 
+        pw.print("chooseUpstreamAutomatically: ");
+        pw.println(chooseUpstreamAutomatically);
         dumpStringArray(pw, "preferredUpstreamIfaceTypes",
                 preferredUpstreamNames(preferredUpstreamIfaceTypes));
 
@@ -160,6 +165,7 @@
         sj.add(String.format("tetherableBluetoothRegexs:%s",
                 makeString(tetherableBluetoothRegexs)));
         sj.add(String.format("isDunRequired:%s", isDunRequired));
+        sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically));
         sj.add(String.format("preferredUpstreamIfaceTypes:%s",
                 makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes))));
         sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
@@ -286,6 +292,14 @@
         }
     }
 
+    private static boolean getResourceBoolean(Context ctx, int resId) {
+        try {
+            return ctx.getResources().getBoolean(resId);
+        } catch (Resources.NotFoundException e404) {
+            return false;
+        }
+    }
+
     private static String[] getResourceStringArray(Context ctx, int resId) {
         try {
             final String[] strArray = ctx.getResources().getStringArray(resId);
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 0ac7a36..605ee9c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.net.INetd;
+import android.net.NetworkRequest;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetdService;
@@ -64,4 +65,8 @@
     public boolean isTetheringSupported() {
         return true;
     }
+
+    public NetworkRequest getDefaultNetworkRequest() {
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 3413291..f488be7 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,9 @@
 import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 
 import android.content.Context;
 import android.os.Handler;
@@ -74,14 +77,13 @@
     private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
-    public static final int EVENT_ON_AVAILABLE      = 1;
-    public static final int EVENT_ON_CAPABILITIES   = 2;
-    public static final int EVENT_ON_LINKPROPERTIES = 3;
-    public static final int EVENT_ON_LOST           = 4;
+    public static final int EVENT_ON_CAPABILITIES   = 1;
+    public static final int EVENT_ON_LINKPROPERTIES = 2;
+    public static final int EVENT_ON_LOST           = 3;
     public static final int NOTIFY_LOCAL_PREFIXES   = 10;
 
     private static final int CALLBACK_LISTEN_ALL = 1;
-    private static final int CALLBACK_TRACK_DEFAULT = 2;
+    private static final int CALLBACK_DEFAULT_INTERNET = 2;
     private static final int CALLBACK_MOBILE_REQUEST = 3;
 
     private final Context mContext;
@@ -117,7 +119,7 @@
         mCM = cm;
     }
 
-    public void start() {
+    public void start(NetworkRequest defaultNetworkRequest) {
         stop();
 
         final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
@@ -125,8 +127,16 @@
         mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
         cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
 
-        mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
-        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
+        if (defaultNetworkRequest != null) {
+            // This is not really a "request", just a way of tracking the system default network.
+            // It's guaranteed not to actually bring up any networks because it's the same request
+            // as the ConnectivityService default request, and thus shares fate with it. We can't
+            // use registerDefaultNetworkCallback because it will not track the system default
+            // network if there is a VPN that applies to our UID.
+            final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest);
+            mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
+            cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler);
+        }
     }
 
     public void stop() {
@@ -225,6 +235,20 @@
         return typeStatePair.ns;
     }
 
+    // Returns null if no current upstream available.
+    public NetworkState getCurrentPreferredUpstream() {
+        final NetworkState dfltState = (mDefaultInternetNetwork != null)
+                ? mNetworkMap.get(mDefaultInternetNetwork)
+                : null;
+        if (!mDunRequired) return dfltState;
+
+        if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
+
+        // Find a DUN network. Note that code in Tethering causes a DUN request
+        // to be filed, but this might be moved into this class in future.
+        return findFirstDunNetwork(mNetworkMap.values());
+    }
+
     public void setCurrentUpstream(Network upstream) {
         mTetheringUpstreamNetwork = upstream;
     }
@@ -233,72 +257,16 @@
         return (Set<IpPrefix>) mLocalPrefixes.clone();
     }
 
-    private void handleAvailable(int callbackType, Network network) {
-        if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
+    private void handleAvailable(Network network) {
+        if (mNetworkMap.containsKey(network)) return;
 
-        if (!mNetworkMap.containsKey(network)) {
-            mNetworkMap.put(network,
-                    new NetworkState(null, null, null, network, null, null));
-        }
-
-        // Always request whatever extra information we can, in case this
-        // was already up when start() was called, in which case we would
-        // not have been notified of any information that had not changed.
-        switch (callbackType) {
-            case CALLBACK_LISTEN_ALL:
-                break;
-
-            case CALLBACK_TRACK_DEFAULT:
-                if (mDefaultNetworkCallback == null) {
-                    // The callback was unregistered in the interval between
-                    // ConnectivityService enqueueing onAvailable() and our
-                    // handling of it here on the mHandler thread.
-                    //
-                    // Clean-up of this network entry is deferred to the
-                    // handling of onLost() by other callbacks.
-                    //
-                    // These request*() calls can be deleted post oag/339444.
-                    return;
-                }
-                mDefaultInternetNetwork = network;
-                break;
-
-            case CALLBACK_MOBILE_REQUEST:
-                if (mMobileNetworkCallback == null) {
-                    // The callback was unregistered in the interval between
-                    // ConnectivityService enqueueing onAvailable() and our
-                    // handling of it here on the mHandler thread.
-                    //
-                    // Clean-up of this network entry is deferred to the
-                    // handling of onLost() by other callbacks.
-                    return;
-                }
-                break;
-        }
-
-        // Requesting updates for mListenAllCallback is not currently possible
-        // because it's a "listen". Two possible solutions to getting updates
-        // about networks without waiting for a change (which might never come)
-        // are:
-        //
-        //     [1] extend request{NetworkCapabilities,LinkProperties}() to
-        //         take a Network argument and have ConnectivityService do
-        //         what's required (if the network satisfies the request)
-        //
-        //     [2] explicitly file a NetworkRequest for each connectivity type
-        //         listed as a preferred upstream and wait for these callbacks
-        //         to be notified (requires tracking many more callbacks).
-        //
-        // Until this is addressed, networks that exist prior to the "listen"
-        // registration and which do not subsequently change will not cause
-        // us to learn their NetworkCapabilities nor their LinkProperties.
-
-        // TODO: If sufficient information is available to select a more
-        // preferable upstream, do so now and notify the target.
-        notifyTarget(EVENT_ON_AVAILABLE, network);
+        if (VDBG) Log.d(TAG, "onAvailable for " + network);
+        mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null));
     }
 
-    private void handleNetCap(Network network, NetworkCapabilities newNc) {
+    private void handleNetCap(int callbackType, Network network, NetworkCapabilities newNc) {
+        if (callbackType == CALLBACK_DEFAULT_INTERNET) mDefaultInternetNetwork = network;
+
         final NetworkState prev = mNetworkMap.get(network);
         if (prev == null || newNc.equals(prev.networkCapabilities)) {
             // Ignore notifications about networks for which we have not yet
@@ -360,13 +328,17 @@
     }
 
     private void handleLost(int callbackType, Network network) {
-        if (callbackType == CALLBACK_TRACK_DEFAULT) {
+        if (network.equals(mDefaultInternetNetwork)) {
             mDefaultInternetNetwork = null;
-            // Receiving onLost() for a default network does not necessarily
-            // mean the network is gone.  We wait for a separate notification
-            // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
-            // clearing all state.
-            return;
+            // There are few TODOs within ConnectivityService's rematching code
+            // pertaining to spurious onLost() notifications.
+            //
+            // TODO: simplify this, probably if favor of code that:
+            //     - selects a new upstream if mTetheringUpstreamNetwork has
+            //       been lost (by any callback)
+            //     - deletes the entry from the map only when the LISTEN_ALL
+            //       callback gets  notified.
+            if (callbackType == CALLBACK_DEFAULT_INTERNET) return;
         }
 
         if (!mNetworkMap.containsKey(network)) {
@@ -416,17 +388,19 @@
 
         @Override
         public void onAvailable(Network network) {
-            handleAvailable(mCallbackType, network);
+            handleAvailable(network);
         }
 
         @Override
         public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
-            handleNetCap(network, newNc);
+            handleNetCap(mCallbackType, network, newNc);
         }
 
         @Override
         public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
             handleLinkProp(network, newLp);
+            // TODO(b/110335330): reduce the number of times this is called by
+            // only recomputing on the LISTEN_ALL callback.
             recomputeLocalPrefixes();
         }
 
@@ -443,6 +417,8 @@
         @Override
         public void onLost(Network network) {
             handleLost(mCallbackType, network);
+            // TODO(b/110335330): reduce the number of times this is called by
+            // only recomputing on the LISTEN_ALL callback.
             recomputeLocalPrefixes();
         }
     }
@@ -509,4 +485,31 @@
         if (nc == null || !nc.hasSignalStrength()) return "unknown";
         return Integer.toString(nc.getSignalStrength());
     }
+
+    private static boolean isCellular(NetworkState ns) {
+        return (ns != null) && isCellular(ns.networkCapabilities);
+    }
+
+    private static boolean isCellular(NetworkCapabilities nc) {
+        return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR) &&
+               nc.hasCapability(NET_CAPABILITY_NOT_VPN);
+    }
+
+    private static boolean hasCapability(NetworkState ns, int netCap) {
+        return (ns != null) && (ns.networkCapabilities != null) &&
+               ns.networkCapabilities.hasCapability(netCap);
+    }
+
+    private static boolean isNetworkUsableAndNotCellular(NetworkState ns) {
+        return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null) &&
+               !isCellular(ns.networkCapabilities);
+    }
+
+    private static NetworkState findFirstDunNetwork(Iterable<NetworkState> netStates) {
+        for (NetworkState ns : netStates) {
+            if (isCellular(ns) && hasCapability(ns, NET_CAPABILITY_DUN)) return ns;
+        }
+
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 0cba76b..f6b032e 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -514,8 +514,7 @@
     static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
         byte[] params = message.getParams();
         return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
-                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
-                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION
+                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION
                         || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index da40692..e5cf394 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -179,6 +179,8 @@
 
     private final PowerManager.WakeLock mWakeLock;
 
+    private final boolean mUseBpfTrafficStats;
+
     private IConnectivityManager mConnManager;
 
     @VisibleForTesting
@@ -328,6 +330,7 @@
         mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
         mSystemDir = checkNotNull(systemDir, "missing systemDir");
         mBaseDir = checkNotNull(baseDir, "missing baseDir");
+        mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
     }
 
     @VisibleForTesting
@@ -916,7 +919,7 @@
     }
 
     private boolean checkBpfStatsEnable() {
-        return new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
+        return mUseBpfTrafficStats;
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 502a21c..5b2bc9e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -559,7 +559,7 @@
     {
         final int pid;
         final String pkg;
-        ITransientNotification callback;
+        final ITransientNotification callback;
         int duration;
         Binder token;
 
@@ -576,10 +576,6 @@
             this.duration = duration;
         }
 
-        void update(ITransientNotification callback) {
-            this.callback = callback;
-        }
-
         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
             if (filter != null && !filter.matches(pkg)) return;
             pw.println(prefix + this);
@@ -1648,28 +1644,38 @@
                 long callingId = Binder.clearCallingIdentity();
                 try {
                     ToastRecord record;
-                    int index;
-                    // All packages aside from the android package can enqueue one toast at a time
-                    if (!isSystemToast) {
-                        index = indexOfToastPackageLocked(pkg);
-                    } else {
-                        index = indexOfToastLocked(pkg, callback);
-                    }
-
-                    // If the package already has a toast, we update its toast
-                    // in the queue, we don't move it to the end of the queue.
+                    int index = indexOfToastLocked(pkg, callback);
+                    // If it's already in the queue, we update it in place, we don't
+                    // move it to the end of the queue.
                     if (index >= 0) {
                         record = mToastQueue.get(index);
                         record.update(duration);
-                        record.update(callback);
                     } else {
+                        // Limit the number of toasts that any given package except the android
+                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
+                        if (!isSystemToast) {
+                            int count = 0;
+                            final int N = mToastQueue.size();
+                            for (int i=0; i<N; i++) {
+                                 final ToastRecord r = mToastQueue.get(i);
+                                 if (r.pkg.equals(pkg)) {
+                                     count++;
+                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+                                         Slog.e(TAG, "Package has already posted " + count
+                                                + " toasts. Not showing more. Package=" + pkg);
+                                         return;
+                                     }
+                                 }
+                            }
+                        }
+
                         Binder token = new Binder();
                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
+                        keepProcessAliveIfNeededLocked(callingPid);
                     }
-                    keepProcessAliveIfNeededLocked(callingPid);
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
                     // new or just been updated.  Call back and tell it to show itself.
                     // If the callback fails, this will remove it from the list, so don't
@@ -4328,21 +4334,7 @@
         int len = list.size();
         for (int i=0; i<len; i++) {
             ToastRecord r = list.get(i);
-            if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    @GuardedBy("mToastQueue")
-    int indexOfToastPackageLocked(String pkg)
-    {
-        ArrayList<ToastRecord> list = mToastQueue;
-        int len = list.size();
-        for (int i=0; i<len; i++) {
-            ToastRecord r = list.get(i);
-            if (r.pkg.equals(pkg)) {
+            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
                 return i;
             }
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0971058..521d558 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6819,7 +6819,7 @@
             } else {
                 if (DEBUG_WAKEUP) Slog.d(TAG,
                         "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
-                finishKeyguardDrawn();
+                mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
             }
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 338ad2a..f2a7d42 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -220,8 +220,8 @@
     private static final int HALT_MODE_REBOOT = 1;
     private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
 
-    // Persistent property for last reboot reason
-    private static final String LAST_REBOOT_PROPERTY = "persist.sys.boot.reason";
+    // property for last reboot reason
+    private static final String REBOOT_PROPERTY = "sys.boot.reason";
 
     private final Context mContext;
     private final ServiceThread mHandlerThread;
@@ -4402,7 +4402,7 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                return getLastShutdownReasonInternal(LAST_REBOOT_PROPERTY);
+                return getLastShutdownReasonInternal(REBOOT_PROPERTY);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
new file mode 100644
index 0000000..7bdc8a3
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.timedetector.TimeSignal;
+import android.content.Intent;
+import android.util.Slog;
+import android.util.TimestampedValue;
+
+import com.android.internal.telephony.TelephonyIntents;
+
+import java.io.PrintWriter;
+
+/**
+ * An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
+ * {@link AlarmManager}. The TimeDetectorService handles thread safety: all calls to
+ * this class can be assumed to be single threaded (though the thread used may vary).
+ */
+// @NotThreadSafe
+public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
+
+    private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
+
+    /**
+     * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
+     * actual system clock time before a warning is logged. Used to help identify situations where
+     * there is something other than this class setting the system clock.
+     */
+    private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
+
+    // @NonNull after initialize()
+    private Callback mCallback;
+
+    // NITZ state.
+    @Nullable private TimestampedValue<Long> mLastNitzTime;
+
+
+    // Information about the last time signal received: Used when toggling auto-time.
+    @Nullable private TimestampedValue<Long> mLastSystemClockTime;
+    private boolean mLastSystemClockTimeSendNetworkBroadcast;
+
+    // System clock state.
+    @Nullable private TimestampedValue<Long> mLastSystemClockTimeSet;
+
+    @Override
+    public void initialize(@NonNull Callback callback) {
+        mCallback = callback;
+    }
+
+    @Override
+    public void suggestTime(@NonNull TimeSignal timeSignal) {
+        if (!TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId())) {
+            Slog.w(TAG, "Ignoring signal from unsupported source: " + timeSignal);
+            return;
+        }
+
+        // NITZ logic
+
+        TimestampedValue<Long> newNitzUtcTime = timeSignal.getUtcTime();
+        boolean nitzTimeIsValid = validateNewNitzTime(newNitzUtcTime, mLastNitzTime);
+        if (!nitzTimeIsValid) {
+            return;
+        }
+        // Always store the last NITZ value received, regardless of whether we go on to use it to
+        // update the system clock. This is so that we can validate future NITZ signals.
+        mLastNitzTime = newNitzUtcTime;
+
+        // System clock update logic.
+
+        // Historically, Android has sent a telephony broadcast only when setting the time using
+        // NITZ.
+        final boolean sendNetworkBroadcast =
+                TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId());
+
+        final TimestampedValue<Long> newUtcTime = newNitzUtcTime;
+        setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
+    }
+
+    private static boolean validateNewNitzTime(TimestampedValue<Long> newNitzUtcTime,
+            TimestampedValue<Long> lastNitzTime) {
+
+        if (lastNitzTime != null) {
+            long referenceTimeDifference =
+                    TimestampedValue.referenceTimeDifference(newNitzUtcTime, lastNitzTime);
+            if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
+                // Out of order or bogus.
+                Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+                        + " referenceTimeDifference=" + referenceTimeDifference
+                        + " lastNitzTime=" + lastNitzTime
+                        + " newNitzUtcTime=" + newNitzUtcTime);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void setSystemClockIfRequired(
+            TimestampedValue<Long> time, boolean sendNetworkBroadcast) {
+
+        // Store the last candidate we've seen in all cases so we can set the system clock
+        // when/if time detection is enabled.
+        mLastSystemClockTime = time;
+        mLastSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
+
+        if (!mCallback.isTimeDetectionEnabled()) {
+            Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
+            return;
+        }
+
+        mCallback.acquireWakeLock();
+        try {
+            long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+            long actualTimeMillis = mCallback.systemClockMillis();
+
+            // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
+            // may be setting the clock.
+            if (mLastSystemClockTimeSet != null) {
+                long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
+                        mLastSystemClockTimeSet, elapsedRealtimeMillis);
+                long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
+                if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
+                    Slog.w(TAG, "System clock has not tracked elapsed real time clock. A clock may"
+                            + " be inaccurate or something unexpectedly set the system clock."
+                            + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+                            + " expectedTimeMillis=" + expectedTimeMillis
+                            + " actualTimeMillis=" + actualTimeMillis);
+                }
+            }
+
+            final String reason = "New time signal";
+            adjustAndSetDeviceSystemClock(
+                    time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, reason);
+        } finally {
+            mCallback.releaseWakeLock();
+        }
+    }
+
+    @Override
+    public void handleAutoTimeDetectionToggle(boolean enabled) {
+        // If automatic time detection is enabled we update the system clock instantly if we can.
+        // Conversely, if automatic time detection is disabled we leave the clock as it is.
+        if (enabled) {
+            if (mLastSystemClockTime != null) {
+                // Only send the network broadcast if the last candidate would have caused one.
+                final boolean sendNetworkBroadcast = mLastSystemClockTimeSendNetworkBroadcast;
+
+                mCallback.acquireWakeLock();
+                try {
+                    long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
+                    long actualTimeMillis = mCallback.systemClockMillis();
+
+                    final String reason = "Automatic time detection enabled.";
+                    adjustAndSetDeviceSystemClock(mLastSystemClockTime, sendNetworkBroadcast,
+                            elapsedRealtimeMillis, actualTimeMillis, reason);
+                } finally {
+                    mCallback.releaseWakeLock();
+                }
+            }
+        } else {
+            // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
+            // it should be in future.
+            mLastSystemClockTimeSet = null;
+        }
+    }
+
+    @Override
+    public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+        pw.println("mLastNitzTime=" + mLastNitzTime);
+        pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
+        pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
+        pw.println("mLastSystemClockTimeSendNetworkBroadcast="
+                + mLastSystemClockTimeSendNetworkBroadcast);
+    }
+
+    private void adjustAndSetDeviceSystemClock(
+            TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
+            long elapsedRealtimeMillis, long actualSystemClockMillis, String reason) {
+
+        // Adjust for the time that has elapsed since the signal was received.
+        long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
+
+        // Check if the new signal would make sufficient difference to the system clock. If it's
+        // below the threshold then ignore it.
+        long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
+        long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis();
+        if (absTimeDifference < systemClockUpdateThreshold) {
+            Slog.d(TAG, "adjustAndSetDeviceSystemClock: Not setting system clock. New time and"
+                    + " system clock are close enough."
+                    + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+                    + " newTime=" + newTime
+                    + " reason=" + reason
+                    + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+                    + " absTimeDifference=" + absTimeDifference);
+            return;
+        }
+
+        Slog.d(TAG, "Setting system clock using time=" + newTime
+                + " reason=" + reason
+                + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+                + " newTimeMillis=" + newSystemClockMillis);
+        mCallback.setSystemClock(newSystemClockMillis);
+
+        // CLOCK_PARANOIA : Record the last time this class set the system clock.
+        mLastSystemClockTimeSet = newTime;
+
+        if (sendNetworkBroadcast) {
+            // Send a broadcast that telephony code used to send after setting the clock.
+            // TODO Remove this broadcast as soon as there are no remaining listeners.
+            Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.putExtra("time", newSystemClockMillis);
+            mCallback.sendStickyBroadcast(intent);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
new file mode 100644
index 0000000..9c83000
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timedetector.ITimeDetectorService;
+import android.app.timedetector.TimeSignal;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Binder;
+import android.provider.Settings;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+import com.android.server.timedetector.TimeDetectorStrategy.Callback;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Objects;
+
+public final class TimeDetectorService extends ITimeDetectorService.Stub {
+    private static final String TAG = "timedetector.TimeDetectorService";
+
+    public static class Lifecycle extends SystemService {
+
+        public Lifecycle(@NonNull Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            TimeDetectorService service = TimeDetectorService.create(getContext());
+
+            // Publish the binder service so it can be accessed from other (appropriately
+            // permissioned) processes.
+            publishBinderService(Context.TIME_DETECTOR_SERVICE, service);
+        }
+    }
+
+    @NonNull private final Context mContext;
+    @NonNull private final Callback mCallback;
+
+    // The lock used when call the strategy to ensure thread safety.
+    @NonNull private final Object mStrategyLock = new Object();
+
+    @GuardedBy("mStrategyLock")
+    @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+
+    private static TimeDetectorService create(@NonNull Context context) {
+        final TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
+        final TimeDetectorStrategyCallbackImpl callback =
+                new TimeDetectorStrategyCallbackImpl(context);
+        timeDetector.initialize(callback);
+
+        TimeDetectorService timeDetectorService =
+                new TimeDetectorService(context, callback, timeDetector);
+
+        // Wire up event listening.
+        ContentResolver contentResolver = context.getContentResolver();
+        contentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
+                new ContentObserver(FgThread.getHandler()) {
+                    public void onChange(boolean selfChange) {
+                        timeDetectorService.handleAutoTimeDetectionToggle();
+                    }
+                });
+
+        return timeDetectorService;
+    }
+
+    @VisibleForTesting
+    public TimeDetectorService(@NonNull Context context, @NonNull Callback callback,
+            @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+        mContext = Objects.requireNonNull(context);
+        mCallback = Objects.requireNonNull(callback);
+        mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
+    }
+
+    @Override
+    public void suggestTime(@NonNull TimeSignal timeSignal) {
+        enforceSetTimePermission();
+        Objects.requireNonNull(timeSignal);
+
+        long idToken = Binder.clearCallingIdentity();
+        try {
+            synchronized (mStrategyLock) {
+                mTimeDetectorStrategy.suggestTime(timeSignal);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(idToken);
+        }
+    }
+
+    @VisibleForTesting
+    public void handleAutoTimeDetectionToggle() {
+        synchronized (mStrategyLock) {
+            final boolean timeDetectionEnabled = mCallback.isTimeDetectionEnabled();
+            mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
+        }
+    }
+
+    @Override
+    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+            @Nullable String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+        synchronized (mStrategyLock) {
+            mTimeDetectorStrategy.dump(pw, args);
+        }
+    }
+
+    private void enforceSetTimePermission() {
+        mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
new file mode 100644
index 0000000..e050865
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timedetector.TimeSignal;
+import android.content.Intent;
+import android.util.TimestampedValue;
+
+import java.io.PrintWriter;
+
+/**
+ * The interface for classes that implement the time detection algorithm used by the
+ * TimeDetectorService. The TimeDetectorService handles thread safety: all calls to implementations
+ * of this interface can be assumed to be single threaded (though the thread used may vary).
+ *
+ * @hide
+ */
+// @NotThreadSafe
+public interface TimeDetectorStrategy {
+
+    /**
+     * The interface used by the strategy to interact with the surrounding service.
+     */
+    interface Callback {
+
+        /**
+         * The absolute threshold below which the system clock need not be updated. i.e. if setting
+         * the system clock would adjust it by less than this (either backwards or forwards) then it
+         * need not be set.
+         */
+        int systemClockUpdateThresholdMillis();
+
+        /** Returns true if automatic time detection is enabled. */
+        boolean isTimeDetectionEnabled();
+
+        /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
+        void acquireWakeLock();
+
+        /** Returns the elapsedRealtimeMillis clock value. The WakeLock must be held. */
+        long elapsedRealtimeMillis();
+
+        /** Returns the system clock value. The WakeLock must be held. */
+        long systemClockMillis();
+
+        /** Sets the device system clock. The WakeLock must be held. */
+        void setSystemClock(long newTimeMillis);
+
+        /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
+        void releaseWakeLock();
+
+        /** Send the supplied intent as a stick broadcast. */
+        void sendStickyBroadcast(@NonNull Intent intent);
+    }
+
+    /** Initialize the strategy. */
+    void initialize(@NonNull Callback callback);
+
+    /** Process the suggested time. */
+    void suggestTime(@NonNull TimeSignal timeSignal);
+
+    /** Handle the auto-time setting being toggled on or off. */
+    void handleAutoTimeDetectionToggle(boolean enabled);
+
+    /** Dump debug information. */
+    void dump(@NonNull PrintWriter pw, @Nullable String[] args);
+
+    // Utility methods below are to be moved to a better home when one becomes more obvious.
+
+    /**
+     * Adjusts the supplied time value by applying the difference between the reference time
+     * supplied and the reference time associated with the time.
+     */
+    static long getTimeAt(@NonNull TimestampedValue<Long> timeValue, long referenceClockMillisNow) {
+        return (referenceClockMillisNow - timeValue.getReferenceTimeMillis())
+                + timeValue.getValue();
+    }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
new file mode 100644
index 0000000..77b9e62
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.app.AlarmManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * The real implementation of {@link TimeDetectorStrategy.Callback} used on device.
+ */
+public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrategy.Callback {
+
+    private final static String TAG = "timedetector.TimeDetectorStrategyCallbackImpl";
+
+    private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
+
+    /**
+     * If a newly calculated system clock time and the current system clock time differs by this or
+     * more the system clock will actually be updated. Used to prevent the system clock being set
+     * for only minor differences.
+     */
+    private final int mSystemClockUpdateThresholdMillis;
+
+    @NonNull private final Context mContext;
+    @NonNull private final ContentResolver mContentResolver;
+    @NonNull private final PowerManager.WakeLock mWakeLock;
+    @NonNull private final AlarmManager mAlarmManager;
+
+    public TimeDetectorStrategyCallbackImpl(@NonNull Context context) {
+        mContext = Objects.requireNonNull(context);
+        mContentResolver = Objects.requireNonNull(context.getContentResolver());
+
+        PowerManager powerManager = context.getSystemService(PowerManager.class);
+        mWakeLock = Objects.requireNonNull(
+                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG));
+
+        mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
+
+        mSystemClockUpdateThresholdMillis =
+                SystemProperties.getInt("ro.sys.time_detector_update_diff",
+                        SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
+    }
+
+    @Override
+    public int systemClockUpdateThresholdMillis() {
+        return mSystemClockUpdateThresholdMillis;
+    }
+
+    @Override
+    public boolean isTimeDetectionEnabled() {
+        try {
+            return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
+        } catch (Settings.SettingNotFoundException snfe) {
+            return true;
+        }
+    }
+
+    @Override
+    public void acquireWakeLock() {
+        if (mWakeLock.isHeld()) {
+            Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
+        }
+        mWakeLock.acquire();
+    }
+
+    @Override
+    public long elapsedRealtimeMillis() {
+        checkWakeLockHeld();
+        return SystemClock.elapsedRealtime();
+    }
+
+    @Override
+    public long systemClockMillis() {
+        checkWakeLockHeld();
+        return System.currentTimeMillis();
+    }
+
+    @Override
+    public void setSystemClock(long newTimeMillis) {
+        checkWakeLockHeld();
+        mAlarmManager.setTime(newTimeMillis);
+    }
+
+    @Override
+    public void releaseWakeLock() {
+        checkWakeLockHeld();
+        mWakeLock.release();
+    }
+
+    @Override
+    public void sendStickyBroadcast(@NonNull Intent intent) {
+        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private void checkWakeLockHeld() {
+        if (!mWakeLock.isHeld()) {
+            Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
new file mode 100644
index 0000000..5f71b0b
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService;
+import android.app.timezonedetector.ITimeZoneDetectorService;
+import android.content.Context;
+import android.util.Slog;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub {
+    private static final String TAG = "timezonedetector.TimeZoneDetectorService";
+
+    public static class Lifecycle extends SystemService {
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            TimeZoneDetectorService service = TimeZoneDetectorService.create(getContext());
+            // Publish the binder service so it can be accessed from other (appropriately
+            // permissioned) processes.
+            publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
+        }
+    }
+
+    private final Context mContext;
+
+    private static TimeZoneDetectorService create(Context context) {
+        return new TimeZoneDetectorService(context);
+    }
+
+    public TimeZoneDetectorService(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void stubbedCall() {
+        // Empty call for initial tests.
+        Slog.d(TAG, "stubbedCall() called");
+        // TODO: Remove when there are real methods.
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+        // TODO: Implement when there is state.
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 60f201f..a602ab1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -204,6 +204,10 @@
             "com.android.server.autofill.AutofillManagerService";
     private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
             "com.android.server.timezone.RulesManagerService$Lifecycle";
+    private static final String TIME_DETECTOR_SERVICE_CLASS =
+            "com.android.server.timedetector.TimeDetectorService$Lifecycle";
+    private static final String TIME_ZONE_DETECTOR_SERVICE_CLASS =
+            "com.android.server.timezonedetector.TimeZoneDetectorService$Lifecycle";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -690,7 +694,6 @@
         WindowManagerService wm = null;
         SerialService serial = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
-        CommonTimeManagementService commonTimeMgmtService = null;
         InputManagerService inputManager = null;
         TelephonyRegistry telephonyRegistry = null;
         ConsumerIrService consumerIr = null;
@@ -1202,6 +1205,25 @@
                 traceEnd();
             }
 
+            final boolean useNewTimeServices = true;
+            if (useNewTimeServices) {
+                traceBeginAndSlog("StartTimeDetectorService");
+                try {
+                    mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
+                } catch (Throwable e) {
+                    reportWtf("starting StartTimeDetectorService service", e);
+                }
+                traceEnd();
+
+                traceBeginAndSlog("StartTimeZoneDetectorService");
+                try {
+                    mSystemServiceManager.startService(TIME_ZONE_DETECTOR_SERVICE_CLASS);
+                } catch (Throwable e) {
+                    reportWtf("starting StartTimeZoneDetectorService service", e);
+                }
+                traceEnd();
+            }
+
             if (!disableNonCoreServices && !disableSearchManager) {
                 traceBeginAndSlog("StartSearchManagerService");
                 try {
@@ -1375,7 +1397,12 @@
             if (!disableNetwork && !disableNetworkTime) {
                 traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
-                    networkTimeUpdater = new NetworkTimeUpdateService(context);
+                    if (useNewTimeServices) {
+                        networkTimeUpdater = new NewNetworkTimeUpdateService(context);
+                    } else {
+                        networkTimeUpdater = new OldNetworkTimeUpdateService(context);
+                    }
+                    Slog.d(TAG, "Using networkTimeUpdater class=" + networkTimeUpdater.getClass());
                     ServiceManager.addService("network_time_update_service", networkTimeUpdater);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkTimeUpdate service", e);
@@ -1383,15 +1410,6 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("StartCommonTimeManagementService");
-            try {
-                commonTimeMgmtService = new CommonTimeManagementService(context);
-                ServiceManager.addService("commontime_management", commonTimeMgmtService);
-            } catch (Throwable e) {
-                reportWtf("starting CommonTimeManagementService service", e);
-            }
-            traceEnd();
-
             if (!disableNetwork) {
                 traceBeginAndSlog("CertBlacklister");
                 try {
@@ -1667,7 +1685,6 @@
         final LocationManagerService locationF = location;
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
-        final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
@@ -1813,15 +1830,6 @@
                 reportWtf("Notifying NetworkTimeService running", e);
             }
             traceEnd();
-            traceBeginAndSlog("MakeCommonTimeManagementServiceReady");
-            try {
-                if (commonTimeMgmtServiceF != null) {
-                    commonTimeMgmtServiceF.systemRunning();
-                }
-            } catch (Throwable e) {
-                reportWtf("Notifying CommonTimeManagementService running", e);
-            }
-            traceEnd();
             traceBeginAndSlog("MakeInputManagerServiceReady");
             try {
                 // TODO(BT) Pass parameter to input manager
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 63ae09a..7f821ff 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -231,10 +231,10 @@
     // TODO: Find an lighter weight approach.
     private class LoggingCallbackWrapper extends Callback {
         private static final String PREFIX = "INVOKE ";
-        private Callback mCallback;
+        private final Callback mCallback;
 
         public LoggingCallbackWrapper(Callback callback) {
-            mCallback = callback;
+            mCallback = (callback != null) ? callback : new Callback();
         }
 
         private void log(String msg) {
@@ -605,6 +605,13 @@
     private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
 
+    // Internal commands to use instead of trying to call transitionTo() inside
+    // a given State's enter() method. Calling transitionTo() from enter/exit
+    // encounters a Log.wtf() that can cause trouble on eng builds.
+    private static final int CMD_JUMP_STARTED_TO_RUNNING          = 100;
+    private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
+    private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
+
     private static final int MAX_LOG_RECORDS = 500;
     private static final int MAX_PACKET_RECORDS = 100;
 
@@ -1418,6 +1425,9 @@
 
             resetLinkProperties();
             if (mStartTimeMillis > 0) {
+                // Completed a life-cycle; send a final empty LinkProperties
+                // (cleared in resetLinkProperties() above) and record an event.
+                mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
                 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
                 mStartTimeMillis = 0;
             }
@@ -1476,13 +1486,17 @@
         public void enter() {
             if (mDhcpClient == null) {
                 // There's no DHCPv4 for which to wait; proceed to stopped.
-                transitionTo(mStoppedState);
+                deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
             }
         }
 
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_JUMP_STOPPING_TO_STOPPED:
+                    transitionTo(mStoppedState);
+                    break;
+
                 case CMD_STOP:
                     break;
 
@@ -1516,7 +1530,7 @@
             }
 
             if (readyToProceed()) {
-                transitionTo(mRunningState);
+                deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
             } else {
                 // Clear all IPv4 and IPv6 before proceeding to RunningState.
                 // Clean up any leftover state from an abnormal exit from
@@ -1533,6 +1547,10 @@
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_JUMP_STARTED_TO_RUNNING:
+                    transitionTo(mRunningState);
+                    break;
+
                 case CMD_STOP:
                     transitionTo(mStoppingState);
                     break;
@@ -1561,7 +1579,7 @@
             return HANDLED;
         }
 
-        boolean readyToProceed() {
+        private boolean readyToProceed() {
             return (!mLinkProperties.hasIPv4Address() &&
                     !mLinkProperties.hasGlobalIPv6Address());
         }
@@ -1593,13 +1611,13 @@
 
             if (mConfiguration.mEnableIPv6 && !startIPv6()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
 
             if (mConfiguration.mEnableIPv4 && !startIPv4()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
 
@@ -1607,7 +1625,7 @@
             if ((config != null) && !applyInitialConfig(config)) {
                 // TODO introduce a new IpManagerEvent constant to distinguish this error case.
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
 
@@ -1621,7 +1639,7 @@
             if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
                 doImmediateProvisioningFailure(
                         IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
         }
@@ -1658,6 +1676,10 @@
             resetLinkProperties();
         }
 
+        private void enqueueJumpToStoppingState() {
+            deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
+        }
+
         private ConnectivityPacketTracker createPacketTracker() {
             try {
                 return new ConnectivityPacketTracker(
@@ -1688,6 +1710,7 @@
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_JUMP_RUNNING_TO_STOPPING:
                 case CMD_STOP:
                     transitionTo(mStoppingState);
                     break;
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 53fd01f..de04fd0 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -53,7 +53,7 @@
 
     public static final int ETHER_HEADER_LEN = 14;
 
-    private static final byte FF = asByte(0xff);
+    public static final byte FF = asByte(0xff);
     public static final byte[] ETHER_ADDR_BROADCAST = {
         FF, FF, FF, FF, FF, FF
     };
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
new file mode 100644
index 0000000..62f1433
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.timedetector.TimeSignal;
+import android.content.Intent;
+import android.icu.util.Calendar;
+import android.icu.util.GregorianCalendar;
+import android.icu.util.TimeZone;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.TimestampedValue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SimpleTimeZoneDetectorStrategyTest {
+
+    private static final Scenario SCENARIO_1 = new Scenario.Builder()
+            .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
+            .setInitialDeviceRealtimeMillis(123456789L)
+            .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
+            .build();
+
+    private Script mScript;
+
+    @Before
+    public void setUp() {
+        mScript = new Script();
+    }
+
+    @Test
+    public void testSuggestTime_nitz_timeDetectionEnabled() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(true);
+
+        TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+        final int clockIncrement = 1000;
+        long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+
+        mScript.simulateTimePassing(clockIncrement)
+                .simulateTimeSignalReceived(timeSignal)
+                .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
+    }
+
+    @Test
+    public void testSuggestTime_systemClockThreshold() {
+        Scenario scenario = SCENARIO_1;
+        final int systemClockUpdateThresholdMillis = 1000;
+        mScript.pokeFakeClocks(scenario)
+                .pokeThresholds(systemClockUpdateThresholdMillis)
+                .pokeTimeDetectionEnabled(true);
+
+        TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+        TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+
+        final int clockIncrement = 100;
+        // Increment the the device clocks to simulate the passage of time.
+        mScript.simulateTimePassing(clockIncrement);
+
+        long expectSystemClockMillis1 =
+                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+        // Send the first time signal. It should be used.
+        mScript.simulateTimeSignalReceived(timeSignal1)
+                .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
+
+        // Now send another time signal, but one that is too similar to the last one and should be
+        // ignored.
+        int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
+        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+                mScript.peekElapsedRealtimeMillis(),
+                mScript.peekSystemClockMillis() + underThresholdMillis);
+        TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+        mScript.simulateTimePassing(clockIncrement)
+                .simulateTimeSignalReceived(timeSignal2)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Now send another time signal, but one that is on the threshold and so should be used.
+        TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
+                mScript.peekElapsedRealtimeMillis(),
+                mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
+
+        TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
+        mScript.simulateTimePassing(clockIncrement);
+
+        long expectSystemClockMillis3 =
+                TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
+
+        mScript.simulateTimeSignalReceived(timeSignal3)
+                .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
+    }
+
+    @Test
+    public void testSuggestTime_nitz_timeDetectionDisabled() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(false);
+
+        TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+        mScript.simulateTimeSignalReceived(timeSignal)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestTime_nitz_invalidNitzReferenceTimesIgnored() {
+        Scenario scenario = SCENARIO_1;
+        final int systemClockUpdateThreshold = 2000;
+        mScript.pokeFakeClocks(scenario)
+                .pokeThresholds(systemClockUpdateThreshold)
+                .pokeTimeDetectionEnabled(true);
+        TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+        TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+
+        // Initialize the strategy / device with a time set from NITZ.
+        mScript.simulateTimePassing(100);
+        long expectedSystemClockMillis1 =
+                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+        mScript.simulateTimeSignalReceived(timeSignal1)
+                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+
+        // The UTC time increment should be larger than the system clock update threshold so we
+        // know it shouldn't be ignored for other reasons.
+        long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold);
+
+        // Now supply a new signal that has an obviously bogus reference time : older than the last
+        // one.
+        long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
+        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+                referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
+        TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+        mScript.simulateTimeSignalReceived(timeSignal2)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Now supply a new signal that has an obviously bogus reference time : substantially in the
+        // future.
+        long referenceTimeInFutureMillis =
+                utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
+        TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
+                referenceTimeInFutureMillis, validUtcTimeMillis);
+        TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
+        mScript.simulateTimeSignalReceived(timeSignal3)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Just to prove validUtcTimeMillis is valid.
+        long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
+        TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
+                validReferenceTimeMillis, validUtcTimeMillis);
+        long expectedSystemClockMillis4 =
+                TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
+        TimeSignal timeSignal4 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime4);
+        mScript.simulateTimeSignalReceived(timeSignal4)
+                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
+    }
+
+    @Test
+    public void testSuggestTime_timeDetectionToggled() {
+        Scenario scenario = SCENARIO_1;
+        final int clockIncrementMillis = 100;
+        final int systemClockUpdateThreshold = 2000;
+        mScript.pokeFakeClocks(scenario)
+                .pokeThresholds(systemClockUpdateThreshold)
+                .pokeTimeDetectionEnabled(false);
+
+        TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+        TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+
+        // Simulate time passing.
+        mScript.simulateTimePassing(clockIncrementMillis);
+
+        // Simulate the time signal being received. It should not be used because auto time
+        // detection is off but it should be recorded.
+        mScript.simulateTimeSignalReceived(timeSignal1)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Simulate more time passing.
+        mScript.simulateTimePassing(clockIncrementMillis);
+
+        long expectedSystemClockMillis1 =
+                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+        // Turn on auto time detection.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+
+        // Turn off auto time detection.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Receive another valid time signal.
+        // It should be on the threshold and accounting for the clock increments.
+        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+                mScript.peekElapsedRealtimeMillis(),
+                mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
+        TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+
+        // Simulate more time passing.
+        mScript.simulateTimePassing(clockIncrementMillis);
+
+        long expectedSystemClockMillis2 =
+                TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis());
+
+        // The new time, though valid, should not be set in the system clock because auto time is
+        // disabled.
+        mScript.simulateTimeSignalReceived(timeSignal2)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Turn on auto time detection.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
+    }
+
+    @Test
+    public void testSuggestTime_unknownSource() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(true);
+
+        TimeSignal timeSignal = scenario.createTimeSignalForActual("unknown");
+        mScript.simulateTimeSignalReceived(timeSignal)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    /**
+     * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
+     * like the real thing should, it also asserts preconditions.
+     */
+    private static class FakeCallback implements TimeDetectorStrategy.Callback {
+        private boolean mTimeDetectionEnabled;
+        private boolean mWakeLockAcquired;
+        private long mElapsedRealtimeMillis;
+        private long mSystemClockMillis;
+        private int mSystemClockUpdateThresholdMillis = 2000;
+
+        // Tracking operations.
+        private boolean mSystemClockWasSet;
+        private Intent mBroadcastSent;
+
+        @Override
+        public int systemClockUpdateThresholdMillis() {
+            return mSystemClockUpdateThresholdMillis;
+        }
+
+        @Override
+        public boolean isTimeDetectionEnabled() {
+            return mTimeDetectionEnabled;
+        }
+
+        @Override
+        public void acquireWakeLock() {
+            if (mWakeLockAcquired) {
+                fail("Wake lock already acquired");
+            }
+            mWakeLockAcquired = true;
+        }
+
+        @Override
+        public long elapsedRealtimeMillis() {
+            assertWakeLockAcquired();
+            return mElapsedRealtimeMillis;
+        }
+
+        @Override
+        public long systemClockMillis() {
+            assertWakeLockAcquired();
+            return mSystemClockMillis;
+        }
+
+        @Override
+        public void setSystemClock(long newTimeMillis) {
+            assertWakeLockAcquired();
+            mSystemClockWasSet = true;
+            mSystemClockMillis = newTimeMillis;
+        }
+
+        @Override
+        public void releaseWakeLock() {
+            assertWakeLockAcquired();
+            mWakeLockAcquired = false;
+        }
+
+        @Override
+        public void sendStickyBroadcast(Intent intent) {
+            assertNotNull(intent);
+            mBroadcastSent = intent;
+        }
+
+        // Methods below are for managing the fake's behavior.
+
+        public void pokeSystemClockUpdateThreshold(int thresholdMillis) {
+            mSystemClockUpdateThresholdMillis = thresholdMillis;
+        }
+
+        public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
+            mElapsedRealtimeMillis = elapsedRealtimeMillis;
+        }
+
+        public void pokeSystemClockMillis(long systemClockMillis) {
+            mSystemClockMillis = systemClockMillis;
+        }
+
+        public void pokeTimeDetectionEnabled(boolean enabled) {
+            mTimeDetectionEnabled = enabled;
+        }
+
+        public long peekElapsedRealtimeMillis() {
+            return mElapsedRealtimeMillis;
+        }
+
+        public long peekSystemClockMillis() {
+            return mSystemClockMillis;
+        }
+
+        public void simulateTimePassing(int incrementMillis) {
+            mElapsedRealtimeMillis += incrementMillis;
+            mSystemClockMillis += incrementMillis;
+        }
+
+        public void verifySystemClockNotSet() {
+            assertFalse(mSystemClockWasSet);
+        }
+
+        public void verifySystemClockWasSet(long expectSystemClockMillis) {
+            assertTrue(mSystemClockWasSet);
+            assertEquals(expectSystemClockMillis, mSystemClockMillis);
+        }
+
+        public void verifyIntentWasBroadcast() {
+            assertTrue(mBroadcastSent != null);
+        }
+
+        public void verifyIntentWasNotBroadcast() {
+            assertNull(mBroadcastSent);
+        }
+
+        public void resetCallTracking() {
+            mSystemClockWasSet = false;
+            mBroadcastSent = null;
+        }
+
+        private void assertWakeLockAcquired() {
+            assertTrue("The operation must be performed only after acquiring the wakelock",
+                    mWakeLockAcquired);
+        }
+    }
+
+    /**
+     * A fluent helper class for tests.
+     */
+    private class Script {
+
+        private final FakeCallback mFakeCallback;
+        private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
+
+        public Script() {
+            mFakeCallback = new FakeCallback();
+            mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
+            mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
+
+        }
+
+        Script pokeTimeDetectionEnabled(boolean enabled) {
+            mFakeCallback.pokeTimeDetectionEnabled(enabled);
+            return this;
+        }
+
+        Script pokeFakeClocks(Scenario scenario) {
+            mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis());
+            mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis());
+            return this;
+        }
+
+        Script pokeThresholds(int systemClockUpdateThreshold) {
+            mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold);
+            return this;
+        }
+
+        long peekElapsedRealtimeMillis() {
+            return mFakeCallback.peekElapsedRealtimeMillis();
+        }
+
+        long peekSystemClockMillis() {
+            return mFakeCallback.peekSystemClockMillis();
+        }
+
+        Script simulateTimeSignalReceived(TimeSignal timeSignal) {
+            mSimpleTimeDetectorStrategy.suggestTime(timeSignal);
+            return this;
+        }
+
+        Script simulateAutoTimeDetectionToggle() {
+            boolean enabled = !mFakeCallback.isTimeDetectionEnabled();
+            mFakeCallback.pokeTimeDetectionEnabled(enabled);
+            mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
+            return this;
+        }
+
+        Script simulateTimePassing(int clockIncrement) {
+            mFakeCallback.simulateTimePassing(clockIncrement);
+            return this;
+        }
+
+        Script verifySystemClockWasNotSetAndResetCallTracking() {
+            mFakeCallback.verifySystemClockNotSet();
+            mFakeCallback.verifyIntentWasNotBroadcast();
+            mFakeCallback.resetCallTracking();
+            return this;
+        }
+
+        Script verifySystemClockWasSetAndResetCallTracking(long expectSystemClockMillis) {
+            mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
+            mFakeCallback.verifyIntentWasBroadcast();
+            mFakeCallback.resetCallTracking();
+            return this;
+        }
+    }
+
+    /**
+     * A starting scenario used during tests. Describes a fictional "physical" reality.
+     */
+    private static class Scenario {
+
+        private final long mInitialDeviceSystemClockMillis;
+        private final long mInitialDeviceRealtimeMillis;
+        private final long mActualTimeMillis;
+
+        Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) {
+            mInitialDeviceSystemClockMillis = initialDeviceSystemClock;
+            mActualTimeMillis = timeMillis;
+            mInitialDeviceRealtimeMillis = elapsedRealtime;
+        }
+
+        long getInitialRealTimeMillis() {
+            return mInitialDeviceRealtimeMillis;
+        }
+
+        long getInitialSystemClockMillis() {
+            return mInitialDeviceSystemClockMillis;
+        }
+
+        long getActualTimeMillis() {
+            return mActualTimeMillis;
+        }
+
+        TimeSignal createTimeSignalForActual(String sourceId) {
+            TimestampedValue<Long> time = new TimestampedValue<>(
+                    mInitialDeviceRealtimeMillis, mActualTimeMillis);
+            return new TimeSignal(sourceId, time);
+        }
+
+        static class Builder {
+
+            private long mInitialDeviceSystemClockMillis;
+            private long mInitialDeviceRealtimeMillis;
+            private long mActualTimeMillis;
+
+            Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day,
+                    int hourOfDay, int minute, int second) {
+                mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay,
+                        minute, second);
+                return this;
+            }
+
+            Builder setInitialDeviceRealtimeMillis(long realtimeMillis) {
+                mInitialDeviceRealtimeMillis = realtimeMillis;
+                return this;
+            }
+
+            Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
+                    int minute, int second) {
+                mActualTimeMillis =
+                        createUtcTime(year, monthInYear, day, hourOfDay, minute, second);
+                return this;
+            }
+
+            Scenario build() {
+                return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis,
+                        mActualTimeMillis);
+            }
+        }
+    }
+
+    private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
+            int second) {
+        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
+        cal.clear();
+        cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
+        return cal.getTimeInMillis();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
new file mode 100644
index 0000000..ed74cd7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.timedetector.TimeSignal;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.TimestampedValue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.android.server.timedetector.TimeDetectorStrategy.Callback;
+
+import java.io.PrintWriter;
+
+@RunWith(AndroidJUnit4.class)
+public class TimeDetectorServiceTest {
+
+    private Context mMockContext;
+    private StubbedTimeDetectorStrategy mStubbedTimeDetectorStrategy;
+    private Callback mMockCallback;
+
+    private TimeDetectorService mTimeDetectorService;
+
+    @Before
+    public void setUp() {
+        mMockContext = mock(Context.class);
+        mMockCallback = mock(Callback.class);
+        mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
+
+        mTimeDetectorService = new TimeDetectorService(
+                mMockContext, mMockCallback,
+                mStubbedTimeDetectorStrategy);
+    }
+
+    @Test(expected=SecurityException.class)
+    public void testStubbedCall_withoutPermission() {
+        doThrow(new SecurityException("Mock"))
+                .when(mMockContext).enforceCallingPermission(anyString(), any());
+        TimeSignal timeSignal = createNitzTimeSignal();
+
+        try {
+            mTimeDetectorService.suggestTime(timeSignal);
+        } finally {
+            verify(mMockContext).enforceCallingPermission(
+                    eq(android.Manifest.permission.SET_TIME), anyString());
+        }
+    }
+
+    @Test
+    public void testSuggestTime() {
+        doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+        TimeSignal timeSignal = createNitzTimeSignal();
+        mTimeDetectorService.suggestTime(timeSignal);
+
+        verify(mMockContext)
+                .enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
+        mStubbedTimeDetectorStrategy.verifySuggestTimeCalled(timeSignal);
+    }
+
+    @Test
+    public void testDump() {
+        when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        mTimeDetectorService.dump(null, null, null);
+
+        verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
+        mStubbedTimeDetectorStrategy.verifyDumpCalled();
+    }
+
+    @Test
+    public void testAutoTimeDetectionToggle() {
+        when(mMockCallback.isTimeDetectionEnabled()).thenReturn(true);
+
+        mTimeDetectorService.handleAutoTimeDetectionToggle();
+
+        mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
+
+        when(mMockCallback.isTimeDetectionEnabled()).thenReturn(false);
+
+        mTimeDetectorService.handleAutoTimeDetectionToggle();
+
+        mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
+    }
+
+    private static TimeSignal createNitzTimeSignal() {
+        TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
+        return new TimeSignal(TimeSignal.SOURCE_ID_NITZ, timeValue);
+    }
+
+    private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
+
+        // Call tracking.
+        private TimeSignal mLastSuggestedTime;
+        private Boolean mLastAutoTimeDetectionToggle;
+        private boolean mDumpCalled;
+
+        @Override
+        public void initialize(Callback ignored) {
+        }
+
+        @Override
+        public void suggestTime(TimeSignal timeSignal) {
+            resetCallTracking();
+            mLastSuggestedTime = timeSignal;
+        }
+
+        @Override
+        public void handleAutoTimeDetectionToggle(boolean enabled) {
+            resetCallTracking();
+            mLastAutoTimeDetectionToggle = enabled;
+        }
+
+        @Override
+        public void dump(PrintWriter pw, String[] args) {
+            resetCallTracking();
+            mDumpCalled = true;
+        }
+
+        void resetCallTracking() {
+            mLastSuggestedTime = null;
+            mLastAutoTimeDetectionToggle = null;
+            mDumpCalled = false;
+        }
+
+        void verifySuggestTimeCalled(TimeSignal expectedSignal) {
+            assertEquals(expectedSignal, mLastSuggestedTime);
+        }
+
+        void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
+            assertNotNull(mLastAutoTimeDetectionToggle);
+            assertEquals(expectedEnable, mLastAutoTimeDetectionToggle);
+        }
+
+        void verifyDumpCalled() {
+            assertTrue(mDumpCalled);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
new file mode 100644
index 0000000..301ded4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.util.TimestampedValue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class TimeDetectorStrategyTest {
+
+    @Test
+    public void testGetTimeAt() {
+        long timeMillis = 1000L;
+        int referenceTimeMillis = 100;
+        TimestampedValue<Long> timestampedValue =
+                new TimestampedValue<>(referenceTimeMillis, timeMillis);
+        // Reference time is after the timestamp.
+        assertEquals(
+                timeMillis + (125 - referenceTimeMillis),
+                TimeDetectorStrategy.getTimeAt(timestampedValue, 125));
+
+        // Reference time is before the timestamp.
+        assertEquals(
+                timeMillis + (75 - referenceTimeMillis),
+                TimeDetectorStrategy.getTimeAt(timestampedValue, 75));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
new file mode 100644
index 0000000..19d31cf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit tests for the {@link TimeZoneDetectorService}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class TimeZoneDetectorServiceTest {
+
+    private TimeZoneDetectorService mTimeZoneDetectorService;
+
+    @Before
+    public void setUp() {
+        final Context context = InstrumentationRegistry.getContext();
+        mTimeZoneDetectorService = new TimeZoneDetectorService(context);
+    }
+
+    @Test
+    public void testStubbedCall() {
+        mTimeZoneDetectorService.stubbedCall();
+    }
+}
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 4b827d2..e33ba7e 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.bluetooth.BluetoothDevice;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -100,6 +101,7 @@
     }
 
     /** @hide */
+    @TestApi
     public CallAudioState(boolean isMuted, @CallAudioRoute int route,
             @CallAudioRoute int supportedRouteMask,
             @Nullable BluetoothDevice activeBluetoothDevice,
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 2fdbc71..4045eea 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1531,6 +1531,14 @@
                     new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"));
         }
 
+        boolean isSelfManaged =
+                (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED)
+                        == Connection.PROPERTY_SELF_MANAGED;
+        // Self-managed Connections should always use voip audio mode; we default here so that the
+        // local state within the ConnectionService matches the default we assume in Telecom.
+        if (isSelfManaged) {
+            connection.setAudioModeIsVoip(true);
+        }
         connection.setTelecomCallId(callId);
         if (connection.getState() != Connection.STATE_DISCONNECTED) {
             addConnection(callId, connection);
@@ -1570,9 +1578,7 @@
                         createIdList(connection.getConferenceables()),
                         connection.getExtras()));
 
-        if (isIncoming && request.shouldShowIncomingCallUi() &&
-                (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) ==
-                        Connection.PROPERTY_SELF_MANAGED) {
+        if (isIncoming && request.shouldShowIncomingCallUi() && isSelfManaged) {
             // Tell ConnectionService to show its incoming call UX.
             connection.onShowIncomingCallUi();
         }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b672e69..a760e30 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -113,6 +113,14 @@
     public static final String
             KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
 
+    /**
+     * Flag indicating whether or not sending emergency SMS messages over IMS
+     * is supported when in LTE/limited LTE (Emergency only) service mode..
+     *
+     */
+    public static final String
+            KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
+
     /** Flag indicating if the phone is a world phone */
     public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
 
@@ -1967,6 +1975,7 @@
         sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
         sDefaults.putBoolean(KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL, true);
         sDefaults.putBoolean(KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 26ffe32..19b3d0d 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -21,31 +21,27 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.location.LocationManager;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Process;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.util.SparseBooleanArray;
+import android.util.Log;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Helper for performing location access checks.
  * @hide
  */
 public final class LocationAccessPolicy {
+    private static final String TAG = "LocationAccessPolicy";
+    private static final boolean DBG = false;
+
     /**
      * API to determine if the caller has permissions to get cell location.
      *
@@ -58,10 +54,11 @@
             int uid, int pid) throws SecurityException {
         Trace.beginSection("TelephonyLocationCheck");
         try {
-            // Always allow the phone process to access location. This avoid breaking legacy code
-            // that rely on public-facing APIs to access cell location, and it doesn't create a
-            // info leak risk because the cell location is stored in the phone process anyway.
-            if (uid == Process.PHONE_UID) {
+            // Always allow the phone process and system server to access location. This avoid
+            // breaking legacy code that rely on public-facing APIs to access cell location, and
+            // it doesn't create an info leak risk because the cell location is stored in the phone
+            // process anyway, and the system server already has location access.
+            if (uid == Process.PHONE_UID || uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
                 return true;
             }
 
@@ -74,15 +71,18 @@
 
             if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
                     PackageManager.PERMISSION_DENIED) {
+                if (DBG) Log.w(TAG, "Permission checked failed (" + pid + "," + uid + ")");
                 return false;
             }
             final int opCode = AppOpsManager.permissionToOpCode(
                     Manifest.permission.ACCESS_COARSE_LOCATION);
             if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
                     .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
+                if (DBG) Log.w(TAG, "AppOp check failed (" + uid + "," + pkgName + ")");
                 return false;
             }
             if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) {
+                if (DBG) Log.w(TAG, "Location disabled, failed, (" + uid + ")");
                 return false;
             }
             // If the user or profile is current, permission is granted.
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index d9fdd97..af4d8d7 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -207,23 +207,25 @@
     public static final int STATUS_UNKNOWN = 0;
 
     /**
-     * Indicates that the file is actively downloading.
+     * Indicates that the file is actively being downloaded.
      */
     public static final int STATUS_ACTIVELY_DOWNLOADING = 1;
 
     /**
-     * TODO: I don't know...
+     * Indicates that the file is awaiting the next download or repair operations. When a more
+     * precise status is known, the status will change to either {@link #STATUS_PENDING_REPAIR} or
+     * {@link #STATUS_PENDING_DOWNLOAD_WINDOW}.
      */
     public static final int STATUS_PENDING_DOWNLOAD = 2;
 
     /**
-     * Indicates that the file is being repaired after the download being interrupted.
+     * Indicates that the file is awaiting file repair after the download has ended.
      */
     public static final int STATUS_PENDING_REPAIR = 3;
 
     /**
      * Indicates that the file is waiting to download because its download window has not yet
-     * started.
+     * started and is scheduled for a future time.
      */
     public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4;
 
@@ -609,6 +611,9 @@
      * If the operation encountered an error, the error code will be delivered via
      * {@link MbmsDownloadSessionCallback#onError}.
      *
+     * Repeated calls to this method for the same {@link DownloadRequest} will replace the
+     * previously registered listener.
+     *
      * @param request The {@link DownloadRequest} that you want updates on.
      * @param executor The {@link Executor} on which calls to {@code listener } should be executed.
      * @param listener The listener that should be called when the middleware has information to
@@ -659,6 +664,9 @@
      * If the operation encountered an error, the error code will be delivered via
      * {@link MbmsDownloadSessionCallback#onError}.
      *
+     * Repeated calls to this method for the same {@link DownloadRequest} will replace the
+     * previously registered listener.
+     *
      * @param request The {@link DownloadRequest} provided during registration
      * @param listener The listener provided during registration.
      */
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index f7e6840..4354314 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -36,8 +36,8 @@
 /**
  * Base class of network service. Services that extend NetworkService must register the service in
  * their AndroidManifest to be detected by the framework. They must be protected by the permission
- * "android.permission.BIND_NETWORK_SERVICE". The network service definition in the manifest must
- * follow the following format:
+ * "android.permission.BIND_TELEPHONY_NETWORK_SERVICE". The network service definition in the
+ * manifest must follow the following format:
  * ...
  * <service android:name=".xxxNetworkService"
  *     android:permission="android.permission.BIND_TELEPHONY_NETWORK_SERVICE" >
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9de1355..e0b465d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2697,7 +2697,8 @@
     }
 
     /**
-     * Gets all the UICC slots.
+     * Gets all the UICC slots. The objects in the array can be null if the slot info is not
+     * available, which is possible between phone process starting and getting slot info from modem.
      *
      * @return UiccSlotInfo array.
      *
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 145ed7e..bb181e6 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -24,12 +24,14 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Telephony;
+import android.provider.Telephony.Carriers;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
@@ -40,27 +42,40 @@
 import java.util.Objects;
 
 /**
- * A class representing an APN configuration.
+ * An Access Point Name (APN) configuration for a carrier data connection.
+ *
+ * <p>The APN provides configuration to connect a cellular network device to an IP data network. A
+ * carrier uses the name, type and other configuration in an {@code APNSetting} to decide which IP
+ * address to assign, any security methods to apply, and how the device might be connected to
+ * private networks.
+ *
+ * <p>Use {@link ApnSetting.Builder} to create new instances.
  */
 public class ApnSetting implements Parcelable {
 
     private static final String LOG_TAG = "ApnSetting";
     private static final boolean VDBG = false;
 
-    private static final Map<String, Integer> APN_TYPE_STRING_MAP;
-    private static final Map<Integer, String> APN_TYPE_INT_MAP;
-    private static final Map<String, Integer> PROTOCOL_STRING_MAP;
-    private static final Map<Integer, String> PROTOCOL_INT_MAP;
-    private static final Map<String, Integer> MVNO_TYPE_STRING_MAP;
-    private static final Map<Integer, String> MVNO_TYPE_INT_MAP;
-    private static final int NOT_IN_MAP_INT = -1;
-    private static final int NO_PORT_SPECIFIED = -1;
+    private static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
+    private static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*";
+    private static final String V4_FORMAT_REGEX = "^\\[ApnSettingV4\\]\\s*";
+    private static final String V5_FORMAT_REGEX = "^\\[ApnSettingV5\\]\\s*";
 
-    /** All APN types except IA. */
-    private static final int TYPE_ALL_BUT_IA = ApnTypes.ALL & (~ApnTypes.IA);
+    /**
+     * Default value for mtu if it's not set. Moved from PhoneConstants.
+     * @hide
+     */
+    public static final int UNSET_MTU = 0;
+    private static final int UNSPECIFIED_INT = -1;
+    private static final String UNSPECIFIED_STRING = "";
 
-    /** APN type for default data traffic and HiPri traffic. */
-    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
+    /**
+     * All APN types.
+     * @hide
+     */
+    public static final int TYPE_ALL = ApnTypes.ALL;
+    /** APN type for default data traffic. */
+    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT;
     /** APN type for MMS traffic. */
     public static final int TYPE_MMS = ApnTypes.MMS;
     /** APN type for SUPL assisted GPS. */
@@ -159,9 +174,16 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface MvnoType {}
 
+    private static final Map<String, Integer> APN_TYPE_STRING_MAP;
+    private static final Map<Integer, String> APN_TYPE_INT_MAP;
+    private static final Map<String, Integer> PROTOCOL_STRING_MAP;
+    private static final Map<Integer, String> PROTOCOL_INT_MAP;
+    private static final Map<String, Integer> MVNO_TYPE_STRING_MAP;
+    private static final Map<Integer, String> MVNO_TYPE_INT_MAP;
+
     static {
         APN_TYPE_STRING_MAP = new ArrayMap<String, Integer>();
-        APN_TYPE_STRING_MAP.put("*", TYPE_ALL_BUT_IA);
+        APN_TYPE_STRING_MAP.put("*", TYPE_ALL);
         APN_TYPE_STRING_MAP.put("default", TYPE_DEFAULT);
         APN_TYPE_STRING_MAP.put("mms", TYPE_MMS);
         APN_TYPE_STRING_MAP.put("supl", TYPE_SUPL);
@@ -209,10 +231,10 @@
 
     private final String mEntryName;
     private final String mApnName;
-    private final InetAddress mProxyAddress;
+    private final String mProxyAddress;
     private final int mProxyPort;
     private final Uri mMmsc;
-    private final InetAddress mMmsProxyAddress;
+    private final String mMmsProxyAddress;
     private final int mMmsProxyPort;
     private final String mUser;
     private final String mPassword;
@@ -238,6 +260,8 @@
     private final int mMvnoType;
     private final String mMvnoMatchData;
 
+    private final int mApnSetId;
+
     private boolean mPermanentFailed = false;
 
     /**
@@ -315,6 +339,21 @@
     }
 
     /**
+     * Returns the APN set id.
+     *
+     * APNs that are part of the same set should be preferred together, e.g. if the
+     * user selects a default APN with apnSetId=1, then we will prefer all APNs with apnSetId = 1.
+     *
+     * If the apnSetId = Carriers.NO_SET_SET(=0) then the APN is not part of a set.
+     *
+     * @return the APN set id
+     * @hide
+     */
+    public int getApnSetId() {
+        return mApnSetId;
+    }
+
+    /**
      * Indicates this APN setting is permanently failed and cannot be
      * retried by the retry manager anymore.
      *
@@ -336,7 +375,7 @@
     }
 
     /**
-     * Returns the entry name of the APN.
+     * Gets the human-readable name that describes the APN.
      *
      * @return the entry name for the APN
      */
@@ -354,18 +393,32 @@
     }
 
     /**
+     * Gets the HTTP proxy address configured for the APN. The proxy address might be an IP address
+     * or hostname. This method returns {@code null} if system networking (typically DNS) isn’t
+     * available to resolve a hostname value—values set as IP addresses don’t have this restriction.
+     * This is a known problem and will be addressed in a future release.
+     *
+     * @return the HTTP proxy address or {@code null} if DNS isn’t available to resolve a hostname
+     * @deprecated use {@link #getProxyAddressAsString()} instead.
+     */
+    @Deprecated
+    public InetAddress getProxyAddress() {
+        return inetAddressFromString(mProxyAddress);
+    }
+
+    /**
      * Returns the proxy address of the APN.
      *
      * @return proxy address.
      */
-    public InetAddress getProxyAddress() {
+    public String getProxyAddressAsString() {
         return mProxyAddress;
     }
 
     /**
-     * Returns the proxy port of the APN.
+     * Returns the proxy address of the APN.
      *
-     * @return proxy port
+     * @return proxy address.
      */
     public int getProxyPort() {
         return mProxyPort;
@@ -380,11 +433,25 @@
     }
 
     /**
+     * Gets the MMS proxy address configured for the APN. The MMS proxy address might be an IP
+     * address or hostname. This method returns {@code null} if system networking (typically DNS)
+     * isn’t available to resolve a hostname value—values set as IP addresses don’t have this
+     * restriction. This is a known problem and will be addressed in a future release.
+     *
+     * @return the MMS proxy address or {@code null} if DNS isn’t available to resolve a hostname
+     * @deprecated use {@link #getMmsProxyAddressAsString()} instead.
+     */
+    @Deprecated
+    public InetAddress getMmsProxyAddress() {
+        return inetAddressFromString(mMmsProxyAddress);
+    }
+
+    /**
      * Returns the MMS proxy address of the APN.
      *
      * @return MMS proxy address.
      */
-    public InetAddress getMmsProxyAddress() {
+    public String getMmsProxyAddressAsString() {
         return mMmsProxyAddress;
     }
 
@@ -550,47 +617,65 @@
         this.mMaxConnsTime = builder.mMaxConnsTime;
         this.mMvnoType = builder.mMvnoType;
         this.mMvnoMatchData = builder.mMvnoMatchData;
+        this.mApnSetId = builder.mApnSetId;
     }
 
     /** @hide */
     public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
-            String apnName, InetAddress proxy, int port, Uri mmsc, InetAddress mmsProxy,
-            int mmsPort, String user, String password, int authType, int mApnTypeBitmask,
-            int protocol, int roamingProtocol, boolean carrierEnabled,
-            int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns,
-            int waitTime, int maxConnsTime, int mtu, int mvnoType, String mvnoMatchData) {
+            String apnName, String proxyAddress, int proxyPort, Uri mmsc,
+            String mmsProxyAddress, int mmsProxyPort, String user, String password,
+            int authType, int mApnTypeBitmask, int protocol, int roamingProtocol,
+            boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive,
+            int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType,
+            String mvnoMatchData, int apnSetId) {
         return new Builder()
-                .setId(id)
-                .setOperatorNumeric(operatorNumeric)
-                .setEntryName(entryName)
-                .setApnName(apnName)
-                .setProxyAddress(proxy)
-                .setProxyPort(port)
-                .setMmsc(mmsc)
-                .setMmsProxyAddress(mmsProxy)
-                .setMmsProxyPort(mmsPort)
-                .setUser(user)
-                .setPassword(password)
-                .setAuthType(authType)
-                .setApnTypeBitmask(mApnTypeBitmask)
-                .setProtocol(protocol)
-                .setRoamingProtocol(roamingProtocol)
-                .setCarrierEnabled(carrierEnabled)
-                .setNetworkTypeBitmask(networkTypeBitmask)
-                .setProfileId(profileId)
-                .setModemCognitive(modemCognitive)
-                .setMaxConns(maxConns)
-                .setWaitTime(waitTime)
-                .setMaxConnsTime(maxConnsTime)
-                .setMtu(mtu)
-                .setMvnoType(mvnoType)
-                .setMvnoMatchData(mvnoMatchData)
-                .build();
+            .setId(id)
+            .setOperatorNumeric(operatorNumeric)
+            .setEntryName(entryName)
+            .setApnName(apnName)
+            .setProxyAddress(proxyAddress)
+            .setProxyPort(proxyPort)
+            .setMmsc(mmsc)
+            .setMmsProxyAddress(mmsProxyAddress)
+            .setMmsProxyPort(mmsProxyPort)
+            .setUser(user)
+            .setPassword(password)
+            .setAuthType(authType)
+            .setApnTypeBitmask(mApnTypeBitmask)
+            .setProtocol(protocol)
+            .setRoamingProtocol(roamingProtocol)
+            .setCarrierEnabled(carrierEnabled)
+            .setNetworkTypeBitmask(networkTypeBitmask)
+            .setProfileId(profileId)
+            .setModemCognitive(modemCognitive)
+            .setMaxConns(maxConns)
+            .setWaitTime(waitTime)
+            .setMaxConnsTime(maxConnsTime)
+            .setMtu(mtu)
+            .setMvnoType(mvnoType)
+            .setMvnoMatchData(mvnoMatchData)
+            .setApnSetId(apnSetId)
+            .buildWithoutCheck();
+    }
+
+    /** @hide */
+    public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
+            String apnName, String proxyAddress, int proxyPort, Uri mmsc,
+            String mmsProxyAddress, int mmsProxyPort, String user, String password,
+            int authType, int mApnTypeBitmask, int protocol, int roamingProtocol,
+            boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive,
+            int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType,
+            String mvnoMatchData) {
+        return makeApnSetting(id, operatorNumeric, entryName, apnName, proxyAddress, proxyPort,
+            mmsc, mmsProxyAddress, mmsProxyPort, user, password, authType, mApnTypeBitmask,
+            protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, profileId,
+            modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType, mvnoMatchData,
+            Carriers.NO_SET_SET);
     }
 
     /** @hide */
     public static ApnSetting makeApnSetting(Cursor cursor) {
-        final int apnTypesBitmask = parseTypes(
+        final int apnTypesBitmask = getApnTypesBitmaskFromString(
                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
         int networkTypeBitmask = cursor.getInt(
                 cursor.getColumnIndexOrThrow(Telephony.Carriers.NETWORK_TYPE_BITMASK));
@@ -602,75 +687,259 @@
         }
 
         return makeApnSetting(
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
-                inetAddressFromString(cursor.getString(
-                        cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
-                portFromString(cursor.getString(
-                        cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
-                UriFromString(cursor.getString(
-                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
-                inetAddressFromString(cursor.getString(
-                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
-                portFromString(cursor.getString(
-                        cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
-                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
-                apnTypesBitmask,
-                nullToNotInMapInt(PROTOCOL_STRING_MAP.get(
-                    cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))),
-                nullToNotInMapInt(PROTOCOL_STRING_MAP.get(
-                    cursor.getString(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.ROAMING_PROTOCOL)))),
-                cursor.getInt(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.CARRIER_ENABLED)) == 1,
-                networkTypeBitmask,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
-                cursor.getInt(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.MODEM_COGNITIVE)) == 1,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
-                cursor.getInt(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.MAX_CONNS_TIME)),
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
-                nullToNotInMapInt(MVNO_TYPE_STRING_MAP.get(
-                    cursor.getString(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.MVNO_TYPE)))),
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
+            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
+            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
+            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
+            cursor.getString(
+                cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+            portFromString(cursor.getString(
+                cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
+            UriFromString(cursor.getString(
+                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
+            cursor.getString(
+                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+            portFromString(cursor.getString(
+                cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
+            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
+            cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
+            apnTypesBitmask,
+            getProtocolIntFromString(
+                cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
+            getProtocolIntFromString(
                 cursor.getString(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.MVNO_MATCH_DATA)));
+                    Telephony.Carriers.ROAMING_PROTOCOL))),
+            cursor.getInt(cursor.getColumnIndexOrThrow(
+                Telephony.Carriers.CARRIER_ENABLED)) == 1,
+            networkTypeBitmask,
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
+            cursor.getInt(cursor.getColumnIndexOrThrow(
+                Telephony.Carriers.MODEM_COGNITIVE)) == 1,
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME)),
+            cursor.getInt(cursor.getColumnIndexOrThrow(
+                Telephony.Carriers.MAX_CONNS_TIME)),
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
+            getMvnoTypeIntFromString(
+                cursor.getString(cursor.getColumnIndexOrThrow(
+                    Telephony.Carriers.MVNO_TYPE))),
+            cursor.getString(cursor.getColumnIndexOrThrow(
+                Telephony.Carriers.MVNO_MATCH_DATA)),
+            cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)));
     }
 
     /** @hide */
     public static ApnSetting makeApnSetting(ApnSetting apn) {
         return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
-                apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, apn.mMmsProxyPort, apn.mUser,
-                apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, apn.mProtocol, apn.mRoamingProtocol,
-                apn.mCarrierEnabled, apn.mNetworkTypeBitmask, apn.mProfileId,
-                apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu,
-                apn.mMvnoType, apn.mMvnoMatchData);
+            apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
+            apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
+            apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
+            apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime,
+            apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
     }
 
-    /** @hide */
+    /**
+     * Creates an ApnSetting object from a string.
+     *
+     * @param data the string to read.
+     *
+     * The string must be in one of two formats (newlines added for clarity,
+     * spaces are optional):
+     *
+     * v1 format:
+     *   <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
+     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
+     *   <type>[| <type>...],
+     *
+     * v2 format:
+     *   [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
+     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
+     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
+     *
+     * v3 format:
+     *   [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
+     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
+     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
+     *   <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
+     *   <mvnoType>, <mvnoMatchData>
+     *
+     * v4 format:
+     *   [ApnSettingV4] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
+     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
+     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
+     *   <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
+     *   <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>
+     *
+     * v5 format:
+     *   [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
+     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
+     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
+     *   <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
+     *   <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>
+     *
+     * Note that the strings generated by {@link #toString()} do not contain the username
+     * and password and thus cannot be read by this method.
+     *
+     * This method may return {@code null} if the input string is invalid.
+     *
+     * @hide
+     */
+    public static ApnSetting fromString(String data) {
+        if (data == null) return null;
+
+        int version;
+        // matches() operates on the whole string, so append .* to the regex.
+        if (data.matches(V5_FORMAT_REGEX + ".*")) {
+            version = 5;
+            data = data.replaceFirst(V5_FORMAT_REGEX, "");
+        } else if (data.matches(V4_FORMAT_REGEX + ".*")) {
+            version = 4;
+            data = data.replaceFirst(V4_FORMAT_REGEX, "");
+        } else if (data.matches(V3_FORMAT_REGEX + ".*")) {
+            version = 3;
+            data = data.replaceFirst(V3_FORMAT_REGEX, "");
+        } else if (data.matches(V2_FORMAT_REGEX + ".*")) {
+            version = 2;
+            data = data.replaceFirst(V2_FORMAT_REGEX, "");
+        } else {
+            version = 1;
+        }
+
+        String[] a = data.split("\\s*,\\s*");
+        if (a.length < 14) {
+            return null;
+        }
+
+        int authType;
+        try {
+            authType = Integer.parseInt(a[12]);
+        } catch (NumberFormatException e) {
+            authType = 0;
+        }
+
+        String[] typeArray;
+        String protocol, roamingProtocol;
+        boolean carrierEnabled;
+        int bearerBitmask = 0;
+        int networkTypeBitmask = 0;
+        int profileId = 0;
+        boolean modemCognitive = false;
+        int maxConns = 0;
+        int waitTime = 0;
+        int maxConnsTime = 0;
+        int mtu = UNSET_MTU;
+        String mvnoType = "";
+        String mvnoMatchData = "";
+        int apnSetId = Carriers.NO_SET_SET;
+        if (version == 1) {
+            typeArray = new String[a.length - 13];
+            System.arraycopy(a, 13, typeArray, 0, a.length - 13);
+            protocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP);
+            roamingProtocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP);
+            carrierEnabled = true;
+        } else {
+            if (a.length < 18) {
+                return null;
+            }
+            typeArray = a[13].split("\\s*\\|\\s*");
+            protocol = a[14];
+            roamingProtocol = a[15];
+            carrierEnabled = Boolean.parseBoolean(a[16]);
+
+            bearerBitmask = ServiceState.getBitmaskFromString(a[17]);
+
+            if (a.length > 22) {
+                modemCognitive = Boolean.parseBoolean(a[19]);
+                try {
+                    profileId = Integer.parseInt(a[18]);
+                    maxConns = Integer.parseInt(a[20]);
+                    waitTime = Integer.parseInt(a[21]);
+                    maxConnsTime = Integer.parseInt(a[22]);
+                } catch (NumberFormatException e) {
+                }
+            }
+            if (a.length > 23) {
+                try {
+                    mtu = Integer.parseInt(a[23]);
+                } catch (NumberFormatException e) {
+                }
+            }
+            if (a.length > 25) {
+                mvnoType = a[24];
+                mvnoMatchData = a[25];
+            }
+            if (a.length > 26) {
+                networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]);
+            }
+            if (a.length > 27) {
+                apnSetId = Integer.parseInt(a[27]);
+            }
+        }
+
+        // If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be
+        // ignored.
+        if (networkTypeBitmask == 0) {
+            networkTypeBitmask =
+                ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
+        }
+        return makeApnSetting(-1, a[10] + a[11], a[0], a[1], a[2],
+            portFromString(a[3]), UriFromString(a[7]), a[8],
+            portFromString(a[9]), a[4], a[5], authType,
+            getApnTypesBitmaskFromString(TextUtils.join(",", typeArray)),
+            getProtocolIntFromString(protocol), getProtocolIntFromString(roamingProtocol),
+            carrierEnabled, networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime,
+            maxConnsTime, mtu, getMvnoTypeIntFromString(mvnoType), mvnoMatchData, apnSetId);
+    }
+
+    /**
+     * Creates an array of ApnSetting objects from a string.
+     *
+     * @param data the string to read.
+     *
+     * Builds on top of the same format used by fromString, but allows for multiple entries
+     * separated by ";".
+     *
+     * @hide
+     */
+    public static List<ApnSetting> arrayFromString(String data) {
+        List<ApnSetting> retVal = new ArrayList<ApnSetting>();
+        if (TextUtils.isEmpty(data)) {
+            return retVal;
+        }
+        String[] apnStrings = data.split("\\s*;\\s*");
+        for (String apnString : apnStrings) {
+            ApnSetting apn = fromString(apnString);
+            if (apn != null) {
+                retVal.add(apn);
+            }
+        }
+        return retVal;
+    }
+
+    /**
+     * Returns the string representation of ApnSetting.
+     *
+     * This method prints null for unset elements. The output doesn't contain password or user.
+     * @hide
+     */
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("[ApnSettingV4] ")
-                .append(mEntryName)
-                .append(", ").append(mId)
-                .append(", ").append(mOperatorNumeric)
-                .append(", ").append(mApnName)
-                .append(", ").append(inetAddressToString(mProxyAddress))
-                .append(", ").append(UriToString(mMmsc))
-                .append(", ").append(inetAddressToString(mMmsProxyAddress))
-                .append(", ").append(portToString(mMmsProxyPort))
-                .append(", ").append(portToString(mProxyPort))
-                .append(", ").append(mAuthType).append(", ");
-        final String[] types = deParseTypes(mApnTypeBitmask).split(",");
-        sb.append(TextUtils.join(" | ", types)).append(", ");
-        sb.append(", ").append(mProtocol);
-        sb.append(", ").append(mRoamingProtocol);
+        sb.append("[ApnSettingV5] ")
+            .append(mEntryName)
+            .append(", ").append(mId)
+            .append(", ").append(mOperatorNumeric)
+            .append(", ").append(mApnName)
+            .append(", ").append(mProxyAddress)
+            .append(", ").append(UriToString(mMmsc))
+            .append(", ").append(mMmsProxyAddress)
+            .append(", ").append(portToString(mMmsProxyPort))
+            .append(", ").append(portToString(mProxyPort))
+            .append(", ").append(mAuthType).append(", ");
+        final String[] types = getApnTypesStringFromBitmask(mApnTypeBitmask).split(",");
+        sb.append(TextUtils.join(" | ", types));
+        sb.append(", ").append(PROTOCOL_INT_MAP.get(mProtocol));
+        sb.append(", ").append(PROTOCOL_INT_MAP.get(mRoamingProtocol));
         sb.append(", ").append(mCarrierEnabled);
         sb.append(", ").append(mProfileId);
         sb.append(", ").append(mModemCognitive);
@@ -678,10 +947,11 @@
         sb.append(", ").append(mWaitTime);
         sb.append(", ").append(mMaxConnsTime);
         sb.append(", ").append(mMtu);
-        sb.append(", ").append(mMvnoType);
+        sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType));
         sb.append(", ").append(mMvnoMatchData);
         sb.append(", ").append(mPermanentFailed);
         sb.append(", ").append(mNetworkTypeBitmask);
+        sb.append(", ").append(mApnSetId);
         return sb.toString();
     }
 
@@ -690,22 +960,34 @@
      * @hide
      */
     public boolean hasMvnoParams() {
-        return (mMvnoType != NOT_IN_MAP_INT) && !TextUtils.isEmpty(mMvnoMatchData);
+        return !TextUtils.isEmpty(getMvnoTypeStringFromInt(mMvnoType))
+            && !TextUtils.isEmpty(mMvnoMatchData);
+    }
+
+    private boolean hasApnType(int type) {
+        return (mApnTypeBitmask & type) == type;
     }
 
     /** @hide */
     public boolean canHandleType(@ApnType int type) {
-        return mCarrierEnabled && ((mApnTypeBitmask & type) == type);
+        if (!mCarrierEnabled) {
+            return false;
+        }
+        // DEFAULT can handle HIPRI.
+        if (hasApnType(type) || (type == TYPE_HIPRI && hasApnType(TYPE_DEFAULT))) {
+            return true;
+        }
+        return false;
     }
 
-    // check whether the types of two APN same (even only one type of each APN is same)
+    // Check whether the types of two APN same (even only one type of each APN is same).
     private boolean typeSameAny(ApnSetting first, ApnSetting second) {
         if (VDBG) {
             StringBuilder apnType1 = new StringBuilder(first.mApnName + ": ");
-            apnType1.append(deParseTypes(first.mApnTypeBitmask));
+            apnType1.append(getApnTypesStringFromBitmask(first.mApnTypeBitmask));
 
             StringBuilder apnType2 = new StringBuilder(second.mApnName + ": ");
-            apnType2.append(deParseTypes(second.mApnTypeBitmask));
+            apnType2.append(getApnTypesStringFromBitmask(second.mApnTypeBitmask));
 
             Rlog.d(LOG_TAG, "APN1: is " + apnType1);
             Rlog.d(LOG_TAG, "APN2: is " + apnType2);
@@ -725,7 +1007,7 @@
     }
 
     // TODO - if we have this function we should also have hashCode.
-    // Also should handle changes in type order and perhaps case-insensitivity
+    // Also should handle changes in type order and perhaps case-insensitivity.
     /** @hide */
     public boolean equals(Object o) {
         if (o instanceof ApnSetting == false) {
@@ -735,30 +1017,31 @@
         ApnSetting other = (ApnSetting) o;
 
         return mEntryName.equals(other.mEntryName)
-                && Objects.equals(mId, other.mId)
-                && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
-                && Objects.equals(mApnName, other.mApnName)
-                && Objects.equals(mProxyAddress, other.mProxyAddress)
-                && Objects.equals(mMmsc, other.mMmsc)
-                && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
-                && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
-                && Objects.equals(mProxyPort,other.mProxyPort)
-                && Objects.equals(mUser, other.mUser)
-                && Objects.equals(mPassword, other.mPassword)
-                && Objects.equals(mAuthType, other.mAuthType)
-                && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
-                && Objects.equals(mProtocol, other.mProtocol)
-                && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
-                && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
-                && Objects.equals(mProfileId, other.mProfileId)
-                && Objects.equals(mModemCognitive, other.mModemCognitive)
-                && Objects.equals(mMaxConns, other.mMaxConns)
-                && Objects.equals(mWaitTime, other.mWaitTime)
-                && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
-                && Objects.equals(mMtu, other.mMtu)
-                && Objects.equals(mMvnoType, other.mMvnoType)
-                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
-                && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask);
+            && Objects.equals(mId, other.mId)
+            && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+            && Objects.equals(mApnName, other.mApnName)
+            && Objects.equals(mProxyAddress, other.mProxyAddress)
+            && Objects.equals(mMmsc, other.mMmsc)
+            && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+            && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+            && Objects.equals(mProxyPort, other.mProxyPort)
+            && Objects.equals(mUser, other.mUser)
+            && Objects.equals(mPassword, other.mPassword)
+            && Objects.equals(mAuthType, other.mAuthType)
+            && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+            && Objects.equals(mProtocol, other.mProtocol)
+            && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
+            && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+            && Objects.equals(mProfileId, other.mProfileId)
+            && Objects.equals(mModemCognitive, other.mModemCognitive)
+            && Objects.equals(mMaxConns, other.mMaxConns)
+            && Objects.equals(mWaitTime, other.mWaitTime)
+            && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+            && Objects.equals(mMtu, other.mMtu)
+            && Objects.equals(mMvnoType, other.mMvnoType)
+            && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+            && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+            && Objects.equals(mApnSetId, other.mApnSetId);
     }
 
     /**
@@ -781,28 +1064,29 @@
         ApnSetting other = (ApnSetting) o;
 
         return mEntryName.equals(other.mEntryName)
-                && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
-                && Objects.equals(mApnName, other.mApnName)
-                && Objects.equals(mProxyAddress, other.mProxyAddress)
-                && Objects.equals(mMmsc, other.mMmsc)
-                && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
-                && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
-                && Objects.equals(mProxyPort, other.mProxyPort)
-                && Objects.equals(mUser, other.mUser)
-                && Objects.equals(mPassword, other.mPassword)
-                && Objects.equals(mAuthType, other.mAuthType)
-                && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
-                && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
-                && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
-                && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
-                && Objects.equals(mProfileId, other.mProfileId)
-                && Objects.equals(mModemCognitive, other.mModemCognitive)
-                && Objects.equals(mMaxConns, other.mMaxConns)
-                && Objects.equals(mWaitTime, other.mWaitTime)
-                && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
-                && Objects.equals(mMtu, other.mMtu)
-                && Objects.equals(mMvnoType, other.mMvnoType)
-                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData);
+            && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+            && Objects.equals(mApnName, other.mApnName)
+            && Objects.equals(mProxyAddress, other.mProxyAddress)
+            && Objects.equals(mMmsc, other.mMmsc)
+            && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+            && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+            && Objects.equals(mProxyPort, other.mProxyPort)
+            && Objects.equals(mUser, other.mUser)
+            && Objects.equals(mPassword, other.mPassword)
+            && Objects.equals(mAuthType, other.mAuthType)
+            && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+            && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
+            && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
+            && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+            && Objects.equals(mProfileId, other.mProfileId)
+            && Objects.equals(mModemCognitive, other.mModemCognitive)
+            && Objects.equals(mMaxConns, other.mMaxConns)
+            && Objects.equals(mWaitTime, other.mWaitTime)
+            && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+            && Objects.equals(mMtu, other.mMtu)
+            && Objects.equals(mMvnoType, other.mMvnoType)
+            && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+            && Objects.equals(mApnSetId, other.mApnSetId);
     }
 
     /**
@@ -814,42 +1098,77 @@
      */
     public boolean similar(ApnSetting other) {
         return (!this.canHandleType(TYPE_DUN)
-                && !other.canHandleType(TYPE_DUN)
-                && Objects.equals(this.mApnName, other.mApnName)
-                && !typeSameAny(this, other)
-                && xorEquals(this.mProxyAddress, other.mProxyAddress)
-                && xorEqualsPort(this.mProxyPort, other.mProxyPort)
-                && xorEquals(this.mProtocol, other.mProtocol)
-                && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
-                && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
-                && Objects.equals(this.mProfileId, other.mProfileId)
-                && Objects.equals(this.mMvnoType, other.mMvnoType)
-                && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
-                && xorEquals(this.mMmsc, other.mMmsc)
-                && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
-                && xorEqualsPort(this.mMmsProxyPort, other.mMmsProxyPort))
-                && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask);
+            && !other.canHandleType(TYPE_DUN)
+            && Objects.equals(this.mApnName, other.mApnName)
+            && !typeSameAny(this, other)
+            && xorEquals(this.mProxyAddress, other.mProxyAddress)
+            && xorEqualsInt(this.mProxyPort, other.mProxyPort)
+            && xorEquals(this.mProtocol, other.mProtocol)
+            && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
+            && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
+            && Objects.equals(this.mProfileId, other.mProfileId)
+            && Objects.equals(this.mMvnoType, other.mMvnoType)
+            && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
+            && xorEquals(this.mMmsc, other.mMmsc)
+            && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+            && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
+            && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+            && Objects.equals(mApnSetId, other.mApnSetId);
     }
 
-    // Equal or one is not specified.
-    private boolean xorEquals(String first, String second) {
-        return (Objects.equals(first, second)
-                || TextUtils.isEmpty(first)
-                || TextUtils.isEmpty(second));
-    }
-
-    // Equal or one is not null.
+    // Equal or one is null.
     private boolean xorEquals(Object first, Object second) {
         return first == null || second == null || first.equals(second);
     }
 
     // Equal or one is not specified.
-    private boolean xorEqualsPort(int first, int second) {
-        return first == NO_PORT_SPECIFIED || second == NO_PORT_SPECIFIED
+    private boolean xorEqualsInt(int first, int second) {
+        return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT
             || Objects.equals(first, second);
     }
 
-    private String deParseTypes(int apnTypeBitmask) {
+    private String nullToEmpty(String stringValue) {
+        return stringValue == null ? UNSPECIFIED_STRING : stringValue;
+    }
+
+    /**
+     * @hide
+     * Called by {@link android.app.admin.DevicePolicyManager} to convert this APN into
+     * ContentValue. If a field is not specified then we put "" instead of null.
+     */
+    public ContentValues toContentValues() {
+        ContentValues apnValue = new ContentValues();
+        apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric));
+        apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName));
+        apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName));
+        apnValue.put(Telephony.Carriers.PROXY, nullToEmpty(mProxyAddress));
+        apnValue.put(Telephony.Carriers.PORT, nullToEmpty(portToString(mProxyPort)));
+        apnValue.put(Telephony.Carriers.MMSC, nullToEmpty(UriToString(mMmsc)));
+        apnValue.put(Telephony.Carriers.MMSPORT, nullToEmpty(portToString(mMmsProxyPort)));
+        apnValue.put(Telephony.Carriers.MMSPROXY, nullToEmpty(
+                mMmsProxyAddress));
+        apnValue.put(Telephony.Carriers.USER, nullToEmpty(mUser));
+        apnValue.put(Telephony.Carriers.PASSWORD, nullToEmpty(mPassword));
+        apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType);
+        String apnType = getApnTypesStringFromBitmask(mApnTypeBitmask);
+        apnValue.put(Telephony.Carriers.TYPE, nullToEmpty(apnType));
+        apnValue.put(Telephony.Carriers.PROTOCOL,
+                getProtocolStringFromInt(mProtocol));
+        apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL,
+                getProtocolStringFromInt(mRoamingProtocol));
+        apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
+        apnValue.put(Telephony.Carriers.MVNO_TYPE, getMvnoTypeStringFromInt(mMvnoType));
+        apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
+
+        return apnValue;
+    }
+
+    /**
+     * @param apnTypeBitmask bitmask of APN types.
+     * @return comma delimited list of APN types.
+     * @hide
+     */
+    public static String getApnTypesStringFromBitmask(int apnTypeBitmask) {
         List<String> types = new ArrayList<>();
         for (Integer type : APN_TYPE_INT_MAP.keySet()) {
             if ((apnTypeBitmask & type) == type) {
@@ -859,54 +1178,19 @@
         return TextUtils.join(",", types);
     }
 
-    private String nullToEmpty(String stringValue) {
-        return stringValue == null ? "" : stringValue;
-    }
-
-    /** @hide */
-    // Called by DPM.
-    public ContentValues toContentValues() {
-        ContentValues apnValue = new ContentValues();
-        apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric));
-        apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName));
-        apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName));
-        apnValue.put(Telephony.Carriers.PROXY, mProxyAddress == null ? ""
-            : inetAddressToString(mProxyAddress));
-        apnValue.put(Telephony.Carriers.PORT, portToString(mProxyPort));
-        apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : UriToString(mMmsc));
-        apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsProxyPort));
-        apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxyAddress == null
-                ? "" : inetAddressToString(mMmsProxyAddress));
-        apnValue.put(Telephony.Carriers.USER, nullToEmpty(mUser));
-        apnValue.put(Telephony.Carriers.PASSWORD, nullToEmpty(mPassword));
-        apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType);
-        String apnType = deParseTypes(mApnTypeBitmask);
-        apnValue.put(Telephony.Carriers.TYPE, nullToEmpty(apnType));
-        apnValue.put(Telephony.Carriers.PROTOCOL,
-            nullToEmpty(PROTOCOL_INT_MAP.get(mProtocol)));
-        apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL,
-            nullToEmpty(PROTOCOL_INT_MAP.get(mRoamingProtocol)));
-        apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
-        apnValue.put(Telephony.Carriers.MVNO_TYPE,
-            nullToEmpty(MVNO_TYPE_INT_MAP.get(mMvnoType)));
-        apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
-
-        return apnValue;
-    }
-
     /**
-     * @param types comma delimited list of APN types
-     * @return bitmask of APN types
+     * @param types comma delimited list of APN types.
+     * @return bitmask of APN types.
      * @hide
      */
-    public static int parseTypes(String types) {
+    public static int getApnTypesBitmaskFromString(String types) {
         // If unset, set to ALL.
         if (TextUtils.isEmpty(types)) {
-            return TYPE_ALL_BUT_IA;
+            return TYPE_ALL;
         } else {
             int result = 0;
             for (String str : types.split(",")) {
-                Integer type = APN_TYPE_STRING_MAP.get(str);
+                Integer type = APN_TYPE_STRING_MAP.get(str.toLowerCase());
                 if (type != null) {
                     result |= type;
                 }
@@ -915,15 +1199,40 @@
         }
     }
 
+    /** @hide */
+    public static int getMvnoTypeIntFromString(String mvnoType) {
+        Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoType);
+        return  mvnoTypeInt == null ? UNSPECIFIED_INT : mvnoTypeInt;
+    }
+
+    /** @hide */
+    public static String getMvnoTypeStringFromInt(int mvnoType) {
+        String mvnoTypeString = MVNO_TYPE_INT_MAP.get(mvnoType);
+        return  mvnoTypeString == null ? UNSPECIFIED_STRING : mvnoTypeString;
+    }
+
+    /** @hide */
+    public static int getProtocolIntFromString(String protocol) {
+        Integer protocolInt = PROTOCOL_STRING_MAP.get(protocol);
+        return  protocolInt == null ? UNSPECIFIED_INT : protocolInt;
+    }
+
+    /** @hide */
+    public static String getProtocolStringFromInt(int protocol) {
+        String protocolString = PROTOCOL_INT_MAP.get(protocol);
+        return  protocolString == null ? UNSPECIFIED_STRING : protocolString;
+    }
+
     private static Uri UriFromString(String uri) {
         return TextUtils.isEmpty(uri) ? null : Uri.parse(uri);
     }
 
     private static String UriToString(Uri uri) {
-        return uri == null ? "" : uri.toString();
+        return uri == null ? null : uri.toString();
     }
 
-    private static InetAddress inetAddressFromString(String inetAddress) {
+    /** @hide */
+    public static InetAddress inetAddressFromString(String inetAddress) {
         if (TextUtils.isEmpty(inetAddress)) {
             return null;
         }
@@ -935,7 +1244,8 @@
         }
     }
 
-    private static String inetAddressToString(InetAddress inetAddress) {
+    /** @hide */
+    public static String inetAddressToString(InetAddress inetAddress) {
         if (inetAddress == null) {
             return null;
         }
@@ -952,7 +1262,7 @@
     }
 
     private static int portFromString(String strPort) {
-        int port = NO_PORT_SPECIFIED;
+        int port = UNSPECIFIED_INT;
         if (!TextUtils.isEmpty(strPort)) {
             try {
                 port = Integer.parseInt(strPort);
@@ -964,7 +1274,7 @@
     }
 
     private static String portToString(int port) {
-        return port == NO_PORT_SPECIFIED ? "" : Integer.toString(port);
+        return port == UNSPECIFIED_INT ? null : Integer.toString(port);
     }
 
     // Implement Parcelable.
@@ -981,10 +1291,10 @@
         dest.writeString(mOperatorNumeric);
         dest.writeString(mEntryName);
         dest.writeString(mApnName);
-        dest.writeValue(mProxyAddress);
+        dest.writeString(mProxyAddress);
         dest.writeInt(mProxyPort);
         dest.writeValue(mMmsc);
-        dest.writeValue(mMmsProxyAddress);
+        dest.writeString(mMmsProxyAddress);
         dest.writeInt(mMmsProxyPort);
         dest.writeString(mUser);
         dest.writeString(mPassword);
@@ -992,7 +1302,7 @@
         dest.writeInt(mApnTypeBitmask);
         dest.writeInt(mProtocol);
         dest.writeInt(mRoamingProtocol);
-        dest.writeInt(mCarrierEnabled ? 1: 0);
+        dest.writeBoolean(mCarrierEnabled);
         dest.writeInt(mMvnoType);
         dest.writeInt(mNetworkTypeBitmask);
     }
@@ -1002,10 +1312,10 @@
         final String operatorNumeric = in.readString();
         final String entryName = in.readString();
         final String apnName = in.readString();
-        final InetAddress proxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
+        final String proxy = in.readString();
         final int port = in.readInt();
         final Uri mmsc = (Uri)in.readValue(Uri.class.getClassLoader());
-        final InetAddress mmsProxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
+        final String mmsProxy = in.readString();
         final int mmsPort = in.readInt();
         final String user = in.readString();
         final String password = in.readString();
@@ -1013,7 +1323,7 @@
         final int apnTypesBitmask = in.readInt();
         final int protocol = in.readInt();
         final int roamingProtocol = in.readInt();
-        final boolean carrierEnabled = in.readInt() > 0;
+        final boolean carrierEnabled = in.readBoolean();
         final int mvnoType = in.readInt();
         final int networkTypeBitmask = in.readInt();
 
@@ -1027,35 +1337,64 @@
             new Parcelable.Creator<ApnSetting>() {
                 @Override
                 public ApnSetting createFromParcel(Parcel in) {
-                    return readFromParcel(in);
-                }
+                return readFromParcel(in);
+            }
 
                 @Override
                 public ApnSetting[] newArray(int size) {
-                    return new ApnSetting[size];
-                }
+                return new ApnSetting[size];
+            }
             };
 
-    private static int nullToNotInMapInt(Integer value) {
-        return value == null ? NOT_IN_MAP_INT : value;
-    }
-
+    /**
+     * Provides a convenient way to set the fields of a {@link ApnSetting} when creating a new
+     * instance. The following settings are required to build an {@code ApnSetting}:
+     *
+     * <ul><li>apnTypeBitmask</li>
+     * <li>apnName</li>
+     * <li>entryName</li></ul>
+     *
+     * <p>The example below shows how you might create a new {@code ApnSetting}:
+     *
+     * <pre><code>
+     * // Create an MMS proxy address with a hostname. A network might not be
+     * // available, so supply a dummy (0.0.0.0) IPv4 address to avoid DNS lookup.
+     * String host = "mms.example.com";
+     * byte[] ipAddress = new byte[4];
+     * InetAddress mmsProxy;
+     * try {
+     *   mmsProxy = InetAddress.getByAddress(host, ipAddress);
+     * } catch (UnknownHostException e) {
+     *   e.printStackTrace();
+     *   return;
+     * }
+     *
+     * ApnSetting apn = new ApnSetting.Builder()
+     *     .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS)
+     *     .setApnName("apn.example.com")
+     *     .setEntryName("Example Carrier APN")
+     *     .setMmsc(Uri.parse("http://mms.example.com:8002"))
+     *     .setMmsProxyAddress(mmsProxy)
+     *     .setMmsProxyPort(8799)
+     *     .build();
+     * </code></pre>
+     */
     public static class Builder{
         private String mEntryName;
         private String mApnName;
-        private InetAddress mProxyAddress;
-        private int mProxyPort = NO_PORT_SPECIFIED;
+        private String mProxyAddress;
+        private int mProxyPort = UNSPECIFIED_INT;
         private Uri mMmsc;
-        private InetAddress mMmsProxyAddress;
-        private int mMmsProxyPort = NO_PORT_SPECIFIED;
+        private String mMmsProxyAddress;
+        private int mMmsProxyPort = UNSPECIFIED_INT;
         private String mUser;
         private String mPassword;
         private int mAuthType;
         private int mApnTypeBitmask;
         private int mId;
         private String mOperatorNumeric;
-        private int mProtocol = NOT_IN_MAP_INT;
-        private int mRoamingProtocol = NOT_IN_MAP_INT;
+        private int mProtocol = UNSPECIFIED_INT;
+        private int mRoamingProtocol = UNSPECIFIED_INT;
         private int mMtu;
         private int mNetworkTypeBitmask;
         private boolean mCarrierEnabled;
@@ -1064,8 +1403,9 @@
         private int mMaxConns;
         private int mWaitTime;
         private int mMaxConnsTime;
-        private int mMvnoType = NOT_IN_MAP_INT;
+        private int mMvnoType = UNSPECIFIED_INT;
         private String mMvnoMatchData;
+        private int mApnSetId;
 
         /**
          * Default constructor for Builder.
@@ -1160,7 +1500,18 @@
         }
 
         /**
-         * Sets the entry name of the APN.
+         * Sets the APN set id for the APN.
+         *
+         * @param apnSetId the set id for the APN
+         * @hide
+         */
+        public Builder setApnSetId(int apnSetId) {
+            this.mApnSetId = apnSetId;
+            return this;
+        }
+
+        /**
+         * Sets a human-readable name that describes the APN.
          *
          * @param entryName the entry name to set for the APN
          */
@@ -1180,11 +1531,31 @@
         }
 
         /**
+         * Sets the address of an HTTP proxy for the APN. The proxy address can be an IP address or
+         * hostname. If {@code proxy} contains both an IP address and hostname, this method ignores
+         * the IP address.
+         *
+         * <p>The {@link java.net.InetAddress} methods
+         * {@link java.net.InetAddress#getAllByName getAllByName()} require DNS for hostname
+         * resolution. To avoid this requirement when setting a hostname, call
+         * {@link java.net.InetAddress#getByAddress(java.lang.String, byte[])} with both the
+         * hostname and a dummy IP address. See {@link ApnSetting.Builder above} for an example.
+         *
+         * @param proxy the proxy address to set for the APN
+         * @deprecated use {@link #setProxyAddress(String)} instead.
+         */
+        @Deprecated
+        public Builder setProxyAddress(InetAddress proxy) {
+            this.mProxyAddress = inetAddressToString(proxy);
+            return this;
+        }
+
+        /**
          * Sets the proxy address of the APN.
          *
          * @param proxy the proxy address to set for the APN
          */
-        public Builder setProxyAddress(InetAddress proxy) {
+        public Builder setProxyAddress(String proxy) {
             this.mProxyAddress = proxy;
             return this;
         }
@@ -1210,11 +1581,32 @@
         }
 
         /**
+         * Sets the address of an MMS proxy for the APN. The MMS proxy address can be an IP address
+         * or hostname. If {@code mmsProxy} contains both an IP address and hostname, this method
+         * ignores the IP address.
+         *
+         * <p>The {@link java.net.InetAddress} methods
+         * {@link java.net.InetAddress#getByName getByName()} and
+         * {@link java.net.InetAddress#getAllByName getAllByName()} require DNS for hostname
+         * resolution. To avoid this requirement when setting a hostname, call
+         * {@link java.net.InetAddress#getByAddress(java.lang.String, byte[])} with both the
+         * hostname and a dummy IP address. See {@link ApnSetting.Builder above} for an example.
+         *
+         * @param mmsProxy the MMS proxy address to set for the APN
+         * @deprecated use {@link #setMmsProxyAddress(String)} instead.
+         */
+        @Deprecated
+        public Builder setMmsProxyAddress(InetAddress mmsProxy) {
+            this.mMmsProxyAddress = inetAddressToString(mmsProxy);
+            return this;
+        }
+
+        /**
          * Sets the MMS proxy address of the APN.
          *
          * @param mmsProxy the MMS proxy address to set for the APN
          */
-        public Builder setMmsProxyAddress(InetAddress mmsProxy) {
+        public Builder setMmsProxyAddress(String mmsProxy) {
             this.mMmsProxyAddress = mmsProxy;
             return this;
         }
@@ -1356,6 +1748,15 @@
             }
             return new ApnSetting(this);
         }
+
+        /**
+         * Builds {@link ApnSetting} from this builder. This function doesn't check if
+         * {@link #setApnName(String)} or {@link #setEntryName(String)}, or
+         * {@link #setApnTypeBitmask(int)} is empty.
+         * @hide
+         */
+        public ApnSetting buildWithoutCheck() {
+            return new ApnSetting(this);
+        }
     }
 }
-
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 4ca5ce3..1db5850 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -44,11 +44,11 @@
 /**
  * Base class of data service. Services that extend DataService must register the service in
  * their AndroidManifest to be detected by the framework. They must be protected by the permission
- * "android.permission.BIND_DATA_SERVICE". The data service definition in the manifest must follow
- * the following format:
+ * "android.permission.BIND_TELEPHONY_DATA_SERVICE". The data service definition in the manifest
+ * must follow the following format:
  * ...
  * <service android:name=".xxxDataService"
- *     android:permission="android.permission.BIND_DATA_SERVICE" >
+ *     android:permission="android.permission.BIND_TELEPHONY_DATA_SERVICE" >
  *     <intent-filter>
  *         <action android:name="android.telephony.data.DataService" />
  *     </intent-filter>
diff --git a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
index 6d72181..2831127 100644
--- a/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
+++ b/telephony/java/android/telephony/ims/ImsCallForwardInfo.java
@@ -29,27 +29,47 @@
 public final class ImsCallForwardInfo implements Parcelable {
     // Refer to ImsUtInterface#CDIV_CF_XXX
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter.
     public int mCondition;
     // 0: disabled, 1: enabled
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter.
     public int mStatus;
     // 0x91: International, 0x81: Unknown
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter.
     public int mToA;
     // Service class
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter.
     public int mServiceClass;
     // Number (it will not include the "sip" or "tel" URI scheme)
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter.
     public String mNumber;
     // No reply timer for CF
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter.
     public int mTimeSeconds;
 
     /** @hide */
+    // TODO: Will be removed in the future, use public constructor instead.
     public ImsCallForwardInfo() {
     }
 
+    /**
+     * IMS Call Forward Information.
+     */
+    public ImsCallForwardInfo(int condition, int status, int toA, int serviceClass, String number,
+            int replyTimerSec) {
+        mCondition = condition;
+        mStatus = status;
+        mToA = toA;
+        mServiceClass = serviceClass;
+        mNumber = number;
+        mTimeSeconds = replyTimerSec;
+    }
+
     /** @hide */
     public ImsCallForwardInfo(Parcel in) {
         readFromParcel(in);
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index e82c115..d03c7e1 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -45,6 +45,7 @@
     private int mCallId;
     // Number
     private Uri mAddress;
+    private Uri mLocalAddress;
     private boolean mIsPullable;
     // CALL_STATE_CONFIRMED / CALL_STATE_TERMINATED
     private int mCallState;
@@ -69,6 +70,19 @@
     }
 
     /** @hide */
+    public ImsExternalCallState(int callId, Uri address, Uri localAddress,
+            boolean isPullable, int callState, int callType, boolean isCallheld) {
+        mCallId = callId;
+        mAddress = address;
+        mLocalAddress = localAddress;
+        mIsPullable = isPullable;
+        mCallState = callState;
+        mCallType = callType;
+        mIsHeld = isCallheld;
+        Rlog.d(TAG, "ImsExternalCallState = " + this);
+    }
+
+    /** @hide */
     public ImsExternalCallState(Parcel in) {
         mCallId = in.readInt();
         ClassLoader classLoader = ImsExternalCallState.class.getClassLoader();
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 7d65430..e70e633 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -399,6 +399,160 @@
      */
     public static final int CODE_UNOBTAINABLE_NUMBER = 1515;
 
+    /**
+     * The rejection cause is not known.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_UNKNOWN = 1600;
+
+    /**
+     * Ongoing call, and call waiting is disabled.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601;
+
+    /**
+     * A call is ongoing on another sub.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602;
+
+    /**
+     * CDMA call collision.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_1X_COLLISION = 1603;
+
+    /**
+     * IMS is not registered for service yet.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604;
+
+    /**
+     * The call type is not allowed on the current RAT.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605;
+
+    /**
+     * And emergency call is ongoing.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_E911_CALL = 1606;
+
+    /**
+     * Another call is in the process of being establilshed.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607;
+
+    /**
+     * Maximum number of allowed calls are already in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608;
+
+    /**
+     * Invalid/unsupported SIP headers received.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609;
+
+    /**
+     * Invalid/unsupported SDP headers received.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610;
+
+    /**
+     * A call transfer is in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611;
+
+    /**
+     * An internal error occured while processing the call.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_INTERNAL_ERROR = 1612;
+
+    /**
+     * Call failure due to lack of dedicated bearer.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_QOS_FAILURE = 1613;
+
+    /**
+     * A call handover is in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_HANDOVER = 1614;
+
+    /**
+     * Video calling not supported with TTY.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615;
+
+    /**
+     * A call upgrade is in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616;
+
+    /**
+     * Call from conference server, when TTY mode is ON.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617;
+
+    /**
+     * A conference call is ongoing.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618;
+
+    /**
+     * A video call with AVPF is not supported.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619;
+
+    /**
+     * And encrypted call is ongoing; other calls not supported.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620;
+
+    /**
+     * A CS call is ongoing.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CS_CALL = 1621;
+
     /* OEM specific error codes. To be used by OEMs when they don't want to
    reveal error code which would be replaced by ERROR_UNSPECIFIED */
     public static final int CODE_OEM_CAUSE_1 = 0xf001;
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index 1ddf199..b68055e 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -15,19 +15,24 @@
  */
 package android.telephony.ims;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
- * Provided STK Call Control Suplementary Service information
+ * Provides STK Call Control Supplementary Service information.
  *
  * {@hide}
  */
 @SystemApi
 public final class ImsSsData implements Parcelable {
 
-    //ServiceType
+    // Supplementary Service Type
+    // Call Forwarding
     public static final int SS_CFU = 0;
     public static final int SS_CF_BUSY = 1;
     public static final int SS_CF_NO_REPLY = 2;
@@ -35,12 +40,16 @@
     public static final int SS_CF_ALL = 4;
     public static final int SS_CF_ALL_CONDITIONAL = 5;
     public static final int SS_CFUT = 6;
+    // Called Line Presentation
     public static final int SS_CLIP = 7;
     public static final int SS_CLIR = 8;
     public static final int SS_COLP = 9;
     public static final int SS_COLR = 10;
+    // Calling Name Presentation
     public static final int SS_CNAP = 11;
+    // Call Waiting
     public static final int SS_WAIT = 12;
+    // Call Barring
     public static final int SS_BAOC = 13;
     public static final int SS_BAOIC = 14;
     public static final int SS_BAOIC_EXC_HOME = 15;
@@ -52,14 +61,14 @@
     public static final int SS_INCOMING_BARRING_DN = 21;
     public static final int SS_INCOMING_BARRING_ANONYMOUS = 22;
 
-    //SSRequestType
+    //Supplementary Service Request Types
     public static final int SS_ACTIVATION = 0;
     public static final int SS_DEACTIVATION = 1;
     public static final int SS_INTERROGATION = 2;
     public static final int SS_REGISTRATION = 3;
     public static final int SS_ERASURE = 4;
 
-    //TeleserviceType
+    // Supplementary Service Teleservice Type
     public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0;
     public static final int SS_ALL_TELESEVICES = 1;
     public static final int SS_TELEPHONY = 2;
@@ -67,40 +76,227 @@
     public static final int SS_SMS_SERVICES = 4;
     public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5;
 
-    // Refer to ServiceType
+    // Service Class of Supplementary Service
+    // See 27.007 +CCFC or +CLCK
     /** @hide */
+    public static final int SERVICE_CLASS_NONE = 0; // no user input
+    /** @hide */
+    public static final int SERVICE_CLASS_VOICE = 1;
+    /** @hide */
+    public static final int SERVICE_CLASS_DATA = (1 << 1);
+    /** @hide */
+    public static final int SERVICE_CLASS_FAX = (1 << 2);
+    /** @hide */
+    public static final int SERVICE_CLASS_SMS = (1 << 3);
+    /** @hide */
+    public static final int SERVICE_CLASS_DATA_SYNC = (1 << 4);
+    /** @hide */
+    public static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5);
+    /** @hide */
+    public static final int SERVICE_CLASS_PACKET = (1 << 6);
+    /** @hide */
+    public static final int SERVICE_CLASS_PAD = (1 << 7);
+
+    /**
+     * Result code used if the operation was successful. See {@link #result}.
+     * @hide
+     */
+    public static final int RESULT_SUCCESS = 0;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "SS_" }, value = {
+            SS_CFU,
+            SS_CF_BUSY,
+            SS_CF_NO_REPLY,
+            SS_CF_NOT_REACHABLE,
+            SS_CF_ALL,
+            SS_CF_ALL_CONDITIONAL,
+            SS_CFUT,
+            SS_CLIP,
+            SS_CLIR,
+            SS_COLP,
+            SS_COLR,
+            SS_CNAP,
+            SS_WAIT,
+            SS_BAOC,
+            SS_BAOIC,
+            SS_BAOIC_EXC_HOME,
+            SS_BAIC,
+            SS_BAIC_ROAMING,
+            SS_ALL_BARRING,
+            SS_OUTGOING_BARRING,
+            SS_INCOMING_BARRING,
+            SS_INCOMING_BARRING_DN,
+            SS_INCOMING_BARRING_ANONYMOUS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ServiceType{}
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "SERVICE_CLASS" }, value = {
+            SERVICE_CLASS_NONE,
+            SERVICE_CLASS_VOICE,
+            SERVICE_CLASS_DATA,
+            SERVICE_CLASS_FAX,
+            SERVICE_CLASS_SMS,
+            SERVICE_CLASS_DATA_SYNC,
+            SERVICE_CLASS_DATA_ASYNC,
+            SERVICE_CLASS_PACKET,
+            SERVICE_CLASS_PAD
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ServiceClass{}
+
+    /**
+     * The Service type of this Supplementary service. Valid values include:
+     *     SS_CFU,
+     *     SS_CF_BUSY,
+     *     SS_CF_NO_REPLY,
+     *     SS_CF_NOT_REACHABLE,
+     *     SS_CF_ALL,
+     *     SS_CF_ALL_CONDITIONAL,
+     *     SS_CFUT,
+     *     SS_CLIP,
+     *     SS_CLIR,
+     *     SS_COLP,
+     *     SS_COLR,
+     *     SS_CNAP,
+     *     SS_WAIT,
+     *     SS_BAOC,
+     *     SS_BAOIC,
+     *     SS_BAOIC_EXC_HOME,
+     *     SS_BAIC,
+     *     SS_BAIC_ROAMING,
+     *     SS_ALL_BARRING,
+     *     SS_OUTGOING_BARRING,
+     *     SS_INCOMING_BARRING,
+     *     SS_INCOMING_BARRING_DN,
+     *     SS_INCOMING_BARRING_ANONYMOUS
+     *
+     * @hide
+     */
+    // TODO: Make final, do not modify this field directly!
     public int serviceType;
-    // Refere to SSRequestType
-    /** @hide */
+
+    /**
+     * Supplementary Service request Type. Valid values are:
+     *     SS_ACTIVATION,
+     *     SS_DEACTIVATION,
+     *     SS_INTERROGATION,
+     *     SS_REGISTRATION,
+     *     SS_ERASURE
+     *
+     * @hide
+     */
+    // TODO: Make final, do not modify this field directly!
     public int requestType;
-    // Refer to TeleserviceType
-    /** @hide */
+
+    /**
+     * Supplementary Service teleservice type:
+     *     SS_TELESERVICE_ALL_TELE_AND_BEARER,
+     *     SS_TELESERVICE_ALL_TELESEVICES,
+     *     SS_TELESERVICE_TELEPHONY,
+     *     SS_TELESERVICE_ALL_DATA,
+     *     SS_TELESERVICE_SMS,
+     *     SS_TELESERVICE_ALL_TELESERVICES_EXCEPT_SMS
+     *
+     * @hide
+     */
+    // TODO: Make this param final! Do not try to modify this param directly.
     public int teleserviceType;
-    // Service Class
-    /** @hide */
+
+    /**
+     * Supplementary Service service class. Valid values are:
+     *     SERVICE_CLASS_NONE,
+     *     SERVICE_CLASS_VOICE,
+     *     SERVICE_CLASS_DATA,
+     *     SERVICE_CLASS_FAX,
+     *     SERVICE_CLASS_SMS,
+     *     SERVICE_CLASS_DATA_SYNC,
+     *     SERVICE_CLASS_DATA_ASYNC,
+     *     SERVICE_CLASS_PACKET,
+     *     SERVICE_CLASS_PAD
+     *
+     * @hide
+     */
+    // TODO: Make this param final! Do not try to modify this param directly.
     public int serviceClass;
-    // Error information
-    /** @hide */
-    public int result;
 
-    /** @hide */
-    public int[] ssInfo; /* Valid for all supplementary services.
-                             This field will be empty for RequestType SS_INTERROGATION
-                             and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
-                             SS_INCOMING_BARRING_ANONYMOUS.*/
+    /**
+     * Result of Supplementary Service operation. Valid values are:
+     *     RESULT_SUCCESS if the result is success, or
+     *     ImsReasonInfo code if the result is a failure.
+     *
+     * @hide
+     */
+    // TODO: Make this param final! Do not try to modify this param directly.
+    public final int result;
 
-    /** @hide */
-    public ImsCallForwardInfo[] cfInfo; /* Valid only for supplementary services
-                                            ServiceType SS_CF_* and RequestType SS_INTERROGATION */
+    private int[] mSsInfo;
+    private ImsCallForwardInfo[] mCfInfo;
+    private ImsSsInfo[] mImsSsInfo;
 
-    /** @hide */
-    public ImsSsInfo[] imsSsInfo;   /* Valid only for ServiceType SS_INCOMING_BARRING_DN and
-                                        ServiceType SS_INCOMING_BARRING_ANONYMOUS */
-
-    public ImsSsData() {}
+    /**
+     * Generate IMS Supplementary Service information.
+     * @param serviceType The Supplementary Service type. Valid entries:
+     *     SS_CFU,
+     *     SS_CF_BUSY,
+     *     SS_CF_NO_REPLY,
+     *     SS_CF_NOT_REACHABLE,
+     *     SS_CF_ALL,
+     *     SS_CF_ALL_CONDITIONAL,
+     *     SS_CFUT,
+     *     SS_CLIP,
+     *     SS_CLIR,
+     *     SS_COLP,
+     *     SS_COLR,
+     *     SS_CNAP,
+     *     SS_WAIT,
+     *     SS_BAOC,
+     *     SS_BAOIC,
+     *     SS_BAOIC_EXC_HOME,
+     *     SS_BAIC,
+     *     SS_BAIC_ROAMING,
+     *     SS_ALL_BARRING,
+     *     SS_OUTGOING_BARRING,
+     *     SS_INCOMING_BARRING,
+     *     SS_INCOMING_BARRING_DN,
+     *     SS_INCOMING_BARRING_ANONYMOUS
+     * @param requestType Supplementary Service request Type. Valid values are:
+     *     SS_ACTIVATION,
+     *     SS_DEACTIVATION,
+     *     SS_INTERROGATION,
+     *     SS_REGISTRATION,
+     *     SS_ERASURE
+     * @param teleserviceType Supplementary Service teleservice type:
+     *     SS_TELESERVICE_ALL_TELE_AND_BEARER,
+     *     SS_TELESERVICE_ALL_TELESEVICES,
+     *     SS_TELESERVICE_TELEPHONY,
+     *     SS_TELESERVICE_ALL_DATA,
+     *     SS_TELESERVICE_SMS,
+     *     SS_TELESERVICE_ALL_TELESERVICES_EXCEPT_SMS
+     * @param serviceClass Supplementary Service service class. See See 27.007 +CCFC or +CLCK.
+     * @param result Result of Supplementary Service operation. Valid values are 0 if the result is
+     *               success, or ImsReasonInfo code if the result is a failure.
+     */
+    public ImsSsData(@ServiceType int serviceType, int requestType, int teleserviceType,
+            @ServiceClass int serviceClass, int result) {
+        this.serviceType = serviceType;
+        this.requestType = requestType;
+        this.teleserviceType = teleserviceType;
+        this.serviceClass = serviceClass;
+        this.result = result;
+    }
 
     private ImsSsData(Parcel in) {
-        readFromParcel(in);
+        serviceType = in.readInt();
+        requestType = in.readInt();
+        teleserviceType = in.readInt();
+        serviceClass = in.readInt();
+        result = in.readInt();
+        mSsInfo = in.createIntArray();
+        mCfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
+        mImsSsInfo = (ImsSsInfo[])in.readParcelableArray(this.getClass().getClassLoader());
     }
 
     public static final Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() {
@@ -122,18 +318,9 @@
         out.writeInt(teleserviceType);
         out.writeInt(serviceClass);
         out.writeInt(result);
-        out.writeIntArray(ssInfo);
-        out.writeParcelableArray(cfInfo, 0);
-    }
-
-    private void readFromParcel(Parcel in) {
-        serviceType = in.readInt();
-        requestType = in.readInt();
-        teleserviceType = in.readInt();
-        serviceClass = in.readInt();
-        result = in.readInt();
-        ssInfo = in.createIntArray();
-        cfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
+        out.writeIntArray(mSsInfo);
+        out.writeParcelableArray(mCfInfo, 0);
+        out.writeParcelableArray(mImsSsInfo, 0);
     }
 
     @Override
@@ -200,7 +387,55 @@
     }
 
     public boolean isTypeInterrogation() {
-        return (requestType == SS_INTERROGATION);
+        return (serviceType == SS_INTERROGATION);
+    }
+
+    /** @hide */
+    public void setSuppServiceInfo(int[] ssInfo) {
+        mSsInfo = ssInfo;
+    }
+
+    /** @hide */
+    public void setImsSpecificSuppServiceInfo(ImsSsInfo[] imsSsInfo) {
+        mImsSsInfo = imsSsInfo;
+    }
+
+    /** @hide */
+    public void setCallForwardingInfo(ImsCallForwardInfo[] cfInfo) {
+        mCfInfo = cfInfo;
+    }
+
+    /**
+     * This field will be null for RequestType SS_INTERROGATION
+     * and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
+     * SS_INCOMING_BARRING_ANONYMOUS.
+     *
+     * @hide
+     */
+    public int[] getSuppServiceInfo() {
+        return mSsInfo;
+    }
+
+    /**
+     * Valid only for ServiceTypes
+     *  - SS_INCOMING_BARRING_DN and
+     *  - ServiceType SS_INCOMING_BARRING_ANONYMOUS.
+     *  Will be null otherwise.
+     * @hide
+     */
+    public ImsSsInfo[] getImsSpecificSuppServiceInfo() {
+        return mImsSsInfo;
+    }
+
+    /**
+     * Valid only for supplementary services
+     * - ServiceType SS_CF_* and
+     * - RequestType SS_INTERROGATION.
+     * Will be null otherwise.
+     * @hide
+     **/
+    public ImsCallForwardInfo[] getCallForwardInfo() {
+        return mCfInfo;
     }
 
     public String toString() {
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index 1d1292f..c6f8622 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -36,13 +36,31 @@
 
     // 0: disabled, 1: enabled
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter!
     public int mStatus;
     /** @hide */
+    // TODO: Make private, do not modify this field directly, use getter!
     public String mIcbNum;
 
+    /**@hide*/
+    // TODO: Remove! Do not use this constructor, instead use public version.
     public ImsSsInfo() {
     }
 
+    /**
+     *
+     * @param status The status of the service registration of activation/deactiviation. Valid
+     *    entries include:
+     *    {@link #NOT_REGISTERED},
+     *    {@link #DISABLED},
+     *    {@link #ENABLED}
+     * @param icbNum The Incoming barring number.
+     */
+    public ImsSsInfo(int status, String icbNum) {
+        mStatus = status;
+        mIcbNum = icbNum;
+    }
+
     private ImsSsInfo(Parcel in) {
         readFromParcel(in);
     }
@@ -81,6 +99,12 @@
         }
     };
 
+    /**
+     * @return Supplementary Service Configuration status. Valid Values are:
+     *     {@link #NOT_REGISTERED},
+     *     {@link #DISABLED},
+     *     {@link #ENABLED}
+     */
     public int getStatus() {
         return mStatus;
     }
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
index 904e7ca..7bbe30a 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
@@ -18,6 +18,9 @@
 
 import android.os.Bundle;
 
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsReasonInfo;
+
 import com.android.ims.internal.IImsCallSession;
 
 /**
@@ -26,5 +29,6 @@
  */
 oneway interface IImsMmTelListener {
     void onIncomingCall(IImsCallSession c, in Bundle extras);
+    void onRejectedCall(in ImsCallProfile callProfile, in ImsReasonInfo reason);
     void onVoiceMessageCountUpdate(int count);
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index d537699..b77881e 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -341,15 +341,15 @@
         }
     }
 
+    /** @hide */
+    protected Context mContext;
+    /** @hide */
+    protected final Object mLock = new Object();
+
     private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
             new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
     private @ImsState int mState = STATE_UNAVAILABLE;
     private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-    /**
-     * @hide
-     */
-    protected Context mContext;
-    private final Object mLock = new Object();
     private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks
             = new RemoteCallbackList<>();
     private Capabilities mCapabilityStatus = new Capabilities();
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index aaf1a1cf8..7681aef 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -18,29 +18,29 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.Message;
 import android.os.RemoteException;
 import android.telecom.TelecomManager;
-import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.telephony.ims.stub.ImsCallSessionImplBase;
-import android.telephony.ims.stub.ImsSmsImplBase;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsCallSession;
+import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsMmTelFeature;
 import android.telephony.ims.aidl.IImsMmTelListener;
 import android.telephony.ims.aidl.IImsSmsListener;
+import android.telephony.ims.stub.ImsCallSessionImplBase;
 import android.telephony.ims.stub.ImsEcbmImplBase;
 import android.telephony.ims.stub.ImsMultiEndpointImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.telephony.ims.stub.ImsSmsImplBase;
 import android.telephony.ims.stub.ImsUtImplBase;
 import android.util.Log;
 
-import android.telephony.ims.ImsCallProfile;
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsMultiEndpoint;
 import com.android.ims.internal.IImsUt;
-import android.telephony.ims.ImsCallSession;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
@@ -61,20 +61,16 @@
     private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
 
         @Override
-        public void setListener(IImsMmTelListener l) throws RemoteException {
-            synchronized (mLock) {
-                MmTelFeature.this.setListener(l);
-            }
+        public void setListener(IImsMmTelListener l) {
+            MmTelFeature.this.setListener(l);
         }
 
         @Override
         public int getFeatureState() throws RemoteException {
-            synchronized (mLock) {
-                try {
-                    return MmTelFeature.this.getFeatureState();
-                } catch (Exception e) {
-                    throw new RemoteException(e.getMessage());
-                }
+            try {
+                return MmTelFeature.this.getFeatureState();
+            } catch (Exception e) {
+                throw new RemoteException(e.getMessage());
             }
         }
 
@@ -138,10 +134,8 @@
         }
 
         @Override
-        public int queryCapabilityStatus() throws RemoteException {
-            synchronized (mLock) {
-                return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
-            }
+        public int queryCapabilityStatus() {
+            return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
         }
 
         @Override
@@ -158,7 +152,7 @@
 
         @Override
         public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
-                IImsCapabilityCallback c) throws RemoteException {
+                IImsCapabilityCallback c) {
             synchronized (mLock) {
                 MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
             }
@@ -173,10 +167,8 @@
         }
 
         @Override
-        public void setSmsListener(IImsSmsListener l) throws RemoteException {
-            synchronized (mLock) {
-                MmTelFeature.this.setSmsListener(l);
-            }
+        public void setSmsListener(IImsSmsListener l) {
+            MmTelFeature.this.setSmsListener(l);
         }
 
         @Override
@@ -326,6 +318,16 @@
         }
 
         /**
+         * Called when the IMS provider implicitly rejects an incoming call during setup.
+         * @param callProfile An {@link ImsCallProfile} with the call details.
+         * @param reason The {@link ImsReasonInfo} reason for call rejection.
+         */
+        @Override
+        public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
+
+        }
+
+        /**
          * Updates the Listener when the voice message count for IMS has changed.
          * @param count an integer representing the new message count.
          */
@@ -354,9 +356,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProcessCallResult {}
 
-
-    // Lock for feature synchronization
-    private final Object mLock = new Object();
     private IImsMmTelListener mListener;
 
     /**
@@ -366,9 +365,9 @@
     private void setListener(IImsMmTelListener listener) {
         synchronized (mLock) {
             mListener = listener;
-        }
-        if (mListener != null) {
-            onFeatureReady();
+            if (mListener != null) {
+                onFeatureReady();
+            }
         }
     }
 
@@ -429,6 +428,26 @@
     }
 
     /**
+     * Notify the framework that a call has been implicitly rejected by this MmTelFeature
+     * during call setup.
+     * @param callProfile The {@link ImsCallProfile} IMS call profile with details.
+     *        This can be null if no call information is available for the rejected call.
+     * @param reason The {@link ImsReasonInfo} call rejection reason.
+     */
+    public final void notifyRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
+        synchronized (mLock) {
+            if (mListener == null) {
+                throw new IllegalStateException("Session is not available.");
+            }
+            try {
+                mListener.onRejectedCall(callProfile, reason);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
      *
      * @hide
      */
@@ -613,7 +632,19 @@
      *         {@link TelecomManager#TTY_MODE_FULL},
      *         {@link TelecomManager#TTY_MODE_HCO},
      *         {@link TelecomManager#TTY_MODE_VCO}
-     * @param onCompleteMessage A {@link Message} to be used when the mode has been set.
+     * @param onCompleteMessage If non-null, this MmTelFeature should call this {@link Message} when
+     *         the operation is complete by using the associated {@link android.os.Messenger} in
+     *         {@link Message#replyTo}. For example:
+     * {@code
+     *     // Set UI TTY Mode and other operations...
+     *     try {
+     *         // Notify framework that the mode was changed.
+     *         Messenger uiMessenger = onCompleteMessage.replyTo;
+     *         uiMessenger.send(onCompleteMessage);
+     *     } catch (RemoteException e) {
+     *         // Remote side is dead
+     *     }
+     * }
      */
     public void setUiTtyMode(int mode, Message onCompleteMessage) {
         // Base Implementation - Should be overridden
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index 7b9fe2b..da6a7a6 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -30,8 +30,6 @@
 import com.android.ims.internal.IImsVideoCallProvider;
 import android.telephony.ims.ImsVideoCallProvider;
 
-import dalvik.system.CloseGuard;
-
 /**
  * Base implementation of IImsCallSession, which implements stub versions of the methods available.
  *
@@ -510,6 +508,21 @@
      * and event flash to 16. Currently, event flash is not supported.
      *
      * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     * @param result If non-null, the {@link Message} to send when the operation is complete. This
+     *         is done by using the associated {@link android.os.Messenger} in
+     *         {@link Message#replyTo}. For example:
+     * {@code
+     *     // Send DTMF and other operations...
+     *     try {
+     *         // Notify framework that the DTMF was sent.
+     *         Messenger dtmfMessenger = result.replyTo;
+     *         if (dtmfMessenger != null) {
+     *             dtmfMessenger.send(result);
+     *         }
+     *     } catch (RemoteException e) {
+     *         // Remote side is dead
+     *     }
+     * }
      */
     public void sendDtmf(char c, Message result) {
     }
diff --git a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
index 2f52c0a..dfb6e2c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
+++ b/telephony/java/android/telephony/ims/stub/ImsFeatureConfiguration.java
@@ -77,6 +77,11 @@
             result = 31 * result + featureType;
             return result;
         }
+
+        @Override
+        public String toString() {
+            return "{s=" + slotId + ", f=" + featureType + "}";
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 4334d3a..31381804 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -213,6 +213,17 @@
 
     /**
      * Notify the framework that the device is disconnected from the IMS network.
+     * <p>
+     * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo)}, you should ensure that any
+     * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent
+     * to the framework.  For example,
+     * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}
+     * and
+     * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}
+     * may be set to unavailable to ensure the framework knows these services are no longer
+     * available due to de-registration.  If you do not report capability changes impacted by
+     * de-registration, the framework will not know which features are no longer available as a
+     * result.
      *
      * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
      */
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 421b015..6ad44ba 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -35,7 +35,6 @@
     private static final String TAG = "ImsConfig";
     private boolean DBG = true;
     private final IImsConfig miConfig;
-    private Context mContext;
 
     /**
      * Broadcast action: the feature enable status was changed
@@ -541,14 +540,12 @@
         public static final int WIFI_PREFERRED = 2;
     }
 
-    public ImsConfig(IImsConfig iconfig, Context context) {
-        if (DBG) Rlog.d(TAG, "ImsConfig created");
+    public ImsConfig(IImsConfig iconfig) {
         miConfig = iconfig;
-        mContext = context;
     }
 
     /**
-     * @deprecated see {@link #getInt(int)} instead.
+     * @deprecated see {@link #getConfigInt(int)} instead.
      */
     public int getProvisionedValue(int item) throws ImsException {
         return getConfigInt(item);
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index d999c13..e546917 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -63,34 +63,25 @@
     public static final int EVENT_RADIO_AVAILABLE = BASE + 1;
     public static final int EVENT_RECORDS_LOADED = BASE + 2;
     public static final int EVENT_TRY_SETUP_DATA = BASE + 3;
-    public static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
-    public static final int EVENT_POLL_PDP = BASE + 5;
     public static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
     public static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
     public static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
     public static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
-    public static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
     public static final int EVENT_ROAMING_ON = BASE + 11;
     public static final int EVENT_ROAMING_OFF = BASE + 12;
     public static final int EVENT_ENABLE_NEW_APN = BASE + 13;
-    public static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
     public static final int EVENT_DISCONNECT_DONE = BASE + 15;
     public static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
     public static final int EVENT_DATA_STALL_ALARM = BASE + 17;
     public static final int EVENT_DO_RECOVERY = BASE + 18;
     public static final int EVENT_APN_CHANGED = BASE + 19;
-    public static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
-    public static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = BASE + 21;
     public static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
     public static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
     public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
-    public static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
     public static final int EVENT_RESTART_RADIO = BASE + 26;
     public static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
-    public static final int EVENT_RESET_DONE = BASE + 28;
     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 29;
     public static final int CMD_SET_USER_DATA_ENABLE = BASE + 30;
-    public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
     public static final int EVENT_ICC_CHANGED = BASE + 33;
     public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
diff --git a/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java b/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java
new file mode 100644
index 0000000..cc1d105
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISmsBaseImpl.java
@@ -0,0 +1,199 @@
+/* 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.internal.telephony;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import java.lang.UnsupportedOperationException;
+import java.util.List;
+
+public class ISmsBaseImpl extends ISms.Stub {
+
+    @Override
+    public List<SmsRawData> getAllMessagesFromIccEfForSubscriber(int subId, String callingPkg) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean updateMessageOnIccEfForSubscriber(int subId, String callingPkg,
+             int messageIndex, int newStatus, byte[] pdu) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean copyMessageToIccEfForSubscriber(int subId, String callingPkg, int status,
+            byte[] pdu, byte[] smsc) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendDataForSubscriber(int subId, String callingPkg, String destAddr,
+            String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
+            PendingIntent deliveryIntent) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendDataForSubscriberWithSelfPermissions(int subId, String callingPkg,
+            String destAddr, String scAddr, int destPort, byte[] data,
+            PendingIntent sentIntent, PendingIntent deliveryIntent)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendTextForSubscriber(int subId, String callingPkg, String destAddr,
+            String scAddr, String text, PendingIntent sentIntent,
+            PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendTextForSubscriberWithSelfPermissions(int subId, String callingPkg,
+            String destAddr, String scAddr, String text, PendingIntent sentIntent,
+            PendingIntent deliveryIntent, boolean persistMessage)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendTextForSubscriberWithOptions(int subId, String callingPkg, String destAddr,
+            String scAddr, String text, PendingIntent sentIntent,
+            PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp,
+            int priority, boolean expectMore, int validityPeriod)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void injectSmsPduForSubscriber(
+            int subId, byte[] pdu, String format, PendingIntent receivedIntent)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendMultipartTextForSubscriber(int subId, String callingPkg,
+            String destinationAddress, String scAddress,
+            List<String> parts, List<PendingIntent> sentIntents,
+            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendMultipartTextForSubscriberWithOptions(int subId, String callingPkg,
+            String destinationAddress, String scAddress,
+            List<String> parts, List<PendingIntent> sentIntents,
+            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
+            int priority, boolean expectMore, int validityPeriod)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean enableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean disableCellBroadcastForSubscriber(int subId, int messageIdentifier, int ranType)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean enableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
+            int endMessageId, int ranType) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean disableCellBroadcastRangeForSubscriber(int subId, int startMessageId,
+            int endMessageId, int ranType) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getPremiumSmsPermission(String packageName) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getPremiumSmsPermissionForSubscriber(int subId, String packageName)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPremiumSmsPermission(String packageName, int permission) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPremiumSmsPermissionForSubscriber(int subId, String packageName,
+            int permission) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isImsSmsSupportedForSubscriber(int subId) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSmsSimPickActivityNeeded(int subId) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getPreferredSmsSubscription() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getImsSmsFormatForSubscriber(int subId) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSMSPromptEnabled() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendStoredText(int subId, String callingPkg, Uri messageUri, String scAddress,
+            PendingIntent sentIntent, PendingIntent deliveryIntent)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendStoredMultipartText(int subId, String callingPkg, Uri messageUri,
+                String scAddress, List<PendingIntent> sentIntents,
+                List<PendingIntent> deliveryIntents) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index e0297ca..3fd1d04 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -823,6 +823,16 @@
     boolean isResolvingImsBinding();
 
     /**
+    *  @return true if the ImsService to bind to for the slot id specified was set, false otherwise.
+    */
+    boolean setImsService(int slotId, boolean isCarrierImsService, String packageName);
+
+    /**
+    * @return the package name of the carrier/device ImsService associated with this slot.
+    */
+    String getImsService(int slotId, boolean isCarrierImsService);
+
+    /**
      * Set the network selection mode to automatic.
      *
      * @param subId the id of the subscription to update.
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index c095438..4790b75 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -105,7 +105,7 @@
     /**
      * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3
      * Returns a concatenated string of MCC+MNC, stripping
-     * all invalid character 'f'
+     * all invalid character 'F'
      */
     public static String bcdPlmnToString(byte[] data, int offset) {
         if (offset + 3 > data.length) {
@@ -117,9 +117,9 @@
         trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF));
         String ret = bytesToHexString(trans);
 
-        // For a valid plmn we trim all character 'f'
-        if (ret.contains("f")) {
-            ret = ret.replaceAll("f", "");
+        // For a valid plmn we trim all character 'F'
+        if (ret.contains("F")) {
+            ret = ret.replaceAll("F", "");
         }
         return ret;
     }
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 61dbcc3..4c68c8b 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -9,9 +9,10 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_CERTIFICATE := platform
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index e682f79..b3a82f5 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -32,6 +32,8 @@
 # These are not normally accessible from apps so they must be explicitly included.
 LOCAL_JNI_SHARED_LIBRARIES := \
     android.hidl.token@1.0 \
+    $(UBSAN_RUNTIME_LIBRARY) \
+    libartbase \
     libbacktrace \
     libbase \
     libbinder \
@@ -57,7 +59,9 @@
     libvndksupport \
     libtinyxml2 \
     libunwindstack \
-    libutilscallstack
+    libutilscallstack \
+    libziparchive \
+    libz
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 9191bd3..8160924 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.test.mock.MockContext;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.system.Os;
@@ -70,11 +71,17 @@
 
     private IpSecService mMockIpSecService;
     private IpSecManager mIpSecManager;
+    private MockContext mMockContext = new MockContext() {
+        @Override
+        public String getOpPackageName() {
+            return "fooPackage";
+        }
+    };
 
     @Before
     public void setUp() throws Exception {
         mMockIpSecService = mock(IpSecService.class);
-        mIpSecManager = new IpSecManager(mMockIpSecService);
+        mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
     }
 
     /*
@@ -255,7 +262,7 @@
                 new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
         when(mMockIpSecService.createTunnelInterface(
                 eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
-                anyObject(), anyObject()))
+                anyObject(), anyObject(), anyString()))
                         .thenReturn(dummyResponse);
 
         IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
@@ -273,7 +280,7 @@
         assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
 
         tunnelIntf.close();
-        verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
+        verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
     }
 
     @Test
@@ -281,12 +288,16 @@
         IpSecManager.IpSecTunnelInterface tunnelIntf =
                 createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
 
-        tunnelIntf.addAddress(VTI_INNER_ADDRESS);
+        tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
+                VTI_INNER_ADDRESS.getPrefixLength());
         verify(mMockIpSecService)
-                .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+                .addAddressToTunnelInterface(
+                        eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
 
-        tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
+        tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
+                VTI_INNER_ADDRESS.getPrefixLength());
         verify(mMockIpSecService)
-                .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+                .addAddressToTunnelInterface(
+                        eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
     }
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 0696592..2f4d69ec 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -40,12 +40,14 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -54,6 +56,9 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NetworkCapabilitiesTest {
+    private static final String TEST_SSID = "TEST_SSID";
+    private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+
     @Test
     public void testMaybeMarkCapabilitiesRestricted() {
         // verify EIMS is restricted
@@ -268,6 +273,8 @@
             .addCapability(NET_CAPABILITY_EIMS)
             .addCapability(NET_CAPABILITY_NOT_METERED);
         assertEqualsThroughMarshalling(netCap);
+        netCap.setSSID(TEST_SSID);
+        assertEqualsThroughMarshalling(netCap);
     }
 
     @Test
@@ -362,6 +369,27 @@
     }
 
     @Test
+    public void testSSID() {
+        NetworkCapabilities nc1 = new NetworkCapabilities();
+        NetworkCapabilities nc2 = new NetworkCapabilities();
+        assertTrue(nc2.satisfiedBySSID(nc1));
+
+        nc1.setSSID(TEST_SSID);
+        assertTrue(nc2.satisfiedBySSID(nc1));
+        nc2.setSSID("different " + TEST_SSID);
+        assertFalse(nc2.satisfiedBySSID(nc1));
+
+        assertTrue(nc1.satisfiedByImmutableNetworkCapabilities(nc2));
+        assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
+    }
+
+    private ArraySet<UidRange> uidRange(int from, int to) {
+        final ArraySet<UidRange> range = new ArraySet<>(1);
+        range.add(new UidRange(from, to));
+        return range;
+    }
+
+    @Test
     public void testCombineCapabilities() {
         NetworkCapabilities nc1 = new NetworkCapabilities();
         NetworkCapabilities nc2 = new NetworkCapabilities();
@@ -382,6 +410,35 @@
         // will never be satisfied.
         assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
         assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+
+        nc1.setSSID(TEST_SSID);
+        nc2.combineCapabilities(nc1);
+        assertTrue(TEST_SSID.equals(nc2.getSSID()));
+
+        // Because they now have the same SSID, the following call should not throw
+        nc2.combineCapabilities(nc1);
+
+        nc1.setSSID(DIFFERENT_TEST_SSID);
+        try {
+            nc2.combineCapabilities(nc1);
+            fail("Expected IllegalStateException: can't combine different SSIDs");
+        } catch (IllegalStateException expected) {}
+        nc1.setSSID(TEST_SSID);
+
+        nc1.setUids(uidRange(10, 13));
+        assertNotEquals(nc1, nc2);
+        nc2.combineCapabilities(nc1);  // Everything + 10~13 is still everything.
+        assertNotEquals(nc1, nc2);
+        nc1.combineCapabilities(nc2);  // 10~13 + everything is everything.
+        assertEquals(nc1, nc2);
+        nc1.setUids(uidRange(10, 13));
+        nc2.setUids(uidRange(20, 23));
+        assertNotEquals(nc1, nc2);
+        nc1.combineCapabilities(nc2);
+        assertTrue(nc1.appliesToUid(12));
+        assertFalse(nc2.appliesToUid(12));
+        assertTrue(nc1.appliesToUid(22));
+        assertTrue(nc2.appliesToUid(22));
     }
 
     @Test
@@ -420,4 +477,38 @@
         p.setDataPosition(0);
         assertEquals(NetworkCapabilities.CREATOR.createFromParcel(p), netCap);
     }
+
+    @Test
+    public void testSet() {
+        NetworkCapabilities nc1 = new NetworkCapabilities();
+        NetworkCapabilities nc2 = new NetworkCapabilities();
+
+        nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+        nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
+        assertNotEquals(nc1, nc2);
+        nc2.set(nc1);
+        assertEquals(nc1, nc2);
+        assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+        assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
+
+        // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
+        nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
+        nc1.setSSID(TEST_SSID);
+        nc2.set(nc1);
+        assertEquals(nc1, nc2);
+        // Contrary to combineCapabilities, set() will have removed the NOT_ROAMING capability
+        // from nc2.
+        assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+        assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+        assertTrue(TEST_SSID.equals(nc2.getSSID()));
+
+        nc1.setSSID(DIFFERENT_TEST_SSID);
+        nc2.set(nc1);
+        assertEquals(nc1, nc2);
+        assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSSID()));
+
+        nc1.setUids(uidRange(10, 13));
+        nc2.set(nc1);  // Overwrites, as opposed to combineCapabilities
+        assertEquals(nc1, nc2);
+    }
 }
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index ed9cbab..9838020 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -77,7 +77,7 @@
 @SmallTest
 public class ApfTest {
     private static final int TIMEOUT_MS = 500;
-    private final static int MIN_APF_VERSION = 2;
+    private static final int MIN_APF_VERSION = 2;
 
     @Mock IpConnectivityLog mLog;
     @Mock Context mContext;
@@ -90,20 +90,30 @@
     }
 
     // Expected return codes from APF interpreter.
-    private final static int PASS = 1;
-    private final static int DROP = 0;
+    private static final int PASS = 1;
+    private static final int DROP = 0;
     // Interpreter will just accept packets without link layer headers, so pad fake packet to at
     // least the minimum packet size.
-    private final static int MIN_PKT_SIZE = 15;
+    private static final int MIN_PKT_SIZE = 15;
 
     private static final ApfCapabilities MOCK_APF_CAPABILITIES =
       new ApfCapabilities(2, 1700, ARPHRD_ETHER);
 
-    private final static boolean DROP_MULTICAST = true;
-    private final static boolean ALLOW_MULTICAST = false;
+    private static final boolean DROP_MULTICAST = true;
+    private static final boolean ALLOW_MULTICAST = false;
 
-    private final static boolean DROP_802_3_FRAMES = true;
-    private final static boolean ALLOW_802_3_FRAMES = false;
+    private static final boolean DROP_802_3_FRAMES = true;
+    private static final boolean ALLOW_802_3_FRAMES = false;
+
+    // Constants for opcode encoding
+    private static final byte LI_OP   = (byte)(13 << 3);
+    private static final byte LDDW_OP = (byte)(22 << 3);
+    private static final byte STDW_OP = (byte)(23 << 3);
+    private static final byte SIZE0   = (byte)(0 << 1);
+    private static final byte SIZE8   = (byte)(1 << 1);
+    private static final byte SIZE16  = (byte)(2 << 1);
+    private static final byte SIZE32  = (byte)(3 << 1);
+    private static final byte R1 = 1;
 
     private static ApfConfiguration getDefaultConfig() {
         ApfFilter.ApfConfiguration config = new ApfConfiguration();
@@ -304,9 +314,9 @@
 
         // Test multiply.
         gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R0, 123456789);
         gen.addMul(2);
-        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
+        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test divide.
@@ -369,10 +379,10 @@
 
         // Test multiply.
         gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R0, 123456789);
         gen.addLoadImmediate(Register.R1, 2);
         gen.addMulR1();
-        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
+        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test divide.
@@ -636,29 +646,28 @@
      */
     @Test
     public void testImmediateEncoding() throws IllegalInstructionException {
-        final int LI_OPCODE = 13 << 3;
         ApfGenerator gen;
 
         // 0-byte immediate: li R0, 0
-        gen = new ApfGenerator(3);
+        gen = new ApfGenerator(4);
         gen.addLoadImmediate(Register.R0, 0);
-        assertProgramEquals(new byte[]{LI_OPCODE | (0 << 1)}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
 
         // 1-byte immediate: li R0, 42
-        gen = new ApfGenerator(3);
+        gen = new ApfGenerator(4);
         gen.addLoadImmediate(Register.R0, 42);
-        assertProgramEquals(new byte[]{LI_OPCODE | (1 << 1), 42}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
 
         // 2-byte immediate: li R1, 0x1234
-        gen = new ApfGenerator(3);
+        gen = new ApfGenerator(4);
         gen.addLoadImmediate(Register.R1, 0x1234);
-        assertProgramEquals(new byte[]{LI_OPCODE | (2 << 1) | 1 , 0x12, 0x34}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
 
         // 4-byte immediate: li R0, 0x12345678
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R0, 0x12345678);
         assertProgramEquals(
-                new byte[]{LI_OPCODE | (3 << 1), 0x12, 0x34, 0x56, 0x78},
+                new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
                 gen.generate());
     }
 
@@ -667,28 +676,61 @@
      */
     @Test
     public void testNegativeImmediateEncoding() throws IllegalInstructionException {
-        final int LI_OPCODE = 13 << 3;
         ApfGenerator gen;
 
         // 1-byte negative immediate: li R0, -42
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R0, -42);
-        assertProgramEquals(new byte[]{LI_OPCODE | (1 << 1), -42}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
 
-        // 2-byte negative immediate: li R1, -0x1234
+        // 2-byte negative immediate: li R1, -0x1122
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R1, -0x1122);
-        assertProgramEquals(new byte[]{LI_OPCODE | (2 << 1) | 1, (byte)0xEE, (byte)0xDE},
+        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
                 gen.generate());
 
         // 4-byte negative immediate: li R0, -0x11223344
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R0, -0x11223344);
         assertProgramEquals(
-                new byte[]{LI_OPCODE | (3 << 1), (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
+                new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
                 gen.generate());
     }
 
+    /**
+     * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
+     */
+    @Test
+    public void testLoadStoreDataEncoding() throws IllegalInstructionException {
+        ApfGenerator gen;
+
+        // Load data with no offset: lddw R0, [0 + r1]
+        gen = new ApfGenerator(3);
+        gen.addLoadData(Register.R0, 0);
+        assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
+
+        // Store data with 8bit negative offset: lddw r0, [-42 + r1]
+        gen = new ApfGenerator(3);
+        gen.addStoreData(Register.R0, -42);
+        assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
+
+        // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
+        gen = new ApfGenerator(3);
+        gen.addStoreData(Register.R1, -0x1122);
+        assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
+                gen.generate());
+
+        // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
+        gen = new ApfGenerator(3);
+        gen.addLoadData(Register.R1, 0xDEADBEEF);
+        assertProgramEquals(
+                new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
+                gen.generate());
+    }
+
+    /**
+     * Test that the interpreter correctly executes STDW with a negative 8bit offset
+     */
     @Test
     public void testApfDataWrite() throws IllegalInstructionException, Exception {
         byte[] packet = new byte[MIN_PKT_SIZE];
@@ -712,12 +754,15 @@
         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
     }
 
+    /**
+     * Test that the interpreter correctly executes LDDW with a negative 16bit offset
+     */
     @Test
     public void testApfDataRead() throws IllegalInstructionException, Exception {
         // Program that DROPs if address 10 (-6) contains 0x87654321.
         ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, 10);
-        gen.addLoadData(Register.R0, -16);  // 10 + -16 = -6 (offset +10 with data_len=16)
+        gen.addLoadImmediate(Register.R1, 1000);
+        gen.addLoadData(Register.R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
         gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
         byte[] program = gen.generate();
         byte[] packet = new byte[MIN_PKT_SIZE];
@@ -737,6 +782,11 @@
         assertDataMemoryContents(DROP, program, packet, data, expected_data);
     }
 
+    /**
+     * Test that the interpreter correctly executes LDDW followed by a STDW.
+     * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
+     * offset.
+     */
     @Test
     public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
         ApfGenerator gen = new ApfGenerator(3);
@@ -844,7 +894,7 @@
     }
 
     private static class TestApfFilter extends ApfFilter {
-        public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
+        public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
 
         private FileDescriptor mWriteSocket;
         private final long mFixedTimeMs = SystemClock.elapsedRealtime();
diff --git a/tests/net/java/android/net/ip/IpClientTest.java b/tests/net/java/android/net/ip/IpClientTest.java
index e9e880d..89453e0 100644
--- a/tests/net/java/android/net/ip/IpClientTest.java
+++ b/tests/net/java/android/net/ip/IpClientTest.java
@@ -133,9 +133,18 @@
         verify(mNMService, times(1)).registerObserver(arg.capture());
         mObserver = arg.getValue();
         reset(mNMService);
+        // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
+        verify(mCb, never()).onLinkPropertiesChange(any());
+        reset(mCb);
         return ipc;
     }
 
+    private static LinkProperties makeEmptyLinkProperties(String iface) {
+        final LinkProperties empty = new LinkProperties();
+        empty.setInterfaceName(iface);
+        return empty;
+    }
+
     @Test
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
@@ -197,6 +206,8 @@
         ipc.shutdown();
         verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
         verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
+        verify(mCb, timeout(100).times(1))
+                .onLinkPropertiesChange(eq(makeEmptyLinkProperties(iface)));
     }
 
     @Test
@@ -246,6 +257,8 @@
         ipc.shutdown();
         verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
         verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
+        verify(mCb, timeout(100).times(1))
+                .onLinkPropertiesChange(eq(makeEmptyLinkProperties(iface)));
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 53c62c2..5e5ba4d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -57,6 +57,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -84,6 +85,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.CaptivePortal;
 import android.net.ConnectivityManager;
@@ -94,6 +96,7 @@
 import android.net.ConnectivityThread;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -111,6 +114,7 @@
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
 import android.net.UidRange;
+import android.net.VpnService;
 import android.net.captiveportal.CaptivePortalProbeResult;
 import android.net.metrics.IpConnectivityLog;
 import android.net.util.MultinetworkPolicyTracker;
@@ -123,6 +127,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -130,9 +135,11 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.net.VpnConfig;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -142,6 +149,7 @@
 import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
+import com.android.server.connectivity.Nat464Xlat;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.Vpn;
@@ -158,10 +166,13 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
 
+import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -187,6 +198,7 @@
     private static final int TIMEOUT_MS = 500;
     private static final int TEST_LINGER_DELAY_MS = 120;
 
+    private static final String CLAT_PREFIX = "v4-";
     private static final String MOBILE_IFNAME = "test_rmnet_data0";
     private static final String WIFI_IFNAME = "test_wlan0";
 
@@ -196,6 +208,7 @@
     private MockNetworkAgent mWiFiNetworkAgent;
     private MockNetworkAgent mCellNetworkAgent;
     private MockNetworkAgent mEthernetNetworkAgent;
+    private MockVpn mMockVpn;
     private Context mContext;
 
     @Mock IpConnectivityMetrics.Logger mMetricsService;
@@ -477,6 +490,14 @@
             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
         }
 
+        public void setNetworkCapabilities(NetworkCapabilities nc,
+                boolean sendToConnectivityService) {
+            mNetworkCapabilities.set(nc);
+            if (sendToConnectivityService) {
+                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+            }
+        }
+
         public void connectWithoutInternet() {
             mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -506,6 +527,7 @@
                 mWrappedNetworkMonitor.gen204ProbeResult = 204;
                 NetworkRequest request = new NetworkRequest.Builder()
                         .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
+                        .clearCapabilities()
                         .build();
                 callback = new NetworkCallback() {
                     public void onCapabilitiesChanged(Network network,
@@ -591,6 +613,10 @@
             return mRedirectUrl;
         }
 
+        public NetworkAgent getNetworkAgent() {
+            return mNetworkAgent;
+        }
+
         public NetworkCapabilities getNetworkCapabilities() {
             return mNetworkCapabilities;
         }
@@ -723,6 +749,87 @@
         }
     }
 
+    private static Looper startHandlerThreadAndReturnLooper() {
+        final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
+        handlerThread.start();
+        return handlerThread.getLooper();
+    }
+
+    private class MockVpn extends Vpn {
+        // TODO : the interactions between this mock and the mock network agent are too
+        // hard to get right at this moment, because it's unclear in which case which
+        // target needs to get a method call or both, and in what order. It's because
+        // MockNetworkAgent wants to manage its own NetworkCapabilities, but the Vpn
+        // parent class of MockVpn agent wants that responsibility.
+        // That being said inside the test it should be possible to make the interactions
+        // harder to get wrong with precise speccing, judicious comments, helper methods
+        // and a few sprinkled assertions.
+
+        private boolean mConnected = false;
+        // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
+        // not inherit from NetworkAgent.
+        private MockNetworkAgent mMockNetworkAgent;
+
+        public MockVpn(int userId) {
+            super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
+                    userId);
+        }
+
+        public void setNetworkAgent(MockNetworkAgent agent) {
+            waitForIdle(agent, TIMEOUT_MS);
+            mMockNetworkAgent = agent;
+            mNetworkAgent = agent.getNetworkAgent();
+            mNetworkCapabilities.set(agent.getNetworkCapabilities());
+        }
+
+        public void setUids(Set<UidRange> uids) {
+            mNetworkCapabilities.setUids(uids);
+            updateCapabilities();
+        }
+
+        @Override
+        public int getNetId() {
+            return mMockNetworkAgent.getNetwork().netId;
+        }
+
+        @Override
+        public boolean appliesToUid(int uid) {
+            return mConnected;  // Trickery to simplify testing.
+        }
+
+        @Override
+        protected boolean isCallerEstablishedOwnerLocked() {
+            return mConnected;  // Similar trickery
+        }
+
+        public void connect() {
+            mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
+            mConnected = true;
+            mConfig = new VpnConfig();
+        }
+
+        @Override
+        public void updateCapabilities() {
+            if (!mConnected) return;
+            super.updateCapabilities();
+            // Because super.updateCapabilities will update the capabilities of the agent but not
+            // the mock agent, the mock agent needs to know about them.
+            copyCapabilitiesToNetworkAgent();
+        }
+
+        private void copyCapabilitiesToNetworkAgent() {
+            if (null != mMockNetworkAgent) {
+                mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
+                        false /* sendToConnectivityService */);
+            }
+        }
+
+        public void disconnect() {
+            mConnected = false;
+            mConfig = null;
+        }
+    }
+
     private class FakeWakeupMessage extends WakeupMessage {
         private static final int UNREASONABLY_LONG_WAIT = 1000;
 
@@ -852,6 +959,10 @@
             return monitor;
         }
 
+        public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
+            return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
+        }
+
         @Override
         public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
                 Context c, Handler h, Runnable r) {
@@ -889,6 +1000,17 @@
             return mLastCreatedNetworkMonitor;
         }
 
+        public void mockVpn(int uid) {
+            synchronized (mVpns) {
+                int userId = UserHandle.getUserId(uid);
+                mMockVpn = new MockVpn(userId);
+                // This has no effect unless the VPN is actually connected, because things like
+                // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
+                // netId, and check if that network is actually connected.
+                mVpns.put(userId, mMockVpn);
+            }
+        }
+
         public void waitForIdle(int timeoutMs) {
             waitForIdleHandler(mHandlerThread, timeoutMs);
         }
@@ -932,8 +1054,9 @@
                 mock(INetworkPolicyManager.class),
                 mock(IpConnectivityLog.class));
 
-        mService.systemReady();
         mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
+        mService.systemReady();
+        mService.mockVpn(Process.myUid());
         mCm.bindProcessToNetwork(null);
 
         // Ensure that the default setting for Captive Portals is used for most tests
@@ -1346,6 +1469,7 @@
         private final static int TIMEOUT_MS = 100;
 
         private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
+        private Network mLastAvailableNetwork;
 
         protected void setLastCallback(CallbackState state, Network network, Object o) {
             mCallbacks.offer(new CallbackInfo(state, network, o));
@@ -1353,6 +1477,7 @@
 
         @Override
         public void onAvailable(Network network) {
+            mLastAvailableNetwork = network;
             setLastCallback(CallbackState.AVAILABLE, network, null);
         }
 
@@ -1388,9 +1513,14 @@
 
         @Override
         public void onLost(Network network) {
+            mLastAvailableNetwork = null;
             setLastCallback(CallbackState.LOST, network, null);
         }
 
+        public Network getLastAvailableNetwork() {
+            return mLastAvailableNetwork;
+        }
+
         CallbackInfo nextCallback(int timeoutMs) {
             CallbackInfo cb = null;
             try {
@@ -1526,7 +1656,8 @@
 
         void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) {
             CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
-            assertTrue(fn.test((NetworkCapabilities) cbi.arg));
+            assertTrue("Received capabilities don't match expectations : " + cbi.arg,
+                    fn.test((NetworkCapabilities) cbi.arg));
         }
 
         void assertNoCallback() {
@@ -1657,6 +1788,7 @@
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.connect(true);
         // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
@@ -1667,6 +1799,7 @@
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         mEthernetNetworkAgent.connect(true);
         callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
@@ -1675,11 +1808,13 @@
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
         assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         mEthernetNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
         defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         for (int i = 0; i < 4; i++) {
             MockNetworkAgent oldNetwork, newNetwork;
@@ -1708,6 +1843,7 @@
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
         defaultCallback.assertNoCallback();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Wifi no longer satisfies our listen, which is for an unmetered network.
         // But because its score is 55, it's still up (and the default network).
@@ -1717,8 +1853,11 @@
         mWiFiNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
         mCellNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        waitForIdle();
+        assertEquals(null, mCm.getActiveNetwork());
 
         mCm.unregisterNetworkCallback(callback);
         waitForIdle();
@@ -1735,6 +1874,7 @@
         callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi with a score of 20.
         // Cell stays up because it would satisfy the default request if it validated.
@@ -1743,12 +1883,14 @@
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi with a score of 70.
         // Cell is lingered because it would not satisfy any request, even if it validated.
@@ -1759,6 +1901,7 @@
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Tear down wifi.
         mWiFiNetworkAgent.disconnect();
@@ -1766,6 +1909,7 @@
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
         // it's arguably correct to linger it, since it was the default network before it validated.
@@ -1777,6 +1921,7 @@
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -1785,12 +1930,15 @@
         mCellNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        waitForIdle();
+        assertEquals(null, mCm.getActiveNetwork());
 
         // If a network is lingering, and we add and remove a request from it, resume lingering.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -1798,6 +1946,7 @@
         // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         NetworkRequest cellRequest = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_CELLULAR).build();
@@ -1814,6 +1963,7 @@
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Cell is now the default network. Pin it with a cell-specific request.
         noopCallback = new NetworkCallback();  // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1824,6 +1974,7 @@
         mWiFiNetworkAgent.connect(true);
         callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
         // The default request is lingering on cell, but nothing happens to cell, and we send no
         // callbacks for it, because it's kept up by cellRequest.
         callback.assertNoCallback();
@@ -1847,6 +1998,7 @@
         callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
         trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
         defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Let linger run its course.
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
@@ -2495,23 +2647,27 @@
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi and expect CALLBACK_AVAILABLE.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring down cell. Expect no default network callback, since it wasn't the default.
         mCellNetworkAgent.disconnect();
         cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring up cell. Expect no default network callback, since it won't be the default.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
         cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         // Bring down wifi. Expect the default network callback to notified of LOST wifi
         // followed by AVAILABLE cell.
@@ -2522,6 +2678,24 @@
         mCellNetworkAgent.disconnect();
         cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        waitForIdle();
+        assertEquals(null, mCm.getActiveNetwork());
+
+        final int uid = Process.myUid();
+        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final ArraySet<UidRange> ranges = new ArraySet<>();
+        ranges.add(new UidRange(uid, uid));
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        mMockVpn.setUids(ranges);
+        vpnNetworkAgent.connect(true);
+        mMockVpn.connect();
+        defaultNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+        assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+        vpnNetworkAgent.disconnect();
+        defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+        waitForIdle();
+        assertEquals(null, mCm.getActiveNetwork());
     }
 
     @Test
@@ -4012,6 +4186,7 @@
         final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
         final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
         final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
         final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
         final NetworkRequest genericRequest = new NetworkRequest.Builder()
                 .removeCapability(NET_CAPABILITY_NOT_VPN).build();
@@ -4024,6 +4199,8 @@
         mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
         mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
         mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+        defaultCallback.assertNoCallback();
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
@@ -4031,26 +4208,30 @@
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         vpnNetworkCallback.assertNoCallback();
-
-        // TODO : check callbacks agree with the return value of mCm.getActiveNetwork().
-        // Right now this is not possible because establish() is not adequately instrumented
-        // in this test.
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
         final ArraySet<UidRange> ranges = new ArraySet<>();
         ranges.add(new UidRange(uid, uid));
-        vpnNetworkAgent.setUids(ranges);
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        mMockVpn.setUids(ranges);
         vpnNetworkAgent.connect(false);
+        mMockVpn.connect();
 
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
         genericNotVpnNetworkCallback.assertNoCallback();
         wifiNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
         genericNotVpnNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
+        defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
 
         ranges.clear();
         vpnNetworkAgent.setUids(ranges);
@@ -4060,13 +4241,24 @@
         wifiNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
 
+        // TODO : The default network callback should actually get a LOST call here (also see the
+        // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
+        // ranges at all when determining whether a network should be rematched. In practice, VPNs
+        // can't currently update their UIDs without disconnecting, so this does not matter too
+        // much, but that is the reason the test here has to check for an update to the
+        // capabilities instead of the expected LOST then AVAILABLE.
+        defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+
         ranges.add(new UidRange(uid, uid));
-        vpnNetworkAgent.setUids(ranges);
+        mMockVpn.setUids(ranges);
 
         genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
         genericNotVpnNetworkCallback.assertNoCallback();
         wifiNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+        // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
+        // happen outside of the test, ConnectivityService does not rematch callbacks.
+        defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
 
         mWiFiNetworkAgent.disconnect();
 
@@ -4074,6 +4266,7 @@
         genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         vpnNetworkCallback.assertNoCallback();
+        defaultCallback.assertNoCallback();
 
         vpnNetworkAgent.disconnect();
 
@@ -4081,9 +4274,254 @@
         genericNotVpnNetworkCallback.assertNoCallback();
         wifiNetworkCallback.assertNoCallback();
         vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+        defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+        assertEquals(null, mCm.getActiveNetwork());
 
         mCm.unregisterNetworkCallback(genericNetworkCallback);
         mCm.unregisterNetworkCallback(wifiNetworkCallback);
         mCm.unregisterNetworkCallback(vpnNetworkCallback);
+        mCm.unregisterNetworkCallback(defaultCallback);
+    }
+
+    @Test
+    public void testVpnWithAndWithoutInternet() {
+        final int uid = Process.myUid();
+
+        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+        defaultCallback.assertNoCallback();
+
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+
+        defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+        MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final ArraySet<UidRange> ranges = new ArraySet<>();
+        ranges.add(new UidRange(uid, uid));
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        mMockVpn.setUids(ranges);
+        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+        mMockVpn.connect();
+
+        defaultCallback.assertNoCallback();
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+        vpnNetworkAgent.disconnect();
+        defaultCallback.assertNoCallback();
+
+        vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        mMockVpn.setUids(ranges);
+        vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
+        mMockVpn.connect();
+        defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+        assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+        vpnNetworkAgent.disconnect();
+        defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+        defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+
+        vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        ranges.clear();
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        mMockVpn.setUids(ranges);
+        vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
+        mMockVpn.connect();
+        defaultCallback.assertNoCallback();
+
+        mCm.unregisterNetworkCallback(defaultCallback);
+    }
+
+    @Test
+    public void testVpnSetUnderlyingNetworks() {
+        final int uid = Process.myUid();
+
+        final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_VPN)
+                .addTransportType(TRANSPORT_VPN)
+                .build();
+        NetworkCapabilities nc;
+        mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+        vpnNetworkCallback.assertNoCallback();
+
+        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final ArraySet<UidRange> ranges = new ArraySet<>();
+        ranges.add(new UidRange(uid, uid));
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        mMockVpn.connect();
+        mMockVpn.setUids(ranges);
+        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+
+        vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+        nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+        assertTrue(nc.hasTransport(TRANSPORT_VPN));
+        assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
+        assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+        // For safety reasons a VPN without underlying networks is considered metered.
+        assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+
+        // Connect cell and use it as an underlying network.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+
+        mService.setUnderlyingNetworksForVpn(
+                new Network[] { mCellNetworkAgent.getNetwork() });
+
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
+                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+        mWiFiNetworkAgent.connect(true);
+
+        mService.setUnderlyingNetworksForVpn(
+                new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
+
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        // Don't disconnect, but note the VPN is not using wifi any more.
+        mService.setUnderlyingNetworksForVpn(
+                new Network[] { mCellNetworkAgent.getNetwork() });
+
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
+                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        // Use Wifi but not cell. Note the VPN is now unmetered.
+        mService.setUnderlyingNetworksForVpn(
+                new Network[] { mWiFiNetworkAgent.getNetwork() });
+
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+                && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        // Use both again.
+        mService.setUnderlyingNetworksForVpn(
+                new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
+
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        // Disconnect cell. Receive update without even removing the dead network from the
+        // underlying networks – it's dead anyway. Not metered any more.
+        mCellNetworkAgent.disconnect();
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+                && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        // Disconnect wifi too. No underlying networks means this is now metered.
+        mWiFiNetworkAgent.disconnect();
+        vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+                && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
+                && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+                vpnNetworkAgent);
+
+        mMockVpn.disconnect();
+    }
+
+    /**
+     * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
+     */
+    private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) {
+        InterfaceConfiguration cfg = new InterfaceConfiguration();
+        cfg.setHardwareAddress("11:22:33:44:55:66");
+        cfg.setLinkAddress(la);
+        return cfg;
+    }
+
+    /**
+     * Make expected stack link properties, copied from Nat464Xlat.
+     */
+    private LinkProperties makeClatLinkProperties(LinkAddress la) {
+        LinkAddress clatAddress = la;
+        LinkProperties stacked = new LinkProperties();
+        stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
+        RouteInfo ipv4Default = new RouteInfo(
+                new LinkAddress(Inet4Address.ANY, 0),
+                clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
+        stacked.addRoute(ipv4Default);
+        stacked.addLinkAddress(clatAddress);
+        return stacked;
+    }
+
+    @Test
+    public void testStackedLinkProperties() throws UnknownHostException, RemoteException {
+        final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
+        final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
+        final NetworkRequest networkRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(networkRequest, networkCallback);
+
+        // Prepare ipv6 only link properties and connect.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName(MOBILE_IFNAME);
+        cellLp.addLinkAddress(myIpv6);
+        cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
+        cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+        reset(mNetworkManagementService);
+        when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+                .thenReturn(getClatInterfaceConfig(myIpv4));
+
+        // Connect with ipv6 link properties, then expect clat setup ipv4 and update link
+        // properties properly.
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        mCellNetworkAgent.connect(true);
+        networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+        verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+        Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
+
+        // Clat iface up, expect stack link updated.
+        clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
+        waitForIdle();
+        List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
+                .getStackedLinks();
+        assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
+
+        // Change trivial linkproperties and see if stacked link is preserved.
+        cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        waitForIdle();
+        networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+
+        List<LinkProperties> stackedLpsAfterChange =
+                mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
+        assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
+        assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
+
+        // Add ipv4 address, expect stacked linkproperties be cleaned up
+        cellLp.addLinkAddress(myIpv4);
+        cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        waitForIdle();
+        networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+        verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+
+        // Clat iface removed, expect linkproperties revert to original one
+        clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
+        waitForIdle();
+        networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+        LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
+        assertEquals(cellLp, actualLpAfterIpv4);
+
+        // Clean up
+        mCellNetworkAgent.disconnect();
+        mCm.unregisterNetworkCallback(networkCallback);
     }
 }
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 410f754..102cb7c 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.INetd;
 import android.net.IpSecAlgorithm;
@@ -40,6 +41,7 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
+import android.test.mock.MockContext;
 import android.support.test.filters.SmallTest;
 import android.system.Os;
 
@@ -48,6 +50,7 @@
 import java.util.Collection;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -92,7 +95,28 @@
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
     };
 
-    Context mMockContext;
+    AppOpsManager mMockAppOps = mock(AppOpsManager.class);
+
+    MockContext mMockContext = new MockContext() {
+        @Override
+        public Object getSystemService(String name) {
+            switch(name) {
+                case Context.APP_OPS_SERVICE:
+                    return mMockAppOps;
+                default:
+                    return null;
+            }
+        }
+
+        @Override
+        public void enforceCallingOrSelfPermission(String permission, String message) {
+            if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
+                return;
+            }
+            throw new SecurityException("Unavailable permission requested");
+        }
+    };
+
     INetd mMockNetd;
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
@@ -114,13 +138,22 @@
 
     @Before
     public void setUp() throws Exception {
-        mMockContext = mock(Context.class);
         mMockNetd = mock(INetd.class);
         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
         mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
 
         // Injecting mock netd
         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+        // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
+        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
+            .thenReturn(AppOpsManager.MODE_ALLOWED);
+        // A system package will not be granted the app op, so this should fall back to
+        // a permissions check, which should pass.
+        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
+            .thenReturn(AppOpsManager.MODE_DEFAULT);
+        // A mismatch between the package name and the UID will return MODE_IGNORED.
+        when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
+            .thenReturn(AppOpsManager.MODE_IGNORED);
     }
 
     @Test
@@ -232,7 +265,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         verify(mMockNetd)
@@ -267,7 +300,7 @@
         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         verify(mMockNetd)
@@ -301,12 +334,12 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         // Attempting to create transform a second time with the same SPIs should throw an error...
         try {
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                 fail("IpSecService should have thrown an error for reuse of SPI");
         } catch (IllegalStateException expected) {
         }
@@ -314,7 +347,7 @@
         // ... even if the transform is deleted
         mIpSecService.deleteTransform(createTransformResp.resourceId);
         try {
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
                 fail("IpSecService should have thrown an error for reuse of SPI");
         } catch (IllegalStateException expected) {
         }
@@ -327,7 +360,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -351,7 +384,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
         mIpSecService.deleteTransform(createTransformResp.resourceId);
 
         verify(mMockNetd, times(1))
@@ -398,7 +431,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
 
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -435,7 +468,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
 
         int resourceId = createTransformResp.resourceId;
@@ -460,10 +493,10 @@
     }
 
     private IpSecTunnelInterfaceResponse createAndValidateTunnel(
-            String localAddr, String remoteAddr) {
+            String localAddr, String remoteAddr, String pkgName) {
         IpSecTunnelInterfaceResponse createTunnelResp =
                 mIpSecService.createTunnelInterface(
-                        mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());
+                        mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
 
         assertNotNull(createTunnelResp);
         assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
@@ -473,7 +506,7 @@
     @Test
     public void testCreateTunnelInterface() throws Exception {
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
         // Check that we have stored the tracking object, and retrieve it
         IpSecService.UserRecord userRecord =
@@ -495,12 +528,12 @@
     @Test
     public void testDeleteTunnelInterface() throws Exception {
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
 
-        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);
+        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
 
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -516,7 +549,7 @@
     @Test
     public void testTunnelInterfaceBinderDeath() throws Exception {
         IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -539,22 +572,35 @@
 
     @Test
     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
-        IpSecTunnelInterfaceResponse createTunnelResp =
-                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+        for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
+            IpSecTunnelInterfaceResponse createTunnelResp =
+                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
+            mIpSecService.addAddressToTunnelInterface(
+                    createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+            verify(mMockNetd, times(1))
+                    .interfaceAddAddress(
+                            eq(createTunnelResp.interfaceName),
+                            eq(mLocalInnerAddress.getAddress().getHostAddress()),
+                            eq(mLocalInnerAddress.getPrefixLength()));
+            mIpSecService.removeAddressFromTunnelInterface(
+                    createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+            verify(mMockNetd, times(1))
+                    .interfaceDelAddress(
+                            eq(createTunnelResp.interfaceName),
+                            eq(mLocalInnerAddress.getAddress().getHostAddress()),
+                            eq(mLocalInnerAddress.getPrefixLength()));
+            mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
+        }
+    }
 
-        mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
-        verify(mMockNetd)
-                .interfaceAddAddress(
-                        eq(createTunnelResp.interfaceName),
-                        eq(mLocalInnerAddress.getAddress().getHostAddress()),
-                        eq(mLocalInnerAddress.getPrefixLength()));
-
-        mIpSecService.removeAddressFromTunnelInterface(
-                createTunnelResp.resourceId, mLocalInnerAddress);
-        verify(mMockNetd)
-                .interfaceDelAddress(
-                        eq(createTunnelResp.interfaceName),
-                        eq(mLocalInnerAddress.getAddress().getHostAddress()),
-                        eq(mLocalInnerAddress.getPrefixLength()));
+    @Ignore
+    @Test
+    public void testAddTunnelFailsForBadPackageName() throws Exception {
+        try {
+            IpSecTunnelInterfaceResponse createTunnelResp =
+                    createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
+            fail("Expected a SecurityException for badPackage.");
+        } catch (SecurityException expected) {
+        }
     }
 }
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index d241b32..44d8f31 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -71,6 +71,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.net.NetworkRequest;
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
@@ -128,6 +129,10 @@
     private static final String TEST_USB_IFNAME = "test_rndis0";
     private static final String TEST_WLAN_IFNAME = "test_wlan0";
 
+    // Actual contents of the request don't matter for this test. The lack of
+    // any specific TRANSPORT_* is sufficient to identify this request.
+    private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
+
     @Mock private ApplicationInfo mApplicationInfo;
     @Mock private Context mContext;
     @Mock private INetworkManagementService mNMService;
@@ -238,6 +243,11 @@
             isTetheringSupportedCalls++;
             return true;
         }
+
+        @Override
+        public NetworkRequest getDefaultNetworkRequest() {
+            return mDefaultRequest;
+        }
     }
 
     private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
@@ -305,6 +315,8 @@
                 .thenReturn(new String[0]);
         when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
                 .thenReturn(new int[0]);
+        when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
+                .thenReturn(false);
         when(mNMService.listInterfaces())
                 .thenReturn(new String[] {
                         TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
@@ -458,6 +470,7 @@
     }
 
     private void prepareUsbTethering(NetworkState upstreamState) {
+        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
         when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
                 .thenReturn(upstreamState);
 
@@ -519,7 +532,7 @@
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
         verifyNoMoreInteractions(mWifiManager);
         verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
-        verify(mUpstreamNetworkMonitor, times(1)).start();
+        verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class));
         // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
         assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
 
@@ -656,6 +669,24 @@
     }
 
     @Test
+    public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception {
+        when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
+                .thenReturn(true);
+        sendConfigurationChanged();
+
+        // Setup IPv6
+        final NetworkState upstreamState = buildMobileIPv6UpstreamState();
+        runUsbTethering(upstreamState);
+
+        // UpstreamNetworkMonitor should choose upstream automatically
+        // (in this specific case: choose the default network).
+        verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
+        verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
+
+        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
+    }
+
+    @Test
     public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
         workingLocalOnlyHotspotEnrichedApBroadcast(true);
     }
@@ -718,7 +749,7 @@
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
         verifyNoMoreInteractions(mWifiManager);
         verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
-        verify(mUpstreamNetworkMonitor, times(1)).start();
+        verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class));
         // In tethering mode, in the default configuration, an explicit request
         // for a mobile network is also made.
         verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
@@ -779,11 +810,12 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
 
-        // We verify get/set called twice here: once for setup and once during
+        // 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.
+        // dispatchAll() above. Note that once the TISM 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(2))
+        verify(mNMService, times(3))
                 .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
         verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
         verify(mWifiManager).updateInterfaceIpState(
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index 7c77cf5..19d3a2e 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -173,6 +173,7 @@
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
         InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
         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(
@@ -270,6 +271,7 @@
         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(
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 9661dc2..3e21a2c 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -31,6 +31,7 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -73,6 +74,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 
@@ -84,6 +86,10 @@
     private static final boolean INCLUDES = true;
     private static final boolean EXCLUDES = false;
 
+    // Actual contents of the request don't matter for this test. The lack of
+    // any specific TRANSPORT_* is sufficient to identify this request.
+    private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
+
     @Mock private Context mContext;
     @Mock private IConnectivityManager mCS;
     @Mock private SharedLog mLog;
@@ -113,6 +119,13 @@
     }
 
     @Test
+    public void testStopWithoutStartIsNonFatal() {
+        mUNM.stop();
+        mUNM.stop();
+        mUNM.stop();
+    }
+
+    @Test
     public void testDoesNothingBeforeStarted() {
         assertTrue(mCM.hasNoCallbacks());
         assertFalse(mUNM.mobileNetworkRequested());
@@ -127,7 +140,7 @@
     public void testDefaultNetworkIsTracked() throws Exception {
         assertEquals(0, mCM.trackingDefault.size());
 
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
         assertEquals(1, mCM.trackingDefault.size());
 
         mUNM.stop();
@@ -138,7 +151,7 @@
     public void testListensForAllNetworks() throws Exception {
         assertTrue(mCM.listening.isEmpty());
 
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
         assertFalse(mCM.listening.isEmpty());
         assertTrue(mCM.isListeningForAll());
 
@@ -148,9 +161,11 @@
 
     @Test
     public void testCallbacksRegistered() {
-        mUNM.start();
-        verify(mCM, times(1)).registerNetworkCallback(any(), any(), any());
-        verify(mCM, times(1)).registerDefaultNetworkCallback(any(), any());
+        mUNM.start(mDefaultRequest);
+        verify(mCM, times(1)).registerNetworkCallback(
+                any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+        verify(mCM, times(1)).requestNetwork(
+                eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
 
         mUNM.stop();
         verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
@@ -161,7 +176,7 @@
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
@@ -184,17 +199,17 @@
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
-        mUNM.start();
-        verify(mCM, Mockito.times(1)).registerNetworkCallback(
+        mUNM.start(mDefaultRequest);
+        verify(mCM, times(1)).registerNetworkCallback(
                 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
-        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
-                any(NetworkCallback.class), any(Handler.class));
+        verify(mCM, times(1)).requestNetwork(
+                eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
         mUNM.updateMobileRequiresDun(true);
         mUNM.registerMobileNetworkRequest();
-        verify(mCM, Mockito.times(1)).requestNetwork(
+        verify(mCM, times(1)).requestNetwork(
                 any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
                 any(Handler.class));
 
@@ -222,7 +237,7 @@
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
@@ -242,7 +257,7 @@
 
     @Test
     public void testUpdateMobileRequiresDun() throws Exception {
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
 
         // Test going from no-DUN to DUN correctly re-registers callbacks.
         mUNM.updateMobileRequiresDun(false);
@@ -270,7 +285,7 @@
         final Collection<Integer> preferredTypes = new ArrayList<>();
         preferredTypes.add(TYPE_WIFI);
 
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
         // There are no networks, so there is nothing to select.
         assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
 
@@ -334,8 +349,47 @@
     }
 
     @Test
+    public void testGetCurrentPreferredUpstream() throws Exception {
+        mUNM.start(mDefaultRequest);
+        mUNM.updateMobileRequiresDun(false);
+
+        // [0] Mobile connects, DUN not required -> mobile selected.
+        final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+        cellAgent.fakeConnect();
+        mCM.makeDefaultNetwork(cellAgent);
+        assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+        // [1] WiFi connects but not validated/promoted to default -> mobile selected.
+        final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
+        wifiAgent.fakeConnect();
+        assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+        // [2] WiFi validates and is promoted to the default network -> WiFi selected.
+        mCM.makeDefaultNetwork(wifiAgent);
+        assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+        // [3] DUN required, no other changes -> WiFi still selected
+        mUNM.updateMobileRequiresDun(true);
+        assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+        // [4] WiFi no longer validated, mobile becomes default, DUN required -> null selected.
+        mCM.makeDefaultNetwork(cellAgent);
+        assertEquals(null, mUNM.getCurrentPreferredUpstream());
+        // TODO: make sure that a DUN request has been filed. This is currently
+        // triggered by code over in Tethering, but once that has been moved
+        // into UNM we should test for this here.
+
+        // [5] DUN network arrives -> DUN selected
+        final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+        dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
+        dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
+        dunAgent.fakeConnect();
+        assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+    }
+
+    @Test
     public void testLocalPrefixes() throws Exception {
-        mUNM.start();
+        mUNM.start(mDefaultRequest);
 
         // [0] Test minimum set of local prefixes.
         Set<IpPrefix> local = mUNM.getLocalPrefixes();
@@ -345,7 +399,7 @@
 
         // [1] Pretend Wi-Fi connects.
         final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
-        final LinkProperties wifiLp = new LinkProperties();
+        final LinkProperties wifiLp = wifiAgent.linkProperties;
         wifiLp.setInterfaceName("wlan0");
         final String[] WIFI_ADDRS = {
                 "fe80::827a:bfff:fe6f:374d", "100.112.103.18",
@@ -358,7 +412,7 @@
             wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr));
         }
         wifiAgent.fakeConnect();
-        wifiAgent.sendLinkProperties(wifiLp);
+        wifiAgent.sendLinkProperties();
 
         local = mUNM.getLocalPrefixes();
         assertPrefixSet(local, INCLUDES, alreadySeen);
@@ -372,7 +426,7 @@
 
         // [2] Pretend mobile connects.
         final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
-        final LinkProperties cellLp = new LinkProperties();
+        final LinkProperties cellLp = cellAgent.linkProperties;
         cellLp.setInterfaceName("rmnet_data0");
         final String[] CELL_ADDRS = {
                 "10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d",
@@ -382,7 +436,7 @@
             cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
         }
         cellAgent.fakeConnect();
-        cellAgent.sendLinkProperties(cellLp);
+        cellAgent.sendLinkProperties();
 
         local = mUNM.getLocalPrefixes();
         assertPrefixSet(local, INCLUDES, alreadySeen);
@@ -394,17 +448,18 @@
         // [3] Pretend DUN connects.
         final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
         dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
-        final LinkProperties dunLp = new LinkProperties();
+        dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
+        final LinkProperties dunLp = dunAgent.linkProperties;
         dunLp.setInterfaceName("rmnet_data1");
         final String[] DUN_ADDRS = {
                 "192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d",
         };
         for (String addrStr : DUN_ADDRS) {
             final String cidr = addrStr.contains(":") ? "/64" : "/27";
-            cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
+            dunLp.addLinkAddress(new LinkAddress(addrStr + cidr));
         }
         dunAgent.fakeConnect();
-        dunAgent.sendLinkProperties(dunLp);
+        dunAgent.sendLinkProperties();
 
         local = mUNM.getLocalPrefixes();
         assertPrefixSet(local, INCLUDES, alreadySeen);
@@ -442,6 +497,7 @@
     public static class TestConnectivityManager extends ConnectivityManager {
         public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
         public Set<NetworkCallback> trackingDefault = new HashSet<>();
+        public TestNetworkAgent defaultNetwork = null;
         public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
         public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
         public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();
@@ -483,12 +539,34 @@
 
         int getNetworkId() { return ++mNetworkId; }
 
+        void makeDefaultNetwork(TestNetworkAgent agent) {
+            if (Objects.equals(defaultNetwork, agent)) return;
+
+            final TestNetworkAgent formerDefault = defaultNetwork;
+            defaultNetwork = agent;
+
+            for (NetworkCallback cb : trackingDefault) {
+                if (defaultNetwork != null) {
+                    cb.onAvailable(defaultNetwork.networkId);
+                    cb.onCapabilitiesChanged(
+                            defaultNetwork.networkId, defaultNetwork.networkCapabilities);
+                    cb.onLinkPropertiesChanged(
+                            defaultNetwork.networkId, defaultNetwork.linkProperties);
+                }
+            }
+        }
+
         @Override
         public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
             assertFalse(allCallbacks.containsKey(cb));
             allCallbacks.put(cb, h);
-            assertFalse(requested.containsKey(cb));
-            requested.put(cb, req);
+            if (mDefaultRequest.equals(req)) {
+                assertFalse(trackingDefault.contains(cb));
+                trackingDefault.add(cb);
+            } else {
+                assertFalse(requested.containsKey(cb));
+                requested.put(cb, req);
+            }
         }
 
         @Override
@@ -524,10 +602,7 @@
 
         @Override
         public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
-            assertFalse(allCallbacks.containsKey(cb));
-            allCallbacks.put(cb, h);
-            assertFalse(trackingDefault.contains(cb));
-            trackingDefault.add(cb);
+            fail("Should never be called.");
         }
 
         @Override
@@ -561,6 +636,7 @@
         public final Network networkId;
         public final int transportType;
         public final NetworkCapabilities networkCapabilities;
+        public final LinkProperties linkProperties;
 
         public TestNetworkAgent(TestConnectivityManager cm, int transportType) {
             this.cm = cm;
@@ -569,12 +645,14 @@
             networkCapabilities = new NetworkCapabilities();
             networkCapabilities.addTransportType(transportType);
             networkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
+            linkProperties = new LinkProperties();
         }
 
         public void fakeConnect() {
             for (NetworkCallback cb : cm.listening.keySet()) {
                 cb.onAvailable(networkId);
                 cb.onCapabilitiesChanged(networkId, copy(networkCapabilities));
+                cb.onLinkPropertiesChanged(networkId, copy(linkProperties));
             }
         }
 
@@ -584,11 +662,16 @@
             }
         }
 
-        public void sendLinkProperties(LinkProperties lp) {
+        public void sendLinkProperties() {
             for (NetworkCallback cb : cm.listening.keySet()) {
-                cb.onLinkPropertiesChanged(networkId, lp);
+                cb.onLinkPropertiesChanged(networkId, copy(linkProperties));
             }
         }
+
+        @Override
+        public String toString() {
+            return String.format("TestNetworkAgent: %s %s", networkId, networkCapabilities);
+        }
     }
 
     public static class TestStateMachine extends StateMachine {
@@ -618,6 +701,10 @@
         return new NetworkCapabilities(nc);
     }
 
+    static LinkProperties copy(LinkProperties lp) {
+        return new LinkProperties(lp);
+    }
+
     static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected) {
         final Set<String> expectedSet = new HashSet<>();
         Collections.addAll(expectedSet, expected);
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 036bf5d8..3a312b0 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1923,6 +1923,12 @@
           .OptionalFlag("--version-name",
                         "Version name to inject into the AndroidManifest.xml if none is present.",
                         &options.manifest_fixer_options.version_name_default)
+          .OptionalSwitch("--replace-version",
+                         "If --version-code and/or --version-name are specified, these\n"
+                         "values will replace any value already in the manifest. By\n"
+                         "default, nothing is changed if the manifest already defines\n"
+                         "these attributes.",
+                         &options.manifest_fixer_options.replace_version)
           .OptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
                           &shared_lib)
           .OptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib)
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index e6271eb..ca7b653 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -237,6 +237,9 @@
   manifest_action.Action(FixCoreAppAttribute);
   manifest_action.Action([&](xml::Element* el) -> bool {
     if (options_.version_name_default) {
+      if (options_.replace_version) {
+        el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
+      }
       if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
         el->attributes.push_back(
             xml::Attribute{xml::kSchemaAndroid, "versionName",
@@ -245,6 +248,9 @@
     }
 
     if (options_.version_code_default) {
+      if (options_.replace_version) {
+        el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
+      }
       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
         el->attributes.push_back(
             xml::Attribute{xml::kSchemaAndroid, "versionCode",
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index dbabab17..d7a5931 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -33,13 +33,22 @@
   Maybe<std::string> target_sdk_version_default;
   Maybe<std::string> rename_manifest_package;
   Maybe<std::string> rename_instrumentation_target_package;
+
+  // The version name to set if 'android:versionName' is not defined in <manifest> or if
+  // replace_version is set.
   Maybe<std::string> version_name_default;
+
+  // The version code to set if 'android:versionCode' is not defined in <manifest> or if
+  // replace_version is set.
   Maybe<std::string> version_code_default;
 
   // Wether validation errors should be treated only as warnings. If this is 'true', then an
   // incorrect node will not result in an error, but only as a warning, and the parsing will
   // continue.
   bool warn_validation = false;
+
+  // Whether to replace the manifest version with the the command line version
+  bool replace_version = false;
 };
 
 /**
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 84e367d..e6410c9 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -21,6 +21,7 @@
 using ::android::StringPiece;
 using ::testing::IsNull;
 using ::testing::NotNull;
+using ::testing::StrEq;
 
 namespace aapt {
 
@@ -339,6 +340,136 @@
   EXPECT_EQ(std::string("0x10000000"), attr->value);
 }
 
+TEST_F(ManifestFixerTest, DontUseDefaultVersionNameAndCode) {
+ManifestFixerOptions options;
+options.version_name_default = std::string("Beta");
+options.version_code_default = std::string("0x10000000");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android"
+                android:versionCode="0x20000000"
+                android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Alpha"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x20000000"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) {
+ManifestFixerOptions options;
+options.replace_version = true;
+options.version_name_default = std::string("Beta");
+options.version_code_default = std::string("0x10000000");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+              package="android"
+              android:versionCode="0x20000000"
+              android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Beta"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x10000000"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceVersionName) {
+ManifestFixerOptions options;
+options.replace_version = true;
+options.version_name_default = std::string("Beta");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+            package="android"
+            android:versionCode="0x20000000"
+            android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Beta"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x20000000"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceVersionCode) {
+ManifestFixerOptions options;
+options.replace_version = true;
+options.version_code_default = std::string("0x10000000");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+            package="android"
+            android:versionCode="0x20000000"
+            android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Alpha"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x10000000"));
+}
+
+TEST_F(ManifestFixerTest, DontReplaceVersionNameOrCode) {
+ManifestFixerOptions options;
+options.replace_version = true;
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android"
+          android:versionCode="0x20000000"
+          android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Alpha"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x20000000"));
+}
+
 TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
   EXPECT_EQ(nullptr,
             Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 1d122db..22767781 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -394,6 +394,15 @@
   return nullptr;
 }
 
+void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
+  auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
+    [&](const Attribute& attr) -> bool {
+      return ns == attr.namespace_uri && name == attr.name;
+    });
+
+  attributes.erase(new_attr_end, attributes.end());
+}
+
 Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
   return FindChildWithAttribute(ns, name, {}, {}, {});
 }
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 1542243..995cdb24 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -98,6 +98,9 @@
   Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
   const Attribute* FindAttribute(const android::StringPiece& ns,
                                  const android::StringPiece& name) const;
+  void RemoveAttribute(const android::StringPiece& ns,
+                       const android::StringPiece& name);
+
   Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
   Element* FindChildWithAttribute(const android::StringPiece& ns, const android::StringPiece& name,
                                   const android::StringPiece& attr_ns,
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index 1d8809f6..4b67a3e98 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -529,6 +529,7 @@
             args[argpos++] = NULL;
             execvp(args[0], (char*const*)args);
             fprintf(stderr, "execvp failed: %s\n", strerror(errno));
+            free(args);
             return 0;
         } else {
             // parent