Tizen 2.1 base
[framework/multimedia/media-server.git] / common / media-server-main.c
1 /*
2  *  Media Server
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Yong Yeon Kim <yy9875.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 /**
23  * This file defines api utilities of contents manager engines.
24  *
25  * @file                media-server-main.c
26  * @author      Yong Yeon Kim(yy9875.kim@samsung.com)
27  * @version     1.0
28  * @brief
29  */
30
31 #include <sys/wait.h>
32 #include <sys/types.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include <malloc.h>
36 #include <vconf.h>
37 #include <heynoti.h>
38
39 #include "media-util.h"
40 #include "media-server-dbg.h"
41 #include "media-server-utils.h"
42 #include "media-server-external-storage.h"
43 #include "media-server-db-svc.h"
44 #include "media-server-inotify.h"
45 #include "media-server-socket.h"
46 #include "media-server-db.h"
47 #include "media-server-drm.h"
48 #include "media-server-dbus.h"
49 #include "media-server-thumb.h"
50 #include "media-server-scanner.h"
51
52 #define APP_NAME "media-server"
53
54 extern GMutex *scanner_mutex;
55 extern GMutex *db_mutex;
56 extern int mmc_state;
57
58 #if MS_INOTI_ENABLE
59 extern GAsyncQueue* ret_queue;
60 extern GMutex *list_mutex;
61 extern GMutex *queue_mutex;
62 extern GArray *reg_list;
63 extern bool power_off; /*If this is TRUE, poweroff notification received*/
64 #endif
65 GMainLoop *mainloop = NULL;
66
67 bool check_process()
68 {
69         DIR *pdir;
70         struct dirent pinfo;
71         struct dirent *result = NULL;
72         bool ret = false;
73         int find_pid = 0;
74         pid_t current_pid = 0;
75
76         current_pid = getpid();
77
78         pdir = opendir("/proc");
79         if (pdir == NULL) {
80                 MS_DBG_ERR("err: NO_DIR\n");
81                 return 0;
82         }
83
84         while (!readdir_r(pdir, &pinfo, &result)) {
85                 if (result == NULL)
86                         break;
87
88                 if (pinfo.d_type != 4 || pinfo.d_name[0] == '.'
89                     || pinfo.d_name[0] > 57)
90                         continue;
91
92                 FILE *fp;
93                 char buff[128];
94                 char path[128];
95
96                 ms_strcopy(path, sizeof(path), "/proc/%s/status", pinfo.d_name);
97                 fp = fopen(path, "rt");
98                 if (fp) {
99                         if (fgets(buff, 128, fp) == NULL)
100                                 MS_DBG_ERR("fgets failed");
101                         fclose(fp);
102
103                         if (strstr(buff, APP_NAME)) {
104                                 find_pid = atoi(pinfo.d_name);
105                                 if (find_pid == current_pid)
106                                         ret = true;
107                                 else {
108                                         ret = false;
109                                         break;
110                                 }
111                         }
112                 } else {
113                         MS_DBG_ERR("Can't read file [%s]", path);
114                 }
115         }
116
117         closedir(pdir);
118
119         return ret;
120 }
121
122 void init_process()
123 {
124
125 }
126
127 static void _power_off_cb(void* data)
128 {
129         MS_DBG("++++++++++++++++++++++++++++++++++++++");
130         MS_DBG("POWER OFF");
131         MS_DBG("++++++++++++++++++++++++++++++++++++++");
132 #if MS_INOTI_ENABLE
133         power_off = true;
134 #endif
135         /*Quit Thumbnail Thread*/
136         GMainLoop *thumb_mainloop = ms_get_thumb_thread_mainloop();
137         if (thumb_mainloop && g_main_is_running(thumb_mainloop)) {
138                 g_main_loop_quit(thumb_mainloop);
139         }
140
141         /*Quit DB Thread*/
142         GMainLoop *db_mainloop = ms_db_get_mainloop();
143         if(db_mainloop && g_main_loop_is_running(db_mainloop)) {
144                 g_main_loop_quit(db_mainloop);
145         }
146
147         /*Quit Main Thread*/
148         if (mainloop && g_main_loop_is_running(mainloop)) {
149                 g_main_loop_quit(mainloop);
150         }
151
152         return;
153 }
154
155 static bool _db_clear(void** handle)
156 {
157         int err;
158         int db_status;
159         bool need_db_create = false;
160
161         /*update just valid type*/
162         err = ms_invalidate_all_items(handle, MS_STORAGE_EXTERNAL);
163         if (err != MS_MEDIA_ERR_NONE)
164                 MS_DBG_ERR("ms_change_valid_type fail");
165
166         ms_config_get_int(MS_SCAN_STATUS_INTERNAL, &db_status);
167         MS_DBG("finish_phone_init_data  db = %d", db_status);
168
169         if (db_status == P_VCONF_SCAN_DOING) {
170                 need_db_create = true;
171
172                 err = ms_invalidate_all_items(handle, MS_STORAGE_INTERNAL);
173                 if (err != MS_MEDIA_ERR_NONE)
174                         MS_DBG_ERR("ms_change_valid_type fail");
175         }
176
177 //      ms_set_db_status(MS_DB_UPDATED);
178
179         return need_db_create;
180 }
181
182 void _ms_signal_handler(int n)
183 {
184         MS_DBG("Receive SIGNAL");
185         int stat, pid, thumb_pid;
186         int scanner_pid;
187
188         thumb_pid = ms_thumb_get_server_pid();
189         MS_DBG("Thumbnail server pid : %d", thumb_pid);
190
191         scanner_pid = ms_get_scanner_pid();
192
193         pid = waitpid(-1, &stat, WNOHANG);
194         /* check pid of child process of thumbnail thread */
195         MS_DBG("[PID %d] signal ID %d", pid, n);
196
197         if (pid == thumb_pid) {
198                 MS_DBG("Thumbnail server is dead");
199                 ms_thumb_reset_server_status();
200         } else if (pid == scanner_pid) {
201                 MS_DBG("Scanner is dead");
202                 ms_reset_scanner_status();
203         } else if (pid == -1) {
204                 MS_DBG("%s", strerror(errno));
205         }
206
207         if (WIFEXITED(stat)) {
208                 MS_DBG("normal termination , exit status : %d", WEXITSTATUS(stat));
209         } else if (WIFSIGNALED(stat)) {
210                 MS_DBG("abnormal termination , signal number : %d", WTERMSIG(stat));
211         } else if (WIFSTOPPED(stat)) {
212                 MS_DBG("child process is stoped, signal number : %d", WSTOPSIG(stat));
213         }
214
215         return;
216 }
217
218 static void _ms_new_global_variable(void)
219 {
220 #if MS_INOTI_ENABLE
221         /*Init for register file*/
222         if (!list_mutex) list_mutex = g_mutex_new();
223         if (!queue_mutex) queue_mutex = g_mutex_new();
224         if (!reg_list) reg_list = g_array_new(TRUE, TRUE, sizeof(char*));
225         /*These are a communicator for thread*/
226         if (!ret_queue) ret_queue = g_async_queue_new();
227 #endif
228         /*Init mutex variable*/
229         if (!db_mutex) db_mutex = g_mutex_new();
230
231         /*media scanner stop/start mutex*/
232         if (!scanner_mutex) scanner_mutex = g_mutex_new();
233 }
234
235 static void _ms_free_global_variable(void)
236 {
237 #if MS_INOTI_ENABLE
238         if (list_mutex) g_mutex_free(list_mutex);
239         if (queue_mutex)g_mutex_free(queue_mutex);
240         if (reg_list) g_array_free(reg_list, true);
241         if (ret_queue) g_async_queue_unref(ret_queue);
242 #endif
243         /*Clear mutex variable*/
244         if (db_mutex) g_mutex_free (db_mutex);
245
246         if (scanner_mutex) g_mutex_free(scanner_mutex);
247 }
248
249 int main(int argc, char **argv)
250 {
251 #if MS_INOTI_ENABLE
252         GThread *inoti_thread = NULL;
253 #endif
254         GThread *db_thread = NULL;
255         GThread *thumb_thread = NULL;
256         GSource *source = NULL;
257         GIOChannel *channel = NULL;
258         GMainContext *context = NULL;
259         int sockfd = MS_SOCK_NOT_ALLOCATE;
260         int err;
261         int heynoti_id;
262         bool check_result = false;
263         bool need_db_create;
264         void **handle = NULL;
265         struct sigaction sigset;
266
267         check_result = check_process();
268         if (check_result == false)
269                 exit(0);
270
271         if (!g_thread_supported()) {
272                 g_thread_init(NULL);
273         }
274
275         /*Init main loop*/
276         mainloop = g_main_loop_new(NULL, FALSE);
277 #if MS_INOTI_ENABLE
278         /*inotify setup */
279         ms_inoti_init();
280 #endif
281         /*heynoti for power off*/
282         if ((heynoti_id = heynoti_init()) <0) {
283                 MS_DBG("heynoti_init failed");
284         } else {
285                 err = heynoti_subscribe(heynoti_id, POWEROFF_NOTI_NAME, _power_off_cb, NULL);
286                 if (err < 0)
287                         MS_DBG("heynoti_subscribe failed");
288
289                 err = heynoti_attach_handler(heynoti_id);
290                 if (err < 0)
291                         MS_DBG("heynoti_attach_handler failed");
292         }
293
294         /*load functions from plusin(s)*/
295         err = ms_load_functions();
296         if (err != MS_MEDIA_ERR_NONE) {
297                 MS_DBG_ERR("function load failed");
298                 exit(0);
299         }
300
301         _ms_new_global_variable();
302
303         /*connect to media db, if conneting is failed, db updating is stopped*/
304         ms_connect_db(&handle);
305
306         ms_dbus_init();
307 #if MS_INOTI_ENABLE
308         ms_inoti_add_watch_all_directory(MS_STORAGE_INTERNAL);
309 #endif
310         /*prepare socket*/
311         /* Create and bind new UDP socket */
312         if (ms_ipc_create_server_socket(MS_PROTOCOL_UDP, MS_SCANNER_PORT, &sockfd)
313                 != MS_MEDIA_ERR_NONE) {
314                 MS_DBG_ERR("Failed to create socket");
315         } else {
316                 context = g_main_loop_get_context(mainloop);
317
318                 /* Create new channel to watch udp socket */
319                 channel = g_io_channel_unix_new(sockfd);
320                 source = g_io_create_watch(channel, G_IO_IN);
321
322                 /* Set callback to be called when socket is readable */
323                 g_source_set_callback(source, (GSourceFunc)ms_read_socket, handle, NULL);
324                 g_source_attach(source, context);
325                 g_source_unref(source);
326         }
327
328         /*create each threads*/
329 #if MS_INOTI_ENABLE
330         inoti_thread = g_thread_new("inotify_thread", (GThreadFunc)ms_inoti_thread, NULL);
331 #endif
332         db_thread = g_thread_new("db_thread", (GThreadFunc)ms_db_thread, NULL);
333         thumb_thread = g_thread_new("thumb_agent_thread", (GThreadFunc)ms_thumb_agent_start_thread, NULL);
334
335         /*set vconf callback function*/
336         err = vconf_notify_key_changed(VCONFKEY_SYSMAN_MMC_STATUS, (vconf_callback_fn) ms_mmc_vconf_cb, NULL);
337         if (err == -1)
338                 MS_DBG_ERR("add call back function for event %s fails", VCONFKEY_SYSMAN_MMC_STATUS);
339
340         MS_DBG("*********************************************************");
341         MS_DBG("*** Begin to check tables of file manager in database ***");
342         MS_DBG("*********************************************************");
343
344         /* Add signal handler */
345         sigset.sa_handler = _ms_signal_handler;
346         if (sigaction(SIGCHLD, &sigset, NULL) < 0) {
347                 MS_DBG_ERR("sigaction failed [%s]", strerror(errno));
348         } else {
349                 MS_DBG("handler ok");
350         }
351
352         /*clear previous data of sdcard on media database and check db status for updating*/
353         while(!ms_db_get_thread_status()) {
354                 MS_DBG("wait db thread");
355                 sleep(1);
356         }
357
358         need_db_create = _db_clear(handle);
359         if (need_db_create) {
360                 /*insert records*/
361                 ms_send_storage_scan_request(MS_STORAGE_INTERNAL, MS_SCAN_ALL);
362         } else {
363                 ms_send_storage_scan_request(MS_STORAGE_INTERNAL, MS_SCAN_PART);
364         }
365
366         if (ms_is_mmc_inserted()) {
367                 mmc_state = VCONFKEY_SYSMAN_MMC_MOUNTED;
368
369                 if (!ms_drm_insert_ext_memory())
370                         MS_DBG_ERR("ms_drm_insert_ext_memory failed");
371
372                 ms_make_default_path_mmc();
373 #if MS_INOTI_ENABLE
374                 ms_inoti_add_watch_all_directory(MS_STORAGE_EXTERNAL);
375 #endif
376                 ms_present_mmc_insert();
377
378                 ms_send_storage_scan_request(MS_STORAGE_EXTERNAL, ms_get_mmc_state());
379         }
380
381         /*Active flush */
382         malloc_trim(0);
383
384         MS_DBG("*****************************************");
385         MS_DBG("*** Server of File Manager is running ***");
386         MS_DBG("*****************************************");
387
388         g_main_loop_run(mainloop);
389 #if MS_INOTI_ENABLE
390         g_thread_join(inoti_thread);
391 #endif
392         g_thread_join(db_thread);
393         g_thread_join(thumb_thread);
394
395         /*close an IO channel*/
396         g_io_channel_shutdown(channel,  FALSE, NULL);
397         g_io_channel_unref(channel);
398
399         heynoti_unsubscribe(heynoti_id, POWEROFF_NOTI_NAME, _power_off_cb);
400         heynoti_close(heynoti_id);
401
402         /***********
403         **remove call back functions
404         ************/
405         vconf_ignore_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
406                                  (vconf_callback_fn) ms_mmc_vconf_cb);
407
408         _ms_free_global_variable();
409
410         /*disconnect form media db*/
411         if (handle) ms_disconnect_db(&handle);
412
413         /*close socket*/
414         close(sockfd);
415
416         /*unload functions*/
417         ms_unload_functions();
418
419         exit(0);
420 }