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. */
27typedef 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 */
37typedef 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. */
70static 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 */
81static 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 */
107static 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
169int
170fbUpdatesImpl_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
250void
251fbUpdatesImpl_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