Merge "Propagate the "dalvik.vm.minidebuginfo" property to ART run-time."
diff --git a/api/current.txt b/api/current.txt
index 2611cbf..a9bf7d1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6,6 +6,7 @@
 
   public static final class Manifest.permission {
     ctor public Manifest.permission();
+    field public static final java.lang.String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
     field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
     field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
     field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -92,6 +93,7 @@
     field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
     field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
     field public static final java.lang.String NFC = "android.permission.NFC";
+    field public static final java.lang.String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
     field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
     field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
@@ -39380,6 +39382,7 @@
     method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
     method public void onExtrasChanged(android.os.Bundle);
+    method public void onHandoverComplete();
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
@@ -56461,6 +56464,7 @@
     method public boolean enqueue();
     method public T get();
     method public boolean isEnqueued();
+    method public static void reachabilityFence(java.lang.Object);
   }
 
   public class ReferenceQueue<T> {
@@ -69483,7 +69487,6 @@
 
   public class ExemptionMechanism {
     ctor protected ExemptionMechanism(javax.crypto.ExemptionMechanismSpi, java.security.Provider, java.lang.String);
-    method protected void finalize();
     method public final byte[] genExemptionBlob() throws javax.crypto.ExemptionMechanismException, java.lang.IllegalStateException;
     method public final int genExemptionBlob(byte[]) throws javax.crypto.ExemptionMechanismException, java.lang.IllegalStateException, javax.crypto.ShortBufferException;
     method public final int genExemptionBlob(byte[], int) throws javax.crypto.ExemptionMechanismException, java.lang.IllegalStateException, javax.crypto.ShortBufferException;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2e7a0ed..da324fc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7044,7 +7044,7 @@
         boolean isAppDebuggable =
                 (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
 
-        // This property is set for all builds except final release
+        // This property is set for all non-user builds except final release
         boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
 
         if (isAppDebuggable || isDlwarningEnabled) {
@@ -7067,11 +7067,14 @@
             }
         }
 
-        // We might disable this for final builds.
-        boolean isApiWarningEnabled = true;
+        // This property is set for all non-user builds except final release
+        boolean isApiWarningEnabled = SystemProperties.getInt("ro.art.hiddenapi.warning", 0) == 1;
 
         if (isAppDebuggable || isApiWarningEnabled) {
-            if (VMRuntime.getRuntime().hasUsedHiddenApi()) {
+            if (!mMainThread.mHiddenApiWarningShown && VMRuntime.getRuntime().hasUsedHiddenApi()) {
+                // Only show the warning once per process.
+                mMainThread.mHiddenApiWarningShown = true;
+
                 String appName = getApplicationInfo().loadLabel(getPackageManager())
                         .toString();
                 String warning = "Detected problems with API compatiblity\n"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2ecd312..565eaeb 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -266,6 +266,7 @@
     boolean mJitEnabled = false;
     boolean mSomeActivitiesChanged = false;
     boolean mUpdatingSystemConfig = false;
+    /* package */ boolean mHiddenApiWarningShown = false;
 
     // These can be accessed by multiple threads; mResourcesManager is the lock.
     // XXX For now we keep around information about all packages we have
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b331d84..e8fbbd7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -252,8 +252,10 @@
     public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
     /** @hide Answer incoming phone calls */
     public static final int OP_ANSWER_PHONE_CALLS = 69;
+    /** @hide Continue handover of a call from another app */
+    public static final int OP_ACCEPT_HANDOVER = 70;
     /** @hide */
-    public static final int _NUM_OP = 70;
+    public static final int _NUM_OP = 71;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -365,6 +367,12 @@
     /** Answer incoming phone calls */
     public static final String OPSTR_ANSWER_PHONE_CALLS
             = "android:answer_phone_calls";
+    /***
+     * Accept call handover
+     * @hide
+     */
+    public static final String OPSTR_ACCEPT_HANDOVER
+            = "android:accept_handover";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -400,6 +408,7 @@
             OP_USE_SIP,
             OP_PROCESS_OUTGOING_CALLS,
             OP_ANSWER_PHONE_CALLS,
+            OP_ACCEPT_HANDOVER,
             // Microphone
             OP_RECORD_AUDIO,
             // Camera
@@ -492,7 +501,8 @@
             OP_REQUEST_INSTALL_PACKAGES,
             OP_PICTURE_IN_PICTURE,
             OP_INSTANT_APP_START_FOREGROUND,
-            OP_ANSWER_PHONE_CALLS
+            OP_ANSWER_PHONE_CALLS,
+            OP_ACCEPT_HANDOVER
     };
 
     /**
@@ -570,6 +580,7 @@
             OPSTR_PICTURE_IN_PICTURE,
             OPSTR_INSTANT_APP_START_FOREGROUND,
             OPSTR_ANSWER_PHONE_CALLS,
+            OPSTR_ACCEPT_HANDOVER
     };
 
     /**
@@ -647,6 +658,7 @@
             "PICTURE_IN_PICTURE",
             "INSTANT_APP_START_FOREGROUND",
             "ANSWER_PHONE_CALLS",
+            "ACCEPT_HANDOVER"
     };
 
     /**
@@ -724,6 +736,7 @@
             null, // no permission for entering picture-in-picture on hide
             Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
             Manifest.permission.ANSWER_PHONE_CALLS,
+            Manifest.permission.ACCEPT_HANDOVER
     };
 
     /**
@@ -802,6 +815,7 @@
             null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
             null, // INSTANT_APP_START_FOREGROUND
             null, // ANSWER_PHONE_CALLS
+            null, // ACCEPT_HANDOVER
     };
 
     /**
@@ -879,6 +893,7 @@
             false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
             false, // INSTANT_APP_START_FOREGROUND
             false, // ANSWER_PHONE_CALLS
+            false, // ACCEPT_HANDOVER
     };
 
     /**
@@ -955,6 +970,7 @@
             AppOpsManager.MODE_ALLOWED,  // OP_PICTURE_IN_PICTURE
             AppOpsManager.MODE_DEFAULT,  // OP_INSTANT_APP_START_FOREGROUND
             AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
+            AppOpsManager.MODE_ALLOWED, // ACCEPT_HANDOVER
     };
 
     /**
@@ -1035,6 +1051,7 @@
             false, // OP_PICTURE_IN_PICTURE
             false,
             false, // ANSWER_PHONE_CALLS
+            false, // ACCEPT_HANDOVER
     };
 
     /**
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 9ccdbe2..0829b4a 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -462,7 +462,7 @@
             mConfig.setMode(MODE_TUNNEL);
             mConfig.setSourceAddress(sourceAddress.getHostAddress());
             mConfig.setSpiResourceId(spi.getResourceId());
-            return new IpSecTransform(mContext, mConfig);
+            return new IpSecTransform(mContext, mConfig).activate();
         }
 
         /**
diff --git a/core/java/android/net/KeepalivePacketData.aidl b/core/java/android/net/KeepalivePacketData.aidl
new file mode 100644
index 0000000..d456b53
--- /dev/null
+++ b/core/java/android/net/KeepalivePacketData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable KeepalivePacketData;
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
new file mode 100644
index 0000000..08d4ff5
--- /dev/null
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.system.OsConstants;
+import android.net.ConnectivityManager;
+import android.net.util.IpUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.system.OsConstants;
+import android.util.Log;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import static android.net.ConnectivityManager.PacketKeepalive.*;
+
+/**
+ * Represents the actual packets that are sent by the
+ * {@link android.net.ConnectivityManager.PacketKeepalive} API.
+ *
+ * @hide
+ */
+public class KeepalivePacketData implements Parcelable {
+    private static final String TAG = "KeepalivePacketData";
+
+    /** Source IP address */
+    public final InetAddress srcAddress;
+
+    /** Destination IP address */
+    public final InetAddress dstAddress;
+
+    /** Source port */
+    public final int srcPort;
+
+    /** Destination port */
+    public final int dstPort;
+
+    /** Packet data. A raw byte string of packet data, not including the link-layer header. */
+    private final byte[] mPacket;
+
+    private static final int IPV4_HEADER_LENGTH = 20;
+    private static final int UDP_HEADER_LENGTH = 8;
+
+    // This should only be constructed via static factory methods, such as
+    // nattKeepalivePacket
+    protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
+            InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
+        this.srcAddress = srcAddress;
+        this.dstAddress = dstAddress;
+        this.srcPort = srcPort;
+        this.dstPort = dstPort;
+        this.mPacket = data;
+
+        // Check we have two IP addresses of the same family.
+        if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName()
+                .equals(dstAddress.getClass().getName())) {
+            Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData");
+            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+        }
+
+        // Check the ports.
+        if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
+            Log.e(TAG, "Invalid ports in KeepalivePacketData");
+            throw new InvalidPacketException(ERROR_INVALID_PORT);
+        }
+    }
+
+    public static class InvalidPacketException extends Exception {
+        public final int error;
+        public InvalidPacketException(int error) {
+            this.error = error;
+        }
+    }
+
+    public byte[] getPacket() {
+        return mPacket.clone();
+    }
+
+    public static KeepalivePacketData nattKeepalivePacket(
+            InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
+            throws InvalidPacketException {
+
+        // FIXME: remove this and actually support IPv6 keepalives
+        if (srcAddress instanceof Inet6Address && dstAddress instanceof Inet6Address) {
+            // Optimistically returning an IPv6 Keepalive Packet with no data,
+            // which currently only works on cellular
+            return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, new byte[0]);
+        }
+
+        if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
+            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+        }
+
+        if (dstPort != NATT_PORT) {
+            throw new InvalidPacketException(ERROR_INVALID_PORT);
+        }
+
+        int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
+        ByteBuffer buf = ByteBuffer.allocate(length);
+        buf.order(ByteOrder.BIG_ENDIAN);
+        buf.putShort((short) 0x4500);             // IP version and TOS
+        buf.putShort((short) length);
+        buf.putInt(0);                            // ID, flags, offset
+        buf.put((byte) 64);                       // TTL
+        buf.put((byte) OsConstants.IPPROTO_UDP);
+        int ipChecksumOffset = buf.position();
+        buf.putShort((short) 0);                  // IP checksum
+        buf.put(srcAddress.getAddress());
+        buf.put(dstAddress.getAddress());
+        buf.putShort((short) srcPort);
+        buf.putShort((short) dstPort);
+        buf.putShort((short) (length - 20));      // UDP length
+        int udpChecksumOffset = buf.position();
+        buf.putShort((short) 0);                  // UDP checksum
+        buf.put((byte) 0xff);                     // NAT-T keepalive
+        buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
+        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
+
+        return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
+    }
+
+    /* Parcelable Implementation */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Write to parcel */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(srcAddress.getHostAddress());
+        out.writeString(dstAddress.getHostAddress());
+        out.writeInt(srcPort);
+        out.writeInt(dstPort);
+        out.writeByteArray(mPacket);
+    }
+
+    private KeepalivePacketData(Parcel in) {
+        srcAddress = NetworkUtils.numericToInetAddress(in.readString());
+        dstAddress = NetworkUtils.numericToInetAddress(in.readString());
+        srcPort = in.readInt();
+        dstPort = in.readInt();
+        mPacket = in.createByteArray();
+    }
+
+    /** Parcelable Creator */
+    public static final Parcelable.Creator<KeepalivePacketData> CREATOR =
+            new Parcelable.Creator<KeepalivePacketData>() {
+                public KeepalivePacketData createFromParcel(Parcel in) {
+                    return new KeepalivePacketData(in);
+                }
+
+                public KeepalivePacketData[] newArray(int size) {
+                    return new KeepalivePacketData[size];
+                }
+            };
+
+}
diff --git a/services/net/java/android/net/util/IpUtils.java b/core/java/android/net/util/IpUtils.java
similarity index 100%
rename from services/net/java/android/net/util/IpUtils.java
rename to core/java/android/net/util/IpUtils.java
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d7f725d..3784d4d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -761,18 +761,17 @@
 
     /*
      * Enable debugging only for apps forked from zygote.
-     * Set suspend=y to pause during VM init and use android ADB transport.
      */
     if (zygote) {
+      // Set the JDWP provider and required arguments. By default let the runtime choose how JDWP is
+      // implemented. When this is not set the runtime defaults to not allowing JDWP.
       addOption("-XjdwpOptions:suspend=n,server=y");
+      parseRuntimeOption("dalvik.vm.jdwp-provider",
+                         jdwpProviderBuf,
+                         "-XjdwpProvider:",
+                         "default");
     }
 
