Merge "Snap for 7187421 from fccbc8f53a20edce32b35a9a12bce8224c238be7 to sdk-release" into sdk-release
diff --git a/clearcut_client/com/android/tradefed/clearcut/ClearcutClient.java b/clearcut_client/com/android/tradefed/clearcut/ClearcutClient.java
index 85adbbb..fe0344f 100644
--- a/clearcut_client/com/android/tradefed/clearcut/ClearcutClient.java
+++ b/clearcut_client/com/android/tradefed/clearcut/ClearcutClient.java
@@ -43,7 +43,9 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
+import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
 /** Client that allows reporting usage metrics to clearcut. */
@@ -111,7 +113,18 @@
         System.out.println(NoticeMessageUtil.getNoticeMessage(mUserType));
 
         // Executor to actually send the events.
-        mExecutor = new ScheduledThreadPoolExecutor(1);
+        mExecutor =
+                new ScheduledThreadPoolExecutor(
+                        1,
+                        new ThreadFactory() {
+                            @Override
+                            public Thread newThread(Runnable r) {
+                                Thread t = Executors.defaultThreadFactory().newThread(r);
+                                t.setDaemon(true);
+                                t.setName("clearcut-client-thread");
+                                return t;
+                            }
+                        });
         Runnable command =
                 new Runnable() {
                     @Override
diff --git a/src/com/android/tradefed/device/DeviceManager.java b/src/com/android/tradefed/device/DeviceManager.java
index 432dc41..e2b86a6 100644
--- a/src/com/android/tradefed/device/DeviceManager.java
+++ b/src/com/android/tradefed/device/DeviceManager.java
@@ -1048,6 +1048,7 @@
     @Override
     public synchronized void terminateDeviceMonitor() {
         mDvcMon.stop();
+        mDvcMonRunning = false;
     }
 
     /** {@inheritDoc} */
diff --git a/src/com/android/tradefed/device/DeviceMonitorMultiplexer.java b/src/com/android/tradefed/device/DeviceMonitorMultiplexer.java
index 7bf6ee0..4930ece 100644
--- a/src/com/android/tradefed/device/DeviceMonitorMultiplexer.java
+++ b/src/com/android/tradefed/device/DeviceMonitorMultiplexer.java
@@ -15,6 +15,8 @@
  */
 package com.android.tradefed.device;
 
+import com.android.tradefed.log.LogUtil.CLog;
+
 import java.util.LinkedList;
 import java.util.List;
 
@@ -75,7 +77,11 @@
     @Override
     public synchronized void stop() {
         for (IDeviceMonitor monitor : mDeviceMonitors) {
-            monitor.stop();
+            try {
+                monitor.stop();
+            } catch (RuntimeException e) {
+                CLog.e(e);
+            }
         }
     }
 }
