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