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