Home | History | Annotate | Download | only in power_IdleSuspend
      1 # Copyright (c) 2012 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 logging, os, tempfile, threading
      6 from autotest_lib.client.bin import test, utils
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.client.common_lib.cros import chrome
      9 
     10 POWER_MANAGER_SETTINGS = {
     11     'plugged_dim_ms': 1000,
     12     'plugged_off_ms': 5000,
     13     'plugged_suspend_ms': 10000,
     14     'unplugged_dim_ms': 1000,
     15     'unplugged_off_ms': 5000,
     16     'unplugged_suspend_ms': 10000,
     17     'disable_idle_suspend': 0,
     18     'ignore_external_policy': 1,
     19 }
     20 
     21 SUSPEND_TIMEOUT_MS = 30000
     22 
     23 
     24 class power_IdleSuspend(test.test):
     25     """
     26     Verify power manager tries to suspend while idle.
     27 
     28     This test does not actually allow the system to suspend. Instead,
     29     it replaces /sys/power/state with a pipe and waits until "mem" is
     30     written to it. Such a write would normally cause suspend.
     31     """
     32     version = 1
     33     mounts = ()
     34 
     35     def initialize(self):
     36         super(power_IdleSuspend, self).initialize()
     37         self.mounts = []
     38 
     39 
     40     def setup_power_manager(self):
     41         """Configures powerd for the test."""
     42         # create directory for temporary settings
     43         self.tempdir = tempfile.mkdtemp(prefix='IdleSuspend.')
     44         logging.info('using temporary directory %s', self.tempdir)
     45 
     46         # override power manager settings
     47         for key, val in POWER_MANAGER_SETTINGS.iteritems():
     48             logging.info('overriding %s to %s', key, val)
     49             tmp_path = '%s/%s' % (self.tempdir, key)
     50             mount_path = '/usr/share/power_manager/%s' % key
     51             utils.write_one_line(tmp_path, str(val))
     52             utils.run('mount --bind %s %s' % (tmp_path, mount_path))
     53             self.mounts.append(mount_path)
     54 
     55         # override /sys/power/state with fifo
     56         fifo_path = '%s/sys_power_state' % self.tempdir
     57         os.mkfifo(fifo_path)
     58         utils.run('mount --bind %s /sys/power/state' % fifo_path)
     59         self.mounts.append('/sys/power/state')
     60 
     61 
     62     def wait_for_suspend(self):
     63         """Thread callback to watch for powerd to announce idle transition."""
     64         # block reading new power state from /sys/power/state
     65         sys_power_state = open('/sys/power/state')
     66         self.new_power_state = sys_power_state.read()
     67         logging.info('new power state: %s', self.new_power_state)
     68 
     69 
     70     def run_once(self):
     71         with chrome.Chrome():
     72             # stop power manager before reconfiguring
     73             logging.info('stopping powerd')
     74             utils.run('stop powerd')
     75 
     76             # override power manager settings
     77             self.setup_power_manager()
     78 
     79             # start thread to wait for suspend
     80             self.new_power_state = None
     81             thread = threading.Thread(target=self.wait_for_suspend)
     82             thread.start()
     83 
     84             # touch OOBE completed file so powerd won't ignore idle state.
     85             utils.run('touch /home/chronos/.oobe_completed')
     86 
     87             # restart powerd to pick up new settings
     88             logging.info('restarting powerd')
     89             utils.run('start powerd')
     90 
     91             # wait for idle suspend
     92             thread.join(SUSPEND_TIMEOUT_MS / 1000.)
     93 
     94             if thread.is_alive():
     95                 # join timed out - powerd didn't write to /sys/power/state
     96                 raise error.TestFail('timed out waiting for suspend')
     97 
     98             if self.new_power_state is None:
     99                 # probably an exception in the thread, check the log
    100                 raise error.TestError('reader thread crashed')
    101 
    102             if self.new_power_state.strip() not in ['mem', 'freeze']:
    103                 err_str = 'bad power state written to /sys/power/state'
    104                 raise error.TestFail(err_str)
    105 
    106 
    107     def cleanup(self):
    108         # restore original power manager settings
    109         for mount in self.mounts:
    110             logging.info('restoring %s', mount)
    111             utils.run('umount -l %s' % mount)
    112 
    113         # restart powerd to pick up original settings
    114         logging.info('restarting powerd')
    115         utils.run('restart powerd')
    116 
    117         super(power_IdleSuspend, self).cleanup()
    118