aboutsummaryrefslogtreecommitdiffstats
path: root/android/protocol/ui-commands-proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'android/protocol/ui-commands-proxy.c')
-rw-r--r--android/protocol/ui-commands-proxy.c209
1 files changed, 209 insertions, 0 deletions
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));
+}