blob: e36c4bfe18a63519ae3827807379f7854f7badd9 [file] [log] [blame]
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -08001/* 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
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080018#include "android/utils/system.h"
19#include "android/utils/debug.h"
David 'Digit' Turneraf81d742014-02-03 17:11:18 +010020#include "android/utils/eintr_wrapper.h"
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080021#include "android/utils/panic.h"
22#include "android/sync-utils.h"
David 'Digit' Turnere9931262011-02-02 14:05:23 +010023#include "android/protocol/core-connection.h"
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080024#include "android/protocol/fb-updates.h"
25#include "android/protocol/fb-updates-impl.h"
26
27/*Enumerates states for the client framebuffer update reader. */
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +010028typedef enum FbImplState {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080029 /* The reader is waiting on update header. */
30 EXPECTS_HEADER,
31
32 /* The reader is waiting on pixels. */
33 EXPECTS_PIXELS,
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +010034} FbImplState;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080035
36/* Descriptor for the UI-side implementation of the "framebufer" service.
37 */
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +010038typedef struct FrameBufferImpl {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080039 /* Framebuffer for this client. */
40 QFrameBuffer* fb;
41
42 /* Core connection instance for the framebuffer client. */
43 CoreConnection* core_connection;
44
45 /* Current update header. */
46 FBUpdateMessage update_header;
47
48 /* Reader's buffer. */
49 uint8_t* reader_buffer;
50
51 /* Offset in the reader's buffer where to read next chunk of data. */
52 size_t reader_offset;
53
54 /* Total number of bytes the reader expects to read. */
55 size_t reader_bytes;
56
57 /* Current state of the update reader. */
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +010058 FbImplState fb_state;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080059
60 /* Socket descriptor for the framebuffer client. */
61 int sock;
62
David 'Digit' Turnerb6c168b2011-02-02 21:39:10 +010063 /* Custom i/o handler */
64 LoopIo io[1];
65
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080066 /* Number of bits used to encode single pixel. */
67 int bits_per_pixel;
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +010068} FrameBufferImpl;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080069
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +010070/* One and the only FrameBufferImpl instance. */
71static FrameBufferImpl _fbImpl;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080072
73/*
74 * Updates a display rectangle.
75 * Param
76 * fb - Framebuffer where to update the rectangle.
77 * x, y, w, and h define rectangle to update.
78 * bits_per_pixel define number of bits used to encode a single pixel.
79 * pixels contains pixels for the rectangle. Buffer addressed by this parameter
80 * must be eventually freed with free()
81 */
82static void
83_update_rect(QFrameBuffer* fb, uint16_t x, uint16_t y, uint16_t w, uint16_t h,
84 uint8_t bits_per_pixel, uint8_t* pixels)
85{
86 if (fb != NULL) {
87 uint16_t n;
88 const uint8_t* src = pixels;
89 const uint16_t src_line_size = w * ((bits_per_pixel + 7) / 8);
90 uint8_t* dst = (uint8_t*)fb->pixels + y * fb->pitch + x *
91 fb->bytes_per_pixel;
92 for (n = 0; n < h; n++) {
93 memcpy(dst, src, src_line_size);
94 src += src_line_size;
95 dst += fb->pitch;
96 }
97 qframebuffer_update(fb, x, y, w, h);
98 }
99 free(pixels);
100}
101
102/*
103 * Asynchronous I/O callback launched when framebuffer notifications are ready
104 * to be read.
105 * Param:
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100106 * opaque - FrameBufferImpl instance.
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800107 */
108static void
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100109_fbUpdatesImpl_io_callback(void* opaque, int fd, unsigned events)
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800110{
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100111 FrameBufferImpl* fbi = opaque;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800112 int ret;
113
114 // Read updates while they are immediately available.
115 for (;;) {
116 // Read next chunk of data.
David 'Digit' Turneraf81d742014-02-03 17:11:18 +0100117 ret = HANDLE_EINTR(
118 socket_recv(fbi->sock,
119 fbi->reader_buffer + fbi->reader_offset,
120 fbi->reader_bytes - fbi->reader_offset));
121 if (ret < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
122 // Chunk is not avalable at this point. Come back later.
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800123 return;
124 }
David 'Digit' Turneraf81d742014-02-03 17:11:18 +0100125 if (ret <= 0) {
126 /* disconnection ! */
127 derror("Unable to receive framebuffer data: %s\n",
128 ret < 0 ? strerror(errno), "unexpected disconnection");
129 fbUpdatesImpl_destroy();
130 return;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800131 }
132
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100133 fbi->reader_offset += ret;
134 if (fbi->reader_offset != fbi->reader_bytes) {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800135 // 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.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100140 if (fbi->fb_state == EXPECTS_HEADER) {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800141 // Update header has been read. Prepare for the pixels.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100142 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) {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800149 APANIC("Unable to allocate memory for framebuffer update\n");
150 }
151 } else {
152 // Pixels have been read. Prepare for the header.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100153 uint8_t* pixels = fbi->reader_buffer;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800154
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100155 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;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800159
160 // Perform the update. Note that pixels buffer must be freed there.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100161 _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,
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800164 pixels);
165 }
166 }
167}
168
169int
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100170fbUpdatesImpl_create(SockAddress* console_socket,
David 'Digit' Turnerb6c168b2011-02-02 21:39:10 +0100171 const char* protocol,
172 QFrameBuffer* fb,
173 Looper* looper)
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800174{
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100175 FrameBufferImpl* fbi = &_fbImpl;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800176 char* handshake = NULL;
177 char switch_cmd[256];
178
179 // Initialize descriptor.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100180 fbi->fb = fb;
181 fbi->reader_buffer = (uint8_t*)&fbi->update_header;
182 fbi->reader_offset = 0;
183 fbi->reader_bytes = sizeof(FBUpdateMessage);
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800184
185 // Connect to the framebuffer service.
186 snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol);
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100187 fbi->core_connection =
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800188 core_connection_create_and_switch(console_socket, switch_cmd, &handshake);
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100189 if (fbi->core_connection == NULL) {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800190 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.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100197 fbi->bits_per_pixel = 0;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800198 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 }
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100207 fbi->bits_per_pixel = strtol(bpp, &end, 0);
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800208 }
209 }
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100210 if (!fbi->bits_per_pixel) {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800211 derror("Unexpected core framebuffer reply: %s\n"
212 "Bits per pixel property is not there, or is invalid\n",
213 handshake);
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100214 fbUpdatesImpl_destroy();
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800215 return -1;
216 }
217
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100218 fbi->sock = core_connection_get_socket(fbi->core_connection);
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800219
220 // At last setup read callback, and start receiving the updates.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100221 loopIo_init(fbi->io, looper, fbi->sock,
222 _fbUpdatesImpl_io_callback, &_fbImpl);
223 loopIo_wantRead(fbi->io);
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800224 {
225 // Force the core to send us entire framebuffer now, when we're prepared
226 // to receive it.
227 FBRequestHeader hd;
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100228 SyncSocket* sk = syncsocket_init(fbi->sock);
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800229
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
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100251fbUpdatesImpl_destroy(void)
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800252{
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100253 FrameBufferImpl* fbi = &_fbImpl;
254
255 if (fbi->core_connection != NULL) {
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800256 // Disable the reader callback.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100257 loopIo_done(fbi->io);
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800258
259 // Close framebuffer connection.
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100260 core_connection_close(fbi->core_connection);
261 core_connection_free(fbi->core_connection);
262 fbi->core_connection = NULL;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800263 }
264
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100265 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;
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -0800270 }
271}