Merge branch 'tizen_2.4_develop' into tizen_3.0_develop
[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  *  Jinhyung choi   <jinhyung2.choi@samsung.com>
7  *  MunKyu Im       <munkyu.im@samsung.com>
8  *  Daiyoung Kim    <daiyoung777.kim@samsung.com>
9  *  YeongKyoon Lee  <yeongkyoon.lee@samsung.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include "qemu-common.h"
34 #include "fsdev/qemu-fsdev.h"
35
36 #include "hw/virtio/maru_virtio_vmodem.h"
37 #include "hw/virtio/maru_virtio_evdi.h"
38 #include "hw/virtio/maru_virtio_jack.h"
39 #include "hw/virtio/maru_virtio_power.h"
40
41 #include "util/device_hotplug.h"
42 #include "util/hds.h"
43 #include "emul_state.h"
44 #include "ecs.h"
45 #include "debug_ch.h"
46 #include "util/osutil.h"
47 #include "util/exported_strings.h"
48
49 MULTI_DEBUG_CHANNEL(qemu, ecs);
50
51 #define MAX_PKGS_LIST       1024
52 #define MAX_SDB_TRIAL       10
53 #define SLEEP_WAIT_SDB      500 // ms
54 #define SLEEP_CONNECT_SDB   1000 // ms
55
56 static QemuThread sdb_thread_id;
57 static QemuThread hds_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     if (ans.category)
84         g_free(ans.category);
85 }
86
87 static bool injector_send(ECS_Client* ccli, ECS__InjectorReq* msg, char* cmd)
88 {
89     int sndlen = 15; // HEADER(CMD + LENGTH + GROUP + ACTION) + 1
90     const char* msg_data;
91     char* sndbuf;
92     bool ret = false;
93     type_group group;
94
95     group = (type_group) (msg->group & 0xff);
96
97     if (msg->has_data && msg->data.data && msg->data.len > 0)
98         sndlen += msg->data.len;
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 >>");
119         ret = send_to_vmodem(route_ij, sndbuf, sndlen);
120     } else {
121         LOG_TRACE("evdi msg >> %s", 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     if (on == NULL) {
149         msglen = 14;
150     } else {
151         datalen = strlen(on);
152         length  = (unsigned short)datalen;
153
154         msglen = datalen + 15;
155     }
156
157     char* status_msg = (char*) malloc(msglen);
158     if(!status_msg)
159         return;
160
161     memset(status_msg, 0, msglen);
162
163     memcpy(status_msg, cmd, cmdlen);
164     memcpy(status_msg + 10, &length, sizeof(unsigned short));
165     memcpy(status_msg + 12, &group, sizeof(unsigned char));
166     memcpy(status_msg + 13, &action, sizeof(unsigned char));
167
168     if (on != NULL) {
169         memcpy(status_msg + 14, on, datalen);
170     }
171
172     send_injector_ntf(status_msg, msglen);
173
174     free(status_msg);
175 }
176
177 static bool injector_req_sensor(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
178 {
179     char data[MAX_INJECTOR_REQ_DATA];
180     type_group group;
181     type_action action;
182
183     memset(data, 0, MAX_INJECTOR_REQ_DATA);
184     group = (type_group) (msg->group & 0xff);
185     action = (type_action) (msg->action & 0xff);
186
187     if (group == MSG_GROUP_STATUS) {
188         switch (action) {
189         case MSG_ACT_BATTERY_LEVEL:
190             sprintf(data, "%d", get_power_capacity());
191             break;
192         case MSG_ACT_BATTERY_CHARGER:
193             sprintf(data, "%d", get_jack_charger());
194             break;
195         case MSG_ACT_USB:
196             sprintf(data, "%d", get_jack_usb());
197             break;
198         case MSG_ACT_EARJACK:
199             sprintf(data, "%d", get_jack_earjack());
200             break;
201         case MSG_ACT_LOCATION:
202             qemu_mutex_lock(&mutex_location_data);
203             sprintf(data, "%s", location_data);
204             qemu_mutex_unlock(&mutex_location_data);
205             break;
206         default:
207             return injector_send(ccli, msg, cmd);
208         }
209         LOG_TRACE("status : %s\n", data);
210         send_status_injector_ntf(MSG_TYPE_SENSOR, 6, action, data);
211         return true;
212     } else if (msg->data.data && msg->data.len > 0) {
213         set_injector_data((char*) msg->data.data);
214         return injector_send(ccli, msg, cmd);
215     }
216
217     return false;
218 }
219
220 static bool injector_req_guest(void)
221 {
222     send_status_injector_ntf(MSG_TYPE_GUEST, 5, get_emuld_connection(), NULL);
223     return true;
224 }
225
226 static bool injector_req_location(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
227 {
228     if (msg->data.data != NULL && msg->data.len > 0) {
229         qemu_mutex_lock(&mutex_location_data);
230         snprintf(location_data, msg->data.len + 1, "%s", (char*)msg->data.data);
231         qemu_mutex_unlock(&mutex_location_data);
232         return injector_send(ccli, msg, cmd);
233     }
234
235     return false;
236 }
237
238 bool msgproc_injector_req(ECS_Client* ccli, ECS__InjectorReq* msg)
239 {
240     char cmd[11];
241     bool ret = false;
242
243     strncpy(cmd, msg->category, sizeof(cmd) - 1);
244
245     if (!strcmp(cmd, MSG_TYPE_SENSOR)) {
246         ret = injector_req_sensor(ccli, msg, cmd);
247     } else if (!strcmp(cmd, MSG_TYPE_GUEST)) {
248         ret = injector_req_guest();
249     } else if (!strcmp(cmd, MSG_TYPE_LOCATION)) {
250         ret = injector_req_location(ccli, msg, cmd);
251     } else {
252         ret = injector_send(ccli, msg, cmd);
253     }
254
255     return ret;
256 }
257
258 void ecs_suspend_lock_state(int state)
259 {
260     int catlen;
261
262     ECS__InjectorReq msg = ECS__INJECTOR_REQ__INIT;
263     const char* category = "suspend";
264
265     catlen = strlen(category);
266     msg.category = (char*) g_malloc0(catlen + 1);
267     memcpy(msg.category, category, catlen);
268
269     msg.group = 5;
270     msg.action = state;
271
272     msgproc_injector_req(NULL, &msg);
273 }
274
275 static void send_hds_mount_request(char* list)
276 {
277     int len = 0;
278     char token[] = ",";
279     char emuld_data [OUT_BUF_SIZE];
280     char* id;
281     char* host;
282     char* guest;
283
284     LOG_INFO("handling mount request: %s\n", list);
285
286     id = strtok(list, token);
287     if (id == NULL) {
288         LOG_SEVERE("cannot send mount request because of id\n");
289         return;
290     }
291
292     host = strtok(NULL, token);
293     if (host == NULL) {
294         LOG_SEVERE("cannot send mount request because of host\n");
295         return;
296     }
297
298     guest = strtok(NULL, token);
299     if (guest == NULL) {
300         LOG_SEVERE("cannot send mount request because of guest\n");
301         return;
302     }
303
304     len = snprintf(emuld_data, sizeof(emuld_data), "%s\n%s\n", id, guest);
305     send_msg_to_guest(MSG_TYPE_HDS, MSG_GROUP_HDS, HDS_ACTION_MOUNT, emuld_data, len + 1);
306 }
307
308 static void* hds_mount_request_thread(void* args)
309 {
310     char* list = (char*)args;
311     char token[] = "\n";
312     char* hds_list;
313
314     hds_list = strtok(list, token);
315     if (hds_list == NULL) {
316         LOG_INFO("no hds mount request\n");
317         free(list);
318         return NULL;
319     }
320
321     send_hds_mount_request(hds_list);
322
323     while((hds_list = strtok(NULL, token)) != NULL) {
324         send_hds_mount_request(hds_list);
325     }
326
327     free(list);
328     return NULL;
329 }
330
331 #define MSG_GROUP_HDS   100
332 static void do_hds(char* cat, type_action action, const char* data)
333 {
334     FsDriverEntry *entry;
335     char msg [OUT_BUF_SIZE];
336     char *host;
337     char *guest;
338     char* list;
339
340     LOG_INFO("hds status is %d, %s\n", action, data);
341     switch (action) {
342         case 0: // get list from devices
343             list = get_hds_lists();
344             if (strlen(list) == 0) {
345                 LOG_INFO("none of mount candidates available.\n");
346                 break;
347             }
348             qemu_thread_create(&hds_thread_id, "hds_mount", hds_mount_request_thread, (void*)list, QEMU_THREAD_DETACHED);
349             break;
350         case 99: // add list for default hds
351             entry = get_fsdev_fsentry((char*)DEFAULT_STATIC_HDS_ID);
352             if (entry == NULL) {
353                 LOG_SEVERE("cannot find fsdev entry.\n");
354                 break;
355             }
356
357             if (!add_hds_list(DEFAULT_STATIC_HDS_ID, entry->path, DEFAULT_HDS_GUEST_PATH)) {
358                 LOG_SEVERE("cannot add into hds list.\n");
359                 break;
360             }
361
362             set_hds_attached(DEFAULT_STATIC_HDS_ID, true);
363             data = DEFAULT_STATIC_HDS_ID;
364
365             // pass-through
366         case 1: // mount success
367             if (data == NULL) {
368                 LOG_SEVERE("error: hds data is null.\n");
369                 break;
370             }
371             host = get_host_path_by_id((char*)data);
372             if (host == NULL)
373                 LOG_SEVERE("get_host_path_by_id failed with %s, %s\n", data, host);
374             guest = get_guest_path_by_id((char*)data);
375             if (guest == NULL)
376                 LOG_SEVERE("get_guest_path_by_id failed with %s, %s\n", data, guest);
377             snprintf(msg, sizeof(msg), "%s,%s,%s", data, host, guest);
378             make_send_device_ntf(cat, MSG_GROUP_HDS, action, msg);
379             break;
380         case 2: // mount failed.
381         case 11: // not exist on the possible path
382         case 12: // not a vaild path
383             if (data == NULL) {
384                 LOG_SEVERE("error: hds data is null.\n");
385                 break;
386             }
387             remove_hds_list((char*)data);
388             do_hotplug(DETACH_HDS, (char*)data, strlen(data) + 1);
389             make_send_device_ntf(cat, MSG_GROUP_HDS, action, (char*)data);
390             break;
391         case 3: // unmount success
392             if (data == NULL) {
393                 LOG_SEVERE("error: hds data is null.\n");
394                 break;
395             }
396             do_hotplug(DETACH_HDS, (char*)data, strlen(data) + 1);
397             make_send_device_ntf(cat, MSG_GROUP_HDS, action, (char*)data);
398             break;
399         case 4: // unmount failed.
400             if (data == NULL) {
401                 LOG_SEVERE("error: hds data is null.\n");
402                 break;
403             }
404             make_send_device_ntf(cat, MSG_GROUP_HDS, action, (char*)data);
405             break;
406         default:
407             LOG_SEVERE("unknown action: %s.\n", action);
408             break;
409     }
410 }
411
412 static bool do_push_package(char* cmd)
413 {
414     char buf[MAX_PKGS_LIST];
415     FILE* fp = popen(cmd, "r");
416     if (fp == NULL) {
417         LOG_SEVERE("Failed to popen push packages\n");
418         return false;
419     }
420
421     memset(buf, 0, sizeof(buf));
422     while(fgets(buf, sizeof(buf), fp) != NULL) {
423         LOG_INFO("[pkgs]%s\n", buf);
424         if (!strncmp(buf, "error", 5)){
425             pclose(fp);
426             return false;
427         }
428         memset(buf, 0, sizeof(buf));
429     }
430
431     pclose(fp);
432     return true;
433 }
434
435 static bool push_package(const char* data)
436 {
437     int index = 0;
438     int ret = 0;
439     char cmd[MAX_PKGS_LIST];
440     char token[] = ", ";
441 #ifndef CONFIG_WIN32
442     const char* sdb_path = "../../../../../tools/sdb";
443     const char* platform_path = "../../../";
444     const char* addon_path = "/emulator-images/add-ons/";
445 #else
446     const char* sdb_path = "..\\..\\..\\..\\..\\tools\\sdb.exe";
447     const char* platform_path = "..\\..\\..\\";
448     const char* addon_path = "\\emulator-images\\add-ons\\";
449 #endif
450     const char* bin_dir = get_bin_path();
451
452     memset(cmd, 0, sizeof(cmd));
453
454     char* addon = strtok((char*)data, token);
455 #ifndef CONFIG_WIN32
456     ret = sprintf(cmd, "\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /opt/usr/apps/tmp/sdk_tools/%s 2>&1",
457 #else
458     ret = sprintf(cmd, "cmd /S /C \"\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /opt/usr/apps/tmp/sdk_tools/%s 2>&1\"",
459 #endif
460             bin_dir, sdb_path, get_device_serial_number(),
461             bin_dir, platform_path, get_profile_name(), addon_path, addon,
462             addon);
463     if (ret < 0) {
464         LOG_SEVERE("SDB push command is wrong: %s\n", cmd);
465         return false;
466     }
467
468     LOG_INFO("[pkgs] SDB push command: %s\n", cmd);
469
470     if (do_push_package(cmd)) {
471         LOG_INFO("[pkgs] SDB push SUCCESS\n");
472         return true;
473     }
474
475     /*
476      * FIXME: unnecessary sdb connection waiting sleep.
477      *        If SDB runs faster, it should be changed/removed.
478      */
479     while(!get_sdb_connection() && index != MAX_SDB_TRIAL) {
480         LOG_INFO("[pkgs] Waiting SDB connection...%d\n", index + 1);
481 #ifdef CONFIG_WIN32
482         Sleep(SLEEP_WAIT_SDB);
483 #else
484         usleep(SLEEP_WAIT_SDB * 1000);
485 #endif
486         index++;
487     }
488
489     index = 0;
490 #ifdef CONFIG_WIN32
491     Sleep(SLEEP_WAIT_SDB);
492 #else
493     usleep(SLEEP_WAIT_SDB * 1000);
494 #endif
495
496     while(index != MAX_SDB_TRIAL) {
497         if (do_push_package(cmd)) {
498             LOG_INFO("[pkgs] SDB push SUCCESS.\n");
499             return true;
500         }
501         LOG_INFO("[pkgs] Try to send package ...%d\n", index + 1);
502         index++;
503 #ifdef CONFIG_WIN32
504         Sleep(SLEEP_CONNECT_SDB);
505 #else
506         usleep(SLEEP_CONNECT_SDB * 1000);
507 #endif
508     }
509
510     return false;
511 }
512
513 static void show_error_popup(char* data)
514 {
515     char fail_msg[MAX_PKGS_LIST];
516     char token[] = ", ";
517     char* addon = strtok(data, token);
518
519     memset(fail_msg, 0, sizeof(fail_msg));
520     strcpy(fail_msg, FAILED_TO_INSTALL_EXTRAPACKAGE_1);
521     strcat(fail_msg, addon);
522     strcat(fail_msg, FAILED_TO_INSTALL_EXTRAPACKAGE_2);
523
524     error_report("%s", fail_msg);
525 }
526
527 static void* push_pkgs_thread(void* args)
528 {
529     char* pkg_data = (char*)args;
530     char* data = strdup(pkg_data);
531     if (pkg_data == NULL || data == NULL) {
532         LOG_SEVERE("pkg data strdup is failed.\n");
533         return NULL;
534     }
535
536     if (!push_package(pkg_data)) {
537         LOG_SEVERE("file upload is failed. %s\n", data);
538         show_error_popup(data);
539         free(pkg_data);
540         free(data);
541         return NULL;
542     }
543
544     // request to install rpms
545     LOG_INFO("[pkgs] Request to install : %s\n", data);
546     send_msg_to_guest(MSG_TYPE_PACKAGE, 0, 2, data, strlen(data) + 1);
547
548     free(pkg_data);
549     free(data);
550
551     return NULL;
552 }
553
554 static void do_package(char* cat, type_action action, const char* data)
555 {
556     if (data == NULL || strlen(data) <= 0) {
557         LOG_SEVERE("data is corrupted.\n");
558         return;
559     }
560
561     if (action == 1) {
562         LOG_INFO("[pkgs] Already installed: %s\n", data);
563     } else if (action == 2) {
564         LOG_INFO("[pkgs] Needed to install: %s\n", data);
565         char* pkgs = g_malloc0(MAX_PKGS_LIST);
566         strncpy(pkgs, data, MAX_PKGS_LIST - 1);
567         qemu_thread_create(&sdb_thread_id, "sdb_push", push_pkgs_thread, (void*)pkgs, QEMU_THREAD_DETACHED);
568     } else if (action == 3) {
569         LOG_INFO("[pkgs] Package Installation Success: %s\n", data);
570     } else if (action == 4) {
571         LOG_INFO("[pkgs] Package Installation Failed: %s\n", data);
572         show_error_popup((char*)data);
573     } else {
574         LOG_SEVERE("unknown pkgs action: %d\n", action);
575     }
576 }
577
578 static bool injector_req_handle(char* cat, type_action action, const char* data)
579 {
580     int state = 0;
581     if (!strcmp(cat, "suspend")) {
582         state = ecs_get_suspend_state();
583         LOG_INFO("send suspend lock state : %d\n", state);
584         ecs_suspend_lock_state(state);
585         return true;
586     } else if (!strcmp(cat, "boot")) {
587         LOG_INFO("emulator booting done.\n");
588         set_emulator_condition(BOOT_COMPLETED);
589         return true;
590     } else if (!strcmp(cat, MSG_TYPE_GUEST)) {
591         LOG_INFO("emuld connection is %d\n", action);
592         set_emuld_connection(action);
593     } else if (!strcmp(cat, "hds")) {
594         do_hds(cat, action, data);
595         return true;
596     } else if (!strcmp(cat, MSG_TYPE_PACKAGE)) {
597         do_package(cat, action, data);
598         return true;
599     } else if (!strcmp(cat, MSG_TYPE_GUESTIP)) {
600         if (data != NULL && strlen(data) > 0) {
601             LOG_INFO("guest ip: %s\n", data);
602             set_emul_guest_ip((char*)data);
603         } else {
604             LOG_SEVERE("guest ip is null!\n");
605         }
606         return true;
607     }
608     return false;
609 }
610
611 bool send_injector_ntf(const char* data, const int len)
612 {
613     type_length length = 0;
614     type_group group = 0;
615     type_action action = 0;
616
617     const int catsize = 10;
618     char cat[catsize + 1];
619     memset(cat, 0, catsize + 1);
620
621     read_val_str(data, cat, catsize);
622     read_val_short(data + catsize, &length);
623     read_val_char(data + catsize + 2, &group);
624     read_val_char(data + catsize + 2 + 1, &action);
625
626     const char* ijdata = (data + catsize + 2 + 1 + 1);
627
628     if (!is_ecs_running()) {
629         LOG_SEVERE("ECS is not running.\n");
630         return false;
631     }
632
633     if (injector_req_handle(cat, action, ijdata)) {
634         return true;
635     }
636
637     LOG_TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length,action, group);
638
639     ECS__Master master = ECS__MASTER__INIT;
640     ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
641
642     ntf.category = (char*) g_malloc(catsize + 1);
643     strncpy(ntf.category, cat, 10);
644
645     ntf.length = length;
646     ntf.group = group;
647     ntf.action = action;
648
649     if (length > 0)
650     {
651         ntf.has_data = 1;
652
653         ntf.data.data = g_malloc(length);
654         ntf.data.len = length;
655         memcpy(ntf.data.data, ijdata, length);
656     }
657
658     master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
659     master.injector_ntf = &ntf;
660
661     pb_to_all_clients(&master);
662
663     if (ntf.data.len > 0)
664     {
665         g_free(ntf.data.data);
666     }
667
668     g_free(ntf.category);
669
670     return true;
671 }
672