1 /* Emulator Control Server
3 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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>
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.
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.
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.
33 #include "qemu-common.h"
34 #include "fsdev/qemu-fsdev.h"
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"
41 #include "util/device_hotplug.h"
43 #include "emul_state.h"
46 #include "util/osutil.h"
47 #include "util/exported_strings.h"
49 MULTI_DEBUG_CHANNEL(qemu, ecs);
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
56 static QemuThread sdb_thread_id;
57 static QemuThread hds_thread_id;
59 extern QemuMutex mutex_location_data;
60 static char location_data[MAX_INJECTOR_REQ_DATA];
62 static void msgproc_injector_ans(ECS_Client* ccli, const char* category, bool succeed)
68 ECS__Master master = ECS__MASTER__INIT;
69 ECS__InjectorAns ans = ECS__INJECTOR_ANS__INIT;
71 LOG_TRACE("injector ans - category : %s, succed : %d\n", category, succeed);
73 catlen = strlen(category);
74 ans.category = (char*) g_malloc0(catlen + 1);
75 memcpy(ans.category, category, catlen);
77 ans.errcode = !succeed;
78 master.type = ECS__MASTER__TYPE__INJECTOR_ANS;
79 master.injector_ans = &ans;
81 pb_to_all_clients(&master);
87 static bool injector_send(ECS_Client* ccli, ECS__InjectorReq* msg, char* cmd)
89 int sndlen = 15; // HEADER(CMD + LENGTH + GROUP + ACTION) + 1
95 group = (type_group) (msg->group & 0xff);
97 if (msg->has_data && msg->data.data && msg->data.len > 0)
98 sndlen += msg->data.len;
100 sndbuf = (char*) g_malloc0(sndlen);
102 msgproc_injector_ans(ccli, cmd, false);
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);
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);
117 if(strcmp(cmd, "telephony") == 0) {
118 LOG_TRACE("telephony msg >>");
119 ret = send_to_vmodem(route_ij, sndbuf, sndlen);
121 LOG_TRACE("evdi msg >> %s", cmd);
122 ret = send_to_evdi(route_ij, sndbuf, sndlen);
127 if (group != MSG_GROUP_STATUS) {
128 msgproc_injector_ans(ccli, cmd, ret);
138 static void send_status_injector_ntf(const char* cmd, int cmdlen, int act, char* on)
140 int msglen = 0, datalen = 0;
141 type_length length = 0;
142 type_group group = MSG_GROUP_STATUS;
143 type_action action = act;
145 if (cmd == NULL || cmdlen > 10)
151 datalen = strlen(on);
152 length = (unsigned short)datalen;
154 msglen = datalen + 15;
157 char* status_msg = (char*) malloc(msglen);
161 memset(status_msg, 0, msglen);
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));
169 memcpy(status_msg + 14, on, datalen);
172 send_injector_ntf(status_msg, msglen);
177 static bool injector_req_sensor(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
179 char data[MAX_INJECTOR_REQ_DATA];
183 memset(data, 0, MAX_INJECTOR_REQ_DATA);
184 group = (type_group) (msg->group & 0xff);
185 action = (type_action) (msg->action & 0xff);
187 if (group == MSG_GROUP_STATUS) {
189 case MSG_ACT_BATTERY_LEVEL:
190 sprintf(data, "%d", get_power_capacity());
192 case MSG_ACT_BATTERY_CHARGER:
193 sprintf(data, "%d", get_jack_charger());
196 sprintf(data, "%d", get_jack_usb());
198 case MSG_ACT_EARJACK:
199 sprintf(data, "%d", get_jack_earjack());
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);
207 return injector_send(ccli, msg, cmd);
209 LOG_TRACE("status : %s\n", data);
210 send_status_injector_ntf(MSG_TYPE_SENSOR, 6, action, data);
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);
220 static bool injector_req_guest(void)
222 send_status_injector_ntf(MSG_TYPE_GUEST, 5, get_emuld_connection(), NULL);
226 static bool injector_req_location(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
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);
238 bool msgproc_injector_req(ECS_Client* ccli, ECS__InjectorReq* msg)
243 strncpy(cmd, msg->category, sizeof(cmd) - 1);
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);
252 ret = injector_send(ccli, msg, cmd);
258 void ecs_suspend_lock_state(int state)
262 ECS__InjectorReq msg = ECS__INJECTOR_REQ__INIT;
263 const char* category = "suspend";
265 catlen = strlen(category);
266 msg.category = (char*) g_malloc0(catlen + 1);
267 memcpy(msg.category, category, catlen);
272 msgproc_injector_req(NULL, &msg);
275 static void send_hds_mount_request(char* list)
279 char emuld_data [OUT_BUF_SIZE];
284 LOG_INFO("handling mount request: %s\n", list);
286 id = strtok(list, token);
288 LOG_SEVERE("cannot send mount request because of id\n");
292 host = strtok(NULL, token);
294 LOG_SEVERE("cannot send mount request because of host\n");
298 guest = strtok(NULL, token);
300 LOG_SEVERE("cannot send mount request because of guest\n");
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);
308 static void* hds_mount_request_thread(void* args)
310 char* list = (char*)args;
314 hds_list = strtok(list, token);
315 if (hds_list == NULL) {
316 LOG_INFO("no hds mount request\n");
321 send_hds_mount_request(hds_list);
323 while((hds_list = strtok(NULL, token)) != NULL) {
324 send_hds_mount_request(hds_list);
331 #define MSG_GROUP_HDS 100
332 static void do_hds(char* cat, type_action action, const char* data)
334 FsDriverEntry *entry;
335 char msg [OUT_BUF_SIZE];
340 LOG_INFO("hds status is %d, %s\n", action, data);
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");
348 qemu_thread_create(&hds_thread_id, "hds_mount", hds_mount_request_thread, (void*)list, QEMU_THREAD_DETACHED);
350 case 99: // add list for default hds
351 entry = get_fsdev_fsentry((char*)DEFAULT_STATIC_HDS_ID);
353 LOG_SEVERE("cannot find fsdev entry.\n");
357 if (!add_hds_list(DEFAULT_STATIC_HDS_ID, entry->path, DEFAULT_HDS_GUEST_PATH)) {
358 LOG_SEVERE("cannot add into hds list.\n");
362 set_hds_attached(DEFAULT_STATIC_HDS_ID, true);
363 data = DEFAULT_STATIC_HDS_ID;
366 case 1: // mount success
368 LOG_SEVERE("error: hds data is null.\n");
371 host = get_host_path_by_id((char*)data);
373 LOG_SEVERE("get_host_path_by_id failed with %s, %s\n", data, host);
374 guest = get_guest_path_by_id((char*)data);
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);
380 case 2: // mount failed.
381 case 11: // not exist on the possible path
382 case 12: // not a vaild path
384 LOG_SEVERE("error: hds data is null.\n");
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);
391 case 3: // unmount success
393 LOG_SEVERE("error: hds data is null.\n");
396 do_hotplug(DETACH_HDS, (char*)data, strlen(data) + 1);
397 make_send_device_ntf(cat, MSG_GROUP_HDS, action, (char*)data);
399 case 4: // unmount failed.
401 LOG_SEVERE("error: hds data is null.\n");
404 make_send_device_ntf(cat, MSG_GROUP_HDS, action, (char*)data);
407 LOG_SEVERE("unknown action: %s.\n", action);
412 static bool do_push_package(char* cmd)
414 char buf[MAX_PKGS_LIST];
415 FILE* fp = popen(cmd, "r");
417 LOG_SEVERE("Failed to popen push packages\n");
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)){
428 memset(buf, 0, sizeof(buf));
435 static bool push_package(const char* data)
439 char cmd[MAX_PKGS_LIST];
442 const char* sdb_path = "../../../../../tools/sdb";
443 const char* platform_path = "../../../";
444 const char* addon_path = "/emulator-images/add-ons/";
446 const char* sdb_path = "..\\..\\..\\..\\..\\tools\\sdb.exe";
447 const char* platform_path = "..\\..\\..\\";
448 const char* addon_path = "\\emulator-images\\add-ons\\";
450 const char* bin_dir = get_bin_path();
452 memset(cmd, 0, sizeof(cmd));
454 char* addon = strtok((char*)data, token);
456 ret = sprintf(cmd, "\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /opt/usr/apps/tmp/sdk_tools/%s 2>&1",
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\"",
460 bin_dir, sdb_path, get_device_serial_number(),
461 bin_dir, platform_path, get_profile_name(), addon_path, addon,
464 LOG_SEVERE("SDB push command is wrong: %s\n", cmd);
468 LOG_INFO("[pkgs] SDB push command: %s\n", cmd);
470 if (do_push_package(cmd)) {
471 LOG_INFO("[pkgs] SDB push SUCCESS\n");
476 * FIXME: unnecessary sdb connection waiting sleep.
477 * If SDB runs faster, it should be changed/removed.
479 while(!get_sdb_connection() && index != MAX_SDB_TRIAL) {
480 LOG_INFO("[pkgs] Waiting SDB connection...%d\n", index + 1);
482 Sleep(SLEEP_WAIT_SDB);
484 usleep(SLEEP_WAIT_SDB * 1000);
491 Sleep(SLEEP_WAIT_SDB);
493 usleep(SLEEP_WAIT_SDB * 1000);
496 while(index != MAX_SDB_TRIAL) {
497 if (do_push_package(cmd)) {
498 LOG_INFO("[pkgs] SDB push SUCCESS.\n");
501 LOG_INFO("[pkgs] Try to send package ...%d\n", index + 1);
504 Sleep(SLEEP_CONNECT_SDB);
506 usleep(SLEEP_CONNECT_SDB * 1000);
513 static void show_error_popup(char* data)
515 char fail_msg[MAX_PKGS_LIST];
517 char* addon = strtok(data, token);
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);
524 error_report("%s", fail_msg);
527 static void* push_pkgs_thread(void* args)
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");
536 if (!push_package(pkg_data)) {
537 LOG_SEVERE("file upload is failed. %s\n", data);
538 show_error_popup(data);
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);
554 static void do_package(char* cat, type_action action, const char* data)
556 if (data == NULL || strlen(data) <= 0) {
557 LOG_SEVERE("data is corrupted.\n");
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);
574 LOG_SEVERE("unknown pkgs action: %d\n", action);
578 static bool injector_req_handle(char* cat, type_action action, const char* data)
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);
586 } else if (!strcmp(cat, "boot")) {
587 LOG_INFO("emulator booting done.\n");
588 set_emulator_condition(BOOT_COMPLETED);
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);
596 } else if (!strcmp(cat, MSG_TYPE_PACKAGE)) {
597 do_package(cat, action, data);
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);
604 LOG_SEVERE("guest ip is null!\n");
611 bool send_injector_ntf(const char* data, const int len)
613 type_length length = 0;
614 type_group group = 0;
615 type_action action = 0;
617 const int catsize = 10;
618 char cat[catsize + 1];
619 memset(cat, 0, catsize + 1);
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);
626 const char* ijdata = (data + catsize + 2 + 1 + 1);
628 if (!is_ecs_running()) {
629 LOG_SEVERE("ECS is not running.\n");
633 if (injector_req_handle(cat, action, ijdata)) {
637 LOG_TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length,action, group);
639 ECS__Master master = ECS__MASTER__INIT;
640 ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
642 ntf.category = (char*) g_malloc(catsize + 1);
643 strncpy(ntf.category, cat, 10);
653 ntf.data.data = g_malloc(length);
654 ntf.data.len = length;
655 memcpy(ntf.data.data, ijdata, length);
658 master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
659 master.injector_ntf = &ntf;
661 pb_to_all_clients(&master);
663 if (ntf.data.len > 0)
665 g_free(ntf.data.data);
668 g_free(ntf.category);