• 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 "ui-core-control" service that is
15  * part of the UI control protocol. Here we send UI control commands to the Core.
16  */
17 
18 #include "console.h"
19 #include "android/looper.h"
20 #include "android/async-utils.h"
21 #include "android/sync-utils.h"
22 #include "android/utils/debug.h"
23 #include "android/utils/panic.h"
24 #include "android/protocol/core-connection.h"
25 #include "android/protocol/core-commands.h"
26 #include "android/protocol/core-commands-proxy.h"
27 #include "android/protocol/core-commands-api.h"
28 
29 /* Descriptor for the UI-side "ui-core-control" service. */
30 typedef struct CoreCmdProxy {
31     /* Core connection established for this service. */
32     CoreConnection*     core_connection;
33 
34     /* Socket descriptor for the UI service. */
35     int                 sock;
36 
37     /* Socket wrapper for sync srites. */
38     SyncSocket*         sync_writer;
39 
40     /* Socket wrapper for sync reads. */
41     SyncSocket*         sync_reader;
42 } CoreCmdProxy;
43 
44 /* One and only one CoreCmdProxy instance. */
45 static CoreCmdProxy  _coreCmdProxy = { 0 };
46 
47 /* Sends UI command to the core.
48  * Param:
49  *  cmd_type, cmd_param, cmd_param_size - Define the command.
50  * Return:
51  *  0 On success, or < 0 on failure.
52  */
53 static int
_coreCmdProxy_send_command(uint8_t cmd_type,void * cmd_param,uint32_t cmd_param_size)54 _coreCmdProxy_send_command(uint8_t cmd_type,
55                            void* cmd_param,
56                            uint32_t cmd_param_size)
57 {
58     int status;
59     UICmdHeader header;
60 
61     // Prepare the command header.
62     header.cmd_type = cmd_type;
63     header.cmd_param_size = cmd_param_size;
64     status = syncsocket_start_write(_coreCmdProxy.sync_writer);
65     if (!status) {
66         // Send the header.
67         status = syncsocket_write(_coreCmdProxy.sync_writer, &header,
68                                   sizeof(header),
69                                   core_connection_get_timeout(sizeof(header)));
70         // If there is request data, send it too.
71         if (status > 0 && cmd_param != NULL && cmd_param_size > 0) {
72             status = syncsocket_write(_coreCmdProxy.sync_writer, cmd_param,
73                                       cmd_param_size,
74                                       core_connection_get_timeout(cmd_param_size));
75         }
76         status = syncsocket_result(status);
77         syncsocket_stop_write(_coreCmdProxy.sync_writer);
78     }
79     if (status < 0) {
80         derror("Unable to send UI control command %d (size %u): %s\n",
81                 cmd_type, cmd_param_size, errno_str);
82     }
83     return status;
84 }
85 
86 /* Reads UI control command response from the core.
87  * Param:
88  *  resp - Upon success contains command response header.
89  *  resp_data - Upon success contains allocated reponse data (if any). The caller
90  *      is responsible for deallocating the memory returned here.
91  * Return:
92  *  0 on success, or < 0 on failure.
93  */
94 static int
_coreCmdProxy_get_response(UICmdRespHeader * resp,void ** resp_data)95 _coreCmdProxy_get_response(UICmdRespHeader* resp, void** resp_data)
96 {
97     int status =  syncsocket_start_read(_coreCmdProxy.sync_reader);
98     if (!status) {
99         // Read the header.
100         status = syncsocket_read(_coreCmdProxy.sync_reader, resp,
101                                  sizeof(UICmdRespHeader),
102                                  core_connection_get_timeout(sizeof(UICmdRespHeader)));
103         // Read response data (if any).
104         if (status > 0 && resp->resp_data_size) {
105             *resp_data = malloc(resp->resp_data_size);
106             if (*resp_data == NULL) {
107                 APANIC("_coreCmdProxy_get_response is unable to allocate response data buffer.\n");
108             }
109             status = syncsocket_read(_coreCmdProxy.sync_reader, *resp_data,
110                                      resp->resp_data_size,
111                                      core_connection_get_timeout(resp->resp_data_size));
112         }
113         status = syncsocket_result(status);
114         syncsocket_stop_read(_coreCmdProxy.sync_reader);
115     }
116     if (status < 0) {
117         derror("Unable to get UI command response from the Core: %s\n",
118                errno_str);
119     }
120     return status;
121 }
122 
123 int
corecmd_set_coarse_orientation(AndroidCoarseOrientation orient)124 corecmd_set_coarse_orientation(AndroidCoarseOrientation orient)
125 {
126     UICmdSetCoarseOrientation cmd;
127     cmd.orient = orient;
128     return _coreCmdProxy_send_command(AUICMD_SET_COARSE_ORIENTATION,
129                                       &cmd, sizeof(cmd));
130 }
131 
132 int
corecmd_toggle_network()133 corecmd_toggle_network()
134 {
135     return _coreCmdProxy_send_command(AUICMD_TOGGLE_NETWORK, NULL, 0);
136 }
137 
138 int
corecmd_trace_control(int start)139 corecmd_trace_control(int start)
140 {
141     UICmdTraceControl cmd;
142     cmd.start = start;
143     return _coreCmdProxy_send_command(AUICMD_TRACE_CONTROL,
144                                       &cmd, sizeof(cmd));
145 }
146 
147 int
corecmd_is_network_disabled()148 corecmd_is_network_disabled()
149 {
150     UICmdRespHeader resp;
151     void* tmp = NULL;
152     int status;
153 
154     status = _coreCmdProxy_send_command(AUICMD_CHK_NETWORK_DISABLED, NULL, 0);
155     if (status < 0) {
156         return status;
157     }
158     status = _coreCmdProxy_get_response(&resp, &tmp);
159     if (status < 0) {
160         return status;
161     }
162     return resp.result;
163 }
164 
165 int
corecmd_get_netspeed(int index,NetworkSpeed ** netspeed)166 corecmd_get_netspeed(int index, NetworkSpeed** netspeed)
167 {
168     UICmdGetNetSpeed req;
169     UICmdRespHeader resp;
170     UICmdGetNetSpeedResp* resp_data = NULL;
171     int status;
172 
173     // Initialize and send the query.
174     req.index = index;
175     status = _coreCmdProxy_send_command(AUICMD_GET_NETSPEED, &req, sizeof(req));
176     if (status < 0) {
177         return status;
178     }
179 
180     // Obtain the response from the core.
181     status = _coreCmdProxy_get_response(&resp, (void**)&resp_data);
182     if (status < 0) {
183         return status;
184     }
185     if (!resp.result) {
186         NetworkSpeed* ret;
187         // Allocate memory for the returning NetworkSpeed instance.
188         // It includes: NetworkSpeed structure +
189         // size of zero-terminated "name" and "display" strings saved in
190         // resp_data.
191         *netspeed = malloc(sizeof(NetworkSpeed) + 1 +
192                            resp.resp_data_size - sizeof(UICmdGetNetSpeedResp));
193         ret = *netspeed;
194 
195         // Copy data obtained from the core to the returning NetworkSpeed
196         // instance.
197         ret->upload = resp_data->upload;
198         ret->download = resp_data->download;
199         ret->name = (char*)ret + sizeof(NetworkSpeed);
200         strcpy((char*)ret->name, resp_data->name);
201         ret->display = ret->name + strlen(ret->name) + 1;
202         strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1);
203     }
204     if (resp_data != NULL) {
205         free(resp_data);
206     }
207     return resp.result;
208 }
209 
210 int
corecmd_get_netdelay(int index,NetworkLatency ** netdelay)211 corecmd_get_netdelay(int index, NetworkLatency** netdelay)
212 {
213     UICmdGetNetDelay req;
214     UICmdRespHeader resp;
215     UICmdGetNetDelayResp* resp_data = NULL;
216     int status;
217 
218     // Initialize and send the query.
219     req.index = index;
220     status = _coreCmdProxy_send_command(AUICMD_GET_NETDELAY, &req, sizeof(req));
221     if (status < 0) {
222         return status;
223     }
224 
225     // Obtain the response from the core.
226     status = _coreCmdProxy_get_response(&resp, (void**)&resp_data);
227     if (status < 0) {
228         return status;
229     }
230     if (!resp.result) {
231         NetworkLatency* ret;
232         // Allocate memory for the returning NetworkLatency instance.
233         // It includes: NetworkLatency structure +
234         // size of zero-terminated "name" and "display" strings saved in
235         // resp_data.
236         *netdelay = malloc(sizeof(NetworkLatency) + 1 +
237                            resp.resp_data_size - sizeof(UICmdGetNetDelayResp));
238         ret = *netdelay;
239 
240         // Copy data obtained from the core to the returning NetworkLatency
241         // instance.
242         ret->min_ms = resp_data->min_ms;
243         ret->max_ms = resp_data->max_ms;
244         ret->name = (char*)ret + sizeof(NetworkLatency);
245         strcpy((char*)ret->name, resp_data->name);
246         ret->display = ret->name + strlen(ret->name) + 1;
247         strcpy((char*)ret->display, resp_data->name + strlen(resp_data->name) + 1);
248     }
249     if (resp_data != NULL) {
250         free(resp_data);
251     }
252     return resp.result;
253 }
254 
255 int
corecmd_get_qemu_path(int type,const char * filename,char * path,size_t path_buf_size)256 corecmd_get_qemu_path(int type,
257                       const char* filename,
258                       char* path,
259                       size_t path_buf_size)
260 {
261     UICmdRespHeader resp;
262     char* resp_data = NULL;
263     int status;
264 
265     // Initialize and send the query.
266     uint32_t cmd_data_size = sizeof(UICmdGetQemuPath) + strlen(filename) + 1;
267     UICmdGetQemuPath* req = (UICmdGetQemuPath*)malloc(cmd_data_size);
268     if (req == NULL) {
269         APANIC("corecmd_get_qemu_path is unable to allocate %u bytes\n",
270                cmd_data_size);
271     }
272     req->type = type;
273     strcpy(req->filename, filename);
274     status = _coreCmdProxy_send_command(AUICMD_GET_QEMU_PATH, req,
275                                         cmd_data_size);
276     if (status < 0) {
277         return status;
278     }
279 
280     // Obtain the response from the core.
281     status = _coreCmdProxy_get_response(&resp, (void**)&resp_data);
282     if (status < 0) {
283         return status;
284     }
285     if (!resp.result && resp_data != NULL) {
286         strncpy(path, resp_data, path_buf_size);
287         path[path_buf_size - 1] = '\0';
288     }
289     if (resp_data != NULL) {
290         free(resp_data);
291     }
292     return resp.result;
293 }
294 
295 int
corecmd_get_hw_lcd_density(void)296 corecmd_get_hw_lcd_density(void)
297 {
298     UICmdRespHeader resp;
299     void* tmp = NULL;
300     int status;
301 
302     status = _coreCmdProxy_send_command(AUICMD_GET_LCD_DENSITY, NULL, 0);
303     if (status < 0) {
304         return status;
305     }
306     status = _coreCmdProxy_get_response(&resp, &tmp);
307     if (status < 0) {
308         return status;
309     }
310     return resp.result;
311 }
312 
313 int
coreCmdProxy_create(SockAddress * console_socket)314 coreCmdProxy_create(SockAddress* console_socket)
315 {
316     char* handshake = NULL;
317 
318     // Connect to the ui-core-control service.
319     _coreCmdProxy.core_connection =
320         core_connection_create_and_switch(console_socket, "ui-core-control",
321                                           &handshake);
322     if (_coreCmdProxy.core_connection == NULL) {
323         derror("Unable to connect to the ui-core-control service: %s\n",
324                errno_str);
325         return -1;
326     }
327 
328     // Initialze command writer and response reader.
329     _coreCmdProxy.sock = core_connection_get_socket(_coreCmdProxy.core_connection);
330     _coreCmdProxy.sync_writer = syncsocket_init(_coreCmdProxy.sock);
331     if (_coreCmdProxy.sync_writer == NULL) {
332         derror("Unable to initialize CoreCmdProxy writer: %s\n", errno_str);
333         coreCmdProxy_destroy();
334         return -1;
335     }
336     _coreCmdProxy.sync_reader = syncsocket_init(_coreCmdProxy.sock);
337     if (_coreCmdProxy.sync_reader == NULL) {
338         derror("Unable to initialize CoreCmdProxy reader: %s\n", errno_str);
339         coreCmdProxy_destroy();
340         return -1;
341     }
342 
343 
344     fprintf(stdout, "ui-core-control is now connected to the core at %s.",
345             sock_address_to_string(console_socket));
346     if (handshake != NULL) {
347         if (handshake[0] != '\0') {
348             fprintf(stdout, " Handshake: %s", handshake);
349         }
350         free(handshake);
351     }
352     fprintf(stdout, "\n");
353 
354     return 0;
355 }
356 
357 /* Destroys CoreCmdProxy instance. */
358 void
coreCmdProxy_destroy(void)359 coreCmdProxy_destroy(void)
360 {
361     if (_coreCmdProxy.sync_writer != NULL) {
362         syncsocket_close(_coreCmdProxy.sync_writer);
363         syncsocket_free(_coreCmdProxy.sync_writer);
364         _coreCmdProxy.sync_writer = NULL;
365     }
366     if (_coreCmdProxy.sync_reader != NULL) {
367         syncsocket_close(_coreCmdProxy.sync_reader);
368         syncsocket_free(_coreCmdProxy.sync_reader);
369         _coreCmdProxy.sync_reader = NULL;
370     }
371     if (_coreCmdProxy.core_connection != NULL) {
372         core_connection_close(_coreCmdProxy.core_connection);
373         core_connection_free(_coreCmdProxy.core_connection);
374         _coreCmdProxy.core_connection = NULL;
375     }
376 }
377