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