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