예제 #1
0
def ProvisionDevices(options):
  if options.device is not None:
    devices = [options.device]
  else:
    devices = android_commands.GetAttachedDevices()
  for device_serial in devices:
    device = device_utils.DeviceUtils(device_serial)
    device.old_interface.EnableAdbRoot()
    install_output = GetCmdOutput(
      ['%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT,
       '--apk',
       '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT
       ])
    failure_string = 'Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE]'
    if failure_string in install_output:
      WipeDeviceData(device)
    _ConfigureLocalProperties(device)
    device_settings.ConfigureContentSettingsDict(
        device, device_settings.DETERMINISTIC_DEVICE_SETTINGS)
    # TODO(tonyg): We eventually want network on. However, currently radios
    # can cause perfbots to drain faster than they charge.
    if 'perf' in os.environ.get('BUILDBOT_BUILDERNAME', '').lower():
      device_settings.ConfigureContentSettingsDict(
          device, device_settings.NETWORK_DISABLED_SETTINGS)
    device.old_interface.RunShellCommandWithSU('date -u %f' % time.time())
    (_, props) = device.old_interface.GetShellCommandStatusAndOutput('getprop')
    for prop in props:
      print prop
  if options.auto_reconnect:
    PushAndLaunchAdbReboot(devices, options.target)
예제 #2
0
def CheckForMissingDevices(options, adb_online_devs):
    """Uses file of previous online devices to detect broken phones.

  Args:
    options: out_dir parameter of options argument is used as the base
             directory to load and update the cache file.
    adb_online_devs: A list of serial numbers of the currently visible
                     and online attached devices.
  """
    out_dir = os.path.abspath(options.out_dir)
    last_devices_path = os.path.join(out_dir, '.last_devices')
    last_devices = []
    try:
        with open(last_devices_path) as f:
            last_devices = f.read().splitlines()
    except IOError:
        # Ignore error, file might not exist
        pass

    missing_devs = list(set(last_devices) - set(adb_online_devs))
    if missing_devs:
        buildbot_report.PrintWarning()
        buildbot_report.PrintSummaryText('%d devices not detected.' %
                                         len(missing_devs))
        print 'Current online devices: %s' % adb_online_devs
        print '%s are no longer visible. Were they removed?\n' % missing_devs
        print 'SHERIFF: See go/chrome_device_monitor'
        print 'Cache file: %s\n\n' % last_devices_path
        print 'adb devices'
        print GetCmdOutput(['adb', 'devices'])
    else:
        new_devs = set(adb_online_devs) - set(last_devices)
        if new_devs and os.path.exists(last_devices_path):
            buildbot_report.PrintWarning()
            buildbot_report.PrintSummaryText('%d new devices detected' %
                                             len(new_devs))
            print(
                'New devices detected %s. And now back to your '
                'regularly scheduled program.' % list(new_devs))

    if not os.path.exists(out_dir):
        os.makedirs(out_dir)
    with open(last_devices_path, 'w') as f:
        # Write devices currently visible plus devices previously seen.
        f.write('\n'.join(set(adb_online_devs + last_devices)))