-    // Set the JDWP provider. By default let the runtime choose.
-    parseRuntimeOption("dalvik.vm.jdwp-provider",
-                       jdwpProviderBuf,
-                       "-XjdwpProvider:",
-                       "default");
-
     parseRuntimeOption("dalvik.vm.lockprof.threshold",
                        lockProfThresholdBuf,
                        "-Xlockprofthreshold:");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 63dba43..fa86c75 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -141,32 +141,45 @@
   errno = saved_errno;
 }
 
-// Configures the SIGCHLD handler for the zygote process. This is configured
-// very late, because earlier in the runtime we may fork() and exec()
-// other processes, and we want to waitpid() for those rather than
+// Configures the SIGCHLD/SIGHUP handlers for the zygote process. This is
+// configured very late, because earlier in the runtime we may fork() and
+// exec() other processes, and we want to waitpid() for those rather than
 // have them be harvested immediately.
 //
+// Ignore SIGHUP because all processes forked by the zygote are in the same
+// process group as the zygote and we don't want to be notified if we become
+// an orphaned group and have one or more stopped processes. This is not a
+// theoretical concern :
+// - we can become an orphaned group if one of our direct descendants forks
+//   and is subsequently killed before its children.
+// - crash_dump routinely STOPs the process it's tracing.
+//
+// See issues b/71965619 and b/25567761 for further details.
+//
 // This ends up being called repeatedly before each fork(), but there's
 // no real harm in that.
