Home | History | Annotate | Download | only in protocol
      1 /* Copyright (C) 2010 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 
     13 /*
     14  * Contains core-side framebuffer service that sends framebuffer updates
     15  * to the UI connected to the core.
     16  */
     17 
     18 #include "console.h"
     19 #include "android/looper.h"
     20 #include "android/display-core.h"
     21 #include "android/async-utils.h"
     22 #include "android/protocol/fb-updates.h"
     23 #include "android/protocol/fb-updates-proxy.h"
     24 #include "android/utils/system.h"
     25 #include "android/utils/debug.h"
     26 
     27 /* Descriptor for the Core-side implementation of the "framebufer" service.
     28  */
     29 struct ProxyFramebuffer {
     30     /* Writer used to send FB update notification messages. */
     31     AsyncWriter             fb_update_writer;
     32 
     33     /* Reader used to read FB requests from the client. */
     34     AsyncReader             fb_req_reader;
     35 
     36     /* I/O associated with this descriptor. */
     37     LoopIo                  io;
     38 
     39     /* Display state used for this service */
     40     DisplayState*           ds;
     41     DisplayUpdateListener*  ds_listener;
     42 
     43     /* Looper used to communicate framebuffer updates. */
     44     Looper* looper;
     45 
     46     /* Head of the list of pending FB update notifications. */
     47     struct FBUpdateNotify*  fb_update_head;
     48 
     49     /* Tail of the list of pending FB update notifications. */
     50     struct FBUpdateNotify*  fb_update_tail;
     51 
     52     /* Socket used to communicate framebuffer updates. */
     53     int     sock;
     54 
     55     /* Framebuffer request header. */
     56     FBRequestHeader         fb_req_header;
     57 };
     58 
     59 /* Framebuffer update notification descriptor. */
     60 typedef struct FBUpdateNotify {
     61     /* Links all pending FB update notifications. */
     62     struct FBUpdateNotify*  next_fb_update;
     63 
     64     /* Core framebuffer instance that owns the message. */
     65     ProxyFramebuffer*       proxy_fb;
     66 
     67     /* Size of the message to transfer. */
     68     size_t                  message_size;
     69 
     70     /* Update message. */
     71     FBUpdateMessage         message;
     72 } FBUpdateNotify;
     73 
     74 /*
     75  * Gets pointer in framebuffer's pixels for the given pixel.
     76  * Param:
     77  *  fb Framebuffer containing pixels.
     78  *  x, and y identify the pixel to get pointer for.
     79  * Return:
     80  *  Pointer in framebuffer's pixels for the given pixel.
     81  */
     82 static const uint8_t*
     83 _pixel_offset(const DisplaySurface* dsu, int x, int y)
     84 {
     85     return (const uint8_t*)dsu->data + y * dsu->linesize + x * dsu->pf.bytes_per_pixel;
     86 }
     87 
     88 /*
     89  * Copies pixels from a framebuffer rectangle.
     90  * Param:
     91  *  rect - Buffer where to copy pixel.
     92  *  fb - Framebuffer containing the rectangle to copy.
     93  *  x, y, w, and h - dimensions of the rectangle to copy.
     94  */
     95 static void
     96 _copy_fb_rect(uint8_t* rect, const DisplaySurface* dsu, int x, int y, int w, int h)
     97 {
     98     const uint8_t* start = _pixel_offset(dsu, x, y);
     99     for (; h > 0; h--) {
    100         memcpy(rect, start, w * dsu->pf.bytes_per_pixel);
    101         start += dsu->linesize;
    102         rect += w * dsu->pf.bytes_per_pixel;
    103     }
    104 }
    105 
    106 /*
    107  * Allocates and initializes framebuffer update notification descriptor.
    108  * Param:
    109  *  ds - Display state for the framebuffer.
    110  *  fb Framebuffer containing pixels.
    111  *  x, y, w, and h identify the rectangle that is being updated.
    112  * Return:
    113  *  Initialized framebuffer update notification descriptor.
    114  */
    115 static FBUpdateNotify*
    116 fbupdatenotify_create(ProxyFramebuffer* proxy_fb,
    117                       int x, int y, int w, int h)
    118 {
    119     const size_t rect_size = w * h * proxy_fb->ds->surface->pf.bytes_per_pixel;
    120     FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size);
    121 
    122     ret->next_fb_update = NULL;
    123     ret->proxy_fb = proxy_fb;
    124     ret->message_size = sizeof(FBUpdateMessage) + rect_size;
    125     ret->message.x = x;
    126     ret->message.y = y;
    127     ret->message.w = w;
    128     ret->message.h = h;
    129     _copy_fb_rect(ret->message.rect, proxy_fb->ds->surface, x, y, w, h);
    130     return ret;
    131 }
    132 
    133 /*
    134  * Deletes FBUpdateNotify descriptor, created with fbupdatenotify_create.
    135  * Param:
    136  *  desc - Descreptor to delete.
    137  */
    138 static void
    139 fbupdatenotify_delete(FBUpdateNotify* desc)
    140 {
    141     if (desc != NULL) {
    142         free(desc);
    143     }
    144 }
    145 
    146 /*
    147  * Asynchronous write I/O callback launched when writing framebuffer
    148  * notifications to the socket.
    149  * Param:
    150  *  proxy_fb - ProxyFramebuffer instance.
    151  */
    152 static void
    153 _proxyFb_io_write(ProxyFramebuffer* proxy_fb)
    154 {
    155     while (proxy_fb->fb_update_head != NULL) {
    156         FBUpdateNotify* current_update = proxy_fb->fb_update_head;
    157         // Lets continue writing of the current notification.
    158         const AsyncStatus status =
    159             asyncWriter_write(&proxy_fb->fb_update_writer);
    160         switch (status) {
    161             case ASYNC_COMPLETE:
    162                 // Done with the current update. Move on to the next one.
    163                 break;
    164             case ASYNC_ERROR:
    165                 // Done with the current update. Move on to the next one.
    166                 loopIo_dontWantWrite(&proxy_fb->io);
    167                 break;
    168 
    169             case ASYNC_NEED_MORE:
    170                 // Transfer will eventually come back into this routine.
    171                 return;
    172         }
    173 
    174         // Advance the list of updates
    175         proxy_fb->fb_update_head = current_update->next_fb_update;
    176         if (proxy_fb->fb_update_head == NULL) {
    177             proxy_fb->fb_update_tail = NULL;
    178         }
    179         fbupdatenotify_delete(current_update);
    180 
    181         if (proxy_fb->fb_update_head != NULL) {
    182             // Schedule the next one.
    183             asyncWriter_init(&proxy_fb->fb_update_writer,
    184                              &proxy_fb->fb_update_head->message,
    185                              proxy_fb->fb_update_head->message_size,
    186                              &proxy_fb->io);
    187         }
    188     }
    189 }
    190 
    191 static void proxyFb_update(void* opaque, int x, int y, int w, int h);
    192 
    193 /*
    194  * Asynchronous read I/O callback launched when reading framebuffer requests
    195  * from the socket.
    196  * Param:
    197  *  proxy_fb - ProxyFramebuffer instance.
    198  */
    199 static void
    200 _proxyFb_io_read(ProxyFramebuffer* proxy_fb)
    201 {
    202     // Read the request header.
    203     DisplaySurface* dsu;
    204     const AsyncStatus status =
    205         asyncReader_read(&proxy_fb->fb_req_reader);
    206     switch (status) {
    207         case ASYNC_COMPLETE:
    208             // Request header is received
    209             switch (proxy_fb->fb_req_header.request_type) {
    210                 case AFB_REQUEST_REFRESH:
    211                     // Force full screen update to be sent
    212                     dsu = proxy_fb->ds->surface;
    213                     proxyFb_update(proxy_fb,
    214                                   0, 0, dsu->width, dsu->height);
    215                     break;
    216                 default:
    217                     derror("Unknown framebuffer request %d\n",
    218                            proxy_fb->fb_req_header.request_type);
    219                     break;
    220             }
    221             proxy_fb->fb_req_header.request_type = -1;
    222             asyncReader_init(&proxy_fb->fb_req_reader, &proxy_fb->fb_req_header,
    223                              sizeof(proxy_fb->fb_req_header), &proxy_fb->io);
    224             break;
    225         case ASYNC_ERROR:
    226             loopIo_dontWantRead(&proxy_fb->io);
    227             if (errno == ECONNRESET) {
    228                 // UI has exited. We need to destroy framebuffer service.
    229                 proxyFb_destroy(proxy_fb);
    230             }
    231             break;
    232 
    233         case ASYNC_NEED_MORE:
    234             // Transfer will eventually come back into this routine.
    235             return;
    236     }
    237 }
    238 
    239 /*
    240  * Asynchronous I/O callback launched when writing framebuffer notifications
    241  * to the socket.
    242  * Param:
    243  *  opaque - ProxyFramebuffer instance.
    244  */
    245 static void
    246 _proxyFb_io_fun(void* opaque, int fd, unsigned events)
    247 {
    248     if (events & LOOP_IO_READ) {
    249         _proxyFb_io_read((ProxyFramebuffer*)opaque);
    250     } else if (events & LOOP_IO_WRITE) {
    251         _proxyFb_io_write((ProxyFramebuffer*)opaque);
    252     }
    253 }
    254 
    255 ProxyFramebuffer*
    256 proxyFb_create(int sock, const char* protocol)
    257 {
    258     // At this point we're implementing the -raw protocol only.
    259     ProxyFramebuffer* ret;
    260     DisplayState* ds = get_displaystate();
    261     DisplayUpdateListener* dul;
    262 
    263     ANEW0(ret);
    264     ret->sock = sock;
    265     ret->looper = looper_newCore();
    266     ret->ds = ds;
    267 
    268     ANEW0(dul);
    269     dul->opaque = ret;
    270     dul->dpy_update = proxyFb_update;
    271     register_displayupdatelistener(ds, dul);
    272     ret->ds_listener = dul;
    273 
    274     ret->fb_update_head = NULL;
    275     ret->fb_update_tail = NULL;
    276     loopIo_init(&ret->io, ret->looper, sock, _proxyFb_io_fun, ret);
    277     asyncReader_init(&ret->fb_req_reader, &ret->fb_req_header,
    278                      sizeof(ret->fb_req_header), &ret->io);
    279     return ret;
    280 }
    281 
    282 void
    283 proxyFb_destroy(ProxyFramebuffer* proxy_fb)
    284 {
    285     if (proxy_fb != NULL) {
    286         unregister_displayupdatelistener(proxy_fb->ds, proxy_fb->ds_listener);
    287         if (proxy_fb->looper != NULL) {
    288             // Stop all I/O that may still be going on.
    289             loopIo_done(&proxy_fb->io);
    290             // Delete all pending frame updates.
    291             while (proxy_fb->fb_update_head != NULL) {
    292                 FBUpdateNotify* pending_update = proxy_fb->fb_update_head;
    293                 proxy_fb->fb_update_head = pending_update->next_fb_update;
    294                 fbupdatenotify_delete(pending_update);
    295             }
    296             proxy_fb->fb_update_tail = NULL;
    297             looper_free(proxy_fb->looper);
    298             proxy_fb->looper = NULL;
    299         }
    300         AFREE(proxy_fb);
    301     }
    302 }
    303 
    304 static void
    305 proxyFb_update(void* opaque, int x, int y, int w, int h)
    306 {
    307     ProxyFramebuffer* proxy_fb = opaque;
    308     AsyncStatus status;
    309     FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, x, y, w, h);
    310 
    311     // Lets see if we should list it behind other pending updates.
    312     if (proxy_fb->fb_update_tail != NULL) {
    313         proxy_fb->fb_update_tail->next_fb_update = descr;
    314         proxy_fb->fb_update_tail = descr;
    315         return;
    316     }
    317 
    318     // We're first in the list. Just send it now.
    319     proxy_fb->fb_update_head = proxy_fb->fb_update_tail = descr;
    320     asyncWriter_init(&proxy_fb->fb_update_writer,
    321                      &proxy_fb->fb_update_head->message,
    322                      proxy_fb->fb_update_head->message_size, &proxy_fb->io);
    323     status = asyncWriter_write(&proxy_fb->fb_update_writer);
    324     switch (status) {
    325         case ASYNC_COMPLETE:
    326             fbupdatenotify_delete(descr);
    327             proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL;
    328             return;
    329         case ASYNC_ERROR:
    330             fbupdatenotify_delete(descr);
    331             proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL;
    332             return;
    333         case ASYNC_NEED_MORE:
    334             // Update transfer will eventually complete in _proxyFb_io_fun
    335             return;
    336     }
    337 }
    338 
    339 int
    340 proxyFb_get_bits_per_pixel(ProxyFramebuffer* proxy_fb)
    341 {
    342     if (proxy_fb == NULL || proxy_fb->ds == NULL)
    343         return -1;
    344 
    345     return proxy_fb->ds->surface->pf.bits_per_pixel;
    346 }
    347