Refactor attach-UI service

Change-Id: Ia68ceb57ee5b5a66fa76b837fe3b990eb12e7188
diff --git a/android/console.c b/android/console.c
index e797d9e..d776a5c 100644
--- a/android/console.c
+++ b/android/console.c
@@ -56,6 +56,7 @@
 #include "android/protocol/ui-commands-api.h"
 #include "android/protocol/core-commands-impl.h"
 #include "android/protocol/ui-commands-proxy.h"
+#include "android/protocol/attach-ui-proxy.h"
 
 #if defined(CONFIG_SLIRP)
 #include "libslirp.h"
@@ -134,9 +135,6 @@
 
 /* UI control service client (Core-> UI). */
 ControlClient core_ui_ctl_client = NULL;
-
-/* UI control service (Core -> UI. */
-// CoreUICtl* core_ui_ctl = NULL;
 #endif  // CONFIG_STANDALONE_CORE
 
 /* -android-avdname option value. Defined in vl-android.c */
@@ -243,6 +241,7 @@
 
 #ifdef CONFIG_STANDALONE_CORE
     if (client == attached_ui_client) {
+        attachUiProxy_destroy();
         attached_ui_client = NULL;
     }
 
@@ -2503,20 +2502,29 @@
         return -1;
     }
 
-    attached_ui_client = client;
-
-    if (android_op_ui_settings != NULL) {
-        // Reply "OK" with the saved -ui-settings property.
+    if (!attachUiProxy_create(client->sock)) {
         char reply_buf[4096];
+        attached_ui_client = client;
+        // Reply "OK" with the saved -ui-settings property.
         snprintf(reply_buf, sizeof(reply_buf), "OK: %s\r\n", android_op_ui_settings);
         control_write( client, reply_buf);
     } else {
-        control_write( client, "OK\r\n");
+        control_write( client, "KO\r\n" );
+        control_client_destroy(client);
+        return -1;
     }
 
     return 0;
 }
 
+void
+destroy_attach_ui_client(void)
+{
+    if (attached_ui_client != NULL) {
+        control_client_destroy(attached_ui_client);
+    }
+}
+
 /* Core display instance. */
 extern CoreDisplay core_display;
 
diff --git a/android/main-ui.c b/android/main-ui.c
index 968eeeb..ac5bfbe 100644
--- a/android/main-ui.c
+++ b/android/main-ui.c
@@ -64,6 +64,7 @@
 #include "android/protocol/user-events-proxy.h"
 #include "android/protocol/core-commands-proxy.h"
 #include "android/protocol/ui-commands-impl.h"
+#include "android/protocol/attach-ui-impl.h"
 
 #include "framebuffer.h"
 #include "iolooper.h"
@@ -103,9 +104,6 @@
 
 unsigned long   android_verbose;
 
-/* Instance of the "attach-UI" Emulator's core console client. */
-CoreConnection*   attach_client = NULL;
-
 /* -ui-settings parameters received from the core on UI attachment. */
 char* core_ui_settings = "";
 
@@ -922,32 +920,7 @@
     }
     sock_address_list_free(sockaddr_list);
 
-    attach_client = core_connection_create(&console_socket);
-    if (attach_client != NULL) {
-        if (!core_connection_open(attach_client)) {
-            if (!core_connection_switch_stream(attach_client, "attach-UI",
-                                               &core_ui_settings)) {
-                fprintf(stdout, "UI is now attached to the core %s\n",
-                        sock_address_to_string(&console_socket));
-                if (*core_ui_settings != '\0') {
-                    fprintf(stdout, "UI setting for the core%s:\n",
-                            core_ui_settings);
-                }
-            } else {
-                derror("Unable to attach to the core %s: %s\n",
-                       sock_address_to_string(&console_socket),
-                       core_ui_settings);
-                core_connection_close(attach_client);
-                core_connection_free(attach_client);
-                attach_client = NULL;
-                return -1;
-            }
-        } else {
-            core_connection_free(attach_client);
-            attach_client = NULL;
-            return -1;
-        }
-    } else {
+    if (attachUiImpl_create(&console_socket)) {
         return -1;
     }
 
@@ -956,28 +929,6 @@
     emulator = qemulator_get();
     qemulator_set_title(emulator);
 
-    // Connect to the core's framebuffer service
-    if (implFb_create(&console_socket, "-raw",
-                        qemulator_get_first_framebuffer(emulator))) {
-        return -1;
-    }
-
-    // Connect to the core's user events service.
-    if (userEventsProxy_create(&console_socket)) {
-        return -1;
-    }
-
-    // Connect to the core's UI control services. 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.
-    if (coreCmdProxy_create(&console_socket)) {
-        return -1;
-    }
-    if (uiCmdImpl_create(&console_socket)) {
-        return -1;
-    }
-
     return 0;
 }
 