예제 #3
0
def CheckForMissingDevices(options, adb_online_devs):
    """Uses file of previous online devices to detect broken phones.

  Args:
    options: out_dir parameter of options argument is used as the base
             directory to load and update the cache file.
    adb_online_devs: A list of serial numbers of the currently visible
                     and online attached devices.
  """
    # TODO(navabi): remove this once the bug that causes different number
    # of devices to be detected between calls is fixed.
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    out_dir = os.path.abspath(options.out_dir)

    # last_devices denotes all known devices prior to this run
    last_devices_path = os.path.join(out_dir,
                                     device_list.LAST_DEVICES_FILENAME)
    last_missing_devices_path = os.path.join(
        out_dir, device_list.LAST_MISSING_DEVICES_FILENAME)
    try:
        last_devices = device_list.GetPersistentDeviceList(last_devices_path)
    except IOError:
        # Ignore error, file might not exist
        last_devices = []

    try:
        last_missing_devices = device_list.GetPersistentDeviceList(
            last_missing_devices_path)
    except IOError:
        last_missing_devices = []

    missing_devs = list(set(last_devices) - set(adb_online_devs))
    new_missing_devs = list(set(missing_devs) - set(last_missing_devices))

    if new_missing_devs and os.environ.get('BUILDBOT_SLAVENAME'):
        logging.info('new_missing_devs %s' % new_missing_devs)
        devices_missing_msg = '%d devices not detected.' % len(missing_devs)
        bb_annotations.PrintSummaryText(devices_missing_msg)

        from_address = '*****@*****.**'
        to_addresses = [
            '*****@*****.**',
            '*****@*****.**'
        ]
        cc_addresses = ['*****@*****.**']
        subject = 'Devices offline on %s, %s, %s' % (
            os.environ.get('BUILDBOT_SLAVENAME'),
            os.environ.get('BUILDBOT_BUILDERNAME'),
            os.environ.get('BUILDBOT_BUILDNUMBER'))
        msg = ('Please reboot the following devices:\n%s' %
               '\n'.join(map(str, new_missing_devs)))
        SendEmail(from_address, to_addresses, cc_addresses, subject, msg)

    all_known_devices = list(set(adb_online_devs) | set(last_devices))
    device_list.WritePersistentDeviceList(last_devices_path, all_known_devices)
    device_list.WritePersistentDeviceList(last_missing_devices_path,
                                          missing_devs)

    if not all_known_devices:
        # This can happen if for some reason the .last_devices file is not
        # present or if it was empty.
        return ['No online devices. Have any devices been plugged in?']
    if missing_devs:
        devices_missing_msg = '%d devices not detected.' % len(missing_devs)
        bb_annotations.PrintSummaryText(devices_missing_msg)

        # TODO(navabi): Debug by printing both output from GetCmdOutput and
        # GetAttachedDevices to compare results.
        crbug_link = (
            'https://code.google.com/p/chromium/issues/entry?summary='
            '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' %
            (urllib.quote('Device Offline'),
             urllib.quote('Buildbot: %s %s\n'
                          'Build: %s\n'
                          '(please don\'t change any labels)' %
                          (os.environ.get('BUILDBOT_BUILDERNAME'),
                           os.environ.get('BUILDBOT_SLAVENAME'),
                           os.environ.get('BUILDBOT_BUILDNUMBER')))))
        return [
            'Current online devices: %s' % adb_online_devs,
            '%s are no longer visible. Were they removed?\n' % missing_devs,
            'SHERIFF:\n',
            '@@@STEP_LINK@Click here to file a bug@%s@@@\n' % crbug_link,
            'Cache file: %s\n\n' % last_devices_path,
            'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
            'adb devices(GetAttachedDevices): %s' % adb_online_devs
        ]
    else:
        new_devs = set(adb_online_devs) - set(last_devices)
        if new_devs and os.path.exists(last_devices_path):
            bb_annotations.PrintWarning()
            bb_annotations.PrintSummaryText('%d new devices detected' %
                                            len(new_devs))
            print(
                'New devices detected %s. And now back to your '
                'regularly scheduled program.' % list(new_devs))
