def take_bug_reports(ads, test_name, begin_time, destination=None): """Takes bug reports on a list of android devices. If you want to take a bug report, call this function with a list of android_device objects in on_fail. But reports will be taken on all the devices in the list concurrently. Bug report takes a relative long time to take, so use this cautiously. Args: ads: A list of AndroidDevice instances. test_name: Name of the test method that triggered this bug report. begin_time: timestamp taken when the test started, can be either string or int. destination: string, path to the directory where the bugreport should be saved. """ begin_time = mobly_logger.normalize_log_line_timestamp(str(begin_time)) def take_br(test_name, begin_time, ad, destination): ad.take_bug_report(test_name=test_name, begin_time=begin_time, destination=destination) args = [(test_name, begin_time, ad, destination) for ad in ads] utils.concurrent_exec(take_br, args)
def take_bug_reports(ads, test_name, begin_time): """Takes bug reports on a list of android devices. If you want to take a bug report, call this function with a list of android_device objects in on_fail. But reports will be taken on all the devices in the list concurrently. Bug report takes a relative long time to take, so use this cautiously. Args: ads: A list of AndroidDevice instances. test_name: Name of the test method that triggered this bug report. begin_time: Logline format timestamp taken when the test started. """ begin_time = mobly_logger.normalize_log_line_timestamp(begin_time) def take_br(test_name, begin_time, ad): ad.take_bug_report(test_name, begin_time) args = [(test_name, begin_time, ad) for ad in ads] utils.concurrent_exec(take_br, args)
def take_bug_report(self, test_name=None, begin_time=None, timeout=300, destination=None): """Takes a bug report on the device and stores it in a file. Args: test_name: Name of the test method that triggered this bug report. If not set, then this will default to android_device.DEFAULT_BUG_REPORT_NAME. begin_time: Timestamp of when the test started. If not set, then this will default to the current time. timeout: float, the number of seconds to wait for bugreport to complete, default is 5min. destination: string, path to the directory where the bugreport should be saved. Returns: A string containing the absolute path to the bug report on the host machine. """ if test_name is None: test_name = DEFAULT_BUG_REPORT_NAME if begin_time is None: epoch_time = utils.get_current_epoch_time() timestamp = mobly_logger.epoch_to_log_line_timestamp(epoch_time) begin_time = mobly_logger.normalize_log_line_timestamp(timestamp) new_br = True try: stdout = self.adb.shell('bugreportz -v').decode('utf-8') # This check is necessary for builds before N, where adb shell's ret # code and stderr are not propagated properly. if 'not found' in stdout: new_br = False except adb.AdbError: new_br = False if destination: br_path = utils.abs_path(destination) else: br_path = os.path.join(self.log_path, 'BugReports') utils.create_dir(br_path) base_name = ',%s,%s.txt' % (begin_time, self._normalized_serial) if new_br: base_name = base_name.replace('.txt', '.zip') test_name_len = utils.MAX_FILENAME_LEN - len(base_name) out_name = test_name[:test_name_len] + base_name full_out_path = os.path.join(br_path, out_name.replace(' ', r'\ ')) # in case device restarted, wait for adb interface to return self.wait_for_boot_completion() self.log.info('Taking bugreport for %s.', test_name) if new_br: out = self.adb.shell('bugreportz', timeout=timeout).decode('utf-8') if not out.startswith('OK'): raise DeviceError(self, 'Failed to take bugreport: %s' % out) br_out_path = out.split(':')[1].strip() self.adb.pull([br_out_path, full_out_path]) else: # shell=True as this command redirects the stdout to a local file # using shell redirection. self.adb.bugreport(' > "%s"' % full_out_path, shell=True, timeout=timeout) self.log.info('Bugreport for %s taken at %s.', test_name, full_out_path) return full_out_path