fixed prevent issues
[platform/core/appfw/app-core.git] / src / appcore.c
1 /*
2  *  app-core
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@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 #define _GNU_SOURCE
24
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <malloc.h>
31 #include <locale.h>
32 #include <linux/limits.h>
33 #include <glib.h>
34 #include <sys/time.h>
35 #include <dlfcn.h>
36 #include <vconf.h>
37 #include <aul.h>
38 #include "appcore-internal.h"
39
40 #define SQLITE_FLUSH_MAX                (1024*1024)
41
42 #define PKGNAME_MAX 256
43 #define PATH_APP_ROOT "/opt/usr/apps"
44 #define PATH_RO_APP_ROOT "/usr/apps"
45 #define PATH_RES "/res"
46 #define PATH_LOCALE "/locale"
47
48 static struct appcore core;
49 static pid_t _pid;
50
51 static enum appcore_event to_ae[SE_MAX] = {
52         APPCORE_EVENT_UNKNOWN,  /* SE_UNKNOWN */
53         APPCORE_EVENT_LOW_MEMORY,       /* SE_LOWMEM */
54         APPCORE_EVENT_LOW_BATTERY,      /* SE_LOWBAT */
55         APPCORE_EVENT_LANG_CHANGE,      /* SE_LANGCGH */
56         APPCORE_EVENT_REGION_CHANGE,
57 };
58
59
60 enum cb_type {                  /* callback */
61         _CB_NONE,
62         _CB_SYSNOTI,
63         _CB_APPNOTI,
64         _CB_VCONF,
65 };
66
67 struct evt_ops {
68         enum cb_type type;
69         union {
70                 enum appcore_event sys;
71                 enum app_event app;
72                 const char *vkey;
73         } key;
74
75         int (*cb_pre) (void *);
76         int (*cb) (void *);
77         int (*cb_post) (void *);
78
79         int (*vcb_pre) (void *, void *);
80         int (*vcb) (void *, void *);
81         int (*vcb_post) (void *, void *);
82 };
83
84 struct open_s {
85         int (*callback) (void *);
86         void *cbdata;
87 };
88
89 static struct open_s open;
90
91 static int __app_terminate(void *data);
92 static int __app_resume(void *data);
93 static int __app_reset(void *data, bundle *k);
94
95 static int __sys_lowmem_post(void *data, void *evt);
96 static int __sys_lowmem(void *data, void *evt);
97 static int __sys_lowbatt(void *data, void *evt);
98 static int __sys_langchg_pre(void *data, void *evt);
99 static int __sys_langchg(void *data, void *evt);
100 static int __sys_regionchg_pre(void *data, void *evt);
101 static int __sys_regionchg(void *data, void *evt);
102 extern void aul_finalize();
103
104
105 static struct evt_ops evtops[] = {
106         {
107          .type = _CB_VCONF,
108          .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
109          .vcb_post = __sys_lowmem_post,
110          .vcb = __sys_lowmem,
111          },
112         {
113          .type = _CB_VCONF,
114          .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
115          .vcb = __sys_lowbatt,
116          },
117         {
118          .type = _CB_VCONF,
119          .key.vkey = VCONFKEY_LANGSET,
120          .vcb_pre = __sys_langchg_pre,
121          .vcb = __sys_langchg,
122          },
123         {
124          .type = _CB_VCONF,
125          .key.vkey = VCONFKEY_REGIONFORMAT,
126          .vcb_pre = __sys_regionchg_pre,
127          .vcb = __sys_regionchg,
128          },
129         {
130          .type = _CB_VCONF,
131          .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
132          .vcb = __sys_regionchg,
133          },
134 };
135
136 static int __get_dir_name(char *dirname)
137 {
138         char pkg_name[PKGNAME_MAX];
139         int r;
140         int pid;
141
142         pid = getpid();
143         if (pid < 0)
144                 return -1;
145
146         if (aul_app_get_pkgname_bypid(pid, pkg_name, PKGNAME_MAX) != AUL_R_OK)
147                 return -1;
148
149         r = snprintf(dirname, PATH_MAX, PATH_APP_ROOT "/%s" PATH_RES PATH_LOCALE,pkg_name);
150         if (r < 0)
151                 return -1;
152         if (access(dirname, R_OK) == 0) return 0;
153         r = snprintf(dirname, PATH_MAX, PATH_RO_APP_ROOT "/%s" PATH_RES PATH_LOCALE,pkg_name);
154         if (r < 0)
155                 return -1;
156
157         return 0;
158 }
159
160 static int __app_terminate(void *data)
161 {
162         struct appcore *ac = data;
163
164         _retv_if(ac == NULL || ac->ops == NULL, -1);
165         _retv_if(ac->ops->cb_app == NULL, 0);
166
167         ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
168
169         return 0;
170 }
171
172 static gboolean __prt_ltime(gpointer data)
173 {
174         int msec;
175
176         msec = appcore_measure_time_from(NULL);
177         if (msec)
178                 _DBG("[APP %d] first idle after reset: %d msec", _pid, msec);
179
180         return FALSE;
181 }
182
183 static int __app_reset(void *data, bundle * k)
184 {
185         struct appcore *ac = data;
186         _retv_if(ac == NULL || ac->ops == NULL, -1);
187         _retv_if(ac->ops->cb_app == NULL, 0);
188
189         g_idle_add(__prt_ltime, ac);
190
191         ac->ops->cb_app(AE_RESET, ac->ops->data, k);
192
193         return 0;
194 }
195
196 static int __app_resume(void *data)
197 {
198         x_raise_win(getpid());
199         return 0;
200 }
201
202 static int __sys_do_default(struct appcore *ac, enum sys_event event)
203 {
204         int r;
205
206         switch (event) {
207         case SE_LOWBAT:
208                 /*r = __def_lowbatt(ac);*/
209                 r = 0;
210                 break;
211         default:
212                 r = 0;
213                 break;
214         };
215
216         return r;
217 }
218
219 static int __sys_do(struct appcore *ac, enum sys_event event)
220 {
221         struct sys_op *op;
222
223         _retv_if(ac == NULL || event >= SE_MAX, -1);
224
225         op = &ac->sops[event];
226
227         if (op->func == NULL)
228                 return __sys_do_default(ac, event);
229
230         return op->func(op->data);
231 }
232
233 static int __sys_lowmem_post(void *data, void *evt)
234 {
235 #if defined(MEMORY_FLUSH_ACTIVATE)
236         struct appcore *ac = data;
237         ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
238 #else
239         malloc_trim(0);
240 #endif
241         return 0;
242 }
243
244 static int __sys_lowmem(void *data, void *evt)
245 {
246         return __sys_do(data, SE_LOWMEM);
247 }
248
249 static int __sys_lowbatt(void *data, void *evt)
250 {
251         keynode_t *key = evt;
252         int val;
253
254         val = vconf_keynode_get_int(key);
255
256         /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
257         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
258                 return __sys_do(data, SE_LOWBAT);
259
260         return 0;
261 }
262
263 static int __sys_langchg_pre(void *data, void *evt)
264 {
265         update_lang();
266         return 0;
267 }
268
269 static int __sys_langchg(void *data, void *evt)
270 {
271         return __sys_do(data, SE_LANGCHG);
272 }
273
274 static int __sys_regionchg_pre(void *data, void *evt)
275 {
276         update_region();
277         return 0;
278 }
279
280 static int __sys_regionchg(void *data, void *evt)
281 {
282         return __sys_do(data, SE_REGIONCHG);
283 }
284
285 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
286 {
287         _ret_if(eo == NULL);
288
289         if (eo->vcb_pre)
290                 eo->vcb_pre(data, key);
291
292         if (eo->vcb)
293                 eo->vcb(data, key);
294
295         if (eo->vcb_post)
296                 eo->vcb_post(data, key);
297 }
298
299 static void __vconf_cb(keynode_t *key, void *data)
300 {
301         int i;
302         const char *name;
303
304         name = vconf_keynode_get_name(key);
305         _ret_if(name == NULL);
306
307         _DBG("[APP %d] vconf changed: %s", _pid, name);
308
309         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
310                 struct evt_ops *eo = &evtops[i];
311
312                 switch (eo->type) {
313                 case _CB_VCONF:
314                         if (!strcmp(name, eo->key.vkey))
315                                 __vconf_do(eo, key, data);
316                         break;
317                 default:
318                         /* do nothing */
319                         break;
320                 }
321         }
322 }
323
324 static int __add_vconf(struct appcore *ac)
325 {
326         int i;
327         int r;
328
329         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
330                 struct evt_ops *eo = &evtops[i];
331
332                 switch (eo->type) {
333                 case _CB_VCONF:
334                         r = vconf_notify_key_changed(eo->key.vkey, __vconf_cb,
335                                                      ac);
336                         break;
337                 default:
338                         /* do nothing */
339                         break;
340                 }
341         }
342
343         return 0;
344 }
345
346 static int __del_vconf(void)
347 {
348         int i;
349         int r;
350
351         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
352                 struct evt_ops *eo = &evtops[i];
353
354                 switch (eo->type) {
355                 case _CB_VCONF:
356                         r = vconf_ignore_key_changed(eo->key.vkey, __vconf_cb);
357                         break;
358                 default:
359                         /* do nothing */
360                         break;
361                 }
362         }
363
364         return 0;
365 }
366
367 static int __aul_handler(aul_type type, bundle *b, void *data)
368 {
369         int ret;
370
371         switch (type) {
372         case AUL_START:
373                 _DBG("[APP %d]     AUL event: AUL_START", _pid);
374                 __app_reset(data, b);
375                 break;
376         case AUL_RESUME:
377                 _DBG("[APP %d]     AUL event: AUL_RESUME", _pid);
378                 if(open.callback) {
379                         ret = open.callback(open.cbdata);
380                         if (ret == 0)
381                                 __app_resume(data);
382                 } else {
383                         __app_resume(data);
384                 }
385                 break;
386         case AUL_TERMINATE:
387                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", _pid);
388                 __app_terminate(data);
389                 break;
390         default:
391                 _DBG("[APP %d]     AUL event: %d", _pid, type);
392                 /* do nothing */
393                 break;
394         }
395
396         return 0;
397 }
398
399
400 static void __clear(struct appcore *ac)
401 {
402         memset(ac, 0, sizeof(struct appcore));
403 }
404
405 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
406                                        void *data)
407 {
408         open.callback = cb;
409         open.cbdata = data;
410
411         return 0;
412 }
413
414 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
415                                           int (*cb) (void *), void *data)
416 {
417         struct appcore *ac = &core;
418         struct sys_op *op;
419         enum sys_event se;
420
421         for (se = SE_UNKNOWN; se < SE_MAX; se++) {
422                 if (event == to_ae[se])
423                         break;
424         }
425
426         if (se == SE_UNKNOWN || se >= SE_MAX) {
427                 _ERR("Unregistered event");
428                 errno = EINVAL;
429                 return -1;
430         }
431
432         op = &ac->sops[se];
433
434         op->func = cb;
435         op->data = data;
436
437         return 0;
438 }
439
440
441
442 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
443                             int argc, char **argv)
444 {
445         int r;
446         char dirname[PATH_MAX];
447
448         if (core.state != 0) {
449                 _ERR("Already in use");
450                 errno = EALREADY;
451                 return -1;
452         }
453
454         if (ops == NULL || ops->cb_app == NULL) {
455                 _ERR("ops or callback function is null");
456                 errno = EINVAL;
457                 return -1;
458         }
459
460         r = __get_dir_name(dirname);
461         r = set_i18n(name, dirname);
462         _retv_if(r == -1, -1);
463
464         r = __add_vconf(&core);
465         if (r == -1) {
466                 _ERR("Add vconf callback failed");
467                 goto err;
468         }
469
470         r = aul_launch_init(__aul_handler, &core);
471         if (r < 0) {
472                 _ERR("Aul init failed: %d", r);
473                 goto err;
474         }
475
476         r = aul_launch_argv_handler(argc, argv);
477         if (r < 0) {
478                 _ERR("Aul argv handler failed: %d", r);
479                 goto err;
480         }
481
482         core.ops = ops;
483         core.state = 1;         /* TODO: use enum value */
484
485         _pid = getpid();
486
487         return 0;
488  err:
489         __del_vconf();
490         __clear(&core);
491         return -1;
492 }
493
494 EXPORT_API void appcore_exit(void)
495 {
496         if (core.state) {
497                 __del_vconf();
498                 __clear(&core);
499         }
500         aul_finalize();
501 }
502
503 EXPORT_API int appcore_flush_memory(void)
504 {
505         int (*flush_fn) (int);
506         int size = 0;
507
508         struct appcore *ac = &core;
509
510         if (!core.state) {
511                 _ERR("Appcore not initialized");
512                 return -1;
513         }
514
515         _DBG("[APP %d] Flushing memory ...", _pid);
516
517         if (ac->ops->cb_app) {
518                 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
519         }
520
521         flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
522         if (flush_fn) {
523                 size = flush_fn(SQLITE_FLUSH_MAX);
524         }
525
526         malloc_trim(0);
527         /*
528         *Disabled - the impact of stack_trim() is unclear
529         *stack_trim();
530         */
531
532         _DBG("[APP %d] Flushing memory DONE", _pid);
533
534         return 0;
535 }