예제 #4
0
def CheckForMissingDevices(options, adb_online_devs):
    """Uses file of previous online devices to detect broken phones.

  Args:
    options: out_dir parameter of options argument is used as the base
             directory to load and update the cache file.
    adb_online_devs: A list of serial numbers of the currently visible
                     and online attached devices.
  """
    # TODO(navabi): remove this once the bug that causes different number
    # of devices to be detected between calls is fixed.
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    out_dir = os.path.abspath(options.out_dir)

    def ReadDeviceList(file_name):
        devices_path = os.path.join(out_dir, file_name)
        devices = []
        try:
            with open(devices_path) as f:
                devices = f.read().splitlines()
        except IOError:
            # Ignore error, file might not exist
            pass
        return devices

    def WriteDeviceList(file_name, device_list):
        path = os.path.join(out_dir, file_name)
        if not os.path.exists(out_dir):
            os.makedirs(out_dir)
        with open(path, 'w') as f:
            # Write devices currently visible plus devices previously seen.
            f.write('\n'.join(set(device_list)))

    last_devices_path = os.path.join(out_dir, '.last_devices')
    last_devices = ReadDeviceList('.last_devices')

    missing_devs = list(set(last_devices) - set(adb_online_devs))
    if missing_devs:
        from_address = '*****@*****.**'
        to_address = '*****@*****.**'
        bot_name = os.environ['BUILDBOT_BUILDERNAME']
        slave_name = os.environ['BUILDBOT_SLAVENAME']
        num_online_devs = len(adb_online_devs)
        subject = 'Devices offline on %s, %s (%d remaining).' % (
            slave_name, bot_name, num_online_devs)
        buildbot_report.PrintWarning()
        devices_missing_msg = '%d devices not detected.' % len(missing_devs)
        buildbot_report.PrintSummaryText(devices_missing_msg)

        # TODO(navabi): Debug by printing both output from GetCmdOutput and
        # GetAttachedDevices to compare results.
        body = '\n'.join([
            'Current online devices: %s' % adb_online_devs,
            '%s are no longer visible. Were they removed?\n' % missing_devs,
            'SHERIFF: See go/chrome_device_monitor',
            'Cache file: %s\n\n' % last_devices_path,
            'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
            'adb devices(GetAttachedDevices): %s' % GetAttachedDevices()
        ])

        print body

        # Only send email if the first time a particular device goes offline
        last_missing = ReadDeviceList('.last_missing')
        new_missing_devs = set(missing_devs) - set(last_missing)

        if new_missing_devs:
            msg_body = '\r\n'.join([
                'From: %s' % from_address,
                'To: %s' % to_address,
                'Subject: %s' % subject, '', body
            ])
            try:
                server = smtplib.SMTP('localhost')
                server.sendmail(from_address, [to_address], msg_body)
                server.quit()
            except Exception as e:
                print 'Failed to send alert email. Error: %s' % e
    else:
        new_devs = set(adb_online_devs) - set(last_devices)
        if new_devs and os.path.exists(last_devices_path):
            buildbot_report.PrintWarning()
            buildbot_report.PrintSummaryText('%d new devices detected' %
                                             len(new_devs))
            print(
                'New devices detected %s. And now back to your '
                'regularly scheduled program.' % list(new_devs))
    WriteDeviceList('.last_devices', (adb_online_devs + last_devices))
    WriteDeviceList('.last_missing', missing_devs)
예제 #5
0
 def AdbShellCmd(cmd):
     return GetCmdOutput('adb -s %s shell %s' % (serial, cmd),
                         shell=True).strip()
예제 #6
0
def CheckForMissingDevices(options, adb_online_devs):
    """Uses file of previous online devices to detect broken phones.

  Args:
    options: out_dir parameter of options argument is used as the base
             directory to load and update the cache file.
    adb_online_devs: A list of serial numbers of the currently visible
                     and online attached devices.
  """
    # TODO(navabi): remove this once the bug that causes different number
    # of devices to be detected between calls is fixed.
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    out_dir = os.path.abspath(options.out_dir)

    def ReadDeviceList(file_name):
        devices_path = os.path.join(out_dir, file_name)
        devices = []
        try:
            with open(devices_path) as f:
                devices = f.read().splitlines()
        except IOError:
            # Ignore error, file might not exist
            pass
        return devices

    def WriteDeviceList(file_name, device_list):
        path = os.path.join(out_dir, file_name)
        if not os.path.exists(out_dir):
            os.makedirs(out_dir)
        with open(path, 'w') as f:
            # Write devices currently visible plus devices previously seen.
            f.write('\n'.join(set(device_list)))

    last_devices_path = os.path.join(out_dir, '.last_devices')
    last_devices = ReadDeviceList('.last_devices')
    missing_devs = list(set(last_devices) - set(adb_online_devs))

    all_known_devices = list(set(adb_online_devs) | set(last_devices))
    WriteDeviceList('.last_devices', all_known_devices)
    WriteDeviceList('.last_missing', missing_devs)

    if not all_known_devices:
        # This can happen if for some reason the .last_devices file is not
        # present or if it was empty.
        return ['No online devices. Have any devices been plugged in?']
    if missing_devs:
        devices_missing_msg = '%d devices not detected.' % len(missing_devs)
        bb_annotations.PrintSummaryText(devices_missing_msg)

        # TODO(navabi): Debug by printing both output from GetCmdOutput and
        # GetAttachedDevices to compare results.
        return [
            'Current online devices: %s' % adb_online_devs,
            '%s are no longer visible. Were they removed?\n' % missing_devs,
            'SHERIFF: See go/chrome_device_monitor',
            'Cache file: %s\n\n' % last_devices_path,
            'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
            'adb devices(GetAttachedDevices): %s' %
            android_commands.GetAttachedDevices()
        ]
    else:
        new_devs = set(adb_online_devs) - set(last_devices)
        if new_devs and os.path.exists(last_devices_path):
            bb_annotations.PrintWarning()
            bb_annotations.PrintSummaryText('%d new devices detected' %
                                            len(new_devs))
            print(
                'New devices detected %s. And now back to your '
                'regularly scheduled program.' % list(new_devs))
