Merge "Start internal support of multi device in ITestSuite" into oc-dev
diff --git a/prod-tests/src/com/android/performance/tests/AppTransitionTests.java b/prod-tests/src/com/android/performance/tests/AppTransitionTests.java
index ff310bd..10dab9d 100644
--- a/prod-tests/src/com/android/performance/tests/AppTransitionTests.java
+++ b/prod-tests/src/com/android/performance/tests/AppTransitionTests.java
@@ -31,6 +31,7 @@
 import com.android.tradefed.result.CollectingTestListener;
 import com.android.tradefed.result.FileInputStreamSource;
 import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.testtype.IDeviceTest;
 import com.android.tradefed.testtype.IRemoteTest;
@@ -42,6 +43,7 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -308,9 +310,14 @@
      * @param logReceiver
      */
     private void stopEventsLogs(LogcatReceiver logReceiver,String launchDesc) {
-        mListener.testLog(String.format("%s-%s", EVENTS_LOG, launchDesc),
-                LogDataType.TEXT, logReceiver.getLogcatData());
-        logReceiver.stop();
+        InputStreamSource logcatData = logReceiver.getLogcatData();
+        try {
+            mListener.testLog(
+                    String.format("%s-%s", EVENTS_LOG, launchDesc), LogDataType.TEXT, logcatData);
+        } finally {
+            StreamUtil.cancel(logcatData);
+            logReceiver.stop();
+        }
     }
 
     /**
@@ -384,12 +391,18 @@
      */
     private List<TransitionDelayItem> parseTransitionDelayInfo() {
         List<TransitionDelayItem> transitionDelayItems = null;
-        try {
-            transitionDelayItems = mEventsLogParser.parseTransitionDelayInfo(new BufferedReader(
-                    new InputStreamReader(mLaunchEventsLogs.getLogcatData().createInputStream())));
+        InputStreamSource logcatData = mLaunchEventsLogs.getLogcatData();
+        InputStream logcatStream = logcatData.createInputStream();
+        InputStreamReader streamReader = new InputStreamReader(logcatStream);
+        try (BufferedReader reader = new BufferedReader(streamReader)) {
+            transitionDelayItems = mEventsLogParser.parseTransitionDelayInfo(reader);
         } catch (IOException e) {
             CLog.e("Problem in parsing the transition delay items from events log");
             CLog.e(e);
+        } finally {
+            StreamUtil.cancel(logcatData);
+            StreamUtil.close(logcatStream);
+            StreamUtil.close(streamReader);
         }
         return transitionDelayItems;
     }
@@ -399,12 +412,18 @@
      */
     private List<LatencyItem> parseLatencyInfo() {
         List<LatencyItem> latencyItems = null;
-        try {
-            latencyItems = mEventsLogParser.parseLatencyInfo(new BufferedReader(
-                    new InputStreamReader(mLaunchEventsLogs.getLogcatData().createInputStream())));
+        InputStreamSource logcatData = mLaunchEventsLogs.getLogcatData();
+        InputStream logcatStream = logcatData.createInputStream();
+        InputStreamReader streamReader = new InputStreamReader(logcatStream);
+        try (BufferedReader reader = new BufferedReader(streamReader)) {
+            latencyItems = mEventsLogParser.parseLatencyInfo(reader);
         } catch (IOException e) {
             CLog.e("Problem in parsing the latency items from events log");
             CLog.e(e);
+        } finally {
+            StreamUtil.cancel(logcatData);
+            StreamUtil.close(logcatStream);
+            StreamUtil.close(streamReader);
         }
         return latencyItems;
     }
diff --git a/prod-tests/src/com/android/performance/tests/HermeticLaunchTest.java b/prod-tests/src/com/android/performance/tests/HermeticLaunchTest.java
index 2e158f9..57758a2 100644
--- a/prod-tests/src/com/android/performance/tests/HermeticLaunchTest.java
+++ b/prod-tests/src/com/android/performance/tests/HermeticLaunchTest.java
@@ -256,8 +256,8 @@
         Map<String, List<Integer>> amLaunchTimes = new HashMap<>();
         InputStreamSource input = mLogcat.getLogcatData();
         InputStream inputStream = input.createInputStream();
-        BufferedReader br = new BufferedReader(new InputStreamReader(
-                inputStream));
+        InputStreamReader streamReader = new InputStreamReader(inputStream);
+        BufferedReader br = new BufferedReader(streamReader);
         Map<Pattern, String> activityPatternMap = new HashMap<>();
         Matcher match = null;
         String line;
@@ -304,6 +304,11 @@
             }
         } catch (IOException io) {
             CLog.e(io);
+        } finally {
+            StreamUtil.cancel(input);
+            StreamUtil.close(inputStream);
+            StreamUtil.close(streamReader);
+            StreamUtil.close(br);
         }
 
         // Verify logcat data
diff --git a/src/com/android/tradefed/testtype/AndroidJUnitTest.java b/src/com/android/tradefed/testtype/AndroidJUnitTest.java
index d44f57c..48f5744 100644
--- a/src/com/android/tradefed/testtype/AndroidJUnitTest.java
+++ b/src/com/android/tradefed/testtype/AndroidJUnitTest.java
@@ -107,7 +107,7 @@
 
     @Option(
         name = "ajur-max-shard",
-        description = "The maximum number of shard we want to allow the test to shard into"
+        description = "The maximum number of shard we want to allow the AJUR test to shard into"
     )
     private Integer mMaxShard = null;
 
