• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tradefed.device.cloud;
17 
18 import com.android.tradefed.device.TestDeviceOptions;
19 import com.android.tradefed.device.TestDeviceOptions.InstanceType;
20 import com.android.tradefed.log.ITestLogger;
21 import com.android.tradefed.log.LogUtil.CLog;
22 import com.android.tradefed.result.ByteArrayInputStreamSource;
23 import com.android.tradefed.result.FileInputStreamSource;
24 import com.android.tradefed.result.InputStreamSource;
25 import com.android.tradefed.result.LogDataType;
26 import com.android.tradefed.util.CommandResult;
27 import com.android.tradefed.util.CommandStatus;
28 import com.android.tradefed.util.FileUtil;
29 import com.android.tradefed.util.IRunUtil;
30 import com.android.tradefed.util.MultiMap;
31 import com.android.tradefed.util.ZipUtil;
32 import com.android.tradefed.util.avd.HostOrchestratorUtil;
33 
34 import com.google.common.base.Strings;
35 
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 
42 /**
43  * This utility allows to avoid code duplication across the different remote device representation
44  * for the remote log fetching logic of common files.
45  */
46 public class CommonLogRemoteFileUtil {
47 
48     /** The directory where to find debug logs for a nested remote instance. */
49     public static final String NESTED_REMOTE_LOG_DIR = "/home/%s/cuttlefish_runtime/";
50     /** The directory where to find debug logs for an emulator instance. */
51     public static final String EMULATOR_REMOTE_LOG_DIR = "/home/%s/log/";
52     public static final String TOMBSTONES_ZIP_NAME = "tombstones-zip";
53 
54     /** The directory where to find emulator logs from Oxygen service. */
55     public static final String OXYGEN_EMULATOR_LOG_DIR = "/tmp/device_launcher/";
56     /** The directory where to find Oxygen device logs. */
57     public static final String OXYGEN_CUTTLEFISH_LOG_DIR =
58             "/tmp/cfbase/3/cuttlefish/instances/cvd-1/logs/";
59 
60     /** cvd fetch log */
61     public static final String OXYGEN_CUTTLEFISH_FETCH_LOG = "/tmp/cfbase/3/fetch.log";
62 
63     /**
64      * The directory where to find Oxygen device runtime logs. Only use this if
65      * OXYGEN_CUTTLEFISH_LOG_DIR is not found.
66      */
67     public static final String OXYGEN_RUNTIME_LOG_DIR = "/tmp/cfbase/3/cuttlefish_runtime/";
68 
69     /** The directory where to find goldfish logs from Oxygen service. */
70     public static final String OXYGEN_GOLDFISH_LOG_DIR = "/tmp/android_platform_gf*/logs/";
71 
72     /** The directory where to find netsim logs from Oxygen service. */
73     public static final String NETSIM_LOG_DIR = "/tmp/android/netsimd/";
74 
75     public static final String NETSIM_USER_LOG_DIR = "/tmp/android-%s/netsimd/";
76 
77     public static final List<KnownLogFileEntry> NETSIM_LOG_FILES = new ArrayList<>();
78 
79     public static final List<KnownLogFileEntry> OXYGEN_LOG_FILES = new ArrayList<>();
80     /** For older version of cuttlefish, log files only exists in cuttlefish_runtime directory. */
81     public static final List<KnownLogFileEntry> OXYGEN_LOG_FILES_FALLBACK = new ArrayList<>();
82 
83     public static final MultiMap<InstanceType, KnownLogFileEntry> KNOWN_FILES_TO_FETCH =
84             new MultiMap<>();
85 
86     static {
87         // Cuttlefish known files to collect
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( "/home/%s/fetcher_config.json", null, LogDataType.CUTTLEFISH_LOG))88         KNOWN_FILES_TO_FETCH.put(
89                 InstanceType.CUTTLEFISH,
90                 new KnownLogFileEntry(
91                         "/home/%s/fetcher_config.json", null, LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( NESTED_REMOTE_LOG_DIR + "kernel.log", null, LogDataType.CUTTLEFISH_LOG))92         KNOWN_FILES_TO_FETCH.put(
93                 InstanceType.CUTTLEFISH,
94                 new KnownLogFileEntry(
95                         NESTED_REMOTE_LOG_DIR + "kernel.log", null, LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( NESTED_REMOTE_LOG_DIR + "logcat", "full_gce_logcat", LogDataType.LOGCAT))96         KNOWN_FILES_TO_FETCH.put(
97                 InstanceType.CUTTLEFISH,
98                 new KnownLogFileEntry(
99                         NESTED_REMOTE_LOG_DIR + "logcat", "full_gce_logcat", LogDataType.LOGCAT));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( NESTED_REMOTE_LOG_DIR + "cuttlefish_config.json", null, LogDataType.CUTTLEFISH_LOG))100         KNOWN_FILES_TO_FETCH.put(
101                 InstanceType.CUTTLEFISH,
102                 new KnownLogFileEntry(
103                         NESTED_REMOTE_LOG_DIR + "cuttlefish_config.json",
104                         null,
105                         LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( NESTED_REMOTE_LOG_DIR + "launcher.log", "cuttlefish_launcher.log", LogDataType.CUTTLEFISH_LOG))106         KNOWN_FILES_TO_FETCH.put(
107                 InstanceType.CUTTLEFISH,
108                 new KnownLogFileEntry(
109                         NESTED_REMOTE_LOG_DIR + "launcher.log",
110                         "cuttlefish_launcher.log",
111                         LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( NESTED_REMOTE_LOG_DIR + "crosvm_openwrt_boot.log", null, LogDataType.CUTTLEFISH_LOG))112         KNOWN_FILES_TO_FETCH.put(
113                 InstanceType.CUTTLEFISH,
114                 new KnownLogFileEntry(
115                         NESTED_REMOTE_LOG_DIR + "crosvm_openwrt_boot.log",
116                         null,
117                         LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( NESTED_REMOTE_LOG_DIR + "crosvm_openwrt.log", null, LogDataType.CUTTLEFISH_LOG))118         KNOWN_FILES_TO_FETCH.put(
119                 InstanceType.CUTTLEFISH,
120                 new KnownLogFileEntry(
121                         NESTED_REMOTE_LOG_DIR + "crosvm_openwrt.log",
122                         null,
123                         LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.CUTTLEFISH, new KnownLogFileEntry( "/var/log/kern.log", "host_kernel.log", LogDataType.CUTTLEFISH_LOG))124         KNOWN_FILES_TO_FETCH.put(
125                 InstanceType.CUTTLEFISH,
126                 new KnownLogFileEntry(
127                         "/var/log/kern.log", "host_kernel.log", LogDataType.CUTTLEFISH_LOG));
128         // Emulator known files to collect
KNOWN_FILES_TO_FETCH.put( InstanceType.EMULATOR, new KnownLogFileEntry( EMULATOR_REMOTE_LOG_DIR + "logcat.log", "full_gce_emulator_logcat", LogDataType.LOGCAT))129         KNOWN_FILES_TO_FETCH.put(
130                 InstanceType.EMULATOR,
131                 new KnownLogFileEntry(
132                         EMULATOR_REMOTE_LOG_DIR + "logcat.log",
133                         "full_gce_emulator_logcat",
134                         LogDataType.LOGCAT));
KNOWN_FILES_TO_FETCH.put( InstanceType.EMULATOR, new KnownLogFileEntry( EMULATOR_REMOTE_LOG_DIR + "adb.log", null, LogDataType.CUTTLEFISH_LOG))135         KNOWN_FILES_TO_FETCH.put(
136                 InstanceType.EMULATOR,
137                 new KnownLogFileEntry(
138                         EMULATOR_REMOTE_LOG_DIR + "adb.log", null, LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.EMULATOR, new KnownLogFileEntry( EMULATOR_REMOTE_LOG_DIR + "kernel.log", null, LogDataType.CUTTLEFISH_LOG))139         KNOWN_FILES_TO_FETCH.put(
140                 InstanceType.EMULATOR,
141                 new KnownLogFileEntry(
142                         EMULATOR_REMOTE_LOG_DIR + "kernel.log", null, LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.EMULATOR, new KnownLogFileEntry("/var/log/daemon.log", null, LogDataType.CUTTLEFISH_LOG))143         KNOWN_FILES_TO_FETCH.put(
144                 InstanceType.EMULATOR,
145                 new KnownLogFileEntry("/var/log/daemon.log", null, LogDataType.CUTTLEFISH_LOG));
KNOWN_FILES_TO_FETCH.put( InstanceType.EMULATOR, new KnownLogFileEntry( "/var/log/kern.log", "host_kernel.log", LogDataType.CUTTLEFISH_LOG))146         KNOWN_FILES_TO_FETCH.put(
147                 InstanceType.EMULATOR,
148                 new KnownLogFileEntry(
149                         "/var/log/kern.log", "host_kernel.log", LogDataType.CUTTLEFISH_LOG));
150 
OXYGEN_LOG_FILES.add(new KnownLogFileEntry(OXYGEN_EMULATOR_LOG_DIR, null, LogDataType.DIR))151         OXYGEN_LOG_FILES.add(new KnownLogFileEntry(OXYGEN_EMULATOR_LOG_DIR, null, LogDataType.DIR));
OXYGEN_LOG_FILES.add( new KnownLogFileEntry(OXYGEN_CUTTLEFISH_LOG_DIR, null, LogDataType.DIR))152         OXYGEN_LOG_FILES.add(
153                 new KnownLogFileEntry(OXYGEN_CUTTLEFISH_LOG_DIR, null, LogDataType.DIR));
OXYGEN_LOG_FILES.add( new KnownLogFileEntry( OXYGEN_CUTTLEFISH_FETCH_LOG, null, LogDataType.CUTTLEFISH_LOG))154         OXYGEN_LOG_FILES.add(
155                 new KnownLogFileEntry(
156                         OXYGEN_CUTTLEFISH_FETCH_LOG, null, LogDataType.CUTTLEFISH_LOG));
OXYGEN_LOG_FILES.add(new KnownLogFileEntry(OXYGEN_GOLDFISH_LOG_DIR, null, LogDataType.DIR))157         OXYGEN_LOG_FILES.add(new KnownLogFileEntry(OXYGEN_GOLDFISH_LOG_DIR, null, LogDataType.DIR));
NETSIM_LOG_FILES.add(new KnownLogFileEntry(NETSIM_LOG_DIR, null, LogDataType.DIR))158         NETSIM_LOG_FILES.add(new KnownLogFileEntry(NETSIM_LOG_DIR, null, LogDataType.DIR));
NETSIM_LOG_FILES.add(new KnownLogFileEntry(NETSIM_USER_LOG_DIR, null, LogDataType.DIR))159         NETSIM_LOG_FILES.add(new KnownLogFileEntry(NETSIM_USER_LOG_DIR, null, LogDataType.DIR));
OXYGEN_LOG_FILES_FALLBACK.add( new KnownLogFileEntry( OXYGEN_RUNTIME_LOG_DIR + "launcher.log", null, LogDataType.CUTTLEFISH_LOG))160         OXYGEN_LOG_FILES_FALLBACK.add(
161                 new KnownLogFileEntry(
162                         OXYGEN_RUNTIME_LOG_DIR + "launcher.log", null, LogDataType.CUTTLEFISH_LOG));
OXYGEN_LOG_FILES_FALLBACK.add( new KnownLogFileEntry( OXYGEN_RUNTIME_LOG_DIR + "crosvm_openwrt_boot.log", null, LogDataType.CUTTLEFISH_LOG))163         OXYGEN_LOG_FILES_FALLBACK.add(
164                 new KnownLogFileEntry(
165                         OXYGEN_RUNTIME_LOG_DIR + "crosvm_openwrt_boot.log",
166                         null,
167                         LogDataType.CUTTLEFISH_LOG));
OXYGEN_LOG_FILES_FALLBACK.add( new KnownLogFileEntry( OXYGEN_RUNTIME_LOG_DIR + "crosvm_openwrt.log", null, LogDataType.CUTTLEFISH_LOG))168         OXYGEN_LOG_FILES_FALLBACK.add(
169                 new KnownLogFileEntry(
170                         OXYGEN_RUNTIME_LOG_DIR + "crosvm_openwrt.log",
171                         null,
172                         LogDataType.CUTTLEFISH_LOG));
OXYGEN_LOG_FILES_FALLBACK.add( new KnownLogFileEntry( OXYGEN_RUNTIME_LOG_DIR + "vdl_stdout.txt", null, LogDataType.CUTTLEFISH_LOG))173         OXYGEN_LOG_FILES_FALLBACK.add(
174                 new KnownLogFileEntry(
175                         OXYGEN_RUNTIME_LOG_DIR + "vdl_stdout.txt",
176                         null,
177                         LogDataType.CUTTLEFISH_LOG));
OXYGEN_LOG_FILES_FALLBACK.add( new KnownLogFileEntry( OXYGEN_RUNTIME_LOG_DIR + "kernel.log", null, LogDataType.CUTTLEFISH_LOG))178         OXYGEN_LOG_FILES_FALLBACK.add(
179                 new KnownLogFileEntry(
180                         OXYGEN_RUNTIME_LOG_DIR + "kernel.log", null, LogDataType.CUTTLEFISH_LOG));
OXYGEN_LOG_FILES_FALLBACK.add( new KnownLogFileEntry( OXYGEN_RUNTIME_LOG_DIR + "logcat", null, LogDataType.CUTTLEFISH_LOG))181         OXYGEN_LOG_FILES_FALLBACK.add(
182                 new KnownLogFileEntry(
183                         OXYGEN_RUNTIME_LOG_DIR + "logcat", null, LogDataType.CUTTLEFISH_LOG));
184     }
185 
186     /** A representation of a known log entry for remote devices. */
187     public static class KnownLogFileEntry {
188         public String path;
189         public String logName;
190         public LogDataType type;
191 
KnownLogFileEntry(String path, String logName, LogDataType type)192         KnownLogFileEntry(String path, String logName, LogDataType type) {
193             this.path = path;
194             this.logName = logName;
195             this.type = type;
196         }
197     }
198 
199     /**
200      * Fetch and log the commonly known files from remote instances.
201      *
202      * @param testLogger The {@link ITestLogger} where to log the files.
203      * @param gceAvd The descriptor of the remote instance.
204      * @param options The {@link TestDeviceOptions} describing the device options
205      * @param runUtil A {@link IRunUtil} to execute commands.
206      */
fetchCommonFiles( ITestLogger testLogger, GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil)207     public static void fetchCommonFiles(
208             ITestLogger testLogger,
209             GceAvdInfo gceAvd,
210             TestDeviceOptions options,
211             IRunUtil runUtil) {
212         if (gceAvd == null || gceAvd.hostAndPort() == null) {
213             CLog.e("GceAvdInfo or its host setting was null, cannot collect remote files.");
214             return;
215         }
216         List<KnownLogFileEntry> toFetch = new ArrayList<>(NETSIM_LOG_FILES);
217         if (options.useOxygen()) {
218             // Override the list of logs to collect when the device is hosted by Oxygen service.
219             toFetch.addAll(OXYGEN_LOG_FILES);
220             if (!RemoteFileUtil.doesRemoteFileExist(
221                     gceAvd, options, runUtil, 60000, OXYGEN_CUTTLEFISH_LOG_DIR)) {
222                 toFetch.addAll(OXYGEN_LOG_FILES_FALLBACK);
223             }
224         } else {
225             boolean reported = false;
226             for (GceAvdInfo.LogFileEntry entry : gceAvd.getLogs()) {
227                 if (logRemoteFile(
228                         testLogger,
229                         gceAvd,
230                         options,
231                         runUtil,
232                         entry.path,
233                         entry.type,
234                         Strings.isNullOrEmpty(entry.name) ? null : entry.name)) {
235                     reported = true;
236                 }
237             }
238             if (!reported) {
239                 CLog.i("GceAvdInfo does not contain logs. Fall back to known log files.");
240                 List<KnownLogFileEntry> knownFileFetch =
241                         KNOWN_FILES_TO_FETCH.get(options.getInstanceType());
242                 if (knownFileFetch != null) {
243                     toFetch.addAll(knownFileFetch);
244                 }
245             }
246         }
247         for (KnownLogFileEntry entry : toFetch) {
248             logRemoteFile(
249                     testLogger,
250                     gceAvd,
251                     options,
252                     runUtil,
253                     // Default fetch rely on main user
254                     String.format(entry.path, options.getInstanceUser()),
255                     entry.type,
256                     entry.logName);
257         }
258 
259         if (options.getRemoteFetchFilePattern().isEmpty()) {
260             return;
261         }
262         for (String file : options.getRemoteFetchFilePattern()) {
263             // TODO: Improve type of files.
264             logRemoteFile(
265                     testLogger, gceAvd, options, runUtil, file, LogDataType.CUTTLEFISH_LOG, null);
266         }
267     }
268 
269     /**
270      * Execute a command to validate the ssh connection to the remote GCE instance.
271      *
272      * @param gceAvd The {@link GceAvdInfo} that describe the device.
273      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
274      *     GCE device.
275      * @param runUtil a {@link IRunUtil} to execute commands.
276      * @return A boolean which indicate whether the remote GCE is reachable by ssh.
277      */
isRemoteGceReachableBySsh( GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil)278     public static boolean isRemoteGceReachableBySsh(
279             GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil) {
280         return isRemoteGceReachableBySsh(gceAvd, options, runUtil, "");
281     }
282 
283     /**
284      * Execute a command to validate the ssh connection to the remote GCE instance.
285      *
286      * @param gceAvd The {@link GceAvdInfo} that describe the device.
287      * @param options a {@link TestDeviceOptions} describing the device options to be used for the
288      *     GCE device.
289      * @param runUtil a {@link IRunUtil} to execute commands.
290      * @param command The command to be executed.
291      * @return A boolean which indicate whether the remote GCE is reachable by ssh.
292      */
isRemoteGceReachableBySsh( GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil, String... command)293     public static boolean isRemoteGceReachableBySsh(
294             GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil, String... command) {
295         List<String> cmd = new ArrayList<>();
296         for (String cmdOption : command) {
297             cmd.add(cmdOption);
298         }
299         cmd.add("exit");
300         CommandStatus sshAttemptStatus =
301                 RemoteSshUtil.remoteSshCommandExec(
302                                 gceAvd, options, runUtil, 10000, cmd.toArray(new String[0]))
303                         .getStatus();
304         if (!CommandStatus.SUCCESS.equals(sshAttemptStatus)) {
305             CLog.e(
306                     String.format(
307                             "Unable to ssh to the remote GCE, ssh failed with status %s.",
308                             sshAttemptStatus));
309             return false;
310         }
311         return true;
312     }
313 
314     /**
315      * Execute a command on remote instance and log its output
316      *
317      * @param testLogger The {@link ITestLogger} where to log the files.
318      * @param gceAvd The descriptor of the remote instance.
319      * @param options The {@link TestDeviceOptions} describing the device options
320      * @param runUtil A {@link IRunUtil} to execute commands.
321      * @param logName the log name to use when reporting to the {@link ITestLogger}
322      * @param remoteCommand the command line to be executed on remote instance
323      */
logRemoteCommandOutput( ITestLogger testLogger, GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil, String logName, String... remoteCommand)324     public static void logRemoteCommandOutput(
325             ITestLogger testLogger,
326             GceAvdInfo gceAvd,
327             TestDeviceOptions options,
328             IRunUtil runUtil,
329             String logName,
330             String... remoteCommand) {
331         if (gceAvd == null || gceAvd.hostAndPort() == null) {
332             CLog.e("GceAvdInfo or its host setting was null, cannot collect remote files.");
333             return;
334         }
335         CommandResult commandResult =
336                 GceManager.remoteSshCommandExecution(
337                         gceAvd, options, runUtil, 60000, remoteCommand);
338         StringBuilder builder = new StringBuilder();
339         builder.append(String.format("Command: %s\n", Arrays.asList(remoteCommand)));
340         builder.append(
341                 String.format(
342                         "Exit code: %d, Status: %s\n",
343                         commandResult.getExitCode(), commandResult.getStatus()));
344         builder.append(String.format("stdout:\n%s\n", commandResult.getStdout()));
345         builder.append(String.format("stderr:\n%s\n", commandResult.getStderr()));
346         testLogger.testLog(
347                 logName,
348                 LogDataType.CUTTLEFISH_LOG,
349                 new ByteArrayInputStreamSource(builder.toString().getBytes()));
350     }
351 
352     /**
353      * Fetch and log the tombstones from the remote instance.
354      *
355      * @param testLogger The {@link ITestLogger} where to log the files.
356      * @param gceAvd The descriptor of the remote instance.
357      * @param options The {@link TestDeviceOptions} describing the device options
358      * @param runUtil A {@link IRunUtil} to execute commands.
359      */
fetchTombstones( ITestLogger testLogger, GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil)360     public static void fetchTombstones(
361             ITestLogger testLogger,
362             GceAvdInfo gceAvd,
363             TestDeviceOptions options,
364             IRunUtil runUtil) {
365         if (gceAvd == null || gceAvd.hostAndPort() == null) {
366             CLog.e("GceAvdInfo or its host setting was null, cannot collect remote files.");
367             return;
368         }
369         InstanceType type = options.getInstanceType();
370         if (!InstanceType.CUTTLEFISH.equals(type) && !InstanceType.REMOTE_AVD.equals(type)) {
371             return;
372         }
373         String path =
374                 String.format("/home/%s/cuttlefish_runtime/tombstones", options.getInstanceUser());
375         for (GceAvdInfo.LogFileEntry entry : gceAvd.getLogs()) {
376             if (entry.name.equals(TOMBSTONES_ZIP_NAME)) {
377                 path = entry.path;
378                 break;
379             }
380         }
381         String pattern = path + "/*";
382         CommandResult resultList =
383                 GceManager.remoteSshCommandExecution(
384                         gceAvd, options, runUtil, 60000, "ls", "-A1", pattern);
385         if (!CommandStatus.SUCCESS.equals(resultList.getStatus())) {
386             CLog.e("Failed to list the tombstones: %s", resultList.getStderr());
387             return;
388         }
389         if (resultList.getStdout().split("\n").length <= 0) {
390             return;
391         }
392         File tombstonesDir = RemoteFileUtil.fetchRemoteDir(gceAvd, options, runUtil, 120000, path);
393         if (tombstonesDir == null) {
394             CLog.w("No tombstones directory was pulled.");
395             return;
396         }
397         try {
398             File zipTombstones = ZipUtil.createZip(tombstonesDir);
399             try (InputStreamSource source = new FileInputStreamSource(zipTombstones, true)) {
400                 testLogger.testLog(TOMBSTONES_ZIP_NAME, LogDataType.TOMBSTONEZ, source);
401             }
402         } catch (IOException e) {
403             CLog.e("Failed to zip the tombstones:");
404             CLog.e(e);
405         }
406     }
407 
408     /**
409      * Pull CF logs via Host Orchestrator.
410      *
411      * @param gceAvdInfo The descriptor of the remote instance.
412      * @param hOUtil The {@link HostOrchestratorUtil} used to pull CF logs.
413      * @param logger The {@link ITestLogger} where to log the file.
414      */
pullCommonCvdLogs( GceAvdInfo gceAvdInfo, HostOrchestratorUtil hoUtil, ITestLogger logger)415     public static void pullCommonCvdLogs(
416             GceAvdInfo gceAvdInfo, HostOrchestratorUtil hoUtil, ITestLogger logger) {
417         pullCommonCvdLogs(gceAvdInfo, hoUtil, logger, null);
418     }
419 
420     /**
421      * Pull CF logs via Host Orchestrator.
422      *
423      * @param gceAvdInfo The descriptor of the remote instance.
424      * @param hOUtil The {@link HostOrchestratorUtil} used to pull CF logs.
425      * @param logger The {@link ITestLogger} where to log the file.
426      * @param options The {@link TestDeviceOptions} describing the device options
427      */
pullCommonCvdLogs( GceAvdInfo gceAvdInfo, HostOrchestratorUtil hOUtil, ITestLogger logger, TestDeviceOptions options)428     public static void pullCommonCvdLogs(
429             GceAvdInfo gceAvdInfo,
430             HostOrchestratorUtil hOUtil,
431             ITestLogger logger,
432             TestDeviceOptions options) {
433         if (hOUtil == null || gceAvdInfo == null || gceAvdInfo.hostAndPort() == null) {
434             CLog.e(
435                     "HostOrchestratorUtil, GceAvdInfo or its host setting was null, cannot collect"
436                             + " remote files.");
437             return;
438         }
439         File cvdLogsDir = hOUtil.pullCvdHostLogs();
440         if (cvdLogsDir != null) {
441             GceManager.logDirectory(cvdLogsDir, null, logger, LogDataType.CUTTLEFISH_LOG);
442             FileUtil.recursiveDelete(cvdLogsDir);
443         } else {
444             CLog.i("CVD Logs is null, no logs collected from host orchestrator.");
445         }
446 
447         File tempFile =
448                 hOUtil.downloadLogFile("host_orchestrator", HostOrchestratorUtil.URL_HO_LOG);
449         GceManager.logAndDeleteFile(tempFile, "host_orchestrator", logger);
450         // The following logs endpoints are only available using the Cuttlefish Host Image.
451         if (options != null && options.useOxygenationDevice()) {
452             tempFile =
453                     hOUtil.downloadLogFile("host_kernel", HostOrchestratorUtil.URL_HOST_KERNEL_LOG);
454             GceManager.logAndDeleteFile(tempFile, "host_kernel", logger);
455             tempFile = hOUtil.getTunnelLog();
456             GceManager.logAndDeleteFile(tempFile, "host_orchestrator_tunnel_log", logger);
457             tempFile =
458                     hOUtil.downloadLogFile(
459                             "oxygen_container_log", HostOrchestratorUtil.URL_OXYGEN_CONTAINER_LOG);
460             GceManager.logAndDeleteFile(tempFile, "oxygen_container_log", logger);
461         }
462     }
463 
464     /**
465      * Captures a log from the remote destination.
466      *
467      * @param testLogger The {@link ITestLogger} where to log the files.
468      * @param gceAvd The descriptor of the remote instance.
469      * @param options The {@link TestDeviceOptions} describing the device options
470      * @param runUtil A {@link IRunUtil} to execute commands.
471      * @param fileToRetrieve The remote path to the file to pull.
472      * @param logType The expected type of the pulled log.
473      * @param baseName The base name that will be used to log the file, if null the actually file
474      *     name will be used.
475      * @return whether the file is logged successfully.
476      */
logRemoteFile( ITestLogger testLogger, GceAvdInfo gceAvd, TestDeviceOptions options, IRunUtil runUtil, String fileToRetrieve, LogDataType logType, String baseName)477     private static boolean logRemoteFile(
478             ITestLogger testLogger,
479             GceAvdInfo gceAvd,
480             TestDeviceOptions options,
481             IRunUtil runUtil,
482             String fileToRetrieve,
483             LogDataType logType,
484             String baseName) {
485         if (baseName != null && baseName.startsWith(TOMBSTONES_ZIP_NAME)) {
486             // TODO(b/154175542): Refactor fetchTombstones.
487             return false;
488         }
489         return GceManager.logNestedRemoteFile(
490                 testLogger, gceAvd, options, runUtil, fileToRetrieve, logType, baseName);
491     }
492 }
493