예제 #7
0
def DeviceInfo(serial, options):
    """Gathers info on a device via various adb calls.

  Args:
    serial: The serial of the attached device to construct info about.

  Returns:
    Tuple of device type, build id, report as a string, error messages, and
    boolean indicating whether or not device can be used for testing.
  """

    device_adb = android_commands.AndroidCommands(serial)

    # TODO(navabi): Replace AdbShellCmd with device_adb.
    device_type = device_adb.GetBuildProduct()
    device_build = device_adb.GetBuildId()
    device_build_type = device_adb.GetBuildType()
    device_product_name = device_adb.GetProductName()

    setup_wizard_disabled = device_adb.GetSetupWizardStatus() == 'DISABLED'
    battery = device_adb.GetBatteryInfo()
    install_output = GetCmdOutput([
        '%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT,
        '--apk',
        '%s/build/android/CheckInstallApk-debug.apk' %
        constants.DIR_SOURCE_ROOT
    ])

    def _GetData(re_expression, line, lambda_function=lambda x: x):
        if not line:
            return 'Unknown'
        found = re.findall(re_expression, line)
        if found and len(found):
            return lambda_function(found[0])
        return 'Unknown'

    install_speed = _GetData('(\d+) KB/s', install_output)
    ac_power = _GetData('AC powered: (\w+)', battery)
    battery_level = _GetData('level: (\d+)', battery)
    battery_temp = _GetData('temperature: (\d+)', battery,
                            lambda x: float(x) / 10.0)
    imei_slice = _GetData('Device ID = (\d+)', device_adb.GetSubscriberInfo(),
                          lambda x: x[-6:])
    report = [
        'Device %s (%s)' % (serial, device_type),
        '  Build: %s (%s)' % (device_build, device_adb.GetBuildFingerprint()),
        '  Battery: %s%%' % battery_level,
        '  Battery temp: %s' % battery_temp,
        '  IMEI slice: %s' % imei_slice,
        '  Wifi IP: %s' % device_adb.GetWifiIP(),
        '  Install Speed: %s KB/s' % install_speed, ''
    ]

    errors = []
    if battery_level < 15:
        errors += ['Device critically low in battery. Turning off device.']
    if (not setup_wizard_disabled and device_build_type != 'user'
            and not options.no_provisioning_check):
        errors += ['Setup wizard not disabled. Was it provisioned correctly?']
    if device_product_name == 'mantaray' and ac_power != 'true':
        errors += ['Mantaray device not connected to AC power.']
    # TODO(navabi): Insert warning once we have a better handle of what install
    # speeds to expect. The following lines were causing too many alerts.
    # if install_speed < 500:
    #   errors += ['Device install speed too low. Do not use for testing.']

    # Causing the device status check step fail for slow install speed or low
    # battery currently is too disruptive to the bots (especially try bots).
    # Turn off devices with low battery and the step does not fail.
    if battery_level < 15:
        device_adb.EnableAdbRoot()
        device_adb.Shutdown()
    full_report = '\n'.join(report)
    return device_type, device_build, battery_level, full_report, errors, True
