blob: 456c61e11e6cd623f2ba7dc61e713ca52e18a2f6 [file] [log] [blame]
Vladimir Chtchetkine777eb682011-01-26 11:19:19 -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 the UI-side implementation of the "core-ui-control" service that is
15 * part of the UI control protocol. Here we handle UI control commands received
16 * from the Core.
17 */
18
19#include "console.h"
20//#include "android/hw-control.h"
21#include "android/looper.h"
22#include "android/core-connection.h"
23#include "android/async-utils.h"
24#include "android/sync-utils.h"
25#include "android/utils/system.h"
26#include "android/utils/debug.h"
27#include "android/utils/panic.h"
28#include "android/protocol/ui-commands-impl.h"
29#include "android/protocol/ui-commands-api.h"
30
31/* Enumerates states for the command reader in UICmdImpl instance. */
32typedef enum UICmdImplState {
33 /* The reader is waiting on command header. */
34 EXPECTS_HEADER,
35
36 /* The reader is waiting on command parameters. */
37 EXPECTS_PARAMETERS,
38} UICmdImplState;
39
40/* Descriptor for the UI-side of the "core-ui-control" service. */
41typedef struct UICmdImpl {
42 /* Core connection established for this service. */
43 CoreConnection* core_connection;
44
45 /* Socket descriptor for the UI service. */
46 int sock;
47
48 /* Command reader state. */
49 UICmdImplState reader_state;
50
51 /* Incoming command header. */
52 UICmdHeader cmd_header;
53
54 /* Reader's buffer. This field can point to the cmd_header field of this
55 * structure (when we expect a command header), or to a buffer allocated for
56 * the (when we expect command parameters). */
57 uint8_t* reader_buffer;
58
59 /* Offset in the reader's buffer where to read next chunk of data. */
60 size_t reader_offset;
61
62 /* Total number of bytes the reader expects to read. */
63 size_t reader_bytes;
64} UICmdImpl;
65
66/* Implemented in android/qemulator.c */
67extern void android_emulator_set_window_scale(double scale, int is_dpi);
68
69/* One and only one UICmdImpl instance. */
70static UICmdImpl _uiCmdImpl;
71
72/* Display brightness change callback. */
73static AndroidHwLightBrightnessCallback _brightness_change_callback = NULL;
74static void* _brightness_change_callback_param = NULL;
75
76/* Destroys UICmdImpl instance. */
77static void
78_uiCmdImpl_destroy()
79{
80 if (_uiCmdImpl.core_connection != NULL) {
81 // Disable I/O callbacks.
82 qemu_set_fd_handler(_uiCmdImpl.sock, NULL, NULL, NULL);
83 core_connection_close(_uiCmdImpl.core_connection);
84 core_connection_free(_uiCmdImpl.core_connection);
85 _uiCmdImpl.core_connection = NULL;
86 }
87 // Properly deallocate the reader buffer.
88 if (_uiCmdImpl.reader_buffer != NULL &&
89 _uiCmdImpl.reader_buffer != (uint8_t*)&_uiCmdImpl.cmd_header) {
90 free(_uiCmdImpl.reader_buffer);
91 _uiCmdImpl.reader_buffer = (uint8_t*)&_uiCmdImpl.cmd_header;
92 }
93}
94
95/* Handles UI control command received from the core.
96 * Param:
97 * uicmd - UICmdImpl instance that received the command.
98 * header - UI control command header.
99 * data - Command parameters formatted accordingly to the command type.
100 */
101static void
102_uiCmdImpl_handle_command(UICmdImpl* uicmd,
103 const UICmdHeader* header,
104 const uint8_t* data)
105{
106 switch (header->cmd_type) {
107 case AUICMD_SET_WINDOWS_SCALE:
108 {
109 UICmdSetWindowsScale* cmd = (UICmdSetWindowsScale*)data;
110 android_emulator_set_window_scale(cmd->scale, cmd->is_dpi);
111 break;
112 }
113
114 case AUICMD_CHANGE_DISP_BRIGHTNESS:
115 {
116 UICmdChangeDispBrightness* cmd = (UICmdChangeDispBrightness*)data;
117 if (_brightness_change_callback != NULL) {
118 _brightness_change_callback(_brightness_change_callback_param,
119 cmd->light, cmd->brightness);
120 }
121 break;
122 }
123
124 default:
125 derror("Unknown command %d is received from the Core\n",
126 header->cmd_type);
127 break;
128 }
129}
130
131/* Asynchronous I/O callback reading UI control commands.
132 * Param:
133 * opaque - UICmdImpl instance.
134 */
135static void
136_uiCmdImpl_io_read(void* opaque)
137{
138 UICmdImpl* uicmd = opaque;
139 int status;
140
141 // Read requests while they are immediately available.
142 for (;;) {
143 // Read next chunk of data.
144 status = read(uicmd->sock, uicmd->reader_buffer + uicmd->reader_offset,
145 uicmd->reader_bytes - uicmd->reader_offset);
146 if (status == 0) {
147 /* Disconnection, meaning that the core process got termonated. */
148 fprintf(stderr, "core-ui-control service got disconnected\n");
149 _uiCmdImpl_destroy();
150 return;
151 }
152 if (status < 0) {
153 if (errno == EINTR) {
154 /* loop on EINTR */
155 continue;
156 } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
157 // Chunk is not avalable at this point. Come back later.
158 return;
159 }
160 }
161
162 uicmd->reader_offset += status;
163 if (uicmd->reader_offset != uicmd->reader_bytes) {
164 // There are still some data left in the pipe.
165 continue;
166 }
167
168 // All expected data has been read. Time to change the state.
169 if (uicmd->reader_state == EXPECTS_HEADER) {
170 // Header has been read.
171 if (uicmd->cmd_header.cmd_param_size) {
172 // Prepare for the command parameters.
173 uicmd->reader_state = EXPECTS_PARAMETERS;
174 uicmd->reader_offset = 0;
175 uicmd->reader_bytes = uicmd->cmd_header.cmd_param_size;
176 uicmd->reader_buffer = malloc(uicmd->reader_bytes);
177 if (uicmd->reader_buffer == NULL) {
178 APANIC("Unable to allocate memory for UI command parameters.\n");
179 }
180 } else {
181 // This command doesn't have any parameters. Handle it now.
182 _uiCmdImpl_handle_command(uicmd, &uicmd->cmd_header, NULL);
183 // Prepare for the next command header.
184 uicmd->reader_state = EXPECTS_HEADER;
185 uicmd->reader_offset = 0;
186 uicmd->reader_bytes = sizeof(uicmd->cmd_header);
187 uicmd->reader_buffer = (uint8_t*)&uicmd->cmd_header;
188 }
189 } else {
190 // All command data is in. Handle it.
191 _uiCmdImpl_handle_command(uicmd, &uicmd->cmd_header,
192 uicmd->reader_buffer);
193 // Prepare for the next command header.
194 free(uicmd->reader_buffer);
195 uicmd->reader_state = EXPECTS_HEADER;
196 uicmd->reader_offset = 0;
197 uicmd->reader_bytes = sizeof(uicmd->cmd_header);
198 uicmd->reader_buffer = (uint8_t*)&uicmd->cmd_header;
199 }
200 }
201}
202
203int
204uiCmdImpl_create(SockAddress* console_socket)
205{
206 char* handshake = NULL;
207
208 // Setup command reader.
209 _uiCmdImpl.reader_buffer = (uint8_t*)&_uiCmdImpl.cmd_header;
210 _uiCmdImpl.reader_state = EXPECTS_HEADER;
211 _uiCmdImpl.reader_offset = 0;
212 _uiCmdImpl.reader_bytes = sizeof(UICmdHeader);
213
214 // Connect to the core-ui-control service.
215 _uiCmdImpl.core_connection =
216 core_connection_create_and_switch(console_socket, "core-ui-control",
217 &handshake);
218 if (_uiCmdImpl.core_connection == NULL) {
219 derror("Unable to connect to the core-ui-control service: %s\n",
220 errno_str);
221 return -1;
222 }
223
224 // Initialze UI command reader.
225 _uiCmdImpl.sock = core_connection_get_socket(_uiCmdImpl.core_connection);
226 if (qemu_set_fd_handler(_uiCmdImpl.sock, _uiCmdImpl_io_read, NULL,
227 &_uiCmdImpl)) {
228 derror("Unable to set up UI _uiCmdImpl_io_read callback: %s\n",
229 errno_str);
230 _uiCmdImpl_destroy();
231 if (handshake != NULL) {
232 free(handshake);
233 }
234 return -1;
235 }
236
237 fprintf(stdout, "core-ui-control 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
250int
251uicmd_set_brightness_change_callback(AndroidHwLightBrightnessCallback callback,
252 void* opaque)
253{
254 _brightness_change_callback = callback;
255 _brightness_change_callback_param = opaque;
256 return 0;
257}