-static void SetSigChldHandler() {
-  struct sigaction sa;
-  memset(&sa, 0, sizeof(sa));
-  sa.sa_handler = SigChldHandler;
+static void SetSignalHandlers() {
+  struct sigaction sig_chld = {};
+  sig_chld.sa_handler = SigChldHandler;
 
-  int err = sigaction(SIGCHLD, &sa, NULL);
-  if (err < 0) {
+  if (sigaction(SIGCHLD, &sig_chld, NULL) < 0) {
     ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
   }
+
+  struct sigaction sig_hup = {};
+  sig_hup.sa_handler = SIG_IGN;
+  if (sigaction(SIGHUP, &sig_hup, NULL) < 0) {
+    ALOGW("Error setting SIGHUP handler: %s", strerror(errno));
+  }
 }
 
 // Sets the SIGCHLD handler back to default behavior in zygote children.
-static void UnsetSigChldHandler() {
+static void UnsetChldSignalHandler() {
   struct sigaction sa;
   memset(&sa, 0, sizeof(sa));
   sa.sa_handler = SIG_DFL;
 
-  int err = sigaction(SIGCHLD, &sa, NULL);
-  if (err < 0) {
+  if (sigaction(SIGCHLD, &sa, NULL) < 0) {
     ALOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
   }
 }
@@ -505,7 +518,7 @@
                                      bool is_system_server, jintArray fdsToClose,
                                      jintArray fdsToIgnore,
                                      jstring instructionSet, jstring dataDir) {
-  SetSigChldHandler();
+  SetSignalHandlers();
 
   sigset_t sigchld;
   sigemptyset(&sigchld);
@@ -682,7 +695,8 @@
     delete se_info;
     delete se_name;
 
-    UnsetSigChldHandler();
+    // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
+    UnsetChldSignalHandler();
 
     env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
                               is_system_server, instructionSet);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fdda55b..43d7df3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -950,6 +950,23 @@
                 android:description="@string/permdesc_manageOwnCalls"
                 android:protectionLevel="normal" />
 
+    <!-- Allows a calling app to continue a call which was started in another app.  An example is a
+         video calling app that wants to continue a voice call on the user's mobile network.<p>
+         When the handover of a call from one app to another takes place, there are two devices
+         which are involved in the handover; the initiating and receiving devices.  The initiating
+         device is where the request to handover the call was started, and the receiving device is
+         where the handover request is confirmed by the other party.<p>
+         This permission protects access to
+         {@link android.telecom.TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}, which
+         the receiving side of the handover uses to accept a handover.
+         <p>Protection level: dangerous
+    -->
+    <permission android:name="android.permission.ACCEPT_HANDOVER"
+                android:permissionGroup="android.permission-group.PHONE"
+                android.label="@string/permlab_acceptHandover"
+                android:description="@string/permdesc_acceptHandover"
+                android:protectionLevel="dangerous" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device microphone                        -->
     <!-- ====================================================================== -->
@@ -1415,6 +1432,12 @@
         android:label="@string/permlab_nfc"
         android:protectionLevel="normal" />
 
+    <!-- Allows applications to receive NFC transaction events.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.permission.NFC_TRANSACTION_EVENT"
+        android:protectionLevel="normal" />
+
     <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
          @hide -->
     <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index befebd9..0a36ba7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1076,6 +1076,17 @@
     <string name="permdesc_manageOwnCalls">Allows the app to route its calls through the system in
         order to improve the calling experience.</string>
 
+    <!-- Title of an application permission.  When granted to a third party app, the user is giving
+         access to the app to continue a call which originated in another app.  For example, the
+         user could be in a voice call over their carrier's mobile network, and a third party video
+         calling app wants to continue that voice call as a video call. -->
+    <string name="permlab_acceptHandover">continue a call from another app</string>
+    <!-- Description of an application permission.  When granted to a third party app, the user is
+         giving access to the app to continue a call which originated in another app.  For example,
+         the user could be in a voice call over their carrier's mobile network, and a third party
+         video calling app wants to continue that voice call as a video call. -->
+    <string name="permdesc_acceptHandover">Allows the app to continue a call which was started in another app.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readPhoneNumbers">read phone numbers</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 99bcd6c..a6c5373 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -36,10 +36,8 @@
 
 include $(BUILD_PACKAGE)
 
-ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
 	$(hide) mkdir -p $(dir $@)
 	$(MAINDEXCLASSES) $< 1>$@
 
 $(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/AndroidManifest.xml
index e3068920..7cd01e54 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/AndroidManifest.xml
@@ -7,6 +7,8 @@
     <uses-sdk
         android:minSdkVersion="9"
         android:targetSdkVersion="19" />
+    <!-- Required for com.android.framework.multidexlegacytestservices.test2 -->
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
 
     <application
         android:label="MultiDexLegacyTestServices">
@@ -124,6 +126,6 @@
                 <action android:name="com.android.framework.multidexlegacytestservices.action.Service19" />
             </intent-filter>
         </service>
-        </application>
+    </application>
 
 </manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java
index 7b83999..cb0a591 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/src/com/android/framework/multidexlegacytestservices/AbstractService.java
@@ -60,35 +60,40 @@
             // of the result file will be too big.
             RandomAccessFile raf = new RandomAccessFile(resultFile, "rw");
             raf.seek(raf.length());
-            Log.i(TAG, "Writing 0x42434445 at " + raf.length() + " in " + resultFile.getPath());
-            raf.writeInt(0x42434445);
+            if (raf.length() == 0) {
+                Log.i(TAG, "Writing 0x42434445 at " + raf.length() + " in " + resultFile.getPath());
+                raf.writeInt(0x42434445);
+            } else {
+                Log.w(TAG, "Service was restarted appending 0x42434445 twice at " + raf.length()
+                        + " in " + resultFile.getPath());
+                raf.writeInt(0x42434445);
+                raf.writeInt(0x42434445);
+            }
             raf.close();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        MultiDex.install(applicationContext);
-        Log.i(TAG, "Multi dex installation done.");
+            MultiDex.install(applicationContext);
+            Log.i(TAG, "Multi dex installation done.");
 
-        int value = getValue();
-        Log.i(TAG, "Saving the result (" + value + ") to " + resultFile.getPath());
-        try {
+            int value = getValue();
+            Log.i(TAG, "Saving the result (" + value + ") to " + resultFile.getPath());
             // Append the check value in result file, keeping the constant values already written.
-            RandomAccessFile raf = new RandomAccessFile(resultFile, "rw");
+            raf = new RandomAccessFile(resultFile, "rw");
             raf.seek(raf.length());
             Log.i(TAG, "Writing result at " + raf.length() + " in " + resultFile.getPath());
             raf.writeInt(value);
             raf.close();
         } catch (IOException e) {
-            e.printStackTrace();
-        }
-        try {
-            // Writing end of processing flags, the existence of the file is the criteria
-            RandomAccessFile raf = new RandomAccessFile(new File(applicationContext.getFilesDir(), getId() + ".complete"), "rw");
-            Log.i(TAG, "creating complete file " + resultFile.getPath());
-            raf.writeInt(0x32333435);
-            raf.close();
-        } catch (IOException e) {
-            e.printStackTrace();
+            throw new AssertionError(e);
+        } finally {
+            try {
+                // Writing end of processing flags, the existence of the file is the criteria
+                RandomAccessFile raf = new RandomAccessFile(
+                        new File(applicationContext.getFilesDir(), getId() + ".complete"), "rw");
+                Log.i(TAG, "creating complete file " + resultFile.getPath());
+                raf.writeInt(0x32333435);
+                raf.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
         }
     }
 
@@ -119,9 +124,10 @@
             intermediate = ReflectIntermediateClass.get(45, 80, 20 /* 5 seems enough on a nakasi,
                 using 20 to get some margin */);
         } catch (Exception e) {
-            e.printStackTrace();
+            throw new AssertionError(e);
         }
-        int value = new com.android.framework.multidexlegacytestservices.manymethods.Big001().get1() +
+        int value =
+                new com.android.framework.multidexlegacytestservices.manymethods.Big001().get1() +
                 new com.android.framework.multidexlegacytestservices.manymethods.Big002().get2() +
                 new com.android.framework.multidexlegacytestservices.manymethods.Big003().get3() +
                 new com.android.framework.multidexlegacytestservices.manymethods.Big004().get4() +
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
new file mode 100644
index 0000000..f3d98a8
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyTestServicesTests2
+
+LOCAL_JAVA_LIBRARIES := android-support-multidex
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
new file mode 100644
index 0000000..0ab2959
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.framework.multidexlegacytestservices.test2"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="9" />
+    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.framework.multidexlegacytestservices" />
+
+    <application
+        android:label="multidexlegacytestservices.test2" >
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
new file mode 100644
index 0000000..900f203
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
@@ -0,0 +1,381 @@
+/*
+ * 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.framework.multidexlegacytestservices.test2;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.concurrent.TimeoutException;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ * com.android.framework.multidexlegacytestservices.test2/android.support.test.runner.AndroidJUnitRunner
+ * </code>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ServicesTests {
+    private static final String TAG = "ServicesTests";
+
+    static {
+        Log.i(TAG, "Initializing");
+    }
+
+    private class ExtensionFilter implements FileFilter {
+        private final String ext;
+
+        public ExtensionFilter(String ext) {
+            this.ext = ext;
+        }
+
+        @Override
+        public boolean accept(File file) {
+            return file.getName().endsWith(ext);
+        }
+    }
+
+    private class ExtractedZipFilter extends ExtensionFilter {
+        public  ExtractedZipFilter() {
+            super(".zip");
+        }
+
+        @Override
+        public boolean accept(File file) {
+            return super.accept(file) && !file.getName().startsWith("tmp-");
+        }
+    }
+
+    private static final int ENDHDR = 22;
+
+    private static final String SERVICE_BASE_ACTION =
+            "com.android.framework.multidexlegacytestservices.action.Service";
+    private static final int MIN_SERVICE = 1;
+    private static final int MAX_SERVICE = 19;
+    private static final String COMPLETION_SUCCESS = "Success";
+
+    private File targetFilesDir;
+
+    @Before
+    public void setup() throws Exception {
+        Log.i(TAG, "setup");
+        killServices();
+
+        File applicationDataDir =
+                new File(InstrumentationRegistry.getTargetContext().getApplicationInfo().dataDir);
+        clearDirContent(applicationDataDir);
+        targetFilesDir = InstrumentationRegistry.getTargetContext().getFilesDir();
+
+        Log.i(TAG, "setup done");
+    }
+
+    @Test
+    public void testStressConcurentLaunch() throws Exception {
+        startServices();
+        waitServicesCompletion();
+        String completionStatus = getServicesCompletionStatus();
+        if (completionStatus != COMPLETION_SUCCESS) {
+            Assert.fail(completionStatus);
+        }
+    }
+
+    @Test
+    public void testRecoverFromZipCorruption() throws Exception {
+        int serviceId = 1;
+        // Ensure extraction.
+        initServicesWorkFiles();
+        startService(serviceId);
+        waitServicesCompletion(serviceId);
+
+        // Corruption of the extracted zips.
+        tamperAllExtractedZips();
+
+        killServices();
+        checkRecover();
+    }
+
+    @Test
+    public void testRecoverFromDexCorruption() throws Exception {
+        int serviceId = 1;
+        // Ensure extraction.
+        initServicesWorkFiles();
+        startService(serviceId);
+        waitServicesCompletion(serviceId);
+
+        // Corruption of the odex files.
+        tamperAllOdex();
+
+        killServices();
+        checkRecover();
+    }
+
+    @Test
+    public void testRecoverFromZipCorruptionStressTest() throws Exception {
+        Thread startServices =
+                new Thread() {
+            @Override
+            public void run() {
+                startServices();
+            }
+        };
+
+        startServices.start();
+
+        // Start services lasts more than 80s, lets cause a few corruptions during this interval.
+        for (int i = 0; i < 80; i++) {
+            Thread.sleep(1000);
+            tamperAllExtractedZips();
+        }
+        startServices.join();
+        try {
+            waitServicesCompletion();
+        } catch (TimeoutException e) {
+            // Can happen.
+        }
+
+        killServices();
+        checkRecover();
+    }
+
+    @Test
+    public void testRecoverFromDexCorruptionStressTest() throws Exception {
+        Thread startServices =
+                new Thread() {
+            @Override
+            public void run() {
+                startServices();
+            }
+        };
+
+        startServices.start();
+
+        // Start services lasts more than 80s, lets cause a few corruptions during this interval.
+        for (int i = 0; i < 80; i++) {
+            Thread.sleep(1000);
+            tamperAllOdex();
+        }
+        startServices.join();
+        try {
+            waitServicesCompletion();
+        } catch (TimeoutException e) {
+            // Will probably happen most of the time considering what we're doing...
+        }
+
+        killServices();
+        checkRecover();
+    }
+
+    private static void clearDirContent(File dir) {
+        for (File subElement : dir.listFiles()) {
+            if (subElement.isDirectory()) {
+                clearDirContent(subElement);
+            }
+            if (!subElement.delete()) {
+                throw new AssertionError("Failed to clear '" + subElement.getAbsolutePath() + "'");
+            }
+        }
+    }
+
+    private void startServices() {
+        Log.i(TAG, "start services");
+        initServicesWorkFiles();
+        for (int i = MIN_SERVICE; i <= MAX_SERVICE; i++) {
+            startService(i);
+            try {
+                Thread.sleep((i - 1) * (1 << (i / 5)));
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    private void startService(int serviceId) {
+        Log.i(TAG, "start service " + serviceId);
+        InstrumentationRegistry.getContext().startService(new Intent(SERVICE_BASE_ACTION + serviceId));
+    }
+
+    private void initServicesWorkFiles() {
+        for (int i = MIN_SERVICE; i <= MAX_SERVICE; i++) {
+            File resultFile = new File(targetFilesDir, "Service" + i);
+            resultFile.delete();
+            Assert.assertFalse(
+                    "Failed to delete result file '" + resultFile.getAbsolutePath() + "'.",
+                    resultFile.exists());
+            File completeFile = new File(targetFilesDir, "Service" + i + ".complete");
+            completeFile.delete();
+            Assert.assertFalse(
+                    "Failed to delete completion file '" + completeFile.getAbsolutePath() + "'.",
+                    completeFile.exists());
+        }
+    }
+
+    private void waitServicesCompletion() throws TimeoutException {
+        Log.i(TAG, "start sleeping");
+        int attempt = 0;
+        int maxAttempt = 50; // 10 is enough for a nexus S
+        do {
+            try {
+                Thread.sleep(5000);
+            } catch (InterruptedException e) {
+            }
+            attempt++;
+            if (attempt >= maxAttempt) {
+                throw new TimeoutException();
+            }
+        } while (!areAllServicesCompleted());
+    }
+
+    private void waitServicesCompletion(int serviceId) throws TimeoutException {
+        Log.i(TAG, "start sleeping");
+        int attempt = 0;
+        int maxAttempt = 50; // 10 is enough for a nexus S
+        do {
+            try {
+                Thread.sleep(5000);
+            } catch (InterruptedException e) {
+            }
+            attempt++;
+            if (attempt >= maxAttempt) {
+                throw new TimeoutException();
+            }
+        } while (isServiceRunning(serviceId));
+    }
+
+    private String getServicesCompletionStatus() {
+        String status = COMPLETION_SUCCESS;
+        for (int i = MIN_SERVICE; i <= MAX_SERVICE; i++) {
+            File resultFile = new File(targetFilesDir, "Service" + i);
+            if (!resultFile.isFile()) {
+                status = "Service" + i + " never completed.";
+                break;
+            }
+            if (resultFile.length() != 8) {
+                status = "Service" + i + " was restarted.";
+                break;
+            }
+        }
+        Log.i(TAG, "Services completion status: " + status);
+        return status;
+    }
+
+    private String getServiceCompletionStatus(int serviceId) {
+        String status = COMPLETION_SUCCESS;
+        File resultFile = new File(targetFilesDir, "Service" + serviceId);
+        if (!resultFile.isFile()) {
+            status = "Service" + serviceId + " never completed.";
+        } else if (resultFile.length() != 8) {
+            status = "Service" + serviceId + " was restarted.";
+        }
+        Log.i(TAG, "Service " + serviceId + " completion status: " + status);
+        return status;
+    }
+
+    private boolean areAllServicesCompleted() {
+        for (int i = MIN_SERVICE; i <= MAX_SERVICE; i++) {
+            if (isServiceRunning(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean isServiceRunning(int i) {
+        File completeFile = new File(targetFilesDir, "Service" + i + ".complete");
+        return !completeFile.exists();
+    }
+
+    private File getSecondaryFolder() {
+        File dir =
+                new File(
+                        new File(
+                                InstrumentationRegistry.getTargetContext().getApplicationInfo().dataDir,
+                                "code_cache"),
+                        "secondary-dexes");
+        Assert.assertTrue(dir.getAbsolutePath(), dir.isDirectory());
+        return dir;
+    }
+
+    private void tamperAllExtractedZips() throws IOException {
+        // First attempt was to just overwrite zip entries but keep central directory, this was no
+        // trouble for Dalvik that was just ignoring those zip and using the odex files.
+        Log.i(TAG, "Tamper extracted zip files by overwriting all content by '\\0's.");
+        byte[] zeros = new byte[4 * 1024];
+        // Do not tamper tmp zip during their extraction.
+        for (File zip : getSecondaryFolder().listFiles(new ExtractedZipFilter())) {
+            long fileLength = zip.length();
+            Assert.assertTrue(fileLength > ENDHDR);
+            zip.setWritable(true);
+            RandomAccessFile raf = new RandomAccessFile(zip, "rw");
+            try {
+                int index = 0;
+                while (index < fileLength) {
+                    int length = (int) Math.min(zeros.length, fileLength - index);
+                    raf.write(zeros, 0, length);
+                    index += length;
+                }
+            } finally {
+                raf.close();
+            }
+        }
+    }
+
+    private void tamperAllOdex() throws IOException {
+        Log.i(TAG, "Tamper odex files by overwriting some content by '\\0's.");
+        byte[] zeros = new byte[4 * 1024];
+        // I think max size would be 40 (u1[8] + 8 u4) but it's a test so lets take big margins.
+        int savedSizeForOdexHeader = 80;
+        for (File odex : getSecondaryFolder().listFiles(new ExtensionFilter(".dex"))) {
+            long fileLength = odex.length();
+            Assert.assertTrue(fileLength > zeros.length + savedSizeForOdexHeader);
+            odex.setWritable(true);
+            RandomAccessFile raf = new RandomAccessFile(odex, "rw");
+            try {
+                raf.seek(savedSizeForOdexHeader);
+                raf.write(zeros, 0, zeros.length);
+            } finally {
+                raf.close();
+            }
+        }
+    }
+
+    private void checkRecover() throws TimeoutException {
+        Log.i(TAG, "Check recover capability");
+        int serviceId = 1;
+        // Start one service and check it was able to run correctly even if a previous run failed.
+        initServicesWorkFiles();
+        startService(serviceId);
+        waitServicesCompletion(serviceId);
+        String completionStatus = getServiceCompletionStatus(serviceId);
+        if (completionStatus != COMPLETION_SUCCESS) {
+            Assert.fail(completionStatus);
+        }
+    }
+
+    private void killServices() {
+        ((ActivityManager)
+                InstrumentationRegistry.getContext().getSystemService(Context.ACTIVITY_SERVICE))
+        .killBackgroundProcesses("com.android.framework.multidexlegacytestservices");
+    }
+}
diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp
index e8e34d7..95246a0 100644
--- a/libs/services/src/os/DropBoxManager.cpp
+++ b/libs/services/src/os/DropBoxManager.cpp
@@ -185,6 +185,11 @@
 Status
 DropBoxManager::addFile(const String16& tag, int fd, int flags)
 {
+    if (fd == -1) {
+        string message("invalid fd (-1) passed to to addFile");
+        ALOGW("DropboxManager: %s", message.c_str());
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, message.c_str());
+    }
     Entry entry(tag, flags, fd);
     return add(entry);
 }
@@ -201,4 +206,3 @@
 }
 
 }} // namespace android::os
-
diff --git a/location/lib/Android.mk b/location/lib/Android.mk
index 62f5677..8424601 100644
--- a/location/lib/Android.mk
+++ b/location/lib/Android.mk
@@ -22,9 +22,7 @@
 LOCAL_MODULE:= com.android.location.provider
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-            $(call all-aidl-files-under, java)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 include $(BUILD_JAVA_LIBRARY)
 
diff --git a/media/lib/remotedisplay/Android.mk b/media/lib/remotedisplay/Android.mk
index ea1ac2b..e88c0f1 100644
--- a/media/lib/remotedisplay/Android.mk
+++ b/media/lib/remotedisplay/Android.mk
@@ -22,9 +22,7 @@
 LOCAL_MODULE:= com.android.media.remotedisplay
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := \
-            $(call all-java-files-under, java) \
-            $(call all-aidl-files-under, java)
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
 
 include $(BUILD_JAVA_LIBRARY)
 
diff --git a/media/lib/signer/Android.mk b/media/lib/signer/Android.mk
index b0d3177..69ca4d2 100644
--- a/media/lib/signer/Android.mk
+++ b/media/lib/signer/Android.mk
@@ -22,9 +22,7 @@
 LOCAL_MODULE:= com.android.mediadrm.signer
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := \
-            $(call all-java-files-under, java) \
-            $(call all-aidl-files-under, java)
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
 
 include $(BUILD_JAVA_LIBRARY)
 
diff --git a/media/lib/tvremote/Android.mk b/media/lib/tvremote/Android.mk
index 06838c2..1ffdd62 100644
--- a/media/lib/tvremote/Android.mk
+++ b/media/lib/tvremote/Android.mk
@@ -22,9 +22,7 @@
 LOCAL_MODULE:= com.android.media.tv.remoteprovider
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := \
-            $(call all-java-files-under, java) \
-            $(call all-aidl-files-under, java)
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
 
 LOCAL_DEX_PREOPT := false
 
@@ -45,4 +43,4 @@
 
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 
-include $(BUILD_PREBUILT)
\ No newline at end of file
+include $(BUILD_PREBUILT)
diff --git a/packages/SystemUI/res/layout/back.xml b/packages/SystemUI/res/layout/back.xml
index 43bec91..6843db9 100644
--- a/packages/SystemUI/res/layout/back.xml
+++ b/packages/SystemUI/res/layout/back.xml
@@ -24,8 +24,8 @@
     systemui:keyCode="4"
     android:scaleType="fitCenter"
     android:contentDescription="@string/accessibility_back"
-    android:paddingTop="15dp"
-    android:paddingBottom="15dp"
+    android:paddingTop="@dimen/home_padding"
+    android:paddingBottom="@dimen/home_padding"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
     />
diff --git a/packages/SystemUI/res/layout/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml
index c84d280..6b08cea 100644
--- a/packages/SystemUI/res/layout/recent_apps.xml
+++ b/packages/SystemUI/res/layout/recent_apps.xml
@@ -23,8 +23,8 @@
     android:layout_weight="0"
     android:scaleType="fitCenter"
     android:contentDescription="@string/accessibility_recent"
-    android:paddingTop="15dp"
-    android:paddingBottom="15dp"
+    android:paddingTop="@dimen/home_padding"
+    android:paddingBottom="@dimen/home_padding"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
     />
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index c8ffe8f..a16ea70 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -98,4 +98,7 @@
 
     <!-- The offsets the tasks animate from when recents is launched while docking -->
     <dimen name="recents_task_stack_animation_launched_while_docking_offset">192dp</dimen>
+
+    <!-- Home button padding for sizing -->
+    <dimen name="home_padding">0dp</dimen>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 4e79314b..9f89fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -219,6 +219,11 @@
             newLayout = getDefaultLayout();
         }
         String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
+        if (sets.length != 3) {
+            Log.d(TAG, "Invalid layout.");
+            newLayout = getDefaultLayout();
+            sets = newLayout.split(GRAVITY_SEPARATOR, 3);
+        }
         String[] start = sets[0].split(BUTTON_SEPARATOR);
         String[] center = sets[1].split(BUTTON_SEPARATOR);
         String[] end = sets[2].split(BUTTON_SEPARATOR);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index fe4ac6d7..a07a982 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -87,6 +87,7 @@
     private static final String NETD_SERVICE_NAME = "netd";
     private static final int[] DIRECTIONS =
             new int[] {IpSecManager.DIRECTION_OUT, IpSecManager.DIRECTION_IN};
+    private static final String[] WILDCARD_ADDRESSES = new String[]{"0.0.0.0", "::"};
 
     private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
     private static final int MAX_PORT_BIND_ATTEMPTS = 10;
@@ -413,12 +414,16 @@
                     .append(mTransformQuotaTracker)
                     .append(", mSocketQuotaTracker=")
                     .append(mSocketQuotaTracker)
+                    .append(", mTunnelQuotaTracker=")
+                    .append(mTunnelQuotaTracker)
                     .append(", mSpiRecords=")
                     .append(mSpiRecords)
                     .append(", mTransformRecords=")
                     .append(mTransformRecords)
                     .append(", mEncapSocketRecords=")
                     .append(mEncapSocketRecords)
+                    .append(", mTunnelInterfaceRecords=")
+                    .append(mTunnelInterfaceRecords)
                     .append("}")
                     .toString();
         }
@@ -815,12 +820,14 @@
             try {
                 mSrvConfig.getNetdInstance().removeVirtualTunnelInterface(mInterfaceName);
 
-                for (int direction : DIRECTIONS) {
-                    int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey;
-                    mSrvConfig
-                            .getNetdInstance()
-                            .ipSecDeleteSecurityPolicy(
-                                    0, direction, mLocalAddress, mRemoteAddress, mark, 0xffffffff);
+                for(String wildcardAddr : WILDCARD_ADDRESSES) {
+                    for (int direction : DIRECTIONS) {
+                        int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey;
+                        mSrvConfig
+                                .getNetdInstance()
+                                .ipSecDeleteSecurityPolicy(
+                                        0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff);
+                    }
                 }
             } catch (ServiceSpecificException e) {
                 // FIXME: get the error code and throw is at an IOException from Errno Exception
@@ -1261,19 +1268,21 @@
                     .getNetdInstance()
                     .addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey);
 
-            for (int direction : DIRECTIONS) {
-                int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey;
+            for(String wildcardAddr : WILDCARD_ADDRESSES) {
+                for (int direction : DIRECTIONS) {
+                    int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey;
 
-                mSrvConfig
-                        .getNetdInstance()
-                        .ipSecAddSecurityPolicy(
+                    mSrvConfig
+                            .getNetdInstance()
+                            .ipSecAddSecurityPolicy(
                                 0, // Use 0 for reqId
                                 direction,
-                                "",
-                                "",
+                                wildcardAddr,
+                                wildcardAddr,
                                 0,
                                 mark,
                                 0xffffffff);
+                }
             }
 
             userRecord.mTunnelInterfaceRecords.put(
@@ -1646,16 +1655,18 @@
                 c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork());
 
                 // If outbound, also add SPI to the policy.
-                mSrvConfig
-                        .getNetdInstance()
-                        .ipSecUpdateSecurityPolicy(
-                                0, // Use 0 for reqId
-                                direction,
-                                "",
-                                "",
-                                transformInfo.getSpiRecord().getSpi(),
-                                mark,
-                                0xffffffff);
+                for(String wildcardAddr : WILDCARD_ADDRESSES) {
+                    mSrvConfig
+                            .getNetdInstance()
+                            .ipSecUpdateSecurityPolicy(
+                                    0, // Use 0 for reqId
+                                    direction,
+                                    wildcardAddr,
+                                    wildcardAddr,
+                                    transformInfo.getSpiRecord().getSpi(),
+                                    mark,
+                                    0xffffffff);
+                }
             }
 
             // Update SA with tunnel mark (ikey or okey based on direction)
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index bd2e96e..e43d152 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -150,7 +150,8 @@
             fillLinkInfo(ev, newNai);
             ev.initialScore = newNai.getCurrentScore();
             if (newNai.lastValidated) {
-                logDefaultNetworkValidity(timeMs, true);
+                mIsCurrentlyValid = true;
+                mLastValidationTimeMs = timeMs;
             }
         } else {
             mIsCurrentlyValid = false;
diff --git a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
deleted file mode 100644
index f6b73b7..0000000
--- a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.util.NetworkConstants.IPV4_HEADER_MIN_LEN;
-import static android.net.util.NetworkConstants.UDP_HEADER_LEN;
-
-import android.system.OsConstants;
-import android.net.ConnectivityManager;
-import android.net.NetworkUtils;
-import android.net.util.IpUtils;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import static android.net.ConnectivityManager.PacketKeepalive.*;
-
-/**
- * Represents the actual packets that are sent by the
- * {@link android.net.ConnectivityManager.PacketKeepalive} API.
- *
- * @hide
- */
-public class KeepalivePacketData {
-    /** Protocol of the packet to send; one of the OsConstants.ETH_P_* values. */
-    public final int protocol;
-
-    /** Source IP address */
-    public final InetAddress srcAddress;
-
-    /** Destination IP address */
-    public final InetAddress dstAddress;
-
-    /** Source port */
-    public final int srcPort;
-
-    /** Destination port */
-    public final int dstPort;
-
-    /** Destination MAC address. Can change if routing changes. */
-    public byte[] dstMac;
-
-    /** Packet data. A raw byte string of packet data, not including the link-layer header. */
-    public final byte[] data;
-
-    protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
-            InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
-        this.srcAddress = srcAddress;
-        this.dstAddress = dstAddress;
-        this.srcPort = srcPort;
-        this.dstPort = dstPort;
-        this.data = data;
-
-        // Check we have two IP addresses of the same family.
-        if (srcAddress == null || dstAddress == null ||
-                !srcAddress.getClass().getName().equals(dstAddress.getClass().getName())) {
-            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
-        }
-
-        // Set the protocol.
-        if (this.dstAddress instanceof Inet4Address) {
-            this.protocol = OsConstants.ETH_P_IP;
-        } else if (this.dstAddress instanceof Inet6Address) {
-            this.protocol = OsConstants.ETH_P_IPV6;
-        } else {
-            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
-        }
-
-        // Check the ports.
-        if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
-            throw new InvalidPacketException(ERROR_INVALID_PORT);
-        }
-    }
-
-    public static class InvalidPacketException extends Exception {
-        final public int error;
-        public InvalidPacketException(int error) {
-            this.error = error;
-        }
-    }
-
-    /**
-     * Creates an IPsec NAT-T keepalive packet with the specified parameters.
-     */
-    public static KeepalivePacketData nattKeepalivePacket(
-            InetAddress srcAddress, int srcPort,
-            InetAddress dstAddress, int dstPort) throws InvalidPacketException {
-
-        if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
-            throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
-        }
-
-        if (dstPort != NATT_PORT) {
-            throw new InvalidPacketException(ERROR_INVALID_PORT);
-        }
-
-        int length = IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + 1;
-        ByteBuffer buf = ByteBuffer.allocate(length);
-        buf.order(ByteOrder.BIG_ENDIAN);
-        buf.putShort((short) 0x4500);             // IP version and TOS
-        buf.putShort((short) length);
-        buf.putInt(0);                            // ID, flags, offset
-        buf.put((byte) 64);                       // TTL
-        buf.put((byte) OsConstants.IPPROTO_UDP);
-        int ipChecksumOffset = buf.position();
-        buf.putShort((short) 0);                  // IP checksum
-        buf.put(srcAddress.getAddress());
-        buf.put(dstAddress.getAddress());
-        buf.putShort((short) srcPort);
-        buf.putShort((short) dstPort);
-        buf.putShort((short) (length - 20));      // UDP length
-        int udpChecksumOffset = buf.position();
-        buf.putShort((short) 0);                  // UDP checksum
-        buf.put((byte) 0xff);                     // NAT-T keepalive
-        buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
-        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_MIN_LEN));
-
-        return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
-    }
-}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 9e1f6b8..d24f9c9 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -18,10 +18,10 @@
 
 import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.connectivity.KeepalivePacketData;
 import com.android.server.connectivity.NetworkAgentInfo;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.PacketKeepalive;
