diff options
author | Vladimir Chtchetkine <vchtchetkine@google.com> | 2011-01-26 11:19:19 -0800 |
---|---|---|
committer | Vladimir Chtchetkine <vchtchetkine@google.com> | 2011-01-28 09:14:01 -0800 |
commit | 777eb68eb60cac18f4b62e2e1b14a906875cbe7a (patch) | |
tree | 5850f03e01bb348ad7fc4e92dd08695416650c48 | |
parent | 316669d58104cb260e2ffa1848f24547b71af49c (diff) | |
download | external_qemu-777eb68eb60cac18f4b62e2e1b14a906875cbe7a.zip external_qemu-777eb68eb60cac18f4b62e2e1b14a906875cbe7a.tar.gz external_qemu-777eb68eb60cac18f4b62e2e1b14a906875cbe7a.tar.bz2 |
Refactored ui-core-control and core-ui-control protocols
Also cleaned the code up from obsolete ui-core-protocol.* and
core-ui-protocol.*
Change-Id: I194bec669d25b68a10c32b2be50bc9da50c52ebb
33 files changed, 2026 insertions, 1818 deletions
diff --git a/Makefile.android b/Makefile.android index 58b37f1..a5336aa 100644 --- a/Makefile.android +++ b/Makefile.android @@ -799,9 +799,6 @@ UI_AND_CORE_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR) UI_AND_CORE_SOURCES += $(LIBPNG_SOURCES) UI_AND_CORE_CFLAGS += $(LIBPNG_CFLAGS) -I$(LOCAL_PATH)/$(LIBPNG_DIR) -# temp files used to collect UI->Core exchange protocol. -UI_AND_CORE_SOURCES += android/ui-core-protocol.c android/core-ui-protocol.c - # The common libraries # QEMU_SYSTEM_LDLIBS := -lm @@ -879,6 +876,8 @@ VL_SOURCES := framebuffer.c \ user-events-qemu.c \ android/cmdline-option.c \ android/looper-qemu.c \ + android/protocol/ui-commands-qemu.c \ + android/protocol/core-commands-qemu.c \ android/main.c \ # Add common system libraries @@ -1059,7 +1058,8 @@ VL_SOURCES := framebuffer.c \ android/display-core.c \ android/framebuffer-core.c \ android/user-events-core.c \ - android/ui-ctl-core.c \ + android/protocol/ui-commands-proxy.c \ + android/protocol/core-commands-impl.c \ # Add common system libraries # @@ -1217,7 +1217,8 @@ VL_SOURCES := framebuffer.c \ console-ui.c \ iolooper-select.c \ android/framebuffer-ui.c \ - android/ui-ctl-ui.c \ + android/protocol/ui-commands-impl.c \ + android/protocol/core-commands-proxy.c \ # Add common system libraries # diff --git a/android/console.c b/android/console.c index 81c2efe..42c3eb6 100644 --- a/android/console.c +++ b/android/console.c @@ -50,11 +50,12 @@ #include "user-events.h" #include "android/keycode-array.h" #include "android/charmap.h" -#include "android/core-ui-protocol.h" #include "android/display-core.h" #include "android/framebuffer-core.h" #include "android/user-events-core.h" -#include "android/ui-ctl-core.h" +#include "android/protocol/ui-commands-api.h" +#include "android/protocol/core-commands-impl.h" +#include "android/protocol/ui-commands-proxy.h" #if defined(CONFIG_SLIRP) #include "libslirp.h" @@ -263,12 +264,12 @@ control_client_destroy( ControlClient client ) } if (client == ui_core_ctl_client) { - uicorectl_destroy(); + coreCmdImpl_destroy(); ui_core_ctl_client = NULL; } if (client == core_ui_ctl_client) { - coreuictl_destroy(); + uiCmdProxy_destroy(); core_ui_ctl_client = NULL; } #endif // CONFIG_STANDALONE_CORE @@ -2443,7 +2444,7 @@ do_window_scale( ControlClient client, char* args ) } } - android_ui_set_window_scale( scale, is_dpi ); + uicmd_set_window_scale( scale, is_dpi ); return 0; } @@ -2624,7 +2625,7 @@ do_create_ui_core_ctl_service( ControlClient client, char* args ) return -1; } - if (!uicorectl_create(client->sock)) { + if (!coreCmdImpl_create(client->sock)) { char reply_buf[4096]; ui_core_ctl_client = client; snprintf(reply_buf, sizeof(reply_buf), "OK\r\n"); @@ -2646,6 +2647,14 @@ destroy_ui_core_ctl_client(void) } } +void +destroy_corecmd_client(void) +{ + if (ui_core_ctl_client != NULL) { + control_client_destroy(ui_core_ctl_client); + } +} + static int do_create_core_ui_ctl_service( ControlClient client, char* args ) { @@ -2656,7 +2665,7 @@ do_create_core_ui_ctl_service( ControlClient client, char* args ) return -1; } - if (!coreuictl_create(client->sock)) { + if (!uiCmdProxy_create(client->sock)) { char reply_buf[4096]; core_ui_ctl_client = client; snprintf(reply_buf, sizeof(reply_buf), "OK\r\n"); @@ -2677,6 +2686,15 @@ destroy_core_ui_ctl_client(void) control_client_destroy(core_ui_ctl_client); } } + +void +destroy_uicmd_client(void) +{ + if (core_ui_ctl_client != NULL) { + control_client_destroy(core_ui_ctl_client); + } +} + #endif // CONFIG_STANDALONE_CORE static const CommandDefRec qemu_commands[] = diff --git a/android/core-connection.c b/android/core-connection.c index 93a3efe..1099291 100644 --- a/android/core-connection.c +++ b/android/core-connection.c @@ -281,10 +281,15 @@ core_connection_switch_stream(CoreConnection* desc, syncsocket_read_line_absolute(desc->ssocket, buf, sizeof(buf), deadline); _zero_terminate(buf, sizeof(buf), handshake_len); // Replace terminating "\r\n" with 0 - if (handshake_len >= 2 && buf[handshake_len - 2] == '\r') { - buf[handshake_len - 2] = '\0'; + if (handshake_len >= 1) { + if (buf[handshake_len - 1] == '\r' || buf[handshake_len - 1] == '\n') { + buf[handshake_len - 1] = '\0'; + if (handshake_len >= 2 && (buf[handshake_len - 2] == '\r' || + buf[handshake_len - 2] == '\n')) { + buf[handshake_len - 2] = '\0'; + } + } } - printf("Handshake: %s\n", buf); // Lets see what kind of response we've got here. if (_is_reply_ok(buf, handshake_len)) { *handshake = strdup(buf + 3); @@ -316,6 +321,35 @@ core_connection_switch_stream(CoreConnection* desc, } } +CoreConnection* +core_connection_create_and_switch(SockAddress* console_socket, + const char* stream_name, + char** handshake) +{ + char switch_cmd[256]; + CoreConnection* connection = NULL; + + // Connect to the console service. + connection = core_connection_create(console_socket); + if (connection == NULL) { + return NULL; + } + if (core_connection_open(connection)) { + core_connection_free(connection); + return NULL; + } + + // Perform the switch. + snprintf(switch_cmd, sizeof(switch_cmd), "%s", stream_name); + if (core_connection_switch_stream(connection, switch_cmd, handshake)) { + core_connection_close(connection); + core_connection_free(connection); + return NULL; + } + + return connection; +} + void core_connection_detach(CoreConnection* desc) { diff --git a/android/core-connection.h b/android/core-connection.h index 19e91a1..5701f8c 100644 --- a/android/core-connection.h +++ b/android/core-connection.h @@ -29,8 +29,8 @@ typedef struct CoreConnection CoreConnection; // Maximum number of core porocesses running simultaneously on a machine. #define MAX_CORE_PROCS 16 -// Socket timeout in millisec (set to half a second) -#define CORE_PORT_TIMEOUT_MS 500 +// Socket timeout in millisec (set to 5 seconds) +#define CORE_PORT_TIMEOUT_MS 5000 /* Opens core console socket. * Param: @@ -122,6 +122,20 @@ int core_connection_switch_stream(CoreConnection* desc, const char* stream_name, char** handshake); +/* Creates a console client, and switches it to a given stream. + * console_socket Socket address for the console. + * stream_name Name of the stream to switch to. + * handshake Address of a string to allocate for a handshake message on + * success, or an error message on failure. If upon return from this + * routine that string is not NULL, its buffer must be freed with 'free'. + * Return: + * Allocated and initialized descriptor for the switched client on success, or + * NULL on failure. + */ +CoreConnection* core_connection_create_and_switch(SockAddress* console_socket, + const char* stream_name, + char** handshake); + /* Detaches opened console client from the console. * By console protocol, writing "\r\n" string to the console will destroy the * console client. @@ -138,4 +152,18 @@ void core_connection_detach(CoreConnection* desc); */ int core_connection_get_socket(CoreConnection* desc); +/* Calculates timeout for transferring the given number of bytes via core + * connection. + * Return: + * Number of milliseconds during which the entire number of bytes is expected + * to be transferred via core connection. + */ +static inline int +core_connection_get_timeout(size_t data_size) +{ + // Min 2 seconds + 10 millisec for each transferring byte. + // TODO: Come up with a better arithmetics here. + return 2000 + data_size * 10; +} + #endif // QEMU_ANDROID_CORE_CONNECTION_H diff --git a/android/core-ui-protocol.c b/android/core-ui-protocol.c deleted file mode 100644 index a85ae7c..0000000 --- a/android/core-ui-protocol.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * This file contains helper routines that are used to establish communication - * between Core and UI components of the emulator. This is a temporary file - * where we will collect functional dependencies between Core and UI in the - * process of separating UI and Core in the emulator build. - */ - -#include "android/globals.h" -#include "android/android.h" -#include "android/core-ui-protocol.h" -#if defined(CONFIG_STANDALONE_CORE) -#include "android/ui-ctl-core.h" -#endif // defined(CONFIG_STANDALONE_CORE) - -#if !defined(CONFIG_STANDALONE_CORE) -/* in android/qemulator.c */ -extern void android_emulator_set_window_scale( double, int ); -#endif - -void -android_ui_set_window_scale(double scale, int is_dpi) -{ -#if !defined(CONFIG_STANDALONE_CORE) - android_emulator_set_window_scale(scale, is_dpi); -#else - coreuictl_set_window_scale(scale, is_dpi); -#endif -} - diff --git a/android/core-ui-protocol.h b/android/core-ui-protocol.h deleted file mode 100644 index 5fc2372..0000000 --- a/android/core-ui-protocol.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * This file contains declarations of helper routines that are used to - * establish communication between Core and UI components of the emulator. - * This is a temporary file where we will collect functional dependencies - * between Core and UI in the process of separating UI and Core in the - * emulator build. - */ - -#ifndef QEMU_ANDROID_CORE_UI_PROTOCOL_H -#define QEMU_ANDROID_CORE_UI_PROTOCOL_H - -/* Changes the scale of the emulator window at runtime. */ -void android_ui_set_window_scale(double scale, int is_dpi); - -#endif // QEMU_ANDROID_CORE_UI_PROTOCOL_H diff --git a/android/help.c b/android/help.c index efdcd06..7df6704 100644 --- a/android/help.c +++ b/android/help.c @@ -10,7 +10,7 @@ #include "audio/audio.h" #include <string.h> #include <stdlib.h> -#include "android/ui-core-protocol.h" +#include "android/protocol/core-commands-api.h" /* XXX: TODO: put most of the help stuff in auto-generated files */ @@ -778,7 +778,7 @@ help_shaper(stralloc_t* out) " the format of -netspeed is one of the following (numbers are kbits/s):\n\n" ); - for (n = 0; !android_core_get_android_netspeed(n, &android_netspeed); n++) { + for (n = 0; !corecmd_get_netspeed(n, &android_netspeed); n++) { PRINTF( " -netspeed %-12s %-15s (up: %.1f, down: %.1f)\n", android_netspeed->name, android_netspeed->display, @@ -791,7 +791,7 @@ help_shaper(stralloc_t* out) PRINTF( " -netspeed %-12s %s", "<up>:<down>", "select individual up and down speed\n"); PRINTF( "\n The format of -netdelay is one of the following (numbers are msec):\n\n" ); - for (n = 0; !android_core_get_android_netdelay(n, &android_netdelay); n++) { + for (n = 0; !corecmd_get_netdelay(n, &android_netdelay); n++) { PRINTF( " -netdelay %-10s %-15s (min %d, max %d)\n", android_netdelay->name, android_netdelay->display, android_netdelay->min_ms, android_netdelay->max_ms ); diff --git a/android/main-ui.c b/android/main-ui.c index d150be5..9ab87de 100644 --- a/android/main-ui.c +++ b/android/main-ui.c @@ -61,7 +61,8 @@ #include "android/snapshot.h" #include "android/core-connection.h" #include "android/framebuffer-ui.h" -#include "android/ui-ctl-ui.h" +#include "android/protocol/core-commands-proxy.h" +#include "android/protocol/ui-commands-impl.h" #include "framebuffer.h" #include "iolooper.h" @@ -760,8 +761,8 @@ _adjustPartitionSize( const char* description, // Maximum number of core porocesses running simultaneously on a machine. #define MAX_CORE_PROCS 16 -// Socket timeout in millisec (set to half a second) -#define CORE_PORT_TIMEOUT_MS 500 +// Socket timeout in millisec (set to 5 seconds) +#define CORE_PORT_TIMEOUT_MS 5000 #include "android/async-console.h" @@ -976,7 +977,10 @@ attach_to_core(AndroidOptions* opts) { // implementation there are two UI control services: "ui-core-control" that // handle UI controls initiated in the UI, and "core-ui-control" that handle // UI controls initiated in the core. - if (clientuictl_create(&console_socket)) { + if (coreCmdProxy_create(&console_socket)) { + return -1; + } + if (uiCmdImpl_create(&console_socket)) { return -1; } diff --git a/android/protocol/core-commands-api.h b/android/protocol/core-commands-api.h new file mode 100644 index 0000000..93a569c --- /dev/null +++ b/android/protocol/core-commands-api.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_CORE_COMMANDS_API_H +#define _ANDROID_PROTOCOL_CORE_COMMANDS_API_H + +/* + * Contains the API for calling into the Core with UI control commands. + */ + +#include "android/android.h" +#include "android/hw-sensors.h" + +/* Instructs the Core to change the coarse orientation. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int corecmd_set_coarse_orientation(AndroidCoarseOrientation orient); + +/* Toggles the network in the Core. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int corecmd_toggle_network(); + +/* Starts or stops tracing in the Core. + * Param: + * start - Starts (> 0), or stops (== 0) tracing. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int corecmd_trace_control(int start); + +/* Checks if network is disabled in the Core. + * Return: + * 0 if network is enabled, 1 if it is disabled, or < 0 on failure. + */ +extern int corecmd_is_network_disabled(); + +/* Requests a NetworkSpeed instance from the Core. + * Param: + * index - Index of an entry in the NetworkSpeed array. + * netspeed - Upon success contains allocated and initialized NetworkSpeed + * instance for the given index. Note that strings addressed by "name" and + * "display" fileds in the returned NetworkSpeed instance are containd + * inside the buffer allocated for the returned NetworkSpeed instance. + * Caller of this routine must eventually free the buffer returned in this + * parameter. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int corecmd_get_netspeed(int index, NetworkSpeed** netspeed); + +/* Requests a NetworkLatency instance from the Core. + * Param: + * index - Index of an entry in the NetworkLatency array. + * netdelay - Upon success contains allocated and initialized NetworkLatency + * instance for the given index. Note that strings addressed by "name" and + * "display" fileds in the returned NetworkLatency instance are containd + * inside the buffer allocated for the returned NetworkLatency instance. + * Caller of this routine must eventually free the buffer returned in this + * parameter. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int corecmd_get_netdelay(int index, NetworkLatency** netdelay); + +/* Requests a QEMU file path from the Core. + * Param: + * type, filename - Request parameters that define the file for which path is + * requested. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int corecmd_get_qemu_path(int type, + const char* filename, + char* path, + size_t path_buf_size); + +/* Gets LCD density property from the core properties. + * Return: + * LCD density on success, or < 0 on failure. + */ +extern int corecmd_get_hw_lcd_density(void); + +#endif /* _ANDROID_PROTOCOL_CORE_COMMANDS_API_H */ diff --git a/android/protocol/core-commands-impl.c b/android/protocol/core-commands-impl.c new file mode 100644 index 0000000..7fa2a0b --- /dev/null +++ b/android/protocol/core-commands-impl.c @@ -0,0 +1,440 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains the Core-side implementation of the "ui-core-control" service that is + * part of the UI control protocol. Here we handle UI control commands sent by + * the UI to the Core. + */ + +#include "android/android.h" +#include "android/globals.h" +#include "telephony/modem_driver.h" +#include "trace.h" +#include "android/looper.h" +#include "android/async-utils.h" +#include "android/sync-utils.h" +#include "android/utils/debug.h" +#include "android/protocol/core-commands.h" +#include "android/protocol/core-commands-impl.h" + +/* Enumerates state values for the command reader in the CoreCmdImpl descriptor. + */ +typedef enum CoreCmdImplState { + /* The reader is waiting on command header. */ + EXPECTS_HEADER, + + /* The reader is waiting on command parameters. */ + EXPECTS_PARAMETERS, +} CoreCmdImplState; + +/* Descriptor for the Core-side implementation of the "ui-core-control" service. + */ +typedef struct CoreCmdImpl { + /* Reader to detect UI disconnection. */ + AsyncReader async_reader; + + /* I/O associated with this descriptor. */ + LoopIo io; + + /* Looper used to communicate with the UI. */ + Looper* looper; + + /* Writer to send responses to the UI commands. */ + SyncSocket* sync_writer; + + /* Socket descriptor for this service. */ + int sock; + + /* Command reader state. */ + CoreCmdImplState cmd_state; + + /* Incoming command header. */ + UICmdHeader cmd_header; + + /* A small preallocated buffer for command parameters. */ + uint8_t cmd_param[256]; + + /* Buffer to use for reading command parameters. Depending on expected size + * of the parameters this buffer can point to cmd_param field of this + * structure (for small commands), or can be allocated for large commands. */ + void* cmd_param_buf; +} CoreCmdImpl; + +/* One and only one CoreCmdImpl instance. */ +static CoreCmdImpl _coreCmdImpl; + +/* Implemented in android/console.c */ +extern void destroy_corecmd_client(void); +/* Implemented in vl-android.c */ +extern char* qemu_find_file(int type, const char* filename); + +/* Properly initializes cmd_param_buf field in CoreCmdImpl instance to receive + * the expected command parameters. + */ +static uint8_t* +_alloc_cmd_param_buf(CoreCmdImpl* corecmd, uint32_t size) +{ + if (size < sizeof(corecmd->cmd_param)) { + // cmd_param can contain all request data. + corecmd->cmd_param_buf = &corecmd->cmd_param[0]; + } else { + // Expected request us too large to fit into preallocated buffer. + corecmd->cmd_param_buf = qemu_malloc(size); + } + return corecmd->cmd_param_buf; +} + +/* Properly frees cmd_param_buf field in CoreCmdImpl instance. + */ +static void +_free_cmd_param_buf(CoreCmdImpl* corecmd) +{ + if (corecmd->cmd_param_buf != &corecmd->cmd_param[0]) { + qemu_free(corecmd->cmd_param_buf); + corecmd->cmd_param_buf = &corecmd->cmd_param[0]; + } +} + +/* Calculates timeout for transferring the given number of bytes via socket. + * Return: + * Number of milliseconds during which the entire number of bytes is expected + * to be transferred via socket for this service. + */ +static int +_coreCmdImpl_get_timeout(size_t data_size) +{ + // Min 2 seconds + 10 millisec for each transferring byte. + // TODO: Come up with a better arithmetics here. + return 2000 + data_size * 10; +} + +/* Sends command response back to the UI. + * Param: + * corecmd - CoreCmdImpl instance to use to send the response. + * resp - Response header. + * resp_data - Response data. Data size is defined by the header. + * Return: + * 0 on success, or < 0 on failure. + */ +static int +_coreCmdImpl_respond(CoreCmdImpl* corecmd, UICmdRespHeader* resp, void* resp_data) +{ + int status = syncsocket_start_write(corecmd->sync_writer); + if (!status) { + // Write the header + status = syncsocket_write(corecmd->sync_writer, resp, + sizeof(UICmdRespHeader), + _coreCmdImpl_get_timeout(sizeof(UICmdRespHeader))); + // Write response data (if any). + if (status > 0 && resp_data != NULL && resp->resp_data_size != 0) { + status = syncsocket_write(corecmd->sync_writer, resp_data, + resp->resp_data_size, + _coreCmdImpl_get_timeout(resp->resp_data_size)); + } + status = syncsocket_result(status); + syncsocket_stop_write(corecmd->sync_writer); + } + if (status < 0) { + derror("Core is unable to respond with %u bytes to the UI control command: %s\n", + resp->resp_data_size, errno_str); + } + return status; +} + +/* Handles UI control command received from the UI. + * Param: + * corecmd - CoreCmdImpl instance that received the command. + * cmd_header - Command header. + * cmd_param - Command data. + */ +static void +_coreCmdImpl_handle_command(CoreCmdImpl* corecmd, + const UICmdHeader* cmd_header, + const uint8_t* cmd_param) +{ + switch (cmd_header->cmd_type) { + case AUICMD_SET_COARSE_ORIENTATION: + { + UICmdSetCoarseOrientation* cmd = + (UICmdSetCoarseOrientation*)cmd_param; + android_sensors_set_coarse_orientation(cmd->orient); + break; + } + + case AUICMD_TOGGLE_NETWORK: + qemu_net_disable = !qemu_net_disable; + if (android_modem) { + amodem_set_data_registration( + android_modem, + qemu_net_disable ? A_REGISTRATION_UNREGISTERED + : A_REGISTRATION_HOME); + } + break; + + case AUICMD_TRACE_CONTROL: + { + UICmdTraceControl* cmd = (UICmdTraceControl*)cmd_param; + if (cmd->start) { + start_tracing(); + } else { + stop_tracing(); + } + break; + } + + case AUICMD_CHK_NETWORK_DISABLED: + { + UICmdRespHeader resp; + resp.resp_data_size = 0; + resp.result = qemu_net_disable; + _coreCmdImpl_respond(corecmd, &resp, NULL); + break; + } + + case AUICMD_GET_NETSPEED: + { + UICmdRespHeader resp; + UICmdGetNetSpeedResp* resp_data = NULL; + UICmdGetNetSpeed* cmd = (UICmdGetNetSpeed*)cmd_param; + + resp.resp_data_size = 0; + resp.result = 0; + + if (cmd->index >= android_netspeeds_count || + android_netspeeds[cmd->index].name == NULL) { + resp.result = -1; + } else { + const NetworkSpeed* netspeed = &android_netspeeds[cmd->index]; + // Calculate size of the response data: + // fixed header + zero-terminated netspeed name. + resp.resp_data_size = sizeof(UICmdGetNetSpeedResp) + + strlen(netspeed->name) + 1; + // Count in zero-terminated netspeed display. + if (netspeed->display != NULL) { + resp.resp_data_size += strlen(netspeed->display) + 1; + } else { + resp.resp_data_size++; + } + // Allocate and initialize response data buffer. + resp_data = + (UICmdGetNetSpeedResp*)qemu_malloc(resp.resp_data_size); + resp_data->upload = netspeed->upload; + resp_data->download = netspeed->download; + strcpy(resp_data->name, netspeed->name); + if (netspeed->display != NULL) { + strcpy(resp_data->name + strlen(resp_data->name) + 1, + netspeed->display); + } else { + strcpy(resp_data->name + strlen(resp_data->name) + 1, ""); + } + } + _coreCmdImpl_respond(corecmd, &resp, resp_data); + if (resp_data != NULL) { + qemu_free(resp_data); + } + break; + } + + case AUICMD_GET_NETDELAY: + { + UICmdRespHeader resp; + UICmdGetNetDelayResp* resp_data = NULL; + UICmdGetNetDelay* cmd = (UICmdGetNetDelay*)cmd_param; + + resp.resp_data_size = 0; + resp.result = 0; + + if (cmd->index >= android_netdelays_count || + android_netdelays[cmd->index].name == NULL) { + resp.result = -1; + } else { + const NetworkLatency* netdelay = &android_netdelays[cmd->index]; + // Calculate size of the response data: + // fixed header + zero-terminated netdelay name. + resp.resp_data_size = sizeof(UICmdGetNetDelayResp) + + strlen(netdelay->name) + 1; + // Count in zero-terminated netdelay display. + if (netdelay->display != NULL) { + resp.resp_data_size += strlen(netdelay->display) + 1; + } else { + resp.resp_data_size++; + } + // Allocate and initialize response data buffer. + resp_data = + (UICmdGetNetDelayResp*)qemu_malloc(resp.resp_data_size); + resp_data->min_ms = netdelay->min_ms; + resp_data->max_ms = netdelay->max_ms; + strcpy(resp_data->name, netdelay->name); + if (netdelay->display != NULL) { + strcpy(resp_data->name + strlen(resp_data->name) + 1, + netdelay->display); + } else { + strcpy(resp_data->name + strlen(resp_data->name) + 1, ""); + } + } + _coreCmdImpl_respond(corecmd, &resp, resp_data); + if (resp_data != NULL) { + qemu_free(resp_data); + } + break; + } + + case AUICMD_GET_QEMU_PATH: + { + UICmdRespHeader resp; + UICmdGetQemuPath* cmd = (UICmdGetQemuPath*)cmd_param; + char* filepath = NULL; + + resp.resp_data_size = 0; + resp.result = -1; + filepath = qemu_find_file(cmd->type, cmd->filename); + if (filepath != NULL) { + resp.resp_data_size = strlen(filepath) + 1; + } + _coreCmdImpl_respond(corecmd, &resp, filepath); + if (filepath != NULL) { + qemu_free(filepath); + } + break; + } + + case AUICMD_GET_LCD_DENSITY: + { + UICmdRespHeader resp; + resp.resp_data_size = 0; + resp.result = android_hw->hw_lcd_density; + _coreCmdImpl_respond(corecmd, &resp, NULL); + break; + } + + default: + derror("Unknown UI control command %d is received by the Core.\n", + cmd_header->cmd_type); + break; + } +} + +/* Asynchronous I/O callback reading UI control commands. + * Param: + * opaque - CoreCmdImpl instance. + * events - Lists I/O event (read or write) this callback is called for. + */ +static void +_coreCmdImpl_io_func(void* opaque, int fd, unsigned events) +{ + AsyncStatus status; + CoreCmdImpl* corecmd; + + if (events & LOOP_IO_WRITE) { + // We don't use async writer here, so we don't expect + // any write callbacks. + derror("Unexpected LOOP_IO_WRITE in _coreCmdImpl_io_func\n"); + return; + } + + corecmd = (CoreCmdImpl*)opaque; + + // Read whatever is expected from the socket. + status = asyncReader_read(&corecmd->async_reader, &corecmd->io); + switch (status) { + case ASYNC_COMPLETE: + switch (corecmd->cmd_state) { + case EXPECTS_HEADER: + // We just read the command header. Now we expect the param. + if (corecmd->cmd_header.cmd_param_size != 0) { + corecmd->cmd_state = EXPECTS_PARAMETERS; + // Setup the reader to read expected amount of data. + _alloc_cmd_param_buf(corecmd, + corecmd->cmd_header.cmd_param_size); + asyncReader_init(&corecmd->async_reader, + corecmd->cmd_param_buf, + corecmd->cmd_header.cmd_param_size, + &corecmd->io); + } else { + // Command doesn't have param. Go ahead and handle it. + _coreCmdImpl_handle_command(corecmd, &corecmd->cmd_header, + NULL); + // Prepare for the next header. + corecmd->cmd_state = EXPECTS_HEADER; + asyncReader_init(&corecmd->async_reader, + &corecmd->cmd_header, + sizeof(corecmd->cmd_header), + &corecmd->io); + } + break; + + case EXPECTS_PARAMETERS: + // Entore command is received. Handle it. + _coreCmdImpl_handle_command(corecmd, &corecmd->cmd_header, + corecmd->cmd_param_buf); + _free_cmd_param_buf(corecmd); + // Prepare for the next command. + corecmd->cmd_state = EXPECTS_HEADER; + asyncReader_init(&corecmd->async_reader, &corecmd->cmd_header, + sizeof(corecmd->cmd_header), &corecmd->io); + break; + } + break; + + case ASYNC_ERROR: + loopIo_dontWantRead(&corecmd->io); + if (errno == ECONNRESET) { + // UI has exited. We need to destroy the service. + destroy_corecmd_client(); + } + break; + + case ASYNC_NEED_MORE: + // Transfer will eventually come back into this routine. + return; + } +} + +int +coreCmdImpl_create(int fd) +{ + _coreCmdImpl.sock = fd; + _coreCmdImpl.looper = looper_newCore(); + loopIo_init(&_coreCmdImpl.io, _coreCmdImpl.looper, _coreCmdImpl.sock, + _coreCmdImpl_io_func, &_coreCmdImpl); + _coreCmdImpl.cmd_state = EXPECTS_HEADER; + _coreCmdImpl.cmd_param_buf = &_coreCmdImpl.cmd_param[0]; + asyncReader_init(&_coreCmdImpl.async_reader, &_coreCmdImpl.cmd_header, + sizeof(_coreCmdImpl.cmd_header), &_coreCmdImpl.io); + _coreCmdImpl.sync_writer = syncsocket_init(fd); + if (_coreCmdImpl.sync_writer == NULL) { + derror("Unable to create writer for CoreCmdImpl instance: %s\n", + errno_str); + coreCmdImpl_destroy(); + return -1; + } + return 0; +} + +void +coreCmdImpl_destroy() +{ + // Destroy the writer + if (_coreCmdImpl.sync_writer != NULL) { + syncsocket_close(_coreCmdImpl.sync_writer); + syncsocket_free(_coreCmdImpl.sync_writer); + } + if (_coreCmdImpl.looper != NULL) { + // Stop all I/O that may still be going on. + loopIo_done(&_coreCmdImpl.io); + looper_free(_coreCmdImpl.looper); + _coreCmdImpl.looper = NULL; + } + // Free allocated memory. + _free_cmd_param_buf(&_coreCmdImpl); +} diff --git a/android/protocol/core-commands-impl.h b/android/protocol/core-commands-impl.h new file mode 100644 index 0000000..8690613 --- /dev/null +++ b/android/protocol/core-commands-impl.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_CORE_COMMANDS_IMPL_H +#define _ANDROID_PROTOCOL_CORE_COMMANDS_IMPL_H + +/* + * Contains the Core-side implementation of the "ui-core-control" service that is + * part of the UI control protocol. Here we handle UI control commands sent by + * the UI to the Core. + */ + +/* Creates and initializes descriptor for the Core-side of the "ui-core-control" + * service. Note that there can be only one instance of this service in the core. + * Param: + * fd - Socket descriptor for the service. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int coreCmdImpl_create(int fd); + +/* Destroys the descriptor for the Core-side of the "ui-core-control" service. */ +extern void coreCmdImpl_destroy(); + +#endif /* _ANDROID_PROTOCOL_CORE_COMMANDS_IMPL_H */ diff --git a/android/protocol/core-commands-proxy.c b/android/protocol/core-commands-proxy.c new file mode 100644 index 0000000..6bd3d4e --- /dev/null +++ b/android/protocol/core-commands-proxy.c @@ -0,0 +1,374 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains the UI-side implementation of the "ui-core-control" service that is + * part of the UI control protocol. Here we send UI control commands to the Core. + */ + +#include "console.h" +#include "android/looper.h" +#include "android/core-connection.h" +#include "android/async-utils.h" +#include "android/sync-utils.h" +#include "android/utils/debug.h" +#include "android/utils/panic.h" +#include "android/protocol/core-commands.h" +#include "android/protocol/core-commands-proxy.h" +#include "android/protocol/core-commands-api.h" + +/* Descriptor for the UI-side "ui-core-control" service. */ +typedef struct CoreCmdProxy { + /* Core connection established for this service. */ + CoreConnection* core_connection; + + /* Socket descriptor for the UI service. */ + int sock; + + /* Socket wrapper for sync srites. */ + SyncSocket* sync_writer; + + /* Socket wrapper for sync reads. */ + SyncSocket* sync_reader; +} CoreCmdProxy; + +/* One and only one CoreCmdProxy instance. */ +static CoreCmdProxy _coreCmdProxy = { 0 }; + +/* Sends UI command to the core. + * Param: + * cmd_type, cmd_param, cmd_param_size - Define the command. + * Return: + * 0 On success, or < 0 on failure. + */ +static int +_coreCmdProxy_send_command(uint8_t cmd_type, + void* cmd_param, + uint32_t cmd_param_size) +{ + int status; + UICmdHeader header; + + // Prepare the command header. + header.cmd_type = cmd_type; + header.cmd_param_size = cmd_param_size; + status = syncsocket_start_write(_coreCmdProxy.sync_writer); + if (!status) { + // Send the header. + status = syncsocket_write(_coreCmdProxy.sync_writer, &header, + sizeof(header), + core_connection_get_timeout(sizeof(header))); + // If there is request data, send it too. + if (status > 0 && cmd_param != NULL && cmd_param_size > 0) { + status = syncsocket_write(_coreCmdProxy.sync_writer, cmd_param, + cmd_param_size, + core_connection_get_timeout(cmd_param_size)); + } + status = syncsocket_result(status); + syncsocket_stop_write(_coreCmdProxy.sync_writer); + } + if (status < 0) { + derror("Unable to send UI control command %d (size %u): %s\n", + cmd_type, cmd_param_size, errno_str); + } + return status; +} + +/* Reads UI control command response from the core. + * Param: + * resp - Upon success contains command response header. + * resp_data - Upon success contains allocated reponse data (if any). The caller + * is responsible for deallocating the memory returned here. + * Return: + * 0 on success, or < 0 on failure. + */ +static int +_coreCmdProxy_get_response(UICmdRespHeader* resp, void** resp_data) +{ + int status = syncsocket_start_read(_coreCmdProxy.sync_reader); + if (!status) { + // Read the header. + status = syncsocket_read(_coreCmdProxy.sync_reader, resp, + sizeof(UICmdRespHeader), + core_connection_get_timeout(sizeof(UICmdRespHeader))); + // Read response data (if any). + if (status > 0 && resp->resp_data_size) { + *resp_data = malloc(resp->resp_data_size); + if (*resp_data == NULL) { + APANIC("_coreCmdProxy_get_response is unable to allocate response data buffer.\n"); + } + status = syncsocket_read(_coreCmdProxy.sync_reader, *resp_data, + resp->resp_data_size, + core_connection_get_timeout(resp->resp_data_size)); + } + status = syncsocket_result(status); + syncsocket_stop_read(_coreCmdProxy.sync_reader); + } + if (status < 0) { + derror("Unable to get UI command response from the Core: %s\n", + errno_str); + } + return status; +} + +/* Destroys CoreCmdProxy instance. */ +static void +_coreCmdProxy_destroy(void) +{ + if (_coreCmdProxy.sync_writer != NULL) { + syncsocket_close(_coreCmdProxy.sync_writer); + syncsocket_free(_coreCmdProxy.sync_writer); + } + if (_coreCmdProxy.sync_reader != NULL) { + syncsocket_close(_coreCmdProxy.sync_reader); + syncsocket_free(_coreCmdProxy.sync_reader); + } + if (_coreCmdProxy.core_connection != NULL) { + core_connection_close(_coreCmdProxy.core_connection); + core_connection_free(_coreCmdProxy.core_connection); + _coreCmdProxy.core_connection = NULL; + } +} + +int +corecmd_set_coarse_orientation(AndroidCoarseOrientation orient) +{ + UICmdSetCoarseOrientation cmd; + cmd.orient = orient; + return _coreCmdProxy_send_command(AUICMD_SET_COARSE_ORIENTATION, + &cmd, sizeof(cmd)); +} + +int +corecmd_toggle_network() +{ + return _coreCmdProxy_send_command(AUICMD_TOGGLE_NETWORK, NULL, 0); +} + +int +corecmd_trace_control(int start) +{ + UICmdTraceControl cmd; + cmd.start = start; + return _coreCmdProxy_send_command(AUICMD_TRACE_CONTROL, + &cmd, sizeof(cmd)); +} + +int +corecmd_is_network_disabled() +{ + UICmdRespHeader resp; + void* tmp = NULL; + int status; + + status = _coreCmdProxy_send_command(AUICMD_CHK_NETWORK_DISABLED, NULL, 0); + if (status < 0) { + return status; + } + status = _coreCmdProxy_get_response(&resp, &tmp); + if (status < 0) { + return status; + } + return resp.result; +} + +int +corecmd_get_netspeed(int index, NetworkSpeed** netspeed) +{ + UICmdGetNetSpeed req; + UICmdRespHeader resp; + UICmdGetNetSpeedResp* resp_data = NULL; + int status; + + // Initialize and send the query. + req.index = index; + status = _coreCmdProxy_send_command(AUICMD_GET_NETSPEED, &req, sizeof(req)); + if (status < 0) { + return status; + } + + // Obtain the response from the core. + status = _coreCmdProxy_get_response(&resp, (void**)&resp_data); + if (status < 0) { + return status; + } + if (!resp.result) { + NetworkSpeed* ret; + // Allocate memory for the returning NetworkSpeed instance. + // It includes: NetworkSpeed structure + + // size of zero-terminated "name" and "display" strings saved in + // resp_data. + *netspeed = malloc(sizeof(NetworkSpeed) + 1 + + resp.resp_data_size - sizeof(UICmdGetNetSpeedResp)); + ret = *netspeed; + + // Copy data obtained from the core to the returning NetworkSpeed + // instance. + ret->upload = resp_data->upload; + ret->download = resp_data->download; + ret->name = (char*)ret + sizeof(NetworkSpeed); + strcpy((char*)ret->name, resp_data->name); + ret->display = ret->name + strlen(ret->name) + 1; + strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1); + } + if (resp_data != NULL) { + free(resp_data); + } + return resp.result; +} + +int +corecmd_get_netdelay(int index, NetworkLatency** netdelay) +{ + UICmdGetNetDelay req; + UICmdRespHeader resp; + UICmdGetNetDelayResp* resp_data = NULL; + int status; + + // Initialize and send the query. + req.index = index; + status = _coreCmdProxy_send_command(AUICMD_GET_NETDELAY, &req, sizeof(req)); + if (status < 0) { + return status; + } + + // Obtain the response from the core. + status = _coreCmdProxy_get_response(&resp, (void**)&resp_data); + if (status < 0) { + return status; + } + if (!resp.result) { + NetworkLatency* ret; + // Allocate memory for the returning NetworkLatency instance. + // It includes: NetworkLatency structure + + // size of zero-terminated "name" and "display" strings saved in + // resp_data. + *netdelay = malloc(sizeof(NetworkLatency) + 1 + + resp.resp_data_size - sizeof(UICmdGetNetDelayResp)); + ret = *netdelay; + + // Copy data obtained from the core to the returning NetworkLatency + // instance. + ret->min_ms = resp_data->min_ms; + ret->max_ms = resp_data->max_ms; + ret->name = (char*)ret + sizeof(NetworkLatency); + strcpy((char*)ret->name, resp_data->name); + ret->display = ret->name + strlen(ret->name) + 1; + strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1); + } + if (resp_data != NULL) { + free(resp_data); + } + return resp.result; +} + +int +corecmd_get_qemu_path(int type, + const char* filename, + char* path, + size_t path_buf_size) +{ + UICmdRespHeader resp; + char* resp_data = NULL; + int status; + + // Initialize and send the query. + uint32_t cmd_data_size = sizeof(UICmdGetQemuPath) + strlen(filename) + 1; + UICmdGetQemuPath* req = (UICmdGetQemuPath*)malloc(cmd_data_size); + if (req == NULL) { + APANIC("corecmd_get_qemu_path is unable to allocate %u bytes\n", + cmd_data_size); + } + req->type = type; + strcpy(req->filename, filename); + status = _coreCmdProxy_send_command(AUICMD_GET_QEMU_PATH, req, + cmd_data_size); + if (status < 0) { + return status; + } + + // Obtain the response from the core. + status = _coreCmdProxy_get_response(&resp, (void**)&resp_data); + if (status < 0) { + return status; + } + if (!resp.result && resp_data != NULL) { + strncpy(path, resp_data, path_buf_size); + path[path_buf_size - 1] = '\0'; + } + if (resp_data != NULL) { + free(resp_data); + } + return resp.result; +} + +int +corecmd_get_hw_lcd_density(void) +{ + UICmdRespHeader resp; + void* tmp = NULL; + int status; + + status = _coreCmdProxy_send_command(AUICMD_GET_LCD_DENSITY, NULL, 0); + if (status < 0) { + return status; + } + status = _coreCmdProxy_get_response(&resp, &tmp); + if (status < 0) { + return status; + } + return resp.result; +} + +int +coreCmdProxy_create(SockAddress* console_socket) +{ + char* handshake = NULL; + + // Connect to the ui-core-control service. + _coreCmdProxy.core_connection = + core_connection_create_and_switch(console_socket, "ui-core-control", + &handshake); + if (_coreCmdProxy.core_connection == NULL) { + derror("Unable to connect to the ui-core-control service: %s\n", + errno_str); + return -1; + } + + // Initialze command writer and response reader. + _coreCmdProxy.sock = core_connection_get_socket(_coreCmdProxy.core_connection); + _coreCmdProxy.sync_writer = syncsocket_init(_coreCmdProxy.sock); + if (_coreCmdProxy.sync_writer == NULL) { + derror("Unable to initialize CoreCmdProxy writer: %s\n", errno_str); + _coreCmdProxy_destroy(); + return -1; + } + _coreCmdProxy.sync_reader = syncsocket_init(_coreCmdProxy.sock); + if (_coreCmdProxy.sync_reader == NULL) { + derror("Unable to initialize CoreCmdProxy reader: %s\n", errno_str); + _coreCmdProxy_destroy(); + return -1; + } + + + fprintf(stdout, "ui-core-control is now connected to the core at %s.", + sock_address_to_string(console_socket)); + if (handshake != NULL) { + if (handshake[0] != '\0') { + fprintf(stdout, " Handshake: %s", handshake); + } + free(handshake); + } + fprintf(stdout, "\n"); + + return 0; +} diff --git a/android/protocol/core-commands-proxy.h b/android/protocol/core-commands-proxy.h new file mode 100644 index 0000000..8303ed4 --- /dev/null +++ b/android/protocol/core-commands-proxy.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_CORE_COMMANDS_PROXY_H +#define _ANDROID_PROTOCOL_CORE_COMMANDS_PROXY_H + +#include "sockets.h" + +/* + * Contains the UI-side implementation of the "ui-core-control" service that is + * part of the UI control protocol. Here we send UI control commands to the Core. + */ + +/* Creates and initializes descriptor for the UI-side of the "ui-core-control" + * service. Note that there can be only one instance of this service in the UI. + * Param: + * console_socket - Addresses Core's console. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int coreCmdProxy_create(SockAddress* console_socket); + +#endif /* _ANDROID_PROTOCOL_CORE_COMMANDS_PROXY_H */ diff --git a/android/protocol/core-commands-qemu.c b/android/protocol/core-commands-qemu.c new file mode 100644 index 0000000..03fef64 --- /dev/null +++ b/android/protocol/core-commands-qemu.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of the API for calling into the Core with the UI + * control commands for standalone (monolithic) emulator. + */ + +#include "android/android.h" +#include "android/globals.h" +#include "android/hw-sensors.h" +#include "telephony/modem_driver.h" +#include "trace.h" +#include "audio/audio.h" +#include "android/protocol/core-commands-api.h" + +/* Implemented in vl-android.c */ +extern char* qemu_find_file(int type, const char* filename); + +int +corecmd_set_coarse_orientation(AndroidCoarseOrientation orient) +{ + android_sensors_set_coarse_orientation(orient); + return 0; +} + +int +corecmd_toggle_network() +{ + qemu_net_disable = !qemu_net_disable; + if (android_modem) { + amodem_set_data_registration( + android_modem, + qemu_net_disable ? A_REGISTRATION_UNREGISTERED + : A_REGISTRATION_HOME); + } + return 0; +} + +int corecmd_trace_control(int start) +{ + if (start) { + start_tracing(); + } else { + stop_tracing(); + } + return 0; +} + +int corecmd_is_network_disabled() +{ + return qemu_net_disable; +} + +int +corecmd_get_netspeed(int index, NetworkSpeed** netspeed) +{ + if (index >= android_netspeeds_count || + android_netspeeds[index].name == NULL) { + return -1; + } + *netspeed = (NetworkSpeed*)malloc(sizeof(NetworkSpeed)); + memcpy(*netspeed, &android_netspeeds[index], sizeof(NetworkSpeed)); + return 0; +} + +int +corecmd_get_netdelay(int index, NetworkLatency** netdelay) +{ + if (index >= android_netdelays_count || + android_netdelays[index].name == NULL) { + return -1; + } + *netdelay = (NetworkLatency*)malloc(sizeof(NetworkLatency)); + memcpy(*netdelay, &android_netdelays[index], sizeof(NetworkLatency)); + return 0; +} + +int +corecmd_get_qemu_path(int type, + const char* filename, + char* path, + size_t path_buf_size) +{ + char* filepath = qemu_find_file(type, filename); + if (filepath == NULL) { + return -1; + } + strncpy(path, filepath, path_buf_size); + path[path_buf_size - 1] = '\0'; + qemu_free(filepath); + return 0; +} + +int +corecmd_get_hw_lcd_density(void) +{ + return android_hw->hw_lcd_density; +} diff --git a/android/protocol/core-commands.h b/android/protocol/core-commands.h new file mode 100644 index 0000000..3ac0ca5 --- /dev/null +++ b/android/protocol/core-commands.h @@ -0,0 +1,104 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_CORE_COMMANDS_H +#define _ANDROID_PROTOCOL_CORE_COMMANDS_H + +/* + * Contains declarations related to the UI control commands sent by the UI and + * handled by the Core. + */ + +#include "android/hw-sensors.h" +#include "android/protocol/ui-common.h" + +/* Sets coarse orientation. */ +#define AUICMD_SET_COARSE_ORIENTATION 1 + +/* Toggles the network. */ +#define AUICMD_TOGGLE_NETWORK 2 + +/* Starts / stops the tracing. */ +#define AUICMD_TRACE_CONTROL 3 + +/* Checks if network is disabled. */ +#define AUICMD_CHK_NETWORK_DISABLED 4 + +/* Gets network speed. */ +#define AUICMD_GET_NETSPEED 5 + +/* Gets network delays */ +#define AUICMD_GET_NETDELAY 6 + +/* Gets path to a QEMU file on local host. */ +#define AUICMD_GET_QEMU_PATH 7 + +/* Gets LCD density. */ +#define AUICMD_GET_LCD_DENSITY 8 + +/* Formats AUICMD_SET_COARSE_ORIENTATION UI control command parameters. */ +typedef struct UICmdSetCoarseOrientation { + AndroidCoarseOrientation orient; +} UICmdSetCoarseOrientation; + +/* Formats AUICMD_TRACE_CONTROL UI control command parameters. */ +typedef struct UICmdTraceControl { + int start; +} UICmdTraceControl; + +/* Formats AUICMD_GET_NETSPEED UI control command parameters. */ +typedef struct UICmdGetNetSpeed { + int index; +} UICmdGetNetSpeed; + +/* Formats AUICMD_GET_NETSPEED UI control command response. + * Instances of this structure contains content of the NetworkSpeed structure, + * including actual "name" and "display" strings. */ +typedef struct UICmdGetNetSpeedResp { + int upload; + int download; + /* Zero-terminated NetworkSpeed's "name" strings starts here. The "display" + * string begins inside this structure, right after the "name"'s + * zero-terminator. */ + char name[0]; +} UICmdGetNetSpeedResp; + +/* Formats AUICMD_GET_NETDELAY UI control command parameters. */ +typedef struct UICmdGetNetDelay { + int index; +} UICmdGetNetDelay; + +/* Formats AUICMD_GET_NETDELAY UI control command response. + * Instances of this structure contains content of the NetworkLatency structure, + * including actual "name" and "display" strings. */ +typedef struct UICmdGetNetDelayResp { + int min_ms; + int max_ms; + /* Zero-terminated NetworkLatency's "name" strings starts here. The "display" + * string begins inside this structure, right after the "name"'s + * zero-terminator. */ + char name[0]; +} UICmdGetNetDelayResp; + +/* Formats AUICMD_GET_QEMU_PATH UI control command parameters. */ +typedef struct UICmdGetQemuPath { + int type; + char filename[0]; +} UICmdGetQemuPath; + +/* Formats AUICMD_GET_QEMU_PATH UI control command response. */ +typedef struct UICmdGetQemuPathResp { + /* Queried qemu path begins here. */ + char path[0]; +} UICmdGetQemuPathResp; + +#endif /* _ANDROID_PROTOCOL_CORE_COMMANDS_H */ diff --git a/android/protocol/ui-commands-api.h b/android/protocol/ui-commands-api.h new file mode 100644 index 0000000..d9fe6b0 --- /dev/null +++ b/android/protocol/ui-commands-api.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_UI_COMMANDS_API_H +#define _ANDROID_PROTOCOL_UI_COMMANDS_API_H + +/* + * Contains the API for calling into the UI with the Core control commands. + */ + +/* Changes the scale of the emulator window at runtime. + * Param: + * scale, is_dpi - New window scale parameters + * Return: + * 0 on success, or < 0 on failure. + */ +extern int uicmd_set_window_scale(double scale, int is_dpi); + +/* This is temporary redeclaration for AndroidHwLightBrightnessFunc declared + * in android/hw-control.h We redeclare it here in order to keep type + * consistency between android_core_set_brightness_change_callback and + * light_brightness field of AndroidHwControlFuncs structure. + */ +typedef void (*AndroidHwLightBrightnessCallback)(void* opaque, + const char* light, + int brightness); + +/* Registers a UI callback to be called when brightness is changed by the core. */ +extern int uicmd_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback, + void* opaque); + +#endif /* _ANDROID_PROTOCOL_UI_COMMANDS_API_H */ diff --git a/android/protocol/ui-commands-impl.c b/android/protocol/ui-commands-impl.c new file mode 100644 index 0000000..456c61e --- /dev/null +++ b/android/protocol/ui-commands-impl.c @@ -0,0 +1,257 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains the UI-side implementation of the "core-ui-control" service that is + * part of the UI control protocol. Here we handle UI control commands received + * from the Core. + */ + +#include "console.h" +//#include "android/hw-control.h" +#include "android/looper.h" +#include "android/core-connection.h" +#include "android/async-utils.h" +#include "android/sync-utils.h" +#include "android/utils/system.h" +#include "android/utils/debug.h" +#include "android/utils/panic.h" +#include "android/protocol/ui-commands-impl.h" +#include "android/protocol/ui-commands-api.h" + +/* Enumerates states for the command reader in UICmdImpl instance. */ +typedef enum UICmdImplState { + /* The reader is waiting on command header. */ + EXPECTS_HEADER, + + /* The reader is waiting on command parameters. */ + EXPECTS_PARAMETERS, +} UICmdImplState; + +/* Descriptor for the UI-side of the "core-ui-control" service. */ +typedef struct UICmdImpl { + /* Core connection established for this service. */ + CoreConnection* core_connection; + + /* Socket descriptor for the UI service. */ + int sock; + + /* Command reader state. */ + UICmdImplState reader_state; + + /* Incoming command header. */ + UICmdHeader cmd_header; + + /* Reader's buffer. This field can point to the cmd_header field of this + * structure (when we expect a command header), or to a buffer allocated for + * the (when we expect command parameters). */ + uint8_t* reader_buffer; + + /* Offset in the reader's buffer where to read next chunk of data. */ + size_t reader_offset; + + /* Total number of bytes the reader expects to read. */ + size_t reader_bytes; +} UICmdImpl; + +/* Implemented in android/qemulator.c */ +extern void android_emulator_set_window_scale(double scale, int is_dpi); + +/* One and only one UICmdImpl instance. */ +static UICmdImpl _uiCmdImpl; + +/* Display brightness change callback. */ +static AndroidHwLightBrightnessCallback _brightness_change_callback = NULL; +static void* _brightness_change_callback_param = NULL; + +/* Destroys UICmdImpl instance. */ +static void +_uiCmdImpl_destroy() +{ + if (_uiCmdImpl.core_connection != NULL) { + // Disable I/O callbacks. + qemu_set_fd_handler(_uiCmdImpl.sock, NULL, NULL, NULL); + core_connection_close(_uiCmdImpl.core_connection); + core_connection_free(_uiCmdImpl.core_connection); + _uiCmdImpl.core_connection = NULL; + } + // Properly deallocate the reader buffer. + if (_uiCmdImpl.reader_buffer != NULL && + _uiCmdImpl.reader_buffer != (uint8_t*)&_uiCmdImpl.cmd_header) { + free(_uiCmdImpl.reader_buffer); + _uiCmdImpl.reader_buffer = (uint8_t*)&_uiCmdImpl.cmd_header; + } +} + +/* Handles UI control command received from the core. + * Param: + * uicmd - UICmdImpl instance that received the command. + * header - UI control command header. + * data - Command parameters formatted accordingly to the command type. + */ +static void +_uiCmdImpl_handle_command(UICmdImpl* uicmd, + const UICmdHeader* header, + const uint8_t* data) +{ + switch (header->cmd_type) { + case AUICMD_SET_WINDOWS_SCALE: + { + UICmdSetWindowsScale* cmd = (UICmdSetWindowsScale*)data; + android_emulator_set_window_scale(cmd->scale, cmd->is_dpi); + break; + } + + case AUICMD_CHANGE_DISP_BRIGHTNESS: + { + UICmdChangeDispBrightness* cmd = (UICmdChangeDispBrightness*)data; + if (_brightness_change_callback != NULL) { + _brightness_change_callback(_brightness_change_callback_param, + cmd->light, cmd->brightness); + } + break; + } + + default: + derror("Unknown command %d is received from the Core\n", + header->cmd_type); + break; + } +} + +/* Asynchronous I/O callback reading UI control commands. + * Param: + * opaque - UICmdImpl instance. + */ +static void +_uiCmdImpl_io_read(void* opaque) +{ + UICmdImpl* uicmd = opaque; + int status; + + // Read requests while they are immediately available. + for (;;) { + // Read next chunk of data. + status = read(uicmd->sock, uicmd->reader_buffer + uicmd->reader_offset, + uicmd->reader_bytes - uicmd->reader_offset); + if (status == 0) { + /* Disconnection, meaning that the core process got termonated. */ + fprintf(stderr, "core-ui-control service got disconnected\n"); + _uiCmdImpl_destroy(); + return; + } + if (status < 0) { + if (errno == EINTR) { + /* loop on EINTR */ + continue; + } else if (errno == EWOULDBLOCK || errno == EAGAIN) { + // Chunk is not avalable at this point. Come back later. + return; + } + } + + uicmd->reader_offset += status; + if (uicmd->reader_offset != uicmd->reader_bytes) { + // There are still some data left in the pipe. + continue; + } + + // All expected data has been read. Time to change the state. + if (uicmd->reader_state == EXPECTS_HEADER) { + // Header has been read. + if (uicmd->cmd_header.cmd_param_size) { + // Prepare for the command parameters. + uicmd->reader_state = EXPECTS_PARAMETERS; + uicmd->reader_offset = 0; + uicmd->reader_bytes = uicmd->cmd_header.cmd_param_size; + uicmd->reader_buffer = malloc(uicmd->reader_bytes); + if (uicmd->reader_buffer == NULL) { + APANIC("Unable to allocate memory for UI command parameters.\n"); + } + } else { + // This command doesn't have any parameters. Handle it now. + _uiCmdImpl_handle_command(uicmd, &uicmd->cmd_header, NULL); + // Prepare for the next command header. + uicmd->reader_state = EXPECTS_HEADER; + uicmd->reader_offset = 0; + uicmd->reader_bytes = sizeof(uicmd->cmd_header); + uicmd->reader_buffer = (uint8_t*)&uicmd->cmd_header; + } + } else { + // All command data is in. Handle it. + _uiCmdImpl_handle_command(uicmd, &uicmd->cmd_header, + uicmd->reader_buffer); + // Prepare for the next command header. + free(uicmd->reader_buffer); + uicmd->reader_state = EXPECTS_HEADER; + uicmd->reader_offset = 0; + uicmd->reader_bytes = sizeof(uicmd->cmd_header); + uicmd->reader_buffer = (uint8_t*)&uicmd->cmd_header; + } + } +} + +int +uiCmdImpl_create(SockAddress* console_socket) +{ + char* handshake = NULL; + + // Setup command reader. + _uiCmdImpl.reader_buffer = (uint8_t*)&_uiCmdImpl.cmd_header; + _uiCmdImpl.reader_state = EXPECTS_HEADER; + _uiCmdImpl.reader_offset = 0; + _uiCmdImpl.reader_bytes = sizeof(UICmdHeader); + + // Connect to the core-ui-control service. + _uiCmdImpl.core_connection = + core_connection_create_and_switch(console_socket, "core-ui-control", + &handshake); + if (_uiCmdImpl.core_connection == NULL) { + derror("Unable to connect to the core-ui-control service: %s\n", + errno_str); + return -1; + } + + // Initialze UI command reader. + _uiCmdImpl.sock = core_connection_get_socket(_uiCmdImpl.core_connection); + if (qemu_set_fd_handler(_uiCmdImpl.sock, _uiCmdImpl_io_read, NULL, + &_uiCmdImpl)) { + derror("Unable to set up UI _uiCmdImpl_io_read callback: %s\n", + errno_str); + _uiCmdImpl_destroy(); + if (handshake != NULL) { + free(handshake); + } + return -1; + } + + fprintf(stdout, "core-ui-control is now connected to the core at %s.", + sock_address_to_string(console_socket)); + if (handshake != NULL) { + if (handshake[0] != '\0') { + fprintf(stdout, " Handshake: %s", handshake); + } + free(handshake); + } + fprintf(stdout, "\n"); + + return 0; +} + +int +uicmd_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback, + void* opaque) +{ + _brightness_change_callback = callback; + _brightness_change_callback_param = opaque; + return 0; +} diff --git a/android/protocol/ui-commands-impl.h b/android/protocol/ui-commands-impl.h new file mode 100644 index 0000000..0e5b52f --- /dev/null +++ b/android/protocol/ui-commands-impl.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_UI_COMMANDS_IMPL_H +#define _ANDROID_PROTOCOL_UI_COMMANDS_IMPL_H + +#include "sockets.h" +#include "android/protocol/ui-commands.h" + +/* + * Contains the UI-side implementation of the "core-ui-control" service that is + * part of the UI control protocol. Here we handle UI control commands sent by + * the Core to the UI. + */ + +/* Creates and initializes descriptor for the UI-side of the "core-ui-control" + * service. Note that there can be only one instance of this service in the UI. + * Param: + * console_socket - Addresses Core's console. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int uiCmdImpl_create(SockAddress* console_socket); + +#endif /* _ANDROID_PROTOCOL_UI_COMMANDS_IMPL_H */ diff --git a/android/protocol/ui-commands-proxy.c b/android/protocol/ui-commands-proxy.c new file mode 100644 index 0000000..76bf883 --- /dev/null +++ b/android/protocol/ui-commands-proxy.c @@ -0,0 +1,209 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains the Core-side implementation of the "core-ui-control" service that is + * part of the UI control protocol. Here we send UI control commands to the UI. + */ + +#include "android/android.h" +#include "android/hw-control.h" +#include "android/looper.h" +#include "android/async-utils.h" +#include "android/sync-utils.h" +#include "android/utils/debug.h" +#include "android/protocol/ui-commands.h" +#include "android/protocol/ui-commands-proxy.h" +#include "android/protocol/ui-commands-api.h" + +/* Descriptor for the UI commands proxy. */ +typedef struct UICmdProxy { + /* I/O associated with this descriptor. */ + LoopIo io; + + /* Looper associated with this descriptor. */ + Looper* looper; + + /* Writer to send UI commands. */ + SyncSocket* sync_writer; + + /* Socket descriptor for this service. */ + int sock; +} UICmdProxy; + +/* One and only one UICmdProxy instance. */ +static UICmdProxy _uiCmdProxy; + +/* Implemented in android/console.c */ +extern void destroy_uicmd_client(void); + +/* Calculates timeout for transferring the given number of bytes via socket. + * Return: + * Number of milliseconds during which the entire number of bytes is expected + * to be transferred via socket. + */ +static int +_uiCmdProxy_get_timeout(size_t data_size) +{ + // Min 2 seconds + 10 millisec for each transferring byte. + // TODO: Come up with a better arithmetics here. + return 2000 + data_size * 10; +} + +/* Sends request to the UI client of this service. + * Param: + * cmd_type, cmd_param, cmd_param_size - Define the command to send. + * Return: + * 0 on success, or < 0 on failure. + */ +static int +_uiCmdProxy_send_command(uint8_t cmd_type, + void* cmd_param, + uint32_t cmd_param_size) +{ + UICmdHeader header; + int status = syncsocket_start_write(_uiCmdProxy.sync_writer); + if (!status) { + // Initialize and send the header. + header.cmd_type = cmd_type; + header.cmd_param_size = cmd_param_size; + status = syncsocket_write(_uiCmdProxy.sync_writer, &header, sizeof(header), + _uiCmdProxy_get_timeout(sizeof(header))); + // If there are command parameters, send them too. + if (status > 0 && cmd_param != NULL && cmd_param_size > 0) { + status = syncsocket_write(_uiCmdProxy.sync_writer, cmd_param, + cmd_param_size, + _uiCmdProxy_get_timeout(cmd_param_size)); + } + status = syncsocket_result(status); + syncsocket_stop_write(_uiCmdProxy.sync_writer); + } + if (status < 0) { + derror("Send UI command %d (%u bytes) has failed: %s\n", + cmd_type, cmd_param_size, errno_str); + } + return status; +} + +/* Asynchronous I/O callback for UICmdProxy instance. + * We expect this callback to be called only on UI detachment condition. In this + * case the event should be LOOP_IO_READ, and read should fail with errno set + * to ECONNRESET. + * Param: + * opaque - UICmdProxy instance. + */ +static void +_uiCmdProxy_io_func(void* opaque, int fd, unsigned events) +{ + UICmdProxy* uicmd = (UICmdProxy*)opaque; + AsyncReader reader; + AsyncStatus status; + uint8_t read_buf[1]; + + if (events & LOOP_IO_WRITE) { + derror("Unexpected LOOP_IO_WRITE in _uiCmdProxy_io_func.\n"); + return; + } + + // Try to read + asyncReader_init(&reader, read_buf, sizeof(read_buf), &uicmd->io); + status = asyncReader_read(&reader, &uicmd->io); + // We expect only error status here. + if (status != ASYNC_ERROR) { + derror("Unexpected read status %d in _uiCmdProxy_io_func\n", status); + return; + } + // We expect only socket disconnection error here. + if (errno != ECONNRESET) { + derror("Unexpected read error %d (%s) in _uiCmdProxy_io_func.\n", + errno, errno_str); + return; + } + + // Client got disconnectted. + destroy_uicmd_client(); +} +/* a callback function called when the system wants to change the brightness + * of a given light. 'light' is a string which can be one of: + * 'lcd_backlight', 'button_backlight' or 'Keyboard_backlight' + * + * brightness is an integer (acceptable range are 0..255), however the + * default is around 105, and we probably don't want to dim the emulator's + * output at that level. + */ +static void +_uiCmdProxy_brightness_change_callback(void* opaque, + const char* light, + int brightness) +{ + // Calculate size of the command parameters. + const size_t cmd_size = sizeof(UICmdChangeDispBrightness) + strlen(light) + 1; + // Allocate and initialize parameters. + UICmdChangeDispBrightness* cmd = + (UICmdChangeDispBrightness*)qemu_malloc(cmd_size); + cmd->brightness = brightness; + strcpy(cmd->light, light); + // Send the command. + _uiCmdProxy_send_command(AUICMD_CHANGE_DISP_BRIGHTNESS, cmd, cmd_size); + qemu_free(cmd); +} + +int +uiCmdProxy_create(int fd) +{ + // Initialize the only UICmdProxy instance. + _uiCmdProxy.sock = fd; + _uiCmdProxy.looper = looper_newCore(); + loopIo_init(&_uiCmdProxy.io, _uiCmdProxy.looper, _uiCmdProxy.sock, + _uiCmdProxy_io_func, &_uiCmdProxy); + loopIo_wantRead(&_uiCmdProxy.io); + _uiCmdProxy.sync_writer = syncsocket_init(fd); + if (_uiCmdProxy.sync_writer == NULL) { + derror("Unable to initialize UICmdProxy writer: %s\n", errno_str); + uiCmdProxy_destroy(); + return -1; + } + { + // Set brighness change callback, so we can notify + // the UI about the event. + AndroidHwControlFuncs funcs; + funcs.light_brightness = _uiCmdProxy_brightness_change_callback; + android_hw_control_init(&_uiCmdProxy, &funcs); + } + return 0; +} + +void +uiCmdProxy_destroy() +{ + // Destroy the sync writer. + if (_uiCmdProxy.sync_writer != NULL) { + syncsocket_close(_uiCmdProxy.sync_writer); + syncsocket_free(_uiCmdProxy.sync_writer); + } + if (_uiCmdProxy.looper != NULL) { + // Stop all I/O that may still be going on. + loopIo_done(&_uiCmdProxy.io); + looper_free(_uiCmdProxy.looper); + _uiCmdProxy.looper = NULL; + } + _uiCmdProxy.sock = -1; +} + +int +uicmd_set_window_scale(double scale, int is_dpi) +{ + UICmdSetWindowsScale cmd; + cmd.scale = scale; + cmd.is_dpi = is_dpi; + return _uiCmdProxy_send_command(AUICMD_SET_WINDOWS_SCALE, &cmd, sizeof(cmd)); +} diff --git a/android/protocol/ui-commands-proxy.h b/android/protocol/ui-commands-proxy.h new file mode 100644 index 0000000..8627537 --- /dev/null +++ b/android/protocol/ui-commands-proxy.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_UI_COMMANDS_PROXY_H +#define _ANDROID_PROTOCOL_UI_COMMANDS_PROXY_H + +/* + * Contains the Core-side implementation of the "core-ui-control" service that is + * part of the UI control protocol. Here we send UI control commands to the UI. + */ + +/* Creates and initializes descriptor for the Core-side of the "core-ui-control" + * service. Note that there can be only one instance of this service in the core. + * Param: + * fd - Socket descriptor for the proxy. + * Return: + * 0 on success, or < 0 on failure. + */ +extern int uiCmdProxy_create(int fd); + +/* Destroys the descriptor for the Core-side of the "core-ui-control" service. */ +extern void uiCmdProxy_destroy(); + +/* Changes the scale of the emulator window at runtime. + * Param: + * scale, is_dpi - New window scale parameters + * Return: + * 0 on success, or < 0 on failure. + */ +extern int uicmd_set_window_scale(double scale, int is_dpi); + +#endif /* _ANDROID_PROTOCOL_UI_COMMANDS_PROXY_H */ diff --git a/android/protocol/ui-commands-qemu.c b/android/protocol/ui-commands-qemu.c new file mode 100644 index 0000000..3dbed31 --- /dev/null +++ b/android/protocol/ui-commands-qemu.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of the API for calling into the UI with the Core + * control commands for standalone (monolithic) emulator. + */ + +#include "android/android.h" +#include "android/hw-control.h" +#include "android/protocol/ui-commands-api.h" + +/* Implemented in android/qemulator.c */ +extern void android_emulator_set_window_scale(double scale, int is_dpi); + +int +uicmd_set_window_scale(double scale, int is_dpi) +{ + android_emulator_set_window_scale(scale, is_dpi); + return 0; +} + +int +uicmd_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback, + void* opaque) +{ + AndroidHwControlFuncs funcs; + funcs.light_brightness = callback; + android_hw_control_init(opaque, &funcs); + return 0; +} diff --git a/android/protocol/ui-commands.h b/android/protocol/ui-commands.h new file mode 100644 index 0000000..4e47b83 --- /dev/null +++ b/android/protocol/ui-commands.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_UI_COMMANDS_H +#define _ANDROID_PROTOCOL_UI_COMMANDS_H + +/* + * Contains declarations related to the UI control commands sent by the Core and + * handled by the UI. + */ + +#include "android/protocol/ui-common.h" + +/* Sets window scale. */ +#define AUICMD_SET_WINDOWS_SCALE 1 + +/* Changes display brightness. */ +#define AUICMD_CHANGE_DISP_BRIGHTNESS 2 + +/* Formats AUICMD_SET_WINDOWS_SCALE UI control command parameters. + * Contains parameters required by android_emulator_set_window_scale routine. + */ +typedef struct UICmdSetWindowsScale { + double scale; + int is_dpi; +} UICmdSetWindowsScale; + +/* Formats AUICMD_CHANGE_DISP_BRIGHTNESS UI control command parameters. + */ +typedef struct UICmdChangeDispBrightness { + int brightness; + char light[0]; +} UICmdChangeDispBrightness; + +#endif /* _ANDROID_PROTOCOL_UI_COMMANDS_H */ diff --git a/android/protocol/ui-common.h b/android/protocol/ui-common.h new file mode 100644 index 0000000..003ed6d --- /dev/null +++ b/android/protocol/ui-common.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _ANDROID_PROTOCOL_UI_COMMON_H +#define _ANDROID_PROTOCOL_UI_COMMON_H + +/* + * Contains declarations for UI control protocol used by both the Core, + * and the UI. + */ + +/* UI control command header. + * Every UI control command sent by the Core, or by the UI begins with this + * header, immediately followed by the command parameters (if there are any). + * Command type is defined by cmd_type field of this header. If command doesn't + * have any command-specific parameters, cmd_param_size field of this header + * must be 0. + */ +typedef struct UICmdHeader { + /* Command type. */ + uint8_t cmd_type; + + /* Byte size of the buffer containing parameters for the comand defined by + * the cmd_type field. The buffer containing parameters must immediately + * follow this header. If command doesn't have any parameters, this field + * must be 0 */ + uint32_t cmd_param_size; +} UICmdHeader; + +/* UI control command response header. + * If UI control command assumes a response from the remote end, the response + * must start with this header, immediately followed by the response data buffer. + */ +typedef struct UICmdRespHeader { + /* Result of the command handling. */ + int result; + + /* Byte size of the buffer containing response data immediately following + * this header. If there are no response data for the command, this field + * must be 0. */ + uint32_t resp_data_size; +} UICmdRespHeader; + +#endif /* _ANDROID_PROTOCOL_UI_COMMON_H */ diff --git a/android/qemu-setup.c b/android/qemu-setup.c index f0157cd..f1a12ee 100644 --- a/android/qemu-setup.c +++ b/android/qemu-setup.c @@ -23,7 +23,6 @@ #include "android/utils/path.h" #include "android/utils/system.h" #include "android/utils/bufprint.h" -#include "android/core-ui-protocol.h" #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) diff --git a/android/qemulator.c b/android/qemulator.c index a5f0dc0..f1b2dbc 100644 --- a/android/qemulator.c +++ b/android/qemulator.c @@ -14,7 +14,8 @@ #include "android/utils/bufprint.h" #include "android/globals.h" #include "android/qemulator.h" -#include "android/ui-core-protocol.h" +#include "android/protocol/core-commands-api.h" +#include "android/protocol/ui-commands-api.h" #include "user-events.h" #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) @@ -87,8 +88,8 @@ qemulator_setup( QEmulator* emulator ) } /* initialize hardware control support */ - android_core_set_brightness_change_callback(qemulator_light_brightness, - emulator); + uicmd_set_brightness_change_callback(qemulator_light_brightness, + emulator); } static void @@ -272,7 +273,7 @@ qemulator_set_title(QEmulator* emulator) int get_device_dpi( AndroidOptions* opts ) { - int dpi_device = android_core_get_hw_lcd_density(); + int dpi_device = corecmd_get_hw_lcd_density(); if (opts->dpi_device != NULL) { char* end; @@ -405,8 +406,8 @@ handle_key_command( void* opaque, SkinKeyCommand command, int down ) { case SKIN_KEY_COMMAND_TOGGLE_NETWORK: { - android_core_toggle_network(); - D( "network is now %s", android_core_is_network_disabled() ? + corecmd_toggle_network(); + D( "network is now %s", corecmd_is_network_disabled() ? "disconnected" : "connected" ); } break; @@ -421,10 +422,7 @@ handle_key_command( void* opaque, SkinKeyCommand command, int down ) { #ifdef CONFIG_TRACE tracing = !tracing; - if (tracing) - android_core_tracing_start(); - else - android_core_tracing_stop(); + corecmd_trace_control(tracing); #endif } break; diff --git a/android/skin/window.c b/android/skin/window.c index 431412b..c2d0bf4 100644 --- a/android/skin/window.c +++ b/android/skin/window.c @@ -16,7 +16,7 @@ #include "android/utils/debug.h" #include "android/utils/system.h" #include "android/utils/duff.h" -#include "android/ui-core-protocol.h" +#include "android/protocol/core-commands-api.h" #include <SDL_syswm.h> #include "user-events.h" #include <math.h> @@ -1340,9 +1340,9 @@ skin_window_reset_internal ( SkinWindow* window, SkinLayout* slayout ) user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value ); /* XXX: hack, replace by better code here */ if (slayout->event_value != 0) - android_core_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT ); + corecmd_set_coarse_orientation( ANDROID_COARSE_PORTRAIT ); else - android_core_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE ); + corecmd_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE ); } return 0; diff --git a/android/ui-core-protocol.c b/android/ui-core-protocol.c deleted file mode 100644 index 8dd14a7..0000000 --- a/android/ui-core-protocol.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * This file contains helper routines that are used to establish communication - * between UI and Core components of the emulator. This is a temporary file - * where we will collect functional dependencies between UI and Core in the - * process of separating UI and Core in the emulator build. Ideally at the - * end this will be replaced with a message protocol over sockets, or other - * means of interprocess communication. - */ - -#include "android/android.h" -#include "android/globals.h" -#include "android/hw-control.h" -#include "android/ui-core-protocol.h" -#include "android/ui-ctl-ui.h" -#if !defined(CONFIG_STANDALONE_UI) -#include "telephony/modem_driver.h" -#include "trace.h" -#include "audio/audio.h" -/* Implemented in vl-android.c */ -extern char* qemu_find_file(int type, const char* filename); -#endif // CONFIG_STANDALONE_UI - -int -android_core_get_hw_lcd_density(void) -{ - return android_hw->hw_lcd_density; -} - -void -android_core_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback, - void* opaque) -{ - AndroidHwControlFuncs funcs; - - funcs.light_brightness = callback; -#if !defined(CONFIG_STANDALONE_UI) - android_hw_control_init( opaque, &funcs ); -#endif // CONFIG_STANDALONE_UI -} - -void -android_core_sensors_set_coarse_orientation( AndroidCoarseOrientation orient ) -{ -#if !defined(CONFIG_STANDALONE_UI) - android_sensors_set_coarse_orientation(orient); -#else - clientuictl_set_coarse_orientation(orient); -#endif // CONFIG_STANDALONE_UI -} - -void -android_core_toggle_network(void) -{ - /* Temporary implementation for the monolitic (core + ui) builds. */ -#if !defined(CONFIG_STANDALONE_UI) - qemu_net_disable = !qemu_net_disable; - if (android_modem) { - amodem_set_data_registration( - android_modem, - qemu_net_disable ? A_REGISTRATION_UNREGISTERED - : A_REGISTRATION_HOME); - } -#else - clientuictl_toggle_network(); -#endif // CONFIG_STANDALONE_UI -} - -int -android_core_is_network_disabled(void) -{ - /* Temporary implementation for the monolitic (core + ui) builds. */ -#if !defined(CONFIG_STANDALONE_UI) - return qemu_net_disable; -#else - return clientuictl_check_network_disabled(); -#endif // CONFIG_STANDALONE_UI -} - -void android_core_tracing_start(void) -{ -#if !defined(CONFIG_STANDALONE_UI) - start_tracing(); -#else - clientuictl_trace_control(1); -#endif // CONFIG_STANDALONE_UI -} - -void android_core_tracing_stop(void) -{ -#if !defined(CONFIG_STANDALONE_UI) - stop_tracing(); -#else - clientuictl_trace_control(0); -#endif // CONFIG_STANDALONE_UI -} - -int -android_core_get_android_netspeed(int index, NetworkSpeed** netspeed) { - /* This is a temporary code used to support current behavior of the - *monolitic (core + ui in one executable) emulator executed with - * -help-netspeed option. In the future, when ui and core get separated, - * behavior of help may change, and this code should be reviewed. */ -#if !defined(CONFIG_STANDALONE_UI) - if (index >= android_netspeeds_count || - android_netspeeds[index].name == NULL) { - return -1; - } - *netspeed = (NetworkSpeed*)malloc(sizeof(NetworkSpeed)); - memcpy(*netspeed, &android_netspeeds[index], sizeof(NetworkSpeed)); - return 0; -#else - return clientuictl_get_netspeed(index, netspeed); -#endif // !CONFIG_STANDALONE_UI -} - -int -android_core_get_android_netdelay(int index, NetworkLatency** delay) { - /* This is a temporary code used to support current behavior of the - * monolitic (core + ui in one executable) emulator executed with - * -help-netdelays option. In the future, when ui and core get separated, - * behavior of help may change, and this code should be reviewed. */ -#if !defined(CONFIG_STANDALONE_UI) - if (index >= android_netdelays_count || - android_netdelays[index].name == NULL) { - return -1; - } - *delay = (NetworkLatency*)malloc(sizeof(NetworkLatency)); - memcpy(*delay, &android_netdelays[index], sizeof(NetworkLatency)); - return 0; -#else - return clientuictl_get_netdelay(index, delay); -#endif // !CONFIG_STANDALONE_UI -} - -int -android_core_qemu_find_file(int type, const char *filename, - char* path, size_t path_buf_size) -{ - /* Temporary implementation for the monolitic (core + ui) builds. */ -#if !defined(CONFIG_STANDALONE_UI) - char* filepath = qemu_find_file(type, filename); - if (filepath == NULL) { - return -1; - } - strncpy(path, filepath, path_buf_size); - path[path_buf_size - 1] = '\0'; - qemu_free(filepath); - return 0; -#else - char* ret_path = NULL; - int status = clientuictl_get_qemu_path(type, filename, &ret_path); - if (!status && ret_path != NULL) { - strncpy(path, ret_path, path_buf_size); - path[path_buf_size - 1] = '\0'; - } - if (ret_path != NULL) { - free(ret_path); - } - return status; -#endif // !CONFIG_STANDALONE_UI -} diff --git a/android/ui-core-protocol.h b/android/ui-core-protocol.h deleted file mode 100644 index 2a4cee6..0000000 --- a/android/ui-core-protocol.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * This file contains declarations of helper routines that are used to - * establish communication between UI and Core components of the emulator. - * This is a temporary file where we will collect functional dependencies - * between UI and Core in the process of separating UI and Core in the - * emulator build. - */ - -#ifndef QEMU_ANDROID_UI_CORE_PROTOCOL_H -#define QEMU_ANDROID_UI_CORE_PROTOCOL_H - -#include "android/hw-sensors.h" - -/* Gets LCD density property from the core properties. */ -int android_core_get_hw_lcd_density(void); - -/* This is temporary redeclaration for AndroidHwLightBrightnessFunc declared - * in android/hw-control.h We redeclare it here in order to keep type - * consistency between android_core_set_brightness_change_callback and - * light_brightness field of AndroidHwControlFuncs structure. - */ -typedef void (*AndroidHwLightBrightnessCallback)( void* opaque, - const char* light, - int brightness ); - -/* Registers a UI callback to be called when brightness is changed by the core. */ -void android_core_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback, - void* opaque); - -/* change the coarse orientation value */ -void android_core_sensors_set_coarse_orientation( AndroidCoarseOrientation orient ); - -/* Toggles the network state */ -void android_core_toggle_network(void); - -/* Gets the network state */ -int android_core_is_network_disabled(void); - -/* Start/stop tracing in the guest system */ -void android_core_tracing_start(void); -void android_core_tracing_stop(void); - -/* Gets an entry in android_netspeeds array defined in net-android.c - * Parameters: - * index - Index of the entry to get from the array. - * netspeed - Upon successful return contains copy of the requested entry. - * Return: - * 0 on success, or -1 if requested entry index is too large. - */ -int android_core_get_android_netspeed(int index, NetworkSpeed** netspeed); - -/* Gets an entry in android_netdelays array defined in net-android.c - * Parameters: - * index - Index of the entry to get from the array. - * netspeed - Upon successful return contains copy of the requested entry. - * Return: - * 0 on success, or -1 if requested entry index is too large. - */ -int android_core_get_android_netdelay(int index, NetworkLatency** delay); - -/* Builds a path to a file of the given type in the emulator's data directory. - * Param: - * type - Type of the file to find. Only QEMU_FILE_TYPE_BIOS, and - * QEMU_FILE_TYPE_KEYMAP are allowed for this value. - * filename - Name of the file to build path for. - * path - Upon success contains path to the requested file inside the - * emulator's data directory. - * path_buf_size Character size of the buffer addressed by the path parameter. - * Return: - * 0 on success, or -1 on an error. - */ -int -android_core_qemu_find_file(int type, const char *filename, - char* path, size_t path_buf_size); - -#endif // QEMU_ANDROID_UI_CORE_PROTOCOL_H diff --git a/android/ui-ctl-common.h b/android/ui-ctl-common.h deleted file mode 100644 index bc5960c..0000000 --- a/android/ui-ctl-common.h +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -#ifndef _ANDROID_UI_CONTROL_COMMON_H -#define _ANDROID_UI_CONTROL_COMMON_H - -#include "android/hw-sensors.h" - -/* - * UI control requests sent by the core to the UI. - */ - -/* Sets window scale. */ -#define ACORE_UICTL_SET_WINDOWS_SCALE 1 - -/* - * UI control requests sent by the UI to the core. - */ - -/* Sets coarse orientation. */ -#define AUI_UICTL_SET_COARSE_ORIENTATION 2 - -/* Toggles the network (no parameters). */ -#define AUI_UICTL_TOGGLE_NETWORK 3 - -/* Starts / stops the tracing. */ -#define AUI_UICTL_TRACE_CONTROL 4 - -/* Checks if network is disabled (no params) */ -#define AUI_UICTL_CHK_NETWORK_DISABLED 5 - -/* Gets net speed */ -#define AUI_UICTL_GET_NETSPEED 6 - -/* Gets net delays */ -#define AUI_UICTL_GET_NETDELAY 7 - -/* Gets path to a QEMU file on local host. */ -#define AUI_UICTL_GET_QEMU_PATH 8 - -/* UI control message header. */ -typedef struct UICtlHeader { - /* Message type. */ - uint8_t msg_type; - - /* Size of the message data following this header. */ - uint32_t msg_data_size; -} UICtlHeader; - -/* UI control response header. */ -typedef struct UICtlRespHeader { - /* Result of the request handling. */ - int result; - - /* Size of the response data following this header. */ - uint32_t resp_data_size; -} UICtlRespHeader; - -/* Formats ACORE_UICTL_SET_WINDOWS_SCALE UI control request. - */ -typedef struct UICtlSetWindowsScale { - double scale; - int is_dpi; -} UICtlSetWindowsScale; - -/* Formats AUI_UICTL_SET_COARSE_ORIENTATION UI control request. - */ -typedef struct UICtlSetCoarseOrientation { - AndroidCoarseOrientation orient; -} UICtlSetCoarseOrientation; - -/* Formats AUI_UICTL_TRACE_CONTROL UI control request. - */ -typedef struct UICtlTraceControl { - int start; -} UICtlTraceControl; - -/* Formats AUI_UICTL_GET_NETSPEED UI control request. - */ -typedef struct UICtlGetNetSpeed { - int index; -} UICtlGetNetSpeed; - -/* Formats AUI_UICTL_GET_NETSPEED UI control request response. - */ -typedef struct UICtlGetNetSpeedResp { - /* Size of the entire response structure including name and display strings. */ - int upload; - int download; - /* display field of NetworkSpeed structure is immediately following - * this field. */ - char name[0]; -} UICtlGetNetSpeedResp; - -/* Formats AUI_UICTL_GET_NETDELAY UI control request. - */ -typedef struct UICtlGetNetDelay { - int index; -} UICtlGetNetDelay; - -/* Formats AUI_UICTL_GET_NETDELAY UI control request response. - */ -typedef struct UICtlGetNetDelayResp { - /* Size of the entire response structure including name and display strings. */ - int min_ms; - int max_ms; - /* display field of NetworkLatency structure is immediately following - * this field. */ - char name[0]; -} UICtlGetNetDelayResp; - -/* Formats AUI_UICTL_GET_QEMU_PATH UI control request. - */ -typedef struct UICtlGetQemuPath { - int type; - char filename[0]; -} UICtlGetQemuPath; - -/* Formats AUI_UICTL_GET_QEMU_PATH UI control request response. - */ -typedef struct UICtlGetQemuPathResp { - /* Size of the entire response structure. */ - char path[0]; -} UICtlGetQemuPathResp; - -#if 0 -android_core_get_android_netspeed(int index, NetworkSpeed* netspeed) { -android_core_get_android_netdelay(int index, NetworkLatency* delay) { -int -android_core_qemu_find_file(int type, const char *filename, - char* path, size_t path_buf_size) -#endif - -#endif /* _ANDROID_UI_CONTROL_COMMON_H */ - diff --git a/android/ui-ctl-core.c b/android/ui-ctl-core.c deleted file mode 100644 index 4552bb8..0000000 --- a/android/ui-ctl-core.c +++ /dev/null @@ -1,568 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -#include "qemu-common.h" -#include "android/globals.h" -#include "android/android.h" -#include "android/looper.h" -#include "android/async-utils.h" -#include "android/sync-utils.h" -#include "android/utils/system.h" -#include "android/utils/debug.h" -#include "android/ui-ctl-common.h" -#include "android/ui-ctl-core.h" -#include "android/hw-sensors.h" -#include "telephony/modem_driver.h" -#include "trace.h" -#include "audio/audio.h" - -/* Enumerates state values for UICoreCtl descriptor. */ -typedef enum UICoreCtlState { - /* UI message header is expected in the pipe. */ - UI_STATE_EXPECT_HEADER, - /* UI message data are expected in the pipe. */ - UI_STATE_EXPECT_DATA -} UICoreCtlState; - -/* Core UI control service descriptor used for UI->Core communication. */ -typedef struct UICoreCtl { - /* Reader to detect UI disconnection. */ - AsyncReader async_reader; - - /* I/O associated with this descriptor. */ - LoopIo io; - - /* Looper used to communicate user events. */ - Looper* looper; - - /* Writer to send responses to UI requests. */ - SyncSocket* sync_writer; - - /* Socket descriptor for this service. */ - int sock; - - /* State of incoming requests. */ - UICoreCtlState in_req_state; - - /* Incoming request header. */ - UICtlHeader req_header; - - /* A buffer for small incoming requests. */ - uint8_t req_data[256]; - - /* Buffer to use for reading incoming request data. Depending on expected - * incoming request size this buffer can point to req_data field of this - * structure (for small requests), or can be allocated for large requests. */ - void* req_data_buffer; -} UICoreCtl; - -/* Core UI control service descriptor used for Core->UI communication. */ -typedef struct CoreUICtl { - /* I/O associated with this descriptor. */ - LoopIo io; - - /* Looper associated with this descriptor. */ - Looper* looper; - - /* Writer to send UI commands. */ - SyncSocket* sync_writer; - - /* Socket descriptor for this service. */ - int sock; -} CoreUICtl; - -/* One and only one CoreUICtl instance. */ -static CoreUICtl _core_ui_ctl; - -/* One and only one UICoreCtl instance. */ -static UICoreCtl _ui_core_ctl; - -/* Calculates timeout for transferring the given number of bytes via UI control - * socket. - * Return: - * Number of milliseconds during which the entire number of bytes is expected - * to be transferred. - */ -static int -_get_transfer_timeout(size_t data_size) -{ - // Min 200 millisec + one millisec for each transferring byte. - // TODO: Come up with a better arithmetics here. - return 200 + data_size; -} - -/* - * Core -> UI control implementation - */ - -/* Implemented in android/console.c */ -extern void destroy_core_ui_ctl_client(void); - -/* Sends request to the UI client. - * Param: - * msg_type, msg_data, msg_data_size - Define core request to send. - * Return: - * 0 on success, or < 0 on failure. - */ -static int -_coreuictl_send_request(uint8_t msg_type, - void* msg_data, - uint32_t msg_data_size) -{ - UICtlHeader header; - int status = syncsocket_start_write(_core_ui_ctl.sync_writer); - if (!status) { - - // Initialize and send the header. - header.msg_type = msg_type; - header.msg_data_size = msg_data_size; - status = syncsocket_write(_core_ui_ctl.sync_writer, &header, sizeof(header), - _get_transfer_timeout(sizeof(header))); - // If there is request data, send it too. - if (status > 0 && msg_data != NULL && msg_data_size > 0) { - status = syncsocket_write(_core_ui_ctl.sync_writer, msg_data, - msg_data_size, - _get_transfer_timeout(msg_data_size)); - } - status = syncsocket_result(status); - syncsocket_stop_write(_core_ui_ctl.sync_writer); - } - if (status < 0) { - derror("Unable to send core UI control request: %s\n", errno_str); - } - return status; -} - -/* - * Asynchronous I/O callback for CoreUICtl instance. - * We expect this callback to be called only on UI detachment condition. In this - * case the event should be LOOP_IO_READ, and read should fail with errno set - * to ECONNRESET. - * Param: - * opaque - CoreUICtl instance. - */ -static void -_coreuictl_io_func(void* opaque, int fd, unsigned events) -{ - CoreUICtl* uictl = (CoreUICtl*)opaque; - AsyncReader reader; - AsyncStatus status; - uint8_t read_buf[1]; - - if (events & LOOP_IO_WRITE) { - derror("Unexpected LOOP_IO_WRITE in coreuictl_io_func\n"); - return; - } - - // Try to read - asyncReader_init(&reader, read_buf, sizeof(read_buf), &uictl->io); - status = asyncReader_read(&reader, &uictl->io); - // We expect only error status here. - if (status != ASYNC_ERROR) { - derror("Unexpected read status %d in coreuictl_io_func\n", status); - return; - } - // We expect only socket disconnection here. - if (errno != ECONNRESET) { - derror("Unexpected read error %d (%s) in coreuictl_io_func\n", - errno, errno_str); - return; - } - - // Client got disconnectted. - destroy_core_ui_ctl_client(); -} - -int -coreuictl_create(int fd) -{ - // Initialize _core_ui_ctl instance. - _core_ui_ctl.sock = fd; - _core_ui_ctl.looper = looper_newCore(); - loopIo_init(&_core_ui_ctl.io, _core_ui_ctl.looper, _core_ui_ctl.sock, - _coreuictl_io_func, &_core_ui_ctl); - loopIo_wantRead(&_core_ui_ctl.io); - _core_ui_ctl.sync_writer = syncsocket_init(fd); - if (_core_ui_ctl.sync_writer == NULL) { - derror("Unable to initialize CoreUICtl writer: %s\n", errno_str); - return -1; - } - return 0; -} - -void -coreuictl_destroy() -{ - if (_core_ui_ctl.looper != NULL) { - // Stop all I/O that may still be going on. - loopIo_done(&_core_ui_ctl.io); - looper_free(_core_ui_ctl.looper); - _core_ui_ctl.looper = NULL; - } - if (_core_ui_ctl.sync_writer != NULL) { - syncsocket_close(_core_ui_ctl.sync_writer); - syncsocket_free(_core_ui_ctl.sync_writer); - } - _core_ui_ctl.sock = -1; -} - -int -coreuictl_set_window_scale(double scale, int is_dpi) -{ - UICtlSetWindowsScale msg; - msg.scale = scale; - msg.is_dpi = is_dpi; - return _coreuictl_send_request(ACORE_UICTL_SET_WINDOWS_SCALE, &msg, - sizeof(msg)); -} - -/* - * UI -> Core control implementation - */ - -/* Implemented in android/console.c */ -extern void destroy_ui_core_ctl_client(void); -/* Implemented in vl-android.c */ -extern char* qemu_find_file(int type, const char* filename); - -/* Properly initializes req_data_buffer field in UICoreCtl instance to receive - * the expected incoming request data buffer. - */ -static uint8_t* -_alloc_req_data_buffer(UICoreCtl* uictl, uint32_t size) -{ - if (size < sizeof(uictl->req_data)) { - // req_data can contain all request data. - uictl->req_data_buffer = &uictl->req_data[0]; - } else { - // Expected request us too large to fit into preallocated buffer. - uictl->req_data_buffer = qemu_malloc(size); - } - return uictl->req_data_buffer; -} - -/* Properly frees req_data_buffer field in UICoreCtl instance. - */ -static void -_free_req_data_buffer(UICoreCtl* uictl) -{ - if (uictl->req_data_buffer != &uictl->req_data[0]) { - qemu_free(uictl->req_data_buffer); - uictl->req_data_buffer = &uictl->req_data[0]; - } -} - -/* Sends response back to the UI - * Param: - * uictl - UICoreCtl instance to use for the response sending. - * resp - Response header. - * resp_data - Response data. Data size is defined by the header. - * Return: - * 0 on success, or < 0 on failure. - */ -static int -_uicorectl_send_response(UICoreCtl* uictl, UICtlRespHeader* resp, void* resp_data) -{ - int status = syncsocket_start_write(uictl->sync_writer); - if (!status) { - // Write the header - status = syncsocket_write(uictl->sync_writer, resp, - sizeof(UICtlRespHeader), - _get_transfer_timeout(sizeof(UICtlRespHeader))); - // Write response data (if any). - if (status > 0 && resp_data != NULL && resp->resp_data_size != 0) { - status = syncsocket_write(uictl->sync_writer, resp_data, - resp->resp_data_size, - _get_transfer_timeout(resp->resp_data_size)); - } - status = syncsocket_result(status); - syncsocket_stop_write(uictl->sync_writer); - } - if (status < 0) { - derror("Unable to send UI control response: %s\n", errno_str); - } - return status; -} - -/* Handles UI control request from the UI. - * Param: - * uictl - UICoreCtl instance that received the request. - * req_header - Request header. - * req_data - Request data. - */ -static void -_handle_uictl_request(UICoreCtl* uictl, - const UICtlHeader* req_header, - const uint8_t* req_data) -{ - switch (req_header->msg_type) { - case AUI_UICTL_SET_COARSE_ORIENTATION: - { - UICtlSetCoarseOrientation* req = (UICtlSetCoarseOrientation*)req_data; - android_sensors_set_coarse_orientation(req->orient); - break; - } - - case AUI_UICTL_TOGGLE_NETWORK: - qemu_net_disable = !qemu_net_disable; - if (android_modem) { - amodem_set_data_registration( - android_modem, - qemu_net_disable ? A_REGISTRATION_UNREGISTERED - : A_REGISTRATION_HOME); - } - break; - - case AUI_UICTL_TRACE_CONTROL: - { - UICtlTraceControl* req = (UICtlTraceControl*)req_data; - if (req->start) { - start_tracing(); - } else { - stop_tracing(); - } - break; - } - - case AUI_UICTL_CHK_NETWORK_DISABLED: - { - UICtlRespHeader resp; - resp.resp_data_size = 0; - resp.result = qemu_net_disable; - _uicorectl_send_response(uictl, &resp, NULL); - break; - } - - case AUI_UICTL_GET_NETSPEED: - { - UICtlRespHeader resp; - UICtlGetNetSpeedResp* resp_data = NULL; - UICtlGetNetSpeed* req = (UICtlGetNetSpeed*)req_data; - - resp.resp_data_size = 0; - resp.result = 0; - - if (req->index >= android_netspeeds_count || - android_netspeeds[req->index].name == NULL) { - resp.result = -1; - } else { - const NetworkSpeed* netspeed = &android_netspeeds[req->index]; - // Calculate size of the response data: - // fixed header + zero-terminated netspeed name. - resp.resp_data_size = sizeof(UICtlGetNetSpeedResp) + - strlen(netspeed->name) + 1; - // Count in zero-terminated netspeed display. - if (netspeed->display != NULL) { - resp.resp_data_size += strlen(netspeed->display) + 1; - } else { - resp.resp_data_size++; - } - // Allocate and initialize response data buffer. - resp_data = - (UICtlGetNetSpeedResp*)qemu_malloc(resp.resp_data_size); - resp_data->upload = netspeed->upload; - resp_data->download = netspeed->download; - strcpy(resp_data->name, netspeed->name); - if (netspeed->display != NULL) { - strcpy(resp_data->name + strlen(resp_data->name) + 1, - netspeed->display); - } else { - strcpy(resp_data->name + strlen(resp_data->name) + 1, ""); - } - } - _uicorectl_send_response(uictl, &resp, resp_data); - if (resp_data != NULL) { - qemu_free(resp_data); - } - break; - } - - case AUI_UICTL_GET_NETDELAY: - { - UICtlRespHeader resp; - UICtlGetNetDelayResp* resp_data = NULL; - UICtlGetNetDelay* req = (UICtlGetNetDelay*)req_data; - - resp.resp_data_size = 0; - resp.result = 0; - - if (req->index >= android_netdelays_count || - android_netdelays[req->index].name == NULL) { - resp.result = -1; - } else { - const NetworkLatency* netdelay = &android_netdelays[req->index]; - // Calculate size of the response data: - // fixed header + zero-terminated netdelay name. - resp.resp_data_size = sizeof(UICtlGetNetDelayResp) + - strlen(netdelay->name) + 1; - // Count in zero-terminated netdelay display. - if (netdelay->display != NULL) { - resp.resp_data_size += strlen(netdelay->display) + 1; - } else { - resp.resp_data_size++; - } - // Allocate and initialize response data buffer. - resp_data = - (UICtlGetNetDelayResp*)qemu_malloc(resp.resp_data_size); - resp_data->min_ms = netdelay->min_ms; - resp_data->max_ms = netdelay->max_ms; - strcpy(resp_data->name, netdelay->name); - if (netdelay->display != NULL) { - strcpy(resp_data->name + strlen(resp_data->name) + 1, - netdelay->display); - } else { - strcpy(resp_data->name + strlen(resp_data->name) + 1, ""); - } - } - _uicorectl_send_response(uictl, &resp, resp_data); - if (resp_data != NULL) { - qemu_free(resp_data); - } - break; - } - - case AUI_UICTL_GET_QEMU_PATH: - { - UICtlRespHeader resp; - UICtlGetQemuPath* req = (UICtlGetQemuPath*)req_data; - char* filepath = NULL; - - resp.resp_data_size = 0; - resp.result = -1; - filepath = qemu_find_file(req->type, req->filename); - if (filepath != NULL) { - resp.resp_data_size = strlen(filepath) + 1; - } - _uicorectl_send_response(uictl, &resp, filepath); - if (filepath != NULL) { - qemu_free(filepath); - } - break; - } - - default: - derror("Unknown UI control request %d\n", req_header->msg_type); - break; - } -} - -/* Asynchronous read I/O callback launched when reading UI control requests. - */ -static void -_uicorectl_io_read(UICoreCtl* uictl) -{ - // Read whatever is expected from the socket. - const AsyncStatus status = - asyncReader_read(&uictl->async_reader, &uictl->io); - - switch (status) { - case ASYNC_COMPLETE: - switch (uictl->in_req_state) { - case UI_STATE_EXPECT_HEADER: - // We just read the request header. Now we expect the data. - if (uictl->req_header.msg_data_size != 0) { - uictl->in_req_state = UI_STATE_EXPECT_DATA; - // Setup the reader to read expected amount of the data. - _alloc_req_data_buffer(uictl, - uictl->req_header.msg_data_size); - asyncReader_init(&uictl->async_reader, - uictl->req_data_buffer, - uictl->req_header.msg_data_size, - &uictl->io); - } else { - // Request doesn't contain data. Go ahead and handle it. - _handle_uictl_request(uictl, &uictl->req_header, - uictl->req_data_buffer); - // Prepare for the next header. - asyncReader_init(&uictl->async_reader, - &uictl->req_header, - sizeof(uictl->req_header), &uictl->io); - } - break; - - case UI_STATE_EXPECT_DATA: - // Request header and data are received. Handle the request. - _handle_uictl_request(uictl, &uictl->req_header, - uictl->req_data_buffer); - _free_req_data_buffer(uictl); - // Prepare for the next request. - uictl->in_req_state = UI_STATE_EXPECT_HEADER; - asyncReader_init(&uictl->async_reader, &uictl->req_header, - sizeof(uictl->req_header), &uictl->io); - break; - } - break; - case ASYNC_ERROR: - loopIo_dontWantRead(&uictl->io); - if (errno == ECONNRESET) { - // UI has exited. We need to destroy the service. - destroy_ui_core_ctl_client(); - } - break; - - case ASYNC_NEED_MORE: - // Transfer will eventually come back into this routine. - return; - } -} - -/* - * Asynchronous I/O callback launched when UI control is received from the UI. - * Param: - * opaque - UICoreCtl instance. - */ -static void -_uicorectl_io_func(void* opaque, int fd, unsigned events) -{ - if (events & LOOP_IO_READ) { - _uicorectl_io_read((UICoreCtl*)opaque); - } else if (events & LOOP_IO_WRITE) { - // We don't use async writer here, so we don't expect - // any write callbacks. - derror("Unexpected LOOP_IO_WRITE in _uicorectl_io_func\n"); - } -} - -int -uicorectl_create(int fd) -{ - _ui_core_ctl.sock = fd; - _ui_core_ctl.looper = looper_newCore(); - loopIo_init(&_ui_core_ctl.io, _ui_core_ctl.looper, _ui_core_ctl.sock, - _uicorectl_io_func, &_ui_core_ctl); - _ui_core_ctl.in_req_state = UI_STATE_EXPECT_HEADER; - _ui_core_ctl.req_data_buffer = &_ui_core_ctl.req_data[0]; - asyncReader_init(&_ui_core_ctl.async_reader, &_ui_core_ctl.req_header, - sizeof(_ui_core_ctl.req_header), &_ui_core_ctl.io); - _ui_core_ctl.sync_writer = syncsocket_init(fd); - if (_ui_core_ctl.sync_writer == NULL) { - derror("Unable to create writer for UICoreCtl instance: %s\n", errno_str); - return -1; - } - return 0; -} - -void -uicorectl_destroy() -{ - if (_ui_core_ctl.looper != NULL) { - // Stop all I/O that may still be going on. - loopIo_done(&_ui_core_ctl.io); - looper_free(_ui_core_ctl.looper); - _ui_core_ctl.looper = NULL; - } - if (_ui_core_ctl.sync_writer != NULL) { - syncsocket_close(_ui_core_ctl.sync_writer); - syncsocket_free(_ui_core_ctl.sync_writer); - } - _free_req_data_buffer(&_ui_core_ctl); -} diff --git a/android/ui-ctl-core.h b/android/ui-ctl-core.h deleted file mode 100644 index f7d7ecf..0000000 --- a/android/ui-ctl-core.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -#ifndef _ANDROID_UI_CONTROL_CORE_H -#define _ANDROID_UI_CONTROL_CORE_H - -/* - * Contains core-side of UI control protocols. For the simplicity of the - * implementation there are two UI control services: "ui-core-control" that - * handle UI controls initiated in the UI, and "core-ui-control" that handle UI - * controls initiated in the core. The reason for hawing two services is that - * some of the UI controls expect the core to respond with some data. The - * simplest way to differentiate core commands from core responses to the UI - * commands, is to have two separate services: one sends commands only, and - * another sends only responses. - */ - -/* - * Creates and initializes Core->UI UI control service. - * Param: - * fd - Socket descriptor for the service. - * Return: - * 0 on success, or < 0 on failure. - */ -extern int coreuictl_create(int fd); - -/* - * Destroys Core->UI UI control service. - */ -extern void coreuictl_destroy(); - -/* Changes the scale of the emulator window at runtime. - * Param: - * scale, is_dpi - New window scale parameters - * Return: - * 0 on success, or < 0 on failure. - */ -extern int coreuictl_set_window_scale(double scale, int is_dpi); - -/* - * Creates and initializes UI->Core UI control instance. - * Param: - * fd - Socket descriptor for the service. - * Return: - * 0 on success, or < 0 on failure. - */ -extern int uicorectl_create(int fd); - -/* - * Destroys UI->Core UI control service. - */ -extern void uicorectl_destroy(); - -#endif /* _ANDROID_UI_CONTROL_CORE_H */ diff --git a/android/ui-ctl-ui.c b/android/ui-ctl-ui.c deleted file mode 100644 index 47d0603..0000000 --- a/android/ui-ctl-ui.c +++ /dev/null @@ -1,568 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains UI-side of UI control protocol. - */ - -#include "console.h" -#include "android/android.h" -#include "android/globals.h" -#include "android/looper.h" -#include "android/core-connection.h" -#include "android/async-utils.h" -#include "android/utils/system.h" -#include "android/utils/debug.h" -#include "android/sync-utils.h" -#include "android/ui-ctl-common.h" -#include "android/ui-ctl-ui.h" - -#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); \ - exit(1); \ - } while (0) - - -/* - * Enumerates states for the request reader in CoreUICtlClient instance. - */ -typedef enum CoreUICtlClientState { - /* The reader is waiting on request header. */ - WAIT_HEADER, - - /* The reader is waiting on request data. */ - WAIT_DATA, -} CoreUICtlClientState; - -/* Common descriptor for UI control clients. */ -typedef struct UICtlCommon { - /* Core connection instance for the UI control client. */ - CoreConnection* core_connection; - - /* Socket wrapper for sync writes. */ - SyncSocket* sync_writer; - - /* Socket descriptor for the UI control client. */ - int sock; -} UICtlCommon; - -/* Descriptor for the Core->UI control client. */ -typedef struct CoreUICtlClient { - /* Common UI control client descriptor. */ - UICtlCommon common; - - /* Current reader state. */ - CoreUICtlClientState reader_state; - - /* Incoming request header. */ - UICtlHeader req_header; - - /* Reader's buffer. */ - uint8_t* reader_buffer; - - /* Offset in the reader's buffer where to read next chunk of data. */ - size_t reader_offset; - - /* Total number of bytes the reader expects to read. */ - size_t reader_bytes; -} CoreUICtlClient; - -/* Descriptor for the UI->Core control client. */ -typedef struct UICoreCtlClient { - /* Common UI control client descriptor. */ - UICtlCommon common; - - /* Socket wrapper for sync reads. */ - SyncSocket* sync_reader; -} UICoreCtlClient; - -/* One and only one Core->UI control client instance. */ -static CoreUICtlClient _core_ui_client; - -/* One and only one UI->Core control client instance. */ -static UICoreCtlClient _ui_core_client; - -/* Calculates timeout for transferring the given number of bytes via UI control - * socket. - * Return: - * Number of milliseconds during which the entire number of bytes is expected - * to be transferred. - */ -static int -_get_transfer_timeout(size_t data_size) -{ - // Min 200 millisec + one millisec for each transferring byte. - // TODO: Come up with a better arithmetics here. - return 200 + data_size; -} - -/* Initializes UICtlCommon instance. - * Param: - * console_socket - Addresses core's console service. - * name - Name of the core's service to attach to ("ui-core client", - * or "core-ui client"). - * uictl_common - UICtlCommon instance to initialize. - * Return: - * 0 on success, or < 0 on failure. - */ -static int -_clientuictl_create_client(SockAddress* console_socket, - char* name, - UICtlCommon* uictl_common) -{ - char* connect_message = NULL; - char switch_cmd[256]; - - // Connect to the console service. - uictl_common->core_connection = core_connection_create(console_socket); - if (uictl_common->core_connection == NULL) { - derror("UI control client %s is unable to connect to the console: %s\n", - name, errno_str); - return -1; - } - if (core_connection_open(uictl_common->core_connection)) { - core_connection_free(uictl_common->core_connection); - uictl_common->core_connection = NULL; - derror("UI control client %s is unable to open the console: %s\n", - name, errno_str); - return -1; - } - snprintf(switch_cmd, sizeof(switch_cmd), "%s", name); - if (core_connection_switch_stream(uictl_common->core_connection, switch_cmd, - &connect_message)) { - derror("Unable to connect to the UI control service %s: %s\n", - name, connect_message ? connect_message : ""); - if (connect_message != NULL) { - free(connect_message); - } - core_connection_close(uictl_common->core_connection); - core_connection_free(uictl_common->core_connection); - uictl_common->core_connection = NULL; - return -1; - } - if (connect_message != NULL) { - free(connect_message); - } - - // Initialize UICtlCommon instance. - uictl_common->sock = core_connection_get_socket(uictl_common->core_connection); - uictl_common->sync_writer = syncsocket_init(uictl_common->sock); - if (uictl_common->sync_writer == NULL) { - derror("Unable to initialize sync writer for %s UI control client: %s\n", - name, errno_str); - return -1; - } - return 0; -} - -/* Destroys UICtlCommon instance. */ -static void -_uictlcommon_destroy(UICtlCommon* desc) -{ - if (desc->core_connection != NULL) { - // Disable I/O callbacks. - qemu_set_fd_handler(desc->sock, NULL, NULL, NULL); - syncsocket_close(desc->sync_writer); - syncsocket_free(desc->sync_writer); - core_connection_close(desc->core_connection); - core_connection_free(desc->core_connection); - desc->core_connection = NULL; - } -} - -/* - * Core->UI control client implementation. - */ - -/* Implemented in android/qemulator.c */ -extern void android_emulator_set_window_scale( double scale, int is_dpi ); - -/* Destroys CoreUICtlClient instance. */ -static void -_core_ui_client_destroy() -{ - _uictlcommon_destroy(&_core_ui_client.common); - if (_core_ui_client.reader_buffer != NULL && - _core_ui_client.reader_buffer != (uint8_t*)&_core_ui_client.req_header) { - free(_core_ui_client.reader_buffer); - } -} - -/* - * Handles UI control request received from the core. - * Param: - * uictl - CoreUICtlClient instance that received the request. - * header - UI control request header. - * data - Request data formatted accordingly to the request type. - */ -static void -_core_ui_ctl_handle_request(CoreUICtlClient* uictl, - UICtlHeader* header, - uint8_t* data) -{ - switch (header->msg_type) { - case ACORE_UICTL_SET_WINDOWS_SCALE: - { - UICtlSetWindowsScale* req = (UICtlSetWindowsScale*)data; - android_emulator_set_window_scale(req->scale, req->is_dpi); - break; - } - default: - derror("Unknown Core UI control %d\n", header->msg_type); - break; - } -} - -/* - * Asynchronous I/O callback launched when UI control requests received from the - * core are ready to be read. - * Param: - * opaque - CoreUICtlClient instance. - */ -static void -_core_ui_client_read_cb(void* opaque) -{ - CoreUICtlClient* uictl = opaque; - int ret; - - // Read requests while they are immediately available. - for (;;) { - // Read next chunk of data. - ret = read(uictl->common.sock, - uictl->reader_buffer + uictl->reader_offset, - uictl->reader_bytes - uictl->reader_offset); - if (ret == 0) { - /* disconnection ! */ - _core_ui_client_destroy(); - return; - } - if (ret < 0) { - if (errno == EINTR) { - /* loop on EINTR */ - continue; - } else if (errno == EWOULDBLOCK || errno == EAGAIN) { - // Chunk is not avalable at this point. Come back later. - return; - } - } - - uictl->reader_offset += ret; - if (uictl->reader_offset != uictl->reader_bytes) { - // There are still some data left in the pipe. - continue; - } - - // All expected data has been read. Time to change the state. - if (uictl->reader_state == WAIT_HEADER) { - // Header has been read. Prepare for the data. - uictl->reader_state = WAIT_DATA; - uictl->reader_offset = 0; - uictl->reader_bytes = uictl->req_header.msg_data_size; - uictl->reader_buffer = malloc(uictl->reader_bytes); - if (uictl->reader_buffer == NULL) { - PANIC("Unable to allocate memory for UI control request.\n"); - } - } else { - _core_ui_ctl_handle_request(uictl, &uictl->req_header, - uictl->reader_buffer); - free(uictl->reader_buffer); - uictl->reader_state = WAIT_HEADER; - uictl->reader_offset = 0; - uictl->reader_bytes = sizeof(uictl->req_header); - uictl->reader_buffer = (uint8_t*)&uictl->req_header; - } - } -} - -/* - * UI->Core control client implementation. - */ - -/* Sends UI request to the core. - * Param: - * msg_type, msg_data, msg_data_size - Define the request. - * Return: - * 0 On success, or < 0 on failure. - */ -static int -_ui_core_ctl_send_request(uint8_t msg_type, - void* msg_data, - uint32_t msg_data_size) -{ - int status; - UICtlHeader header; - - // Prepare and send the header. - header.msg_type = msg_type; - header.msg_data_size = msg_data_size; - status = syncsocket_start_write(_ui_core_client.common.sync_writer); - if (!status) { - // Send the header. - status = syncsocket_write(_ui_core_client.common.sync_writer, &header, - sizeof(header), - _get_transfer_timeout(sizeof(header))); - // If there is request data, send it too. - if (status > 0 && msg_data != NULL && msg_data_size > 0) { - status = syncsocket_write(_ui_core_client.common.sync_writer, msg_data, - msg_data_size, - _get_transfer_timeout(msg_data_size)); - } - status = syncsocket_result(status); - syncsocket_stop_write(_ui_core_client.common.sync_writer); - } - if (status < 0) { - derror("Unable to send UI control request: %s\n", errno_str); - } - return status; -} - -/* Reads response to a UI control request from the core. - * Param: - * resp - Upon success contains response header. - * resp_data - Upon success contains allocated reponse data (if any). The caller - * is responsible for deallocating of the memory returned in this parameter. - * Return: - * 0 on success, or < 0 on failure. - */ -static int -_ui_core_ctl_get_response(UICtlRespHeader* resp, void** resp_data) -{ - int status = syncsocket_start_read(_ui_core_client.sync_reader); - if (!status) { - // Read the header. - status = syncsocket_read(_ui_core_client.sync_reader, resp, - sizeof(UICtlRespHeader), - _get_transfer_timeout(sizeof(UICtlRespHeader))); - // Read response data (if any). - if (status > 0 && resp->resp_data_size) { - *resp_data = malloc(resp->resp_data_size); - if (*resp_data == NULL) { - PANIC("Unable to allocate response data buffer\n"); - } - status = syncsocket_read(_ui_core_client.sync_reader, *resp_data, - resp->resp_data_size, - _get_transfer_timeout(resp->resp_data_size)); - } - status = syncsocket_result(status); - syncsocket_stop_read(_ui_core_client.sync_reader); - } - if (status < 0) { - derror("Unable to get UI control response: %s\n", errno_str); - } - return status; -} - -int -clientuictl_set_coarse_orientation(AndroidCoarseOrientation orient) -{ - UICtlSetCoarseOrientation msg; - msg.orient = orient; - return _ui_core_ctl_send_request(AUI_UICTL_SET_COARSE_ORIENTATION, - &msg, sizeof(msg)); -} - -int -clientuictl_toggle_network() -{ - return _ui_core_ctl_send_request(AUI_UICTL_TOGGLE_NETWORK, NULL, 0); -} - -int -clientuictl_trace_control(int start) -{ - UICtlTraceControl msg; - msg.start = start; - return _ui_core_ctl_send_request(AUI_UICTL_TRACE_CONTROL, - &msg, sizeof(msg)); -} - -int -clientuictl_check_network_disabled() -{ - UICtlRespHeader resp; - void* tmp = NULL; - int status; - - status = _ui_core_ctl_send_request(AUI_UICTL_CHK_NETWORK_DISABLED, NULL, 0); - if (status < 0) { - return status; - } - status = _ui_core_ctl_get_response(&resp, &tmp); - if (status < 0) { - return status; - } - return resp.result; -} - -int -clientuictl_get_netspeed(int index, NetworkSpeed** netspeed) -{ - UICtlGetNetSpeed req; - UICtlRespHeader resp; - UICtlGetNetSpeedResp* resp_data = NULL; - int status; - - // Initialize and send the query. - req.index = index; - status = _ui_core_ctl_send_request(AUI_UICTL_GET_NETSPEED, &req, sizeof(req)); - if (status < 0) { - return status; - } - - // Obtain the response from the core. - status = _ui_core_ctl_get_response(&resp, (void**)&resp_data); - if (status < 0) { - return status; - } - if (!resp.result) { - NetworkSpeed* ret; - // Allocate memory for the returning NetworkSpeed instance. - // It includes: NetworkSpeed structure + - // size of zero-terminated "name" and "display" strings saved in - // resp_data. - *netspeed = malloc(sizeof(NetworkSpeed) + 1 + - resp.resp_data_size - sizeof(UICtlGetNetSpeedResp)); - ret = *netspeed; - - // Copy data obtained from the core to the returning NetworkSpeed - // instance. - ret->upload = resp_data->upload; - ret->download = resp_data->download; - ret->name = (char*)ret + sizeof(NetworkSpeed); - strcpy((char*)ret->name, resp_data->name); - ret->display = ret->name + strlen(ret->name) + 1; - strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1); - } - if (resp_data != NULL) { - free(resp_data); - } - return resp.result; -} - -int -clientuictl_get_netdelay(int index, NetworkLatency** netdelay) -{ - UICtlGetNetDelay req; - UICtlRespHeader resp; - UICtlGetNetDelayResp* resp_data = NULL; - int status; - - // Initialize and send the query. - req.index = index; - status = _ui_core_ctl_send_request(AUI_UICTL_GET_NETDELAY, &req, sizeof(req)); - if (status < 0) { - return status; - } - - // Obtain the response from the core. - status = _ui_core_ctl_get_response(&resp, (void**)&resp_data); - if (status < 0) { - return status; - } - if (!resp.result) { - NetworkLatency* ret; - // Allocate memory for the returning NetworkLatency instance. - // It includes: NetworkLatency structure + - // size of zero-terminated "name" and "display" strings saved in - // resp_data. - *netdelay = malloc(sizeof(NetworkLatency) + 1 + - resp.resp_data_size - sizeof(UICtlGetNetDelayResp)); - ret = *netdelay; - - // Copy data obtained from the core to the returning NetworkLatency - // instance. - ret->min_ms = resp_data->min_ms; - ret->max_ms = resp_data->max_ms; - ret->name = (char*)ret + sizeof(NetworkLatency); - strcpy((char*)ret->name, resp_data->name); - ret->display = ret->name + strlen(ret->name) + 1; - strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1); - } - if (resp_data != NULL) { - free(resp_data); - } - return resp.result; -} - -int -clientuictl_get_qemu_path(int type, const char* filename, char** path) -{ - UICtlRespHeader resp; - char* resp_data = NULL; - int status; - - // Initialize and send the query. - uint32_t req_data_size = sizeof(UICtlGetQemuPath) + strlen(filename) + 1; - UICtlGetQemuPath* req = (UICtlGetQemuPath*)malloc(req_data_size); - if (req == NULL) { - PANIC("Unable to allocate query qemu path request\n"); - } - req->type = type; - strcpy(req->filename, filename); - status = _ui_core_ctl_send_request(AUI_UICTL_GET_QEMU_PATH, req, - req_data_size); - if (status < 0) { - return status; - } - - // Obtain the response from the core. - status = _ui_core_ctl_get_response(&resp, (void**)&resp_data); - if (status < 0) { - return status; - } - if (!resp.result && resp_data != NULL) { - *path = strdup(resp_data); - } - if (resp_data != NULL) { - free(resp_data); - } - return resp.result; -} - -int -clientuictl_create(SockAddress* console_socket) -{ - // Connect to Core->UI service - if (_clientuictl_create_client(console_socket, "core-ui-control", - &_core_ui_client.common)) { - return -1; - } - _core_ui_client.reader_state = WAIT_HEADER; - if (qemu_set_fd_handler(_core_ui_client.common.sock, _core_ui_client_read_cb, - NULL, &_core_ui_client)) { - derror("Unable to set up UI control read callback\n"); - core_connection_close(_core_ui_client.common.core_connection); - core_connection_free(_core_ui_client.common.core_connection); - _core_ui_client.common.core_connection = NULL; - return -1; - } - fprintf(stdout, "Core->UI client is now attached to the core %s\n", - sock_address_to_string(console_socket)); - - // Connect to UI->Core service - if (_clientuictl_create_client(console_socket, "ui-core-control", - &_ui_core_client.common)) { - _core_ui_client_destroy(); - return -1; - } - _ui_core_client.sync_reader = syncsocket_init(_ui_core_client.common.sock); - if (_ui_core_client.sync_reader == NULL) { - derror("Unable to create reader for CoreUICtlClient instance: %s\n", - errno_str); - _core_ui_client_destroy(); - return -1; - } - - fprintf(stdout, "UI->Core client is now attached to the core %s\n", - sock_address_to_string(console_socket)); - - return 0; -} diff --git a/android/ui-ctl-ui.h b/android/ui-ctl-ui.h deleted file mode 100644 index 4359ba1..0000000 --- a/android/ui-ctl-ui.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -#ifndef _ANDROID_UI_CONTROL_UI_H -#define _ANDROID_UI_CONTROL_UI_H - -/* - * Contains UI-side of UI control protocols. For the simplicity of implementation - * there are two UI control services: "ui-core-control" that handle UI controls - * initiated in the UI, and "core-ui-control" that handle UI controls initiated - * in the core. The reason for hawing two services is that some of the UI - * controls expect the core to respond with some data. The simplest way to - * differentiate core commands from core responses to the UI commands, is to have - * two separate services: one sends commands only, and another sends only - * responses. - */ - -#include "sockets.h" -#include "android/ui-ctl-common.h" - -/* Establishes connection with UI control services in the core. - * Param: - * console_socket Core's console socket. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_create(SockAddress* console_socket); - -/* - * UI->Core API - */ - -/* Sends AUI_UICTL_SET_COARSE_ORIENTATION message to the core. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_set_coarse_orientation(AndroidCoarseOrientation orient); - -/* Sends AUI_UICTL_TOGGLE_NETWORK message to the core. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_toggle_network(); - -/* Sends AUI_UICTL_TRACE_CONTROL message to the core. - * Param: - * start - Starts (> 0), or stops (== 0) tracing. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_trace_control(int start); - -/* Sends AUI_UICTL_CHK_NETWORK_DISABLED message to the core. - * Return: - * 0 if network is enabled, 1 if it is disabled, or < 0 on failure. - */ -int clientuictl_check_network_disabled(); - -/* Sends AUI_UICTL_GET_NETSPEED message to the core. - * Param: - * index - Index of an entry in the NetworkSpeed array. - * netspeed - Upon success contains allocated and initialized NetworkSpeed - * instance for the given index. Note that strings addressed by "name" and - * "display" fileds in the returned NetworkSpeed instance are containd inside - * the buffer allocated for the returned NetworkSpeed instance. Caller of this - * routine must eventually free the buffer returned in this parameter. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_get_netspeed(int index, NetworkSpeed** netspeed); - -/* Sends AUI_UICTL_GET_NETDELAY message to the core. - * Param: - * index - Index of an entry in the NetworkLatency array. - * netdelay - Upon success contains allocated and initialized NetworkLatency - * instance for the given index. Note that strings addressed by "name" and - * "display" fileds in the returned NetworkLatency instance are containd inside - * the buffer allocated for the returned NetworkLatency instance. Caller of this - * routine must eventually free the buffer returned in this parameter. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_get_netdelay(int index, NetworkLatency** netdelay); - -/* Sends AUI_UICTL_GET_QEMU_PATH message to the core. - * Param: - * type, filename - Query parameters - * netdelay - Upon success contains allocated and initialized NetworkLatency - * instance for the given index. Note that strings addressed by "name" and - * "display" fileds in the returned NetworkLatency instance are containd inside - * the buffer allocated for the returned NetworkLatency instance. Caller of this - * routine must eventually free the buffer returned in this parameter. - * Return: - * 0 on success, or < 0 on failure. - */ -int clientuictl_get_qemu_path(int type, const char* filename, char** path); - -#endif /* _ANDROID_UI_CONTROL_UI_H */ - |