diff --git a/src/com/android/tradefed/invoker/shard/token/CecControllerTokenProvider.java b/src/com/android/tradefed/invoker/shard/token/CecControllerTokenProvider.java
index 1c62bd0..b7ee9fc 100644
--- a/src/com/android/tradefed/invoker/shard/token/CecControllerTokenProvider.java
+++ b/src/com/android/tradefed/invoker/shard/token/CecControllerTokenProvider.java
@@ -36,6 +36,7 @@
 public class CecControllerTokenProvider implements ITokenProvider {
 
     private static final int TIMEOUT_MILLIS = 10000;
+    private List<String> devicesWithToken = new ArrayList<>();
 
     @Override
     public boolean hasToken(ITestDevice device, TokenProperty token) {
@@ -144,6 +145,12 @@
     boolean isCecAdapterConnected(ITestDevice device) throws DeviceNotAvailableException {
         List<String> launchCommand = new ArrayList();
         Process mCecClient;
+        String serialNo = device.getProperty("ro.serialno");
+
+        if (devicesWithToken.contains(serialNo)) {
+            /* This device has been checked and issued a token, don't check again. */
+            return true;
+        }
 
         launchCommand.add("cec-client");
 
@@ -166,7 +173,6 @@
                 launchCommand.add("x");
             }
 
-            String serialNo = device.getProperty("ro.serialno");
             String serialNoParam = convertStringToHexParams(serialNo);
             StringBuilder sendVendorCommand = new StringBuilder("cmd hdmi_control vendorcommand ");
             sendVendorCommand.append(" -t " + targetDevice);
@@ -184,6 +190,8 @@
 
                         device.executeShellCommand(sendVendorCommand.toString());
                         if (checkConsoleOutput(serialNoParam, TIMEOUT_MILLIS, inputConsole)) {
+                            /* Add to list of devices with token, it need not be checked again */
+                            devicesWithToken.add(serialNo);
                             return true;
                         }
                     } else {
diff --git a/src/com/android/tradefed/monitoring/LabResourceDeviceMonitor.java b/src/com/android/tradefed/monitoring/LabResourceDeviceMonitor.java
index 58c67dd..bbfd40e 100644
--- a/src/com/android/tradefed/monitoring/LabResourceDeviceMonitor.java
+++ b/src/com/android/tradefed/monitoring/LabResourceDeviceMonitor.java
@@ -51,6 +51,7 @@
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.ReadWriteLock;
@@ -148,7 +149,20 @@
                     // For example: adding docker run argument "-p 127.0.0.1:8887:8887".
                     ServerBuilder.forPort(DEFAULT_PORT)
                             .addService(this)
-                            .executor(Executors.newFixedThreadPool(DEFAULT_THREAD_COUNT))
+                            .executor(
+                                    Executors.newFixedThreadPool(
+                                            DEFAULT_THREAD_COUNT,
+                                            new ThreadFactory() {
+                                                @Override
+                                                public Thread newThread(Runnable r) {
+                                                    Thread t =
+                                                            Executors.defaultThreadFactory()
+                                                                    .newThread(r);
+                                                    t.setDaemon(true);
+                                                    t.setName("lab-resource-server");
+                                                    return t;
+                                                }
+                                            }))
                             .build();
         }
         try {
@@ -166,8 +180,28 @@
     void startExecutors() {
         mMetricizeExecutor =
                 MoreExecutors.getExitingScheduledExecutorService(
-                        new ScheduledThreadPoolExecutor(1));
-        mCollectionExecutor = Executors.newSingleThreadExecutor();
+                        new ScheduledThreadPoolExecutor(
+                                1,
+                                new ThreadFactory() {
+                                    @Override
+                                    public Thread newThread(Runnable r) {
+                                        Thread t = Executors.defaultThreadFactory().newThread(r);
+                                        t.setDaemon(true);
+                                        t.setName("lab-resource-metricize-executor");
+                                        return t;
+                                    }
+                                }));
+        mCollectionExecutor =
+                Executors.newSingleThreadExecutor(
+                        new ThreadFactory() {
+                            @Override
+                            public Thread newThread(Runnable r) {
+                                Thread t = Executors.defaultThreadFactory().newThread(r);
+                                t.setDaemon(true);
+                                t.setName("lab-resource-collection-executor");
+                                return t;
+                            }
+                        });
     }
 
     @VisibleForTesting
diff --git a/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollector.java b/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollector.java
index 65009a5..c010390 100644
--- a/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollector.java
+++ b/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollector.java
@@ -43,35 +43,57 @@
     FREQUENCY=5500
     AVG_RSSI=-77
     */
-    public static final String WIFI_METRIC_CMD = "wpa_cli -i wlan0 signal_poll";
-    public static final Pattern WIFI_METRIC_PATTERN =
+    public static final String WIFI_SIGNAL_CMD = "wpa_cli -i wlan0 signal_poll";
+    /*
+    wpa_cli status example response:
+    bssid=d8:47:32:23:26:36
+    freq=5785
+    ssid=foo
+    id=0
+    id_str=foo-bar
+    mode=station
+    wifi_generation=5
+    pairwise_cipher=CCMP
+    group_cipher=CCMP
+    key_mgmt=WPA2-PSK
+    wpa_state=COMPLETED
+    ip_address=192.168.0.244
+    address=16:cb:cf:39:91:4b
+    uuid=97dc605c-72a7-5546-9d15-d950a789da14
+    ieee80211ac=1
+    */
+    public static final String WIFI_STATUS_CMD = "wpa_cli -i wlan0 status";
+    public static final Pattern WIFI_SIGNAL_PATTERN =
             Pattern.compile(
                     "RSSI=(?<rssi>[\\-0-9]+)\\nLINKSPEED=(?<speed>[0-9]+)\\nNOISE="
                             + "(?<noise>[\\-0-9]+)\\n");
+    public static final Pattern WIFI_STATUS_PATTERN =
+            Pattern.compile("bssid=.*\\nfreq=.*\\nssid=" + "(?<ssid>.*)");
     public static final String RSSI = "rssi";
     public static final String SPEED = "speed";
     public static final String NOISE = "noise";
+    public static final String SSID = "ssid";
     private static final long CMD_TIMEOUT_MS = 500;
 
     /** Issues adb shell command and parses the WiFi metrics. */
     @Override
     public Collection<Resource> getDeviceResourceMetrics(
             DeviceDescriptor descriptor, IDeviceManager deviceManager) {
-        final Optional<String> response =
-                ResourceMetricUtil.GetCommandResponse(
-                        deviceManager, descriptor.getSerial(), WIFI_METRIC_CMD, CMD_TIMEOUT_MS);
-        if (!response.isPresent()) {
-            return List.of();
-        }
-        final Matcher matcher = WIFI_METRIC_PATTERN.matcher(response.get());
-        if (!matcher.find()) {
+        final Matcher signalMatcher =
+                getWifiCmdResponseMatcher(
+                        descriptor, deviceManager, WIFI_SIGNAL_CMD, WIFI_SIGNAL_PATTERN);
+        final Matcher statusMatcher =
+                getWifiCmdResponseMatcher(
+                        descriptor, deviceManager, WIFI_STATUS_CMD, WIFI_STATUS_PATTERN);
+        if (!signalMatcher.find() || !statusMatcher.find()) {
             return List.of();
         }
         Resource.Builder builder =
                 Resource.newBuilder()
+                        .setResourceInstance(statusMatcher.group(SSID))
                         .setResourceName(WIFI_METRIC_NAME)
                         .setTimestamp(ResourceMetricUtil.GetCurrentTimestamp());
-        float speed = ResourceMetricUtil.RoundedMetricValue(matcher.group(SPEED));
+        float speed = ResourceMetricUtil.RoundedMetricValue(signalMatcher.group(SPEED));
         if (speed == 0.f) {
             // If the speed is 0, the rest metrics are meaningless.
             return List.of(
@@ -82,13 +104,28 @@
                         Metric.newBuilder()
                                 .setTag(RSSI)
                                 .setValue(
-                                        ResourceMetricUtil.RoundedMetricValue(matcher.group(RSSI))))
+                                        ResourceMetricUtil.RoundedMetricValue(
+                                                signalMatcher.group(RSSI))))
                 .addMetric(
                         Metric.newBuilder()
                                 .setTag(NOISE)
                                 .setValue(
                                         ResourceMetricUtil.RoundedMetricValue(
-                                                matcher.group(NOISE))));
+                                                signalMatcher.group(NOISE))));
         return List.of(builder.build());
     }
