1# Copyright 2016 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 6import time 7 8from autotest_lib.client.bin import utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.cros import cryptohome 11from autotest_lib.client.cros.enterprise import enterprise_policy_base 12from autotest_lib.client.cros.graphics import graphics_utils 13from autotest_lib.client.cros.power import power_status, power_utils 14 15 16class policy_PowerManagementIdleSettings( 17 enterprise_policy_base.EnterprisePolicyTest): 18 """ 19 Test effect of PowerManagementIdleSettings policy on Chrome OS behavior. 20 21 This test verifies the effect of the PowerManagementIdleSettings user 22 policy on specific Chrome OS client behaviors. It tests two valid values 23 for the IdleAction property: 'DoNothing' and Not set, with three test 24 cases: DoNothing_Continue, NotSet_Sleep, and Logout_EndSession. It also 25 verifies that the screen dims after ScreenDim delay, and then turns off 26 after ScreenOff delay (both delays in milliseconds). 27 28 Note: Valid IdleAction values are 'DoNothing', 'Suspend', 'Logout', and 29 'Shutdown'. This test exercises only the DoNothing and Logout actions. 30 Suspend is tested by enterprise_PowerManager.py. Shutdown can be tested 31 only using a Server-side AutoTest. 32 33 Chrome reports user activity to the power manager at most every 5 seconds. 34 To accomodate potential delays, the test pads the idle-action delay with 35 a 5 second activity report interval. 36 37 Several supporting policies are necessary to facillitate testing, or to 38 make testing more reliable. These policies are listed below with a brief 39 description of the set value. 40 - WaitForInitialUserActivity=False so idle timer starts immediately after 41 session starts. 42 - UserActivityScreenDimDelayScale=100 to prevent increase delays when 43 user activity occurs after screen dim. 44 - ChromeOsLockOnIdleSuspend=False to prevent screen lock upon suspend. 45 - AllowScreenLock=False to prevent manual screen lock. Will not affect 46 this test, but is the safest setting. 47 - AllowScreenWakeLocks=False to ignore 'keep awake' requests. Since wake 48 locks are not requested during this test, ignoring them is unnecessary. 49 But for safety we ignore them when testing suspend. 50 - LidCloseAction=3 to invoke no action upon (accidental) lid closure. 51 - ResoreOnStartup* polices are set to display the settings and policy 52 pages. This is useful when debugging failures. 53 54 """ 55 version = 1 56 57 def initialize(self, **kwargs): 58 """Set up local variables and ensure device is on AC power.""" 59 self._initialize_test_constants() 60 self._power_status = power_status.get_status() 61 if not self._power_status.on_ac(): 62 raise error.TestNAError('Test must be run with DUT on AC power.') 63 self._backlight = power_utils.Backlight() 64 super(policy_PowerManagementIdleSettings, self).initialize(**kwargs) 65 66 def _initialize_test_constants(self): 67 self.POLICY_NAME = 'PowerManagementIdleSettings' 68 self.SCREEN_SETTLE_TIME = 0.3 69 self.SCREEN_DIM_DELAY = 4 70 self.IDLE_WARNING_DELAY = 6 71 self.SCREEN_OFF_DELAY = 8 72 self.IDLE_ACTION_DELAY = 10 73 self.ACTIVITY_REPORT_INTERVAL = 5 74 self.IDLE_ACTION_NOTSET = { 75 'AC': { 76 'Delays': { 77 'ScreenDim': (self.SCREEN_DIM_DELAY * 1000), 78 'IdleWarning': (self.IDLE_WARNING_DELAY * 1000), 79 'ScreenOff': (self.SCREEN_OFF_DELAY * 1000), 80 'Idle': (self.IDLE_ACTION_DELAY * 1000) 81 } 82 } 83 } 84 self.IDLE_ACTION_DONOTHING = { 85 'AC': { 86 'Delays': { 87 'ScreenDim': (self.SCREEN_DIM_DELAY * 1000), 88 'IdleWarning': (self.IDLE_WARNING_DELAY * 1000), 89 'ScreenOff': (self.SCREEN_OFF_DELAY * 1000), 90 'Idle': (self.IDLE_ACTION_DELAY * 1000) 91 }, 92 'IdleAction': 'DoNothing' 93 } 94 } 95 self.IDLE_ACTION_LOGOUT = { 96 'AC': { 97 'Delays': { 98 'ScreenDim': (self.SCREEN_DIM_DELAY * 1000), 99 'IdleWarning': (self.IDLE_WARNING_DELAY * 1000), 100 'ScreenOff': (self.SCREEN_OFF_DELAY * 1000), 101 'Idle': (self.IDLE_ACTION_DELAY * 1000) 102 }, 103 'IdleAction': 'Logout' 104 } 105 } 106 self.TEST_CASES = { 107 'NotSet_Sleep': self.IDLE_ACTION_NOTSET, 108 'DoNothing_Continue': self.IDLE_ACTION_DONOTHING, 109 'Logout_EndSession': self.IDLE_ACTION_LOGOUT 110 } 111 self.STARTUP_URLS = ['chrome://settings', 'chrome://policy'] 112 self.SUPPORTING_POLICIES = { 113 'WaitForInitialUserActivity': True, 114 'UserActivityScreenDimDelayScale': 100, 115 'ChromeOsLockOnIdleSuspend': False, 116 'AllowScreenLock': False, 117 'AllowScreenWakeLocks': False, 118 'LidCloseAction': 3, 119 'RestoreOnStartup': 4, 120 'RestoreOnStartupURLs': self.STARTUP_URLS 121 } 122 123 124 def elapsed_time(self, start_time): 125 """Get time elapsed since |start_time|. 126 127 @param start_time: clock time from which elapsed time is measured. 128 @returns time elapsed since the start time. 129 """ 130 return time.time() - start_time 131 132 133 def _simulate_user_activity(self): 134 """Inject user activity via D-bus to restart idle timer. 135 136 Note that if the screen has gone black, these use activities will 137 wake up the display again. However, they will not wake up a screen 138 that has merely been dimmed. 139 140 """ 141 graphics_utils.click_mouse() # Note: Duration is 0.4 seconds. 142 graphics_utils.press_keys(['KEY_LEFTCTRL']) 143 144 145 def _wait_for_login_status(self, attribute, value, timeout): 146 """Return when attribute has value, or its current value on timeout. 147 148 Login_status is a dictionary of attributes that describe the login 149 status of the current session. It contains values for the following 150 attributes: isLoggedIn, isRegularUser, isOwner, isKiosk, isGuest, 151 isScreenLocked, userImage, email, and displayEmail. 152 153 @param attribute: String attribute key to be measured. 154 @param value: Boolean attribute value expected. 155 @param timeout: integer seconds till timeout. 156 @returns dict of login status. 157 158 """ 159 attribute_value = utils.wait_for_value( 160 lambda: self.cr.login_status[attribute], 161 expected_value=value, 162 timeout_sec=timeout) 163 return attribute_value 164 165 166 def _poll_until_user_is_logged_out(self, timeout): 167 """Return True when user logs out, False when user remains logged in. 168 169 @returns boolean of user logged out status. 170 171 """ 172 my_result = utils.poll_for_condition( 173 lambda: not cryptohome.is_vault_mounted(user=self.username, 174 allow_fail=True), 175 exception=None, 176 timeout=timeout, 177 sleep_interval=2, 178 desc='Polling for user to be logged out.') 179 return my_result 180 181 182 def _set_brightness_to_maximum(self): 183 """Set screen to maximum brightness.""" 184 max_level = self._backlight.get_max_level() 185 self._backlight.set_level(max_level) 186 187 188 def _wait_for_brightness_change(self, timeout): 189 """Return screen brightness on update, or current value on timeout. 190 191 @returns float of screen brightness percentage. 192 193 """ 194 initial_brightness = self._backlight.get_percent() 195 current_brightness = utils.wait_for_value_changed( 196 lambda: self._backlight.get_percent(), 197 old_value=initial_brightness, 198 timeout_sec=timeout) 199 if current_brightness != initial_brightness: 200 time.sleep(self.SCREEN_SETTLE_TIME) 201 current_brightness = self._backlight.get_percent() 202 return current_brightness 203 204 205 def _test_idle_action(self, policy_value): 206 """ 207 Verify CrOS enforces PowerManagementIdleSettings policy value. 208 209 @param policy_value: policy value for this case. 210 @raises: TestFail if idle actions are not performed after their 211 specified delays. 212 213 """ 214 logging.info('Running _test_idle_action(%s)', policy_value) 215 216 # Wait until UI settles down with user logged in. 217 user_is_logged_in = self._wait_for_login_status( 218 'isLoggedIn', True, self.IDLE_ACTION_DELAY) 219 if not user_is_logged_in: 220 raise error.TestFail('User must be logged in at start.') 221 222 # Set screen to maxiumum brightness. 223 self._set_brightness_to_maximum() 224 max_brightness = self._backlight.get_percent() 225 logging.info('Brightness maximized to: %.2f', max_brightness) 226 227 # Induce user activity to start idle timer. 228 self._simulate_user_activity() 229 start_time = time.time() 230 231 # Verify screen is dimmed after expected delay. 232 seconds_to_dim = ( 233 self.SCREEN_DIM_DELAY - self.elapsed_time(start_time)) 234 dim_brightness = self._wait_for_brightness_change(seconds_to_dim) 235 dim_elapsed_time = self.elapsed_time(start_time) 236 logging.info(' Brightness dimmed to: %.2f, ', dim_brightness) 237 logging.info(' after %s seconds.', dim_elapsed_time) 238 if not (dim_brightness < max_brightness and dim_brightness > 0.0): 239 raise error.TestFail('Screen did not dim on delay.') 240 241 # Verify screen is turned off after expected delay. 242 seconds_to_off = ( 243 self.SCREEN_OFF_DELAY - self.elapsed_time(start_time)) 244 off_brightness = self._wait_for_brightness_change(seconds_to_off) 245 off_elapsed_time = self.elapsed_time(start_time) 246 logging.info(' Brightness off to: %.2f, ', off_brightness) 247 logging.info(' after %s seconds.', off_elapsed_time) 248 if not off_brightness < dim_brightness: 249 raise error.TestFail('Screen did not turn off on delay.') 250 251 # Verify user is still logged in before IdleAction. 252 user_is_logged_in = self.cr.login_status['isLoggedIn'] 253 if not user_is_logged_in: 254 raise error.TestFail('User must be logged in before idle action.') 255 256 # Get user logged in state after IdleAction. 257 seconds_to_action = ( 258 self.IDLE_ACTION_DELAY + self.ACTIVITY_REPORT_INTERVAL 259 - self.elapsed_time(start_time)) 260 try: 261 user_is_logged_in = not self._poll_until_user_is_logged_out( 262 seconds_to_action) 263 except utils.TimeoutError: 264 pass 265 action_elapsed_time = self.elapsed_time(start_time) 266 logging.info(' User logged out: %r, ', not user_is_logged_in) 267 logging.info(' after %s seconds.', action_elapsed_time) 268 269 # Verify user status against expected result, based on case. 270 if self.case == 'NotSet_Sleep' or self.case == 'DoNothing_Continue': 271 if not user_is_logged_in: 272 raise error.TestFail('User should be logged in.') 273 elif self.case == 'Logout_EndSession': 274 if user_is_logged_in: 275 raise error.TestFail('User should be logged out.') 276 277 278 def run_once(self, case): 279 """ 280 Setup and run the test configured for the specified test case. 281 282 @param case: Name of the test case to run. 283 284 """ 285 case_value = self.TEST_CASES[case] 286 self.SUPPORTING_POLICIES[self.POLICY_NAME] = case_value 287 self.setup_case(user_policies=self.SUPPORTING_POLICIES) 288 self._test_idle_action(case_value) 289