Remove memory allocation in signal handler to avoid deadlock
[platform/core/multimedia/libmm-session.git] / mm_session.c
1 /*
2  * libmm-session
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin at samsung.com>, Sangchul Lee <sc11.lee at 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 <stdio.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <mm_session_private.h>
28 #include <mm_error.h>
29 #include <mm_debug.h>
30 #include <errno.h>
31 #include <pthread.h>
32 #include <signal.h>
33
34 #define EXPORT_API __attribute__((__visibility__("default")))
35 #define MAX_FILE_LENGTH 256
36
37 int g_session_type = -1;
38
39 struct sigaction session_int_old_action;
40 struct sigaction session_abrt_old_action;
41 struct sigaction session_segv_old_action;
42 struct sigaction session_term_old_action;
43 struct sigaction session_sys_old_action;
44 struct sigaction session_xcpu_old_action;
45
46 EXPORT_API
47 int mm_session_init(int sessiontype)
48 {
49         debug_fenter();
50         return mm_session_init_ex(sessiontype, NULL, NULL);
51         debug_fleave();
52 }
53
54 EXPORT_API
55 int mm_session_init_ex(int sessiontype, session_callback_fn callback, void* user_param)
56 {
57         int result = MM_ERROR_NONE;
58         int ltype = 0;
59         bool do_not_update_session_info = false;
60
61         debug_fenter();
62         debug_log("type : %d", sessiontype);
63
64         if (sessiontype < MM_SESSION_TYPE_MEDIA || sessiontype >= MM_SESSION_TYPE_NUM) {
65                 debug_error("Invalid argument %d",sessiontype);
66                 return MM_ERROR_INVALID_ARGUMENT;
67         }
68
69         result = _mm_session_util_read_type(-1, &ltype);
70         if (MM_ERROR_INVALID_HANDLE != result) {
71                 if ((ltype == MM_SESSION_TYPE_MEDIA_RECORD) && sessiontype == MM_SESSION_TYPE_MEDIA) {
72                         /* already set by mm-camcorder, mm-sound(pcm in), keep going */
73                         do_not_update_session_info = true;
74                 } else {
75                         debug_error("Session already initialized. Please finish current session first");
76                         return MM_ERROR_POLICY_DUPLICATED;
77                 }
78         }
79
80         /* Monitor Callback */
81         if (NULL == callback) {
82                 debug_warning("Null callback function");
83         } else {
84                 debug_warning("It was deprecated, do not use monitor callback, callback(%p), user_param(%p)", callback, user_param);
85         }
86
87         g_session_type = sessiontype;
88
89         if (!do_not_update_session_info) {
90                 result = _mm_session_util_write_type(-1, sessiontype);
91                 if (MM_ERROR_NONE != result) {
92                         debug_error("Write type failed");
93                         g_session_type = -1;
94                         return result;
95                 }
96         }
97
98         debug_fleave();
99
100         return MM_ERROR_NONE;
101 }
102
103 EXPORT_API
104 int mm_session_update_option(session_update_type_t update_type, int options)
105 {
106         int result = MM_ERROR_NONE;
107         int ltype = 0;
108         int loption = 0;
109
110         debug_log("update_type: %d(0:Add, 1:Remove), options: %x", update_type, options);
111
112         if (update_type < 0 || update_type >= MM_SESSION_UPDATE_TYPE_NUM) {
113                 debug_error("Invalid update_type value(%d)", update_type);
114                 return MM_ERROR_INVALID_ARGUMENT;
115         }
116         if (options < 0) {
117                 debug_error("Invalid options value(%x)", options);
118                 return MM_ERROR_INVALID_ARGUMENT;
119         }
120
121         result = _mm_session_util_read_information(-1, &ltype, &loption);
122         if (result) {
123                 debug_error("failed to _mm_session_util_read_information(), ret(%x)", result);
124                 return result;
125         }
126         debug_log("[current] session_type: %d, session_option: %x", ltype, loption);
127
128         if (update_type == MM_SESSION_UPDATE_TYPE_ADD) {
129                 loption |= options;
130         } else if (update_type == MM_SESSION_UPDATE_TYPE_REMOVE) {
131                 loption &= ~options;
132         }
133
134         result = _mm_session_util_write_information(-1, ltype, loption);
135         if (result) {
136                 debug_error("failed to _mm_session_util_write_information(), ret(%x)", result);
137                 return result;
138         }
139
140         debug_log("[updated] session_type: %d, session_option: %x", ltype, loption);
141
142
143         return MM_ERROR_NONE;
144 }
145
146 EXPORT_API
147 int mm_session_add_watch_callback(int watchevent, int watchstate, watch_callback_fn callback, void* user_param)
148 {
149         debug_fenter();
150
151         debug_fleave();
152
153         return MM_ERROR_NOT_SUPPORT_API;
154 }
155
156 EXPORT_API
157 int mm_session_get_current_type(int *sessiontype)
158 {
159         int result = MM_ERROR_NONE;
160         int ltype = 0;
161
162         debug_fenter();
163
164         if (sessiontype == NULL) {
165                 debug_error("input argument is NULL\n");
166                 return MM_ERROR_INVALID_ARGUMENT;
167         }
168
169         result = _mm_session_util_read_type(-1, &ltype);
170         if (result == MM_ERROR_NONE) {
171                 debug_log("Current process session type = [%d]\n", ltype);
172                 *sessiontype = ltype;
173         } else {
174                 debug_error("failed to get current process session type!!\n");
175         }
176
177         debug_fleave();
178
179         return result;
180 }
181
182 EXPORT_API
183 int mm_session_get_current_information(int *session_type, int *session_options)
184 {
185         int result = MM_ERROR_NONE;
186         int ltype = 0;
187         int loption = 0;
188
189         debug_fenter();
190
191         if (session_type == NULL) {
192                 debug_error("input argument is NULL\n");
193                 return MM_ERROR_INVALID_ARGUMENT;
194         }
195
196         result = _mm_session_util_read_information(-1, &ltype, &loption);
197         if (result == MM_ERROR_NONE) {
198                 debug_log("Current process session type = [%d], options = [%x]\n", ltype, loption);
199                 *session_type = ltype;
200                 *session_options = loption;
201         } else {
202                 debug_error("failed to get current process session type, option!!\n");
203         }
204
205         debug_fleave();
206
207         return result;
208 }
209
210 EXPORT_API
211 int mm_session_finish(void)
212 {
213         int result = MM_ERROR_NONE;
214         int sessiontype = MM_SESSION_TYPE_MEDIA;
215
216         debug_fenter();
217
218         result = _mm_session_util_read_type(-1, &sessiontype);
219         if (MM_ERROR_NONE != result) {
220                 debug_error("Can not read current type");
221                 return result;
222         }
223
224         /* Check monitor handle */
225         result = _mm_session_util_delete_information(-1);
226         if(result != MM_ERROR_NONE)
227                 return result;
228
229         debug_fleave();
230
231         return MM_ERROR_NONE;
232 }
233
234 EXPORT_API
235 int mm_session_remove_watch_callback(int watchevent, int watchstate)
236 {
237         debug_fenter();
238
239         debug_fleave();
240
241         return MM_ERROR_NOT_SUPPORT_API;
242 }
243
244 EXPORT_API
245 int mm_session_set_subsession(mm_subsession_t subsession, mm_subsession_option_t option)
246 {
247         debug_fenter();
248
249         debug_fleave();
250
251         return MM_ERROR_NOT_SUPPORT_API;
252 }
253
254 EXPORT_API
255 int mm_session_get_subsession(mm_subsession_t *subsession)
256 {
257         debug_fenter();
258
259         debug_fleave();
260
261         return MM_ERROR_NOT_SUPPORT_API;
262 }
263
264 EXPORT_API
265 int mm_session_set_subevent(mm_session_sub_t subevent)
266 {
267         debug_fenter();
268
269         debug_fleave();
270
271         return MM_ERROR_NOT_SUPPORT_API;
272 }
273
274 EXPORT_API
275 int mm_session_get_subevent(mm_session_sub_t *subevent)
276 {
277         debug_fenter();
278
279         debug_fleave();
280
281         return MM_ERROR_NOT_SUPPORT_API;
282 }
283
284 EXPORT_API
285 int mm_session_reset_resumption_info(void)
286 {
287         debug_fenter();
288
289         debug_fleave();
290
291         return MM_ERROR_NOT_SUPPORT_API;
292 }
293
294 EXPORT_API
295 int _mm_session_util_delete_information(int app_pid)
296 {
297         pid_t mypid;
298         char filename[MAX_FILE_LENGTH];
299
300         if(app_pid == -1)
301                 mypid = getpid();
302         else
303                 mypid = (pid_t)app_pid;
304
305         ////// DELETE SESSION TYPE /////////
306         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
307         if(-1 ==  unlink(filename))
308                 return MM_ERROR_FILE_NOT_FOUND;
309         ////// DELETE SESSION TYPE /////////
310
311         return MM_ERROR_NONE;
312 }
313
314 EXPORT_API
315 int _mm_session_util_write_type(int app_pid, int sessiontype)
316 {
317         pid_t mypid;
318         int fd = -1;
319         char filename[MAX_FILE_LENGTH];
320
321         if(sessiontype < MM_SESSION_TYPE_MEDIA || sessiontype >= MM_SESSION_TYPE_NUM) {
322                 return MM_ERROR_INVALID_ARGUMENT;
323         }
324
325         if(app_pid == -1)
326                 mypid = getpid();
327         else
328                 mypid = (pid_t)app_pid;
329
330         ////// WRITE SESSION TYPE /////////
331         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
332         fd = open(filename, O_WRONLY | O_CREAT, 0644 );
333         if(fd < 0) {
334                 debug_error("open() failed with %d",errno);
335                 return MM_ERROR_FILE_WRITE;
336         }
337         sessiontype = sessiontype << 16;
338         write(fd, &sessiontype, sizeof(int));
339         if(0 > fchmod (fd, 00777)) {
340                 debug_error("fchmod failed with %d", errno);
341         } else {
342                 debug_warning("write sessiontype(%d) to /tmp/mm_session_%d", sessiontype >> 16, mypid);
343         }
344         close(fd);
345         ////// WRITE SESSION TYPE /////////
346
347         return MM_ERROR_NONE;
348 }
349
350 EXPORT_API
351 int _mm_session_util_read_type(int app_pid, int *sessiontype)
352 {
353         pid_t mypid;
354         int fd = -1;
355         char filename[MAX_FILE_LENGTH];
356
357         debug_fenter();
358
359         if(sessiontype == NULL)
360                 return MM_ERROR_INVALID_ARGUMENT;
361
362         if(app_pid == -1)
363                 mypid = getpid();
364         else
365                 mypid = (pid_t)app_pid;
366
367         ////// READ SESSION TYPE /////////
368         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
369         fd = open(filename, O_RDONLY);
370         if(fd < 0) {
371                 return MM_ERROR_INVALID_HANDLE;
372         }
373         read(fd, sessiontype, sizeof(int));
374         *sessiontype = *sessiontype >> 16;
375         debug_warning("read sessiontype(%d) from /tmp/mm_session_%d", *sessiontype, mypid);
376         close(fd);
377         ////// READ SESSION TYPE /////////
378
379         debug_fleave();
380
381         return MM_ERROR_NONE;
382 }
383
384 EXPORT_API
385 int _mm_session_util_write_information(int app_pid, int session_type, int flags)
386 {
387         pid_t mypid;
388         int fd = -1;
389         char filename[MAX_FILE_LENGTH];
390         int result_info = 0;
391
392         if ((session_type != MM_SESSION_TYPE_REPLACED_BY_STREAM) &&
393             (session_type < MM_SESSION_TYPE_MEDIA || session_type >= MM_SESSION_TYPE_NUM)) {
394                 return MM_ERROR_INVALID_ARGUMENT;
395         }
396         if(flags < 0) {
397                 return MM_ERROR_INVALID_ARGUMENT;
398         }
399
400         if(app_pid == -1) {
401                 mypid = getpid();
402         } else {
403                 mypid = (pid_t)app_pid;
404         }
405
406         ////// WRITE SESSION INFO /////////
407         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
408         fd = open(filename, O_WRONLY | O_CREAT, 0644 );
409         if(fd < 0) {
410                 debug_error("open() failed with %d",errno);
411                 return MM_ERROR_FILE_WRITE;
412         }
413
414         result_info = (flags) | (session_type << 16);
415         write(fd, &result_info, sizeof(int));
416         if (0 > fchmod (fd, 00777)) {
417                 debug_error("fchmod failed with %d", errno);
418         } else {
419                 debug_warning("write session information(%x) to /tmp/mm_session_%d", result_info, mypid);
420         }
421         close(fd);
422         ////// WRITE SESSION INFO /////////
423
424         return MM_ERROR_NONE;
425 }
426
427 EXPORT_API
428 int _mm_session_util_read_information(int app_pid, int *session_type, int *flags)
429 {
430         pid_t mypid;
431         int fd = -1;
432         char filename[MAX_FILE_LENGTH];
433         int result_info = 0;
434
435         debug_fenter();
436
437         if(session_type == NULL || flags == NULL) {
438                 return MM_ERROR_INVALID_ARGUMENT;
439         }
440
441         if(app_pid == -1) {
442                 mypid = getpid();
443         } else {
444                 mypid = (pid_t)app_pid;
445         }
446
447         ////// READ SESSION INFO /////////
448         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
449         fd = open(filename, O_RDONLY);
450         if(fd < 0) {
451                 return MM_ERROR_INVALID_HANDLE;
452         }
453         read(fd, &result_info, sizeof(int));
454         *session_type = result_info >> 16;
455         *flags = result_info & 0x0000ffff;
456
457         debug_warning("read session_type(%d), session_option(%x) from /tmp/mm_session_%d", *session_type, *flags, mypid);
458         close(fd);
459         ////// READ SESSION INFO /////////
460
461         debug_fleave();
462
463         return MM_ERROR_NONE;
464 }
465
466 void __session_signal_handler(int signo)
467 {
468         char filename[MAX_FILE_LENGTH];
469         char str_error[256];
470
471         debug_warning("ENTER, sig.num(%d)", signo);
472
473         /* signal block -------------- */
474         sigset_t old_mask, all_mask;
475         sigfillset(&all_mask);
476         sigprocmask(SIG_BLOCK, &all_mask, &old_mask);
477
478         snprintf(filename, sizeof(filename) - 1, "/tmp/mm_session_%d", getpid());
479         if (!remove(filename)) {
480                 debug_log(" remove %s success\n", filename);
481         } else {
482                 strerror_r(errno, str_error, sizeof(str_error));
483                 debug_error(" remove %s failed with %s\n", filename, str_error);
484         }
485
486         sigprocmask(SIG_SETMASK, &old_mask, NULL);
487         /* signal unblock ------------ */
488
489         switch (signo) {
490         case SIGINT:
491                 sigaction(SIGINT, &session_int_old_action, NULL);
492                 raise(signo);
493                 break;
494         case SIGABRT:
495                 sigaction(SIGABRT, &session_abrt_old_action, NULL);
496                 raise(signo);
497                 break;
498         case SIGSEGV:
499                 sigaction(SIGSEGV, &session_segv_old_action, NULL);
500                 raise(signo);
501                 break;
502         case SIGTERM:
503                 sigaction(SIGTERM, &session_term_old_action, NULL);
504                 raise(signo);
505                 break;
506         case SIGSYS:
507                 sigaction(SIGSYS, &session_sys_old_action, NULL);
508                 raise(signo);
509                 break;
510         case SIGXCPU:
511                 sigaction(SIGXCPU, &session_xcpu_old_action, NULL);
512                 raise(signo);
513                 break;
514         default:
515                 break;
516         }
517
518         debug_warning("LEAVE");
519 }
520
521 __attribute__ ((constructor))
522 void __mmsession_initialize(void)
523 {
524         struct sigaction session_action;
525         session_action.sa_handler = __session_signal_handler;
526         session_action.sa_flags = SA_NOCLDSTOP;
527
528         debug_fenter();
529
530         sigemptyset(&session_action.sa_mask);
531
532         sigaction(SIGINT, &session_action, &session_int_old_action);
533         sigaction(SIGABRT, &session_action, &session_abrt_old_action);
534         sigaction(SIGSEGV, &session_action, &session_segv_old_action);
535         sigaction(SIGTERM, &session_action, &session_term_old_action);
536         sigaction(SIGSYS, &session_action, &session_sys_old_action);
537         sigaction(SIGXCPU, &session_action, &session_xcpu_old_action);
538
539         debug_fleave();
540 }
541
542 __attribute__ ((destructor))
543 void __mmsession_finalize(void)
544 {
545
546         debug_fenter();
547
548         _mm_session_util_delete_information(-1);
549
550         sigaction(SIGINT, &session_int_old_action, NULL);
551         sigaction(SIGABRT, &session_abrt_old_action, NULL);
552         sigaction(SIGSEGV, &session_segv_old_action, NULL);
553         sigaction(SIGTERM, &session_term_old_action, NULL);
554         sigaction(SIGSYS, &session_sys_old_action, NULL);
555         sigaction(SIGXCPU, &session_xcpu_old_action, NULL);
556
557         debug_fleave();
558 }
559