Merge "Reveal the call trace of failed test cases which run in executors"
diff --git a/api/system-current.txt b/api/system-current.txt
index e2b6960..a2f83fd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3275,7 +3275,7 @@
     method @Nullable public String getDomains();
     method @Nullable public java.net.InetAddress getGateway();
     method @Nullable public android.net.LinkAddress getIpAddress();
-    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(String);
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
     method public void setDomains(@Nullable String);
     method public void setGateway(@Nullable java.net.InetAddress);
     method public void setIpAddress(@Nullable android.net.LinkAddress);
@@ -3495,7 +3495,7 @@
   }
 
   public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
-    method public static String getProbeName(int);
+    method @NonNull public static String getProbeName(int);
     field public static final int DNS_FAILURE = 0; // 0x0
     field public static final int DNS_SUCCESS = 1; // 0x1
     field public static final int PROBE_DNS = 0; // 0x0
diff --git a/api/test-current.txt b/api/test-current.txt
index 43bbca3..bb1a957 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -695,7 +695,7 @@
     method @Nullable public String getDomains();
     method @Nullable public java.net.InetAddress getGateway();
     method @Nullable public android.net.LinkAddress getIpAddress();
-    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(String);
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
     method public void setDomains(@Nullable String);
     method public void setGateway(@Nullable java.net.InetAddress);
     method public void setIpAddress(@Nullable android.net.LinkAddress);
@@ -914,7 +914,7 @@
   }
 
   public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
-    method public static String getProbeName(int);
+    method @NonNull public static String getProbeName(int);
     field public static final int DNS_FAILURE = 0; // 0x0
     field public static final int DNS_SUCCESS = 1; // 0x1
     field public static final int PROBE_DNS = 0; // 0x0
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 0728d83..14dbca0 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -134,7 +134,7 @@
      * route to the gateway as well. This configuration is arguably invalid, but it used to work
      * in K and earlier, and other OSes appear to accept it.
      */
-    public @NonNull List<RouteInfo> getRoutes(String iface) {
+    public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) {
         List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
         if (ipAddress != null) {
             RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 9eb87ef..ebca7e6 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -153,11 +153,14 @@
         return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
     }
 
-    public static String getProbeName(int probeType) {
+    /**
+     * Get the name of a probe specified by its probe type.
+     */
+    public static @NonNull String getProbeName(int probeType) {
         return Decoder.constants.get(probeType & 0xff, "PROBE_???");
     }
 
-    private static String getValidationStage(int probeType) {
+    private static @NonNull String getValidationStage(int probeType) {
         return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
     }
 
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 3f6ebf0..99c48cb 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -20,6 +20,7 @@
 juliatuttle@google.com
 kozynski@google.com
 kprevas@google.com
+lynhan@google.com
 madym@google.com
 mankoff@google.com
 nbenbernou@google.com
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fdd698f..4a4b625 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1888,7 +1888,7 @@
                 pw.println("mDataConnectionState=" + mDataConnectionState[i]);
                 pw.println("mCellLocation=" + mCellLocation[i]);
                 pw.println("mCellInfo=" + mCellInfo.get(i));
-                pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i).toString());
+                pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i));
                 pw.decreaseIndent();
             }
             pw.println("mCallNetworkType=" + mCallNetworkType);
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index 09badec..e570ef1e 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -23,7 +23,10 @@
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
 import static android.system.OsConstants.ENOPROTOOPT;
 import static android.system.OsConstants.FIONREAD;
+import static android.system.OsConstants.IPPROTO_IP;
 import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IP_TOS;
+import static android.system.OsConstants.IP_TTL;
 import static android.system.OsConstants.TIOCOUTQ;
 
 import android.annotation.NonNull;
@@ -193,6 +196,12 @@
             trw = NetworkUtils.getTcpRepairWindow(fd);
             tcpDetails.rcvWnd = trw.rcvWnd;
             tcpDetails.rcvWndScale = trw.rcvWndScale;
