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