+
+    private Matcher getWifiCmdResponseMatcher(
+            DeviceDescriptor descriptor,
+            IDeviceManager deviceManager,
+            String cmd,
+            Pattern responsePattern) {
+        final Optional<String> response =
+                ResourceMetricUtil.GetCommandResponse(
+                        deviceManager, descriptor.getSerial(), cmd, CMD_TIMEOUT_MS);
+        if (!response.isPresent()) {
+            return responsePattern.matcher("");
+        }
+        return responsePattern.matcher(response.get());
+    }
 }
diff --git a/tests/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollectorTest.java b/tests/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollectorTest.java
index 50b78b7..4beafc4 100644
--- a/tests/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollectorTest.java
+++ b/tests/src/com/android/tradefed/monitoring/collector/DeviceWifiResourceMetricCollectorTest.java
@@ -17,6 +17,7 @@
 package com.android.tradefed.monitoring.collector;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -37,9 +38,9 @@
 
 /** Tests for {@link DeviceWifiResourceMetricCollector}. */
 public class DeviceWifiResourceMetricCollectorTest {
-    private static final String MOCK_NO_WIFI_RESPONSE =
+    private static final String MOCK_NO_WIFI_SIGNAL_RESPONSE =
             String.join("\n", "RSSI=-9999", "LINKSPEED=0", "NOISE=-119", "FREQUENCY=2412");
-    private static final String MOCK_WIFI_RESPONSE =
+    private static final String MOCK_WIFI_SIGNAL_RESPONSE =
             String.join(
                     "\n",
                     "RSSI=-76",
@@ -47,6 +48,24 @@
                     "NOISE=-189",
                     "FREQUENCY=2412",
                     "AVG_RSSI=-77");
+    private static final String MOCK_WIFI_STATUS_RESPONSE =
+            String.join(
+                    "\n",
+                    "bssid=d8:47:32:23:26:36",
+                    "freq=5785",
+                    "ssid=foo-bar",
+                    "id=0",
+                    "id_str=foo-bar",
+                    "mode=station",
+                    "wifi_generation=5",
+                    "pairwise_cipher=CCMP",
+                    "group_cipher=CCMP",
+                    "key_mgmt=WPA2-PSK",
+                    "wpa_state=COMPLETED",
+                    "ip_address=192.168.0.244",
+                    "address=16:cb:cf:39:91:4b",
+                    "uuid=97dc605c-72a7-5546-9d15-d950a789da14",
+                    "ieee80211ac=1");
     @Mock private IDeviceManager mDeviceManager;
     @Rule public MockitoRule rule = MockitoJUnit.rule();
     private final DeviceWifiResourceMetricCollector mCollector =
@@ -59,12 +78,11 @@
                 }
             };
 
