blob: f0b999474ef7132c872a94d0bdcba90b70ed45e6 [file] [log] [blame]
# 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()