c16f7e37dccd8721121ffb32a0a8b7e76395c203
[platform/core/appfw/appcore-agent.git] / src / appcore-agent.c
1 /*
2  *  service-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 <Ecore.h>
32 #include <linux/limits.h>
33 #include <dlfcn.h>
34 #include <glib.h>
35
36 #include <bundle.h>
37 #include <aul.h>
38 #include <appcore-common.h>
39 #include <app_control_internal.h>
40 #include <dlog.h>
41 #include <vconf.h>
42
43 #include "appcore-agent.h"
44
45 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
46 #include <gio/gio.h>
47
48 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
49 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.frezer"
50 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
51 #define APPFW_SUSPEND_HINT_PATH "/Org/Tizen/Appfw/SuspendHint"
52 #define APPFW_SUSPEND_HINT_INTERFACE "org.tizen.appfw.SuspendHint"
53 #define APPFW_SUSPEND_HINT_SIGNAL "SuspendHint"
54
55 #endif
56
57 #ifdef LOG_TAG
58 #undef LOG_TAG
59 #endif
60
61 #define LOG_TAG "APPCORE_AGENT"
62 #define SQLITE_FLUSH_MAX        (1024 * 1024)
63
64 #define _ERR(fmt, arg...) LOGE(fmt, ##arg)
65 #define _INFO(fmt, arg...) LOGI(fmt, ##arg)
66 #define _DBG(fmt, arg...) LOGD(fmt, ##arg)
67
68 #ifndef EXPORT_API
69 #define EXPORT_API __attribute__ ((visibility("default")))
70 #endif
71
72 #ifndef _ERR
73 #define _ERR(fmt, arg...) LOGE(fmt, ##arg)
74 #endif
75
76 #ifndef _INFO
77 #define _INFO(...) LOGI(__VA_ARGS__)
78 #endif
79
80 #ifndef _DBG
81 #define _DBG(...) LOGD(__VA_ARGS__)
82 #endif
83
84 #define _warn_if(expr, fmt, arg...) do { \
85                 if (expr) { \
86                         _ERR(fmt, ##arg); \
87                 } \
88         } while (0)
89
90 #define _ret_if(expr) do { \
91                 if (expr) { \
92                         return; \
93                 } \
94         } while (0)
95
96 #define _retv_if(expr, val) do { \
97                 if (expr) { \
98                         return (val); \
99                 } \
100         } while (0)
101
102 #define _retm_if(expr, fmt, arg...) do { \
103                 if (expr) { \
104                         _ERR(fmt, ##arg); \
105                         return; \
106                 } \
107         } while (0)
108
109 #define _retvm_if(expr, val, fmt, arg...) do { \
110                 if (expr) { \
111                         _ERR(fmt, ##arg); \
112                         return (val); \
113                 } \
114         } while (0)
115
116 #define APPID_MAX 256
117 #define PATH_LOCALE "locale"
118
119 static pid_t _pid;
120
121 /**
122  * Appcore internal system event
123  */
124 enum sys_event {
125         SE_UNKNOWN,
126         SE_LOWMEM,
127         SE_LOWBAT,
128         SE_LANGCHG,
129         SE_REGIONCHG,
130         SE_SUSPENDED_STATE,
131         SE_MAX
132 };
133
134 /**
135  * agent internal state
136  */
137 enum agent_state {
138         AGS_NONE,
139         AGS_CREATED,
140         AGS_RUNNING,
141         AGS_STOPED,
142         AGS_DYING,
143 };
144
145 enum agent_event {
146         AGE_UNKNOWN,
147         AGE_CREATE,
148         AGE_TERMINATE,
149         AGE_STOP,
150         AGE_REQUEST,
151         AGE_MAX
152 };
153
154
155 static enum appcore_agent_event to_ae[SE_MAX] = {
156         APPCORE_AGENT_EVENT_UNKNOWN,            /* SE_UNKNOWN */
157         APPCORE_AGENT_EVENT_LOW_MEMORY,         /* SE_LOWMEM */
158         APPCORE_AGENT_EVENT_LOW_BATTERY,        /* SE_LOWBAT */
159         APPCORE_AGENT_EVENT_LANG_CHANGE,        /* SE_LANGCHG */
160         APPCORE_AGENT_EVENT_REGION_CHANGE,      /* SE_REGIONCHG */
161         APPCORE_AGENT_EVENT_SUSPENDED_STATE_CHANGE, /* SE_SUSPENDED_STATE */
162 };
163
164 static int appcore_agent_event_initialized[SE_MAX] = {0};
165
166 enum cb_type {                  /* callback */
167         _CB_NONE,
168         _CB_SYSNOTI,
169         _CB_APPNOTI,
170         _CB_VCONF,
171 };
172
173 enum appcore_agent_suspended_state {
174         APPCORE_AGENT_SUSPENDED_STATE_WILL_ENTER_SUSPEND = 0,
175         APPCORE_AGENT_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND
176 };
177
178 struct evt_ops {
179         enum cb_type type;
180         union {
181                 enum appcore_agent_event sys;
182                 enum agent_event app;
183                 const char *vkey;
184         } key;
185
186         int (*cb_pre) (void *);
187         int (*cb) (void *);
188         int (*cb_post) (void *);
189
190         int (*vcb_pre) (void *, void *);
191         int (*vcb) (void *, void *);
192         int (*vcb_post) (void *, void *);
193 };
194
195 struct agent_priv {
196         enum agent_state state;
197
198         struct agent_appcore *app_core;
199         struct agentcore_ops *ops;
200 };
201
202 static struct agent_priv priv;
203
204 struct agent_ops {
205         void *data;
206         void (*cb_app)(enum agent_event, void *, bundle *);
207 };
208
209 /**
210  * Appcore system event operation
211  */
212 struct sys_op {
213         int (*func) (void *, void *);
214         void *data;
215 };
216
217 struct agent_appcore {
218         int state;
219         unsigned int tid;
220         bool suspended_state;
221         bool allowed_bg;
222
223         const struct agent_ops *ops;
224         struct sys_op sops[SE_MAX];
225 };
226
227 static struct agent_appcore core;
228
229 static int __sys_lowmem_post(void *data, void *evt);
230 static int __sys_lowmem(void *data, void *evt);
231 static int __sys_lowbatt(void *data, void *evt);
232 static int __sys_langchg_pre(void *data, void *evt);
233 static int __sys_langchg(void *data, void *evt);
234 static int __sys_regionchg_pre(void *data, void *evt);
235 static int __sys_regionchg(void *data, void *evt);
236
237 static struct evt_ops evtops[] = {
238         {
239          .type = _CB_VCONF,
240          .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
241          .vcb_post = __sys_lowmem_post,
242          .vcb = __sys_lowmem,
243          },
244         {
245          .type = _CB_VCONF,
246          .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
247          .vcb = __sys_lowbatt,
248          },
249         {
250         .type = _CB_VCONF,
251         .key.vkey = VCONFKEY_LANGSET,
252         .vcb_pre = __sys_langchg_pre,
253         .vcb = __sys_langchg,
254         },
255         {
256         .type = _CB_VCONF,
257         .key.vkey = VCONFKEY_REGIONFORMAT,
258         .vcb_pre = __sys_regionchg_pre,
259         .vcb = __sys_regionchg,
260          },
261         {
262         .type = _CB_VCONF,
263         .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
264         .vcb = __sys_regionchg,
265          },
266 };
267
268 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
269 static GDBusConnection *bus = NULL;
270 static guint __suspend_dbus_handler_initialized = 0;
271 #endif
272
273 extern int app_control_create_event(bundle *data, struct app_control_s **app_control);
274 static int __sys_do(struct agent_appcore *ac, void *event_info, enum sys_event event);
275
276 /* LCOV_EXCL_START */
277 static int appcore_agent_flush_memory(void)
278 {
279         int (*flush_fn) (int);
280
281         if (!core.state) {
282                 _ERR("Appcore not initialized");
283                 return -1;
284         }
285
286         flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
287         if (flush_fn) {
288                 flush_fn(SQLITE_FLUSH_MAX);
289         }
290
291         malloc_trim(0);
292
293         return 0;
294 }
295 /* LCOV_EXCL_STOP */
296
297 /* LCOV_EXCL_START */
298 static void __prepare_to_suspend(void *data)
299 {
300 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
301         int suspend = APPCORE_AGENT_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
302         struct agent_appcore *ac = data;
303
304         if (ac && !ac->allowed_bg && !ac->suspended_state) {
305                 _DBG("[__SUSPEND__]");
306                 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
307                 ac->suspended_state = true;
308         }
309 #endif
310 }
311 /* LCOV_EXCL_STOP */
312
313 /* LCOV_EXCL_START */
314 static void __exit_from_suspend(void *data)
315 {
316 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
317         int suspend = APPCORE_AGENT_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
318         struct agent_appcore *ac = data;
319
320         if (ac && !ac->allowed_bg && ac->suspended_state) {
321                 _DBG("[__SUSPEND__]");
322                 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
323                 ac->suspended_state = false;
324         }
325 #endif
326 }
327 /* LCOV_EXCL_START */
328
329 /* LCOV_EXCL_START */
330 static gboolean __flush_memory(gpointer data)
331 {
332 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
333         struct agent_appcore *ac = (struct agent_appcore *)data;
334
335         appcore_agent_flush_memory();
336
337         if (!ac) {
338                 return FALSE;
339         }
340         ac->tid = 0;
341
342         _DBG("[__SUSPEND__] flush case");
343         __prepare_to_suspend(ac);
344 #endif
345         return FALSE;
346 }
347 /* LCOV_EXCL_STOP */
348
349 /* LCOV_EXCL_START */
350 static void __add_suspend_timer(struct agent_appcore *ac)
351 {
352 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
353         ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
354 #endif
355 }
356 /* LCOV_EXCL_STOP */
357
358 /* LCOV_EXCL_START */
359 static void __remove_suspend_timer(struct agent_appcore *ac)
360 {
361 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
362         if (ac->tid > 0) {
363                 g_source_remove(ac->tid);
364                 ac->tid = 0;
365         }
366 #endif
367 }
368 /* LCOV_EXCL_STOP */
369
370 static void __exit_loop(void *data)
371 {
372         ecore_main_loop_quit();
373         __remove_suspend_timer(&core);
374 }
375
376 static void __do_app(enum agent_event event, void *data, bundle * b)
377 {
378         struct agent_priv *svc = data;
379         app_control_h app_control = NULL;
380
381         _ret_if(svc == NULL);
382
383         if (event == AGE_TERMINATE) {
384                 svc->state = AGS_DYING;
385                 ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_loop, NULL);
386                 return;
387         }
388
389         _ret_if(svc->ops == NULL);
390
391         if (app_control_create_event(b, &app_control) != 0)
392                 return;
393
394         switch (event) {
395         case AGE_REQUEST:
396                 if (svc->ops->app_control)
397                         svc->ops->app_control(app_control, svc->ops->data);
398                 svc->state = AGS_RUNNING;
399                 break;
400 /*      case AGE_STOP:
401                 if(svc->state == AGS_RUNNING) {
402                         if (svc->ops->stop)
403                                 svc->ops->stop(svc->ops->data);
404                         svc->state = AGS_STOPED;
405                 }
406                 break;
407 */      default:
408                 /* do nothing */
409                 break;
410         }
411         app_control_destroy(app_control);
412 }
413
414 static struct agent_ops s_ops = {
415         .data = &priv,
416         .cb_app = __do_app,
417 };
418
419 static int __set_data(struct agent_priv *agent, struct agentcore_ops *ops)
420 {
421         if (ops == NULL) {
422                 errno = EINVAL;
423                 return -1;
424         }
425
426         agent->ops = ops;
427         agent->app_core = NULL;
428
429         _pid = getpid();
430
431         return 0;
432 }
433
434 static int __agent_request(void *data, bundle * k)
435 {
436         struct agent_appcore *ac = data;
437         _retv_if(ac == NULL || ac->ops == NULL, -1);
438         _retv_if(ac->ops->cb_app == NULL, 0);
439
440         ac->ops->cb_app(AGE_REQUEST, ac->ops->data, k);
441
442         return 0;
443 }
444
445 /* LCOV_EXCL_START */
446 static int __agent_terminate(void *data)
447 {
448         struct agent_appcore *ac = data;
449
450         _retv_if(ac == NULL || ac->ops == NULL, -1);
451         _retv_if(ac->ops->cb_app == NULL, 0);
452
453         ac->ops->cb_app(AGE_TERMINATE, ac->ops->data, NULL);
454
455         return 0;
456 }
457 /* LCOV_EXCL_STOP */
458
459 static int __sys_do_default(struct agent_appcore *ac, enum sys_event event)
460 {
461         int r;
462
463         switch (event) {
464         case SE_LOWBAT:
465                 /*r = __def_lowbatt(ac);*/
466                 r = 0;
467                 break;
468         default:
469                 r = 0;
470                 break;
471         };
472
473         return r;
474 }
475
476 static int __sys_do(struct agent_appcore *ac, void *event_info, enum sys_event event)
477 {
478         struct sys_op *op;
479
480         _retv_if(ac == NULL || event >= SE_MAX, -1);
481
482         op = &ac->sops[event];
483
484         if (op->func == NULL)
485                 return __sys_do_default(ac, event);
486
487         return op->func(event_info, op->data);
488 }
489
490 static int __sys_lowmem_post(void *data, void *evt)
491 {
492 #if defined(MEMORY_FLUSH_ACTIVATE)
493         struct agent_appcore *ac = data;
494         ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
495 #else
496         malloc_trim(0);
497 #endif
498         return 0;
499 }
500
501 static int __sys_lowmem(void *data, void *evt)
502 {
503         keynode_t *key = evt;
504         int val;
505
506         val = vconf_keynode_get_int(key);
507
508         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
509                 return __sys_do(data, (void *)&val, SE_LOWMEM);
510
511         return 0;
512 }
513
514 static int __sys_lowbatt(void *data, void *evt)
515 {
516         keynode_t *key = evt;
517         int val;
518
519         val = vconf_keynode_get_int(key);
520
521         /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
522         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
523                 return __sys_do(data, (void *)&val, SE_LOWBAT);
524
525         return 0;
526 }
527
528 static int __sys_langchg_pre(void *data, void *evt)
529 {
530         keynode_t *key = evt;
531         char language[32];
532         char *lang;
533         char *r;
534
535         lang = vconf_keynode_get_str(key);
536         if (lang) {
537                 snprintf(language, sizeof(language), "%s:en_US:en_GB:en", lang);
538                 setenv("LANGUAGE", language, 1);
539                 setenv("LANG", lang, 1);
540                 setenv("LC_MESSAGES", lang, 1);
541
542                 r = setlocale(LC_ALL, lang);
543                 if (r == NULL) {
544                         r = setlocale(LC_ALL, lang);
545                         if (r)
546                                 _DBG("*****appcore-agent setlocale=%s\n", r);
547                 }
548         }
549
550         return 0;
551 }
552
553 static int __sys_langchg(void *data, void *evt)
554 {
555         keynode_t *key = evt;
556         char *val;
557
558         val = vconf_keynode_get_str(key);
559
560         return __sys_do(data, (void *)val, SE_LANGCHG);
561 }
562
563 static int __sys_regionchg_pre(void *data, void *evt)
564 {
565         keynode_t *key = evt;
566         char *region;
567         char *r;
568
569         region = vconf_keynode_get_str(key);
570         if (region) {
571                 setenv("LC_CTYPE", region, 1);
572                 setenv("LC_NUMERIC", region, 1);
573                 setenv("LC_TIME", region, 1);
574                 setenv("LC_COLLATE", region, 1);
575                 setenv("LC_MONETARY", region, 1);
576                 setenv("LC_PAPER", region, 1);
577                 setenv("LC_NAME", region, 1);
578                 setenv("LC_ADDRESS", region, 1);
579                 setenv("LC_TELEPHONE", region, 1);
580                 setenv("LC_MEASUREMENT", region, 1);
581                 setenv("LC_IDENTIFICATION", region, 1);
582
583                 r = setlocale(LC_ALL, "");
584                 if (r != NULL)
585                         _DBG("*****appcore-agent setlocale=%s\n", r);
586         }
587
588         return 0;
589 }
590
591 static int __sys_regionchg(void *data, void *evt)
592 {
593         keynode_t *key = evt;
594         char *val = NULL;
595         const char *name;
596
597         name = vconf_keynode_get_name(key);
598         if (!strcmp(name, VCONFKEY_REGIONFORMAT))
599                 val = vconf_keynode_get_str(key);
600
601         return __sys_do(data, (void *)val, SE_REGIONCHG);
602 }
603
604 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
605 {
606         _ret_if(eo == NULL);
607
608         if (eo->vcb_pre)
609                 eo->vcb_pre(data, key);
610
611         if (eo->vcb)
612                 eo->vcb(data, key);
613
614         if (eo->vcb_post)
615                 eo->vcb_post(data, key);
616 }
617
618 static void __vconf_cb(keynode_t *key, void *data)
619 {
620         int i;
621         const char *name;
622
623         name = vconf_keynode_get_name(key);
624         _ret_if(name == NULL);
625
626         SECURE_LOGD("[APP %d] vconf changed: %s", _pid, name);
627
628         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
629                 struct evt_ops *eo = &evtops[i];
630
631                 switch (eo->type) {
632                 case _CB_VCONF:
633                         if (!strcmp(name, eo->key.vkey))
634                                 __vconf_do(eo, key, data);
635                         break;
636                 default:
637                         /* do nothing */
638                         break;
639                 }
640         }
641 }
642
643 static int __add_vconf(struct agent_appcore *ac, enum sys_event se)
644 {
645         int r;
646
647         switch (se) {
648         case SE_LOWMEM:
649                 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
650                 break;
651         case SE_LOWBAT:
652                 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
653                 break;
654         case SE_LANGCHG:
655                 r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
656                 break;
657         case SE_REGIONCHG:
658                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
659                 if (r < 0)
660                         break;
661
662                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
663                 break;
664         default:
665                 r = -1;
666                 break;
667         }
668
669         return r;
670 }
671
672 static int __del_vconf(enum sys_event se)
673 {
674         int r;
675
676         switch (se) {
677         case SE_LOWMEM:
678                 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
679                 break;
680         case SE_LOWBAT:
681                 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
682                 break;
683         case SE_LANGCHG:
684                 r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
685                 break;
686         case SE_REGIONCHG:
687                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
688                 if (r < 0)
689                         break;
690
691                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
692                 break;
693         default:
694                 r = -1;
695                 break;
696         }
697
698         return r;
699 }
700
701 static int __del_vconf_list(void)
702 {
703         int r;
704         enum sys_event se;
705
706         for (se = SE_LOWMEM; se < SE_MAX; se++) {
707                 if (appcore_agent_event_initialized[se]) {
708                         r = __del_vconf(se);
709                         if (r < 0)
710                                 _ERR("Delete vconf callback failed");
711                         else
712                                 appcore_agent_event_initialized[se] = 0;
713                 }
714         }
715
716         return 0;
717 }
718
719 static int __aul_handler(aul_type type, bundle *b, void *data)
720 {
721         int ret = 0;
722         char *bg = NULL;
723         struct agent_appcore *ac = data;
724
725         switch (type) {
726         case AUL_START:
727                 bundle_get_str(b, AUL_K_ALLOWED_BG, &bg);
728                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
729                         _DBG("[__SUSPEND__] allowed background");
730                         ac->allowed_bg = true;
731                         __remove_suspend_timer(data);
732                 }
733                 ret = __agent_request(data, b);
734                 break;
735         case AUL_RESUME:
736                 bundle_get_str(b, AUL_K_ALLOWED_BG, &bg);
737                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
738                         _DBG("[__SUSPEND__] allowed background");
739                         ac->allowed_bg = true;
740                         __remove_suspend_timer(data);
741                 }
742                 break;
743 /*      case AUL_STOP:
744                 __service_stop(data);
745                 break;
746 */
747         case AUL_TERMINATE:
748         case AUL_TERMINATE_BGAPP:
749                 if (!ac->allowed_bg) {
750                         __remove_suspend_timer(data);
751                 }
752                 ret = __agent_terminate(data);
753                 break;
754         case AUL_SUSPEND:
755                 if (!ac->allowed_bg) {
756                         _DBG("[__SUSPEND__] suspend");
757                         __add_suspend_timer(data);
758                 }
759                 break;
760         case AUL_WAKE:
761                 if (!ac->allowed_bg) {
762                         _DBG("[__SUSPEND__] wake");
763                         __remove_suspend_timer(data);
764                         __exit_from_suspend(data);
765                 }
766                 break;
767         default:
768                 /* do nothing */
769                 break;
770         }
771
772         return ret;
773 }
774
775 static int __get_package_app_name(int pid, char **app_name)
776 {
777         char *name_token = NULL;
778         char appid[APPID_MAX] = {0};
779         int r;
780
781         r = aul_app_get_appid_bypid(pid, appid, APPID_MAX);
782         if (r != AUL_R_OK)
783                 return -1;
784
785         if (appid[0] == '\0')
786                 return -1;
787
788         name_token = strrchr(appid, '.');
789         if (name_token == NULL)
790                 return -1;
791
792         name_token++;
793
794         *app_name = strdup(name_token);
795         if (*app_name == NULL)
796                 return -1;
797
798         return 0;
799 }
800
801 EXPORT_API int appcore_agent_set_event_callback(enum appcore_agent_event event,
802                                           int (*cb) (void *, void *), void *data)
803 {
804         struct agent_appcore *ac = &core;
805         struct sys_op *op;
806         enum sys_event se;
807         int r = 0;
808
809         for (se = SE_UNKNOWN; se < SE_MAX; se++) {
810                 if (event == to_ae[se])
811                         break;
812         }
813
814         if (se == SE_UNKNOWN || se >= SE_MAX) {
815                 _ERR("Unregistered event");
816                 errno = EINVAL;
817                 return -1;
818         }
819
820         op = &ac->sops[se];
821
822         op->func = cb;
823         op->data = data;
824
825         if (op->func && !appcore_agent_event_initialized[se]) {
826                 r = __add_vconf(ac, se);
827                 if (r < 0)
828                         _ERR("Add vconf callback failed");
829                 else
830                         appcore_agent_event_initialized[se] = 1;
831         } else if (!op->func && appcore_agent_event_initialized[se]) {
832                 r = __del_vconf(se);
833                 if (r < 0)
834                         _ERR("Delete vconf callback failed");
835                 else
836                         appcore_agent_event_initialized[se] = 0;
837         }
838
839         return r;
840 }
841
842 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
843 static gboolean __init_suspend(gpointer data)
844 {
845         int r;
846
847         r = _appcore_agent_init_suspend_dbus_handler(&core);
848         if (r == -1)
849                 _ERR("Initailzing suspended state handler failed");
850
851         return FALSE;
852 }
853 #endif
854
855 static int __get_locale_resource_dir(char *locale_dir, int size)
856 {
857         const char *res_path;
858
859         res_path = aul_get_app_resource_path();
860         if (res_path == NULL) {
861                 _ERR("Failed to get resource path");
862                 return -1;
863         }
864
865         snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
866         if (access(locale_dir, R_OK) != 0)
867                 return -1;
868
869         return 0;
870 }
871
872 EXPORT_API int appcore_agent_init(const struct agent_ops *ops,
873                             int argc, char **argv)
874 {
875         int r;
876         char locale_dir[PATH_MAX];
877         char *app_name = NULL;
878
879         if (core.state != 0) {
880                 errno = EALREADY;
881                 return -1;
882         }
883
884         if (ops == NULL || ops->cb_app == NULL) {
885                 errno = EINVAL;
886                 return -1;
887         }
888
889         r = __get_package_app_name(getpid(), &app_name);
890         if (r < 0)
891                 return -1;
892
893         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
894         SECURE_LOGD("dir : %s", locale_dir);
895         SECURE_LOGD("app name : %s", app_name);
896         r = appcore_set_i18n(app_name, locale_dir);
897         free(app_name);
898         _retv_if(r == -1, -1);
899
900 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
901         g_idle_add(__init_suspend, NULL);
902 #endif
903
904         r = aul_launch_init(__aul_handler, &core);
905         if (r < 0)
906                 goto err;
907
908         r = aul_launch_argv_handler(argc, argv);
909         if (r < 0)
910                 goto err;
911
912         core.ops = ops;
913         core.state = 1;         /* TODO: use enum value */
914         core.tid = 0;
915         core.suspended_state = false;
916         core.allowed_bg = false;
917
918         return 0;
919  err:
920         __del_vconf_list();
921         return -1;
922 }
923
924 static void appcore_agent_get_app_core(struct agent_appcore **ac)
925 {
926         *ac = &core;
927 }
928
929 static int __before_loop(struct agent_priv *agent, int argc, char **argv)
930 {
931         int r;
932         struct agent_appcore *ac = NULL;
933
934         if (argc <= 0 || argv == NULL) {
935                 errno = EINVAL;
936                 return -1;
937         }
938
939         ecore_init();
940
941         r = appcore_agent_init(&s_ops, argc, argv);
942         _retv_if(r == -1, -1);
943
944         appcore_agent_get_app_core(&ac);
945         agent->app_core = ac;
946         SECURE_LOGD("[__SUSPEND__] agent appcore initialized, appcore addr: 0x%x", ac);
947
948         if (agent->ops && agent->ops->create) {
949                 r = agent->ops->create(agent->ops->data);
950                 if (r < 0) {
951                         if (agent->ops && agent->ops->terminate)
952                                 agent->ops->terminate(agent->ops->data);
953                         errno = ECANCELED;
954                         return -1;
955                 }
956         }
957         agent->state = AGS_CREATED;
958
959         return 0;
960 }
961
962 static void __after_loop(struct agent_priv *agent)
963 {
964         __del_vconf_list();
965         priv.state = AGS_DYING;
966         if (agent->ops && agent->ops->terminate)
967                 agent->ops->terminate(agent->ops->data);
968         ecore_shutdown();
969 }
970
971 EXPORT_API int appcore_agent_terminate()
972 {
973         __del_vconf_list();
974         ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_loop, NULL);
975
976         return 0;
977 }
978
979 EXPORT_API int appcore_agent_terminate_without_restart()
980 {
981         __del_vconf_list();
982         aul_status_update(STATUS_NORESTART);
983         ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_loop, NULL);
984
985         return 0;
986 }
987
988 EXPORT_API int appcore_agent_main(int argc, char **argv,
989                                 struct agentcore_ops *ops)
990 {
991         int r;
992
993         r = __set_data(&priv, ops);
994         _retv_if(r == -1, -1);
995
996         r = __before_loop(&priv, argc, argv);
997         if (r == -1)
998                 return -1;
999
1000         ecore_main_loop_begin();
1001
1002         aul_status_update(STATUS_DYING);
1003
1004         __after_loop(&priv);
1005
1006         return 0;
1007 }
1008
1009 /* LCOV_EXCL_START */
1010 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
1011 static void __suspend_dbus_signal_handler(GDBusConnection *connection,
1012                                         const gchar *sender_name,
1013                                         const gchar *object_path,
1014                                         const gchar *interface_name,
1015                                         const gchar *signal_name,
1016                                         GVariant *parameters,
1017                                         gpointer user_data)
1018 {
1019         struct agent_appcore *ac = (struct agent_appcore *)user_data;
1020         gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
1021         gint pid;
1022         gint status;
1023
1024         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
1025                 g_variant_get(parameters, "(ii)", &status, &pid);
1026                 if (pid == getpid() && status == 0) { /* thawed */
1027                         if (ac && !ac->allowed_bg && ac->suspended_state) {
1028                                 __remove_suspend_timer(ac);
1029                                 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
1030                                 ac->suspended_state = false;
1031                                 __add_suspend_timer(ac);
1032                         }
1033                 }
1034         }
1035 }
1036 /* LCOV_EXCL_STOP */
1037
1038 int _appcore_agent_init_suspend_dbus_handler(void *data)
1039 {
1040         GError *err = NULL;
1041
1042         if (__suspend_dbus_handler_initialized)
1043                 return 0;
1044
1045         if (!bus) {
1046                 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1047                 if (!bus) {
1048                         _ERR("Failed to connect to the D-BUS daemon: %s",
1049                                                 err->message);
1050                         g_error_free(err);
1051                         return -1;
1052                 }
1053         }
1054
1055         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
1056                                                 bus,
1057                                                 NULL,
1058                                                 RESOURCED_FREEZER_INTERFACE,
1059                                                 RESOURCED_FREEZER_SIGNAL,
1060                                                 RESOURCED_FREEZER_PATH,
1061                                                 NULL,
1062                                                 G_DBUS_SIGNAL_FLAGS_NONE,
1063                                                 __suspend_dbus_signal_handler,
1064                                                 data,
1065                                                 NULL);
1066         if (__suspend_dbus_handler_initialized == 0) {
1067                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
1068                 return -1;
1069         }
1070
1071         _DBG("[__SUSPEND__] suspend signal initialized");
1072
1073         return 0;
1074 }
1075
1076 #endif