@@ -1019,6 +970,21 @@
         exit(1);
     }
 
+    // Lets see if we're attaching to a running core process here.
+    if (opts->attach_core) {
+        if (attach_to_core(opts)) {
+            return -1;
+        }
+        // Connect to the core's UI control services.
+        if (coreCmdProxy_create(attachUiImpl_get_console_socket())) {
+            return -1;
+        }
+        // Connect to the core's user events service.
+        if (userEventsProxy_create(attachUiImpl_get_console_socket())) {
+            return -1;
+        }
+    }
+
     while (argc-- > 1) {
         opt = (++argv)[0];
 
@@ -1385,13 +1351,15 @@
     emulator_config_init();
     init_skinned_ui(opts->skindir, opts->skin, opts);
 
-    // Lets see if we're attaching to a running core process here.
-    if (opts->attach_core) {
-        /* TODO: This is just for the testing and debugging purposes. Later,
-         * when code develops, there will be more meat on that bone. */
-        if (attach_to_core(opts)) {
-            return -1;
-        }
+    // Connect to the core's framebuffer service
+    if (implFb_create(attachUiImpl_get_console_socket(), "-raw",
+                      qemulator_get_first_framebuffer(qemulator_get()))) {
+        return -1;
+    }
+
+    // Attach the recepient of UI commands.
+    if (uiCmdImpl_create(attachUiImpl_get_console_socket())) {
+        return -1;
     }
 
     if (!opts->netspeed) {
diff --git a/android/protocol/attach-ui-impl.c b/android/protocol/attach-ui-impl.c
new file mode 100644
index 0000000..8ca204c
--- /dev/null
+++ b/android/protocol/attach-ui-impl.c
@@ -0,0 +1,83 @@
+/* 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 "android/core-connection.h"
+#include "android/utils/debug.h"
+#include "android/utils/panic.h"
+#include "android/protocol/attach-ui-impl.h"
+
+/* Descriptor for the UI-side of the "attach-ui" service. */
+typedef struct AttachUIImpl {
+    /* Address of the Core's console socket. */
+    SockAddress     console_socket;
+
+    /* Core connection established for this service. */
+    CoreConnection* core_connection;
+
+    /* Socket descriptor for the UI service. */
+    int             sock;
+} AttachUIImpl;
+
+/* One and only one AttachUIImpl instance. */
+static AttachUIImpl  _attachUiImpl;
+
+SockAddress*
+attachUiImpl_get_console_socket(void)
+{
+    return &_attachUiImpl.console_socket;
+}
+
+int
+attachUiImpl_create(SockAddress* console_socket)
+{
+    char* handshake = NULL;
+
+    _attachUiImpl.console_socket = *console_socket;
+
+    // Connect to the core-ui-control service.
+    _attachUiImpl.core_connection =
+        core_connection_create_and_switch(console_socket, "attach-UI",
+                                          &handshake);
+    if (_attachUiImpl.core_connection == NULL) {
+        derror("Unable to connect to the attach-UI service: %s\n",
+               errno_str);
+        return -1;
+    }
+
+    fprintf(stdout, "UI is now attached 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;
+}
+
+void
+attachUiImpl_destroy(void)
+{
+    if (_attachUiImpl.core_connection != NULL) {
+        core_connection_close(_attachUiImpl.core_connection);
+        core_connection_free(_attachUiImpl.core_connection);
+        _attachUiImpl.core_connection = NULL;
+    }
+}
diff --git a/android/protocol/attach-ui-impl.h b/android/protocol/attach-ui-impl.h
new file mode 100644
index 0000000..3adc83a
--- /dev/null
+++ b/android/protocol/attach-ui-impl.h
@@ -0,0 +1,39 @@
+/* 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_ATTACH_UI_IMPL_H
+#define _ANDROID_PROTOCOL_ATTACH_UI_IMPL_H
+
+#include "sockets.h"
+
+/*
+ * Contains the UI-side implementation of the "attach-ui" service that is
+ * used to establish connection between the UI and the Core.
+ */
+
+/* Creates and initializes descriptor for the UI-side of the "atatch-ui"
+ * service. Note that there can be only one instance of this service in the core.
+ * Param:
+ *  console_socket - Addresses Core's console.
+ * Return:
+ *  0 on success, or < 0 on failure.
+ */
+extern int attachUiImpl_create(SockAddress* console_socket);
+
+/* Destroys the descriptor for the UI-side of the "attach-ui" service. */
+extern void attachUiImpl_destroy(void);
+
+/* Gets Core's console socket address for the attached UI. */
+extern SockAddress* attachUiImpl_get_console_socket(void);
+
+#endif /* _ANDROID_PROTOCOL_ATTACH_UI_IMPL_H */
+
diff --git a/android/protocol/attach-ui-proxy.c b/android/protocol/attach-ui-proxy.c
new file mode 100644
index 0000000..191b36d
--- /dev/null
+++ b/android/protocol/attach-ui-proxy.c
@@ -0,0 +1,110 @@
+/* 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 "attach-ui" service that is
+ * used to establish connection between the UI and the Core.
+ */
+
+#include "android/android.h"
+#include "android/globals.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"
+
+/* Descriptor for the UI attach-ui proxy. */
+typedef struct AttachUIProxy {
+    /* 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;
+
+    /* Socket descriptor for this service. */
+    int                 sock;
+} AttachUIProxy;
+
+/* One and only one AttachUIProxy instance. */
+static AttachUIProxy    _attachUiProxy;
+
+/* Implemented in android/console.c */
+extern void destroy_attach_ui_client(void);
+
+/* Asynchronous I/O callback for AttachUIProxy 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 - AttachUIProxy instance.
+ */
+static void
+_attachUiProxy_io_func(void* opaque, int fd, unsigned events)
+{
+    AttachUIProxy* uicmd = (AttachUIProxy*)opaque;
+    AsyncReader reader;
+    AsyncStatus status;
+    uint8_t read_buf[1];
+
+    if (events & LOOP_IO_WRITE) {
+        derror("Unexpected LOOP_IO_WRITE in _attachUiProxy_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 _attachUiProxy_io_func\n", status);
+        return;
+    }
+    // We expect only socket disconnection error here.
+    if (errno != ECONNRESET) {
+        derror("Unexpected read error %d (%s) in _attachUiProxy_io_func.\n",
+               errno, errno_str);
+        return;
+    }
+
+    // Client got disconnectted.
+    destroy_attach_ui_client();
+}
+
+int
+attachUiProxy_create(int fd)
+{
+    // Initialize the only AttachUIProxy instance.
+    _attachUiProxy.sock = fd;
+    _attachUiProxy.looper = looper_newCore();
+    loopIo_init(&_attachUiProxy.io, _attachUiProxy.looper, _attachUiProxy.sock,
+                _attachUiProxy_io_func, &_attachUiProxy);
+    loopIo_wantRead(&_attachUiProxy.io);
+
+    return 0;
+}
+
+void
+attachUiProxy_destroy(void)
+{
+    if (_attachUiProxy.looper != NULL) {
+        // Stop all I/O that may still be going on.
+        loopIo_done(&_attachUiProxy.io);
+        looper_free(_attachUiProxy.looper);
+        _attachUiProxy.looper = NULL;
+    }
+    _attachUiProxy.sock = -1;
+}
diff --git a/android/protocol/attach-ui-proxy.h b/android/protocol/attach-ui-proxy.h
new file mode 100644
index 0000000..a7d54f4
--- /dev/null
+++ b/android/protocol/attach-ui-proxy.h
@@ -0,0 +1,33 @@
+/* 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_ATTACH_UI_PROXY_H
+#define _ANDROID_PROTOCOL_ATTACH_UI_PROXY_H
+
+/*
+ * Contains the Core-side implementation of the "attach-ui" service that is
+ * used to establish connection between the UI and the Core.
+ */
+
+/* Creates and initializes descriptor for the Core-side of the "atatch-ui"
+ * 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 attachUiProxy_create(int fd);
+
+/* Destroys the descriptor for the Core-side of the "attach-ui" service. */
+extern void attachUiProxy_destroy(void);
+
+#endif /* _ANDROID_PROTOCOL_ATTACH_UI_PROXY_H */
diff --git a/android/protocol/core-commands-proxy.c b/android/protocol/core-commands-proxy.c
index 1bd0937..a52a376 100644
--- a/android/protocol/core-commands-proxy.c
+++ b/android/protocol/core-commands-proxy.c
@@ -120,27 +120,6 @@
     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);
-        _coreCmdProxy.sync_writer = NULL;
-    }
-    if (_coreCmdProxy.sync_reader != NULL) {
-        syncsocket_close(_coreCmdProxy.sync_reader);
-        syncsocket_free(_coreCmdProxy.sync_reader);
-        _coreCmdProxy.sync_reader = NULL;
-    }
-    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)
 {
@@ -351,13 +330,13 @@
     _coreCmdProxy.sync_writer = syncsocket_init(_coreCmdProxy.sock);
     if (_coreCmdProxy.sync_writer == NULL) {
         derror("Unable to initialize CoreCmdProxy writer: %s\n", errno_str);
-        _coreCmdProxy_destroy();
+        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();
+        coreCmdProxy_destroy();
         return -1;
     }
 
@@ -374,3 +353,24 @@
 
     return 0;
 }
+
+/* Destroys CoreCmdProxy instance. */
+void
+coreCmdProxy_destroy(void)
+{
+    if (_coreCmdProxy.sync_writer != NULL) {
+        syncsocket_close(_coreCmdProxy.sync_writer);
+        syncsocket_free(_coreCmdProxy.sync_writer);
+        _coreCmdProxy.sync_writer = NULL;
+    }
+    if (_coreCmdProxy.sync_reader != NULL) {
+        syncsocket_close(_coreCmdProxy.sync_reader);
+        syncsocket_free(_coreCmdProxy.sync_reader);
+        _coreCmdProxy.sync_reader = NULL;
+    }
+    if (_coreCmdProxy.core_connection != NULL) {
+        core_connection_close(_coreCmdProxy.core_connection);
+        core_connection_free(_coreCmdProxy.core_connection);
+        _coreCmdProxy.core_connection = NULL;
+    }
+}
diff --git a/android/protocol/core-commands-proxy.h b/android/protocol/core-commands-proxy.h
index 8303ed4..4283296 100644
--- a/android/protocol/core-commands-proxy.h
+++ b/android/protocol/core-commands-proxy.h
@@ -29,4 +29,7 @@
  */
 extern int coreCmdProxy_create(SockAddress* console_socket);
 
+/* Destroys the UI-side of the "ui-core-control" */
+void coreCmdProxy_destroy(void);
+
 #endif /* _ANDROID_PROTOCOL_CORE_COMMANDS_PROXY_H */
diff --git a/android/protocol/ui-commands-impl.c b/android/protocol/ui-commands-impl.c
index 456c61e..30d5277 100644
--- a/android/protocol/ui-commands-impl.c
+++ b/android/protocol/ui-commands-impl.c
@@ -17,7 +17,6 @@
  */
 
 #include "console.h"
-//#include "android/hw-control.h"
 #include "android/looper.h"
 #include "android/core-connection.h"
 #include "android/async-utils.h"
@@ -73,25 +72,6 @@
 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.
@@ -146,7 +126,7 @@
         if (status == 0) {
             /* Disconnection, meaning that the core process got termonated. */
             fprintf(stderr, "core-ui-control service got disconnected\n");
-            _uiCmdImpl_destroy();
+            uiCmdImpl_destroy();
             return;
         }
         if (status < 0) {
@@ -227,7 +207,7 @@
                             &_uiCmdImpl)) {
         derror("Unable to set up UI _uiCmdImpl_io_read callback: %s\n",
                errno_str);
-        _uiCmdImpl_destroy();
+        uiCmdImpl_destroy();
         if (handshake != NULL) {
             free(handshake);
         }
@@ -247,6 +227,24 @@
     return 0;
 }
 
