Home | History | Annotate | Download | only in protocol
      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*
     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
    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
    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
    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
    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
    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
    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
    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