1*9c5db199SXin Li# Copyright 2018 The Chromium OS Authors. All rights reserved. 2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 3*9c5db199SXin Li# found in the LICENSE file. 4*9c5db199SXin Li 5*9c5db199SXin Li'''Login with test account and display chart file using telemetry.''' 6*9c5db199SXin Li 7*9c5db199SXin Liimport argparse 8*9c5db199SXin Liimport contextlib 9*9c5db199SXin Liimport json 10*9c5db199SXin Liimport logging 11*9c5db199SXin Liimport os 12*9c5db199SXin Liimport select 13*9c5db199SXin Liimport signal 14*9c5db199SXin Liimport sys 15*9c5db199SXin Liimport tempfile 16*9c5db199SXin Li 17*9c5db199SXin Li# Set chart process preferred logging format before overridden by importing 18*9c5db199SXin Li# common package. 19*9c5db199SXin Lilogging.basicConfig( 20*9c5db199SXin Li level=logging.DEBUG, 21*9c5db199SXin Li format='%(asctime)s - %(levelname)s - %(message)s') 22*9c5db199SXin Li 23*9c5db199SXin Li# This sets up import paths for autotest. 24*9c5db199SXin Lisys.path.append('/usr/local/autotest/bin') 25*9c5db199SXin Liimport common 26*9c5db199SXin Lifrom autotest_lib.client.bin import utils 27*9c5db199SXin Lifrom autotest_lib.client.cros import constants 28*9c5db199SXin Lifrom autotest_lib.client.cros.multimedia import display_facade as display_facade_lib 29*9c5db199SXin Lifrom autotest_lib.client.cros.multimedia import facade_resource 30*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import chrome 31*9c5db199SXin Li 32*9c5db199SXin LiDEFAULT_DISPLAY_LEVEL = 96.0 33*9c5db199SXin Li 34*9c5db199SXin Li 35*9c5db199SXin Liclass Fifo: 36*9c5db199SXin Li """Fifo to communicate with chart service.""" 37*9c5db199SXin Li 38*9c5db199SXin Li FIFO_POLL_TIMEOUT_MS = 300 39*9c5db199SXin Li 40*9c5db199SXin Li def __init__(self): 41*9c5db199SXin Li self._ready = False 42*9c5db199SXin Li 43*9c5db199SXin Li def __enter__(self): 44*9c5db199SXin Li # Prepare fifo file. 45*9c5db199SXin Li self._tmpdir = tempfile.mkdtemp(prefix='chart_fifo_', dir='/tmp') 46*9c5db199SXin Li self._path = os.path.join(self._tmpdir, 'fifo') 47*9c5db199SXin Li os.mkfifo(self._path) 48*9c5db199SXin Li 49*9c5db199SXin Li # Hook SIGINT signal to stop fifo. 50*9c5db199SXin Li self._original_sig_handler = signal.getsignal(signal.SIGINT) 51*9c5db199SXin Li 52*9c5db199SXin Li def handler(a, b): 53*9c5db199SXin Li signal.signal(signal.SIGINT, self._original_sig_handler) 54*9c5db199SXin Li self._ready = False 55*9c5db199SXin Li 56*9c5db199SXin Li signal.signal(signal.SIGINT, handler) 57*9c5db199SXin Li 58*9c5db199SXin Li self._ready = True 59*9c5db199SXin Li return self 60*9c5db199SXin Li 61*9c5db199SXin Li def __exit__(self, exc_type, exc_value, exc_traceback): 62*9c5db199SXin Li signal.signal(signal.SIGINT, self._original_sig_handler) 63*9c5db199SXin Li os.unlink(self._path) 64*9c5db199SXin Li os.rmdir(self._tmpdir) 65*9c5db199SXin Li 66*9c5db199SXin Li def get_path(self): 67*9c5db199SXin Li return self._path 68*9c5db199SXin Li 69*9c5db199SXin Li def read(self): 70*9c5db199SXin Li """Read json format command from fifo.""" 71*9c5db199SXin Li while self._ready: 72*9c5db199SXin Li with os.fdopen(os.open(self._path, os.O_RDONLY | os.O_NONBLOCK), 73*9c5db199SXin Li 'r') as fd: 74*9c5db199SXin Li p = select.poll() 75*9c5db199SXin Li p.register(fd, select.POLLIN) 76*9c5db199SXin Li if p.poll(self.FIFO_POLL_TIMEOUT_MS): 77*9c5db199SXin Li cmd = fd.read() 78*9c5db199SXin Li return json.loads(cmd) 79*9c5db199SXin Li return None 80*9c5db199SXin Li 81*9c5db199SXin Li 82*9c5db199SXin Li@contextlib.contextmanager 83*9c5db199SXin Lidef control_brightness(): 84*9c5db199SXin Li """Help to programmatically control the brightness. 85*9c5db199SXin Li 86*9c5db199SXin Li Returns: 87*9c5db199SXin Li A function which can set brightness between [0.0, 100.0]. 88*9c5db199SXin Li """ 89*9c5db199SXin Li 90*9c5db199SXin Li def set_brightness(display_level): 91*9c5db199SXin Li utils.system('backlight_tool --set_brightness_percent=%s' % 92*9c5db199SXin Li display_level) 93*9c5db199SXin Li logging.info('Set display brightness to %r', display_level) 94*9c5db199SXin Li 95*9c5db199SXin Li original_display_level = utils.system_output( 96*9c5db199SXin Li 'backlight_tool --get_brightness_percent') 97*9c5db199SXin Li logging.info('Save original display brightness %r', original_display_level) 98*9c5db199SXin Li 99*9c5db199SXin Li utils.system('stop powerd', ignore_status=True) 100*9c5db199SXin Li yield set_brightness 101*9c5db199SXin Li logging.info('Restore display brightness %r', original_display_level) 102*9c5db199SXin Li utils.system('start powerd', ignore_status=True) 103*9c5db199SXin Li set_brightness(original_display_level) 104*9c5db199SXin Li 105*9c5db199SXin Li 106*9c5db199SXin Li@contextlib.contextmanager 107*9c5db199SXin Lidef control_display(cr): 108*9c5db199SXin Li """Fix the display orientation instead of using gyro orientation.""" 109*9c5db199SXin Li board = utils.get_board() 110*9c5db199SXin Li logging.info("Board:%s", board) 111*9c5db199SXin Li if board == 'scarlet': 112*9c5db199SXin Li DISPLAY_ORIENTATION = 90 113*9c5db199SXin Li else: 114*9c5db199SXin Li DISPLAY_ORIENTATION = 0 115*9c5db199SXin Li 116*9c5db199SXin Li logging.info('Set fullscreen.') 117*9c5db199SXin Li facade = facade_resource.FacadeResource(cr) 118*9c5db199SXin Li display_facade = display_facade_lib.DisplayFacadeLocal(facade) 119*9c5db199SXin Li display_facade.set_fullscreen(True) 120*9c5db199SXin Li 121*9c5db199SXin Li logging.info('Fix screen rotation %d.', DISPLAY_ORIENTATION) 122*9c5db199SXin Li internal_display_id = display_facade.get_internal_display_id() 123*9c5db199SXin Li original_display_orientation = display_facade.get_display_rotation( 124*9c5db199SXin Li internal_display_id) 125*9c5db199SXin Li display_facade.set_display_rotation(internal_display_id, 126*9c5db199SXin Li rotation=DISPLAY_ORIENTATION) 127*9c5db199SXin Li yield 128*9c5db199SXin Li display_facade.set_display_rotation(internal_display_id, 129*9c5db199SXin Li rotation=original_display_orientation) 130*9c5db199SXin Li 131*9c5db199SXin Li 132*9c5db199SXin Lidef display(chart_path, display_level): 133*9c5db199SXin Li """Display chart on device by using telemetry.""" 134*9c5db199SXin Li chart_path = os.path.abspath(chart_path) 135*9c5db199SXin Li if os.path.isfile(chart_path): 136*9c5db199SXin Li first_chart_name = os.path.basename(chart_path) 137*9c5db199SXin Li chart_dir_path = os.path.dirname(chart_path) 138*9c5db199SXin Li elif os.path.isdir(chart_path): 139*9c5db199SXin Li first_chart_name = None 140*9c5db199SXin Li chart_dir_path = chart_path 141*9c5db199SXin Li else: 142*9c5db199SXin Li assert False, 'chart_path %r not found.' % chart_path 143*9c5db199SXin Li 144*9c5db199SXin Li def show_chart(name): 145*9c5db199SXin Li """Show image on chart base on file name""" 146*9c5db199SXin Li filepath = os.path.join(chart_dir_path, name) 147*9c5db199SXin Li logging.info('Display chart file of path %r.', filepath) 148*9c5db199SXin Li tab = cr.browser.tabs[0] 149*9c5db199SXin Li tab.Navigate(cr.browser.platform.http_server.UrlOf(filepath)) 150*9c5db199SXin Li tab.WaitForDocumentReadyStateToBeComplete() 151*9c5db199SXin Li 152*9c5db199SXin Li logging.info('Setup SIGINT listener for stop displaying.') 153*9c5db199SXin Li 154*9c5db199SXin Li with chrome.Chrome( 155*9c5db199SXin Li extension_paths=[constants.DISPLAY_TEST_EXTENSION], 156*9c5db199SXin Li autotest_ext=True, 157*9c5db199SXin Li init_network_controller=True) as cr, \ 158*9c5db199SXin Li control_brightness() as set_brightness, \ 159*9c5db199SXin Li control_display(cr), \ 160*9c5db199SXin Li Fifo() as fifo: 161*9c5db199SXin Li set_brightness(display_level) 162*9c5db199SXin Li 163*9c5db199SXin Li cr.browser.platform.SetHTTPServerDirectories(chart_dir_path) 164*9c5db199SXin Li if first_chart_name is not None: 165*9c5db199SXin Li show_chart(first_chart_name) 166*9c5db199SXin Li 167*9c5db199SXin Li logging.info('Chart is ready. Fifo: %s', fifo.get_path()) 168*9c5db199SXin Li # Flush the 'is ready' message for server test to sync with ready state. 169*9c5db199SXin Li sys.stdout.flush() 170*9c5db199SXin Li sys.stderr.flush() 171*9c5db199SXin Li 172*9c5db199SXin Li while True: 173*9c5db199SXin Li cmd = fifo.read() 174*9c5db199SXin Li if cmd is None: 175*9c5db199SXin Li break 176*9c5db199SXin Li new_chart_name = cmd.get('chart_name') 177*9c5db199SXin Li if new_chart_name is not None: 178*9c5db199SXin Li show_chart(new_chart_name) 179*9c5db199SXin Li 180*9c5db199SXin Li new_display_level = cmd.get('display_level') 181*9c5db199SXin Li if new_display_level is not None: 182*9c5db199SXin Li set_brightness(new_display_level) 183*9c5db199SXin Li 184*9c5db199SXin Li 185*9c5db199SXin Liif __name__ == '__main__': 186*9c5db199SXin Li argparser = argparse.ArgumentParser( 187*9c5db199SXin Li description='Display chart file on chrome by using telemetry.' 188*9c5db199SXin Li ' Send SIGINT or keyboard interrupt to stop displaying.') 189*9c5db199SXin Li argparser.add_argument( 190*9c5db199SXin Li 'chart_path', 191*9c5db199SXin Li help='Path of displayed chart file' 192*9c5db199SXin Li ' or the directory to put chart files for displaying in fifo mode.' 193*9c5db199SXin Li ) 194*9c5db199SXin Li argparser.add_argument( 195*9c5db199SXin Li '--display_level', 196*9c5db199SXin Li type=float, 197*9c5db199SXin Li default=DEFAULT_DISPLAY_LEVEL, 198*9c5db199SXin Li help= 199*9c5db199SXin Li 'Set brightness as linearly-calculated percent in [0.0, 100.0].') 200*9c5db199SXin Li 201*9c5db199SXin Li args = argparser.parse_args() 202*9c5db199SXin Li display(args.chart_path, args.display_level) 203