Force core to send entire framebuffer on UI attachment

Change-Id: I2feb813314163b94781ffe765eb23527b6c4a0f1
diff --git a/android/display-core.c b/android/display-core.c
index 0b2a869..27b0706 100644
--- a/android/display-core.c
+++ b/android/display-core.c
@@ -43,7 +43,7 @@
 {
     CoreDisplay* cd = (CoreDisplay*)opaque;
     if (cd->core_fb) {
-        corefb_update(cd->core_fb, cd->ds, cd->fb, x, y, w, h);
+        corefb_update(cd->core_fb, cd->fb, x, y, w, h);
     }
 }
 
diff --git a/android/framebuffer-common.h b/android/framebuffer-common.h
index 95f65b6..da773b7 100644
--- a/android/framebuffer-common.h
+++ b/android/framebuffer-common.h
@@ -31,4 +31,15 @@
     uint8_t rect[0];
 } FBUpdateMessage;
 
+/* Requests the service to refresh framebuffer. */
+#define AFB_REQUEST_REFRESH     1
+
+/* Header for framebuffer requests sent from the client (UI)
+ * to the service (core).
+ */
+typedef struct FBRequestHeader {
+    /* Request type. See AFB_REQUEST_XXX for the values. */
+    uint8_t request_type;
+} FBRequestHeader;
+
 #endif /* _ANDROID_FRAMEBUFFER_UI_H */
diff --git a/android/framebuffer-core.c b/android/framebuffer-core.c
index 3eb7665..89b7b46 100644
--- a/android/framebuffer-core.c
+++ b/android/framebuffer-core.c
@@ -30,6 +30,9 @@
     /* Writer used to send FB update notification messages. */
     AsyncWriter             fb_update_writer;
 
+    /* Reader used to read FB requests from the client. */
+    AsyncReader             fb_req_reader;
+
     /* I/O associated with this descriptor. */
     LoopIo                  io;
 
@@ -47,6 +50,9 @@
 
     /* Socket used to communicate framebuffer updates. */
     int     sock;
+
+    /* Framebuffer request header. */
+    FBRequestHeader         fb_req_header;
 };
 
 /* Framebuffer update notification descriptor to the core. */
@@ -140,25 +146,14 @@
 extern void destroy_control_fb_client(void);
 
 /*
- * Asynchronous I/O callback launched when writing framebuffer notifications
- * to the socket.
+ * Asynchronous write I/O callback launched when writing framebuffer
+ * notifications to the socket.
  * Param:
- *  opaque - CoreFramebuffer instance.
+ *  core_fb - CoreFramebuffer instance.
  */
 static void
-corefb_io_func(void* opaque, int fd, unsigned events)
+corefb_io_write(CoreFramebuffer* core_fb)
 {
-    CoreFramebuffer* core_fb = opaque;
-
-    if (events & LOOP_IO_READ) {
-        // We don't expect the UI client to write anything here, except when
-        // the client gets disconnected.
-        loopIo_dontWantWrite(&core_fb->io);
-        loopIo_dontWantRead(&core_fb->io);
-        destroy_control_fb_client();
-        return;
-    }
-
     while (core_fb->fb_update_head != NULL) {
         FBUpdateNotify* current_update = core_fb->fb_update_head;
         // Lets continue writing of the current notification.
@@ -195,6 +190,66 @@
     }
 }
 
