init wayland support
[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 #ifdef WAYLAND
199         struct appcore *ac = data;
200
201         _retv_if(ac == NULL || ac->ops == NULL, -1);
202         _retv_if(ac->ops->cb_app == NULL, 0);
203
204         ac->ops->cb_app(AE_RESUME, ac->ops->data, NULL);
205
206 #else
207         x_raise_win(getpid());
208 #endif
209         return 0;
210 }
211
212 static int __sys_do_default(struct appcore *ac, enum sys_event event)
213 {
214         int r;
215
216         switch (event) {
217         case SE_LOWBAT:
218                 /*r = __def_lowbatt(ac);*/
219                 r = 0;
220                 break;
221         default:
222                 r = 0;
223                 break;
224         };
225
226         return r;
227 }
228
229 static int __sys_do(struct appcore *ac, enum sys_event event)
230 {
231         struct sys_op *op;
232
233         _retv_if(ac == NULL || event >= SE_MAX, -1);
234
235         op = &ac->sops[event];
236
237         if (op->func == NULL)
238                 return __sys_do_default(ac, event);
239
240         return op->func(op->data);
241 }
242
243 static int __sys_lowmem_post(void *data, void *evt)
244 {
245         keynode_t *key = evt;
246         int val;
247
248         val = vconf_keynode_get_int(key);
249
250         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)     {
251 #if defined(MEMORY_FLUSH_ACTIVATE)
252                 struct appcore *ac = data;
253                 ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
254 #else
255                 malloc_trim(0);
256 #endif
257         }
258         return 0;
259 }
260
261 static int __sys_lowmem(void *data, void *evt)
262 {
263         keynode_t *key = evt;
264         int val;
265
266         val = vconf_keynode_get_int(key);
267
268         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
269                 return __sys_do(data, SE_LOWMEM);
270
271         return 0;
272 }
273
274 static int __sys_lowbatt(void *data, void *evt)
275 {
276         keynode_t *key = evt;
277         int val;
278
279         val = vconf_keynode_get_int(key);
280
281         /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
282         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
283                 return __sys_do(data, SE_LOWBAT);
284
285         return 0;
286 }
287
288 static int __sys_langchg_pre(void *data, void *evt)
289 {
290         update_lang();
291         return 0;
292 }
293
294 static int __sys_langchg(void *data, void *evt)
295 {
296         return __sys_do(data, SE_LANGCHG);
297 }
298
299 static int __sys_regionchg_pre(void *data, void *evt)
300 {
301         update_region();
302         return 0;
303 }
304
305 static int __sys_regionchg(void *data, void *evt)
306 {
307         return __sys_do(data, SE_REGIONCHG);
308 }
309
310 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
311 {
312         _ret_if(eo == NULL);
313
314         if (eo->vcb_pre)
315                 eo->vcb_pre(data, key);
316
317         if (eo->vcb)
318                 eo->vcb(data, key);
319
320         if (eo->vcb_post)
321                 eo->vcb_post(data, key);
322 }
323
324 static void __vconf_cb(keynode_t *key, void *data)
325 {
326         int i;
327         const char *name;
328
329         name = vconf_keynode_get_name(key);
330         _ret_if(name == NULL);
331
332         _DBG("[APP %d] vconf changed: %s", _pid, name);
333
334         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
335                 struct evt_ops *eo = &evtops[i];
336
337                 switch (eo->type) {
338                 case _CB_VCONF:
339                         if (!strcmp(name, eo->key.vkey))
340                                 __vconf_do(eo, key, data);
341                         break;
342                 default:
343                         /* do nothing */
344                         break;
345                 }
346         }
347 }
348
349 static int __add_vconf(struct appcore *ac)
350 {
351         int i;
352         int r;
353
354         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
355                 struct evt_ops *eo = &evtops[i];
356
357                 switch (eo->type) {
358                 case _CB_VCONF:
359                         r = vconf_notify_key_changed(eo->key.vkey, __vconf_cb,
360                                                      ac);
361                         break;
362                 default:
363                         /* do nothing */
364                         break;
365                 }
366         }
367
368         return 0;
369 }
370
371 static int __del_vconf(void)
372 {
373         int i;
374         int r;
375
376         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
377                 struct evt_ops *eo = &evtops[i];
378
379                 switch (eo->type) {
380                 case _CB_VCONF:
381                         r = vconf_ignore_key_changed(eo->key.vkey, __vconf_cb);
382                         break;
383                 default:
384                         /* do nothing */
385                         break;
386                 }
387         }
388
389         return 0;
390 }
391
392 static int __aul_handler(aul_type type, bundle *b, void *data)
393 {
394         int ret;
395
396         switch (type) {
397         case AUL_START:
398                 _DBG("[APP %d]     AUL event: AUL_START", _pid);
399                 __app_reset(data, b);
400                 break;
401         case AUL_RESUME:
402                 _DBG("[APP %d]     AUL event: AUL_RESUME", _pid);
403                 if(open.callback) {
404                         ret = open.callback(open.cbdata);
405                         if (ret == 0)
406                                 __app_resume(data);
407                 } else {
408                         __app_resume(data);
409                 }
410                 break;
411         case AUL_TERMINATE:
412                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", _pid);
413                 __app_terminate(data);
414                 break;
415         default:
416                 _DBG("[APP %d]     AUL event: %d", _pid, type);
417                 /* do nothing */
418                 break;
419         }
420
421         return 0;
422 }
423
424
425 static void __clear(struct appcore *ac)
426 {
427         memset(ac, 0, sizeof(struct appcore));
428 }
429
430 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
431                                        void *data)
432 {
433         open.callback = cb;
434         open.cbdata = data;
435
436         return 0;
437 }
438
439 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
440                                           int (*cb) (void *), void *data)
441 {
442         struct appcore *ac = &core;
443         struct sys_op *op;
444         enum sys_event se;
445
446         for (se = SE_UNKNOWN; se < SE_MAX; se++) {
447                 if (event == to_ae[se])
448                         break;
449         }
450
451         if (se == SE_UNKNOWN || se >= SE_MAX) {
452                 _ERR("Unregistered event");
453                 errno = EINVAL;
454                 return -1;
455         }
456
457         op = &ac->sops[se];
458
459         op->func = cb;
460         op->data = data;
461
462         return 0;
463 }
464
465
466
467 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
468                             int argc, char **argv)
469 {
470         int r;
471         char dirname[PATH_MAX];
472
473         if (core.state != 0) {
474                 _ERR("Already in use");
475                 errno = EALREADY;
476                 return -1;
477         }
478
479         if (ops == NULL || ops->cb_app == NULL) {
480                 _ERR("ops or callback function is null");
481                 errno = EINVAL;
482                 return -1;
483         }
484
485         r = __get_dir_name(dirname);
486         r = set_i18n(name, dirname);
487         _retv_if(r == -1, -1);
488
489         r = __add_vconf(&core);
490         if (r == -1) {
491                 _ERR("Add vconf callback failed");
492                 goto err;
493         }
494
495         r = aul_launch_init(__aul_handler, &core);
496         if (r < 0) {
497                 _ERR("Aul init failed: %d", r);
498                 goto err;
499         }
500
501         r = aul_launch_argv_handler(argc, argv);
502         if (r < 0) {
503                 _ERR("Aul argv handler failed: %d", r);
504                 goto err;
505         }
506
507         core.ops = ops;
508         core.state = 1;         /* TODO: use enum value */
509
510         _pid = getpid();
511
512         return 0;
513  err:
514         __del_vconf();
515         __clear(&core);
516         return -1;
517 }
518
519 EXPORT_API void appcore_exit(void)
520 {
521         if (core.state) {
522                 __del_vconf();
523                 __clear(&core);
524         }
525         aul_finalize();
526 }
527
528 EXPORT_API int appcore_flush_memory(void)
529 {
530         int (*flush_fn) (int);
531         int size = 0;
532
533         struct appcore *ac = &core;
534
535         if (!core.state) {
536                 _ERR("Appcore not initialized");
537                 return -1;
538         }
539
540         _DBG("[APP %d] Flushing memory ...", _pid);
541
542         if (ac->ops->cb_app) {
543                 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
544         }
545
546         flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
547         if (flush_fn) {
548                 size = flush_fn(SQLITE_FLUSH_MAX);
549         }
550
551         malloc_trim(0);
552         /*
553         *Disabled - the impact of stack_trim() is unclear
554         *stack_trim();
555         */
556
557         _DBG("[APP %d] Flushing memory DONE", _pid);
558
559         return 0;
560 }