+import android.net.KeepalivePacketData;
 import android.net.LinkAddress;
 import android.net.NetworkAgent;
 import android.net.NetworkUtils;
@@ -129,7 +129,7 @@
                     .append("->")
                     .append(IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort))
                     .append(" interval=" + mInterval)
-                    .append(" data=" + HexDump.toHexString(mPacket.data))
+                    .append(" packetData=" + HexDump.toHexString(mPacket.getPacket()))
                     .append(" uid=").append(mUid).append(" pid=").append(mPid)
                     .append(" ]")
                     .toString();
@@ -172,7 +172,7 @@
         }
 
         private int checkInterval() {
-            return mInterval >= 20 ? SUCCESS : ERROR_INVALID_INTERVAL;
+            return mInterval >= 10 ? SUCCESS : ERROR_INVALID_INTERVAL;
         }
 
         private int isValid() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6a53e48..4454c71 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -611,7 +611,8 @@
             Manifest.permission.READ_EXTERNAL_STORAGE,
             Manifest.permission.WRITE_EXTERNAL_STORAGE,
             Manifest.permission.READ_PHONE_NUMBERS,
-            Manifest.permission.ANSWER_PHONE_CALLS);
+            Manifest.permission.ANSWER_PHONE_CALLS,
+            Manifest.permission.ACCEPT_HANDOVER);
 
 
     /**
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index f0ce3c9..1268464 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -60,10 +60,8 @@
     // to synchronize access during policy load and access attempts.
     private static List<Policy> sPolicies = new ArrayList<>();
 
-    /** Path to MAC permissions on system image */
-    private static final File[] MAC_PERMISSIONS =
-    { new File(Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml"),
-      new File(Environment.getVendorDirectory(), "/etc/selinux/nonplat_mac_permissions.xml") };
+    /** Required MAC permissions files */
+    private static List<File> sMacPermissions = new ArrayList<>();
 
     // Append privapp to existing seinfo label
     private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -74,13 +72,40 @@
     // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
     private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
 
+    // Only initialize sMacPermissions once.
+    static {
+        // Platform mac permissions.
+        sMacPermissions.add(new File(
+            Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml"));
+
+        // Vendor mac permissions.
+        // The filename has been renamed from nonplat_mac_permissions to
+        // vendor_mac_permissions. Either of them should exist.
+        final File vendorMacPermission = new File(
+            Environment.getVendorDirectory(), "/etc/selinux/vendor_mac_permissions.xml");
+        if (vendorMacPermission.exists()) {
+            sMacPermissions.add(vendorMacPermission);
+        } else {
+            // For backward compatibility.
+            sMacPermissions.add(new File(Environment.getVendorDirectory(),
+                                         "/etc/selinux/nonplat_mac_permissions.xml"));
+        }
+
+        // ODM mac permissions (optional).
+        final File odmMacPermission = new File(
+            Environment.getOdmDirectory(), "/etc/selinux/odm_mac_permissions.xml");
+        if (odmMacPermission.exists()) {
+            sMacPermissions.add(odmMacPermission);
+        }
+    }
+
     /**
      * Load the mac_permissions.xml file containing all seinfo assignments used to
-     * label apps. The loaded mac_permissions.xml file is determined by the
-     * MAC_PERMISSIONS class variable which is set at class load time which itself
-     * is based on the USE_OVERRIDE_POLICY class variable. For further guidance on
+     * label apps. The loaded mac_permissions.xml files are plat_mac_permissions.xml and
+     * vendor_mac_permissions.xml, on /system and /vendor partitions, respectively.
+     * odm_mac_permissions.xml on /odm partition is optional. For further guidance on
      * the proper structure of a mac_permissions.xml file consult the source code
-     * located at system/sepolicy/mac_permissions.xml.
+     * located at system/sepolicy/private/mac_permissions.xml.
      *
      * @return boolean indicating if policy was correctly loaded. A value of false
      *         typically indicates a structural problem with the xml or incorrectly
@@ -93,10 +118,13 @@
 
         FileReader policyFile = null;
         XmlPullParser parser = Xml.newPullParser();
-        for (int i = 0; i < MAC_PERMISSIONS.length; i++) {
+
+        final int count = sMacPermissions.size();
+        for (int i = 0; i < count; ++i) {
+            final File macPermission = sMacPermissions.get(i);
             try {
-                policyFile = new FileReader(MAC_PERMISSIONS[i]);
-                Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS[i]);
+                policyFile = new FileReader(macPermission);
+                Slog.d(TAG, "Using policy file " + macPermission);
 
                 parser.setInput(policyFile);
                 parser.nextTag();
@@ -120,13 +148,13 @@
                 StringBuilder sb = new StringBuilder("Exception @");
                 sb.append(parser.getPositionDescription());
                 sb.append(" while parsing ");
-                sb.append(MAC_PERMISSIONS[i]);
+                sb.append(macPermission);
                 sb.append(":");
                 sb.append(ex);
                 Slog.w(TAG, sb.toString());
                 return false;
             } catch (IOException ioe) {
-                Slog.w(TAG, "Exception parsing " + MAC_PERMISSIONS[i], ioe);
+                Slog.w(TAG, "Exception parsing " + macPermission, ioe);
                 return false;
             } finally {
                 IoUtils.closeQuietly(policyFile);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8c7d6b3..8a4b046 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1961,6 +1961,15 @@
         }
     }
 
+    /** {@hide} */
+    final void internalOnHandoverComplete() {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(() -> callback.onHandoverComplete(call));
+        }
+    }
+
     private void fireStateChanged(final int newState) {
         for (CallbackRecord<Callback> record : mCallbackRecords) {
             final Call call = this;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index d71fde2..8150efa 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2800,6 +2800,15 @@
     public void onCallEvent(String event, Bundle extras) {}
 
     /**
+     * Notifies this {@link Connection} that a handover has completed.
+     * <p>
+     * A handover is initiated with {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int,
+     * Bundle)} on the initiating side of the handover, and on the receiving side with
+     * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}.
+     */
+    public void onHandoverComplete() {}
+
+    /**
      * Notifies this {@link Connection} of a change to the extras made outside the
      * {@link ConnectionService}.
      * <p>
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index e37aeb4..990b0b4 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -140,6 +140,7 @@
     private static final String SESSION_POST_DIAL_CONT = "CS.oPDC";
     private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
     private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
+    private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
     private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
     private static final String SESSION_START_RTT = "CS.+RTT";
     private static final String SESSION_STOP_RTT = "CS.-RTT";
@@ -179,6 +180,7 @@
     private static final int MSG_CONNECTION_SERVICE_FOCUS_LOST = 30;
     private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31;
     private static final int MSG_HANDOVER_FAILED = 32;
+    private static final int MSG_HANDOVER_COMPLETE = 33;
 
     private static Connection sNullConnection;
 
@@ -298,6 +300,19 @@
         }
 
         @Override
+        public void handoverComplete(String callId, Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_HANDOVER_COMPLETE);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_HANDOVER_COMPLETE, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void abort(String callId, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_ABORT);
             try {
@@ -1028,6 +1043,19 @@
                     }
                     break;
                 }
+                case MSG_HANDOVER_COMPLETE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        Log.continueSession((Session) args.arg2,
+                                SESSION_HANDLER + SESSION_HANDOVER_COMPLETE);
+                        String callId = (String) args.arg1;
+                        notifyHandoverComplete(callId);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_ON_EXTRAS_CHANGED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -1445,19 +1473,24 @@
             final ConnectionRequest request,
             boolean isIncoming,
             boolean isUnknown) {
+        boolean isLegacyHandover = request.getExtras() != null &&
+                request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER, false);
+        boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
+                TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
         Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
-                        "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request,
-                isIncoming,
-                isUnknown);
+                        "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b",
+                callManagerAccount, callId, request, isIncoming, isUnknown, isLegacyHandover,
+                isHandover);
 
         Connection connection = null;
-        if (getApplicationContext().getApplicationInfo().targetSdkVersion >
-                Build.VERSION_CODES.O_MR1 && request.getExtras() != null &&
-                request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER,false)) {
+        if (isHandover) {
+            PhoneAccountHandle fromPhoneAccountHandle = request.getExtras() != null
+                    ? (PhoneAccountHandle) request.getExtras().getParcelable(
+                    TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT) : null;
             if (!isIncoming) {
-                connection = onCreateOutgoingHandoverConnection(callManagerAccount, request);
+                connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);
             } else {
-                connection = onCreateIncomingHandoverConnection(callManagerAccount, request);
+                connection = onCreateIncomingHandoverConnection(fromPhoneAccountHandle, request);
             }
         } else {
             connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
@@ -1754,6 +1787,19 @@
     }
 
     /**
+     * Notifies a {@link Connection} that a handover has completed.
+     *
+     * @param callId The ID of the call which completed handover.
+     */
+    private void notifyHandoverComplete(String callId) {
+        Log.d(this, "notifyHandoverComplete(%s)", callId);
+        Connection connection = findConnectionForAction(callId, "notifyHandoverComplete");
+        if (connection != null) {
+            connection.onHandoverComplete();
+        }
+    }
+
+    /**
      * Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom.
      * <p>
      * These extra changes can originate from Telecom itself, or from an {@link InCallService} via
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 74fa62d..fcf04c9 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -81,6 +81,7 @@
     private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
     private static final int MSG_ON_RTT_INITIATION_FAILURE = 11;
     private static final int MSG_ON_HANDOVER_FAILED = 12;
+    private static final int MSG_ON_HANDOVER_COMPLETE = 13;
 
     /** Default Handler used to consolidate binder method calls onto a single thread. */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -157,6 +158,11 @@
                     mPhone.internalOnHandoverFailed(callId, error);
                     break;
                 }
+                case MSG_ON_HANDOVER_COMPLETE: {
+                    String callId = (String) msg.obj;
+                    mPhone.internalOnHandoverComplete(callId);
+                    break;
+                }
                 default:
                     break;
             }
@@ -237,6 +243,11 @@
         public void onHandoverFailed(String callId, int error) {
             mHandler.obtainMessage(MSG_ON_HANDOVER_FAILED, error, 0, callId).sendToTarget();
         }
+
+        @Override
+        public void onHandoverComplete(String callId) {
+            mHandler.obtainMessage(MSG_ON_HANDOVER_COMPLETE, callId).sendToTarget();
+        }
     }
 
     private Phone.Listener mPhoneListener = new Phone.Listener() {
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index b5394b9..99f94f2 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -230,6 +230,13 @@
         }
     }
 
