1 /* Emulator Control Server
3 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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>
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.
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.
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.
34 #include "qemu/osdep.h"
35 #include "qemu-common.h"
36 #include "qemu/error-report.h"
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"
43 #include "emul_state.h"
45 #include "ecs_sensor.h"
47 #include "util/osutil.h"
48 #include "util/exported_strings.h"
50 MULTI_DEBUG_CHANNEL(qemu, ecs);
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 */
57 static QemuThread sdb_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);
86 static bool injector_send(ECS_Client *ccli, ECS__InjectorReq *msg, char *cmd)
88 int sndlen = 15; /* HEADER(CMD + LENGTH + GROUP + ACTION) + 1 */
94 group = (type_group) (msg->group & 0xff);
96 if (msg->has_data && msg->data.data && msg->data.len > 0) {
97 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 >>\n");
119 ret = send_to_vmodem(route_ij, sndbuf, sndlen);
121 LOG_TRACE("evdi msg >> %s\n", 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) {
152 datalen = strlen(on);
153 length = (unsigned short)datalen;
155 msglen = datalen + 15;
158 char *status_msg = (char *) malloc(msglen);
163 memset(status_msg, 0, msglen);
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));
171 memcpy(status_msg + 14, on, datalen);
174 send_injector_ntf(status_msg, msglen);
179 static bool injector_req_sensor(ECS_Client *ccli, ECS__InjectorReq *msg, char *cmd)
181 char data[MAX_INJECTOR_REQ_DATA];
185 memset(data, 0, MAX_INJECTOR_REQ_DATA);
186 group = (type_group) (msg->group & 0xff);
187 action = (type_action) (msg->action & 0xff);
189 if (group == MSG_GROUP_STATUS) {
191 case MSG_ACT_BATTERY_LEVEL:
192 sprintf(data, "%d", get_power_capacity());
194 case MSG_ACT_BATTERY_CHARGER:
195 sprintf(data, "%d", get_jack_charger());
198 sprintf(data, "%d", get_jack_usb());
200 case MSG_ACT_EARJACK:
201 sprintf(data, "%d", get_jack_earjack());
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);
209 return injector_send(ccli, msg, cmd);
211 LOG_TRACE("status : %s\n", data);
212 send_status_injector_ntf(MSG_TYPE_SENSOR, 6, action, data);
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);
222 static bool injector_req_guest(void)
224 send_status_injector_ntf(MSG_TYPE_GUEST, 5, get_emuld_connection(), NULL);
228 static bool injector_req_location(ECS_Client *ccli, ECS__InjectorReq *msg, char *cmd)
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);
240 bool msgproc_injector_req(ECS_Client *ccli, ECS__InjectorReq *msg)
245 strncpy(cmd, msg->category, sizeof(cmd) - 1);
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);
254 ret = injector_send(ccli, msg, cmd);
260 void ecs_suspend_lock_state(int state)
264 ECS__InjectorReq msg = ECS__INJECTOR_REQ__INIT;
265 const char *category = "suspend";
267 catlen = strlen(category);
268 msg.category = (char *) g_malloc0(catlen + 1);
269 memcpy(msg.category, category, catlen);
274 msgproc_injector_req(NULL, &msg);
277 static bool do_push_package(char *cmd)
279 char buf[MAX_PKGS_LIST];
280 FILE *fp = popen(cmd, "r");
282 LOG_SEVERE("Failed to popen push packages\n");
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)) {
293 memset(buf, 0, sizeof(buf));
300 static bool push_package(const char *data)
304 char cmd[MAX_PKGS_LIST];
307 const char *sdb_path = "../../../../../tools/sdb";
308 const char *platform_path = "../../../";
309 const char *addon_path = "/emulator-images/add-ons/";
311 const char *sdb_path = "..\\..\\..\\..\\..\\tools\\sdb.exe";
312 const char *platform_path = "..\\..\\..\\";
313 const char *addon_path = "\\emulator-images\\add-ons\\";
315 const char *bin_dir = get_bin_path();
317 memset(cmd, 0, sizeof(cmd));
319 char *addon = strtok((char *)data, token);
321 ret = sprintf(cmd, "\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /tmp/.emulator/apps/%s 2>&1",
323 ret = sprintf(cmd, "cmd /S /C \"\"%s%s\" -s emulator-%d push \"%s%s%s%s%s\" /tmp/.emulator/apps/%s 2>&1\"",
325 bin_dir, sdb_path, get_vm_device_serial_number(),
326 bin_dir, platform_path, get_profile_name(), addon_path, addon,
329 LOG_SEVERE("SDB push command is wrong: %s\n", cmd);
333 LOG_INFO("[pkgs] SDB push command: %s\n", cmd);
335 if (do_push_package(cmd)) {
336 LOG_INFO("[pkgs] SDB push SUCCESS\n");
341 * FIXME: unnecessary sdb connection waiting sleep.
342 * If SDB runs faster, it should be changed/removed.
344 while (!get_sdb_connection() && index != MAX_SDB_TRIAL) {
345 LOG_INFO("[pkgs] Waiting SDB connection...%d\n", index + 1);
347 Sleep(SLEEP_WAIT_SDB);
349 usleep(SLEEP_WAIT_SDB * 1000);
356 Sleep(SLEEP_WAIT_SDB);
358 usleep(SLEEP_WAIT_SDB * 1000);
361 while (index != MAX_SDB_TRIAL) {
362 if (do_push_package(cmd)) {
363 LOG_INFO("[pkgs] SDB push SUCCESS.\n");
366 LOG_INFO("[pkgs] Try to send package ...%d\n", index + 1);
369 Sleep(SLEEP_CONNECT_SDB);
371 usleep(SLEEP_CONNECT_SDB * 1000);
378 static void show_error_popup(char *data)
380 char fail_msg[MAX_PKGS_LIST];
382 char *addon = strtok(data, token);
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);
389 error_report("%s", fail_msg);
392 static void *push_pkgs_thread(void *args)
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");
401 if (!push_package(pkg_data)) {
402 LOG_SEVERE("file upload is failed. %s\n", data);
403 show_error_popup(data);
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);
419 static void do_package(char *cat, type_action action, const char *data)
421 if (data == NULL || strlen(data) <= 0) {
422 LOG_SEVERE("data is corrupted.\n");
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);
439 LOG_SEVERE("unknown pkgs action: %d\n", action);
443 static bool injector_req_handle(char *cat, type_action action, const char *data)
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);
451 } else if (!strcmp(cat, "boot")) {
452 LOG_INFO("emulator booting done.\n");
453 set_emulator_condition(BOOT_COMPLETED);
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")) {
460 msgproc_injector_do_hds(cat, action, data);
463 LOG_WARNING("VirtFS is not enabled.\n");
466 } else if (!strcmp(cat, MSG_TYPE_CAP)) {
467 LOG_INFO("set capabilities: %s\n", data);
468 ecs_set_device_capabilities(data);
470 } else if (!strcmp(cat, MSG_TYPE_PACKAGE)) {
471 do_package(cat, action, data);
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);
478 LOG_SEVERE("guest ip is null!\n");
485 bool send_injector_ntf(const char *data, const int len)
487 type_length length = 0;
488 type_group group = 0;
489 type_action action = 0;
491 const int catsize = 10;
492 char cat[catsize + 1];
493 memset(cat, 0, catsize + 1);
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);
500 const char *ijdata = (data + catsize + 2 + 1 + 1);
502 if (!is_ecs_running()) {
503 LOG_SEVERE("ECS is not running.\n");
507 if (injector_req_handle(cat, action, ijdata)) {
511 LOG_TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length, action, group);
513 ECS__Master master = ECS__MASTER__INIT;
514 ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
516 ntf.category = (char *) g_malloc(catsize + 1);
517 strncpy(ntf.category, cat, 10);
526 ntf.data.data = g_malloc(length);
527 ntf.data.len = length;
528 memcpy(ntf.data.data, ijdata, length);
531 master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
532 master.injector_ntf = &ntf;
534 pb_to_all_clients(&master);
536 if (ntf.data.len > 0) {
537 g_free(ntf.data.data);
540 g_free(ntf.category);