pkg: change destination path for add on packages
[sdk/emulator/qemu.git] / tizen / src / ecs / ecs_msg_injector.c
1 /* Emulator Control Server
2  *
3  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
4  *
5  * Contact:
6  *  Chulho Song     <ch81.song@samsung.com>
7  *  Jinhyung Choi   <jinh0.choi@samsung.com>
8  *  MunKyu Im       <munkyu.im@samsung.com>
9  *  Daiyoung Kim    <daiyoung777.kim@samsung.com>
10  *  YeongKyoon Lee  <yeongkyoon.lee@samsung.com>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include "qemu/osdep.h"
35 #include "qemu-common.h"
36 #include "qemu/error-report.h"
37
38 #include "hw/virtio/maru_virtio_vmodem.h"
39 #include "hw/virtio/maru_virtio_evdi.h"
40 #include "hw/virtio/maru_virtio_jack.h"
41 #include "hw/virtio/maru_virtio_power.h"
42
43 #include "emul_state.h"
44 #include "ecs_hds.h"
45 #include "ecs_sensor.h"
46 #include "debug_ch.h"
47 #include "util/osutil.h"
48 #include "util/exported_strings.h"
49
50 MULTI_DEBUG_CHANNEL(qemu, ecs);
51
52 #define MAX_PKGS_LIST       1024
53 #define MAX_SDB_TRIAL       10
54 #define SLEEP_WAIT_SDB      500  /* ms */
55 #define SLEEP_CONNECT_SDB   1000 /* ms */
56
57 static QemuThread sdb_thread_id;
58
59 extern QemuMutex mutex_location_data;
60 static char location_data[MAX_INJECTOR_REQ_DATA];
61
62 static void msgproc_injector_ans(ECS_Client *ccli, const char *category, bool succeed)
63 {
64     if (ccli == NULL) {
65         return;
66     }
67     int catlen = 0;
68     ECS__Master master = ECS__MASTER__INIT;
69     ECS__InjectorAns ans = ECS__INJECTOR_ANS__INIT;
70
71     LOG_TRACE("injector ans - category : %s, succed : %d\n", category, succeed);
72
73     catlen = strlen(category);
74     ans.category = (char *) g_malloc0(catlen + 1);
75     memcpy(ans.category, category, catlen);
76
77     ans.errcode = !succeed;
78     master.type = ECS__MASTER__TYPE__INJECTOR_ANS;
79     master.injector_ans = &ans;
80
81     pb_to_all_clients(&master);
82
83     g_free(ans.category);
84 }
85
86 static bool injector_send(ECS_Client *ccli, ECS__InjectorReq *msg, char *cmd)
87 {
88     int sndlen = 15; /* HEADER(CMD + LENGTH + GROUP + ACTION) + 1 */
89     const char *msg_data;
90     char *sndbuf;
91     bool ret = false;
92     type_group group;
93
94     group = (type_group) (msg->group & 0xff);
95
96     if (msg->has_data && msg->data.data && msg->data.len > 0) {
97         sndlen += msg->data.len;
98     }
99
100     sndbuf = (char *) g_malloc0(sndlen);
101     if (!sndbuf) {
102         msgproc_injector_ans(ccli, cmd, false);
103         return false;
104     }
105
106     memcpy(sndbuf, cmd, 10);
107     memcpy(sndbuf + 10, &msg->length, 2);
108     memcpy(sndbuf + 12, &msg->group, 1);
109     memcpy(sndbuf + 13, &msg->action, 1);
110
111     if (msg->has_data && msg->data.data && msg->data.len > 0) {
112         msg_data = (const char *)msg->data.data;
113         memcpy(sndbuf + 14, msg_data, msg->data.len);
114         LOG_TRACE(">> print len = %zd, data\" %s\"\n", msg->data.len, msg_data);
115     }
116
117     if (strcmp(cmd, "telephony") == 0) {
118         LOG_TRACE("telephony msg >>\n");
119         ret = send_to_vmodem(route_ij, sndbuf, sndlen);
120     } else {
121         LOG_TRACE("evdi msg >> %s\n", cmd);
122         ret = send_to_evdi(route_ij, sndbuf, sndlen);
123     }
124
125     g_free(sndbuf);
126
127     if (group != MSG_GROUP_STATUS) {
128         msgproc_injector_ans(ccli, cmd, ret);
129     }
130
131     if (!ret) {
132         return false;
133     }
134
135     return true;
136 }
137
138 static void send_status_injector_ntf(const char *cmd, int cmdlen, int act, char *on)
139 {
140     int msglen = 0, datalen = 0;
141     type_length length  = 0;
142     type_group group = MSG_GROUP_STATUS;
143     type_action action = act;
144
145     if (cmd == NULL || cmdlen > 10) {
146         return;
147     }
148
149     if (on == NULL) {
150         msglen = 14;
151     } else {
152         datalen = strlen(on);
153         length  = (unsigned short)datalen;
154
155         msglen = datalen + 15;
156     }
157
158     char *status_msg = (char *) malloc(msglen);
159     if (!status_msg) {
160         return;
161     }
162
163     memset(status_msg, 0, msglen);
164
165     memcpy(status_msg, cmd, cmdlen);
166     memcpy(status_msg + 10, &length, sizeof(unsigned short));
167     memcpy(status_msg + 12, &group, sizeof(unsigned char));
168     memcpy(status_msg + 13, &action, sizeof(unsigned char));
169
170     if (on != NULL) {
171         memcpy(status_msg + 14, on, datalen);
172     }
173
174     send_injector_ntf(status_msg, msglen);
175
176     free(status_msg);
177 }
178
179 static bool injector_req_sensor(ECS_Client *ccli, ECS__InjectorReq *msg, char *cmd)
180 {
181     char data[MAX_INJECTOR_REQ_DATA];
182     type_group group;
183     type_action action;
184
185     memset(data, 0, MAX_INJECTOR_REQ_DATA);
186     group = (type_group) (msg->group & 0xff);
187     action = (type_action) (msg->action & 0xff);
188
189     if (group == MSG_GROUP_STATUS) {
190         switch (action) {
191         case MSG_ACT_BATTERY_LEVEL:
192             sprintf(data, "%d", get_power_capacity());
193             break;
194         case MSG_ACT_BATTERY_CHARGER:
195             sprintf(data, "%d", get_jack_charger());
196             break;
197         case MSG_ACT_USB:
198             sprintf(data, "%d", get_jack_usb());
199             break;
200         case MSG_ACT_EARJACK:
201             sprintf(data, "%d", get_jack_earjack());
202             break;
203         case MSG_ACT_LOCATION:
204             qemu_mutex_lock(&mutex_location_data);
205             sprintf(data, "%s", location_data);
206             qemu_mutex_unlock(&mutex_location_data);
207             break;
208         default:
209             return injector_send(ccli, msg, cmd);
210         }
211         LOG_TRACE("status : %s\n", data);
212         send_status_injector_ntf(MSG_TYPE_SENSOR, 6, action, data);
213         return true;
214     } else if (msg->data.data && msg->data.len > 0) {
215         ecs_sensor_set_injector_data((char *) msg->data.data);
216         return injector_send(ccli, msg, cmd);
217     }
218
219     return false;
220 }
221
222 static bool injector_req_guest(void)
223 {
224     send_status_injector_ntf(MSG_TYPE_GUEST, 5, get_emuld_connection(), NULL);
225     return true;
226 }
227
228 static bool injector_req_location(ECS_Client *ccli, ECS__InjectorReq *msg, char *cmd)
229 {
230     if (msg->data.data != NULL && msg->data.len > 0) {
231         qemu_mutex_lock(&mutex_location_data);
232         snprintf(location_data, msg->data.len + 1, "%s", (char *)msg->data.data);
233         qemu_mutex_unlock(&mutex_location_data);
234         return injector_send(ccli, msg, cmd);
235     }
236
237     return false;
238 }
239
240 bool msgproc_injector_req(ECS_Client *ccli, ECS__InjectorReq *msg)
241 {
242     char cmd[11];
243     bool ret = false;
244
245     strncpy(cmd, msg->category, sizeof(cmd) - 1);
246
247     if (!strcmp(cmd, MSG_TYPE_SENSOR)) {
248         ret = injector_req_sensor(ccli, msg, cmd);
249     } else if (!strcmp(cmd, MSG_TYPE_GUEST)) {
250         ret = injector_req_guest();
251     } else if (!strcmp(cmd, MSG_TYPE_LOCATION)) {
252         ret = injector_req_location(ccli, msg, cmd);
253     } else {
254         ret = injector_send(ccli, msg, cmd);
255     }
256
257     return ret;
258 }
259
260 void ecs_suspend_lock_state(int state)
261 {
262     int catlen;
263
264     ECS__InjectorReq msg = ECS__INJECTOR_REQ__INIT;
265     const char *category = "suspend";
266
267     catlen = strlen(category);
268     msg.category = (char *) g_malloc0(catlen + 1);
269     memcpy(msg.category, category, catlen);
270
271     msg.group = 5;
272     msg.action = state;
273
274     msgproc_injector_req(NULL, &msg);
275 }
276
277 static bool do_push_package(char *cmd)
278 {
279     char buf[MAX_PKGS_LIST];
280     FILE *fp = popen(cmd, "r");
281     if (fp == NULL) {
282         LOG_SEVERE("Failed to popen push packages\n");
283         return false;
284     }
285
286     memset(buf, 0, sizeof(buf));
287     while (fgets(buf, sizeof(buf), fp) != NULL) {
288         LOG_INFO("[pkgs]%s\n", buf);
289         if (!strncmp(buf, "error", 5)) {
290             pclose(fp);
291             return false;
292         }
293         memset(buf, 0, sizeof(buf));
294     }
295
296     pclose(fp);
297     return true;
298 }
299
300 static bool push_package(const char *data)
301 {
302     int index = 0;
303     int ret = 0;
304     char cmd[MAX_PKGS_LIST];
305     char token[] = ", ";
306 #ifndef CONFIG_WIN32
307     const char *sdb_path = "../../../../../tools/sdb";
308     const char *platform_path = "../../../";
309     const char *addon_path = "/emulator-images/add-ons/";
310 #else
311     const char *sdb_path = "..\\..\\..\\..\\..\\tools\\sdb.exe";
312     const char *platform_path = "..\\..\\..\\";
313     const char *addon_path = "\\emulator-images\\add-ons\\";
314 #endif
315     const char *bin_dir = get_bin_path();
316
317     memset(cmd, 0, sizeof(cmd));
318
319     char *addon = strtok((char *)data, token);
320 #ifndef CONFIG_WIN32
321     ret = sprintf(cmd, "\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /tmp/.emulator/apps/%s 2>&1",
322 #else
323     ret = sprintf(cmd, "cmd /S /C \"\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /tmp/.emulator/apps/%s 2>&1\"",
324 #endif
325             bin_dir, sdb_path, get_vm_device_serial_number(),
326             bin_dir, platform_path, get_profile_name(), addon_path, addon,
327             addon);
328     if (ret < 0) {
329         LOG_SEVERE("SDB push command is wrong: %s\n", cmd);
330         return false;
331     }
332
333     LOG_INFO("[pkgs] SDB push command: %s\n", cmd);
334
335     if (do_push_package(cmd)) {
336         LOG_INFO("[pkgs] SDB push SUCCESS\n");
337         return true;
338     }
339
340     /*
341      * FIXME: unnecessary sdb connection waiting sleep.
342      *        If SDB runs faster, it should be changed/removed.
343      */
344     while (!get_sdb_connection() && index != MAX_SDB_TRIAL) {
345         LOG_INFO("[pkgs] Waiting SDB connection...%d\n", index + 1);
346 #ifdef CONFIG_WIN32
347         Sleep(SLEEP_WAIT_SDB);
348 #else
349         usleep(SLEEP_WAIT_SDB * 1000);
350 #endif
351         index++;
352     }
353
354     index = 0;
355 #ifdef CONFIG_WIN32
356     Sleep(SLEEP_WAIT_SDB);
357 #else
358     usleep(SLEEP_WAIT_SDB * 1000);
359 #endif
360
361     while (index != MAX_SDB_TRIAL) {
362         if (do_push_package(cmd)) {
363             LOG_INFO("[pkgs] SDB push SUCCESS.\n");
364             return true;
365         }
366         LOG_INFO("[pkgs] Try to send package ...%d\n", index + 1);
367         index++;
368 #ifdef CONFIG_WIN32
369         Sleep(SLEEP_CONNECT_SDB);
370 #else
371         usleep(SLEEP_CONNECT_SDB * 1000);
372 #endif
373     }
374
375     return false;
376 }
377
378 static void show_error_popup(char *data)
379 {
380     char fail_msg[MAX_PKGS_LIST];
381     char token[] = ", ";
382     char *addon = strtok(data, token);
383
384     memset(fail_msg, 0, sizeof(fail_msg));
385     strcpy(fail_msg, FAILED_TO_INSTALL_EXTRAPACKAGE_1);
386     strcat(fail_msg, addon);
387     strcat(fail_msg, FAILED_TO_INSTALL_EXTRAPACKAGE_2);
388
389     error_report("%s", fail_msg);
390 }
391
392 static void *push_pkgs_thread(void *args)
393 {
394     char *pkg_data = (char *)args;
395     char *data = strdup(pkg_data);
396     if (pkg_data == NULL || data == NULL) {
397         LOG_SEVERE("pkg data strdup is failed.\n");
398         return NULL;
399     }
400
401     if (!push_package(pkg_data)) {
402         LOG_SEVERE("file upload is failed. %s\n", data);
403         show_error_popup(data);
404         free(pkg_data);
405         free(data);
406         return NULL;
407     }
408
409     /* request to install rpms */
410     LOG_INFO("[pkgs] Request to install : %s\n", data);
411     send_msg_to_guest(MSG_TYPE_PACKAGE, 0, 2, data, strlen(data) + 1);
412
413     free(pkg_data);
414     free(data);
415
416     return NULL;
417 }
418
419 static void do_package(char *cat, type_action action, const char *data)
420 {
421     if (data == NULL || strlen(data) <= 0) {
422         LOG_SEVERE("data is corrupted.\n");
423         return;
424     }
425
426     if (action == 1) {
427         LOG_INFO("[pkgs] Already installed: %s\n", data);
428     } else if (action == 2) {
429         LOG_INFO("[pkgs] Needed to install: %s\n", data);
430         char *pkgs = g_malloc0(MAX_PKGS_LIST);
431         strncpy(pkgs, data, MAX_PKGS_LIST - 1);
432         qemu_thread_create(&sdb_thread_id, "sdb_push", push_pkgs_thread, (void *)pkgs, QEMU_THREAD_DETACHED);
433     } else if (action == 3) {
434         LOG_INFO("[pkgs] Package Installation Success: %s\n", data);
435     } else if (action == 4) {
436         LOG_INFO("[pkgs] Package Installation Failed: %s\n", data);
437         show_error_popup((char *)data);
438     } else {
439         LOG_SEVERE("unknown pkgs action: %d\n", action);
440     }
441 }
442
443 static bool injector_req_handle(char *cat, type_action action, const char *data)
444 {
445     int state = 0;
446     if (!strcmp(cat, "suspend")) {
447         state = ecs_get_suspend_state();
448         LOG_INFO("send suspend lock state : %d\n", state);
449         ecs_suspend_lock_state(state);
450         return true;
451     } else if (!strcmp(cat, "boot")) {
452         LOG_INFO("emulator booting done.\n");
453         set_emulator_condition(BOOT_COMPLETED);
454         return true;
455     } else if (!strcmp(cat, MSG_TYPE_GUEST)) {
456         LOG_INFO("emuld connection is %d\n", action);
457         set_emuld_connection(action);
458     } else if (!strcmp(cat, "hds")) {
459 #ifdef CONFIG_VIRTFS
460         msgproc_injector_do_hds(cat, action, data);
461         return true;
462 #else
463         LOG_WARNING("VirtFS is not enabled.\n");
464         return false;
465 #endif
466     } else if (!strcmp(cat, MSG_TYPE_CAP)) {
467         LOG_INFO("set capabilities: %s\n", data);
468         ecs_set_device_capabilities(data);
469         return true;
470     } else if (!strcmp(cat, MSG_TYPE_PACKAGE)) {
471         do_package(cat, action, data);
472         return true;
473     } else if (!strcmp(cat, MSG_TYPE_GUESTIP)) {
474         if (data != NULL && strlen(data) > 0) {
475             LOG_INFO("guest ip: %s\n", data);
476             set_guest_ip((char *)data);
477         } else {
478             LOG_SEVERE("guest ip is null!\n");
479         }
480         return true;
481     }
482     return false;
483 }
484
485 bool send_injector_ntf(const char *data, const int len)
486 {
487     type_length length = 0;
488     type_group group = 0;
489     type_action action = 0;
490
491     const int catsize = 10;
492     char cat[catsize + 1];
493     memset(cat, 0, catsize + 1);
494
495     read_val_str(data, cat, catsize);
496     read_val_short(data + catsize, &length);
497     read_val_char(data + catsize + 2, &group);
498     read_val_char(data + catsize + 2 + 1, &action);
499
500     const char *ijdata = (data + catsize + 2 + 1 + 1);
501
502     if (!is_ecs_running()) {
503         LOG_SEVERE("ECS is not running.\n");
504         return false;
505     }
506
507     if (injector_req_handle(cat, action, ijdata)) {
508         return true;
509     }
510
511     LOG_TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length, action, group);
512
513     ECS__Master master = ECS__MASTER__INIT;
514     ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
515
516     ntf.category = (char *) g_malloc(catsize + 1);
517     strncpy(ntf.category, cat, 10);
518
519     ntf.length = length;
520     ntf.group = group;
521     ntf.action = action;
522
523     if (length > 0) {
524         ntf.has_data = 1;
525
526         ntf.data.data = g_malloc(length);
527         ntf.data.len = length;
528         memcpy(ntf.data.data, ijdata, length);
529     }
530
531     master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
532     master.injector_ntf = &ntf;
533
534     pb_to_all_clients(&master);
535
536     if (ntf.data.len > 0) {
537         g_free(ntf.data.data);
538     }
539
540     g_free(ntf.category);
541
542     return true;
543 }
544