+/*
+ * Asynchronous read I/O callback launched when reading framebuffer requests
+ * from the socket.
+ * Param:
+ *  core_fb - CoreFramebuffer instance.
+ */
+static void
+corefb_io_read(CoreFramebuffer* core_fb)
+{
+    // Read the request header.
+    const AsyncStatus status =
+        asyncReader_read(&core_fb->fb_req_reader, &core_fb->io);
+    switch (status) {
+        case ASYNC_COMPLETE:
+            // Request header is received
+            switch (core_fb->fb_req_header.request_type) {
+                case AFB_REQUEST_REFRESH:
+                    // Force full screen update to be sent
+                    corefb_update(core_fb, core_fb->fb,
+                                  0, 0, core_fb->fb->width, core_fb->fb->height);
+                    break;
+                default:
+                    derror("Unknown framebuffer request %d\n",
+                           core_fb->fb_req_header.request_type);
+                    break;
+            }
+            core_fb->fb_req_header.request_type = -1;
+            asyncReader_init(&core_fb->fb_req_reader, &core_fb->fb_req_header,
+                             sizeof(core_fb->fb_req_header), &core_fb->io);
+            break;
+        case ASYNC_ERROR:
+            loopIo_dontWantRead(&core_fb->io);
+            if (errno == ECONNRESET) {
+                // UI has exited. We need to destroy framebuffer service.
+                destroy_control_fb_client();
+            }
+            break;
+
+        case ASYNC_NEED_MORE:
+            // Transfer will eventually come back into this routine.
+            return;
+    }
+}
+
+/*
+ * 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)
+{
+    if (events & LOOP_IO_READ) {
+        corefb_io_read((CoreFramebuffer*)opaque);
+    } else if (events & LOOP_IO_WRITE) {
+        corefb_io_write((CoreFramebuffer*)opaque);
+    }
+}
+
 CoreFramebuffer*
 corefb_create(int sock, const char* protocol, QFrameBuffer* fb)
 {
@@ -203,13 +258,12 @@
     ANEW0(ret);
     ret->sock = sock;
     ret->looper = looper_newCore();
-    loopIo_init(&ret->io, ret->looper, sock, corefb_io_func, ret);
-    // Since we're overriding the read callback with our looper's I/O routine,
-    // we need to have set our read callback here to monitor disconnections.
-    loopIo_wantRead(&ret->io);
     ret->fb = fb;
     ret->fb_update_head = NULL;
     ret->fb_update_tail = NULL;
+    loopIo_init(&ret->io, ret->looper, sock, corefb_io_func, ret);
+    asyncReader_init(&ret->fb_req_reader, &ret->fb_req_header,
+                     sizeof(ret->fb_req_header), &ret->io);
     return ret;
 }
 
@@ -234,7 +288,7 @@
 }
 
 void
-corefb_update(CoreFramebuffer* core_fb, struct DisplayState* ds,
+corefb_update(CoreFramebuffer* core_fb,
               struct QFrameBuffer* fb, int x, int y, int w, int h)
 {
     AsyncStatus status;
diff --git a/android/framebuffer-core.h b/android/framebuffer-core.h
index fd4af52..773c248 100644
--- a/android/framebuffer-core.h
+++ b/android/framebuffer-core.h
@@ -46,12 +46,11 @@
  * 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);
+void corefb_update(CoreFramebuffer* core_fb, struct QFrameBuffer* fb,
+                   int x, int y, int w, int h);
 
 /*
  * Gets number of bits used to encode a single pixel.
diff --git a/android/framebuffer-ui.c b/android/framebuffer-ui.c
index 5202381..0ae109f 100644
--- a/android/framebuffer-ui.c
+++ b/android/framebuffer-ui.c
@@ -19,6 +19,7 @@
 #include "android/framebuffer-ui.h"
 #include "android/utils/system.h"
 #include "android/utils/debug.h"
+#include "android/sync-utils.h"
 
 #define  PANIC(...) do { fprintf(stderr, __VA_ARGS__);  \
                          exit(1);                       \
@@ -247,7 +248,18 @@
         _client_fb.core_connection = NULL;
         return NULL;
     }
+    {
+        // Force the core to send us entire framebuffer now, when we're prepared
+        // to receive it.
+        FBRequestHeader hd;
+        SyncSocket* sk = syncsocket_init(_client_fb.sock);
 
+        hd.request_type = AFB_REQUEST_REFRESH;
+        syncsocket_start_write(sk);
+        syncsocket_write(sk, &hd, sizeof(hd), 500);
+        syncsocket_stop_write(sk);
+        syncsocket_free(sk);
+    }
     fprintf(stdout, "Framebuffer %s is now attached to the core %s\n",
             protocol, sock_address_to_string(console_socket));
 
diff --git a/android/sync-utils.c b/android/sync-utils.c
index 32c803c..6d3cea6 100644
--- a/android/sync-utils.c
+++ b/android/sync-utils.c
@@ -113,7 +113,6 @@
 syncsocket_free(SyncSocket* ssocket)
 {
     if (ssocket != NULL) {
-        syncsocket_close(ssocket);
         if (ssocket->iolooper != NULL) {
             iolooper_free(ssocket->iolooper);
         }
diff --git a/android/sync-utils.h b/android/sync-utils.h
index 110a143..1dcf649 100644
--- a/android/sync-utils.h
+++ b/android/sync-utils.h
@@ -43,7 +43,7 @@
  * Note: this routine will explicitly call socket_set_nonblock on the fd passed
  * to this routine.
  * Param:
- *  fd - File descriptor for the already connected.
+ *  fd - File descriptor for the already connected socket.
  * Return:
  *  Initialized SyncSocket descriptor on success, or NULL on failure.
  */