diff --git a/src/com/android/tradefed/testtype/InstrumentationTest.java b/src/com/android/tradefed/testtype/InstrumentationTest.java
index 206679e..fac7099 100644
--- a/src/com/android/tradefed/testtype/InstrumentationTest.java
+++ b/src/com/android/tradefed/testtype/InstrumentationTest.java
@@ -105,18 +105,26 @@
             description="Deprecated - Use \"shell-timeout\" or \"test-timeout\" instead.")
     private Integer mTimeout = null;
 
-    @Option(name = "shell-timeout",
-            description="The defined timeout (in milliseconds) is used as a maximum waiting time "
-                    + "when expecting the command output from the device. At any time, if the "
-                    + "shell command does not output anything for a period longer than defined "
-                    + "timeout the TF run terminates. For no timeout, set to 0.")
-    private long mShellTimeout = 10 * 60 * 1000;  // default to 10 minutes
+    @Option(
+        name = "shell-timeout",
+        description =
+                "The defined timeout (in milliseconds) is used as a maximum waiting time when "
+                        + "expecting the command output from the device. At any time, if the shell "
+                        + "command does not output anything for a period longer than defined "
+                        + "timeout the TF run terminates. For no timeout, set to 0.",
+        isTimeVal = true
+    )
+    private long mShellTimeout = 10 * 60 * 1000; // default to 10 minutes
 
-    @Option(name = "test-timeout",
-            description="Sets timeout (in milliseconds) that will be applied to each test. In the "
-                    + "event of a test timeout it will log the results and proceed with executing "
-                    + "the next test. For no timeout, set to 0.")
-    private int mTestTimeout = 5 * 60 * 1000;  // default to 5 minutes
+    @Option(
+        name = "test-timeout",
+        description =
+                "Sets timeout (in milliseconds) that will be applied to each test. In the event of "
+                        + "a test timeout, it will log the results and proceed with executing the "
+                        + "next test. For no timeout, set to 0.",
+        isTimeVal = true
+    )
+    private long mTestTimeout = 5 * 60 * 1000; // default to 5 minutes
 
     @Option(
         name = "max-timeout",
@@ -442,10 +450,8 @@
         return mShellTimeout;
     }
 
-    /**
-     * Get the test timeout in ms.
-     */
-    int getTestTimeout() {
+    /** Get the test timeout in ms. */
+    long getTestTimeout() {
         return mTestTimeout;
     }
 
diff --git a/src/com/android/tradefed/util/LogcatUpdaterEventParser.java b/src/com/android/tradefed/util/LogcatUpdaterEventParser.java
index 59c282c..6ccb9a0 100644
--- a/src/com/android/tradefed/util/LogcatUpdaterEventParser.java
+++ b/src/com/android/tradefed/util/LogcatUpdaterEventParser.java
@@ -20,8 +20,12 @@
 import com.android.loganalysis.item.MiscLogcatItem;
 import com.android.loganalysis.parser.LogcatParser;
 import com.android.tradefed.device.ILogcatReceiver;
+import com.android.tradefed.result.InputStreamSource;
+
 import java.io.BufferedReader;
+import java.io.Closeable;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.HashMap;
 import java.util.List;
@@ -31,17 +35,20 @@
 /**
  * Parse logcat input for system updater related events.
  *
- * In any system with A/B updates, the updater will log its progress to logcat. This class
- * interprets updater-related logcat messages and can inform listeners of events in both
- * a blocking and non-blocking fashion.
+ * <p>In any system with A/B updates, the updater will log its progress to logcat. This class
+ * interprets updater-related logcat messages and can inform listeners of events in both a blocking
+ * and non-blocking fashion.
  */
-public class LogcatUpdaterEventParser {
+public class LogcatUpdaterEventParser implements Closeable {
 
     private static final String ERR_REGEX = "onPayloadApplicationComplete\\(ErrorCode\\.*$";
     private Map<UpdaterEventTrigger, UpdaterEventType> mEventTriggerMap;
     private ILogcatReceiver mLogcatReceiver;
     private LogcatParser mInternalParser;
     private BufferedReader mStreamReader = null;
+    private InputStreamSource mCurrentLogcatData = null;
+    private InputStream mCurrentInputStream = null;
+    private InputStreamReader mCurrentStreamReader = null;
 
     private class UpdaterEventTrigger {
         public String mTag;
@@ -147,8 +154,10 @@
         registerEventTrigger("dex2oat", "dex2oat took ",
                 UpdaterEventType.D2O_COMPLETE);
 
-        mStreamReader = new BufferedReader(new InputStreamReader(
-                mLogcatReceiver.getLogcatData().createInputStream()));
+        mCurrentLogcatData = mLogcatReceiver.getLogcatData();
+        mCurrentInputStream = mCurrentLogcatData.createInputStream();
+        mCurrentStreamReader = new InputStreamReader(mCurrentInputStream);
+        mStreamReader = new BufferedReader(mCurrentStreamReader);
     }
 
     protected void registerEventTrigger(String tag, String msg, UpdaterEventType response) {
@@ -258,9 +267,19 @@
 
     private void refreshLogcatStream() throws IOException {
         mStreamReader.close();
+        StreamUtil.cancel(mCurrentLogcatData);
+        mCurrentLogcatData = mLogcatReceiver.getLogcatData();
+        mCurrentInputStream = mCurrentLogcatData.createInputStream();
+        mCurrentStreamReader = new InputStreamReader(mCurrentInputStream);
+        mStreamReader = new BufferedReader(mCurrentStreamReader);
+    }
 
-        mStreamReader = new BufferedReader(new InputStreamReader(
-                mLogcatReceiver.getLogcatData().createInputStream()));
+    @Override
+    public void close() throws IOException {
+        StreamUtil.close(mStreamReader);
+        StreamUtil.cancel(mCurrentLogcatData);
+        StreamUtil.close(mCurrentInputStream);
+        StreamUtil.close(mCurrentStreamReader);
     }
 }