+            if (tcpDetails.srcAddress.length == 4 /* V4 address length */) {
+                // Query TOS.
+                tcpDetails.tos = Os.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
+                // Query TTL.
+                tcpDetails.ttl = Os.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
+            }
         } catch (ErrnoException e) {
             Log.e(TAG, "Exception reading TCP state from socket", e);
             if (e.errno == ENOPROTOOPT) {
diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
index d79ad1f..7f2f499 100644
--- a/services/net/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -38,7 +38,7 @@
 public class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
     private static final String TAG = "TcpKeepalivePacketData";
 
-     /** TCP sequence number. */
+    /** TCP sequence number. */
     public final int tcpSeq;
 
     /** TCP ACK number. */
@@ -50,6 +50,12 @@
     /** TCP RCV window scale. */
     public final int tcpWndScale;
 
+    /** IP TOS. */
+    public final int ipTos;
+
+    /** IP TTL. */
+    public final int ipTtl;
+
     private static final int IPV4_HEADER_LENGTH = 20;
     private static final int IPV6_HEADER_LENGTH = 40;
     private static final int TCP_HEADER_LENGTH = 20;
@@ -65,6 +71,8 @@
         // In the packet, the window is shifted right by the window scale.
         tcpWnd = tcpDetails.rcvWnd;
         tcpWndScale = tcpDetails.rcvWndScale;
+        ipTos = tcpDetails.tos;
+        ipTtl = tcpDetails.ttl;
     }
 
     /**
@@ -98,12 +106,11 @@
         final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH;
         ByteBuffer buf = ByteBuffer.allocate(length);
         buf.order(ByteOrder.BIG_ENDIAN);
-        // IP version and TOS. TODO : fetch this from getsockopt(SOL_IP, IP_TOS)
-        buf.putShort((short) 0x4500);
+        buf.put((byte) 0x45);                       // IP version and IHL
+        buf.put((byte) tcpDetails.tos);             // TOS
         buf.putShort((short) length);
-        buf.putInt(0x4000);                         // ID, flags=DF, offset
-        // TODO : fetch TTL from getsockopt(SOL_IP, IP_TTL)
-        buf.put((byte) 64);
+        buf.putInt(0x00004000);                     // ID, flags=DF, offset
+        buf.put((byte) tcpDetails.ttl);             // TTL
         buf.put((byte) OsConstants.IPPROTO_TCP);
         final int ipChecksumOffset = buf.position();
         buf.putShort((short) 0);                    // IP checksum
@@ -117,7 +124,9 @@
         buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale));   // Window size
         final int tcpChecksumOffset = buf.position();
         buf.putShort((short) 0);                    // TCP checksum
-        // URG is not set therefore the urgent pointer is not included
+        // URG is not set therefore the urgent pointer is zero.
+        buf.putShort((short) 0);                    // Urgent pointer
+
         buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
         buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum(
                 buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH));
@@ -138,13 +147,15 @@
                 && this.tcpAck == other.tcpAck
                 && this.tcpSeq == other.tcpSeq
                 && this.tcpWnd == other.tcpWnd
-                && this.tcpWndScale == other.tcpWndScale;
+                && this.tcpWndScale == other.tcpWndScale
+                && this.ipTos == other.ipTos
+                && this.ipTtl == other.ipTtl;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(srcAddress, dstAddress, srcPort, dstPort, tcpAck, tcpSeq, tcpWnd,
-                tcpWndScale);
+                tcpWndScale, ipTos, ipTtl);
     }
 
     /**
@@ -164,6 +175,8 @@
         out.writeInt(tcpAck);
         out.writeInt(tcpWnd);
         out.writeInt(tcpWndScale);
+        out.writeInt(ipTos);
+        out.writeInt(ipTtl);
     }
 
     private TcpKeepalivePacketData(Parcel in) {
@@ -172,6 +185,8 @@
         tcpAck = in.readInt();
         tcpWnd = in.readInt();
         tcpWndScale = in.readInt();
+        ipTos = in.readInt();
+        ipTtl = in.readInt();
     }
 
     /** Parcelable Creator. */
@@ -200,6 +215,8 @@
         parcel.ack = tcpAck;
         parcel.rcvWnd = tcpWnd;
         parcel.rcvWndScale = tcpWndScale;
+        parcel.tos = ipTos;
+        parcel.ttl = ipTtl;
         return parcel;
     }
 
