aboutsummaryrefslogtreecommitdiffstats
path: root/android/protocol
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2011-01-28 10:56:16 -0800
committerVladimir Chtchetkine <vchtchetkine@google.com>2011-01-28 10:56:16 -0800
commit250b2e00af04f8407dea564e643dad4ef08b8a88 (patch)
treea9aac104fcd0752b3ba93246bf0fa98ac142ece0 /android/protocol
parent138f690b8c80a0d0e06a0549d4715243c12a0c96 (diff)
downloadexternal_qemu-250b2e00af04f8407dea564e643dad4ef08b8a88.zip
external_qemu-250b2e00af04f8407dea564e643dad4ef08b8a88.tar.gz
external_qemu-250b2e00af04f8407dea564e643dad4ef08b8a88.tar.bz2
Refactored user-events protocol
Change-Id: I08afb96ef17a52c3795f5029acfc244a93ab57c7
Diffstat (limited to 'android/protocol')
-rw-r--r--android/protocol/core-commands-proxy.c2
-rw-r--r--android/protocol/user-events-impl.c206
-rw-r--r--android/protocol/user-events-impl.h33
-rw-r--r--android/protocol/user-events-protocol.h58
-rw-r--r--android/protocol/user-events-proxy.c180
-rw-r--r--android/protocol/user-events-proxy.h30
6 files changed, 509 insertions, 0 deletions
diff --git a/android/protocol/core-commands-proxy.c b/android/protocol/core-commands-proxy.c
index 6bd3d4e..1bd0937 100644
--- a/android/protocol/core-commands-proxy.c
+++ b/android/protocol/core-commands-proxy.c
@@ -127,10 +127,12 @@ _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);
diff --git a/android/protocol/user-events-impl.c b/android/protocol/user-events-impl.c
new file mode 100644
index 0000000..5c9525e
--- /dev/null
+++ b/android/protocol/user-events-impl.c
@@ -0,0 +1,206 @@
+/* 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 of the "user events" service. Here we receive and
+ * handle user events sent from the UI.
+ */
+
+#include "user-events.h"
+#include "android/globals.h"
+#include "android/android.h"
+#include "android/looper.h"
+#include "android/async-utils.h"
+#include "android/sync-utils.h"
+#include "android/utils/system.h"
+#include "android/utils/debug.h"
+#include "android/protocol/user-events-protocol.h"
+#include "android/protocol/user-events-impl.h"
+
+/* Enumerates state values for the event reader in the UserEventsImpl descriptor.
+ */
+typedef enum UserEventsImplState {
+ /* The reader is waiting on event header. */
+ EXPECTS_HEADER,
+
+ /* The reader is waiting on event parameters. */
+ EXPECTS_PARAMETERS,
+} UserEventsImplState;
+
+
+/* Core user events service descriptor. */
+typedef struct UserEventsImpl {
+ /* Reader to receive user events. */
+ AsyncReader user_events_reader;
+
+ /* I/O associated with this descriptor. */
+ LoopIo io;
+
+ /* Looper used to communicate user events. */
+ Looper* looper;
+
+ /* Socket for this service. */
+ int sock;
+
+ /* State of the service (see UE_STATE_XXX for possible values). */
+ UserEventsImplState state;
+
+ /* Current event header. */
+ UserEventHeader event_header;
+
+ /* Current event parameters. */
+ union {
+ UserEventGeneric generic_event;
+ UserEventMouse mouse_event;
+ UserEventKeycode keycode_event;
+ };
+} UserEventsImpl;
+
+/* Implemented in android/console.c */
+extern void destroy_user_events_client(void);
+
+/* One and only one UserEventsImpl instance. */
+static UserEventsImpl _UserEventsImpl;
+
+/* Asynchronous I/O callback reading user events.
+ * Param:
+ * opaque - UserEventsImpl instance.
+ */
+static void
+_userEventsImpl_io_func(void* opaque, int fd, unsigned events)
+{
+ UserEventsImpl* ueimpl;
+ AsyncStatus status;
+
+ 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 _userEventsImpl_io_func\n");
+ return;
+ }
+
+ ueimpl = (UserEventsImpl*)opaque;
+ // Read whatever is expected from the socket.
+ status = asyncReader_read(&ueimpl->user_events_reader, &ueimpl->io);
+
+
+ switch (status) {
+ case ASYNC_COMPLETE:
+ switch (ueimpl->state) {
+ case EXPECTS_HEADER:
+ // We just read event header. Now we expect event parameters.
+ ueimpl->state = EXPECTS_PARAMETERS;
+ // Setup the reader depending on the event type.
+ switch (ueimpl->event_header.event_type) {
+ case AUSER_EVENT_MOUSE:
+ asyncReader_init(&ueimpl->user_events_reader,
+ &ueimpl->mouse_event,
+ sizeof(ueimpl->mouse_event),
+ &ueimpl->io);
+ break;
+
+ case AUSER_EVENT_KEYCODE:
+ asyncReader_init(&ueimpl->user_events_reader,
+ &ueimpl->keycode_event,
+ sizeof(ueimpl->keycode_event),
+ &ueimpl->io);
+ break;
+
+ case AUSER_EVENT_GENERIC:
+ asyncReader_init(&ueimpl->user_events_reader,
+ &ueimpl->generic_event,
+ sizeof(ueimpl->generic_event),
+ &ueimpl->io);
+ break;
+
+ default:
+ derror("Unexpected user event type %d\n",
+ ueimpl->event_header.event_type);
+ break;
+ }
+ break;
+
+ case EXPECTS_PARAMETERS:
+ // We just read event parameters. Lets fire the event.
+ switch (ueimpl->event_header.event_type) {
+ case AUSER_EVENT_MOUSE:
+ user_event_mouse(ueimpl->mouse_event.dx,
+ ueimpl->mouse_event.dy,
+ ueimpl->mouse_event.dz,
+ ueimpl->mouse_event.buttons_state);
+ break;
+
+ case AUSER_EVENT_KEYCODE:
+ user_event_keycode(ueimpl->keycode_event.keycode);
+ break;
+
+ case AUSER_EVENT_GENERIC:
+ user_event_generic(ueimpl->generic_event.type,
+ ueimpl->generic_event.code,
+ ueimpl->generic_event.value);
+ break;
+
+ default:
+ derror("Unexpected user event type %d\n",
+ ueimpl->event_header.event_type);
+ break;
+ }
+ // Prepare to receive the next event header.
+ ueimpl->event_header.event_type = -1;
+ ueimpl->state = EXPECTS_HEADER;
+ asyncReader_init(&ueimpl->user_events_reader,
+ &ueimpl->event_header,
+ sizeof(ueimpl->event_header), &ueimpl->io);
+ break;
+ }
+ break;
+ case ASYNC_ERROR:
+ loopIo_dontWantRead(&ueimpl->io);
+ if (errno == ECONNRESET) {
+ // UI has exited. We need to destroy user event service.
+ destroy_user_events_client();
+ } else {
+ derror("User event read error %d -> %s\n", errno, errno_str);
+ }
+ break;
+
+ case ASYNC_NEED_MORE:
+ // Transfer will eventually come back into this routine.
+ return;
+ }
+}
+
+int
+userEventsImpl_create(int fd)
+{
+ _UserEventsImpl.sock = fd;
+ _UserEventsImpl.event_header.event_type = -1;
+ _UserEventsImpl.state = EXPECTS_HEADER;
+ _UserEventsImpl.looper = looper_newCore();
+ loopIo_init(&_UserEventsImpl.io, _UserEventsImpl.looper, _UserEventsImpl.sock,
+ _userEventsImpl_io_func, &_UserEventsImpl);
+ asyncReader_init(&_UserEventsImpl.user_events_reader,
+ &_UserEventsImpl.event_header,
+ sizeof(_UserEventsImpl.event_header), &_UserEventsImpl.io);
+ return 0;
+}
+
+void
+userEventsImpl_destroy(void)
+{
+ if (_UserEventsImpl.looper != NULL) {
+ // Stop all I/O that may still be going on.
+ loopIo_done(&_UserEventsImpl.io);
+ looper_free(_UserEventsImpl.looper);
+ _UserEventsImpl.looper = NULL;
+ }
+}
diff --git a/android/protocol/user-events-impl.h b/android/protocol/user-events-impl.h
new file mode 100644
index 0000000..af5d5a4
--- /dev/null
+++ b/android/protocol/user-events-impl.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.
+*/
+
+/*
+ * Contains the Core-side of the "user events" service. Here we receive and
+ * handle user events sent from the UI.
+ */
+
+#ifndef _ANDROID_PROTOCOL_USER_EVENTS_IMPL_H
+#define _ANDROID_PROTOCOL_USER_EVENTS_IMPL_H
+
+/* Creates and initializes descriptor for the Core-side of the "user-events"
+ * 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 userEventsImpl_create(int fd);
+
+/* Destroys the descriptor for the Core-side of the "user-events" service. */
+extern void userEventsImpl_destroy(void);
+
+#endif /* _ANDROID_PROTOCOL_USER_EVENTS_IMPL_H */
diff --git a/android/protocol/user-events-protocol.h b/android/protocol/user-events-protocol.h
new file mode 100644
index 0000000..c1e64e2
--- /dev/null
+++ b/android/protocol/user-events-protocol.h
@@ -0,0 +1,58 @@
+/* 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_USER_EVENTS_H
+#define _ANDROID_PROTOCOL_USER_EVENTS_H
+
+/*
+ * Contains declarations related to the UI events handled by the Core.
+ */
+
+#include "android/globals.h"
+
+/* Mouse event. */
+#define AUSER_EVENT_MOUSE 0
+/* Keycode event. */
+#define AUSER_EVENT_KEYCODE 1
+/* Generic event. */
+#define AUSER_EVENT_GENERIC 2
+
+/* Header for user event message sent from the UI to the Core.
+ * Every user event sent by the UI begins with this header, immediately followed
+ * by the event parameters (if there are any).
+ */
+typedef struct UserEventHeader {
+ /* Event type. See AUSER_EVENT_XXX for possible values. */
+ uint8_t event_type;
+} UserEventHeader;
+
+/* Formats mouse event message (AUSER_EVENT_MOUSE) */
+typedef struct UserEventMouse {
+ int dx;
+ int dy;
+ int dz;
+ unsigned buttons_state;
+} UserEventMouse;
+
+/* Formats keycode event message (AUSER_EVENT_KEYCODE) */
+typedef struct UserEventKeycode {
+ int keycode;
+} UserEventKeycode;
+
+/* Formats generic event message (AUSER_EVENT_GENERIC) */
+typedef struct UserEventGeneric {
+ int type;
+ int code;
+ int value;
+} UserEventGeneric;
+
+#endif /* _ANDROID_PROTOCOL_USER_EVENTS_H */
diff --git a/android/protocol/user-events-proxy.c b/android/protocol/user-events-proxy.c
new file mode 100644
index 0000000..d35012f
--- /dev/null
+++ b/android/protocol/user-events-proxy.c
@@ -0,0 +1,180 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "user-events.h"
+#include "console.h"
+#include "android/looper.h"
+#include "android/async-utils.h"
+#include "android/core-connection.h"
+#include "android/utils/debug.h"
+#include "android/protocol/user-events-protocol.h"
+#include "android/protocol/user-events-proxy.h"
+
+/* Descriptor for the user events client. */
+typedef struct UserEventsProxy {
+ /* Core connection instance for the user events client. */
+ CoreConnection* core_connection;
+
+ /* Socket for the client. */
+ int sock;
+
+ /* Writes user events to the socket. */
+ SyncSocket* sync_writer;
+} UserEventsProxy;
+
+/* 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.
+ * event_param - Event parameters.
+ * size - Byte size of the event parameters buffer.
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+static int
+_userEventsProxy_send(uint8_t event, const void* event_param, size_t size)
+{
+ int res;
+ UserEventHeader header;
+
+ header.event_type = event;
+ res = syncsocket_start_write(_userEventsProxy.sync_writer);
+ if (!res) {
+ // Send event type first (event header)
+ res = syncsocket_write(_userEventsProxy.sync_writer, &header,
+ sizeof(header),
+ core_connection_get_timeout(sizeof(header)));
+ if (res > 0) {
+ // Send event param next.
+ res = syncsocket_write(_userEventsProxy.sync_writer, event_param,
+ size,
+ core_connection_get_timeout(sizeof(size)));
+ }
+ res = syncsocket_result(res);
+ syncsocket_stop_write(_userEventsProxy.sync_writer);
+ }
+ if (res < 0) {
+ derror("Unable to send user event: %s\n", errno_str);
+ }
+ return res;
+}
+
+int
+userEventsProxy_create(SockAddress* console_socket)
+{
+ char* handshake = NULL;
+
+ // Connect to the user-events service.
+ _userEventsProxy.core_connection =
+ core_connection_create_and_switch(console_socket, "user-events",
+ &handshake);
+ if (_userEventsProxy.core_connection == NULL) {
+ derror("Unable to connect to the user-events service: %s\n",
+ errno_str);
+ return -1;
+ }
+
+ // Initialze event writer.
+ _userEventsProxy.sock =
+ core_connection_get_socket(_userEventsProxy.core_connection);
+ _userEventsProxy.sync_writer = syncsocket_init(_userEventsProxy.sock);
+ if (_userEventsProxy.sync_writer == NULL) {
+ derror("Unable to initialize UserEventsProxy writer: %s\n", errno_str);
+ _userEventsProxy_destroy();
+ return -1;
+ }
+
+ fprintf(stdout, "user-events 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;
+}
+
+void
+user_event_keycodes(int *kcodes, int count)
+{
+ int nn;
+ for (nn = 0; nn < count; nn++)
+ user_event_keycode(kcodes[nn]);
+}
+
+void
+user_event_keycode(int kcode)
+{
+ UserEventKeycode message;
+ message.keycode = kcode;
+ _userEventsProxy_send(AUSER_EVENT_KEYCODE, &message, sizeof(message));
+}
+
+void
+user_event_key(unsigned code, unsigned down)
+{
+ if(code == 0) {
+ return;
+ }
+ if (VERBOSE_CHECK(keys))
+ printf(">> KEY [0x%03x,%s]\n", (code & 0x1ff), down ? "down" : " up " );
+
+ user_event_keycode((code & 0x1ff) | (down ? 0x200 : 0));
+}
+
+
+void
+user_event_mouse(int dx, int dy, int dz, unsigned buttons_state)
+{
+ UserEventMouse message;
+ message.dx = dx;
+ message.dy = dy;
+ message.dz = dz;
+ message.buttons_state = buttons_state;
+ _userEventsProxy_send(AUSER_EVENT_MOUSE, &message, sizeof(message));
+}
+
+void
+user_event_register_generic(void* opaque, QEMUPutGenericEvent *callback)
+{
+}
+
+void
+user_event_generic(int type, int code, int value)
+{
+ UserEventGeneric message;
+ message.type = type;
+ message.code = code;
+ message.value = value;
+ _userEventsProxy_send(AUSER_EVENT_GENERIC, &message, sizeof(message));
+}
diff --git a/android/protocol/user-events-proxy.h b/android/protocol/user-events-proxy.h
new file mode 100644
index 0000000..95f6614
--- /dev/null
+++ b/android/protocol/user-events-proxy.h
@@ -0,0 +1,30 @@
+/* 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 of the "user events" service. Here we send user events
+ * to the Core.
+ */
+
+#ifndef _ANDROID_PROTOCOL_USER_EVENTS_PROXY_H
+#define _ANDROID_PROTOCOL_USER_EVENTS_PROXY_H
+
+/* Creates and initializes descriptor for the UI-side of the "user-events"
+ * 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 userEventsProxy_create(SockAddress* console_socket);
+
+#endif /* _ANDROID_PROTOCOL_USER_EVENTS_PROXY_H */