普通文本  |  159行  |  5.98 KB

# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import glob, os
from autotest_lib.client.bin import test
from autotest_lib.client.common_lib import error, utils

class power_ProbeDriver(test.test):
    """Confirms that AC driver is loaded and functioning
    unless device is AC only."""
    version = 1
    power_supply_path = '/sys/class/power_supply/*'

    def run_once(self, test_which='Mains'):
        # This test doesn't apply to systems that run on AC only.
        cmd = "mosys psu type"
        if utils.system_output(cmd, ignore_status=True).strip() == "AC_only":
            return
        ac_paths  = []
        bat_paths = []
        # Gather power supplies
        for path in glob.glob(power_ProbeDriver.power_supply_path):
            type_path = os.path.join(path, 'type')
            if not os.path.exists(type_path):
                continue
            # With the advent of USB Type-C, mains power might show up as
            # one of several variants of USB.
            psu_type = utils.read_one_line(type_path)
            if any( [psu_type == 'Mains', psu_type == 'USB',
                     psu_type == 'USB_DCP', psu_type == 'USB_CDP',
                     psu_type == 'USB_TYPE_C', psu_type == 'USB_PD',
                     psu_type == 'USB_PD_DRP'] ):
                ac_paths.append(path)
            elif psu_type == 'Battery':
                bat_paths.append(path)
        run_dict = { 'Mains': self.run_ac, 'Battery': self.run_bat }
        run = run_dict.get(test_which)
        if run:
            run(ac_paths, bat_paths)
        else:
            raise error.TestNAError('Unknown test type: %s' % test_which)

    def run_ac(self, ac_paths, bat_paths):
        """Checks AC driver.

        @param ac_paths: sysfs AC entries
        @param bat_paths: sysfs battery entries
        """
        if not ac_paths:
            raise error.TestFail('No line power devices found in %s' %
                                 power_supply_path)

        if not any([self._online(ac_path) for ac_path in ac_paths]):
            raise error.TestFail('Line power is not connected')

        # if there are batteries, test fails if one of them is discharging
        # note: any([]) == False, so we don't have to test len(bat_paths) > 0
        if any(self._is_discharging(bat_path, ac_paths)
               for bat_path in bat_paths
               if self._present(bat_path)):
            raise error.TestFail('One of batteries is discharging')

    def run_bat(self, ac_paths, bat_paths):
        """ Checks batteries.

        @param ac_paths: sysfs AC entries
        @param bat_paths: sysfs battery entries
        """
        if len(bat_paths) == 0:
            raise error.TestFail('Find no batteries')

        presented = [bat_path for bat_path in bat_paths
                     if self._present(bat_path)]
        if len(presented) == 0:
            raise error.TestFail('No batteries are presented')

        if all(not self._is_discharging(bat_path, ac_paths) for bat_path
               in presented):
            raise error.TestFail('No batteries are discharging')

        if any(self._online(ac_path) for ac_path in ac_paths):
            raise error.TestFail('One of ACs is online')

    def _online(self, ac_path):
        online_path = os.path.join(ac_path, 'online')
        if not os.path.exists(online_path):
            raise error.TestFail('online path does not exist: %s' % online_path)
        online = utils.read_one_line(online_path)
        return online == '1'

    def _has_property(self, bat_path, field):
        """
        Indicates whether a battery sysfs has the given field.

        Fields:
        str     bat_path:           Battery sysfs path
        str     field:              Sysfs field to test for.

        Return value:
        bool    True if the field exists, False otherwise.
        """
        return os.path.exists(os.path.join(bat_path, field))

    def _read_property(self, bat_path, field):
        """
        Reads the contents of a sysfs field for a battery sysfs.

        Fields:
        str     bat_path:           Battery sysfs path
        str     field:              Sysfs field to read.

        Return value:
        str     The contents of the sysfs field.
        """
        property_path = os.path.join(bat_path, field)
        if not self._has_property(bat_path, field):
            raise error.TestNAError('Path not found: %s' % property_path)
        return utils.read_one_line(property_path)

    def _present(self, bat_path):
        """
        Indicates whether a battery is present, based on sysfs status.

        Fields:
        str     bat_path:           Battery sysfs path

        Return value:
        bool    True if the battery is present, False otherwise.
        """
        return self._read_property(bat_path, 'present') == '1'

    def _is_discharging(self, bat_path, ac_paths):
        """
        Indicates whether a battery is discharging, based on sysfs status.

        Sometimes the sysfs will not show status='Discharging' when actually
        discharging.  So this function looks at both battery sysfs and AC sysfs.
        If the battery is discharging, there will be no line power and the
        power/current draw will be nonzero.

        Fields:
        str     bat_path:           Battery sysfs path
        str[]   ac_paths:           List of AC sysfs paths

        Return value:
        bool    True if the battery is discharging, False otherwise.
        """
        if self._read_property(bat_path, 'status') == 'Discharging':
            return True
        if all(not self._online(ac_path) for ac_path in ac_paths):
            if (self._has_property(bat_path, 'power_now') and
                self._read_property(bat_path, 'power_now') != '0'):
                return True
            if (self._has_property(bat_path, 'current_now') and
                self._read_property(bat_path, 'current_now') != '0'):
                return True
        return False