@@ -212,6 +229,8 @@
                 + " seq: " + tcpSeq
                 + " ack: " + tcpAck
                 + " wnd: " + tcpWnd
-                + " wndScale: " + tcpWndScale;
+                + " wndScale: " + tcpWndScale
+                + " tos: " + ipTos
+                + " ttl: " + ipTtl;
     }
 }
diff --git a/services/net/java/android/net/TcpKeepalivePacketDataParcelable.aidl b/services/net/java/android/net/TcpKeepalivePacketDataParcelable.aidl
index d66b6ae..e25168d 100644
--- a/services/net/java/android/net/TcpKeepalivePacketDataParcelable.aidl
+++ b/services/net/java/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -25,4 +25,6 @@
     int ack;
     int rcvWnd;
     int rcvWndScale;
+    int tos;
+    int ttl;
 }
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index 372ffcd..e0b7227 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -48,6 +48,8 @@
         final int ack = 0x22222222;
         final int wnd = 8000;
         final int wndScale = 2;
+        final int tos = 4;
+        final int ttl = 64;
         TcpKeepalivePacketData resultData = null;
         final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
         testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
@@ -58,6 +60,8 @@
         testInfo.ack = ack;
         testInfo.rcvWnd = wnd;
         testInfo.rcvWndScale = wndScale;
+        testInfo.tos = tos;
+        testInfo.ttl = ttl;
         try {
             resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
         } catch (InvalidPacketException e) {
@@ -72,16 +76,21 @@
         assertEquals(testInfo.ack, resultData.tcpAck);
         assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
         assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
+        assertEquals(testInfo.tos, resultData.ipTos);
+        assertEquals(testInfo.ttl, resultData.ipTtl);
 
         TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR);
 
         final byte[] packet = resultData.getPacket();
-        // IP version and TOS.
-        ByteBuffer buf = ByteBuffer.wrap(packet);
-        assertEquals(buf.getShort(), 0x4500);
+        // IP version and IHL
+        assertEquals(packet[0], 0x45);
+        // TOS
+        assertEquals(packet[1], tos);
+        // TTL
+        assertEquals(packet[8], ttl);
         // Source IP address.
         byte[] ip = new byte[4];
-        buf = ByteBuffer.wrap(packet, 12, 4);
+        ByteBuffer buf = ByteBuffer.wrap(packet, 12, 4);
         buf.get(ip);
         assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
         // Destination IP address.
@@ -113,6 +122,8 @@
         final int ack = 0x22222222;
         final int wnd = 48_000;
         final int wndScale = 2;
+        final int tos = 4;
+        final int ttl = 64;
         final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
         testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
         testInfo.srcPort = srcPort;
@@ -122,6 +133,8 @@
         testInfo.ack = ack;
         testInfo.rcvWnd = wnd;
         testInfo.rcvWndScale = wndScale;
+        testInfo.tos = tos;
+        testInfo.ttl = ttl;
         TcpKeepalivePacketData testData = null;
         TcpKeepalivePacketDataParcelable resultData = null;
         testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
@@ -134,5 +147,7 @@
         assertEquals(resultData.ack, ack);
         assertEquals(resultData.rcvWnd, wnd);
         assertEquals(resultData.rcvWndScale, wndScale);
