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 */
32typedef 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 */
42typedef 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. */
74static CoreCmdImpl    _coreCmdImpl;
75
76/* Implemented in android/console.c */
77extern void destroy_corecmd_client(void);
78/* Implemented in vl-android.c */
79extern 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 */
84static uint8_t*
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 */
99static void
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 */
113static int
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 */
129static int
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 */
160static void
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 */
332static void
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
403int
404coreCmdImpl_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
424void
425coreCmdImpl_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