mobile-lua: add additional LABELLED_BY relation
[profile/tv/apps/native/screen-reader.git] / src / main.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <time.h>
18 #include <signal.h>
19 #include <err.h>
20 #include <execinfo.h>
21 #include <appcore-efl.h>
22 #include <Elementary.h>
23 #include <eldbus-1/Eldbus.h>
24 #include <vconf.h>
25 #ifndef SCREEN_READER_TV
26 #include "navigator.h"
27 #include "screen_reader_gestures.h"
28 #endif
29 #include "logger.h"
30 #include "screen_reader.h"
31 #include "screen_reader_switch.h"
32
33 #define MAX_STACK_FRAMES 64
34 static void *stack_traces[MAX_STACK_FRAMES];
35
36 void posix_print_stack_trace(FILE * log_file)
37 {
38         int i, trace_size = 0;
39         char **messages = (char **)NULL;
40
41         trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
42         messages = backtrace_symbols(stack_traces, trace_size);
43
44         /* skip the first couple stack frames (as they are this function and
45            our handler) and also skip the last frame as it's (always?) junk. */
46         // for (i = 3; i < (trace_size - 1); ++i)
47         for (i = 0; i < trace_size; ++i)        // we'll use this for now so you can see what's going on
48         {
49                 fprintf(log_file, "  BACKTRACE LINE %i: %s\n", i, messages[i]);
50         }
51         if (messages) {
52                 free(messages);
53         }
54 }
55
56 void print_warning(int sig, siginfo_t * siginfo, FILE * log_file)
57 {
58         switch (sig) {
59         case SIGSEGV:
60                 fputs("Caught SIGSEGV: Segmentation Fault\n", log_file);
61                 break;
62         case SIGINT:
63                 fputs("Caught SIGINT: Interactive attention signal, (usually ctrl+c)\n", log_file);
64                 break;
65         case SIGFPE:
66                 switch (siginfo->si_code) {
67                 case FPE_INTDIV:
68                         fputs("Caught SIGFPE: (integer divide by zero)\n", log_file);
69                         break;
70                 case FPE_INTOVF:
71                         fputs("Caught SIGFPE: (integer overflow)\n", log_file);
72                         break;
73                 case FPE_FLTDIV:
74                         fputs("Caught SIGFPE: (floating-point divide by zero)\n", log_file);
75                         break;
76                 case FPE_FLTOVF:
77                         fputs("Caught SIGFPE: (floating-point overflow)\n", log_file);
78                         break;
79                 case FPE_FLTUND:
80                         fputs("Caught SIGFPE: (floating-point underflow)\n", log_file);
81                         break;
82                 case FPE_FLTRES:
83                         fputs("Caught SIGFPE: (floating-point inexact result)\n", log_file);
84                         break;
85                 case FPE_FLTINV:
86                         fputs("Caught SIGFPE: (floating-point invalid operation)\n", log_file);
87                         break;
88                 case FPE_FLTSUB:
89                         fputs("Caught SIGFPE: (subscript out of range)\n", log_file);
90                         break;
91                 default:
92                         fputs("Caught SIGFPE: Arithmetic Exception\n", log_file);
93                         break;
94                 }
95                 break;
96         case SIGILL:
97                 switch (siginfo->si_code) {
98                 case ILL_ILLOPC:
99                         fputs("Caught SIGILL: (illegal opcode)\n", log_file);
100                         break;
101                 case ILL_ILLOPN:
102                         fputs("Caught SIGILL: (illegal operand)\n", log_file);
103                         break;
104                 case ILL_ILLADR:
105                         fputs("Caught SIGILL: (illegal addressing mode)\n", log_file);
106                         break;
107                 case ILL_ILLTRP:
108                         fputs("Caught SIGILL: (illegal trap)\n", log_file);
109                         break;
110                 case ILL_PRVOPC:
111                         fputs("Caught SIGILL: (privileged opcode)\n", log_file);
112                         break;
113                 case ILL_PRVREG:
114                         fputs("Caught SIGILL: (privileged register)\n", log_file);
115                         break;
116                 case ILL_COPROC:
117                         fputs("Caught SIGILL: (coprocessor error)\n", log_file);
118                         break;
119                 case ILL_BADSTK:
120                         fputs("Caught SIGILL: (internal stack error)\n", log_file);
121                         break;
122                 default:
123                         fputs("Caught SIGILL: Illegal Instruction\n", log_file);
124                         break;
125                 }
126                 break;
127         case SIGTERM:
128                 fputs("Caught SIGTERM: a termination request was sent to the program\n", log_file);
129                 break;
130         case SIGABRT:
131                 fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", log_file);
132                 break;
133         default:
134                 break;
135         }
136 }
137
138 void posix_signal_handler(int sig, siginfo_t * siginfo, void *context)
139 {
140         char file_name[256];
141         struct tm *timeinfo;
142         time_t rawtime = time(NULL);
143         timeinfo = localtime(&rawtime);
144         if (timeinfo)
145                 snprintf(file_name, sizeof(file_name), "/tmp/screen_reader_crash_stacktrace_%i%i%i_%i:%i:%i_pid_%i.log", timeinfo->tm_year, timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, getpid());
146         else
147                 snprintf(file_name, sizeof(file_name), "/tmp/screen_reader_crash_stacktrace_pid_%i.log", getpid());
148
149         FILE *log_file = fopen(file_name, "w");
150         if (log_file) {
151                 (void)context;
152                 print_warning(sig, siginfo, stderr);
153
154                 /* check file if it is symbolic link */
155                 struct stat lstat_info;
156                 if (lstat(file_name, &lstat_info) != -1) {
157                         print_warning(sig, siginfo, log_file);
158                         posix_print_stack_trace(log_file);
159                 }
160
161                 fclose(log_file);
162                 log_file = NULL;
163         }
164
165         _Exit(1);
166 }
167
168 static uint8_t alternate_stack[SIGSTKSZ];
169 void set_signal_handler()
170 {
171         /* setup alternate stack */
172         {
173                 stack_t ss = { };
174                 /* malloc is usually used here, I'm not 100% sure my static allocation
175                    is valid but it seems to work just fine. */
176                 ss.ss_sp = (void *)alternate_stack;
177                 ss.ss_size = SIGSTKSZ;
178                 ss.ss_flags = 0;
179
180                 if (sigaltstack(&ss, NULL) != 0) {
181                         err(1, "sigaltstack");
182                 }
183         }
184
185         /* register our signal handlers */
186         {
187                 struct sigaction sig_action = { };
188                 sig_action.sa_sigaction = posix_signal_handler;
189                 sigemptyset(&sig_action.sa_mask);
190
191                 sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
192
193                 if (sigaction(SIGSEGV, &sig_action, NULL) != 0) {
194                         err(1, "sigaction");
195                 }
196                 if (sigaction(SIGFPE, &sig_action, NULL) != 0) {
197                         err(1, "sigaction");
198                 }
199                 if (sigaction(SIGINT, &sig_action, NULL) != 0) {
200                         err(1, "sigaction");
201                 }
202                 if (sigaction(SIGILL, &sig_action, NULL) != 0) {
203                         err(1, "sigaction");
204                 }
205                 if (sigaction(SIGTERM, &sig_action, NULL) != 0) {
206                         err(1, "sigaction");
207                 }
208                 if (sigaction(SIGABRT, &sig_action, NULL) != 0) {
209                         err(1, "sigaction");
210                 }
211         }
212 }
213
214 static int app_create(void *data)
215 {
216         if (vconf_set_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, 1))
217                 ERROR("Can't set value of %s vconf key to 1", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS);
218         elm_init(0, NULL);
219         atspi_init();
220
221         screen_reader_create_service(data);
222 #ifndef SCREEN_READER_TV
223         screen_reader_gestures_init();
224         navigator_init();
225 #endif
226         screen_reader_switch_enabled_set(EINA_TRUE);
227         return 0;
228 }
229
230 static int app_terminate(void *data)
231 {
232         DEBUG("screen reader terminating");
233 #ifndef SCREEN_READER_TV
234         DEBUG("terminate navigator");
235         navigator_shutdown();
236         DEBUG("terminate gestures");
237         screen_reader_gestures_shutdown();
238 #endif
239         DEBUG("terminate service");
240         screen_reader_terminate_service(data);
241         DEBUG("clear ScreenReaderEnabled property");
242         screen_reader_switch_enabled_set(EINA_FALSE);
243         DEBUG("screen reader terminated");
244
245         DEBUG("libatspi terminated");
246         atspi_exit();
247         if (vconf_set_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, 0))
248                 ERROR("Can't set value of %s vconf key to 1", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS);
249         return 0;
250 }
251
252 int main(int argc, char **argv)
253 {
254         set_signal_handler();
255         unsetenv("ELM_ATSPI_MODE");
256
257         struct appcore_ops ops = {
258                 .create = app_create,
259                 .terminate = app_terminate,
260                 .pause = NULL,
261                 .resume = NULL,
262                 .reset = NULL
263         };
264         ops.data = get_pointer_to_service_data_struct();
265
266         return appcore_efl_main("screen-reader", &argc, &argv, &ops);
267 }