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 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
     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
     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
    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
    133 corecmd_toggle_network()
    134 {
    135     return _coreCmdProxy_send_command(AUICMD_TOGGLE_NETWORK, NULL, 0);
    136 }
    137 
    138 int
    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
    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
    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
    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
    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
    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
    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
    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