+    final void internalOnHandoverComplete(String callId) {
+        Call call = mCallByTelecomCallId.get(callId);
+        if (call != null) {
+            call.internalOnHandoverComplete();
+        }
+    }
+
     /**
      * Called to destroy the phone and cleanup any lingering calls.
      */
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 96c6e0a..7e89745 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -379,6 +379,17 @@
     public static final String EXTRA_IS_HANDOVER = "android.telecom.extra.IS_HANDOVER";
 
     /**
+     * When {@code true} indicates that a request to create a new connection is for the purpose of
+     * a handover.  Note: This is used with the
+     * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)} API as part of the
+     * internal communication mechanism with the {@link android.telecom.ConnectionService}.  It is
+     * not the same as the legacy {@link #EXTRA_IS_HANDOVER} extra.
+     * @hide
+     */
+    public static final String EXTRA_IS_HANDOVER_CONNECTION =
+            "android.telecom.extra.IS_HANDOVER_CONNECTION";
+
+    /**
      * Parcelable extra used with {@link #EXTRA_IS_HANDOVER} to indicate the source
      * {@link PhoneAccountHandle} when initiating a handover which {@link ConnectionService}
      * the handover is from.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 02e1ff8..3dbc8dd 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -104,6 +104,8 @@
     void handoverFailed(String callId, in ConnectionRequest request,
             int error, in Session.Info sessionInfo);
 
+    void handoverComplete(String callId, in Session.Info sessionInfo);
+
     void connectionServiceFocusLost(in Session.Info sessionInfo);
 
     void connectionServiceFocusGained(in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 110109e..b9563fa 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -56,4 +56,6 @@
     void onRttInitiationFailure(String callId, int reason);
 
     void onHandoverFailed(String callId, int error);
+
+    void onHandoverComplete(String callId);
 }
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 0474362..dfaaab9 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * Signal strength related information.
  */
