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 UI-side framebuffer client that receives framebuffer updates
     15  * from the core.
     16  */
     17 
     18 #include "android/utils/system.h"
     19 #include "android/utils/debug.h"
     20 #include "android/utils/panic.h"
     21 #include "android/sync-utils.h"
     22 #include "android/protocol/core-connection.h"
     23 #include "android/protocol/fb-updates.h"
     24 #include "android/protocol/fb-updates-impl.h"
     25 
     26 /*Enumerates states for the client framebuffer update reader. */
     27 typedef enum FbImplState {
     28     /* The reader is waiting on update header. */
     29     EXPECTS_HEADER,
     30 
     31     /* The reader is waiting on pixels. */
     32     EXPECTS_PIXELS,
     33 } FbImplState;
     34 
     35 /* Descriptor for the UI-side implementation of the "framebufer" service.
     36  */
     37 typedef struct FrameBufferImpl {
     38     /* Framebuffer for this client. */
     39     QFrameBuffer*   fb;
     40 
     41     /* Core connection instance for the framebuffer client. */
     42     CoreConnection* core_connection;
     43 
     44     /* Current update header. */
     45     FBUpdateMessage update_header;
     46 
     47     /* Reader's buffer. */
     48     uint8_t*        reader_buffer;
     49 
     50     /* Offset in the reader's buffer where to read next chunk of data. */
     51     size_t          reader_offset;
     52 
     53     /* Total number of bytes the reader expects to read. */
     54     size_t          reader_bytes;
     55 
     56     /* Current state of the update reader. */
     57     FbImplState     fb_state;
     58 
     59     /* Socket descriptor for the framebuffer client. */
     60     int             sock;
     61 
     62     /* Custom i/o handler */
     63     LoopIo          io[1];
     64 
     65     /* Number of bits used to encode single pixel. */
     66     int             bits_per_pixel;
     67 } FrameBufferImpl;
     68 
     69 /* One and the only FrameBufferImpl instance. */
     70 static FrameBufferImpl _fbImpl;
     71 
     72 /*
     73  * Updates a display rectangle.
     74  * Param
     75  *  fb - Framebuffer where to update the rectangle.
     76  *  x, y, w, and h define rectangle to update.
     77  *  bits_per_pixel define number of bits used to encode a single pixel.
     78  *  pixels contains pixels for the rectangle. Buffer addressed by this parameter
     79  *      must be eventually freed with free()
     80  */
     81 static void
     82 _update_rect(QFrameBuffer* fb, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
     83              uint8_t bits_per_pixel, uint8_t* pixels)
     84 {
     85     if (fb != NULL) {
     86         uint16_t n;
     87         const uint8_t* src = pixels;
     88         const uint16_t src_line_size = w * ((bits_per_pixel + 7) / 8);
     89         uint8_t* dst  = (uint8_t*)fb->pixels + y * fb->pitch + x *
     90                         fb->bytes_per_pixel;
     91         for (n = 0; n < h; n++) {
     92             memcpy(dst, src, src_line_size);
     93             src += src_line_size;
     94             dst += fb->pitch;
     95         }
     96         qframebuffer_update(fb, x, y, w, h);
     97     }
     98     free(pixels);
     99 }
    100 
    101 /*
    102  * Asynchronous I/O callback launched when framebuffer notifications are ready
    103  * to be read.
    104  * Param:
    105  *  opaque - FrameBufferImpl instance.
    106  */
    107 static void
    108 _fbUpdatesImpl_io_callback(void* opaque, int fd, unsigned events)
    109 {
    110     FrameBufferImpl* fbi = opaque;
    111     int  ret;
    112 
    113     // Read updates while they are immediately available.
    114     for (;;) {
    115         // Read next chunk of data.
    116         ret = socket_recv(fbi->sock, fbi->reader_buffer + fbi->reader_offset,
    117                           fbi->reader_bytes - fbi->reader_offset);
    118         if (ret == 0) {
    119             /* disconnection ! */
    120             fbUpdatesImpl_destroy();
    121             return;
    122         }
    123         if (ret < 0) {
    124             if (errno == EINTR) {
    125                 /* loop on EINTR */
    126                 continue;
    127             } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
    128                 // Chunk is not avalable at this point. Come back later.
    129                 return;
    130             }
    131         }
    132 
    133         fbi->reader_offset += ret;
    134         if (fbi->reader_offset != fbi->reader_bytes) {
    135             // There are still some data left in the pipe.
    136             continue;
    137         }
    138 
    139         // All expected data has been read. Time to change the state.
    140         if (fbi->fb_state == EXPECTS_HEADER) {
    141             // Update header has been read. Prepare for the pixels.
    142             fbi->fb_state = EXPECTS_PIXELS;
    143             fbi->reader_offset = 0;
    144             fbi->reader_bytes = fbi->update_header.w *
    145                                       fbi->update_header.h *
    146                                       (fbi->bits_per_pixel / 8);
    147             fbi->reader_buffer = malloc(fbi->reader_bytes);
    148             if (fbi->reader_buffer == NULL) {
    149                 APANIC("Unable to allocate memory for framebuffer update\n");
    150             }
    151         } else {
    152             // Pixels have been read. Prepare for the header.
    153              uint8_t* pixels = fbi->reader_buffer;
    154 
    155             fbi->fb_state = EXPECTS_HEADER;
    156             fbi->reader_offset = 0;
    157             fbi->reader_bytes = sizeof(FBUpdateMessage);
    158             fbi->reader_buffer = (uint8_t*)&fbi->update_header;
    159 
    160             // Perform the update. Note that pixels buffer must be freed there.
    161             _update_rect(fbi->fb, fbi->update_header.x,
    162                         fbi->update_header.y, fbi->update_header.w,
    163                         fbi->update_header.h, fbi->bits_per_pixel,
    164                         pixels);
    165         }
    166     }
    167 }
    168 
    169 int
    170 fbUpdatesImpl_create(SockAddress* console_socket,
    171               const char* protocol,
    172               QFrameBuffer* fb,
    173               Looper* looper)
    174 {
    175     FrameBufferImpl* fbi = &_fbImpl;
    176     char* handshake = NULL;
    177     char switch_cmd[256];
    178 
    179     // Initialize descriptor.
    180     fbi->fb = fb;
    181     fbi->reader_buffer = (uint8_t*)&fbi->update_header;
    182     fbi->reader_offset = 0;
    183     fbi->reader_bytes = sizeof(FBUpdateMessage);
    184 
    185     // Connect to the framebuffer service.
    186     snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol);
    187     fbi->core_connection =
    188         core_connection_create_and_switch(console_socket, switch_cmd, &handshake);
    189     if (fbi->core_connection == NULL) {
    190         derror("Unable to connect to the framebuffer service: %s\n",
    191                errno_str);
    192         return -1;
    193     }
    194 
    195     // We expect core framebuffer to return us bits per pixel property in
    196     // the handshake message.
    197     fbi->bits_per_pixel = 0;
    198     if (handshake != NULL) {
    199         char* bpp = strstr(handshake, "bitsperpixel=");
    200         if (bpp != NULL) {
    201             char* end;
    202             bpp += strlen("bitsperpixel=");
    203             end = strchr(bpp, ' ');
    204             if (end == NULL) {
    205                 end = bpp + strlen(bpp);
    206             }
    207             fbi->bits_per_pixel = strtol(bpp, &end, 0);
    208         }
    209     }
    210     if (!fbi->bits_per_pixel) {
    211         derror("Unexpected core framebuffer reply: %s\n"
    212                "Bits per pixel property is not there, or is invalid\n",
    213                handshake);
    214         fbUpdatesImpl_destroy();
    215         return -1;
    216     }
    217 
    218     fbi->sock = core_connection_get_socket(fbi->core_connection);
    219 
    220     // At last setup read callback, and start receiving the updates.
    221     loopIo_init(fbi->io, looper, fbi->sock,
    222                 _fbUpdatesImpl_io_callback, &_fbImpl);
    223     loopIo_wantRead(fbi->io);
    224     {
    225         // Force the core to send us entire framebuffer now, when we're prepared
    226         // to receive it.
    227         FBRequestHeader hd;
    228         SyncSocket* sk = syncsocket_init(fbi->sock);
    229 
    230         hd.request_type = AFB_REQUEST_REFRESH;
    231         syncsocket_start_write(sk);
    232         syncsocket_write(sk, &hd, sizeof(hd), 5000);
    233         syncsocket_stop_write(sk);
    234         syncsocket_free(sk);
    235     }
    236 
    237     fprintf(stdout, "framebuffer is now connected to the core at %s.",
    238             sock_address_to_string(console_socket));
    239     if (handshake != NULL) {
    240         if (handshake[0] != '\0') {
    241             fprintf(stdout, " Handshake: %s", handshake);
    242         }
    243         free(handshake);
    244     }
    245     fprintf(stdout, "\n");
    246 
    247     return 0;
    248 }
    249 
    250 void
    251 fbUpdatesImpl_destroy(void)
    252 {
    253     FrameBufferImpl* fbi = &_fbImpl;
    254 
    255     if (fbi->core_connection != NULL) {
    256         // Disable the reader callback.
    257         loopIo_done(fbi->io);
    258 
    259         // Close framebuffer connection.
    260         core_connection_close(fbi->core_connection);
    261         core_connection_free(fbi->core_connection);
    262         fbi->core_connection = NULL;
    263     }
    264 
    265     fbi->fb = NULL;
    266     if (fbi->reader_buffer != NULL &&
    267         fbi->reader_buffer != (uint8_t*)&fbi->update_header) {
    268         free(fbi->reader_buffer);
    269         fbi->reader_buffer = (uint8_t*)&fbi->update_header;
    270     }
    271 }
    272