Allow RemoteDevice to track the adb connect logs

The adb connect logs can be very useful to detect something
going wrong. Allow to collect them.

Test: unit tests
Bug: 114747032
Change-Id: I2dee63700a24b0bd5e894ca6e1f098086c1c6064
Merged-In: I2dee63700a24b0bd5e894ca6e1f098086c1c6064
diff --git a/src/com/android/tradefed/device/RemoteAndroidDevice.java b/src/com/android/tradefed/device/RemoteAndroidDevice.java
index d70739c..714b210 100644
--- a/src/com/android/tradefed/device/RemoteAndroidDevice.java
+++ b/src/com/android/tradefed/device/RemoteAndroidDevice.java
@@ -20,6 +20,12 @@
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.IRunUtil;
+import com.android.tradefed.util.RunUtil;
+
+import java.io.File;
+import java.io.IOException;
 
 /**
  * Implementation of a {@link ITestDevice} for a full stack android device connected via
@@ -37,6 +43,8 @@
     private static final String ADB_ALREADY_CONNECTED_TAG = "already";
     private static final String ADB_CONN_REFUSED = "Connection refused";
 
+    private File mAdbConnectLogs = null;
+
     /**
      * Creates a {@link RemoteAndroidDevice}.
      *
@@ -78,7 +86,9 @@
         // A remote nested device does not loose the ssh bridge when rebooted only adb connect is
         // required.
         InstanceType type = mOptions.getInstanceType();
-        if (InstanceType.CUTTLEFISH.equals(type) || InstanceType.REMOTE_NESTED_AVD.equals(type)) {
+        if (InstanceType.CUTTLEFISH.equals(type)
+                || InstanceType.REMOTE_NESTED_AVD.equals(type)
+                || InstanceType.EMULATOR.equals(type)) {
             adbTcpConnect(getHostName(), getPortNum());
             waitForAdbConnect(WAIT_FOR_ADB_CONNECT);
         }
@@ -145,12 +155,12 @@
      */
     public boolean adbTcpConnect(String host, String port) {
         for (int i = 0; i < MAX_RETRIES; i++) {
-            CommandResult result = getRunUtil().runTimedCmd(DEFAULT_SHORT_CMD_TIMEOUT, "adb",
-                    "connect", String.format("%s:%s", host, port));
+            CommandResult result = adbConnect(host, port);
             if (CommandStatus.SUCCESS.equals(result.getStatus()) &&
                 result.getStdout().contains(ADB_SUCCESS_CONNECT_TAG)) {
-                CLog.d("adb connect output: status: %s stdout: %s stderr: %s",
-                        result.getStatus(), result.getStdout(), result.getStderr());
+                CLog.d(
+                        "adb connect output: status: %s stdout: %s",
+                        result.getStatus(), result.getStdout());
 
                 // It is possible to get a positive result without it being connected because of
                 // the ssh bridge. Retrying to get confirmation, and expecting "already connected".
@@ -170,13 +180,10 @@
     }
 
     private boolean confirmAdbTcpConnect(String host, String port) {
-        CommandResult resultConfirmation =
-                getRunUtil().runTimedCmd(DEFAULT_SHORT_CMD_TIMEOUT, "adb", "connect",
-                String.format("%s:%s", host, port));
-        if (CommandStatus.SUCCESS.equals(resultConfirmation.getStatus()) &&
-                resultConfirmation.getStdout().contains(ADB_ALREADY_CONNECTED_TAG)) {
-            CLog.d("adb connect confirmed:\nstdout: %s\nsterr: %s",
-                    resultConfirmation.getStdout(), resultConfirmation.getStderr());
+        CommandResult resultConfirmation = adbConnect(host, port);
+        if (CommandStatus.SUCCESS.equals(resultConfirmation.getStatus())
+                && resultConfirmation.getStdout().contains(ADB_ALREADY_CONNECTED_TAG)) {
+            CLog.d("adb connect confirmed:\nstdout: %s\n", resultConfirmation.getStdout());
             return true;
         } else {
             CLog.d("adb connect confirmation failed:\nstatus:%s\nstdout: %s\nsterr: %s",
@@ -229,10 +236,42 @@
     }
 
     /**
+     * Give a receiver file where we can store all the adb connection logs for debugging purpose.
+     */
+    public void setAdbLogFile(File adbLogFile) {
+        mAdbConnectLogs = adbLogFile;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
     public String getMacAddress() {
         return null;
     }
+
+    /** Run adb connect. */
+    private CommandResult adbConnect(String host, String port) {
+        IRunUtil runUtil = getRunUtil();
+        if (mAdbConnectLogs != null) {
+            runUtil = new RunUtil();
+            runUtil.setEnvVariable("ADB_TRACE", "1");
+        }
+        CommandResult result =
+                runUtil.runTimedCmd(
+                        DEFAULT_SHORT_CMD_TIMEOUT,
+                        "adb",
+                        "connect",
+                        String.format("%s:%s", host, port));
+        if (mAdbConnectLogs != null) {
+            try {
+                FileUtil.writeToFile(result.getStderr(), mAdbConnectLogs, true);
+                FileUtil.writeToFile(
+                        "\n======= SEPARATOR OF ATTEMPTS =====\n", mAdbConnectLogs, true);
+            } catch (IOException e) {
+                CLog.e(e);
+            }
+        }
+        return result;
+    }
 }