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