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