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