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