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