Do not raise() inside signal handler
[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         int result = MM_ERROR_NONE;
50         int ltype = 0;
51         bool do_not_update_session_info = false;
52
53         debug_fenter();
54         debug_log("type : %d", sessiontype);
55
56         if (sessiontype < MM_SESSION_TYPE_MEDIA || sessiontype >= MM_SESSION_TYPE_NUM) {
57                 debug_error("Invalid argument %d",sessiontype);
58                 return MM_ERROR_INVALID_ARGUMENT;
59         }
60
61         result = _mm_session_util_read_type(-1, &ltype);
62         if (MM_ERROR_INVALID_HANDLE != result) {
63                 if ((ltype == MM_SESSION_TYPE_MEDIA_RECORD) && sessiontype == MM_SESSION_TYPE_MEDIA) {
64                         /* already set by mm-camcorder, mm-sound(pcm in), keep going */
65                         do_not_update_session_info = true;
66                 } else {
67                         debug_error("Session already initialized. Please finish current session first");
68                         return MM_ERROR_POLICY_DUPLICATED;
69                 }
70         }
71
72         g_session_type = sessiontype;
73
74         if (!do_not_update_session_info) {
75                 result = _mm_session_util_write_type(-1, sessiontype);
76                 if (MM_ERROR_NONE != result) {
77                         debug_error("Write type failed");
78                         g_session_type = -1;
79                         return result;
80                 }
81         }
82
83         debug_fleave();
84
85         return MM_ERROR_NONE;
86 }
87
88 EXPORT_API
89 int mm_session_update_option(session_update_type_t update_type, int options)
90 {
91         int result = MM_ERROR_NONE;
92         int ltype = 0;
93         int loption = 0;
94
95         debug_log("update_type: %d(0:Add, 1:Remove), options: %x", update_type, options);
96
97         if (update_type < 0 || update_type >= MM_SESSION_UPDATE_TYPE_NUM) {
98                 debug_error("Invalid update_type value(%d)", update_type);
99                 return MM_ERROR_INVALID_ARGUMENT;
100         }
101         if (options < 0) {
102                 debug_error("Invalid options value(%x)", options);
103                 return MM_ERROR_INVALID_ARGUMENT;
104         }
105
106         result = _mm_session_util_read_information(-1, &ltype, &loption);
107         if (result) {
108                 debug_error("failed to _mm_session_util_read_information(), ret(%x)", result);
109                 return result;
110         }
111         debug_log("[current] session_type: %d, session_option: %x", ltype, loption);
112
113         if (update_type == MM_SESSION_UPDATE_TYPE_ADD) {
114                 loption |= options;
115         } else if (update_type == MM_SESSION_UPDATE_TYPE_REMOVE) {
116                 loption &= ~options;
117         }
118
119         result = _mm_session_util_write_information(-1, ltype, loption);
120         if (result) {
121                 debug_error("failed to _mm_session_util_write_information(), ret(%x)", result);
122                 return result;
123         }
124
125         debug_log("[updated] session_type: %d, session_option: %x", ltype, loption);
126
127
128         return MM_ERROR_NONE;
129 }
130
131 EXPORT_API
132 int mm_session_get_current_type(int *sessiontype)
133 {
134         int result = MM_ERROR_NONE;
135         int ltype = 0;
136
137         debug_fenter();
138
139         if (sessiontype == NULL) {
140                 debug_error("input argument is NULL\n");
141                 return MM_ERROR_INVALID_ARGUMENT;
142         }
143
144         result = _mm_session_util_read_type(-1, &ltype);
145         if (result == MM_ERROR_NONE) {
146                 debug_log("Current process session type = [%d]\n", ltype);
147                 *sessiontype = ltype;
148         } else {
149                 debug_error("failed to get current process session type!!\n");
150         }
151
152         debug_fleave();
153
154         return result;
155 }
156
157 EXPORT_API
158 int mm_session_get_current_information(int *session_type, int *session_options)
159 {
160         int result = MM_ERROR_NONE;
161         int ltype = 0;
162         int loption = 0;
163
164         debug_fenter();
165
166         if (session_type == NULL) {
167                 debug_error("input argument is NULL\n");
168                 return MM_ERROR_INVALID_ARGUMENT;
169         }
170
171         result = _mm_session_util_read_information(-1, &ltype, &loption);
172         if (result == MM_ERROR_NONE) {
173                 debug_log("Current process session type = [%d], options = [%x]\n", ltype, loption);
174                 *session_type = ltype;
175                 *session_options = loption;
176         } else {
177                 debug_error("failed to get current process session type, option!!\n");
178         }
179
180         debug_fleave();
181
182         return result;
183 }
184
185 EXPORT_API
186 int mm_session_finish(void)
187 {
188         int result = MM_ERROR_NONE;
189         int sessiontype = MM_SESSION_TYPE_MEDIA;
190
191         debug_fenter();
192
193         result = _mm_session_util_read_type(-1, &sessiontype);
194         if (MM_ERROR_NONE != result) {
195                 debug_error("Can not read current type");
196                 return result;
197         }
198
199         /* Check monitor handle */
200         result = _mm_session_util_delete_information(-1);
201         if(result != MM_ERROR_NONE)
202                 return result;
203
204         debug_fleave();
205
206         return MM_ERROR_NONE;
207 }
208
209 EXPORT_API
210 int _mm_session_util_delete_information(int app_pid)
211 {
212         pid_t mypid;
213         char filename[MAX_FILE_LENGTH];
214
215         if(app_pid == -1)
216                 mypid = getpid();
217         else
218                 mypid = (pid_t)app_pid;
219
220         ////// DELETE SESSION TYPE /////////
221         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
222         if(-1 ==  unlink(filename))
223                 return MM_ERROR_FILE_NOT_FOUND;
224         ////// DELETE SESSION TYPE /////////
225
226         return MM_ERROR_NONE;
227 }
228
229 EXPORT_API
230 int _mm_session_util_write_type(int app_pid, int sessiontype)
231 {
232         pid_t mypid;
233         int fd = -1;
234         char filename[MAX_FILE_LENGTH];
235
236         if(sessiontype < MM_SESSION_TYPE_MEDIA || sessiontype >= MM_SESSION_TYPE_NUM) {
237                 return MM_ERROR_INVALID_ARGUMENT;
238         }
239
240         if(app_pid == -1)
241                 mypid = getpid();
242         else
243                 mypid = (pid_t)app_pid;
244
245         ////// WRITE SESSION TYPE /////////
246         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
247         fd = open(filename, O_WRONLY | O_CREAT, 0644 );
248         if(fd < 0) {
249                 debug_error("open() failed with %d",errno);
250                 return MM_ERROR_FILE_WRITE;
251         }
252         sessiontype = sessiontype << 16;
253         write(fd, &sessiontype, sizeof(int));
254         if(0 > fchmod (fd, 00777)) {
255                 debug_error("fchmod failed with %d", errno);
256         } else {
257                 debug_warning("write sessiontype(%d) to /tmp/mm_session_%d", sessiontype >> 16, mypid);
258         }
259         close(fd);
260         ////// WRITE SESSION TYPE /////////
261
262         return MM_ERROR_NONE;
263 }
264
265 EXPORT_API
266 int _mm_session_util_read_type(int app_pid, int *sessiontype)
267 {
268         pid_t mypid;
269         int fd = -1;
270         char filename[MAX_FILE_LENGTH];
271
272         debug_fenter();
273
274         if(sessiontype == NULL)
275                 return MM_ERROR_INVALID_ARGUMENT;
276
277         if(app_pid == -1)
278                 mypid = getpid();
279         else
280                 mypid = (pid_t)app_pid;
281
282         ////// READ SESSION TYPE /////////
283         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
284         fd = open(filename, O_RDONLY);
285         if(fd < 0) {
286                 return MM_ERROR_INVALID_HANDLE;
287         }
288         read(fd, sessiontype, sizeof(int));
289         *sessiontype = *sessiontype >> 16;
290         debug_warning("read sessiontype(%d) from /tmp/mm_session_%d", *sessiontype, mypid);
291         close(fd);
292         ////// READ SESSION TYPE /////////
293
294         debug_fleave();
295
296         return MM_ERROR_NONE;
297 }
298
299 EXPORT_API
300 int _mm_session_util_write_information(int app_pid, int session_type, int flags)
301 {
302         pid_t mypid;
303         int fd = -1;
304         char filename[MAX_FILE_LENGTH];
305         int result_info = 0;
306
307         if ((session_type != MM_SESSION_TYPE_REPLACED_BY_STREAM) &&
308             (session_type < MM_SESSION_TYPE_MEDIA || session_type >= MM_SESSION_TYPE_NUM)) {
309                 return MM_ERROR_INVALID_ARGUMENT;
310         }
311         if(flags < 0) {
312                 return MM_ERROR_INVALID_ARGUMENT;
313         }
314
315         if(app_pid == -1) {
316                 mypid = getpid();
317         } else {
318                 mypid = (pid_t)app_pid;
319         }
320
321         ////// WRITE SESSION INFO /////////
322         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
323         fd = open(filename, O_WRONLY | O_CREAT, 0644 );
324         if(fd < 0) {
325                 debug_error("open() failed with %d",errno);
326                 return MM_ERROR_FILE_WRITE;
327         }
328
329         result_info = (flags) | (session_type << 16);
330         write(fd, &result_info, sizeof(int));
331         if (0 > fchmod (fd, 00777)) {
332                 debug_error("fchmod failed with %d", errno);
333         } else {
334                 debug_warning("write session information(%x) to /tmp/mm_session_%d", result_info, mypid);
335         }
336         close(fd);
337         ////// WRITE SESSION INFO /////////
338
339         return MM_ERROR_NONE;
340 }
341
342 EXPORT_API
343 int _mm_session_util_read_information(int app_pid, int *session_type, int *flags)
344 {
345         pid_t mypid;
346         int fd = -1;
347         char filename[MAX_FILE_LENGTH];
348         int result_info = 0;
349
350         debug_fenter();
351
352         if(session_type == NULL || flags == NULL) {
353                 return MM_ERROR_INVALID_ARGUMENT;
354         }
355
356         if(app_pid == -1) {
357                 mypid = getpid();
358         } else {
359                 mypid = (pid_t)app_pid;
360         }
361
362         ////// READ SESSION INFO /////////
363         snprintf(filename, sizeof(filename)-1, "/tmp/mm_session_%d", mypid);
364         fd = open(filename, O_RDONLY);
365         if(fd < 0) {
366                 return MM_ERROR_INVALID_HANDLE;
367         }
368         read(fd, &result_info, sizeof(int));
369         *session_type = result_info >> 16;
370         *flags = result_info & 0x0000ffff;
371
372         debug_warning("read session_type(%d), session_option(%x) from /tmp/mm_session_%d", *session_type, *flags, mypid);
373         close(fd);
374         ////// READ SESSION INFO /////////
375
376         debug_fleave();
377
378         return MM_ERROR_NONE;
379 }
380
381 void __session_signal_handler(int signo, siginfo_t *siginfo, void *context)
382 {
383         char filename[MAX_FILE_LENGTH];
384         char str_error[256];
385
386         debug_warning("ENTER, sig.num(%d)", signo);
387
388         /* signal block -------------- */
389         sigset_t old_mask, all_mask;
390         sigfillset(&all_mask);
391         sigprocmask(SIG_BLOCK, &all_mask, &old_mask);
392
393         snprintf(filename, sizeof(filename) - 1, "/tmp/mm_session_%d", getpid());
394         if (!remove(filename)) {
395                 debug_log(" remove %s success\n", filename);
396         } else {
397                 strerror_r(errno, str_error, sizeof(str_error));
398                 debug_error(" remove %s failed with %s\n", filename, str_error);
399         }
400
401         sigprocmask(SIG_SETMASK, &old_mask, NULL);
402         /* signal unblock ------------ */
403
404         switch (signo) {
405         case SIGINT:
406                 if (session_int_old_action.sa_sigaction)
407                         session_int_old_action.sa_sigaction(signo, siginfo, context);
408                 else
409                         sigaction(signo, &session_int_old_action, NULL);
410                 break;
411         case SIGABRT:
412                 if (session_abrt_old_action.sa_sigaction)
413                         session_abrt_old_action.sa_sigaction(signo, siginfo, context);
414                 else
415                         sigaction(signo, &session_abrt_old_action, NULL);
416                 break;
417         case SIGSEGV:
418                 if (session_segv_old_action.sa_sigaction)
419                         session_segv_old_action.sa_sigaction(signo, siginfo, context);
420                 else
421                         sigaction(signo, &session_segv_old_action, NULL);
422                 break;
423         case SIGTERM:
424                 if (session_term_old_action.sa_sigaction)
425                         session_term_old_action.sa_sigaction(signo, siginfo, context);
426                 else
427                         sigaction(signo, &session_term_old_action, NULL);
428                 break;
429         case SIGSYS:
430                 if (session_sys_old_action.sa_sigaction)
431                         session_sys_old_action.sa_sigaction(signo, siginfo, context);
432                 else
433                         sigaction(signo, &session_sys_old_action, NULL);
434                 break;
435         case SIGXCPU:
436                 if (session_xcpu_old_action.sa_sigaction)
437                         session_xcpu_old_action.sa_sigaction(signo, siginfo, context);
438                 else
439                         sigaction(signo, &session_xcpu_old_action, NULL);
440                 break;
441         default:
442                 break;
443         }
444
445         debug_warning("LEAVE");
446 }
447
448 __attribute__ ((constructor))
449 void __mmsession_initialize(void)
450 {
451         struct sigaction session_action;
452         session_action.sa_sigaction = __session_signal_handler;
453         session_action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
454
455         debug_fenter();
456
457         sigemptyset(&session_action.sa_mask);
458
459         sigaction(SIGINT, &session_action, &session_int_old_action);
460         sigaction(SIGABRT, &session_action, &session_abrt_old_action);
461         sigaction(SIGSEGV, &session_action, &session_segv_old_action);
462         sigaction(SIGTERM, &session_action, &session_term_old_action);
463         sigaction(SIGSYS, &session_action, &session_sys_old_action);
464         sigaction(SIGXCPU, &session_action, &session_xcpu_old_action);
465
466         debug_fleave();
467 }
468
469 __attribute__ ((destructor))
470 void __mmsession_finalize(void)
471 {
472
473         debug_fenter();
474
475         _mm_session_util_delete_information(-1);
476
477         sigaction(SIGINT, &session_int_old_action, NULL);
478         sigaction(SIGABRT, &session_abrt_old_action, NULL);
479         sigaction(SIGSEGV, &session_segv_old_action, NULL);
480         sigaction(SIGTERM, &session_term_old_action, NULL);
481         sigaction(SIGSYS, &session_sys_old_action, NULL);
482         sigaction(SIGXCPU, &session_xcpu_old_action, NULL);
483
484         debug_fleave();
485 }
486