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