# Copyright (c) 2012 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 logging, os, tempfile, threading from autotest_lib.client.bin import test, utils from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib.cros import chrome POWER_MANAGER_SETTINGS = { 'plugged_dim_ms': 1000, 'plugged_off_ms': 5000, 'plugged_suspend_ms': 10000, 'unplugged_dim_ms': 1000, 'unplugged_off_ms': 5000, 'unplugged_suspend_ms': 10000, 'disable_idle_suspend': 0, 'ignore_external_policy': 1, } SUSPEND_TIMEOUT_MS = 30000 class power_IdleSuspend(test.test): """ Verify power manager tries to suspend while idle. This test does not actually allow the system to suspend. Instead, it replaces /sys/power/state with a pipe and waits until "mem" is written to it. Such a write would normally cause suspend. """ version = 1 mounts = () def initialize(self): super(power_IdleSuspend, self).initialize() self.mounts = [] def setup_power_manager(self): """Configures powerd for the test.""" # create directory for temporary settings self.tempdir = tempfile.mkdtemp(prefix='IdleSuspend.') logging.info('using temporary directory %s', self.tempdir) # override power manager settings for key, val in POWER_MANAGER_SETTINGS.iteritems(): logging.info('overriding %s to %s', key, val) tmp_path = '%s/%s' % (self.tempdir, key) mount_path = '/usr/share/power_manager/%s' % key utils.write_one_line(tmp_path, str(val)) utils.run('mount --bind %s %s' % (tmp_path, mount_path)) self.mounts.append(mount_path) # override /sys/power/state with fifo fifo_path = '%s/sys_power_state' % self.tempdir os.mkfifo(fifo_path) utils.run('mount --bind %s /sys/power/state' % fifo_path) self.mounts.append('/sys/power/state') def wait_for_suspend(self): """Thread callback to watch for powerd to announce idle transition.""" # block reading new power state from /sys/power/state sys_power_state = open('/sys/power/state') self.new_power_state = sys_power_state.read() logging.info('new power state: %s', self.new_power_state) def run_once(self): with chrome.Chrome(): # stop power manager before reconfiguring logging.info('stopping powerd') utils.run('stop powerd') # override power manager settings self.setup_power_manager() # start thread to wait for suspend self.new_power_state = None thread = threading.Thread(target=self.wait_for_suspend) thread.start() # touch OOBE completed file so powerd won't ignore idle state. utils.run('touch /home/chronos/.oobe_completed') # restart powerd to pick up new settings logging.info('restarting powerd') utils.run('start powerd') # wait for idle suspend thread.join(SUSPEND_TIMEOUT_MS / 1000.) if thread.is_alive(): # join timed out - powerd didn't write to /sys/power/state raise error.TestFail('timed out waiting for suspend') if self.new_power_state is None: # probably an exception in the thread, check the log raise error.TestError('reader thread crashed') if self.new_power_state.strip() not in ['mem', 'freeze']: err_str = 'bad power state written to /sys/power/state' raise error.TestFail(err_str) def cleanup(self): # restore original power manager settings for mount in self.mounts: logging.info('restoring %s', mount) utils.run('umount -l %s' % mount) # restart powerd to pick up original settings logging.info('restarting powerd') utils.run('restart powerd') super(power_IdleSuspend, self).cleanup()