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
_update_rect(QFrameBuffer * fb,uint16_t x,uint16_t y,uint16_t w,uint16_t h,uint8_t bits_per_pixel,uint8_t * pixels)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
_fbUpdatesImpl_io_callback(void * opaque,int fd,unsigned events)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
fbUpdatesImpl_create(SockAddress * console_socket,const char * protocol,QFrameBuffer * fb,Looper * looper)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
fbUpdatesImpl_destroy(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