+void
+uiCmdImpl_destroy(void)
+{
+    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;
+    }
+}
+
 int
 uicmd_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback,
                                      void* opaque)
diff --git a/android/protocol/ui-commands-impl.h b/android/protocol/ui-commands-impl.h
index 0e5b52f..fa05e8e 100644
--- a/android/protocol/ui-commands-impl.h
+++ b/android/protocol/ui-commands-impl.h
@@ -31,4 +31,7 @@
  */
 extern int uiCmdImpl_create(SockAddress* console_socket);
 
+/* Destroys UI-side of the "core-ui-control" service. */
+extern void uiCmdImpl_destroy();
+
 #endif /* _ANDROID_PROTOCOL_UI_COMMANDS_IMPL_H */
diff --git a/android/protocol/user-events-proxy.c b/android/protocol/user-events-proxy.c
index d35012f..2049b68 100644
--- a/android/protocol/user-events-proxy.c
+++ b/android/protocol/user-events-proxy.c
@@ -34,22 +34,6 @@
 /* One and only one user events client instance. */
 static UserEventsProxy _userEventsProxy = { 0 };
 
-/* Destroys CoreCmdProxy instance. */
-static void
-_userEventsProxy_destroy(void)
-{
-    if (_userEventsProxy.sync_writer != NULL) {
-        syncsocket_close(_userEventsProxy.sync_writer);
-        syncsocket_free(_userEventsProxy.sync_writer);
-        _userEventsProxy.sync_writer = NULL;
-    }
-    if (_userEventsProxy.core_connection != NULL) {
-        core_connection_close(_userEventsProxy.core_connection);
-        core_connection_free(_userEventsProxy.core_connection);
-        _userEventsProxy.core_connection = NULL;
-    }
-}
-
 /* Sends an event to the core.
  * Parameters:
  *  event - Event type. Must be one of the AUSER_EVENT_XXX.
@@ -107,7 +91,7 @@
     _userEventsProxy.sync_writer = syncsocket_init(_userEventsProxy.sock);
     if (_userEventsProxy.sync_writer == NULL) {
         derror("Unable to initialize UserEventsProxy writer: %s\n", errno_str);
-        _userEventsProxy_destroy();
+        userEventsProxy_destroy();
         return -1;
     }
 
@@ -125,6 +109,20 @@
 }
 
 void
+userEventsProxy_destroy(void)
+{
+    if (_userEventsProxy.sync_writer != NULL) {
+        syncsocket_close(_userEventsProxy.sync_writer);
+        syncsocket_free(_userEventsProxy.sync_writer);
+        _userEventsProxy.sync_writer = NULL;
+    }
+    if (_userEventsProxy.core_connection != NULL) {
+        core_connection_close(_userEventsProxy.core_connection);
+        core_connection_free(_userEventsProxy.core_connection);
+        _userEventsProxy.core_connection = NULL;
+    }
+}
+void
 user_event_keycodes(int *kcodes, int count)
 {
     int nn;
diff --git a/android/protocol/user-events-proxy.h b/android/protocol/user-events-proxy.h
index 95f6614..08a80cf 100644
--- a/android/protocol/user-events-proxy.h
+++ b/android/protocol/user-events-proxy.h
@@ -27,4 +27,7 @@
  */
 extern int userEventsProxy_create(SockAddress* console_socket);
 
+/* Destroys the UI-side of the "user-events". */
+extern void userEventsProxy_destroy(void);
+
 #endif /* _ANDROID_PROTOCOL_USER_EVENTS_PROXY_H */
diff --git a/android/sync-utils.h b/android/sync-utils.h
index d99caaf..bb54f3c 100644
--- a/android/sync-utils.h
+++ b/android/sync-utils.h
@@ -22,6 +22,7 @@
 #ifndef ANDROID_SYNC_UTILS_H
 #define ANDROID_SYNC_UTILS_H
 
+#include "android/android.h"
 #include "sockets.h"
 
 /* Descriptor for a connected non-blocking socket providing synchronous I/O */