• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*
_pixel_offset(const DisplaySurface * dsu,int x,int y)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
_copy_fb_rect(uint8_t * rect,const DisplaySurface * dsu,int x,int y,int w,int h)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*
fbupdatenotify_create(ProxyFramebuffer * proxy_fb,int x,int y,int w,int h)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
fbupdatenotify_delete(FBUpdateNotify * desc)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
_proxyFb_io_write(ProxyFramebuffer * proxy_fb)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
_proxyFb_io_read(ProxyFramebuffer * proxy_fb)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
_proxyFb_io_fun(void * opaque,int fd,unsigned events)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*
proxyFb_create(int sock,const char * protocol)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
proxyFb_destroy(ProxyFramebuffer * proxy_fb)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
proxyFb_update(void * opaque,int x,int y,int w,int h)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
proxyFb_get_bits_per_pixel(ProxyFramebuffer * proxy_fb)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