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 5import logging, os, tempfile, threading 6from autotest_lib.client.bin import test, utils 7from autotest_lib.client.common_lib import error 8from autotest_lib.client.common_lib.cros import chrome 9 10POWER_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 21SUSPEND_TIMEOUT_MS = 30000 22 23 24class 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 # create directory for temporary settings 42 self.tempdir = tempfile.mkdtemp(prefix='IdleSuspend.') 43 logging.info('using temporary directory %s', self.tempdir) 44 45 # override power manager settings 46 for key, val in POWER_MANAGER_SETTINGS.iteritems(): 47 logging.info('overriding %s to %s', key, val) 48 tmp_path = '%s/%s' % (self.tempdir, key) 49 mount_path = '/usr/share/power_manager/%s' % key 50 utils.write_one_line(tmp_path, str(val)) 51 utils.run('mount --bind %s %s' % (tmp_path, mount_path)) 52 self.mounts.append(mount_path) 53 54 # override /sys/power/state with fifo 55 fifo_path = '%s/sys_power_state' % self.tempdir 56 os.mkfifo(fifo_path) 57 utils.run('mount --bind %s /sys/power/state' % fifo_path) 58 self.mounts.append('/sys/power/state') 59 60 61 def wait_for_suspend(self): 62 # block reading new power state from /sys/power/state 63 sys_power_state = open('/sys/power/state') 64 self.new_power_state = sys_power_state.read() 65 logging.info('new power state: %s', self.new_power_state) 66 67 68 def run_once(self): 69 with chrome.Chrome(): 70 # stop power manager before reconfiguring 71 logging.info('stopping powerd') 72 utils.run('stop powerd') 73 74 # override power manager settings 75 self.setup_power_manager() 76 77 # start thread to wait for suspend 78 self.new_power_state = None 79 thread = threading.Thread(target=self.wait_for_suspend) 80 thread.start() 81 82 # restart powerd to pick up new settings 83 logging.info('restarting powerd') 84 utils.run('start powerd') 85 86 # wait for idle suspend 87 thread.join(SUSPEND_TIMEOUT_MS / 1000.) 88 89 if thread.is_alive(): 90 # join timed out - powerd didn't write to /sys/power/state 91 raise error.TestFail('timed out waiting for suspend') 92 93 if self.new_power_state is None: 94 # probably an exception in the thread, check the log 95 raise error.TestError('reader thread crashed') 96 97 if self.new_power_state.strip() != 'mem': 98 # oops, power manager wrote something other than "mem" 99 err_str = 'bad power state written to /sys/power/state' 100 raise error.TestFail(err_str) 101 102 103 def cleanup(self): 104 # restore original power manager settings 105 for mount in self.mounts: 106 logging.info('restoring %s', mount) 107 utils.run('umount -l %s' % mount) 108 109 # restart powerd to pick up original settings 110 logging.info('restarting powerd') 111 utils.run('restart powerd') 112 113 super(power_IdleSuspend, self).cleanup() 114