def DeviceInfo(serial, options):
    """Gathers info on a device via various adb calls.

  Args:
    serial: The serial of the attached device to construct info about.

  Returns:
    Tuple of device type, build id, report as a string, error messages, and
    boolean indicating whether or not device can be used for testing.
  """
    def AdbShellCmd(cmd):
        return GetCmdOutput('adb -s %s shell %s' % (serial, cmd),
                            shell=True).strip()

    device_adb = android_commands.AndroidCommands(serial)

    # TODO(navabi): Replace AdbShellCmd with device_adb.
    device_type = AdbShellCmd('getprop ro.build.product')
    device_build = AdbShellCmd('getprop ro.build.id')
    device_build_type = AdbShellCmd('getprop ro.build.type')
    device_product_name = AdbShellCmd('getprop ro.product.name')

    setup_wizard_disabled = AdbShellCmd(
        'getprop ro.setupwizard.mode') == 'DISABLED'
    battery = AdbShellCmd('dumpsys battery')
    install_output = GetCmdOutput([
        '%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT,
        '--apk',
        '%s/build/android/CheckInstallApk-debug.apk' %
        constants.DIR_SOURCE_ROOT
    ])
    install_speed_found = re.findall('(\d+) KB/s', install_output)
    if install_speed_found:
        install_speed = int(install_speed_found[0])
    else:
        install_speed = 'Unknown'
    if 'Error' in battery:
        ac_power = 'Unknown'
        battery_level = 'Unknown'
        battery_temp = 'Unknown'
    else:
        ac_power = re.findall('AC powered: (\w+)', battery)[0]
        battery_level = int(re.findall('level: (\d+)', battery)[0])
        battery_temp = float(re.findall('temperature: (\d+)', battery)[0]) / 10
    report = [
        'Device %s (%s)' % (serial, device_type),
        '  Build: %s (%s)' %
        (device_build, AdbShellCmd('getprop ro.build.fingerprint')),
        '  Battery: %s%%' % battery_level,
        '  Battery temp: %s' % battery_temp,
        '  IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo '
                                         '| grep Device'
                                         "| awk '{print $4}'")[-6:],
        '  Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'),
        '  Install Speed: %s KB/s' % install_speed, ''
    ]

    errors = []
    if battery_level < 15:
        errors += ['Device critically low in battery. Turning off device.']
    if (not setup_wizard_disabled and device_build_type != 'user'
            and not options.no_provisioning_check):
        errors += ['Setup wizard not disabled. Was it provisioned correctly?']
    if device_product_name == 'mantaray' and ac_power != 'true':
        errors += ['Mantaray device not connected to AC power.']
    # TODO(navabi): Insert warning once we have a better handle of what install
    # speeds to expect. The following lines were causing too many alerts.
    # if install_speed < 500:
    #   errors += ['Device install speed too low. Do not use for testing.']

    # Causing the device status check step fail for slow install speed or low
    # battery currently is too disruptive to the bots (especially try bots).
    # Turn off devices with low battery and the step does not fail.
    if battery_level < 15:
        device_adb.EnableAdbRoot()
        AdbShellCmd('reboot -p')
    return device_type, device_build, '\n'.join(report), errors, True
예제 #9
0
def CheckForMissingDevices(options, adb_online_devs):
    """Uses file of previous online devices to detect broken phones.

  Args:
    options: out_dir parameter of options argument is used as the base
             directory to load and update the cache file.
    adb_online_devs: A list of serial numbers of the currently visible
                     and online attached devices.
  """
    # TODO(navabi): remove this once the bug that causes different number
    # of devices to be detected between calls is fixed.
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    out_dir = os.path.abspath(options.out_dir)

    def WriteDeviceList(file_name, device_list):
        path = os.path.join(out_dir, file_name)
        if not os.path.exists(out_dir):
            os.makedirs(out_dir)
        with open(path, 'w') as f:
            # Write devices currently visible plus devices previously seen.
            f.write('\n'.join(set(device_list)))

    last_devices_path = os.path.join(out_dir, '.last_devices')
    last_devices = GetLastDevices(out_dir)
    missing_devs = list(set(last_devices) - set(adb_online_devs))

    all_known_devices = list(set(adb_online_devs) | set(last_devices))
    WriteDeviceList('.last_devices', all_known_devices)
    WriteDeviceList('.last_missing', missing_devs)

    if not all_known_devices:
        # This can happen if for some reason the .last_devices file is not
        # present or if it was empty.
        return ['No online devices. Have any devices been plugged in?']
    if missing_devs:
        devices_missing_msg = '%d devices not detected.' % len(missing_devs)
        bb_annotations.PrintSummaryText(devices_missing_msg)

        # TODO(navabi): Debug by printing both output from GetCmdOutput and
        # GetAttachedDevices to compare results.
        crbug_link = (
            'https://code.google.com/p/chromium/issues/entry?summary='
            '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' %
            (urllib.quote('Device Offline'),
             urllib.quote('Buildbot: %s %s\n'
                          'Build: %s\n'
                          '(please don\'t change any labels)' %
                          (os.environ.get('BUILDBOT_BUILDERNAME'),
                           os.environ.get('BUILDBOT_SLAVENAME'),
                           os.environ.get('BUILDBOT_BUILDNUMBER')))))
        return [
            'Current online devices: %s' % adb_online_devs,
            '%s are no longer visible. Were they removed?\n' % missing_devs,
            'SHERIFF:\n',
            '@@@STEP_LINK@Click here to file a bug@%s@@@\n' % crbug_link,
            'Cache file: %s\n\n' % last_devices_path,
            'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
            'adb devices(GetAttachedDevices): %s' %
            android_commands.GetAttachedDevices()
        ]
    else:
        new_devs = set(adb_online_devs) - set(last_devices)
        if new_devs and os.path.exists(last_devices_path):
            bb_annotations.PrintWarning()
            bb_annotations.PrintSummaryText('%d new devices detected' %
                                            len(new_devs))
            print(
                'New devices detected %s. And now back to your '
                'regularly scheduled program.' % list(new_devs))