-    /** Tests getting metrics when no wifi connection. */
-    @Test
-    public void testGetDeviceResourceMetrics_noWifi() {
+    @Before
+    public void setup() {
         when(mDeviceManager.executeCmdOnAvailableDevice(
                         "foo",
-                        DeviceWifiResourceMetricCollector.WIFI_METRIC_CMD,
+                        DeviceWifiResourceMetricCollector.WIFI_STATUS_CMD,
                         500,
                         TimeUnit.MILLISECONDS))
                 .thenReturn(
@@ -76,7 +94,29 @@
 
                             @Override
                             public String getStdout() {
-                                return MOCK_NO_WIFI_RESPONSE;
+                                return MOCK_WIFI_STATUS_RESPONSE;
+                            }
+                        });
+    }
+
+    /** Tests getting metrics when no wifi connection. */
+    @Test
+    public void testGetDeviceResourceMetrics_noWifi() {
+        when(mDeviceManager.executeCmdOnAvailableDevice(
+                        "foo",
+                        DeviceWifiResourceMetricCollector.WIFI_SIGNAL_CMD,
+                        500,
+                        TimeUnit.MILLISECONDS))
+                .thenReturn(
+                        new CommandResult() {
+                            @Override
+                            public CommandStatus getStatus() {
+                                return CommandStatus.SUCCESS;
+                            }
+
+                            @Override
+                            public String getStdout() {
+                                return MOCK_NO_WIFI_SIGNAL_RESPONSE;
                             }
                         });
         Collection<Resource> resources =
@@ -84,6 +124,7 @@
         Assert.assertEquals(1, resources.size());
         Resource resource = resources.iterator().next();
         Assert.assertEquals("wifi", resource.getResourceName());
+        Assert.assertEquals("foo-bar", resource.getResourceInstance());
         Assert.assertEquals(1, resource.getMetricCount());
         Assert.assertEquals("speed", resource.getMetric(0).getTag());
         Assert.assertEquals(0.f, resource.getMetric(0).getValue(), 0.f);
@@ -94,7 +135,7 @@
     public void testGetDeviceResourceMetrics_success() {
         when(mDeviceManager.executeCmdOnAvailableDevice(
                         "foo",
-                        DeviceWifiResourceMetricCollector.WIFI_METRIC_CMD,
+                        DeviceWifiResourceMetricCollector.WIFI_SIGNAL_CMD,
                         500,
                         TimeUnit.MILLISECONDS))
                 .thenReturn(
@@ -106,7 +147,7 @@
 
                             @Override
                             public String getStdout() {
-                                return MOCK_WIFI_RESPONSE;
+                                return MOCK_WIFI_SIGNAL_RESPONSE;
                             }
                         });
         Collection<Resource> resources =
@@ -114,6 +155,7 @@
         Assert.assertEquals(1, resources.size());
         Resource resource = resources.iterator().next();
         Assert.assertEquals("wifi", resource.getResourceName());
+        Assert.assertEquals("foo-bar", resource.getResourceInstance());
         Assert.assertEquals(165.f, resource.getMetric(0).getValue(), 0.f);
         Assert.assertEquals(-76.f, resource.getMetric(1).getValue(), 0.f);
         Assert.assertEquals(-189.f, resource.getMetric(2).getValue(), 0.f);
diff --git a/tests/src/com/android/tradefed/presubmit/DeviceTestsConfigValidation.java b/tests/src/com/android/tradefed/presubmit/DeviceTestsConfigValidation.java
index fd67799..51daff4 100644
--- a/tests/src/com/android/tradefed/presubmit/DeviceTestsConfigValidation.java
+++ b/tests/src/com/android/tradefed/presubmit/DeviceTestsConfigValidation.java
@@ -22,6 +22,7 @@
 import com.android.tradefed.config.ConfigurationUtil;
 import com.android.tradefed.config.IConfiguration;
 import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.config.Option;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.suite.ValidateSuiteConfigHelper;
@@ -46,6 +47,11 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class DeviceTestsConfigValidation implements IBuildReceiver {
 
+    @Option(
+            name = "config-extension",
+            description = "The expected extension from configuration to check.")
+    private String mConfigExtension = "config";
+
     private IBuildInfo mBuild;
 
     @Override
@@ -64,10 +70,10 @@
         IDeviceBuildInfo deviceBuildInfo = (IDeviceBuildInfo) mBuild;
         File testsDir = deviceBuildInfo.getTestsDir();
         List<File> extraTestCasesDirs = Arrays.asList(testsDir);
-        // Only load the .config as .xml might be data in device-tests.zip case.
+        String configPattern = ".*\\." + mConfigExtension + "$";
         configs.addAll(
                 ConfigurationUtil.getConfigNamesFileFromDirs(
-                        null, extraTestCasesDirs, Arrays.asList(".*\\.config$")));
+                        null, extraTestCasesDirs, Arrays.asList(configPattern)));
         for (File config : configs) {
             try {
                 IConfiguration c =