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