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 Core-side implementation of the "ui-core-control" service that is
15 * part of the UI control protocol. Here we handle UI control commands sent by
16 * the UI to the Core.
17 */
18
19 #include "android/android.h"
20 #include "android/globals.h"
21 #include "telephony/modem_driver.h"
22 #include "android-trace.h"
23 #include "android/looper.h"
24 #include "android/async-utils.h"
25 #include "android/sync-utils.h"
26 #include "android/utils/debug.h"
27 #include "android/protocol/core-commands.h"
28 #include "android/protocol/core-commands-impl.h"
29
30 /* Enumerates state values for the command reader in the CoreCmdImpl descriptor.
31 */
32 typedef enum CoreCmdImplState {
33 /* The reader is waiting on command header. */
34 EXPECTS_HEADER,
35
36 /* The reader is waiting on command parameters. */
37 EXPECTS_PARAMETERS,
38 } CoreCmdImplState;
39
40 /* Descriptor for the Core-side implementation of the "ui-core-control" service.
41 */
42 typedef struct CoreCmdImpl {
43 /* Reader to detect UI disconnection. */
44 AsyncReader async_reader;
45
46 /* I/O associated with this descriptor. */
47 LoopIo io;
48
49 /* Looper used to communicate with the UI. */
50 Looper* looper;
51
52 /* Writer to send responses to the UI commands. */
53 SyncSocket* sync_writer;
54
55 /* Socket descriptor for this service. */
56 int sock;
57
58 /* Command reader state. */
59 CoreCmdImplState cmd_state;
60
61 /* Incoming command header. */
62 UICmdHeader cmd_header;
63
64 /* A small preallocated buffer for command parameters. */
65 uint8_t cmd_param[256];
66
67 /* Buffer to use for reading command parameters. Depending on expected size
68 * of the parameters this buffer can point to cmd_param field of this
69 * structure (for small commands), or can be allocated for large commands. */
70 void* cmd_param_buf;
71 } CoreCmdImpl;
72
73 /* One and only one CoreCmdImpl instance. */
74 static CoreCmdImpl _coreCmdImpl;
75
76 /* Implemented in android/console.c */
77 extern void destroy_corecmd_client(void);
78 /* Implemented in vl-android.c */
79 extern char* qemu_find_file(int type, const char* filename);
80
81 /* Properly initializes cmd_param_buf field in CoreCmdImpl instance to receive
82 * the expected command parameters.
83 */
84 static uint8_t*
_alloc_cmd_param_buf(CoreCmdImpl * corecmd,uint32_t size)85 _alloc_cmd_param_buf(CoreCmdImpl* corecmd, uint32_t size)
86 {
87 if (size < sizeof(corecmd->cmd_param)) {
88 // cmd_param can contain all request data.
89 corecmd->cmd_param_buf = &corecmd->cmd_param[0];
90 } else {
91 // Expected request us too large to fit into preallocated buffer.
92 corecmd->cmd_param_buf = qemu_malloc(size);
93 }
94 return corecmd->cmd_param_buf;
95 }
96
97 /* Properly frees cmd_param_buf field in CoreCmdImpl instance.
98 */
99 static void
_free_cmd_param_buf(CoreCmdImpl * corecmd)100 _free_cmd_param_buf(CoreCmdImpl* corecmd)
101 {
102 if (corecmd->cmd_param_buf != &corecmd->cmd_param[0]) {
103 qemu_free(corecmd->cmd_param_buf);
104 corecmd->cmd_param_buf = &corecmd->cmd_param[0];
105 }
106 }
107
108 /* Calculates timeout for transferring the given number of bytes via socket.
109 * Return:
110 * Number of milliseconds during which the entire number of bytes is expected
111 * to be transferred via socket for this service.
112 */
113 static int
_coreCmdImpl_get_timeout(size_t data_size)114 _coreCmdImpl_get_timeout(size_t data_size)
115 {
116 // Min 2 seconds + 10 millisec for each transferring byte.
117 // TODO: Come up with a better arithmetics here.
118 return 2000 + data_size * 10;
119 }
120
121 /* Sends command response back to the UI.
122 * Param:
123 * corecmd - CoreCmdImpl instance to use to send the response.
124 * resp - Response header.
125 * resp_data - Response data. Data size is defined by the header.
126 * Return:
127 * 0 on success, or < 0 on failure.
128 */
129 static int
_coreCmdImpl_respond(CoreCmdImpl * corecmd,UICmdRespHeader * resp,void * resp_data)130 _coreCmdImpl_respond(CoreCmdImpl* corecmd, UICmdRespHeader* resp, void* resp_data)
131 {
132 int status = syncsocket_start_write(corecmd->sync_writer);
133 if (!status) {
134 // Write the header
135 status = syncsocket_write(corecmd->sync_writer, resp,
136 sizeof(UICmdRespHeader),
137 _coreCmdImpl_get_timeout(sizeof(UICmdRespHeader)));
138 // Write response data (if any).
139 if (status > 0 && resp_data != NULL && resp->resp_data_size != 0) {
140 status = syncsocket_write(corecmd->sync_writer, resp_data,
141 resp->resp_data_size,
142 _coreCmdImpl_get_timeout(resp->resp_data_size));
143 }
144 status = syncsocket_result(status);
145 syncsocket_stop_write(corecmd->sync_writer);
146 }
147 if (status < 0) {
148 derror("Core is unable to respond with %u bytes to the UI control command: %s\n",
149 resp->resp_data_size, errno_str);
150 }
151 return status;
152 }
153
154 /* Handles UI control command received from the UI.
155 * Param:
156 * corecmd - CoreCmdImpl instance that received the command.
157 * cmd_header - Command header.
158 * cmd_param - Command data.
159 */
160 static void
_coreCmdImpl_handle_command(CoreCmdImpl * corecmd,const UICmdHeader * cmd_header,const uint8_t * cmd_param)161 _coreCmdImpl_handle_command(CoreCmdImpl* corecmd,
162 const UICmdHeader* cmd_header,
163 const uint8_t* cmd_param)
164 {
165 switch (cmd_header->cmd_type) {
166 case AUICMD_SET_COARSE_ORIENTATION:
167 {
168 UICmdSetCoarseOrientation* cmd =
169 (UICmdSetCoarseOrientation*)cmd_param;
170 android_sensors_set_coarse_orientation(cmd->orient);
171 break;
172 }
173
174 case AUICMD_TOGGLE_NETWORK:
175 qemu_net_disable = !qemu_net_disable;
176 if (android_modem) {
177 amodem_set_data_registration(
178 android_modem,
179 qemu_net_disable ? A_REGISTRATION_UNREGISTERED
180 : A_REGISTRATION_HOME);
181 }
182 break;
183
184 case AUICMD_TRACE_CONTROL:
185 {
186 UICmdTraceControl* cmd = (UICmdTraceControl*)cmd_param;
187 if (cmd->start) {
188 start_tracing();
189 } else {
190 stop_tracing();
191 }
192 break;
193 }
194
195 case AUICMD_CHK_NETWORK_DISABLED:
196 {
197 UICmdRespHeader resp;
198 resp.resp_data_size = 0;
199 resp.result = qemu_net_disable;
200 _coreCmdImpl_respond(corecmd, &resp, NULL);
201 break;
202 }
203
204 case AUICMD_GET_NETSPEED:
205 {
206 UICmdRespHeader resp;
207 UICmdGetNetSpeedResp* resp_data = NULL;
208 UICmdGetNetSpeed* cmd = (UICmdGetNetSpeed*)cmd_param;
209
210 resp.resp_data_size = 0;
211 resp.result = 0;
212
213 if (cmd->index >= android_netspeeds_count ||
214 android_netspeeds[cmd->index].name == NULL) {
215 resp.result = -1;
216 } else {
217 const NetworkSpeed* netspeed = &android_netspeeds[cmd->index];
218 // Calculate size of the response data:
219 // fixed header + zero-terminated netspeed name.
220 resp.resp_data_size = sizeof(UICmdGetNetSpeedResp) +
221 strlen(netspeed->name) + 1;
222 // Count in zero-terminated netspeed display.
223 if (netspeed->display != NULL) {
224 resp.resp_data_size += strlen(netspeed->display) + 1;
225 } else {
226 resp.resp_data_size++;
227 }
228 // Allocate and initialize response data buffer.
229 resp_data =
230 (UICmdGetNetSpeedResp*)qemu_malloc(resp.resp_data_size);
231 resp_data->upload = netspeed->upload;
232 resp_data->download = netspeed->download;
233 strcpy(resp_data->name, netspeed->name);
234 if (netspeed->display != NULL) {
235 strcpy(resp_data->name + strlen(resp_data->name) + 1,
236 netspeed->display);
237 } else {
238 strcpy(resp_data->name + strlen(resp_data->name) + 1, "");
239 }
240 }
241 _coreCmdImpl_respond(corecmd, &resp, resp_data);
242 if (resp_data != NULL) {
243 qemu_free(resp_data);
244 }
245 break;
246 }
247
248 case AUICMD_GET_NETDELAY:
249 {
250 UICmdRespHeader resp;
251 UICmdGetNetDelayResp* resp_data = NULL;
252 UICmdGetNetDelay* cmd = (UICmdGetNetDelay*)cmd_param;
253
254 resp.resp_data_size = 0;
255 resp.result = 0;
256
257 if (cmd->index >= android_netdelays_count ||
258 android_netdelays[cmd->index].name == NULL) {
259 resp.result = -1;
260 } else {
261 const NetworkLatency* netdelay = &android_netdelays[cmd->index];
262 // Calculate size of the response data:
263 // fixed header + zero-terminated netdelay name.
264 resp.resp_data_size = sizeof(UICmdGetNetDelayResp) +
265 strlen(netdelay->name) + 1;
266 // Count in zero-terminated netdelay display.
267 if (netdelay->display != NULL) {
268 resp.resp_data_size += strlen(netdelay->display) + 1;
269 } else {
270 resp.resp_data_size++;
271 }
272 // Allocate and initialize response data buffer.
273 resp_data =
274 (UICmdGetNetDelayResp*)qemu_malloc(resp.resp_data_size);
275 resp_data->min_ms = netdelay->min_ms;
276 resp_data->max_ms = netdelay->max_ms;
277 strcpy(resp_data->name, netdelay->name);
278 if (netdelay->display != NULL) {
279 strcpy(resp_data->name + strlen(resp_data->name) + 1,
280 netdelay->display);
281 } else {
282 strcpy(resp_data->name + strlen(resp_data->name) + 1, "");
283 }
284 }
285 _coreCmdImpl_respond(corecmd, &resp, resp_data);
286 if (resp_data != NULL) {
287 qemu_free(resp_data);
288 }
289 break;
290 }
291
292 case AUICMD_GET_QEMU_PATH:
293 {
294 UICmdRespHeader resp;
295 UICmdGetQemuPath* cmd = (UICmdGetQemuPath*)cmd_param;
296 char* filepath = NULL;
297
298 resp.resp_data_size = 0;
299 resp.result = -1;
300 filepath = qemu_find_file(cmd->type, cmd->filename);
301 if (filepath != NULL) {
302 resp.resp_data_size = strlen(filepath) + 1;
303 }
304 _coreCmdImpl_respond(corecmd, &resp, filepath);
305 if (filepath != NULL) {
306 qemu_free(filepath);
307 }
308 break;
309 }
310
311 case AUICMD_GET_LCD_DENSITY:
312 {
313 UICmdRespHeader resp;
314 resp.resp_data_size = 0;
315 resp.result = android_hw->hw_lcd_density;
316 _coreCmdImpl_respond(corecmd, &resp, NULL);
317 break;
318 }
319
320 default:
321 derror("Unknown UI control command %d is received by the Core.\n",
322 cmd_header->cmd_type);
323 break;
324 }
325 }
326
327 /* Asynchronous I/O callback reading UI control commands.
328 * Param:
329 * opaque - CoreCmdImpl instance.
330 * events - Lists I/O event (read or write) this callback is called for.
331 */
332 static void
_coreCmdImpl_io_func(void * opaque,int fd,unsigned events)333 _coreCmdImpl_io_func(void* opaque, int fd, unsigned events)
334 {
335 AsyncStatus status;
336 CoreCmdImpl* corecmd;
337
338 if (events & LOOP_IO_WRITE) {
339 // We don't use async writer here, so we don't expect
340 // any write callbacks.
341 derror("Unexpected LOOP_IO_WRITE in _coreCmdImpl_io_func\n");
342 return;
343 }
344
345 corecmd = (CoreCmdImpl*)opaque;
346
347 // Read whatever is expected from the socket.
348 status = asyncReader_read(&corecmd->async_reader);
349 switch (status) {
350 case ASYNC_COMPLETE:
351 switch (corecmd->cmd_state) {
352 case EXPECTS_HEADER:
353 // We just read the command header. Now we expect the param.
354 if (corecmd->cmd_header.cmd_param_size != 0) {
355 corecmd->cmd_state = EXPECTS_PARAMETERS;
356 // Setup the reader to read expected amount of data.
357 _alloc_cmd_param_buf(corecmd,
358 corecmd->cmd_header.cmd_param_size);
359 asyncReader_init(&corecmd->async_reader,
360 corecmd->cmd_param_buf,
361 corecmd->cmd_header.cmd_param_size,
362 &corecmd->io);
363 } else {
364 // Command doesn't have param. Go ahead and handle it.
365 _coreCmdImpl_handle_command(corecmd, &corecmd->cmd_header,
366 NULL);
367 // Prepare for the next header.
368 corecmd->cmd_state = EXPECTS_HEADER;
369 asyncReader_init(&corecmd->async_reader,
370 &corecmd->cmd_header,
371 sizeof(corecmd->cmd_header),
372 &corecmd->io);
373 }
374 break;
375
376 case EXPECTS_PARAMETERS:
377 // Entore command is received. Handle it.
378 _coreCmdImpl_handle_command(corecmd, &corecmd->cmd_header,
379 corecmd->cmd_param_buf);
380 _free_cmd_param_buf(corecmd);
381 // Prepare for the next command.
382 corecmd->cmd_state = EXPECTS_HEADER;
383 asyncReader_init(&corecmd->async_reader, &corecmd->cmd_header,
384 sizeof(corecmd->cmd_header), &corecmd->io);
385 break;
386 }
387 break;
388
389 case ASYNC_ERROR:
390 loopIo_dontWantRead(&corecmd->io);
391 if (errno == ECONNRESET) {
392 // UI has exited. We need to destroy the service.
393 destroy_corecmd_client();
394 }
395 break;
396
397 case ASYNC_NEED_MORE:
398 // Transfer will eventually come back into this routine.
399 return;
400 }
401 }
402
403 int
coreCmdImpl_create(int fd)404 coreCmdImpl_create(int fd)
405 {
406 _coreCmdImpl.sock = fd;
407 _coreCmdImpl.looper = looper_newCore();
408 loopIo_init(&_coreCmdImpl.io, _coreCmdImpl.looper, _coreCmdImpl.sock,
409 _coreCmdImpl_io_func, &_coreCmdImpl);
410 _coreCmdImpl.cmd_state = EXPECTS_HEADER;
411 _coreCmdImpl.cmd_param_buf = &_coreCmdImpl.cmd_param[0];
412 asyncReader_init(&_coreCmdImpl.async_reader, &_coreCmdImpl.cmd_header,
413 sizeof(_coreCmdImpl.cmd_header), &_coreCmdImpl.io);
414 _coreCmdImpl.sync_writer = syncsocket_init(fd);
415 if (_coreCmdImpl.sync_writer == NULL) {
416 derror("Unable to create writer for CoreCmdImpl instance: %s\n",
417 errno_str);
418 coreCmdImpl_destroy();
419 return -1;
420 }
421 return 0;
422 }
423
424 void
coreCmdImpl_destroy()425 coreCmdImpl_destroy()
426 {
427 // Destroy the writer
428 if (_coreCmdImpl.sync_writer != NULL) {
429 syncsocket_close(_coreCmdImpl.sync_writer);
430 syncsocket_free(_coreCmdImpl.sync_writer);
431 }
432 if (_coreCmdImpl.looper != NULL) {
433 // Stop all I/O that may still be going on.
434 loopIo_done(&_coreCmdImpl.io);
435 looper_free(_coreCmdImpl.looper);
436 _coreCmdImpl.looper = NULL;
437 }
438 // Free allocated memory.
439 _free_cmd_param_buf(&_coreCmdImpl);
440 }
441