Home | History | Annotate | Download | only in power_ProbeDriver
      1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import glob, os
      6 from autotest_lib.client.bin import test
      7 from autotest_lib.client.common_lib import error, utils
      8 
      9 class power_ProbeDriver(test.test):
     10     """Confirms that AC driver is loaded and functioning
     11     unless device is AC only."""
     12     version = 1
     13     power_supply_path = '/sys/class/power_supply/*'
     14 
     15     def run_once(self, test_which='Mains'):
     16         # This test doesn't apply to systems that run on AC only.
     17         cmd = "mosys psu type"
     18         if utils.system_output(cmd, ignore_status=True).strip() == "AC_only":
     19             return
     20         ac_paths  = []
     21         bat_paths = []
     22         # Gather power supplies
     23         for path in glob.glob(power_ProbeDriver.power_supply_path):
     24             type_path = os.path.join(path, 'type')
     25             if not os.path.exists(type_path):
     26                 continue
     27             # With the advent of USB Type-C, mains power might show up as
     28             # one of several variants of USB.
     29             psu_type = utils.read_one_line(type_path)
     30             if any( [psu_type == 'Mains', psu_type == 'USB',
     31                      psu_type == 'USB_DCP', psu_type == 'USB_CDP',
     32                      psu_type == 'USB_C', psu_type == 'USB_PD',
     33                      psu_type == 'USB_PD_DRP'] ):
     34                 ac_paths.append(path)
     35             elif psu_type == 'Battery':
     36                 bat_paths.append(path)
     37         run_dict = { 'Mains': self.run_ac, 'Battery': self.run_bat }
     38         run = run_dict.get(test_which)
     39         if run:
     40             run(ac_paths, bat_paths)
     41         else:
     42             raise error.TestNAError('Unknown test type: %s' % test_which)
     43 
     44     def run_ac(self, ac_paths, bat_paths):
     45         """Checks AC driver.
     46 
     47         @param ac_paths: sysfs AC entries
     48         @param bat_paths: sysfs battery entries
     49         """
     50         if not ac_paths:
     51             raise error.TestFail('No line power devices found in %s' %
     52                                  power_ProbeDriver.power_supply_path)
     53 
     54         if not any([self._online(ac_path) for ac_path in ac_paths]):
     55             raise error.TestFail('Line power is not connected')
     56 
     57         # if there are batteries, test fails if one of them is discharging
     58         # note: any([]) == False, so we don't have to test len(bat_paths) > 0
     59         if any(self._is_discharging(bat_path, ac_paths)
     60                for bat_path in bat_paths
     61                if self._present(bat_path)):
     62             raise error.TestFail('One of batteries is discharging')
     63 
     64     def run_bat(self, ac_paths, bat_paths):
     65         """ Checks batteries.
     66 
     67         @param ac_paths: sysfs AC entries
     68         @param bat_paths: sysfs battery entries
     69         """
     70         if len(bat_paths) == 0:
     71             raise error.TestFail('Find no batteries')
     72 
     73         presented = [bat_path for bat_path in bat_paths
     74                      if self._present(bat_path)]
     75         if len(presented) == 0:
     76             raise error.TestFail('No batteries are presented')
     77 
     78         if all(not self._is_discharging(bat_path, ac_paths) for bat_path
     79                in presented):
     80             raise error.TestFail('No batteries are discharging')
     81 
     82         if any(self._online(ac_path) for ac_path in ac_paths):
     83             raise error.TestFail('One of ACs is online')
     84 
     85     def _online(self, ac_path):
     86         online_path = os.path.join(ac_path, 'online')
     87         if not os.path.exists(online_path):
     88             raise error.TestFail('online path does not exist: %s' % online_path)
     89         online = utils.read_one_line(online_path)
     90         return online == '1'
     91 
     92     def _has_property(self, bat_path, field):
     93         """
     94         Indicates whether a battery sysfs has the given field.
     95 
     96         Fields:
     97         str     bat_path:           Battery sysfs path
     98         str     field:              Sysfs field to test for.
     99 
    100         Return value:
    101         bool    True if the field exists, False otherwise.
    102         """
    103         return os.path.exists(os.path.join(bat_path, field))
    104 
    105     def _read_property(self, bat_path, field):
    106         """
    107         Reads the contents of a sysfs field for a battery sysfs.
    108 
    109         Fields:
    110         str     bat_path:           Battery sysfs path
    111         str     field:              Sysfs field to read.
    112 
    113         Return value:
    114         str     The contents of the sysfs field.
    115         """
    116         property_path = os.path.join(bat_path, field)
    117         if not self._has_property(bat_path, field):
    118             raise error.TestNAError('Path not found: %s' % property_path)
    119         return utils.read_one_line(property_path)
    120 
    121     def _present(self, bat_path):
    122         """
    123         Indicates whether a battery is present, based on sysfs status.
    124 
    125         Fields:
    126         str     bat_path:           Battery sysfs path
    127 
    128         Return value:
    129         bool    True if the battery is present, False otherwise.
    130         """
    131         return self._read_property(bat_path, 'present') == '1'
    132 
    133     def _is_discharging(self, bat_path, ac_paths):
    134         """
    135         Indicates whether a battery is discharging, based on sysfs status.
    136 
    137         Sometimes the sysfs will not show status='Discharging' when actually
    138         discharging.  So this function looks at both battery sysfs and AC sysfs.
    139         If the battery is discharging, there will be no line power and the
    140         power/current draw will be nonzero.
    141 
    142         Fields:
    143         str     bat_path:           Battery sysfs path
    144         str[]   ac_paths:           List of AC sysfs paths
    145 
    146         Return value:
    147         bool    True if the battery is discharging, False otherwise.
    148         """
    149         if self._read_property(bat_path, 'status') == 'Discharging':
    150             return True
    151         if all(not self._online(ac_path) for ac_path in ac_paths):
    152             if (self._has_property(bat_path, 'power_now') and
    153                 self._read_property(bat_path, 'power_now') != '0'):
    154                 return True
    155             if (self._has_property(bat_path, 'current_now') and
    156                 self._read_property(bat_path, 'current_now') != '0'):
    157                 return True
    158         return False
    159