+        assertEquals(resultData.tos, tos);
+        assertEquals(resultData.ttl, ttl);
     }
 }
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index 0a9e964..f71be7b 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -19,7 +19,10 @@
 
     srcs: ["java/**/*.java"],
 
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "hamcrest-library",
+    ],
 
     libs: [
         "android.test.runner",
diff --git a/core/tests/coretests/src/com/android/server/wm/test/filters/CoreTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/CoreTestsFilter.java
similarity index 100%
rename from core/tests/coretests/src/com/android/server/wm/test/filters/CoreTestsFilter.java
rename to tests/utils/testutils/java/com/android/server/wm/test/filters/CoreTestsFilter.java
diff --git a/tests/utils/testutils/java/com/android/test/filters/SelectTest.java b/tests/utils/testutils/java/com/android/test/filters/SelectTest.java
index d0350af..d5b14c5 100644
--- a/tests/utils/testutils/java/com/android/test/filters/SelectTest.java
+++ b/tests/utils/testutils/java/com/android/test/filters/SelectTest.java
@@ -26,10 +26,12 @@
 import org.junit.runner.Description;
 import org.junit.runner.manipulation.Filter;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringJoiner;
@@ -131,7 +133,8 @@
      *
      * @param testArgs instrumentation test arguments.
      * @param selectTests array of class name to be selected to run.
-     * @return modified instrumentation test arguments.
+     * @return modified instrumentation test arguments. if {@link #OPTION_SELECT_TEST} argument
+     *      already exists in {@code testArgs}, those are prepended before {@code selectTests}.
      */
     @NonNull
     protected static Bundle addSelectTest(
@@ -139,7 +142,13 @@
         if (selectTests.length == 0) {
             return testArgs;
         }
-        testArgs.putString(OPTION_SELECT_TEST, join(Arrays.asList(selectTests)));
+        final List<String> selectedTestList = new ArrayList<>();
+        final String selectTestArgs = testArgs.getString(OPTION_SELECT_TEST);
+        if (selectTestArgs != null) {
+            selectedTestList.addAll(Arrays.asList(selectTestArgs.split(ARGUMENT_ITEM_SEPARATOR)));
+        }
+        selectedTestList.addAll(Arrays.asList(selectTests));
+        testArgs.putString(OPTION_SELECT_TEST, join(selectedTestList));
         return testArgs;
     }
 
diff --git a/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java b/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java
index 163b00a..df18985 100644
--- a/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java
+++ b/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java
@@ -19,7 +19,11 @@
 import static com.android.test.filters.SelectTest.OPTION_SELECT_TEST;
 import static com.android.test.filters.SelectTest.OPTION_SELECT_TEST_VERBOSE;
 
+import static org.hamcrest.collection.IsArrayContaining.hasItemInArray;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Bundle;
@@ -146,6 +150,45 @@
     }
 
     @Test
+    public void testAddSelectTest() {
+        final Bundle testArgs = new Bundle();
+
+        final Bundle modifiedTestArgs =
+                SelectTest.addSelectTest(testArgs, PACKAGE_A, CLASS_B3, METHOD_C5X);
+        assertSame(testArgs, modifiedTestArgs);
+
+        final String selectTestArgs = modifiedTestArgs.getString(OPTION_SELECT_TEST);
+        assertNotNull(selectTestArgs);
+        final String[] selectedTests = selectTestArgs.split(",");
+        assertThat(selectedTests, hasItemInArray(PACKAGE_A));
+        assertThat(selectedTests, hasItemInArray(CLASS_B3));
+        assertThat(selectedTests, hasItemInArray(METHOD_C5X));
+    }
+
+    @Test
+    public void testAddSelectTest_prependExistingTestArg() {
+        final Bundle testArgs = new Bundle();
+        testArgs.putString(OPTION_SELECT_TEST, new StringJoiner(",")
+                .add(PACKAGE_A)
+                .add(CLASS_B3)
+                .add(METHOD_C5X)
+                .toString());
+
+        final Bundle modifiedTestArgs =
+                SelectTest.addSelectTest(testArgs, PACKAGE_B, CLASS_B4, METHOD_C6Y);
+
+        final String selectTestArgs = modifiedTestArgs.getString(OPTION_SELECT_TEST);
+        assertNotNull(selectTestArgs);
+        final String[] selectedTests = selectTestArgs.split(",");
+        assertThat(selectedTests, hasItemInArray(PACKAGE_A));
+        assertThat(selectedTests, hasItemInArray(CLASS_B3));
+        assertThat(selectedTests, hasItemInArray(METHOD_C5X));
+        assertThat(selectedTests, hasItemInArray(PACKAGE_B));
+        assertThat(selectedTests, hasItemInArray(CLASS_B4));
+        assertThat(selectedTests, hasItemInArray(METHOD_C6Y));
+    }
+
+    @Test
     public void testFilterDisabled() {
         final Filter filter = mBuilder.build();
         acceptTests(filter, TEST_ALL);