blob: f0b091f025783cd1a46f8916d6dc5921cd572d16 [file] [log] [blame]
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +08001# Copyright (c) 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
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +08005import httplib
6import logging
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +08007import os
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +08008import socket
Tom Wai-Hong Tamc3846422014-02-17 16:41:57 +08009import sys
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080010import xmlrpclib
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080011
12from autotest_lib.client.bin import utils
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080013from autotest_lib.client.common_lib.cros import retry
Wai-Hong Tam44cb5452014-03-18 16:14:24 -070014from autotest_lib.client.cros import constants
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080015from autotest_lib.server import autotest
16
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080017class DisplayClient(object):
18 """DisplayClient is a layer to control display logic over a remote DUT.
19
20 The Autotest host object representing the remote DUT, passed to this
21 class on initialization, can be accessed from its _client property.
22
23 """
24
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080025 X_ENV_VARIABLES = 'DISPLAY=:0.0 XAUTHORITY=/home/chronos/.Xauthority'
26 XMLRPC_CONNECT_TIMEOUT = 30
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080027 XMLRPC_RETRY_TIMEOUT = 180
28 XMLRPC_RETRY_DELAY = 10
Tom Wai-Hong Tam23362632014-04-09 16:38:37 +080029 HTTP_PORT = 8000
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080030
31
32 def __init__(self, host):
33 """Construct a DisplayClient.
34
35 @param host: Host object representing a remote host.
36 """
37 self._client = host
38 self._display_xmlrpc_client = None
Wai-Hong Tam44cb5452014-03-18 16:14:24 -070039 module_dir = os.path.dirname(sys.modules[__name__].__file__)
40 self._source_images_dir = os.path.join(module_dir, 'calibration_images')
41 self._dest_tmp_dir = '/tmp'
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080042
43
Wai-Hong Tam44cb5452014-03-18 16:14:24 -070044 def initialize(self):
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080045 """Initializes some required servers, like HTTP daemon, RPC connection.
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080046 """
47 # Make sure the client library is on the device so that the proxy code
48 # is there when we try to call it.
49 client_at = autotest.Autotest(self._client)
50 client_at.install()
Tom Wai-Hong Tamfe395092014-02-12 20:16:22 +080051 self.connect()
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080052
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080053
Tom Wai-Hong Tamfe395092014-02-12 20:16:22 +080054 def connect(self):
55 """Connects the XML-RPC proxy on the client."""
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080056 @retry.retry((socket.error,
57 xmlrpclib.ProtocolError,
58 httplib.BadStatusLine),
59 timeout_min=self.XMLRPC_RETRY_TIMEOUT / 60.0,
60 delay_sec=self.XMLRPC_RETRY_DELAY)
61 def connect_with_retries():
62 """Connects the XML-RPC proxy with retries."""
63 self._display_xmlrpc_client = self._client.xmlrpc_connect(
64 constants.DISPLAY_TESTING_XMLRPC_SERVER_COMMAND,
65 constants.DISPLAY_TESTING_XMLRPC_SERVER_PORT,
66 command_name=(
67 constants.DISPLAY_TESTING_XMLRPC_SERVER_CLEANUP_PATTERN
68 ),
69 ready_test_name=(
70 constants.DISPLAY_TESTING_XMLRPC_SERVER_READY_METHOD),
71 timeout_seconds=self.XMLRPC_CONNECT_TIMEOUT)
72
73 logging.info('Setup the display_client RPC server, with retries...')
74 connect_with_retries()
Tom Wai-Hong Tamfe395092014-02-12 20:16:22 +080075
76
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080077 def cleanup(self):
78 """Cleans up."""
Tom Wai-Hong Tam0d836592014-04-23 11:27:40 +080079 self._client.rpc_disconnect(
80 constants.DISPLAY_TESTING_XMLRPC_SERVER_PORT)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +080081
82
83 def __del__(self):
84 """Destructor of DisplayClient."""
85 self.cleanup()
86
87
88 def get_connector_name(self):
89 """Gets the name of the external output connector.
90
91 @return The external output connector name as a string.
92 """
93 return self._display_xmlrpc_client.get_ext_connector_name()
94
95
96 def load_calibration_image(self, resolution):
97 """Load a full screen calibration image from the HTTP server.
98
99 @param resolution: A tuple (width, height) of resolution.
100 """
Wai-Hong Tam44cb5452014-03-18 16:14:24 -0700101 filename = '%dx%d.png' % resolution
102 image_path = os.path.join(self._source_images_dir, filename)
103 self._client.send_file(image_path, self._dest_tmp_dir)
Tom Wai-Hong Tam23362632014-04-09 16:38:37 +0800104 page_url = ('http://localhost:%d/%s' % (self.HTTP_PORT, filename))
105 self._display_xmlrpc_client.start_httpd(self.HTTP_PORT,
106 self._dest_tmp_dir)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800107 self._display_xmlrpc_client.load_url(page_url)
Tom Wai-Hong Tam23362632014-04-09 16:38:37 +0800108 self._display_xmlrpc_client.stop_httpd()
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800109
110
111 def close_tab(self, index=-1):
112 """Closes the tab of the given index.
113
114 @param index: The tab index to close. Defaults to the last tab.
115 """
116 return self._display_xmlrpc_client.close_tab(index)
117
118
119 def set_mirrored(self, is_mirrored):
120 """Sets mirrored mode.
121
122 @param is_mirrored: True or False to indicate mirrored state.
123 """
124 return self._display_xmlrpc_client.set_mirrored(is_mirrored)
125
126
Tom Wai-Hong Tam328dbeb2014-02-14 11:20:19 +0800127 def suspend_resume(self, suspend_time=10):
128 """Suspends the DUT for a given time in second.
129
130 @param suspend_time: Suspend time in second, default: 10s.
131 """
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800132 # TODO(waihong): Use other general API instead of this RPC.
Tom Wai-Hong Tam328dbeb2014-02-14 11:20:19 +0800133 return self._display_xmlrpc_client.suspend_resume(suspend_time)
134
135
136 def suspend_resume_bg(self, suspend_time=10):
137 """Suspends the DUT for a given time in second in the background.
138
139 @param suspend_time: Suspend time in second, default: 10s.
140 """
141 # TODO(waihong): Use other general API instead of this RPC.
142 return self._display_xmlrpc_client.suspend_resume_bg(suspend_time)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800143
144
145 def reconnect_output_and_wait(self):
146 """Reconnects output and waits it available."""
147 output = self.get_connector_name()
148 self._display_xmlrpc_client.reconnect_output(output)
149 self._display_xmlrpc_client.wait_output_connected(output)
150 utils.wait_for_value(lambda: (
151 len(self._display_xmlrpc_client.get_display_info())),
152 expected_value=2)
153
154
Hung-ying Tyan67541652014-03-12 11:44:46 +0800155 def hide_cursor(self):
156 """Hides mouse cursor by sending a keystroke."""
157 self._client.run('%s xdotool key Up' % self.X_ENV_VARIABLES)
Tom Wai-Hong Tamb2d39dc2014-01-21 15:26:23 +0800158
159
160 def capture_external_screen(self, file_path):
161 """Captures the external screen framebuffer.
162
163 @param file_path: The path of file for output.
164
165 @return: The byte-array for the screen.
166 """
167 output = self.get_connector_name()
168 fb_w, fb_h, fb_x, fb_y = (
169 self._display_xmlrpc_client.get_resolution(output))
170 basename = os.path.basename(file_path)
171 remote_path = os.path.join('/tmp', basename)
172 command = ('%s import -window root -depth 8 -crop %dx%d+%d+%d %s' %
173 (self.X_ENV_VARIABLES, fb_w, fb_h, fb_x, fb_y, remote_path))
174 self._client.run(command)
175 self._client.get_file(remote_path, file_path)
176 return open(file_path).read()
Tom Wai-Hong Tamf6bb17f2014-04-24 13:36:49 +0800177
178
179 def get_resolution(self):
180 """Gets the external resolution on framebuffer.
181
182 @return The resolution tuple (width, height)
183 """
184 output = self.get_connector_name()
185 width, height, _, _ = self._display_xmlrpc_client.get_resolution(output)
186 return (width, height)