remove sysman dependency
[framework/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 <glib.h>
31
32 #include "aul.h"
33 #include "appcore-agent.h"
34 #include <dlog.h>
35 #include <vconf.h>
36
37 #ifdef LOG_TAG
38 #undef LOG_TAG
39 #endif
40
41 #define LOG_TAG "APPCORE_AGENT"
42
43
44 #ifndef EXPORT_API
45 #  define EXPORT_API __attribute__ ((visibility("default")))
46 #endif
47
48 #define _warn_if(expr, fmt, arg...) do { \
49                 if (expr) { \
50                         _ERR(fmt, ##arg); \
51                 } \
52         } while (0)
53
54 #define _ret_if(expr) do { \
55                 if (expr) { \
56                         return; \
57                 } \
58         } while (0)
59
60 #define _retv_if(expr, val) do { \
61                 if (expr) { \
62                         return (val); \
63                 } \
64         } while (0)
65
66 #define _retm_if(expr, fmt, arg...) do { \
67                 if (expr) { \
68                         _ERR(fmt, ##arg); \
69                         return; \
70                 } \
71         } while (0)
72
73 #define _retvm_if(expr, val, fmt, arg...) do { \
74                 if (expr) { \
75                         _ERR(fmt, ##arg); \
76                         return (val); \
77                 } \
78         } while (0)
79
80
81 static pid_t _pid;
82
83 /**
84  * Appcore internal system event
85  */
86 enum sys_event {
87         SE_UNKNOWN,
88         SE_LOWMEM,
89         SE_LOWBAT,
90         SE_MAX
91 };
92
93 /**
94  * agent internal state
95  */
96 enum agent_state {
97         AGS_NONE,
98         AGS_CREATED,
99         AGS_RUNNING,
100         AGS_STOPED,
101         AGS_DYING,
102 };
103
104 enum agent_event {
105         AGE_UNKNOWN,
106         AGE_CREATE,
107         AGE_TERMINATE,
108         AGE_STOP,
109         AGE_REQUEST,
110         AGE_MAX
111 };
112
113
114 static enum appcore_agent_event to_ae[SE_MAX] = {
115         APPCORE_AGENT_EVENT_UNKNOWN,    /* SE_UNKNOWN */
116         APPCORE_AGENT_EVENT_LOW_MEMORY, /* SE_LOWMEM */
117         APPCORE_AGENT_EVENT_LOW_BATTERY,        /* SE_LOWBAT */
118 };
119
120
121 enum cb_type {                  /* callback */
122         _CB_NONE,
123         _CB_SYSNOTI,
124         _CB_APPNOTI,
125         _CB_VCONF,
126 };
127
128 struct evt_ops {
129         enum cb_type type;
130         union {
131                 enum appcore_agent_event sys;
132                 enum agent_event app;
133                 const char *vkey;
134         } key;
135
136         int (*cb_pre) (void *);
137         int (*cb) (void *);
138         int (*cb_post) (void *);
139
140         int (*vcb_pre) (void *, void *);
141         int (*vcb) (void *, void *);
142         int (*vcb_post) (void *, void *);
143 };
144
145 struct agent_priv {
146         enum agent_state state;
147
148         struct agentcore_ops *ops;
149 };
150
151 static struct agent_priv priv;
152
153 struct agent_ops {
154         void *data;
155         void (*cb_app)(int, void *, bundle *);
156 };
157
158 /**
159  * Appcore system event operation
160  */
161 struct sys_op {
162         int (*func) (void *);
163         void *data;
164 };
165
166 struct agent_appcore {
167         int state;
168
169         const struct agent_ops *ops;
170         struct sys_op sops[SE_MAX];
171 };
172
173 static struct agent_appcore core;
174
175 GMainLoop *mainloop;
176
177 extern int service_create_request(bundle *data, service_h *service);
178 static int __sys_lowmem_post(void *data, void *evt);
179 static int __sys_lowmem(void *data, void *evt);
180 static int __sys_lowbatt(void *data, void *evt);
181
182
183 static struct evt_ops evtops[] = {
184         {
185          .type = _CB_VCONF,
186          .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
187          .vcb_post = __sys_lowmem_post,
188          .vcb = __sys_lowmem,
189          },
190         {
191          .type = _CB_VCONF,
192          .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
193          .vcb = __sys_lowbatt,
194          }
195 };
196
197 static void __do_app(enum agent_event event, void *data, bundle * b)
198 {
199         int r = 0;
200         struct agent_priv *svc = data;
201         service_h service = NULL;
202
203         _ret_if(svc == NULL);
204
205         if (event == AGE_TERMINATE) {
206                 svc->state = AGS_DYING;
207                 g_main_loop_quit(mainloop);
208                 return;
209         }
210
211         _ret_if(svc->ops == NULL);
212
213         if (service_create_event(b, &service) != 0)
214         {
215                 return;
216         }
217
218         switch (event) {
219         case AGE_REQUEST:
220                 if (svc->ops->service)
221                         r = svc->ops->service(service, svc->ops->data);
222                 svc->state = AGS_RUNNING;
223                 break;
224 /*      case AGE_STOP:
225                 if(svc->state == AGS_RUNNING) {
226                         if (svc->ops->stop)
227                                 r = svc->ops->stop(svc->ops->data);
228                         svc->state = AGS_STOPED;
229                 }
230                 break;
231 */      default:
232                 /* do nothing */
233                 break;
234         }
235         service_destroy(service);
236 }
237
238 static struct agent_ops s_ops = {
239         .data = &priv,
240         .cb_app = __do_app,
241 };
242
243 static int __set_data(struct agent_priv *agent, struct agentcore_ops *ops)
244 {
245         if (ops == NULL) {
246                 errno = EINVAL;
247                 return -1;
248         }
249
250         agent->ops = ops;
251
252         _pid = getpid();
253
254         return 0;
255 }
256
257 static int __agent_request(void *data, bundle * k)
258 {
259         struct agent_appcore *ac = data;
260         _retv_if(ac == NULL || ac->ops == NULL, -1);
261         _retv_if(ac->ops->cb_app == NULL, 0);
262
263         ac->ops->cb_app(AGE_REQUEST, ac->ops->data, k);
264
265         return 0;
266 }
267
268 static int __agent_terminate(void *data)
269 {
270         struct agent_appcore *ac = data;
271
272         _retv_if(ac == NULL || ac->ops == NULL, -1);
273         _retv_if(ac->ops->cb_app == NULL, 0);
274
275         ac->ops->cb_app(AGE_TERMINATE, ac->ops->data, NULL);
276
277         return 0;
278 }
279
280 static int __sys_do_default(struct appcore *ac, enum sys_event event)
281 {
282         int r;
283
284         switch (event) {
285         case SE_LOWBAT:
286                 /*r = __def_lowbatt(ac);*/
287                 r = 0;
288                 break;
289         default:
290                 r = 0;
291                 break;
292         };
293
294         return r;
295 }
296
297 static int __sys_do(struct agent_appcore *ac, enum sys_event event)
298 {
299         struct sys_op *op;
300
301         _retv_if(ac == NULL || event >= SE_MAX, -1);
302
303         op = &ac->sops[event];
304
305         if (op->func == NULL)
306                 return __sys_do_default(ac, event);
307
308         return op->func(op->data);
309 }
310
311 static int __sys_lowmem_post(void *data, void *evt)
312 {
313 #if defined(MEMORY_FLUSH_ACTIVATE)
314         struct appcore *ac = data;
315         ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
316 #else
317         malloc_trim(0);
318 #endif
319         return 0;
320 }
321
322 static int __sys_lowmem(void *data, void *evt)
323 {
324         return __sys_do(data, SE_LOWMEM);
325 }
326
327 static int __sys_lowbatt(void *data, void *evt)
328 {
329         keynode_t *key = evt;
330         int val;
331
332         val = vconf_keynode_get_int(key);
333
334         /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
335         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
336                 return __sys_do(data, SE_LOWBAT);
337
338         return 0;
339 }
340
341 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
342 {
343         _ret_if(eo == NULL);
344
345         if (eo->vcb_pre)
346                 eo->vcb_pre(data, key);
347
348         if (eo->vcb)
349                 eo->vcb(data, key);
350
351         if (eo->vcb_post)
352                 eo->vcb_post(data, key);
353 }
354
355 static void __vconf_cb(keynode_t *key, void *data)
356 {
357         int i;
358         const char *name;
359
360         name = vconf_keynode_get_name(key);
361         _ret_if(name == NULL);
362
363         SECURE_LOGD("[APP %d] vconf changed: %s", _pid, name);
364
365         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
366                 struct evt_ops *eo = &evtops[i];
367
368                 switch (eo->type) {
369                 case _CB_VCONF:
370                         if (!strcmp(name, eo->key.vkey))
371                                 __vconf_do(eo, key, data);
372                         break;
373                 default:
374                         /* do nothing */
375                         break;
376                 }
377         }
378 }
379
380 static int __add_vconf(struct agent_appcore *ac)
381 {
382         int i;
383         int r;
384
385         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
386                 struct evt_ops *eo = &evtops[i];
387
388                 switch (eo->type) {
389                 case _CB_VCONF:
390                         r = vconf_notify_key_changed(eo->key.vkey, __vconf_cb,
391                                                      ac);
392                         break;
393                 default:
394                         /* do nothing */
395                         break;
396                 }
397         }
398
399         return 0;
400 }
401
402 static int __del_vconf(void)
403 {
404         int i;
405         int r;
406
407         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
408                 struct evt_ops *eo = &evtops[i];
409
410                 switch (eo->type) {
411                 case _CB_VCONF:
412                         r = vconf_ignore_key_changed(eo->key.vkey, __vconf_cb);
413                         break;
414                 default:
415                         /* do nothing */
416                         break;
417                 }
418         }
419
420         return 0;
421 }
422
423 static int __aul_handler(aul_type type, bundle *b, void *data)
424 {
425         int ret;
426
427         switch (type) {
428         case AUL_START:
429                 ret = __agent_request(data, b);
430                 break;
431         case AUL_RESUME:
432                 break;
433 /*      case AUL_STOP:
434                 ret = __service_stop(data);
435                 break;
436 */
437         case AUL_TERMINATE:
438                 ret = __agent_terminate(data);
439                 break;
440         default:
441                 /* do nothing */
442                 break;
443         }
444
445         return 0;
446 }
447
448 EXPORT_API int appcore_agent_set_event_callback(enum appcore_agent_event event,
449                                           int (*cb) (void *), void *data)
450 {
451         struct agent_appcore *ac = &core;
452         struct sys_op *op;
453         enum sys_event se;
454
455         for (se = SE_UNKNOWN; se < SE_MAX; se++) {
456                 if (event == to_ae[se])
457                         break;
458         }
459
460         if (se == SE_UNKNOWN || se >= SE_MAX) {
461                 _ERR("Unregistered event");
462                 errno = EINVAL;
463                 return -1;
464         }
465
466         op = &ac->sops[se];
467
468         op->func = cb;
469         op->data = data;
470
471         return 0;
472 }
473
474 EXPORT_API int appcore_agent_init(const struct agent_ops *ops,
475                             int argc, char **argv)
476 {
477         int r;
478
479         if (core.state != 0) {
480                 errno = EALREADY;
481                 return -1;
482         }
483
484         if (ops == NULL || ops->cb_app == NULL) {
485                 errno = EINVAL;
486                 return -1;
487         }
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                 goto err;
498         }
499
500         r = aul_launch_argv_handler(argc, argv);
501         if (r < 0) {
502                 goto err;
503         }
504
505         core.ops = ops;
506         core.state = 1;         /* TODO: use enum value */
507
508         return 0;
509  err:
510         //__clear(&core);
511         return -1;
512 }
513
514
515 static int __before_loop(struct agent_priv *agent, int argc, char **argv)
516 {
517         int r;
518
519         if (argc == NULL || argv == NULL) {
520                 errno = EINVAL;
521                 return -1;
522         }
523
524         g_type_init();
525
526         r = appcore_agent_init(&s_ops, argc, argv);
527         _retv_if(r == -1, -1);
528
529         if (agent->ops && agent->ops->create) {
530                 r = agent->ops->create(agent->ops->data);
531                 if (r == -1) {
532                         //appcore_exit();
533                         errno = ECANCELED;
534                         return -1;
535                 }
536         }
537         agent->state = AGS_CREATED;
538
539         return 0;
540 }
541
542 static void __after_loop(struct agent_priv *agent)
543 {
544         priv.state = AGS_DYING;
545         if (agent->ops && agent->ops->terminate)
546                 agent->ops->terminate(agent->ops->data);
547 }
548
549
550 EXPORT_API int appcore_agent_terminate()
551 {
552         g_main_loop_quit(mainloop);
553         return 0;
554 }
555
556
557 EXPORT_API int appcore_agent_main(int argc, char **argv,
558                                 struct agentcore_ops *ops)
559 {
560         int r;
561
562         r = __set_data(&priv, ops);
563         _retv_if(r == -1, -1);
564
565         r = __before_loop(&priv, argc, argv);
566         if (r == -1) {
567                 //__unset_data(&priv);
568                 return -1;
569         }
570
571         mainloop = g_main_loop_new(NULL, FALSE);
572
573         g_main_loop_run(mainloop);
574
575
576         __after_loop(&priv);
577
578         //__unset_data(&priv);
579
580         return 0;
581 }