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