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
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 */