b1b7c97ad11c9f59874c305f16fa9b7ca2a8518e
[platform/core/multimedia/mmsvc-core.git] / server / src / muse_server_private.c
1 /*
2  * muse-server
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include "muse_server_private.h"
23 #include <sys/file.h>
24 #include <sys/syscall.h>
25 #include <gst/gst.h>
26 #include <syslog.h>
27 #include <tzplatform_config.h>
28
29 #if !GLIB_CHECK_VERSION(2, 58, 0)
30 #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
31 #endif
32
33 #ifdef MUSE_REGISTER_VIP
34 #include <proc_stat.h>
35 #endif
36
37 #ifdef MUSE_USE_LWIPC
38 #include <lwipc.h>
39 #define MUSE_LWIPC_WAIT_TIME                    1000
40 #endif
41
42
43 static const char *channel_name[MUSE_CHANNEL_MAX] = {
44         "msg",
45         "data"
46 };
47
48 static const char *UDS_files[MUSE_CHANNEL_MAX] = {MUSE_MSG_SOCK, MUSE_DATA_SOCK};
49
50 static muse_server_h muse_server;
51
52 static const char *module_cmd[MUSE_MODULE_COMMAND_MAX] = {
53         "initialize",
54         "shutdown",
55         "debug_info_dump",
56         "create_server_ack",
57         "resource_not_available",
58         "external_storage_state_changed",
59         "create_caution",
60         "resource_manager_shutdown"
61 };
62
63 static bool _ms_attach(int fd, muse_module_callback connection_handler, gpointer module_idx);
64 static void _ms_create_new_server_from_fd(int fd[], int type);
65 static int _ms_new(muse_channel_e channel);
66 static int _ms_get_pid(int fd);
67 static void _ms_get_module_addr(int fd, intptr_t *module_addr);
68 static void _ms_check_idle_state(void);
69 static gpointer _ms_diag_check_idle_state_thread(gpointer data);
70 static gpointer _ms_diag_check_connection_event_thread(gpointer data);
71 static void _ms_lock_state(void);
72 static void _ms_unlock_state(void);
73 static gboolean _ms_connection_handler(GIOChannel *source, GIOCondition condition, gpointer data);
74 #ifdef MUSE_USE_LWIPC
75 static void _ms_wait_event(void);
76 static void _ms_diag_init(void);
77 static void _ms_diag_deinit(void);
78 static gboolean _ms_idle_cb(gpointer user_data);
79 static int _ms_open_lockfile(void);
80
81 static void _ms_wait_event(void)
82 {
83         const char *lw_event_list[] = { "/run/.wm_ready", "/tmp/avoc_ready" };
84         unsigned int count = sizeof(lw_event_list) / sizeof(char *);
85
86         if (LwipcWaitMultiEvents(lw_event_list, count, true, MUSE_LWIPC_WAIT_TIME, NULL, 0) != 0)
87                 LOGE("Fail to receive Multiple Events");
88 }
89 #endif
90
91 static bool _ms_attach(int fd, muse_module_callback connection_handler, gpointer module_idx)
92 {
93         GIOChannel *channel = NULL;
94         GSource *src = NULL;
95
96         LOGI("Enter");
97
98         muse_return_val_if_fail(muse_server, false);
99         muse_return_val_if_fail(muse_core_fd_is_valid(fd), false);
100
101         channel = g_io_channel_unix_new(fd);
102         muse_return_val_if_fail(channel, false);
103
104         src = g_io_create_watch(channel, G_IO_IN);
105         if (!src) {
106                 LOGE("g_io_create_watch() is failed");
107                 g_io_channel_unref(channel);
108                 return false;
109         }
110
111         g_source_set_callback(src, G_SOURCE_FUNC(connection_handler), module_idx, NULL);
112
113         if (g_source_attach(src, g_main_loop_get_context(muse_server->main_loop)) == 0) {
114                 LOGE("g_source_attach() is failed");
115                 g_io_channel_unref(channel);
116                 return false;
117         }
118
119         g_source_unref(src);
120
121         g_io_channel_unref(channel);
122
123         LOGI("Leave");
124
125         return true;
126 }
127
128 static void _ms_create_new_server_from_fd(int fd[], int type)
129 {
130         int i;
131         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
132
133         LOGD("Enter");
134
135         muse_return_if_fail(muse_server);
136
137         muse_server->msg_fd = fd[MUSE_CHANNEL_MSG];
138         muse_server->data_fd = fd[MUSE_CHANNEL_DATA];
139         muse_server->type = type;
140
141         for (i = 0; i < MUSE_CHANNEL_MAX; i++) {
142                 if (!_ms_attach(fd[i], _ms_connection_handler, GINT_TO_POINTER(i))) {
143                         snprintf(err_msg, sizeof(err_msg), "Fail to attach server fd %d", fd[i]);
144
145                         LOGE("%s", err_msg);
146                         ms_terminate(SIGABRT);
147                 }
148         }
149
150         LOGD("Leave");
151 }
152
153 static int _ms_new(muse_channel_e channel)
154 {
155         int fd, errsv;
156         struct sockaddr_un addr_un;
157         socklen_t address_len;
158         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
159
160         muse_return_val_if_fail(channel < MUSE_CHANNEL_MAX, MM_ERROR_INVALID_ARGUMENT);
161
162         unlink(UDS_files[channel]);
163
164         /* Create Socket */
165         fd = socket(AF_UNIX, SOCK_STREAM, 0); /* Unix Domain Socket */
166         if (!muse_core_fd_is_valid(fd)) {
167                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
168                 LOGE("socket failed sock (%d) : %s", errno, err_msg);
169                 return MUSE_ERR;
170         }
171
172         LOGD("muse server fd : %d", fd);
173
174         memset(&addr_un, 0, sizeof(addr_un));
175         addr_un.sun_family = AF_UNIX;
176         strncpy(addr_un.sun_path, UDS_files[channel], sizeof(addr_un.sun_path) - 1);
177         address_len = sizeof(addr_un);
178
179         /* Bind to filename */
180         if (bind(fd, (struct sockaddr *)&addr_un, address_len) < 0) {
181                 errsv = errno;
182                 strerror_r(errsv, err_msg, MUSE_MSG_LEN_MAX);
183                 LOGE("[%d] socket bind failed (%d) %s", fd, errsv, err_msg);
184                 muse_core_log_file_list(UDS_files[channel]);
185                 ms_log_user_group_info();
186                 if (errsv == EADDRINUSE)
187                         unlink(addr_un.sun_path);
188                 close(fd);
189                 return MUSE_ERR;
190         }
191
192         /* Setup listen queue */
193         if (listen(fd, 5) == MUSE_ERR) {
194                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
195                 LOGE("[%d] listen() failed (%d) %s", fd, errno, err_msg);
196                 muse_core_log_file_list(UDS_files[channel]);
197                 ms_log_user_group_info();
198                 close(fd);
199                 return MUSE_ERR;
200         }
201
202         if (muse_core_set_nonblocking(fd, false) < 0) /* blocking */
203                 LOGE("failed to set server socket to blocking");
204
205         return fd;
206 }
207
208 static int _ms_get_pid(int fd)
209 {
210         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
211         struct ucred credentials;
212         socklen_t length;
213
214         length = sizeof(struct ucred);
215         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &length) < 0) {
216                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
217                 LOGE("failed to get the value of credential type %s", err_msg);
218                 return MUSE_ERR;
219         }
220
221         muse_core_update_fd_state(fd);
222
223         return credentials.pid;
224 }
225
226 static void _ms_get_module_addr(int fd, intptr_t *module_addr)
227 {
228         void *jobj;
229         int try_count = 0;
230         bool ret = true;
231         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
232         char recv_buf[MUSE_MSG_LEN_MAX] = {'\0',};
233
234         do {
235                 if (muse_core_msg_recv_fd(fd, recv_buf, MUSE_MSG_LEN_MAX, NULL) <= 0) {
236                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
237                         LOGE("failed to receive message for module %s", err_msg);
238                         return;
239                 }
240
241                 jobj = muse_core_msg_object_new(recv_buf, NULL, NULL);
242                 if (jobj) {
243                         ret = muse_core_msg_object_get_value(MSG_KEY_MODULE_ADDR, jobj, MUSE_TYPE_POINTER, module_addr);
244                         muse_core_msg_object_free(jobj);
245                         if (!ret)
246                                 LOGE("[%d] Error - module_addr %s", try_count, recv_buf);
247                         else
248                                 break;
249                 }
250         } while (++try_count < MS_RECV_TRY_COUNT_MAX);
251 }
252
253 static gboolean _ms_connection_handler(GIOChannel *source, GIOCondition condition, gpointer data)
254 {
255         int server_sockfd, client_sockfd, pid, idx, len;
256         socklen_t client_len;
257         struct sockaddr_un client_address;
258         muse_channel_e channel = GPOINTER_TO_INT(data);
259         muse_module_h m = NULL;
260         muse_module_h peeked_m = NULL;
261         muse_module_h candidate_m = NULL;
262         intptr_t module_addr = 0;
263         GQueue *instance_queue = NULL;
264         ms_connection_t *connection = NULL;
265         char time_buf[MUSE_MSG_TIME_LEN];
266
267         muse_return_val_if_fail(channel == MUSE_CHANNEL_MSG || channel == MUSE_CHANNEL_DATA, FALSE);
268
269         LOGI("Enter [%s channel]", channel_name[channel]);
270
271         muse_return_val_if_fail(muse_server, FALSE);
272
273         connection = muse_server->connection;
274         muse_return_val_if_fail(connection, FALSE);
275
276         _ms_lock_state();
277
278         if (!ms_is_server_ready()) {
279                 LOGW("Now mused state is not ready...");
280                 _ms_unlock_state();
281                 ms_terminate(SIGABRT);
282         }
283
284         server_sockfd = g_io_channel_unix_get_fd(source);
285         if (!muse_core_fd_is_valid(server_sockfd)) {
286                 LOGE("Critical Error : server %d is invalid", server_sockfd);
287                 _ms_unlock_state();
288                 muse_core_dump_fd_state(server_sockfd);
289                 ms_terminate(SIGABRT);
290         }
291
292         client_len = sizeof(client_address);
293
294         LOGI("[%d] Try to accept...", server_sockfd);
295         client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
296         if (!muse_core_fd_is_valid(client_sockfd)) {
297                 LOGE("Critical Error : accept %d is invalid", client_sockfd);
298                 muse_core_dump_fd_state(client_sockfd);
299                 close(server_sockfd);
300                 _ms_unlock_state();
301                 ms_terminate(SIGABRT);
302         }
303
304         LOGI("server : %d client [%s channel] : %d", server_sockfd, channel_name[channel], client_sockfd);
305
306         pid = _ms_get_pid(client_sockfd);
307
308         if (channel == MUSE_CHANNEL_MSG) {
309                 m = g_new0(muse_module_t, 1);
310                 SECURE_LOGI("module [%p]", m);
311                 m->ch[MUSE_CHANNEL_MSG].sock_fd = client_sockfd;
312                 m->pid = pid;
313                 g_mutex_init(&m->dispatch_lock);
314
315                 ms_ipc_create_msg_dispatch_worker(m);
316
317         } else {
318                 _ms_get_module_addr(client_sockfd, &module_addr);
319
320                 ms_connection_lock(connection);
321
322                 instance_queue = connection->instance_q;
323                 len = g_queue_get_length(instance_queue);
324
325                 m = (muse_module_h)module_addr;
326
327                 for (idx = 0; idx < len; idx++) {
328                         peeked_m = (muse_module_h)g_queue_peek_nth(instance_queue, idx);
329                         if (!peeked_m) {
330                                 LOGW("[%d] Make sure if the queue length is changed (%d = %d), which means that it was destroyed somewhere",
331                                         idx, len, g_queue_get_length(instance_queue));
332                                 continue;
333                         }
334
335                         if (peeked_m->pid != pid)
336                                 continue;
337
338                         if (!m) {
339                                 if (candidate_m) {
340                                         LOGE("muse-server can't support the error case which there are several modules now");
341                                         ms_connection_unlock(connection);
342                                         goto out;
343                                 }
344
345                                 if (!muse_core_fd_is_valid(peeked_m->ch[MUSE_CHANNEL_DATA].sock_fd))
346                                         candidate_m = peeked_m;
347                                 else
348                                         SECURE_LOGW("already paired module %p", peeked_m);
349
350                                 continue;
351                         }
352
353                         if (m != peeked_m)
354                                 continue;
355
356                         if (muse_core_fd_is_valid(m->ch[MUSE_CHANNEL_DATA].sock_fd)) {
357                                 SECURE_LOGE("[%d] %s pid %d %p you had better check if instance destroy completed properly",
358                                         client_sockfd, ms_config_get_host_name(m->idx), pid, m);
359                                 ms_connection_unlock(connection);
360                                 goto out;
361                         }
362
363                         m->ch[MUSE_CHANNEL_DATA].sock_fd = client_sockfd;
364                         SECURE_LOGI("%s (pid %d) module : %p module addr from client : %p",
365                                 ms_config_get_host_name(m->idx), pid, m, (void *)module_addr);
366                         break;
367                 }
368
369                 if (candidate_m) {
370                         m = candidate_m;
371                         m->ch[MUSE_CHANNEL_DATA].sock_fd = client_sockfd;
372                         SECURE_LOGW("[%d] %s pid %d %p restore module address at the only one null data channel",
373                                 client_sockfd, ms_config_get_host_name(m->idx), pid, m);
374                 }
375
376                 ms_connection_unlock(connection);
377
378                 ms_ipc_create_data_dispatch_worker(m);
379         }
380
381         muse_core_get_cur_time(&muse_server->tv, NULL);
382         muse_core_change_time_format((int)muse_server->tv.tv_sec, time_buf);
383         LOGW("connected time (%s)", time_buf);
384
385         _ms_unlock_state();
386
387         LOGI("Leave");
388
389         return TRUE;
390 out:
391         close(server_sockfd);
392         close(client_sockfd);
393
394         if (m) {
395                 if (channel == MUSE_CHANNEL_MSG)
396                         g_free(m);
397                 else
398                         muse_core_connection_close(m->ch[MUSE_CHANNEL_MSG].sock_fd);
399         }
400
401         _ms_unlock_state();
402
403         LOGE("FALSE");
404
405         return FALSE;
406 }
407
408 static void _ms_check_idle_state(void)
409 {
410         ms_connection_t *connection = NULL;
411         ms_config_t *conf = NULL;
412         int instance_number, period;
413         uint32_t elapsed_time;
414         struct timespec tv;
415         static int period_idx = 1;
416         char time_buf[MUSE_MSG_TIME_LEN];
417
418         muse_return_if_fail(muse_server);
419         muse_return_if_fail(muse_server->state == MUSE_SERVER_STATE_READY);
420
421         connection = muse_server->connection;
422         muse_return_if_fail(connection);
423
424         conf = muse_server->conf;
425         muse_return_if_fail(conf);
426
427         period = ms_config_get_log_period();
428
429         if (muse_server->tv.tv_sec == 0)
430                 return;
431
432         muse_core_get_cur_time(&tv, NULL);
433
434         elapsed_time = tv.tv_sec - muse_server->tv.tv_sec;
435
436         ms_connection_lock(connection);
437
438         instance_number = g_queue_get_length(connection->instance_q);
439
440         if (elapsed_time >= (uint32_t)(period * period_idx)) {
441                 muse_core_change_time_format((int)muse_server->tv.tv_sec, time_buf);
442                 LOGW("[#%d] %us [period %ds] [%s] total number of modules = %d ( %s)", period_idx,
443                         elapsed_time, period, time_buf, instance_number, muse_server->instance_pid_info);
444                 period_idx++;
445         }
446
447         ms_connection_unlock(connection);
448
449         if (conf->is_on_demand) {
450                 if (instance_number == 0 && elapsed_time >= (uint32_t)ms_config_get_max_idle_time()) {
451                         LOGE("Timeout exit !!! [Idle time] %u sec", elapsed_time);
452                         ms_remove_ready_file();
453                         exit(EXIT_SUCCESS);
454                 }
455         }
456 }
457
458 static gpointer _ms_diag_check_idle_state_thread(gpointer data)
459 {
460         int idle_state_wait_time = ms_config_get_idle_state_wait_time();
461
462         muse_return_val_if_fail(muse_server, NULL);
463         muse_return_val_if_fail(idle_state_wait_time > 0, NULL);
464
465         while (ms_is_server_ready()) {
466                 _ms_check_idle_state();
467                 sleep(idle_state_wait_time);
468         }
469
470         return NULL;
471 }
472
473 static gpointer _ms_diag_check_connection_event_thread(gpointer data)
474 {
475         ms_diag_t *d;
476         ms_diag_msg_t *dm = NULL;
477         muse_return_val_if_fail(muse_server, NULL);
478
479         d = &muse_server->diag;
480
481         while (ms_is_server_ready()) {
482                 dm = (ms_diag_msg_t *)g_async_queue_pop(d->msg_aq);
483
484                 LOGD("[%p] POP message (thread stop ? %d [%s])", dm, dm->thread_stop, ms_get_command_string(dm->cmd));
485
486                 if (dm->thread_stop) {
487                         g_free(dm);
488                         break;
489                 }
490
491                 if (dm->cmd == API_CREATE) {
492                         /* can be updated if connection at the next patch */
493                 } else if (dm->cmd == API_DESTROY) {
494                         ms_check_cpu_memory();
495                 }
496
497                 g_free(dm);
498         }
499
500         return NULL;
501 }
502
503 static void _ms_lock_state(void)
504 {
505         muse_return_if_fail(muse_server);
506         g_mutex_lock(&muse_server->state_lock);
507 }
508
509 static void _ms_unlock_state(void)
510 {
511         muse_return_if_fail(muse_server);
512         g_mutex_unlock(&muse_server->state_lock);
513 }
514
515 static void _ms_diag_init(void)
516 {
517         ms_diag_t *d;
518         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
519         GError *error = NULL;
520
521         muse_return_if_fail(muse_server);
522
523         d = &muse_server->diag;
524
525         d->idle_state_thread = g_thread_try_new("diag_idle_state",
526                 _ms_diag_check_idle_state_thread, muse_server->main_loop, &error);
527         if (!d->idle_state_thread) {
528                 snprintf(err_msg, sizeof(err_msg), "diag_idle_state_thread creation failed : %s", error->message);
529                 LOGE("%s", err_msg);
530                 g_error_free(error);
531                 ms_log_process_info(muse_server->pid);
532         }
533
534         d->msg_aq = g_async_queue_new_full(g_free);
535
536         d->conn_event_thread = g_thread_try_new("diag_connection",
537                 _ms_diag_check_connection_event_thread, muse_server->main_loop, &error);
538         if (!d->conn_event_thread) {
539                 snprintf(err_msg, sizeof(err_msg), "diag_connection_event_thread creation failed : %s", error->message);
540                 LOGE("%s", err_msg);
541                 g_error_free(error);
542                 ms_log_process_info(muse_server->pid);
543         }
544 }
545
546 static void _ms_diag_deinit(void)
547 {
548         ms_diag_t *d;
549         ms_diag_msg_t *dm;
550
551         LOGD("Enter");
552
553         muse_return_if_fail(muse_server);
554
555         d = &muse_server->diag;
556
557         dm = g_new0(ms_diag_msg_t, 1);
558
559         dm->thread_stop = TRUE;
560         LOGI("[%p] g_async_queue_push", dm);
561         g_async_queue_push_front(d->msg_aq, (gpointer)dm);
562
563         if (d->idle_state_thread) {
564                 g_thread_join(d->idle_state_thread);
565                 d->idle_state_thread = NULL;
566         }
567
568         if (d->conn_event_thread) {
569                 g_thread_join(d->conn_event_thread);
570                 d->conn_event_thread = NULL;
571         }
572
573         g_async_queue_unref(d->msg_aq);
574         d->msg_aq = NULL;
575 }
576
577 static gboolean _ms_idle_cb(gpointer user_data)
578 {
579         struct timespec tv;
580         char time_buf[MUSE_MSG_TIME_LEN];
581
582         if (!ms_create_ready_file())
583                 LOGE("%s file creation is failed", MUSE_SERVER_READY);
584
585         _ms_diag_init();
586
587         muse_core_get_cur_time(&tv, NULL);
588
589         muse_core_change_time_format((int)tv.tv_sec, time_buf);
590
591         LOGW("muse server is completed to ready (%s)", time_buf);
592
593         return G_SOURCE_REMOVE;
594 }
595
596 static void _ms_init(void)
597 {
598         int idx;
599
600         LOGD("Enter");
601
602         muse_server->system = g_new0(ms_system_t, 1);
603         ms_system_init(muse_server->system);
604
605         muse_server->conf = g_new0(ms_config_t, 1);
606         ms_config_init(muse_server->conf);
607
608         muse_server->log = g_new0(ms_log_t, 1);
609         ms_log_init(muse_server->log);
610
611         muse_server->security = g_new0(ms_security_t, 1);
612         ms_security_init(muse_server->security);
613
614         for (idx = 0; idx < muse_server->conf->host_cnt; idx++) {
615                 muse_server->module[idx] = g_new0(ms_module_t, 1);
616                 muse_server->module[idx]->idx = idx;
617                 ms_module_init(muse_server->module[idx]);
618         }
619
620 #ifdef MUSE_USE_WATCHDOG
621         muse_server->watchdog = g_new0(ms_watchdog_t, 1);
622         if (ms_watchdog_init(muse_server->watchdog) != MM_ERROR_NONE)
623                 LOGE("Fail to initialize server watchdog");
624 #endif
625
626         muse_server->connection = g_new0(ms_connection_t, 1);
627         ms_connection_init(muse_server->connection);
628
629         ms_signal_init();
630
631         g_mutex_init(&muse_server->state_lock);
632
633         muse_core_create_fd_table();
634
635         muse_server->cpu_threshold = ms_config_get_cpu_threshold();
636
637         muse_server->main_loop = g_main_loop_new(NULL, FALSE);
638         muse_return_if_fail(muse_server->main_loop);
639
640         LOGD("Leave");
641 }
642
643 static int _ms_open_lockfile(void)
644 {
645         int fd, already_running;
646         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
647         char *lockfile = NULL;
648
649         muse_return_val_if_fail(muse_server, MUSE_ERR);
650
651         lockfile = ms_config_get_lockfile();
652         muse_return_val_if_fail(lockfile, MUSE_ERR);
653
654         muse_core_remove_symlink((const char *)lockfile);
655         fd = open(lockfile, O_RDONLY);
656         if (fd == -1 && errno != ENOENT) {
657                 /* Cannot open file even though file exists. */
658                 snprintf(err_msg, sizeof(err_msg), "Cannot open lock file %s", lockfile);
659                 LOGE("open failed : %s", err_msg);
660                 return MUSE_ERR;
661         } else if (fd != -1) {
662                 already_running = flock(fd, LOCK_EX | LOCK_NB) == -1;
663                 close(fd);
664                 if (already_running) {
665                         LOGE("File already locked. There's already a server running");
666                         return MUSE_ERR;
667                 }
668         }
669
670         /* Lock file does not exist, or is not locked. Create a new lockfile and lock it. */
671         fd = open(lockfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
672         if (fd == -1) {
673                 LOGE("dataserver: Cannot create lock file");
674                 return MUSE_ERR;
675         }
676
677         if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
678                 LOGE("Can't lock the lock file \"%s\". " "Is another instance running?", lockfile);
679                 close(fd);
680                 return MUSE_ERR;
681         }
682
683         close(fd);
684
685         return MM_ERROR_NONE;
686 }
687
688 void ms_setup_syslog(void)
689 {
690         int flags = LOG_CONS|LOG_NDELAY|LOG_PID;
691         if (isatty(STDOUT_FILENO))
692                 flags |= LOG_PERROR;
693
694         openlog("mused", flags, LOG_DAEMON);
695         LOGD("openlog - mused");
696 }
697
698 void ms_fork(int *notify_fd)
699 {
700         pid_t pid;
701         int fds[2];
702         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
703         char msg[MUSE_MSG_LEN_MAX] = {'\0',};
704
705         if (pipe(fds) == MUSE_ERR) {
706                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
707                 LOGE("Failed to create pipe to get child status: %s", err_msg);
708                 exit(EXIT_FAILURE);
709         }
710
711         if ((pid = fork()) < 0) {
712                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
713                 LOGE("Error: fork() failed: %s", err_msg);
714                 exit(EXIT_FAILURE);
715         } else if (pid != 0) {
716                 close(fds[1]);
717                 /* Read in a string from the pipe */
718                 if (read(fds[0], msg, sizeof(msg)) <= 0) {
719                         LOGE("Failed to read from a file descriptor [%d]", fds[0]);
720                         close(fds[0]);
721                         return;
722                 }
723                 close(fds[0]);
724
725                 /* Parent process closes up output side of pipe */
726                 if (!strcmp(msg, MSG_DONE)) {
727                         LOGI("Successfully daemonized");
728                         exit(EXIT_SUCCESS);
729                 } else {
730                         LOGE("Daemonizing failed after fork");
731                         exit(EXIT_FAILURE);
732                 }
733         } else if (pid == 0) {
734                 /* Child process closes up input side of pipe */
735                 close(fds[0]);
736                 *notify_fd = fds[1];
737         }
738 }
739
740 pid_t ms_daemonize(int *notify_fd)
741 {
742         pid_t pid;
743         int fd, result;
744
745         muse_return_val_if_fail(notify_fd, MUSE_ERR);
746
747         ms_fork(notify_fd);
748
749         if ((pid = setsid()) < 0) {
750                 LOGE("create new session");
751                 exit(EXIT_FAILURE);
752         }
753
754         /* change the file mode mask */
755         umask(0);
756
757         result = chdir("/");
758         LOGD("result = %d sid: %d pgid: %d pid: %d ppid: %d", result, (int)getsid(0), (int)getpgid(0), (int)pid, (int)getppid());
759
760         /* redirect fds to /dev/null */
761         fd = open("/dev/null", O_RDWR);
762         if (!muse_core_fd_is_valid(fd)) {
763                 LOGE("Critical Error : %d is invalid", fd);
764                 exit(EXIT_SUCCESS);
765         }
766
767         close(STDIN_FILENO);
768         close(STDOUT_FILENO);
769         close(STDERR_FILENO);
770
771         dup2(fd, STDIN_FILENO);
772         dup2(fd, STDOUT_FILENO);
773         dup2(fd, STDERR_FILENO);
774
775         close(fd);
776
777         return pid;
778 }
779
780 void ms_daemonize_complete(int notify_fd)
781 {
782         LOGD("Enter");
783
784         muse_return_if_fail(muse_core_fd_is_valid(notify_fd));
785
786 #ifdef MUSE_REGISTER_VIP
787         proc_stat_set_vip_process();
788 #endif
789
790         write(notify_fd, MSG_DONE, strlen(MSG_DONE) + 1);
791         LOGW("[%d] Notify parent process that child initialization is done", notify_fd);
792         close(notify_fd);
793
794         LOGD("Leave");
795 }
796
797 void ms_gst_init(char **cmd)
798 {
799         gint argc = 0;
800         gchar **argv = NULL;
801         GError *err = NULL;
802         gboolean ret = FALSE;
803         int gst_param_cnt;
804
805 #ifdef MUSE_TTRACE_LOG
806         trace_begin("MUSE:gst_init");
807 #endif
808
809         gst_param_cnt = ms_config_get_gst_param_cnt();
810
811         /* add gst_param */
812         argv = g_malloc0(sizeof(gchar *) * (gst_param_cnt + 1));
813
814         argv[argc++] = (gchar *)cmd[0];
815         for (; argc <= gst_param_cnt; argc++) {
816                 argv[argc] = ms_config_get_gst_param_str(argc - 1);
817                 LOGI("%d %s", argc, argv[argc]);
818         }
819
820         /* initializing gstreamer */
821         ret = gst_init_check(&argc, &argv, &err);
822         if (!ret) {
823                 LOGE("Could not initialize GStreamer: %s ", err ? err->message : "unknown error occurred");
824                 if (err)
825                         g_error_free(err);
826         }
827
828         LOGI("gst_init_check is completed");
829
830         /* release */
831         g_free(argv);
832
833         LOGI("complete to initialize gstreamer");
834
835 #ifdef MUSE_TTRACE_LOG
836         trace_end();
837 #endif
838 }
839
840 void ms_gst_preload_plugin(void)
841 {
842         char *token = NULL;
843         char *saveptr = NULL;
844         char plugin_path[128];
845         const char *delimeters = " ,";
846         gchar *gst_preload_plugins = g_strdup(ms_config_get_gst_preload_plugins());
847         GstPlugin *plugin = NULL;
848
849         muse_return_if_fail(gst_preload_plugins);
850
851         LOGI("preload plugins [%s]", gst_preload_plugins);
852
853         token = strtok_r(gst_preload_plugins, delimeters, &saveptr);
854         while (token) {
855                 snprintf(plugin_path, sizeof(plugin_path), "%s/gstreamer-1.0/libgst%s.so", LIBDIR, token);
856
857                 LOGI("    plugin path : %s", plugin_path);
858
859                 plugin = gst_plugin_load_file(plugin_path, NULL);
860                 if (plugin)
861                         gst_object_unref(plugin);
862                 else
863                         LOGW("failed to load plugin [%s]", plugin_path);
864
865                 token = strtok_r(NULL, delimeters, &saveptr);
866         }
867
868         g_free(gst_preload_plugins);
869
870         LOGI("Leave");
871 }
872
873 int ms_pidfile_create(const char *path, pid_t pid)
874 {
875         int fd;
876         struct flock lock;
877         char pid_buf[MUSE_MSG_LEN] = {'\0',};
878         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
879
880         muse_return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT);
881         muse_core_remove_symlink(path);
882         fd = open(path, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
883
884         if (!muse_core_fd_is_valid(fd)) {
885                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
886                 LOGE("Fail to open pidfile [%s] : %s", path, err_msg);
887                 return MM_ERROR_FILE_NOT_FOUND;
888         }
889
890         lock.l_type = F_WRLCK;
891         lock.l_start = 0;
892         lock.l_whence = SEEK_SET;
893         lock.l_len = 0;
894
895         if (fcntl(fd, F_SETLK, &lock) < 0) {
896                 if (errno != EACCES && errno != EAGAIN) {
897                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
898                         LOGE("Fail to lock pidfile [%s] : %s", path, err_msg);
899                 } else {
900                         LOGE("process is already running");
901                 }
902                 close(fd);
903                 return MM_ERROR_FILE_INTERNAL;
904         }
905
906         if (ftruncate(fd, 0) < 0) {
907                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
908                 LOGE("Fail to truncate pidfile [%s] : %s", path, err_msg);
909                 close(fd);
910                 return MM_ERROR_FILE_INTERNAL;
911         }
912
913         memset(pid_buf, 0, sizeof(pid_buf));
914         snprintf(pid_buf, sizeof(pid_buf), "%u", pid);
915
916         if (write(fd, pid_buf, strlen(pid_buf)) != (int)strlen(pid_buf)) {
917                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
918                 LOGE("Fail to write pid to pidfile [%s] : %s", path, err_msg);
919                 close(fd);
920                 return MM_ERROR_FILE_WRITE;
921         }
922
923         close(fd);
924         return MM_ERROR_NONE;
925 }
926
927 void ms_init(char **argv)
928 {
929         int idx;
930         int notify_fd;
931         muse_module_cmd_dispatchfunc *cmd_dispatcher = NULL;
932
933         LOGW("Enter");
934
935         muse_server = g_new0(muse_server_t, 1);
936
937         ms_setup_syslog();
938
939         muse_server->pid = ms_daemonize(&notify_fd);
940
941         if (g_mkdir_with_parents(tzplatform_mkpath(TZ_SYS_RUN, "mused"), S_IRWXU | S_IRWXG | S_IRWXO) != 0)
942                 exit(EXIT_FAILURE);
943
944         if (ms_pidfile_create(MUSE_DEFAULT_PIDFILE, muse_server->pid) != MM_ERROR_NONE)
945                 exit(EXIT_FAILURE);
946         else
947                 LOGW("MUSE_DEFAULT_PIDFILE(%s) file was created", MUSE_DEFAULT_PIDFILE);
948
949         _ms_init();
950
951         muse_return_if_fail(_ms_open_lockfile() == MM_ERROR_NONE);
952
953         ms_new();
954
955         ms_daemonize_complete(notify_fd);
956
957 #ifdef MUSE_TTRACE_LOG
958         trace_end();
959 #endif
960
961         ms_system_subscribe_external_event(muse_server->system);
962
963 #ifdef MUSE_USE_WATCHDOG
964         if (!ms_watchdog_attach(muse_server->watchdog)) {
965                 LOGE("watchdog thread failed");
966                 ms_log_process_info(muse_server->pid);
967                 return;
968         }
969 #endif
970
971         ms_gst_init(argv);
972
973 #ifdef MUSE_TTRACE_LOG
974         trace_begin("MUSE:preloading module");
975 #endif
976         for (idx = 0; idx < ms_config_get_host_cnt(); idx++) {
977                 if (0 == strncmp(ms_config_get_preloaded_value(idx), "yes", strlen("yes") + 1)) {
978                         g_module_symbol(ms_module_open(idx), CMD_DISPATCHER, (gpointer *)&cmd_dispatcher);
979                         if (cmd_dispatcher && cmd_dispatcher[MUSE_MODULE_COMMAND_INITIALIZE])
980                                 cmd_dispatcher[MUSE_MODULE_COMMAND_INITIALIZE](NULL);
981                 }
982         }
983 #ifdef MUSE_TTRACE_LOG
984         trace_end();
985 #endif
986
987 #ifdef MUSE_TTRACE_LOG
988         trace_begin("MUSE:preloading GST module");
989 #endif
990         ms_gst_preload_plugin();
991 #ifdef MUSE_TTRACE_LOG
992         trace_end();
993 #endif
994
995 #ifdef MUSE_GCOV_TEST
996         muse_core_setenv("GCOV_PREFIX", "/tmp", 1);
997 #endif
998
999         LOGW("Leave");
1000 }
1001
1002 muse_server_h ms_get_instance(void)
1003 {
1004         return muse_server;
1005 }
1006
1007 gboolean ms_check_module_idx(int idx)
1008 {
1009         int module_cnt = ms_config_get_host_cnt();
1010
1011         if (idx < 0 || idx >= module_cnt) {
1012                 LOGE("%d error - the number of modules is %d", idx, module_cnt);
1013                 return FALSE;
1014         }
1015
1016         return TRUE;
1017 }
1018
1019 ms_module_t *ms_get_module_instance(int idx)
1020 {
1021         muse_return_val_if_fail(ms_check_module_idx(idx), NULL);
1022
1023         return muse_server->module[idx];
1024 }
1025
1026 int ms_deinit(void)
1027 {
1028         int retval = MUSE_ERR;
1029         int idx;
1030
1031         LOGD("Enter");
1032
1033         muse_return_val_if_fail(muse_server, retval);
1034         muse_return_val_if_fail(muse_server->conf, retval);
1035         muse_return_val_if_fail(muse_server->connection, retval);
1036         muse_return_val_if_fail(muse_server->log, retval);
1037         muse_return_val_if_fail(muse_server->security, retval);
1038         muse_return_val_if_fail(muse_server->watchdog, retval);
1039
1040         ms_recursive_rmdir(MUSE_DATA_ROOT_PATH);
1041
1042         ms_set_state(MUSE_SERVER_STATE_IDLE);
1043
1044         _ms_diag_deinit();
1045
1046 #ifdef MUSE_USE_WATCHDOG
1047         ms_watchdog_detach(muse_server->watchdog);
1048
1049         if (ms_watchdog_deinit(muse_server->watchdog) == MM_ERROR_NONE)
1050                 free(muse_server->watchdog);
1051         else
1052                 LOGE("Fail to deinitialize server watchdog");
1053 #endif
1054
1055         ms_remove_ready_file();
1056
1057         retval = muse_server->retval;
1058         muse_core_fd_close(muse_server->msg_fd);
1059         muse_core_fd_close(muse_server->data_fd);
1060         for (idx = 0; idx < MUSE_CHANNEL_MAX; idx++) {
1061                 if (remove(UDS_files[idx]) == MUSE_ERR)
1062                         LOGE("remove %s failed", UDS_files[idx]);
1063         }
1064
1065         if (remove(MUSE_DEFAULT_PIDFILE) == -1)
1066                 LOGE("remove %s failed [errno : %d]", MUSE_DEFAULT_PIDFILE, errno);
1067
1068         for (idx = 0; idx < muse_server->conf->host_cnt; idx++)
1069                 ms_module_deinit(muse_server->module[idx]);
1070
1071         ms_security_deinit(muse_server->security);
1072         muse_server->security = NULL;
1073
1074         ms_system_deinit(muse_server->system);
1075         muse_server->system = NULL;
1076
1077         ms_log_deinit(muse_server->log);
1078         muse_server->log = NULL;
1079
1080         ms_config_deinit(muse_server->conf);
1081         muse_server->conf = NULL;
1082
1083         ms_connection_deinit(muse_server->connection);
1084         muse_server->connection = NULL;
1085
1086         muse_core_destroy_fd_table();
1087
1088         ms_deinit_bufmgr();
1089
1090         g_mutex_clear(&muse_server->state_lock);
1091
1092         g_free(muse_server);
1093         muse_server = NULL;
1094
1095         LOGD("Leave");
1096         return retval;
1097 }
1098
1099 void ms_check_cpu_memory(void)
1100 {
1101         int used_pss, memory_threshold, cpu_usage;
1102         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
1103         ms_connection_t *connection = NULL;
1104
1105         muse_return_if_fail(muse_server);
1106
1107         connection = muse_server->connection;
1108         muse_return_if_fail(connection);
1109
1110         ms_connection_lock(connection);
1111
1112         if (g_queue_is_empty(connection->instance_q) && ms_is_server_ready()) {
1113                 used_pss = ms_system_get_memory_usage(muse_server->pid);
1114                 cpu_usage = muse_core_get_process_cpu_usage(muse_server->pid);
1115
1116                 LOGW("[%d] Proportional set size %d (KByte) (CPU %d %%)", muse_server->pid, used_pss, cpu_usage);
1117                 memory_threshold = ms_config_get_memory_threshold();
1118
1119                 if (used_pss >= memory_threshold || cpu_usage >= muse_server->cpu_threshold) {
1120                         ms_log_process_info(muse_server->pid);
1121
1122                         snprintf(err_msg, sizeof(err_msg), "[Memory Leak] %d >= %d (KByte) [CPU] %d >= %d %%",
1123                                 used_pss, memory_threshold, cpu_usage, muse_server->cpu_threshold);
1124
1125                         LOGE("%s", err_msg);
1126                         ms_connection_unlock(connection);
1127                         ms_terminate(SIGTERM);
1128                 }
1129
1130                 muse_core_remove_all_fd_table();
1131         } else {
1132                 LOGI("skip cpu memory check due to instance queue length : %d", g_queue_get_length(connection->instance_q));
1133         }
1134
1135         ms_connection_unlock(connection);
1136 }
1137
1138 void ms_new(void)
1139 {
1140         int fd[MUSE_CHANNEL_MAX];
1141         int i, j;
1142
1143         for (i = 0; i < MUSE_CHANNEL_MAX; i++) {
1144                 if (ms_config_is_on_demand() && i == MUSE_CHANNEL_MSG)
1145                         fd[i] = SD_LISTEN_FDS_START;
1146                 else
1147                         fd[i] = _ms_new(i);
1148
1149                 if (!muse_core_fd_is_valid(fd[i])) {
1150                         LOGE("Failed to create socket server %d", i);
1151                         for (j = 0; j < i; j++)
1152                                 close(fd[j]);
1153                         return;
1154                 }
1155         }
1156
1157         _ms_create_new_server_from_fd(fd, READ | PERSIST);
1158 }
1159
1160 void ms_run(void)
1161 {
1162         LOGW("Enter");
1163
1164         muse_return_if_fail(muse_server->main_loop);
1165
1166         muse_return_if_fail(g_idle_add_full(G_PRIORITY_HIGH, _ms_idle_cb, NULL, NULL) > 0);
1167
1168         LOGI("g_main_loop_run");
1169         g_main_loop_run(muse_server->main_loop);
1170
1171         LOGW("Leave");
1172 }
1173
1174 void ms_cmd_dispatch(muse_module_h m, muse_module_command_e cmd)
1175 {
1176         muse_module_cmd_dispatchfunc *cmd_dispatcher = NULL;
1177
1178         if (m->ch[MUSE_CHANNEL_MSG].dll_handle &&
1179                 g_module_symbol(m->ch[MUSE_CHANNEL_MSG].dll_handle, CMD_DISPATCHER, (gpointer *)&cmd_dispatcher)) {
1180                 if (cmd_dispatcher && cmd_dispatcher[cmd])
1181                         cmd_dispatcher[cmd](m);
1182         }
1183 }
1184
1185 void ms_terminate(int signo)
1186 {
1187         muse_return_if_fail(muse_server);
1188
1189         ms_set_state(MUSE_SERVER_STATE_IDLE);
1190
1191         LOGE("send signal %d to process %d", signo, muse_server->pid);
1192         raise(signo);
1193 }
1194
1195 int ms_get_pid(muse_module_h m)
1196 {
1197         muse_return_val_if_fail(m, MUSE_ERR);
1198         return m->pid;
1199 }
1200
1201 void ms_log_process_info(int pid)
1202 {
1203         muse_core_log_process_thread_info(pid);
1204
1205         muse_core_log_process_opened_fds(pid);
1206
1207         muse_core_log_process_cpu_memory(pid);
1208 }
1209
1210 void ms_log_user_group_info(void)
1211 {
1212         uid_t uid;
1213         gid_t gid;
1214         char buffer[MUSE_MSG_MAX_LENGTH];
1215         struct passwd pwbuf;
1216         struct passwd *pwbufp;
1217         struct group gbuf;
1218         struct group *gbufp;
1219
1220         uid = getuid();
1221         gid = getgid();
1222
1223         getpwuid_r(uid, &pwbuf, buffer, sizeof(buffer), &pwbufp);
1224         muse_return_if_fail(pwbufp);
1225
1226         getgrgid_r(gid, &gbuf, buffer, sizeof(buffer), &gbufp);
1227         muse_return_if_fail(gbufp);
1228
1229         LOGE("user [%s : %lu] group [%s : %lu]", pwbufp->pw_name, (unsigned long)uid, gbufp->gr_name, (unsigned long)gid);
1230 }
1231
1232 gboolean ms_is_log_enabled(void)
1233 {
1234         return ms_config_is_log_enabled();
1235 }
1236
1237 gboolean ms_init_bufmgr(void)
1238 {
1239         LOGD("Enter");
1240
1241         muse_return_val_if_fail(muse_server, FALSE);
1242
1243         muse_server->bufmgr = tbm_bufmgr_init(-1);
1244         if (!muse_server->bufmgr) {
1245                 LOGE("Error - tbm_bufmgr_init");
1246                 ms_log_user_group_info();
1247                 return FALSE;
1248         }
1249
1250         LOGD("Leave bufmgr: %p", muse_server->bufmgr);
1251
1252         return TRUE;
1253 }
1254
1255 void ms_deinit_bufmgr(void)
1256 {
1257         LOGD("Enter");
1258
1259         muse_return_if_fail(muse_server);
1260         muse_return_if_fail(muse_server->bufmgr);
1261
1262         tbm_bufmgr_deinit(muse_server->bufmgr);
1263
1264         LOGD("Leave");
1265 }
1266
1267 void ms_cmd_dispatch_foreach_func(gpointer data, gpointer user_data)
1268 {
1269         muse_module_h m = (muse_module_h)data;
1270         ms_cmd_dispatcher_info_t *dispatch = (ms_cmd_dispatcher_info_t *)user_data;
1271         muse_module_command_e cmd;
1272         muse_external_storage_info_t *storage;
1273
1274         muse_return_if_fail(muse_server);
1275         muse_return_if_fail(m);
1276         muse_return_if_fail(dispatch);
1277
1278         cmd = dispatch->cmd;
1279
1280         if (cmd == MUSE_MODULE_COMMAND_EXTERNAL_STORAGE_STATE_CHANGED) {
1281                 storage = &dispatch->storage;
1282                 LOGD("external storage id %d state %d path %s", storage->id, storage->state, storage->path);
1283                 muse_server_set_user_data(m, (void *)storage);
1284         }
1285
1286         ms_cmd_dispatch(m, cmd);
1287         SECURE_LOGI("[%s] module %p (%s)", module_cmd[cmd], m, muse_server->conf->host[m->idx]);
1288
1289         if (cmd == MUSE_MODULE_COMMAND_EXTERNAL_STORAGE_STATE_CHANGED)
1290                 muse_server_set_user_data(m, NULL);
1291 }
1292
1293 void ms_set_state(ms_state_e state)
1294 {
1295         muse_return_if_fail(muse_server);
1296
1297         g_mutex_lock(&muse_server->state_lock);
1298         muse_server->state = state;
1299         g_mutex_unlock(&muse_server->state_lock);
1300 }
1301
1302 gboolean ms_is_server_ready(void)
1303 {
1304         muse_return_val_if_fail(muse_server, FALSE);
1305
1306         return muse_server->state == MUSE_SERVER_STATE_READY;
1307 }
1308
1309 gboolean ms_create_ready_file(void)
1310 {
1311         LOGD("Enter");
1312 #ifndef MUSE_USE_LWIPC
1313         int ready_fd;
1314 #endif
1315
1316 #ifdef MUSE_USE_LWIPC
1317         _ms_wait_event();
1318
1319         ms_set_state(MUSE_SERVER_STATE_READY);
1320
1321         if (LwipcEventDone(MUSE_SERVER_READY) < 0) {
1322                 LOGE("Fail to send server ready done event");
1323                 return FALSE;
1324         }
1325 #else
1326         ready_fd = creat(MUSE_SERVER_READY, 0644);
1327         if (muse_core_fd_is_valid(ready_fd)) {
1328                 LOGD("MUSE_SERVER_READY(%s) file was created", MUSE_SERVER_READY);
1329
1330                 close(ready_fd);
1331                 ms_set_state(MUSE_SERVER_STATE_READY);
1332         } else {
1333                 LOGE("[%d] Fail to create MUSE_SERVER_READY(%s)", ready_fd, MUSE_SERVER_READY);
1334                 return FALSE;
1335         }
1336 #endif
1337         LOGD("Leave");
1338
1339         return TRUE;
1340
1341 }
1342
1343 void ms_remove_ready_file(void)
1344 {
1345 #ifdef MUSE_USE_LWIPC
1346         (void)LwipcResetEvent(MUSE_SERVER_READY);
1347 #else
1348         (void)unlink(MUSE_SERVER_READY);
1349         (void)unlink(MUSE_DEFAULT_PIDFILE);
1350 #endif
1351 }
1352
1353 const char *ms_get_command_string(int cmd)
1354 {
1355         if (cmd == API_CREATE)
1356                 return "connect";
1357         else if (cmd == API_DESTROY)
1358                 return "disconnect";
1359         else
1360                 LOGE("Invalid value of cmd (%d)", cmd);
1361
1362         return "Invalid value of cmd";
1363 }
1364