aboutsummaryrefslogtreecommitdiffstats
path: root/android
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2010-12-20 08:28:03 -0800
committerVladimir Chtchetkine <vchtchetkine@google.com>2010-12-20 08:28:03 -0800
commite95660aadc669784406d5f5a867988b8ecc2ed0d (patch)
tree480b3feaa14f6d392ceed62dba9cd0334dcba48d /android
parentaec5741a217d98db6007219c4e28dc24d3ecdb03 (diff)
downloadexternal_qemu-e95660aadc669784406d5f5a867988b8ecc2ed0d.zip
external_qemu-e95660aadc669784406d5f5a867988b8ecc2ed0d.tar.gz
external_qemu-e95660aadc669784406d5f5a867988b8ecc2ed0d.tar.bz2
Resubmit framebuffer service implementation
Change-Id: I184e27a1e8d88835bc9f0502eccfa3f64a7aaf9e
Diffstat (limited to 'android')
-rw-r--r--android/async-utils.h6
-rw-r--r--android/console.c77
-rw-r--r--android/core-connection.c6
-rw-r--r--android/core-connection.h8
-rw-r--r--android/display-core.c48
-rw-r--r--android/display-core.h22
-rw-r--r--android/framebuffer-common.h37
-rw-r--r--android/framebuffer-core.c258
-rw-r--r--android/framebuffer-core.h55
-rw-r--r--android/framebuffer-ui.c223
-rw-r--r--android/framebuffer-ui.h49
-rw-r--r--android/looper-qemu.c6
-rw-r--r--android/main-ui.c14
-rw-r--r--android/sync-utils.c6
-rw-r--r--android/sync-utils.h8
15 files changed, 803 insertions, 20 deletions
diff --git a/android/async-utils.h b/android/async-utils.h
index e34e1bb..0b52f37 100644
--- a/android/async-utils.h
+++ b/android/async-utils.h
@@ -80,8 +80,8 @@ typedef struct {
size_t pos;
} AsyncWriter;
-/* Setup an ASyncReader, by giving the address of the read buffer,
- * and the number of bytes we want to read.
+/* Setup an ASyncWriter, by giving the address of the write buffer,
+ * and the number of bytes we want to write.
*
* This also calls loopIo_wantWrite(io) for you.
*/
@@ -100,7 +100,7 @@ void asyncWriter_init(AsyncWriter* aw,
* ECONNRESET in case of disconnection.
*
* ASYNC_NEED_MORE: If not all bytes could be sent yet (or if 'events'
- * doesn't contain LOOP_IO_READ).
+ * doesn't contain LOOP_IO_WRITE).
*/
AsyncStatus asyncWriter_write(AsyncWriter* aw,
LoopIo* io);
diff --git a/android/console.c b/android/console.c
index 68b9480..398218a 100644
--- a/android/console.c
+++ b/android/console.c
@@ -25,7 +25,6 @@
#include "qemu-char.h"
#include "sysemu.h"
#include "android/android.h"
-#include "sockets.h"
#include "cpu.h"
#include "hw/goldfish_device.h"
#include "hw/power_supply.h"
@@ -52,6 +51,8 @@
#include "android/keycode-array.h"
#include "android/charmap.h"
#include "android/core-ui-protocol.h"
+#include "android/display-core.h"
+#include "android/framebuffer-core.h"
#if defined(CONFIG_SLIRP)
#include "libslirp.h"
@@ -112,9 +113,14 @@ typedef struct ControlGlobalRec_
} ControlGlobalRec;
+#ifdef CONFIG_STANDALONE_CORE
/* UI client currently attached to the core. */
ControlClient attached_ui_client = NULL;
+/* Core framebuffer service client. */
+ControlClient framebuffer_client = NULL;
+#endif // CONFIG_STANDALONE_CORE
+
static int
control_global_add_redir( ControlGlobal global,
int host_port,
@@ -214,10 +220,21 @@ control_client_destroy( ControlClient client )
D(( "destroying control client %p\n", client ));
+#ifdef CONFIG_STANDALONE_CORE
if (client == attached_ui_client) {
attached_ui_client = NULL;
}
+ if (client == framebuffer_client) {
+ CoreFramebuffer* core_fb = coredisplay_detach_fb_service();
+ if (core_fb != NULL) {
+ corefb_destroy(core_fb);
+ AFREE(core_fb);
+ }
+ framebuffer_client = NULL;
+ }
+#endif // CONFIG_STANDALONE_CORE
+
sock = control_client_detach( client );
if (sock >= 0)
socket_close(sock);
@@ -2436,6 +2453,7 @@ do_qemu_monitor( ControlClient client, char* args )
return 0;
}
+#ifdef CONFIG_STANDALONE_CORE
/* UI settings, passed to the core via -ui-settings command line parameter. */
extern char* android_op_ui_settings;
@@ -2463,16 +2481,73 @@ do_attach_ui( ControlClient client, char* args )
return 0;
}
+/* Core display instance. */
+extern CoreDisplay core_display;
+
+static int
+do_create_framebuffer_service( ControlClient client, char* args )
+{
+ CoreFramebuffer* core_fb;
+ const char* protocol = "-raw"; // Default framebuffer exchange protocol.
+
+ // Protocol type is defined by the arguments passed with the stream switch
+ // command.
+ if (args != NULL && *args != '\0') {
+ size_t token_len;
+ const char* param_end = strchr(args, ' ');
+ if (param_end == NULL) {
+ param_end = args + strlen(args);
+ }
+ token_len = param_end - args;
+ protocol = args;
+
+ // Make sure that this is one of the supported protocols.
+ if (strncmp(protocol, "-raw", token_len) &&
+ strncmp(protocol, "-shared", token_len)) {
+ derror("Invalid framebuffer parameter %s\n", protocol);
+ control_write( client, "KO: Invalid parameter\r\n" );
+ control_client_destroy(client);
+ return -1;
+ }
+ }
+
+ // Make sure that there are no framebuffer client already existing.
+ if (framebuffer_client != NULL) {
+ control_write( client, "KO: Another framebuffer service is already existing!\r\n" );
+ control_client_destroy(client);
+ return -1;
+ }
+
+ core_fb = corefb_create(client->sock, protocol);
+ if (!coredisplay_attach_fb_service(core_fb)) {
+ framebuffer_client = client;
+ control_write( client, "OK\r\n");
+ } else {
+ control_write( client, "KO\r\n" );
+ control_client_destroy(client);
+ return -1;
+ }
+
+ return 0;
+}
+#endif // CONFIG_STANDALONE_CORE
+
static const CommandDefRec qemu_commands[] =
{
{ "monitor", "enter QEMU monitor",
"Enter the QEMU virtual machine monitor\r\n",
NULL, do_qemu_monitor, NULL },
+#ifdef CONFIG_STANDALONE_CORE
{ "attach UI", "attach UI to the core",
"Attach UI to the core\r\n",
NULL, do_attach_ui, NULL },
+ { "framebuffer", "create framebuffer service",
+ "Create framebuffer service\r\n",
+ NULL, do_create_framebuffer_service, NULL },
+#endif // CONFIG_STANDALONE_CORE
+
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
diff --git a/android/core-connection.c b/android/core-connection.c
index 6e05be0..f3950a7 100644
--- a/android/core-connection.c
+++ b/android/core-connection.c
@@ -321,3 +321,9 @@ core_connection_detach(CoreConnection* desc)
{
core_connection_write(desc, "\n", 1, NULL);
}
+
+int
+core_connection_get_socket(CoreConnection* desc)
+{
+ return (desc != NULL) ? syncsocket_get_socket(desc->ssocket) : -1;
+}
diff --git a/android/core-connection.h b/android/core-connection.h
index fc1be43..19e91a1 100644
--- a/android/core-connection.h
+++ b/android/core-connection.h
@@ -130,4 +130,12 @@ int core_connection_switch_stream(CoreConnection* desc,
*/
void core_connection_detach(CoreConnection* desc);
+/* Gets socket descriptor associated with the core connection.
+ * Param:
+ * desc Console client descriptor opened with core_connection_open.
+ * Return
+ * Socket descriptor associated with the core connection.
+ */
+int core_connection_get_socket(CoreConnection* desc);
+
#endif // QEMU_ANDROID_CORE_CONNECTION_H
diff --git a/android/display-core.c b/android/display-core.c
index e0574a3..70e7b14 100644
--- a/android/display-core.c
+++ b/android/display-core.c
@@ -21,14 +21,17 @@
/* Core display descriptor. */
struct CoreDisplay {
/* Display state for this core display. */
- DisplayState* ds;
+ DisplayState* ds;
/* Framebuffer for this core display. */
- QFrameBuffer* fb;
+ QFrameBuffer* fb;
+
+ /* Framebuffer service associated with this core display. */
+ CoreFramebuffer* core_fb;
};
/* One and only one core display instance. */
-static CoreDisplay core_display;
+CoreDisplay core_display;
/*
* Framebuffer calls this routine when it detects changes. This routine will
@@ -36,8 +39,12 @@ static CoreDisplay core_display;
* See QFrameBufferUpdateFunc in framebuffer.h for more info on this callback.
*/
static void
-core_display_fb_update(void* opaque, int x, int y, int w, int h)
+coredisplay_fb_update(void* opaque, int x, int y, int w, int h)
{
+ CoreDisplay* cd = (CoreDisplay*)opaque;
+ if (cd->core_fb) {
+ corefb_update(cd->core_fb, cd->ds, cd->fb, x, y, w, h);
+ }
}
/*
@@ -45,7 +52,7 @@ core_display_fb_update(void* opaque, int x, int y, int w, int h)
* info on this callback.
*/
static void
-core_display_fb_rotate(void* opaque, int rotation)
+coredisplay_fb_rotate(void* opaque, int rotation)
{
}
@@ -54,7 +61,7 @@ core_display_fb_rotate(void* opaque, int rotation)
* info on this callback.
*/
static void
-core_display_fb_poll(void* opaque)
+coredisplay_fb_poll(void* opaque)
{
// This will eventually call core_display_fb_update.
qframebuffer_check_updates();
@@ -65,18 +72,19 @@ core_display_fb_poll(void* opaque)
* info on this callback.
*/
static void
-core_display_fb_done(void* opaque)
+coredisplay_fb_done(void* opaque)
{
}
void
-core_display_init(DisplayState* ds)
+coredisplay_init(DisplayState* ds)
{
core_display.ds = ds;
/* Create and initialize framebuffer instance that will be used for core
* display.
*/
ANEW0(core_display.fb);
+ core_display.core_fb = NULL;
qframebuffer_init(core_display.fb, ds->surface->width, ds->surface->height,
0, QFRAME_BUFFER_RGB565 );
qframebuffer_fifo_add(core_display.fb);
@@ -85,7 +93,27 @@ core_display_init(DisplayState* ds)
* core all framebuffer callbacks are essentially no-ops.
*/
qframebuffer_add_client(core_display.fb, &core_display,
- core_display_fb_update, core_display_fb_rotate,
- core_display_fb_poll, core_display_fb_done);
+ coredisplay_fb_update, coredisplay_fb_rotate,
+ coredisplay_fb_poll, coredisplay_fb_done);
android_display_init(ds, core_display.fb);
}
+
+int
+coredisplay_attach_fb_service(CoreFramebuffer* core_fb)
+{
+ if (core_display.core_fb == NULL) {
+ core_display.core_fb = core_fb;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+CoreFramebuffer*
+coredisplay_detach_fb_service(void)
+{
+ CoreFramebuffer* ret = core_display.core_fb;
+ core_display.core_fb = NULL;
+ return ret;
+}
+
diff --git a/android/display-core.h b/android/display-core.h
index 9a44f9a..02301c5 100644
--- a/android/display-core.h
+++ b/android/display-core.h
@@ -18,8 +18,9 @@
#ifndef _ANDROID_DISPLAY_CORE_H
#define _ANDROID_DISPLAY_CORE_H
-#include "android/display.h"
#include "framebuffer.h"
+#include "android/display.h"
+#include "android/framebuffer-core.h"
/* Descriptor for a core display instance */
typedef struct CoreDisplay CoreDisplay;
@@ -29,6 +30,23 @@ typedef struct CoreDisplay CoreDisplay;
* Param:
* ds - Display state to use for the core display.
*/
-extern void core_display_init(DisplayState* ds);
+extern void coredisplay_init(DisplayState* ds);
+
+/*
+ * Attaches framebuffer service to the core display.
+ * Param:
+ * core_fb - Framebuffer service descriptor to attach.
+ * Return:
+ * 0 on success, or -1 on failure.
+ */
+extern int coredisplay_attach_fb_service(CoreFramebuffer* core_fb);
+
+/*
+ * Detaches framebuffer service previously attached to the core display.
+ * Return:
+ * Framebuffer service descriptor attached to the core display, or NULL if
+ * the core display didn't have framebuffer service attached to it.
+ */
+extern CoreFramebuffer* coredisplay_detach_fb_service(void);
#endif /* _ANDROID_DISPLAY_CORE_H */
diff --git a/android/framebuffer-common.h b/android/framebuffer-common.h
new file mode 100644
index 0000000..7ca654c
--- /dev/null
+++ b/android/framebuffer-common.h
@@ -0,0 +1,37 @@
+/* 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 framebuffer declarations that are shared by the core and the UI.
+ */
+
+#ifndef _ANDROID_FRAMEBUFFER_COMMON_H
+#define _ANDROID_FRAMEBUFFER_COMMON_H
+
+#include "sysemu.h"
+
+/* Header of framebuffer update message sent from the core to the UI. */
+typedef struct FBUpdateMessage {
+ /* x, y, w, and h identify the rectangle that is being updated. */
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+
+ /* Number of bits used to encode a single pixel. */
+ uint8_t bits_per_pixel;
+
+ /* Contains updating rectangle copied over from the framebuffer's pixels. */
+ uint8_t rect[0];
+} FBUpdateMessage;
+
+#endif /* _ANDROID_FRAMEBUFFER_UI_H */
diff --git a/android/framebuffer-core.c b/android/framebuffer-core.c
new file mode 100644
index 0000000..a473415
--- /dev/null
+++ b/android/framebuffer-core.c
@@ -0,0 +1,258 @@
+/* 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 core-side framebuffer service that sends framebuffer updates
+ * to the UI connected to the core.
+ */
+
+#include "console.h"
+#include "framebuffer.h"
+#include "android/looper.h"
+#include "android/display-core.h"
+#include "android/async-utils.h"
+#include "android/framebuffer-common.h"
+#include "android/framebuffer-core.h"
+#include "android/utils/system.h"
+#include "android/utils/debug.h"
+
+/* Core framebuffer descriptor. */
+struct CoreFramebuffer {
+ /* Writer used to send FB update notification messages. */
+ AsyncWriter fb_update_writer;
+
+ /* I/O associated with this descriptor. */
+ LoopIo io;
+
+ /* Looper used to communicate framebuffer updates. */
+ Looper* looper;
+
+ /* Head of the list of pending FB update notifications. */
+ struct FBUpdateNotify* fb_update_head;
+
+ /* Tail of the list of pending FB update notifications. */
+ struct FBUpdateNotify* fb_update_tail;
+
+ /* Socket used to communicate framebuffer updates. */
+ int sock;
+};
+
+/* Framebuffer update notification descriptor to the core. */
+typedef struct FBUpdateNotify {
+ /* Links all pending FB update notifications. */
+ struct FBUpdateNotify* next_fb_update;
+
+ /* Core framebuffer instance that owns the message. */
+ CoreFramebuffer* core_fb;
+
+ /* Size of the message to transfer. */
+ size_t message_size;
+
+ /* Update message. */
+ FBUpdateMessage message;
+} FBUpdateNotify;
+
+/*
+ * Gets pointer in framebuffer's pixels for the given pixel.
+ * Param:
+ * fb Framebuffer containing pixels.
+ * x, and y identify the pixel to get pointer for.
+ * Return:
+ * Pointer in framebuffer's pixels for the given pixel.
+ */
+static const uint8_t*
+_pixel_offset(const QFrameBuffer* fb, int x, int y)
+{
+ return (const uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel;
+}
+
+/*
+ * Copies pixels from a framebuffer rectangle.
+ * Param:
+ * rect - Buffer where to copy pixel.
+ * fb - Framebuffer containing the rectangle to copy.
+ * x, y, w, and h - dimensions of the rectangle to copy.
+ */
+static void
+_copy_fb_rect(uint8_t* rect, const QFrameBuffer* fb, int x, int y, int w, int h)
+{
+ const uint8_t* start = _pixel_offset(fb, x, y);
+ for (; h > 0; h--) {
+ memcpy(rect, start, w * fb->bytes_per_pixel);
+ start += fb->pitch;
+ rect += w * fb->bytes_per_pixel;
+ }
+}
+
+/*
+ * Allocates and initializes framebuffer update notification descriptor.
+ * Param:
+ * ds - Display state for the framebuffer.
+ * fb Framebuffer containing pixels.
+ * x, y, w, and h identify the rectangle that is being updated.
+ * Return:
+ * Initialized framebuffer update notification descriptor.
+ */
+static FBUpdateNotify*
+fbupdatenotify_create(CoreFramebuffer* core_fb, const QFrameBuffer* fb,
+ int x, int y, int w, int h)
+{
+ const size_t rect_size = w * h * fb->bytes_per_pixel;
+ FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size);
+
+ ret->next_fb_update = NULL;
+ ret->core_fb = core_fb;
+ ret->message_size = sizeof(FBUpdateMessage) + rect_size;
+ ret->message.x = x;
+ ret->message.y = y;
+ ret->message.w = w;
+ ret->message.h = h;
+ ret->message.bits_per_pixel = fb->bits_per_pixel;
+ _copy_fb_rect(ret->message.rect, fb, x, y, w, h);
+ return ret;
+}
+
+/*
+ * Deletes FBUpdateNotify descriptor, created with fbupdatenotify_create.
+ * Param:
+ * desc - Descreptor to delete.
+ */
+static void
+fbupdatenotify_delete(FBUpdateNotify* desc)
+{
+ if (desc != NULL) {
+ free(desc);
+ }
+}
+
+/*
+ * Asynchronous I/O callback launched when writing framebuffer notifications
+ * to the socket.
+ * Param:
+ * opaque - CoreFramebuffer instance.
+ */
+static void
+corefb_io_func(void* opaque, int fd, unsigned events)
+{
+ CoreFramebuffer* core_fb = opaque;
+
+ while (core_fb->fb_update_head != NULL) {
+ FBUpdateNotify* current_update = core_fb->fb_update_head;
+ // Lets continue writing of the current notification.
+ const AsyncStatus status =
+ asyncWriter_write(&core_fb->fb_update_writer, &core_fb->io);
+ switch (status) {
+ case ASYNC_COMPLETE:
+ // Done with the current update. Move on to the next one.
+ break;
+ case ASYNC_ERROR:
+ // Done with the current update. Move on to the next one.
+ loopIo_dontWantWrite(&core_fb->io);
+ break;
+
+ case ASYNC_NEED_MORE:
+ // Transfer will eventually come back into this routine.
+ return;
+ }
+
+ // Advance the list of updates
+ core_fb->fb_update_head = current_update->next_fb_update;
+ if (core_fb->fb_update_head == NULL) {
+ core_fb->fb_update_tail = NULL;
+ }
+ fbupdatenotify_delete(current_update);
+
+ if (core_fb->fb_update_head != NULL) {
+ // Schedule the next one.
+ asyncWriter_init(&core_fb->fb_update_writer,
+ &core_fb->fb_update_head->message,
+ core_fb->fb_update_head->message_size,
+ &core_fb->io);
+ }
+ }
+}
+
+CoreFramebuffer*
+corefb_create(int sock, const char* protocol)
+{
+ // At this point we're implementing the -raw protocol only.
+ CoreFramebuffer* ret;
+ ANEW0(ret);
+ ret->sock = sock;
+ ret->looper = looper_newCore();
+ loopIo_init(&ret->io, ret->looper, sock, corefb_io_func, ret);
+ ret->fb_update_head = NULL;
+ ret->fb_update_tail = NULL;
+ return ret;
+}
+
+void
+corefb_destroy(CoreFramebuffer* core_fb)
+{
+ if (core_fb != NULL) {
+ if (core_fb->looper != NULL) {
+ // Stop all I/O that may still be going on.
+ loopIo_done(&core_fb->io);
+ // Delete all pending frame updates.
+ while (core_fb->fb_update_head != NULL) {
+ FBUpdateNotify* pending_update = core_fb->fb_update_head;
+ core_fb->fb_update_head = pending_update->next_fb_update;
+ fbupdatenotify_delete(pending_update);
+ }
+ core_fb->fb_update_tail = NULL;
+ looper_free(core_fb->looper);
+ core_fb->looper = NULL;
+ }
+ }
+}
+
+void
+corefb_update(CoreFramebuffer* core_fb, struct DisplayState* ds,
+ struct QFrameBuffer* fb, int x, int y, int w, int h)
+{
+ AsyncStatus status;
+ FBUpdateNotify* descr = fbupdatenotify_create(core_fb, fb, x, y, w, h);
+
+ printf("Update framebuffer (%u bytes): %d:%d - %d:%d ",
+ descr->message_size, x, y, w, h);
+
+ // Lets see if we should list it behind other pending updates.
+ if (core_fb->fb_update_tail != NULL) {
+ core_fb->fb_update_tail->next_fb_update = descr;
+ core_fb->fb_update_tail = descr;
+ printf("PENDED\n");
+ return;
+ }
+
+ // We're first in the list. Just send it now.
+ core_fb->fb_update_head = core_fb->fb_update_tail = descr;
+ asyncWriter_init(&core_fb->fb_update_writer,
+ &core_fb->fb_update_head->message,
+ core_fb->fb_update_head->message_size, &core_fb->io);
+ status = asyncWriter_write(&core_fb->fb_update_writer, &core_fb->io);
+ switch (status) {
+ case ASYNC_COMPLETE:
+ fbupdatenotify_delete(descr);
+ core_fb->fb_update_head = core_fb->fb_update_tail = NULL;
+ printf("COMPLETED\n");
+ return;
+ case ASYNC_ERROR:
+ printf("FAILED: %s\n", errno_str);
+ fbupdatenotify_delete(descr);
+ core_fb->fb_update_head = core_fb->fb_update_tail = NULL;
+ return;
+ case ASYNC_NEED_MORE:
+ // Update transfer will eventually complete in corefb_io_func
+ printf("PARTIAL\n");
+ return;
+ }
+}
diff --git a/android/framebuffer-core.h b/android/framebuffer-core.h
new file mode 100644
index 0000000..6738d0e
--- /dev/null
+++ b/android/framebuffer-core.h
@@ -0,0 +1,55 @@
+/* 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 core-side framebuffer service that sends framebuffer updates
+ * to the UI connected to the core.
+ */
+
+#ifndef _ANDROID_FRAMEBUFFER_CORE_H
+#define _ANDROID_FRAMEBUFFER_CORE_H
+
+/* Descriptor for a framebuffer core service instance */
+typedef struct CoreFramebuffer CoreFramebuffer;
+
+/*
+ * Creates framebuffer service.
+ * Param:
+ * sock - Socket descriptor for the service
+ * protocol - Defines protocol to use when sending FB updates to the UI. The
+ * supported values ar:
+ * -raw Transfers the updating rectangle buffer over the socket.
+ * -shared Used a shared memory to transfer the updating rectangle buffer.
+ * Return:
+ * Framebuffer service descriptor.
+ */
+CoreFramebuffer* corefb_create(int sock, const char* protocol);
+
+/*
+ * Destroys framebuffer service created with corefb_create.
+ * Param:
+ * core_fb - Framebuffer service descriptor created with corefb_create
+ */
+void corefb_destroy(CoreFramebuffer* core_fb);
+
+/*
+ * Notifies framebuffer client about changes in framebuffer.
+ * Param:
+ * core_fb - Framebuffer service descriptor created with corefb_create
+ * ds - Display state for the framebuffer.
+ * fb Framebuffer containing pixels.
+ * x, y, w, and h identify the rectangle that has benn changed.
+ */
+void corefb_update(CoreFramebuffer* core_fb, struct DisplayState* ds,
+ struct QFrameBuffer* fb, int x, int y, int w, int h);
+
+#endif /* _ANDROID_FRAMEBUFFER_CORE_H */
diff --git a/android/framebuffer-ui.c b/android/framebuffer-ui.c
new file mode 100644
index 0000000..0402df0
--- /dev/null
+++ b/android/framebuffer-ui.c
@@ -0,0 +1,223 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/*
+ * Contains UI-side framebuffer client that receives framebuffer updates
+ * from the core.
+ */
+
+#include "android/framebuffer-common.h"
+#include "android/framebuffer-ui.h"
+#include "android/utils/system.h"
+#include "android/utils/debug.h"
+
+#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); \
+ exit(1); \
+ } while (0)
+
+/*
+ * Enumerates states for the client framebuffer update reader.
+ */
+typedef enum ClientFBState {
+ /* The reader is waiting on update header. */
+ WAIT_HEADER,
+
+ /* The reader is waiting on pixels. */
+ WAIT_PIXELS,
+} ClientFBState;
+
+/*
+ * Descriptor for the framebuffer client.
+ */
+struct ClientFramebuffer {
+ /* Core connection instance for the framebuffer client. */
+ CoreConnection* core_connection;
+
+ /* Current update header. */
+ FBUpdateMessage update_header;
+
+ /* Reader's buffer. */
+ uint8_t* reader_buffer;
+
+ /* Offset in the reader's buffer where to read next chunk of data. */
+ size_t reader_offset;
+
+ /* Total number of bytes the reader expects to read. */
+ size_t reader_bytes;
+
+ /* Current state of the update reader. */
+ ClientFBState fb_state;
+
+ /* Socket descriptor for the framebuffer client. */
+ int sock;
+};
+
+/* The only instance of framebuffer client. */
+static ClientFramebuffer _client_fb;
+
+/*
+ * Updates a desplay rectangle.
+ * Param
+ * x, y, w, and h define rectangle to update.
+ * bits_per_pixel define number of bits used to encode a single pixel.
+ * pixels contains pixels for the rectangle. Buffer addressed by this parameter
+ * must be eventually freed with free()
+ */
+void
+update_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
+ uint8_t bits_per_pixel, uint8_t* pixels)
+{
+ // TODO: Do the actual update!
+ printf("Update rectangle (%d bytes): %d:%d %d:%d\n",
+ w * h * (bits_per_pixel / 8), x, y, w, h);
+ free(pixels);
+}
+
+/*
+ * Asynchronous I/O callback launched when framebuffer notifications are ready
+ * to be read.
+ * Param:
+ * opaque - ClientFramebuffer instance.
+ */
+static void
+_clientfb_read_cb(void* opaque)
+{
+ ClientFramebuffer* fb_client = opaque;
+ int ret;
+
+ // Read updates while they are immediately available.
+ for (;;) {
+ // Read next chunk of data.
+ ret = read(fb_client->sock, fb_client->reader_buffer + fb_client->reader_offset,
+ fb_client->reader_bytes - fb_client->reader_offset);
+ if (ret == 0) {
+ /* disconnection ! */
+ clientfb_destroy(fb_client);
+ return;
+ }
+ if (ret < 0) {
+ if (errno == EINTR) {
+ /* loop on EINTR */
+ continue;
+ } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ // Chunk is not avalable at this point. Come back later.
+ return;
+ }
+ }
+
+ fb_client->reader_offset += ret;
+ if (fb_client->reader_offset != fb_client->reader_bytes) {
+ // There are still some data left in the pipe.
+ continue;
+ }
+
+ // All expected data has been read. Time to change the state.
+ if (fb_client->fb_state == WAIT_HEADER) {
+ // Update header has been read. Prepare for the pixels.
+ fb_client->fb_state = WAIT_PIXELS;
+ fb_client->reader_offset = 0;
+ fb_client->reader_bytes = fb_client->update_header.w *
+ fb_client->update_header.h *
+ (fb_client->update_header.bits_per_pixel / 8);
+ fb_client->reader_buffer = malloc(fb_client->reader_bytes);
+ if (fb_client->reader_buffer == NULL) {
+ PANIC("Unable to allocate memory for framebuffer update\n");
+ }
+ } else {
+ // Pixels have been read. Prepare for the header.
+ uint8_t* pixels = fb_client->reader_buffer;
+
+ fb_client->fb_state = WAIT_HEADER;
+ fb_client->reader_offset = 0;
+ fb_client->reader_bytes = sizeof(FBUpdateMessage);
+ fb_client->reader_buffer = (uint8_t*)&fb_client->update_header;
+
+ // Perform the update. Note that pixels buffer must be freed there.
+ update_rect(fb_client->update_header.x, fb_client->update_header.y,
+ fb_client->update_header.w, fb_client->update_header.h,
+ fb_client->update_header.bits_per_pixel, pixels);
+ }
+ }
+}
+
+ClientFramebuffer*
+clientfb_create(SockAddress* console_socket, const char* protocol)
+{
+ char* connect_message = NULL;
+ char switch_cmd[256];
+
+ // Connect to the framebuffer service.
+ _client_fb.core_connection = core_connection_create(console_socket);
+ if (_client_fb.core_connection == NULL) {
+ derror("Framebuffer client is unable to connect to the console: %s\n",
+ errno_str);
+ return NULL;
+ }
+ if (core_connection_open(_client_fb.core_connection)) {
+ core_connection_free(_client_fb.core_connection);
+ _client_fb.core_connection = NULL;
+ derror("Framebuffer client is unable to ioen the console: %s\n",
+ errno_str);
+ return NULL;
+ }
+ snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol);
+ if (core_connection_switch_stream(_client_fb.core_connection, switch_cmd,
+ &connect_message)) {
+ derror("Unable to attach to the framebuffer %s: %s\n",
+ switch_cmd, connect_message ? connect_message : "");
+ if (connect_message != NULL) {
+ free(connect_message);
+ }
+ core_connection_close(_client_fb.core_connection);
+ core_connection_free(_client_fb.core_connection);
+ _client_fb.core_connection = NULL;
+ return NULL;
+ }
+ if (connect_message != NULL) {
+ free(connect_message);
+ }
+
+ // Now that we're connected lets initialize the descriptor.
+ _client_fb.sock = core_connection_get_socket(_client_fb.core_connection);
+ _client_fb.fb_state = WAIT_HEADER;
+ _client_fb.reader_buffer = (uint8_t*)&_client_fb.update_header;
+ _client_fb.reader_offset = 0;
+ _client_fb.reader_bytes = sizeof(FBUpdateMessage);
+
+ // At last setup read callback, and start receiving the updates.
+ if (qemu_set_fd_handler(_client_fb.sock, _clientfb_read_cb, NULL, &_client_fb)) {
+ derror("Unable to set up framebuffer read callback\n");
+ core_connection_close(_client_fb.core_connection);
+ core_connection_free(_client_fb.core_connection);
+ _client_fb.core_connection = NULL;
+ return NULL;
+ }
+
+ fprintf(stdout, "Framebuffer %s is now attached to the core %s\n",
+ protocol, sock_address_to_string(console_socket));
+
+ return &_client_fb;
+}
+
+void
+clientfb_destroy(ClientFramebuffer* client_fb)
+{
+ if (client_fb != NULL && client_fb->core_connection != NULL) {
+ // Disable the reader callback.
+ qemu_set_fd_handler(client_fb->sock, NULL, NULL, NULL);
+
+ // Close framebuffer connection.
+ core_connection_close(client_fb->core_connection);
+ core_connection_free(client_fb->core_connection);
+ client_fb->core_connection = NULL;
+ }
+}
diff --git a/android/framebuffer-ui.h b/android/framebuffer-ui.h
new file mode 100644
index 0000000..188a3c1
--- /dev/null
+++ b/android/framebuffer-ui.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/*
+ * Contains UI-side framebuffer client that receives framebuffer updates
+ * from the core.
+ */
+
+#ifndef _ANDROID_FRAMEBUFFER_UI_H
+#define _ANDROID_FRAMEBUFFER_UI_H
+
+#include "console.h"
+#include "android/looper.h"
+#include "android/async-utils.h"
+#include "android/core-connection.h"
+
+/* Descriptor for the framebuffer client. */
+typedef struct ClientFramebuffer ClientFramebuffer;
+
+/*
+ * Creates framebuffer client, and connects it with the core.
+ * Param:
+ * console_socket Address of the core's console socket.
+ * protocol Protocol to use for the updates:
+ * -raw Stream pixels over socket
+ * -shared Use shared memory for pixels.
+ * Return:
+ * Descriptor for the framebuffer client on success, or NULL on failure.
+ */
+ClientFramebuffer* clientfb_create(SockAddress* console_socket,
+ const char* protocol);
+
+/*
+ * Disconnects and destroys framebuffer client.
+ * Param:
+ * client_fb Framebuffer client descriptor created with clientfb_create.
+ */
+void clientfb_destroy(ClientFramebuffer* client_fb);
+
+#endif /* _ANDROID_FRAMEBUFFER_UI_H */
diff --git a/android/looper-qemu.c b/android/looper-qemu.c
index 400f7c1..cce0bfa 100644
--- a/android/looper-qemu.c
+++ b/android/looper-qemu.c
@@ -199,13 +199,15 @@ qloopio_modify(QLoopIo* io, unsigned wanted)
/* if we're pending, but the new mask doesn't care about
* out state, remove from pending list */
- if (io->ready && (io->ready & wanted) == 0)
+ if (io->ready && (io->ready & wanted) == 0) {
qloopio_removePending(io);
+ }
/* recompute read/write handlers for QEMU */
IOHandler* fd_read = (wanted & LOOP_IO_READ) ? qloopio_handleRead : NULL;
IOHandler* fd_write = (wanted & LOOP_IO_WRITE) ? qloopio_handleWrite : NULL;
qemu_set_fd_handler(io->fd, fd_read, fd_write, io);
+ io->wanted = wanted;
}
static void
@@ -312,7 +314,7 @@ qlooper_addPendingIo(QLooper* looper, QLoopIo* io)
qemu_bh_schedule(looper->io_bh);
}
io->pendingNext = looper->io_pending;
- looper->io_pending = io->pendingNext;
+ looper->io_pending = io;
}
static void
diff --git a/android/main-ui.c b/android/main-ui.c
index 5f3b8e9..043a9a8 100644
--- a/android/main-ui.c
+++ b/android/main-ui.c
@@ -61,6 +61,7 @@
#include "android/snapshot.h"
#include "android/core-connection.h"
+#include "android/framebuffer-ui.h"
#include "framebuffer.h"
#include "iolooper.h"
@@ -103,6 +104,9 @@ unsigned long android_verbose;
/* Instance of the "attach UI" Emulator's core console client. */
CoreConnection* attach_client = NULL;
+/* Instance of the "framebuffer" console client. */
+ClientFramebuffer* fb_client = NULL;
+
/* -ui-settings parameters received from the core on UI attachment. */
char* core_ui_settings = "";
@@ -208,7 +212,7 @@ sdl_set_window_icon( void )
SDL_FreeSurface(icon);
free( icon_pixels );
}
-#endif /* !_WIN32 */
+#endif /* !_WIN32 */
}
}
@@ -921,7 +925,6 @@ attach_to_core(AndroidOptions* opts) {
fprintf(stdout, "UI setting for the core%s:\n",
core_ui_settings);
}
- return 0;
} else {
derror("Unable to attach to the core %s: %s\n",
sock_address_to_string(&console_socket),
@@ -939,6 +942,13 @@ attach_to_core(AndroidOptions* opts) {
} else {
return -1;
}
+
+ fb_client = clientfb_create(&console_socket, "-raw");
+ if (fb_client == NULL) {
+ return -1;
+ }
+
+ return 0;
}
int main(int argc, char **argv)
diff --git a/android/sync-utils.c b/android/sync-utils.c
index 8d55823..c5674b2 100644
--- a/android/sync-utils.c
+++ b/android/sync-utils.c
@@ -271,3 +271,9 @@ syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout
return syncsocket_read_line_absolute(ssocket, buffer, size,
iolooper_now() + timeout);
}
+
+int
+syncsocket_get_socket(SyncSocket* ssocket)
+{
+ return (ssocket != NULL) ? ssocket->fd : -1;
+}
diff --git a/android/sync-utils.h b/android/sync-utils.h
index f522e27..726b310 100644
--- a/android/sync-utils.h
+++ b/android/sync-utils.h
@@ -205,4 +205,12 @@ ssize_t syncsocket_read_line(SyncSocket* ssocket,
size_t size,
int timeout);
+/* Gets socket descriptor associated with the sync socket.
+ * Param:
+ * ssocket - SyncSocket descriptor obtained from syncsocket_connect routine.
+ * Return
+ * Socket descriptor associated with the sync socket.
+ */
+int syncsocket_get_socket(SyncSocket* ssocket);
+
#endif // ANDROID_SYNC_UTILS_H