| # Copyright 2014 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 |
| |
| from autotest_lib.client.cros import constants |
| from autotest_lib.server import autotest |
| |
| POWER_DIR = '/var/lib/power_manager' |
| TMP_POWER_DIR = '/tmp/power_manager' |
| POWER_DEFAULTS = '/usr/share/power_manager/board_specific' |
| |
| RESUME_CTRL_RETRIES = 3 |
| RESUME_GRACE_PERIOD = 10 |
| XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60 |
| DARK_SUSPEND_MAX_DELAY_TIMEOUT_MILLISECONDS = 60000 |
| |
| |
| class DarkResumeUtils(object): |
| """Class containing common functionality for tests which exercise dark |
| resume pathways. We set up powerd to allow dark resume and also configure |
| the suspended devices so that the backchannel can stay up. We can also |
| check for the number of dark resumes that have happened in a particular |
| suspend request. |
| """ |
| |
| |
| def __init__(self, host, duration=0): |
| """Set up powerd preferences so we will properly go into dark resume, |
| and still be able to communicate with the DUT. |
| |
| @param host: the DUT to set up dark resume for |
| |
| """ |
| self._host = host |
| logging.info('Setting up dark resume preferences') |
| |
| # Make temporary directory, which will be used to hold |
| # temporary preferences. We want to avoid writing into |
| # /var/lib so we don't have to save any state. |
| logging.debug('Creating temporary powerd prefs at %s', TMP_POWER_DIR) |
| host.run('mkdir -p %s' % TMP_POWER_DIR) |
| |
| logging.debug('Enabling dark resume') |
| host.run('echo 0 > %s/disable_dark_resume' % TMP_POWER_DIR) |
| logging.debug('setting max dark suspend delay timeout to %d msecs', |
| DARK_SUSPEND_MAX_DELAY_TIMEOUT_MILLISECONDS) |
| host.run('echo %d > %s/max_dark_suspend_delay_timeout_ms' % |
| (DARK_SUSPEND_MAX_DELAY_TIMEOUT_MILLISECONDS, TMP_POWER_DIR)) |
| |
| # bind the tmp directory to the power preference directory |
| host.run('mount --bind %s %s' % (TMP_POWER_DIR, POWER_DIR)) |
| |
| logging.debug('Restarting powerd with new settings') |
| host.run('stop powerd; start powerd') |
| |
| logging.debug('Starting XMLRPC session to watch for dark resumes') |
| self._client_proxy = self._get_xmlrpc_proxy() |
| |
| |
| def teardown(self): |
| """Clean up changes made by DarkResumeUtils.""" |
| |
| logging.info('Tearing down dark resume preferences') |
| |
| logging.debug('Cleaning up temporary powerd bind mounts') |
| self._host.run('umount %s' % POWER_DIR) |
| |
| logging.debug('Restarting powerd to revert to old settings') |
| self._host.run('stop powerd; start powerd') |
| |
| |
| def suspend(self, suspend_secs): |
| """ Suspends the device for |suspend_secs| without blocking for resume. |
| |
| @param suspend_secs : Sleep for seconds. Sets a RTC alarm to wake the |
| system. |
| """ |
| logging.info('Suspending DUT (in background)...') |
| self._client_proxy.suspend_bg(suspend_secs) |
| |
| |
| def stop_resuspend_on_dark_resume(self, stop_resuspend=True): |
| """ |
| If |stop_resuspend| is True, stops re-suspend on seeing a dark resume. |
| """ |
| self._client_proxy.set_stop_resuspend(stop_resuspend) |
| |
| |
| def count_dark_resumes(self): |
| """Return the number of dark resumes since the beginning of the test. |
| |
| This method will raise an error if the DUT is not reachable. |
| |
| @return the number of dark resumes counted by this DarkResumeUtils |
| |
| """ |
| return self._client_proxy.get_dark_resume_count() |
| |
| |
| |
| def host_has_lid(self): |
| """Returns True if the DUT has a lid.""" |
| return self._client_proxy.has_lid() |
| |
| |
| def _get_xmlrpc_proxy(self): |
| """Get a dark resume XMLRPC proxy for the host this DarkResumeUtils is |
| attached to. |
| |
| The returned object has no particular type. Instead, when you call |
| a method on the object, it marshalls the objects passed as arguments |
| and uses them to make RPCs on the remote server. Thus, you should |
| read dark_resume_xmlrpc_server.py to find out what methods are supported. |
| |
| @return proxy object for remote XMLRPC server. |
| |
| """ |
| # Make sure the client library is on the device so that the proxy |
| # code is there when we try to call it. |
| client_at = autotest.Autotest(self._host) |
| client_at.install() |
| # Start up the XMLRPC proxy on the client |
| proxy = self._host.rpc_server_tracker.xmlrpc_connect( |
| constants.DARK_RESUME_XMLRPC_SERVER_COMMAND, |
| constants.DARK_RESUME_XMLRPC_SERVER_PORT, |
| command_name= |
| constants.DARK_RESUME_XMLRPC_SERVER_CLEANUP_PATTERN, |
| ready_test_name= |
| constants.DARK_RESUME_XMLRPC_SERVER_READY_METHOD, |
| timeout_seconds=XMLRPC_BRINGUP_TIMEOUT_SECONDS) |
| return proxy |