Merge "Add a Telephony Debug Surface"
diff --git a/api/current.txt b/api/current.txt
index c386819..0f5f282 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -42083,7 +42083,7 @@
   }
 
   public final class AvailableNetworkInfo implements android.os.Parcelable {
-    ctor public AvailableNetworkInfo(int, int, java.util.ArrayList<java.lang.String>);
+    ctor public AvailableNetworkInfo(int, int, java.util.List<java.lang.String>);
     method public int describeContents();
     method public java.util.List<java.lang.String> getMccMncs();
     method public int getPriority();
@@ -43038,7 +43038,7 @@
     method public int getNetworkType();
     method public int getPhoneCount();
     method public int getPhoneType();
-    method public int getPreferredOpportunisticDataSubscription();
+    method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.ServiceState getServiceState();
     method @Nullable public android.telephony.SignalStrength getSignalStrength();
     method public int getSimCarrierId();
@@ -43606,9 +43606,9 @@
   }
 
   public interface GroupCallCallback {
-    method public void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
-    method public void onError(int, @Nullable String);
-    method public void onGroupCallStateChanged(int, int);
+    method public default void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
+    method public default void onError(int, @Nullable String);
+    method public default void onGroupCallStateChanged(int, int);
     field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
   }
 
@@ -43666,10 +43666,10 @@
   }
 
   public interface MbmsGroupCallSessionCallback {
-    method public void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
-    method public void onError(int, @Nullable String);
-    method public void onMiddlewareReady();
-    method public void onServiceInterfaceAvailable(@NonNull String, int);
+    method public default void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
+    method public default void onError(int, @Nullable String);
+    method public default void onMiddlewareReady();
+    method public default void onServiceInterfaceAvailable(@NonNull String, int);
   }
 
   public class MbmsStreamingSessionCallback {
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index b2288fc..87568e8 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -16,13 +16,15 @@
 
 package android.ddm;
 
+import android.os.Debug;
+import android.os.UserHandle;
+import android.util.Log;
+
+import dalvik.system.VMRuntime;
+
 import org.apache.harmony.dalvik.ddmc.Chunk;
 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
 import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
-import android.os.Debug;
-import android.os.UserHandle;
-import dalvik.system.VMRuntime;
 
 import java.nio.ByteBuffer;
 
@@ -35,6 +37,8 @@
     public static final int CHUNK_WAIT = type("WAIT");
     public static final int CHUNK_FEAT = type("FEAT");
 
+    private static final int CLIENT_PROTOCOL_VERSION = 1;
+
     private static DdmHandleHello mInstance = new DdmHandleHello();
 
     private static final String[] FRAMEWORK_FEATURES = new String[] {
@@ -145,7 +149,7 @@
                             + vmFlags.length() * 2
                             + 1);
         out.order(ChunkHandler.CHUNK_ORDER);
-        out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
+        out.putInt(CLIENT_PROTOCOL_VERSION);
         out.putInt(android.os.Process.myPid());
         out.putInt(vmIdent.length());
         out.putInt(appName.length());
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1240ef8..2ea23ec 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1816,7 +1816,7 @@
                 @Override
                 public void handleMessage(Message message) {
                     switch (message.what) {
-                        case NetworkAgent.EVENT_PACKET_KEEPALIVE:
+                        case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
                             int error = message.arg2;
                             try {
                                 if (error == SUCCESS) {
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 7436ad0..16555d8 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -16,22 +16,20 @@
 
 package android.net;
 
-import static android.net.ConnectivityManager.PacketKeepalive.*;
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
 
+import android.net.SocketKeepalive.InvalidPacketException;
 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.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 /**
  * Represents the actual packets that are sent by the
- * {@link android.net.ConnectivityManager.PacketKeepalive} API.
+ * {@link android.net.SocketKeepalive} API.
  *
  * @hide
  */
@@ -53,8 +51,8 @@
     /** 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;
+    protected static final int IPV4_HEADER_LENGTH = 20;
+    protected static final int UDP_HEADER_LENGTH = 8;
 
     // This should only be constructed via static factory methods, such as
     // nattKeepalivePacket
@@ -80,53 +78,10 @@
         }
     }
 
-    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 {
-
-        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;
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
new file mode 100644
index 0000000..dd2b108
--- /dev/null
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.SocketKeepalive.InvalidPacketException;
+import android.net.util.IpUtils;
+import android.system.OsConstants;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/** @hide */
+public final class NattKeepalivePacketData extends KeepalivePacketData {
+
+    // This should only be constructed via static factory methods, such as
+    // nattKeepalivePacket
+    private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
+            InetAddress dstAddress, int dstPort, byte[] data) throws
+            InvalidPacketException {
+        super(srcAddress, srcPort, dstAddress, dstPort, data);
+    }
+
+    /**
+     * Factory method to create Nat-T keepalive packet structure.
+     */
+    public static NattKeepalivePacketData nattKeepalivePacket(
+            InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
+            throws InvalidPacketException {
+
+        if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
+            throw new InvalidPacketException(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
+        }
+
+        if (dstPort != NattSocketKeepalive.NATT_PORT) {
+            throw new InvalidPacketException(SocketKeepalive.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 NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
+    }
+}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 99bfc14..dfb6d6f 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -18,7 +18,6 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.net.ConnectivityManager.PacketKeepalive;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -154,7 +153,7 @@
      *
      * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
      */
-    public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11;
+    public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11;
 
     /**
      * Requests that the specified keepalive packet be stopped.
@@ -163,20 +162,20 @@
      *
      * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
      */
-    public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12;
+    public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12;
 
     /**
-     * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive
-     * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous
+     * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive
+     * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous
      * error notification.
      *
-     * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to
-     * so that the app's PacketKeepaliveCallback methods can be called.
+     * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive},
+     * so that the app's {@link SocketKeepalive.Callback} methods can be called.
      *
      * arg1 = slot number of the keepalive
      * arg2 = error code
      */
-    public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
+    public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
 
     /**
      * Sent by ConnectivityService to inform this network transport of signal strength thresholds
@@ -288,12 +287,12 @@
                 saveAcceptUnvalidated(msg.arg1 != 0);
                 break;
             }
-            case CMD_START_PACKET_KEEPALIVE: {
-                startPacketKeepalive(msg);
+            case CMD_START_SOCKET_KEEPALIVE: {
+                startSocketKeepalive(msg);
                 break;
             }
-            case CMD_STOP_PACKET_KEEPALIVE: {
-                stopPacketKeepalive(msg);
+            case CMD_STOP_SOCKET_KEEPALIVE: {
+                stopSocketKeepalive(msg);
                 break;
             }
 
@@ -443,22 +442,22 @@
     /**
      * Requests that the network hardware send the specified packet at the specified interval.
      */
-    protected void startPacketKeepalive(Message msg) {
-        onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+    protected void startSocketKeepalive(Message msg) {
+        onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
     }
 
     /**
-     * Requests that the network hardware send the specified packet at the specified interval.
+     * Requests that the network hardware stops sending keepalive packets.
      */
-    protected void stopPacketKeepalive(Message msg) {
-        onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+    protected void stopSocketKeepalive(Message msg) {
+        onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
     }
 
     /**
-     * Called by the network when a packet keepalive event occurs.
+     * Called by the network when a socket keepalive event occurs.
      */
-    public void onPacketKeepaliveEvent(int slot, int reason) {
-        queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason);
+    public void onSocketKeepaliveEvent(int slot, int reason) {
+        queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, reason);
     }
 
     /**
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 97d50f4..a47c11af 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -109,6 +109,18 @@
      **/
     public static final int MAX_INTERVAL_SEC = 3600;
 
+    /**
+     * This packet is invalid.
+     * See the error code for details.
+     * @hide
+     */
+    public static class InvalidPacketException extends Exception {
+        public final int error;
+        public InvalidPacketException(int error) {
+            this.error = error;
+        }
+    }
+
     @NonNull final IConnectivityManager mService;
     @NonNull final Network mNetwork;
     @NonNull private final Executor mExecutor;
@@ -135,7 +147,7 @@
             @Override
             public void handleMessage(Message message) {
                 switch (message.what) {
-                    case NetworkAgent.EVENT_PACKET_KEEPALIVE:
+                    case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
                         final int status = message.arg2;
                         try {
                             if (status == SUCCESS) {
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 3a5b8a8..27f7e22 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -24,7 +24,8 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
-import android.os.IBinder.DeathRecipient;
+
+import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
@@ -127,13 +128,16 @@
             @NonNull BugreportParams params,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull BugreportCallback callback) {
-        // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
+        Preconditions.checkNotNull(bugreportFd);
+        Preconditions.checkNotNull(params);
+        Preconditions.checkNotNull(executor);
+        Preconditions.checkNotNull(callback);
         DumpstateListener dsListener = new DumpstateListener(executor, callback);
         try {
             // Note: mBinder can get callingUid from the binder transaction.
             mBinder.startBugreport(-1 /* callingUid */,
                     mContext.getOpPackageName(),
-                    (bugreportFd != null ? bugreportFd.getFileDescriptor() : new FileDescriptor()),
+                    bugreportFd.getFileDescriptor(),
                     (screenshotFd != null
                             ? screenshotFd.getFileDescriptor() : new FileDescriptor()),
                     params.getMode(), dsListener);
@@ -154,8 +158,7 @@
         }
     }
 
-    private final class DumpstateListener extends IDumpstateListener.Stub
-            implements DeathRecipient {
+    private final class DumpstateListener extends IDumpstateListener.Stub {
         private final Executor mExecutor;
         private final BugreportCallback mCallback;
 
@@ -165,11 +168,6 @@
         }
 
         @Override
-        public void binderDied() {
-            // TODO(b/111441001): implement
-        }
-
-        @Override
         public void onProgress(int progress) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 08e4903..b98d7a1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -60,7 +60,6 @@
 import android.database.ContentObserver;
 import android.net.ConnectionInfo;
 import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.PacketKeepalive;
 import android.net.IConnectivityManager;
 import android.net.IIpConnectivityMetrics;
 import android.net.INetd;
@@ -93,6 +92,7 @@
 import android.net.PrivateDnsConfigParcel;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
+import android.net.SocketKeepalive;
 import android.net.UidRange;
 import android.net.Uri;
 import android.net.VpnService;
@@ -2487,8 +2487,8 @@
                     nai.networkMisc.acceptUnvalidated = msg.arg1 == 1;
                     break;
                 }
-                case NetworkAgent.EVENT_PACKET_KEEPALIVE: {
-                    mKeepaliveTracker.handleEventPacketKeepalive(nai, msg);
+                case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
+                    mKeepaliveTracker.handleEventSocketKeepalive(nai, msg);
                     break;
                 }
             }
@@ -2853,8 +2853,7 @@
         // sending all CALLBACK_LOST messages (for requests, not listens) at the end
         // of rematchAllNetworksAndRequests
         notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
-        mKeepaliveTracker.handleStopAllKeepalives(nai,
-                ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+        mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
         for (String iface : nai.linkProperties.getAllInterfaceNames()) {
             // Disable wakeup packet monitoring for each interface.
             wakeupModifyInterface(iface, nai.networkCapabilities, false);
@@ -3446,12 +3445,12 @@
                     break;
                 }
                 // Sent by KeepaliveTracker to process an app request on the state machine thread.
-                case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
+                case NetworkAgent.CMD_START_SOCKET_KEEPALIVE: {
                     mKeepaliveTracker.handleStartKeepalive(msg);
                     break;
                 }
                 // Sent by KeepaliveTracker to process an app request on the state machine thread.
-                case NetworkAgent.CMD_STOP_PACKET_KEEPALIVE: {
+                case NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE: {
                     NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj);
                     int slot = msg.arg1;
                     int reason = msg.arg2;
@@ -6315,7 +6314,7 @@
         mKeepaliveTracker.startNattKeepalive(
                 getNetworkAgentInfoForNetwork(network),
                 intervalSeconds, messenger, binder,
-                srcAddr, srcPort, dstAddr, ConnectivityManager.PacketKeepalive.NATT_PORT);
+                srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT);
     }
 
     @Override
@@ -6332,7 +6331,7 @@
     @Override
     public void stopKeepalive(Network network, int slot) {
         mHandler.sendMessage(mHandler.obtainMessage(
-                NetworkAgent.CMD_STOP_PACKET_KEEPALIVE, slot, PacketKeepalive.SUCCESS, network));
+                NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, slot, SocketKeepalive.SUCCESS, network));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 1559ba8..07e28f9 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -16,26 +16,27 @@
 
 package com.android.server.connectivity;
 
-// TODO: Clean up imports and remove references of PacketKeepalive constants.
-
-import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_INTERVAL;
-import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS;
-import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK;
-import static android.net.ConnectivityManager.PacketKeepalive.MIN_INTERVAL;
-import static android.net.ConnectivityManager.PacketKeepalive.NATT_PORT;
-import static android.net.ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
-import static android.net.ConnectivityManager.PacketKeepalive.SUCCESS;
-import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
-import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
-import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
+import static android.net.NattSocketKeepalive.NATT_PORT;
+import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
+import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
+import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
+import static android.net.SocketKeepalive.BINDER_DIED;
+import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
+import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
+import static android.net.SocketKeepalive.NO_KEEPALIVE;
+import static android.net.SocketKeepalive.SUCCESS;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.net.ConnectivityManager.PacketKeepalive;
 import android.net.KeepalivePacketData;
+import android.net.NattKeepalivePacketData;
 import android.net.NetworkAgent;
 import android.net.NetworkUtils;
+import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.util.IpUtils;
 import android.os.Binder;
 import android.os.Handler;
@@ -60,7 +61,7 @@
 import java.util.HashMap;
 
 /**
- * Manages packet keepalive requests.
+ * Manages socket keepalive requests.
  *
  * Provides methods to stop and start keepalive requests, and keeps track of keepalives across all
  * networks. This class is tightly coupled to ConnectivityService. It is not thread-safe and its
@@ -83,13 +84,13 @@
     }
 
     /**
-     * Tracks information about a packet keepalive.
+     * Tracks information about a socket keepalive.
      *
      * All information about this keepalive is known at construction time except the slot number,
      * which is only returned when the hardware has successfully started the keepalive.
      */
     class KeepaliveInfo implements IBinder.DeathRecipient {
-        // Bookkeping data.
+        // Bookkeeping data.
         private final Messenger mMessenger;
         private final IBinder mBinder;
         private final int mUid;
@@ -98,7 +99,7 @@
 
         /** Keepalive slot. A small integer that identifies this keepalive among the ones handled
           * by this network. */
-        private int mSlot = PacketKeepalive.NO_KEEPALIVE;
+        private int mSlot = NO_KEEPALIVE;
 
         // Packet data.
         private final KeepalivePacketData mPacket;
@@ -144,7 +145,7 @@
                     .toString();
         }
 
-        /** Sends a message back to the application via its PacketKeepalive.Callback. */
+        /** Sends a message back to the application via its SocketKeepalive.Callback. */
         void notifyMessenger(int slot, int err) {
             KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err);
         }
@@ -153,8 +154,8 @@
         public void binderDied() {
             // Not called from ConnectivityService handler thread, so send it a message.
             mConnectivityServiceHandler.obtainMessage(
-                    NetworkAgent.CMD_STOP_PACKET_KEEPALIVE,
-                    mSlot, PacketKeepalive.BINDER_DIED, mNai.network).sendToTarget();
+                    NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE,
+                    mSlot, BINDER_DIED, mNai.network).sendToTarget();
         }
 
         void unlinkDeathRecipient() {
@@ -181,7 +182,10 @@
         }
 
         private int checkInterval() {
-            return mInterval >= MIN_INTERVAL ? SUCCESS : ERROR_INVALID_INTERVAL;
+            if (mInterval < MIN_INTERVAL_SEC || mInterval > MAX_INTERVAL_SEC) {
+                return ERROR_INVALID_INTERVAL;
+            }
+            return SUCCESS;
         }
 
         private int isValid() {
@@ -198,7 +202,7 @@
             int error = isValid();
             if (error == SUCCESS) {
                 Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
-                mNai.asyncChannel.sendMessage(CMD_START_PACKET_KEEPALIVE, slot, mInterval, mPacket);
+                mNai.asyncChannel.sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
             } else {
                 handleStopKeepalive(mNai, mSlot, error);
                 return;
@@ -214,7 +218,7 @@
             }
             if (isStarted) {
                 Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
-                mNai.asyncChannel.sendMessage(CMD_STOP_PACKET_KEEPALIVE, mSlot);
+                mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
             }
             // TODO: at the moment we unconditionally return failure here. In cases where the
             // NetworkAgent is alive, should we ask it to reply, so it can return failure?
@@ -225,7 +229,7 @@
 
     void notifyMessenger(Messenger messenger, int slot, int err) {
         Message message = Message.obtain();
-        message.what = EVENT_PACKET_KEEPALIVE;
+        message.what = EVENT_SOCKET_KEEPALIVE;
         message.arg1 = slot;
         message.arg2 = err;
         message.obj = null;
@@ -310,7 +314,7 @@
     }
 
     /** Handle keepalive events from lower layer. */
-    public void handleEventPacketKeepalive(@NonNull NetworkAgentInfo nai,
+    public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai,
             @NonNull Message message) {
         int slot = message.arg1;
         int reason = message.arg2;
@@ -369,16 +373,16 @@
 
         KeepalivePacketData packet;
         try {
-            packet = KeepalivePacketData.nattKeepalivePacket(
+            packet = NattKeepalivePacketData.nattKeepalivePacket(
                     srcAddress, srcPort, dstAddress, NATT_PORT);
-        } catch (KeepalivePacketData.InvalidPacketException e) {
+        } catch (InvalidPacketException e) {
             notifyMessenger(messenger, NO_KEEPALIVE, e.error);
             return;
         }
         KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds);
         Log.d(TAG, "Created keepalive: " + ki.toString());
         mConnectivityServiceHandler.obtainMessage(
-                NetworkAgent.CMD_START_PACKET_KEEPALIVE, ki).sendToTarget();
+                CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
     }
 
    /**
@@ -432,7 +436,7 @@
     }
 
     public void dump(IndentingPrintWriter pw) {
-        pw.println("Packet keepalives:");
+        pw.println("Socket keepalives:");
         pw.increaseIndent();
         for (NetworkAgentInfo nai : mKeepalives.keySet()) {
             pw.println(nai.name());
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index f736056..1dada92 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -17,8 +17,10 @@
 package com.android.server.os;
 
 import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.BugreportParams;
 import android.os.IDumpstate;
@@ -28,26 +30,29 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserManager;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
 import java.io.FileDescriptor;
 
 // TODO(b/111441001):
-// 1. Handle the case where another bugreport is in progress
-// 2. Make everything threadsafe
-// 3. Pass validation & other errors on listener
+// Intercept onFinished() & implement death recipient here and shutdown
+// bugreportd service.
 
 /**
  * Implementation of the service that provides a privileged API to capture and consume bugreports.
  *
- * <p>Delegates the actualy generation to a native implementation of {@code Dumpstate}.
+ * <p>Delegates the actualy generation to a native implementation of {@code IDumpstate}.
  */
 class BugreportManagerServiceImpl extends IDumpstate.Stub {
     private static final String TAG = "BugreportManagerService";
     private static final String BUGREPORT_SERVICE = "bugreportd";
     private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
 
-    private IDumpstate mDs = null;
+    private final Object mLock = new Object();
     private final Context mContext;
     private final AppOpsManager mAppOps;
 
@@ -59,43 +64,44 @@
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
     public IDumpstateToken setListener(String name, IDumpstateListener listener,
-            boolean getSectionDetails) throws RemoteException {
-        // TODO(b/111441001): Figure out if lazy setting of listener should be allowed
-        // and if so how to handle it.
+            boolean getSectionDetails) {
         throw new UnsupportedOperationException("setListener is not allowed on this service");
     }
 
-    // TODO(b/111441001): Intercept onFinished here in system server and shutdown
-    // the bugreportd service.
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
     public void startBugreport(int callingUidUnused, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
-            int bugreportMode, IDumpstateListener listener) throws RemoteException {
-        int callingUid = Binder.getCallingUid();
-        // TODO(b/111441001): validate all arguments & ensure primary user
-        validate(bugreportMode);
+            int bugreportMode, IDumpstateListener listener) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
+        Preconditions.checkNotNull(callingPackage);
+        Preconditions.checkNotNull(bugreportFd);
+        Preconditions.checkNotNull(listener);
+        validateBugreportMode(bugreportMode);
+        ensureIsPrimaryUser();
 
+        int callingUid = Binder.getCallingUid();
         mAppOps.checkPackage(callingUid, callingPackage);
-        mDs = getDumpstateService();
-        if (mDs == null) {
-            Slog.w(TAG, "Unable to get bugreport service");
-            // TODO(b/111441001): pass error on listener
-            return;
+
+        synchronized (mLock) {
+            startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
+                    bugreportMode, listener);
         }
-        mDs.startBugreport(callingUid, callingPackage,
-                bugreportFd, screenshotFd, bugreportMode, listener);
     }
 
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void cancelBugreport() throws RemoteException {
-        // This tells init to cancel bugreportd service.
-        SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
-        mDs = null;
+    public void cancelBugreport() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
+        // This tells init to cancel bugreportd service. Note that this is achieved through setting
+        // a system property which is not thread-safe. So the lock here offers thread-safety only
+        // among callers of the API.
+        synchronized (mLock) {
+            SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
+        }
     }
 
-    private boolean validate(@BugreportParams.BugreportMode int mode) {
+    private void validateBugreportMode(@BugreportParams.BugreportMode int mode) {
         if (mode != BugreportParams.BUGREPORT_MODE_FULL
                 && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
                 && mode != BugreportParams.BUGREPORT_MODE_REMOTE
@@ -103,9 +109,66 @@
                 && mode != BugreportParams.BUGREPORT_MODE_TELEPHONY
                 && mode != BugreportParams.BUGREPORT_MODE_WIFI) {
             Slog.w(TAG, "Unknown bugreport mode: " + mode);
-            return false;
+            throw new IllegalArgumentException("Unknown bugreport mode: " + mode);
         }
-        return true;
+    }
+
+    /**
+     * Validates that the current user is the primary user.
+     *
+     * @throws IllegalArgumentException if the current user is not the primary user
+     */
+    private void ensureIsPrimaryUser() {
+        UserInfo currentUser = null;
+        try {
+            currentUser = ActivityManager.getService().getCurrentUser();
+        } catch (RemoteException e) {
+            // Impossible to get RemoteException for an in-process call.
+        }
+
+        UserInfo primaryUser = UserManager.get(mContext).getPrimaryUser();
+        if (currentUser == null) {
+            logAndThrow("No current user. Only primary user is allowed to take bugreports.");
+        }
+        if (primaryUser == null) {
+            logAndThrow("No primary user. Only primary user is allowed to take bugreports.");
+        }
+        if (primaryUser.id != currentUser.id) {
+            logAndThrow("Current user not primary user. Only primary user"
+                    + " is allowed to take bugreports.");
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void startBugreportLocked(int callingUid, String callingPackage,
+            FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+            int bugreportMode, IDumpstateListener listener) {
+        if (isDumpstateBinderServiceRunningLocked()) {
+            Slog.w(TAG, "'dumpstate' is already running. Cannot start a new bugreport"
+                    + " while another one is currently in progress.");
+            // TODO(b/111441001): Use a new error code; add this to the documentation of the API.
+            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+            return;
+        }
+
+        IDumpstate ds = startAndGetDumpstateBinderServiceLocked();
+        if (ds == null) {
+            Slog.w(TAG, "Unable to get bugreport service");
+            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+            return;
+        }
+        try {
+            ds.startBugreport(callingUid, callingPackage,
+                    bugreportFd, screenshotFd, bugreportMode, listener);
+        } catch (RemoteException e) {
+            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean isDumpstateBinderServiceRunningLocked() {
+        IDumpstate ds = IDumpstate.Stub.asInterface(ServiceManager.getService("dumpstate"));
+        return ds != null;
     }
 
     /*
@@ -115,8 +178,12 @@
      * <p>Generating bugreports requires root privileges. To limit the footprint
      * of the root access, the actual generation in Dumpstate binary is accessed as a
      * oneshot service 'bugreport'.
+     *
+     * <p>Note that starting the service is achieved through setting a system property, which is
+     * not thread-safe. So the lock here offers thread-safety only among callers of the API.
      */
-    private IDumpstate getDumpstateService() {
+    @GuardedBy("mLock")
+    private IDumpstate startAndGetDumpstateBinderServiceLocked() {
         // Start bugreport service.
         SystemProperties.set("ctl.start", BUGREPORT_SERVICE);
 
@@ -145,4 +212,18 @@
         }
         return ds;
     }
+
+    private void reportError(IDumpstateListener listener, int errorCode) {
+        try {
+            listener.onError(errorCode);
+        } catch (RemoteException e) {
+            // Something went wrong in binder or app process. There's nothing to do here.
+            Slog.w(TAG, "onError() transaction threw RemoteException: " + e.getMessage());
+        }
+    }
+
+    private void logAndThrow(String message) {
+        Slog.w(TAG, message);
+        throw new IllegalArgumentException(message);
+    }
 }
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index 4da79b3..b407b2a 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -114,7 +114,7 @@
         in.readStringList(mMccMncs);
     }
 
-    public AvailableNetworkInfo(int subId, int priority, ArrayList<String> mccMncs) {
+    public AvailableNetworkInfo(int subId, int priority, List<String> mccMncs) {
         mSubId = subId;
         mPriority = priority;
         mMccMncs = new ArrayList<String>(mccMncs);
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index a4cce9c..0d4f09f 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -117,9 +117,9 @@
 
         CallAttributes s = (CallAttributes) o;
 
-        return (mPreciseCallState == s.mPreciseCallState
+        return (Objects.equals(mPreciseCallState, s.mPreciseCallState)
                 && mNetworkType == s.mNetworkType
-                && mCallQuality == s.mCallQuality);
+                && Objects.equals(mCallQuality, s.mCallQuality));
     }
 
     /**
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 59f3e1f..19e1931 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -287,11 +287,11 @@
             return false;
         }
         PreciseCallState other = (PreciseCallState) obj;
-        return (mRingingCallState != other.mRingingCallState &&
-            mForegroundCallState != other.mForegroundCallState &&
-            mBackgroundCallState != other.mBackgroundCallState &&
-            mDisconnectCause != other.mDisconnectCause &&
-            mPreciseDisconnectCause != other.mPreciseDisconnectCause);
+        return (mRingingCallState == other.mRingingCallState
+                && mForegroundCallState == other.mForegroundCallState
+                && mBackgroundCallState == other.mBackgroundCallState
+                && mDisconnectCause == other.mDisconnectCause
+                && mPreciseDisconnectCause == other.mPreciseDisconnectCause);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 455fa1e..148563a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9599,10 +9599,10 @@
      *
      * <p>
      * Requires Permission:
-     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isOpportunisticNetworkEnabled() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean isEnabled = false;
@@ -9983,12 +9983,17 @@
      * Get preferred opportunistic data subscription Id
      *
      * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}),
-     * or has permission {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
+     * or has either READ_PRIVILEGED_PHONE_STATE
+     * or {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission.
      * @return subId preferred opportunistic subscription id or
      * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} if there are no preferred
      * subscription id
      *
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            android.Manifest.permission.READ_PHONE_STATE
+    })
     public int getPreferredOpportunisticDataSubscription() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
index 77e36bb..603f4e6 100644
--- a/telephony/java/android/telephony/mbms/GroupCallCallback.java
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -57,7 +57,7 @@
      * @param errorCode The error code.
      * @param message A human-readable message generated by the middleware for debugging purposes.
      */
-    void onError(@GroupCallError int errorCode, @Nullable String message);
+    default void onError(@GroupCallError int errorCode, @Nullable String message) {}
 
     /**
      * Called to indicate this call has changed state.
@@ -65,8 +65,8 @@
      * See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
      * and {@link GroupCall#STATE_STALLED}.
      */
-    void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
-            @GroupCall.GroupCallStateChangeReason int reason);
+    default void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+            @GroupCall.GroupCallStateChangeReason int reason) {}
 
     /**
      * Broadcast Signal Strength updated.
@@ -78,5 +78,6 @@
      * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
      * for this call due to timing, geography or popularity.
      */
-    void onBroadcastSignalStrengthUpdated(@IntRange(from = -1, to = 4) int signalStrength);
+    default void onBroadcastSignalStrengthUpdated(
+            @IntRange(from = -1, to = 4) int signalStrength) {}
 }
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
index 04e7ba1..ac7e172 100644
--- a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -57,7 +57,7 @@
      * @param errorCode The error code.
      * @param message A human-readable message generated by the middleware for debugging purposes.
      */
-    void onError(@GroupCallError int errorCode, @Nullable String message);
+    default void onError(@GroupCallError int errorCode, @Nullable String message) {}
 
     /**
      * Indicates that the list of currently available SAIs has been updated. The app may use this
@@ -70,8 +70,8 @@
      * @param availableSais A list of lists of available SAIS in neighboring cells, where each list
      *                      contains the available SAIs in an individual cell.
      */
-    void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
-            @NonNull List<List<Integer>> availableSais);
+    default void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
+            @NonNull List<List<Integer>> availableSais) {}
 
     /**
      * Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
@@ -85,7 +85,7 @@
      * @param interfaceName The interface name for the data link.
      * @param index The index for the data link.
      */
-    void onServiceInterfaceAvailable(@NonNull String interfaceName, int index);
+    default void onServiceInterfaceAvailable(@NonNull String interfaceName, int index) {}
 
     /**
      * Called to indicate that the middleware has been initialized and is ready.
@@ -95,5 +95,5 @@
      * delivered via {@link #onError(int, String)} with error code
      * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
      */
-    void onMiddlewareReady();
+    default void onMiddlewareReady() {}
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ebfb69e..1548a76 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -194,6 +194,7 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -500,17 +501,17 @@
                 public void unwanted() { mDisconnected.open(); }
 
                 @Override
-                public void startPacketKeepalive(Message msg) {
+                public void startSocketKeepalive(Message msg) {
                     int slot = msg.arg1;
                     if (mExpectedKeepaliveSlot != null) {
                         assertEquals((int) mExpectedKeepaliveSlot, slot);
                     }
-                    onPacketKeepaliveEvent(slot, mStartKeepaliveError);
+                    onSocketKeepaliveEvent(slot, mStartKeepaliveError);
                 }
 
                 @Override
-                public void stopPacketKeepalive(Message msg) {
-                    onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
+                public void stopSocketKeepalive(Message msg) {
+                    onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
                 }
 
                 @Override
@@ -3791,10 +3792,17 @@
 
     @Test
     public void testNattSocketKeepalives() throws Exception {
+        final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
+        doTestNattSocketKeepalivesWithExecutor(executorSingleThread);
+        executorSingleThread.shutdown();
+
+        final Executor executorInline = (Runnable r) -> r.run();
+        doTestNattSocketKeepalivesWithExecutor(executorInline);
+    }
+
+    private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
         // TODO: 1. Move this outside of ConnectivityServiceTest.
-        //       2. Add helper function to test against newSingleThreadExecutor as well as inline
-        //          executor.
-        //       3. Make test to verify that Nat-T keepalive socket is created by IpSecService.
+        //       2. Make test to verify that Nat-T keepalive socket is created by IpSecService.
         final int srcPort = 12345;
         final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
         final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
@@ -3808,8 +3816,6 @@
         final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
         final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort);
 
-        final Executor executor = Executors.newSingleThreadExecutor();
-
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("wlan12");
         lp.addLinkAddress(new LinkAddress(myIPv6, 64));
@@ -3926,6 +3932,11 @@
 
         ka2.stop();
         callback2.expectStopped();
+
+        testSocket.close();
+        testSocket2.close();
+
+        mWiFiNetworkAgent.disconnect();
     }
 
     @Test