1# Copyright 2014 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 6 7from autotest_lib.client.cros import constants 8from autotest_lib.server import autotest 9 10POWER_DIR = '/var/lib/power_manager' 11TMP_POWER_DIR = '/tmp/power_manager' 12POWER_DEFAULTS = '/usr/share/power_manager/board_specific' 13 14RESUME_CTRL_RETRIES = 3 15RESUME_GRACE_PERIOD = 10 16XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60 17DARK_SUSPEND_MAX_DELAY_TIMEOUT_MILLISECONDS = 60000 18 19 20class DarkResumeUtils(object): 21 """Class containing common functionality for tests which exercise dark 22 resume pathways. We set up powerd to allow dark resume and also configure 23 the suspended devices so that the backchannel can stay up. We can also 24 check for the number of dark resumes that have happened in a particular 25 suspend request. 26 """ 27 28 29 def __init__(self, host, duration=0): 30 """Set up powerd preferences so we will properly go into dark resume, 31 and still be able to communicate with the DUT. 32 33 @param host: the DUT to set up dark resume for 34 35 """ 36 self._host = host 37 logging.info('Setting up dark resume preferences') 38 39 # Make temporary directory, which will be used to hold 40 # temporary preferences. We want to avoid writing into 41 # /var/lib so we don't have to save any state. 42 logging.debug('Creating temporary powerd prefs at %s', TMP_POWER_DIR) 43 host.run('mkdir -p %s' % TMP_POWER_DIR) 44 45 logging.debug('Enabling dark resume') 46 host.run('echo 0 > %s/disable_dark_resume' % TMP_POWER_DIR) 47 logging.debug('setting max dark suspend delay timeout to %d msecs', 48 DARK_SUSPEND_MAX_DELAY_TIMEOUT_MILLISECONDS) 49 host.run('echo %d > %s/max_dark_suspend_delay_timeout_ms' % 50 (DARK_SUSPEND_MAX_DELAY_TIMEOUT_MILLISECONDS, TMP_POWER_DIR)) 51 52 # bind the tmp directory to the power preference directory 53 host.run('mount --bind %s %s' % (TMP_POWER_DIR, POWER_DIR)) 54 55 logging.debug('Restarting powerd with new settings') 56 host.run('stop powerd; start powerd') 57 58 logging.debug('Starting XMLRPC session to watch for dark resumes') 59 self._client_proxy = self._get_xmlrpc_proxy() 60 61 62 def teardown(self): 63 """Clean up changes made by DarkResumeUtils.""" 64 65 logging.info('Tearing down dark resume preferences') 66 67 logging.debug('Cleaning up temporary powerd bind mounts') 68 self._host.run('umount %s' % POWER_DIR) 69 70 logging.debug('Restarting powerd to revert to old settings') 71 self._host.run('stop powerd; start powerd') 72 73 74 def suspend(self, suspend_secs): 75 """ Suspends the device for |suspend_secs| without blocking for resume. 76 77 @param suspend_secs : Sleep for seconds. Sets a RTC alarm to wake the 78 system. 79 """ 80 logging.info('Suspending DUT (in background)...') 81 self._client_proxy.suspend_bg(suspend_secs) 82 83 84 def stop_resuspend_on_dark_resume(self, stop_resuspend=True): 85 """ 86 If |stop_resuspend| is True, stops re-suspend on seeing a dark resume. 87 """ 88 self._client_proxy.set_stop_resuspend(stop_resuspend) 89 90 91 def count_dark_resumes(self): 92 """Return the number of dark resumes since the beginning of the test. 93 94 This method will raise an error if the DUT is not reachable. 95 96 @return the number of dark resumes counted by this DarkResumeUtils 97 98 """ 99 return self._client_proxy.get_dark_resume_count() 100 101 102 103 def host_has_lid(self): 104 """Returns True if the DUT has a lid.""" 105 return self._client_proxy.has_lid() 106 107 108 def _get_xmlrpc_proxy(self): 109 """Get a dark resume XMLRPC proxy for the host this DarkResumeUtils is 110 attached to. 111 112 The returned object has no particular type. Instead, when you call 113 a method on the object, it marshalls the objects passed as arguments 114 and uses them to make RPCs on the remote server. Thus, you should 115 read dark_resume_xmlrpc_server.py to find out what methods are supported. 116 117 @return proxy object for remote XMLRPC server. 118 119 """ 120 # Make sure the client library is on the device so that the proxy 121 # code is there when we try to call it. 122 client_at = autotest.Autotest(self._host) 123 client_at.install() 124 # Start up the XMLRPC proxy on the client 125 proxy = self._host.rpc_server_tracker.xmlrpc_connect( 126 constants.DARK_RESUME_XMLRPC_SERVER_COMMAND, 127 constants.DARK_RESUME_XMLRPC_SERVER_PORT, 128 command_name= 129 constants.DARK_RESUME_XMLRPC_SERVER_CLEANUP_PATTERN, 130 ready_test_name= 131 constants.DARK_RESUME_XMLRPC_SERVER_READY_METHOD, 132 timeout_seconds=XMLRPC_BRINGUP_TIMEOUT_SECONDS) 133 return proxy 134