@@ -293,9 +295,7 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return ((mCdmaDbm * primeNum) + (mCdmaEcio * primeNum)
-                + (mEvdoDbm * primeNum) + (mEvdoEcio * primeNum) + (mEvdoSnr * primeNum));
+        return Objects.hash(mCdmaDbm, mCdmaEcio, mEvdoDbm, mEvdoEcio, mEvdoSnr);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 4137853..f68d2ca 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * GSM signal strength related information.
  */
@@ -185,8 +187,7 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mSignalStrength * primeNum) + (mBitErrorRate * primeNum);
+        return Objects.hash(mSignalStrength, mBitErrorRate, mTimingAdvance);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 0d07a40..6ffc8b6 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * LTE signal strength related information.
  */
@@ -231,10 +233,7 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mSignalStrength * primeNum) + (mRsrp * primeNum)
-                + (mRsrq * primeNum) + (mRssnr * primeNum) + (mCqi * primeNum)
-                + (mTimingAdvance * primeNum);
+        return Objects.hash(mSignalStrength, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index b94b01d..2cd56b8 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * Wcdma signal strength related information.
  */
@@ -156,8 +158,7 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mSignalStrength * primeNum) + (mBitErrorRate * primeNum);
+        return Objects.hash(mSignalStrength, mBitErrorRate);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index dcdda86..6e083c2 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Binder;
 import android.os.Parcel;
 import android.content.res.Resources;
