1 /* Copyright (C) 2010 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12
13 /*
14 * Contains the UI-side implementation of the "ui-core-control" service that is
15 * part of the UI control protocol. Here we send UI control commands to the Core.
16 */
17
18 #include "console.h"
19 #include "android/looper.h"
20 #include "android/async-utils.h"
21 #include "android/sync-utils.h"
22 #include "android/utils/debug.h"
23 #include "android/utils/panic.h"
24 #include "android/protocol/core-connection.h"
25 #include "android/protocol/core-commands.h"
26 #include "android/protocol/core-commands-proxy.h"
27 #include "android/protocol/core-commands-api.h"
28
29 /* Descriptor for the UI-side "ui-core-control" service. */
30 typedef struct CoreCmdProxy {
31 /* Core connection established for this service. */
32 CoreConnection* core_connection;
33
34 /* Socket descriptor for the UI service. */
35 int sock;
36
37 /* Socket wrapper for sync srites. */
38 SyncSocket* sync_writer;
39
40 /* Socket wrapper for sync reads. */
41 SyncSocket* sync_reader;
42 } CoreCmdProxy;
43
44 /* One and only one CoreCmdProxy instance. */
45 static CoreCmdProxy _coreCmdProxy = { 0 };
46
47 /* Sends UI command to the core.
48 * Param:
49 * cmd_type, cmd_param, cmd_param_size - Define the command.
50 * Return:
51 * 0 On success, or < 0 on failure.
52 */
53 static int
_coreCmdProxy_send_command(uint8_t cmd_type,void * cmd_param,uint32_t cmd_param_size)54 _coreCmdProxy_send_command(uint8_t cmd_type,
55 void* cmd_param,
56 uint32_t cmd_param_size)
57 {
58 int status;
59 UICmdHeader header;
60
61 // Prepare the command header.
62 header.cmd_type = cmd_type;
63 header.cmd_param_size = cmd_param_size;
64 status = syncsocket_start_write(_coreCmdProxy.sync_writer);
65 if (!status) {
66 // Send the header.
67 status = syncsocket_write(_coreCmdProxy.sync_writer, &header,
68 sizeof(header),
69 core_connection_get_timeout(sizeof(header)));
70 // If there is request data, send it too.
71 if (status > 0 && cmd_param != NULL && cmd_param_size > 0) {
72 status = syncsocket_write(_coreCmdProxy.sync_writer, cmd_param,
73 cmd_param_size,
74 core_connection_get_timeout(cmd_param_size));
75 }
76 status = syncsocket_result(status);
77 syncsocket_stop_write(_coreCmdProxy.sync_writer);
78 }
79 if (status < 0) {
80 derror("Unable to send UI control command %d (size %u): %s\n",
81 cmd_type, cmd_param_size, errno_str);
82 }
83 return status;
84 }
85
86 /* Reads UI control command response from the core.
87 * Param:
88 * resp - Upon success contains command response header.
89 * resp_data - Upon success contains allocated reponse data (if any). The caller
90 * is responsible for deallocating the memory returned here.
91 * Return:
92 * 0 on success, or < 0 on failure.
93 */
94 static int
_coreCmdProxy_get_response(UICmdRespHeader * resp,void ** resp_data)95 _coreCmdProxy_get_response(UICmdRespHeader* resp, void** resp_data)
96 {
97 int status = syncsocket_start_read(_coreCmdProxy.sync_reader);
98 if (!status) {
99 // Read the header.
100 status = syncsocket_read(_coreCmdProxy.sync_reader, resp,
101 sizeof(UICmdRespHeader),
102 core_connection_get_timeout(sizeof(UICmdRespHeader)));
103 // Read response data (if any).
104 if (status > 0 && resp->resp_data_size) {
105 *resp_data = malloc(resp->resp_data_size);
106 if (*resp_data == NULL) {
107 APANIC("_coreCmdProxy_get_response is unable to allocate response data buffer.\n");
108 }
109 status = syncsocket_read(_coreCmdProxy.sync_reader, *resp_data,
110 resp->resp_data_size,
111 core_connection_get_timeout(resp->resp_data_size));
112 }
113 status = syncsocket_result(status);
114 syncsocket_stop_read(_coreCmdProxy.sync_reader);
115 }
116 if (status < 0) {
117 derror("Unable to get UI command response from the Core: %s\n",
118 errno_str);
119 }
120 return status;
121 }
122
123 int
corecmd_set_coarse_orientation(AndroidCoarseOrientation orient)124 corecmd_set_coarse_orientation(AndroidCoarseOrientation orient)
125 {
126 UICmdSetCoarseOrientation cmd;
127 cmd.orient = orient;
128 return _coreCmdProxy_send_command(AUICMD_SET_COARSE_ORIENTATION,
129 &cmd, sizeof(cmd));
130 }
131
132 int
corecmd_toggle_network()133 corecmd_toggle_network()
134 {
135 return _coreCmdProxy_send_command(AUICMD_TOGGLE_NETWORK, NULL, 0);
136 }
137
138 int
corecmd_trace_control(int start)139 corecmd_trace_control(int start)
140 {
141 UICmdTraceControl cmd;
142 cmd.start = start;
143 return _coreCmdProxy_send_command(AUICMD_TRACE_CONTROL,
144 &cmd, sizeof(cmd));
145 }
146
147 int
corecmd_is_network_disabled()148 corecmd_is_network_disabled()
149 {
150 UICmdRespHeader resp;
151 void* tmp = NULL;
152 int status;
153
154 status = _coreCmdProxy_send_command(AUICMD_CHK_NETWORK_DISABLED, NULL, 0);
155 if (status < 0) {
156 return status;
157 }
158 status = _coreCmdProxy_get_response(&resp, &tmp);
159 if (status < 0) {
160 return status;
161 }
162 return resp.result;
163 }
164
165 int
corecmd_get_netspeed(int index,NetworkSpeed ** netspeed)166 corecmd_get_netspeed(int index, NetworkSpeed** netspeed)
167 {
168 UICmdGetNetSpeed req;
169 UICmdRespHeader resp;
170 UICmdGetNetSpeedResp* resp_data = NULL;
171 int status;
172
173 // Initialize and send the query.
174 req.index = index;
175 status = _coreCmdProxy_send_command(AUICMD_GET_NETSPEED, &req, sizeof(req));
176 if (status < 0) {
177 return status;
178 }
179
180 // Obtain the response from the core.
181 status = _coreCmdProxy_get_response(&resp, (void**)&resp_data);
182 if (status < 0) {
183 return status;
184 }
185 if (!resp.result) {
186 NetworkSpeed* ret;
187 // Allocate memory for the returning NetworkSpeed instance.
188 // It includes: NetworkSpeed structure +
189 // size of zero-terminated "name" and "display" strings saved in
190 // resp_data.
191 *netspeed = malloc(sizeof(NetworkSpeed) + 1 +
192 resp.resp_data_size - sizeof(UICmdGetNetSpeedResp));
193 ret = *netspeed;
194
195 // Copy data obtained from the core to the returning NetworkSpeed
196 // instance.
197 ret->upload = resp_data->upload;
198 ret->download = resp_data->download;
199 ret->name = (char*)ret + sizeof(NetworkSpeed);
200 strcpy((char*)ret->name, resp_data->name);
201 ret->display = ret->name + strlen(ret->name) + 1;
202 strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1);
203 }
204 if (resp_data != NULL) {
205 free(resp_data);
206 }
207 return resp.result;
208 }
209
210 int
corecmd_get_netdelay(int index,NetworkLatency ** netdelay)211 corecmd_get_netdelay(int index, NetworkLatency** netdelay)
212 {
213 UICmdGetNetDelay req;
214 UICmdRespHeader resp;
215 UICmdGetNetDelayResp* resp_data = NULL;
216 int status;
217
218 // Initialize and send the query.
219 req.index = index;
220 status = _coreCmdProxy_send_command(AUICMD_GET_NETDELAY, &req, sizeof(req));
221 if (status < 0) {
222 return status;
223 }
224
225 // Obtain the response from the core.
226 status = _coreCmdProxy_get_response(&resp, (void**)&resp_data);
227 if (status < 0) {
228 return status;
229 }
230 if (!resp.result) {
231 NetworkLatency* ret;
232 // Allocate memory for the returning NetworkLatency instance.
233 // It includes: NetworkLatency structure +
234 // size of zero-terminated "name" and "display" strings saved in
235 // resp_data.
236 *netdelay = malloc(sizeof(NetworkLatency) + 1 +
237 resp.resp_data_size - sizeof(UICmdGetNetDelayResp));
238 ret = *netdelay;
239
240 // Copy data obtained from the core to the returning NetworkLatency
241 // instance.
242 ret->min_ms = resp_data->min_ms;
243 ret->max_ms = resp_data->max_ms;
244 ret->name = (char*)ret + sizeof(NetworkLatency);
245 strcpy((char*)ret->name, resp_data->name);
246 ret->display = ret->name + strlen(ret->name) + 1;
247 strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1);
248 }
249 if (resp_data != NULL) {
250 free(resp_data);
251 }
252 return resp.result;
253 }
254
255 int
corecmd_get_qemu_path(int type,const char * filename,char * path,size_t path_buf_size)256 corecmd_get_qemu_path(int type,
257 const char* filename,
258 char* path,
259 size_t path_buf_size)
260 {
261 UICmdRespHeader resp;
262 char* resp_data = NULL;
263 int status;
264
265 // Initialize and send the query.
266 uint32_t cmd_data_size = sizeof(UICmdGetQemuPath) + strlen(filename) + 1;
267 UICmdGetQemuPath* req = (UICmdGetQemuPath*)malloc(cmd_data_size);
268 if (req == NULL) {
269 APANIC("corecmd_get_qemu_path is unable to allocate %u bytes\n",
270 cmd_data_size);
271 }
272 req->type = type;
273 strcpy(req->filename, filename);
274 status = _coreCmdProxy_send_command(AUICMD_GET_QEMU_PATH, req,
275 cmd_data_size);
276 if (status < 0) {
277 return status;
278 }
279
280 // Obtain the response from the core.
281 status = _coreCmdProxy_get_response(&resp, (void**)&resp_data);
282 if (status < 0) {
283 return status;
284 }
285 if (!resp.result && resp_data != NULL) {
286 strncpy(path, resp_data, path_buf_size);
287 path[path_buf_size - 1] = '\0';
288 }
289 if (resp_data != NULL) {
290 free(resp_data);
291 }
292 return resp.result;
293 }
294
295 int
corecmd_get_hw_lcd_density(void)296 corecmd_get_hw_lcd_density(void)
297 {
298 UICmdRespHeader resp;
299 void* tmp = NULL;
300 int status;
301
302 status = _coreCmdProxy_send_command(AUICMD_GET_LCD_DENSITY, NULL, 0);
303 if (status < 0) {
304 return status;
305 }
306 status = _coreCmdProxy_get_response(&resp, &tmp);
307 if (status < 0) {
308 return status;
309 }
310 return resp.result;
311 }
312
313 int
coreCmdProxy_create(SockAddress * console_socket)314 coreCmdProxy_create(SockAddress* console_socket)
315 {
316 char* handshake = NULL;
317
318 // Connect to the ui-core-control service.
319 _coreCmdProxy.core_connection =
320 core_connection_create_and_switch(console_socket, "ui-core-control",
321 &handshake);
322 if (_coreCmdProxy.core_connection == NULL) {
323 derror("Unable to connect to the ui-core-control service: %s\n",
324 errno_str);
325 return -1;
326 }
327
328 // Initialze command writer and response reader.
329 _coreCmdProxy.sock = core_connection_get_socket(_coreCmdProxy.core_connection);
330 _coreCmdProxy.sync_writer = syncsocket_init(_coreCmdProxy.sock);
331 if (_coreCmdProxy.sync_writer == NULL) {
332 derror("Unable to initialize CoreCmdProxy writer: %s\n", errno_str);
333 coreCmdProxy_destroy();
334 return -1;
335 }
336 _coreCmdProxy.sync_reader = syncsocket_init(_coreCmdProxy.sock);
337 if (_coreCmdProxy.sync_reader == NULL) {
338 derror("Unable to initialize CoreCmdProxy reader: %s\n", errno_str);
339 coreCmdProxy_destroy();
340 return -1;
341 }
342
343
344 fprintf(stdout, "ui-core-control is now connected to the core at %s.",
345 sock_address_to_string(console_socket));
346 if (handshake != NULL) {
347 if (handshake[0] != '\0') {
348 fprintf(stdout, " Handshake: %s", handshake);
349 }
350 free(handshake);
351 }
352 fprintf(stdout, "\n");
353
354 return 0;
355 }
356
357 /* Destroys CoreCmdProxy instance. */
358 void
coreCmdProxy_destroy(void)359 coreCmdProxy_destroy(void)
360 {
361 if (_coreCmdProxy.sync_writer != NULL) {
362 syncsocket_close(_coreCmdProxy.sync_writer);
363 syncsocket_free(_coreCmdProxy.sync_writer);
364 _coreCmdProxy.sync_writer = NULL;
365 }
366 if (_coreCmdProxy.sync_reader != NULL) {
367 syncsocket_close(_coreCmdProxy.sync_reader);
368 syncsocket_free(_coreCmdProxy.sync_reader);
369 _coreCmdProxy.sync_reader = NULL;
370 }
371 if (_coreCmdProxy.core_connection != NULL) {
372 core_connection_close(_coreCmdProxy.core_connection);
373 core_connection_free(_coreCmdProxy.core_connection);
374 _coreCmdProxy.core_connection = NULL;
375 }
376 }
377