예제 #10
0
def DeviceInfo(serial):
    """Gathers info on a device via various adb calls.

  Args:
    serial: The serial of the attached device to construct info about.

  Returns:
    Tuple of device type, build id, report as a string, error messages, and
    boolean indicating whether or not device can be used for testing.
  """
    def AdbShellCmd(cmd):
        return GetCmdOutput('adb -s %s shell %s' % (serial, cmd),
                            shell=True).strip()

    device_type = AdbShellCmd('getprop ro.build.product')
    device_build = AdbShellCmd('getprop ro.build.id')
    device_build_type = AdbShellCmd('getprop ro.build.type')
    device_product_name = AdbShellCmd('getprop ro.product.name')

    setup_wizard_disabled = AdbShellCmd(
        'getprop ro.setupwizard.mode') == 'DISABLED'
    battery = AdbShellCmd('dumpsys battery')
    install_output = GetCmdOutput([
        '%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT,
        '--apk',
        '%s/build/android/CheckInstallApk-debug.apk' %
        constants.DIR_SOURCE_ROOT
    ])
    install_speed_found = re.findall('(\d+) KB/s', install_output)
    if install_speed_found:
        install_speed = int(install_speed_found[0])
    else:
        install_speed = 'Unknown'
    if 'Error' in battery:
        ac_power = 'Unknown'
        battery_level = 'Unknown'
        battery_temp = 'Unknown'
    else:
        ac_power = re.findall('AC powered: (\w+)', battery)[0]
        battery_level = int(re.findall('level: (\d+)', battery)[0])
        battery_temp = float(re.findall('temperature: (\d+)', battery)[0]) / 10
    report = [
        'Device %s (%s)' % (serial, device_type),
        '  Build: %s (%s)' %
        (device_build, AdbShellCmd('getprop ro.build.fingerprint')),
        '  Battery: %s%%' % battery_level,
        '  Battery temp: %s' % battery_temp,
        '  IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo '
                                         '| grep Device'
                                         "| awk '{print $4}'")[-6:],
        '  Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'),
        '  Install Speed: %s KB/s' % install_speed, ''
    ]

    errors = []
    if battery_level < 5:
        errors += ['Device critically low in battery. Do not use for testing.']
    if not setup_wizard_disabled and device_build_type != 'user':
        errors += ['Setup wizard not disabled. Was it provisioned correctly?']
    if device_product_name == 'mantaray' and ac_power != 'true':
        errors += ['Mantaray device not connected to AC power.']
    if install_speed < 800:
        errors += ['Device install speed too low. Do not use for testing.']

    # TODO(navabi): Determine if device status check step should fail on slow
    # install speed. The original CL caused the step to fail but was reverted
    # because it caused too many early failures. Determine if it was just flake.
    # Also, do not fail on 'Unknown' caused by offline device, because other
    # devices can still be used for tests.
    fail_step = (battery_level == 'Unknown' or battery_level >= 5)
    return device_type, device_build, '\n'.join(report), errors, fail_step