@@ -534,8 +535,16 @@
 
     /**
      * Returns the originating address (sender) of this SMS message in String
-     * form or null if unavailable
+     * form or null if unavailable.
+     *
+     * <p>If the address is a GSM-formatted address, it will be in a format specified by 3GPP
+     * 23.040 Sec 9.1.2.5. If it is a CDMA address, it will be a format specified by 3GPP2
+     * C.S005-D Table 2.7.1.3.2.4-2. The choice of format is carrier-specific, so callers of the
+     * should be careful to avoid assumptions about the returned content.
+     *
+     * @return a String representation of the address; null if unavailable.
      */
+    @Nullable
     public String getOriginatingAddress() {
         return mWrappedSmsMessage.getOriginatingAddress();
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ada697f..4138e29 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4279,7 +4279,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccTransmitApduBasicChannel(subId, cla,
+                return telephony.iccTransmitApduBasicChannel(subId, getOpPackageName(), cla,
                     instruction, p1, p2, p3, data);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -4768,28 +4768,6 @@
         }
     }
 
-    /**
-     * Returns the response of ISIM Authetification through RIL.
-     * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo.
-     * @return the response of ISIM Authetification, or null if not available
-     * @hide
-     * @deprecated
-     * @see getIccAuthentication with appType=PhoneConstants.APPTYPE_ISIM
-     */
-    public String getIsimChallengeResponse(String nonce){
-        try {
-            IPhoneSubInfo info = getSubscriberInfo();
-            if (info == null)
-                return null;
-            return info.getIsimChallengeResponse(nonce);
-        } catch (RemoteException ex) {
-            return null;
-        } catch (NullPointerException ex) {
-            // This could happen before phone restarts due to crashing
-            return null;
-        }
-    }
-
     // ICC SIM Application Types
     /** UICC application type is SIM */
     public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index ef3a183..25f5133 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -27,6 +27,7 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Description of the response of a setup data call connection request.
