• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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