@@ -220,17 +221,8 @@
 
     @Override
     public int hashCode() {
-        return mStatus * 31
-                + mSuggestedRetryTime * 37
-                + mCid * 41
-                + mActive * 43
-                + mType.hashCode() * 47
-                + mIfname.hashCode() * 53
-                + mAddresses.hashCode() * 59
-                + mDnses.hashCode() * 61
-                + mGateways.hashCode() * 67
-                + mPcscfs.hashCode() * 71
-                + mMtu * 73;
+        return Objects.hash(mStatus, mSuggestedRetryTime, mCid, mActive, mType, mIfname, mAddresses,
+                mDnses, mGateways, mPcscfs, mMtu);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 8bb709f..662056e 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -276,8 +276,8 @@
      *
      * @return the status of eUICC OTA. If {@link #isEnabled()} is false or the eUICC is not ready,
      *     {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned.
+     * TODO(b/35851809): Make this a SystemApi.
      */
-    @SystemApi
     public int getOtaStatus() {
         if (!isEnabled()) {
             return EUICC_OTA_STATUS_UNAVAILABLE;
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 0f31821..303a068 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -195,14 +195,6 @@
     String[] getIsimPcscf(int subId);
 
     /**
-     * TODO: Deprecate and remove this interface. Superceded by getIccsimChallengeResponse.
-     * Returns the response of ISIM Authetification through RIL.
-     * @return the response of ISIM Authetification, or null if
-     *     the Authentification hasn't been successed or isn't present iphonesubinfo.
-     */
-    String getIsimChallengeResponse(String nonce);
-
-    /**
      * Returns the response of the SIM application on the UICC to authentication
      * challenge/response algorithm. The data string and challenge response are
      * Base64 encoded Strings.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dfb3c34..797805b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -680,6 +680,7 @@
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
      *
      * @param subId The subscription to use.
+     * @param callingPackage the name of the package making the call.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
      * @param p1 P1 value of the APDU command.
@@ -690,7 +691,7 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
-    String iccTransmitApduBasicChannel(int subId, int cla, int instruction,
+    String iccTransmitApduBasicChannel(int subId, String callingPackage, int cla, int instruction,
             int p1, int p2, int p3, String data);
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index f804cb0..cdee9e6 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -105,6 +105,8 @@
     int DEVICE_IN_USE = 64;                   /* Operation cannot be performed because the device
                                                  is currently in use */
     int ABORTED = 65;                         /* Operation aborted */
+    int INVALID_RESPONSE = 66;                /* Invalid response sent by vendor code */
+
     // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
     // reveal particular replacement for Generic failure
     int OEM_ERROR_1 = 501;
@@ -419,6 +421,8 @@
     int RIL_REQUEST_STOP_NETWORK_SCAN = 143;
     int RIL_REQUEST_GET_SLOT_STATUS = 144;
     int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 145;
+    int RIL_REQUEST_START_KEEPALIVE = 146;
+    int RIL_REQUEST_STOP_KEEPALIVE = 147;
 
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
 
@@ -474,4 +478,5 @@
     int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1048;
     int RIL_UNSOL_NETWORK_SCAN_RESULT = 1049;
     int RIL_UNSOL_ICC_SLOT_STATUS = 1050;
+    int RIL_UNSOL_KEEPALIVE_STATUS = 1051;
 }
diff --git a/test-base/Android.bp b/test-base/Android.bp
index a42dc5a..62fed61 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -64,27 +64,22 @@
     jarjar_rules: "jarjar-rules.txt",
 }
 
-// Build the legacy-android-test library
-// =====================================
-// This contains the android.test classes that were in Android API level 25,
-// including those from android.test.runner.
-// Also contains the com.android.internal.util.Predicate[s] classes.
+// Build the android.test.base-minus-junit library
+// ===============================================
+// This contains the android.test classes from android.test.base plus
+// the com.android.internal.util.Predicate[s] classes. This is only
+// intended for inclusion in the android.test.legacy static library and
+// must not be used elsewhere.
 java_library_static {
-    name: "legacy-android-test",
+    name: "android.test.base-minus-junit",
 
     srcs: [
         "src/android/**/*.java",
         "src/com/**/*.java",
     ],
 
-    static_libs: [
-        "android.test.runner-minus-junit",
-        "android.test.mock",
-    ],
-
-    no_framework_libs: true,
+    sdk_version: "current",
     libs: [
-        "framework",
         "junit",
     ],
 }
diff --git a/test-base/Android.mk b/test-base/Android.mk
index 25c3d76..8613854 100644
--- a/test-base/Android.mk
+++ b/test-base/Android.mk
@@ -16,8 +16,11 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# Generate the stub source files for legacy.test.stubs
-# ====================================================
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
+# Generate the stub source files for android.test.base.stubs
+# ==========================================================
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
@@ -107,6 +110,8 @@
 	@echo Copying removed.txt
 	$(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_BASE_REMOVED_API_FILE)
 
+endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
+
 ifeq ($(HOST_OS),linux)
 # Build the legacy-performance-test-hostdex library
 # =================================================
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
new file mode 100644
index 0000000..d2af8a9
--- /dev/null
+++ b/test-legacy/Android.bp
@@ -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.
+//
+
+// Build the legacy-android-test library
+// =====================================
+// This contains the android.test classes that were in Android API level 25,
+// including those from android.test.runner.
+// Also contains the com.android.internal.util.Predicate[s] classes.
+java_library_static {
+    name: "legacy-android-test",
+
+    static_libs: [
+        "android.test.base-minus-junit",
+        "android.test.runner-minus-junit",
+        "android.test.mock",
+    ],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+        "junit",
+    ],
+}
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
new file mode 100644
index 0000000..b8c5326
--- /dev/null
+++ b/test-legacy/Android.mk
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
+# Build the android.test.legacy library
+# =====================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.legacy
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_JAVA_LIBRARIES := junit
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android.test.base-minus-junit \
+    android.test.runner-minus-junit \
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Archive a copy of the classes.jar in SDK build.
+$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.legacy.jar)
+
+endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index cdc7756..706f636 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -16,6 +16,9 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
 # Generate the stub source files for android.test.runner.stubs
 # ============================================================
 include $(CLEAR_VARS)
@@ -69,9 +72,11 @@
     android.test.mock.stubs \
 
 LOCAL_SOURCE_FILES_ALL_GENERATED := true
+LOCAL_SDK_VERSION := current
 
 # Make sure to run droiddoc first to generate the stub source files.
 LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_runner_api_gen_stamp)
+android_test_runner_api_gen_stamp :=
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
@@ -109,3 +114,8 @@
 	$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) $(ANDROID_TEST_RUNNER_API_FILE)
 	@echo Copying removed.txt
 	$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
+
+endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
+
+# additionally, build unit tests in a separate .apk
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 24524e3..4907894 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -37,6 +37,7 @@
     libc++ \
     libcrypto \
     libcutils \
+    libdexfile \
     libframeworksnettestsjni \
     libhidl-gen-utils \
     libhidlbase \
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index 2ac73db..56a075b 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -99,8 +99,12 @@
 
     @After
     public void tearDown() throws Exception {
-        if (mSocket != null) mSocket.close();
-        if (mServerSocket != null) mServerSocket.close();
+        mNMService.shutdown();
+        // Once NetworkManagementService#shutdown() actually does something and shutdowns
+        // the underlying NativeDaemonConnector, the block below should be uncommented.
+        // if (mOutputStream != null) mOutputStream.close();
+        // if (mSocket != null) mSocket.close();
+        // if (mServerSocket != null) mServerSocket.close();
     }
 
     /**
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 9f2cb92..8359fe2 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -66,7 +66,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -175,7 +174,6 @@
     }
 
     @Test
-    @Ignore
     public void testDefaultNetworkEvents() throws Exception {
         final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
         final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
@@ -294,7 +292,6 @@
     }
 
     @Test
-    @Ignore
     public void testEndToEndLogging() throws Exception {
         // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
         IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
@@ -635,6 +632,7 @@
         when(nai.getCurrentScore()).thenReturn(score);
         nai.linkProperties = new LinkProperties();
         nai.networkCapabilities = new NetworkCapabilities();
+        nai.lastValidated = true;
         for (int t : BitUtils.unpackBits(transports)) {
             nai.networkCapabilities.addTransportType(t);
         }