Update package management code.
[platform/framework/web/data-provider-master.git] / src / package.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <errno.h>
19 #include <string.h> /* strcmp */
20 #include <stdlib.h> /* free */
21
22 #include <dlog.h>
23 #include <Eina.h>
24 #include <Ecore_Evas.h>
25
26 #include <packet.h>
27 #include <livebox-errno.h>
28 #include <livebox-service.h>
29 #include <ail.h>
30
31 #include "critical_log.h"
32 #include "debug.h"
33 #include "util.h"
34 #include "parser.h"
35 #include "conf.h"
36 #include "slave_life.h"
37 #include "slave_rpc.h"
38 #include "client_life.h"
39 #include "package.h"
40 #include "fault_manager.h"
41 #include "instance.h"
42 #include "script_handler.h"
43 #include "group.h"
44 #include "abi.h"
45 #include "io.h"
46 #include "pkgmgr.h"
47 #include "xmonitor.h"
48
49 int errno;
50
51 struct fault_info {
52         double timestamp;
53         char *filename;
54         char *function;
55 };
56
57 /*!
58  * pkg_info describes the loaded package.
59  */
60
61 struct pkg_info {
62         char *pkgid;
63         char *lbid;
64
65         struct {
66                 enum lb_type type;
67
68                 union {
69                         struct {
70                                 char *path;
71                                 char *group;
72                         } script;
73
74                         struct {
75                                 /*!< Reserved for future use */
76                         } file;
77
78                         struct {
79                                 /*!< Reserved for future use */
80                         } text;
81
82                         struct {
83                                 /*!< Reserved for future use */
84                         } buffer;
85                 } info;
86
87                 unsigned int size_list;
88                 char *auto_launch;
89                 int pinup;
90                 int timeout;
91                 double period;
92                 char *libexec;
93         } lb;
94
95         struct {
96                 enum pd_type type;
97
98                 union {
99                         struct {
100                                 char *path;
101                                 char *group;
102                         } script;
103
104                         struct {
105                                 /*!< Reserved for future use */
106                         } text;
107
108                         struct {
109                                 /*!< Reserved for future use */
110                         } buffer;
111                 } info;
112
113                 unsigned int width;
114                 unsigned int height;
115         } pd;
116
117         int network;
118         int secured;
119         char *script; /* script type: edje, ... */
120         char *abi;
121
122         int fault_count;
123         struct fault_info *fault_info;
124
125         struct slave_node *slave;
126         int refcnt;
127
128         Eina_List *inst_list;
129         Eina_List *ctx_list;
130
131         int is_uninstalled;
132 };
133
134 static struct {
135         Eina_List *pkg_list;
136 } s_info = {
137         .pkg_list = NULL,
138 };
139
140 static int slave_activated_cb(struct slave_node *slave, void *data)
141 {
142         struct pkg_info *info = data;
143         struct inst_info *inst;
144         Eina_List *l;
145         Eina_List *n;
146         int cnt;
147         int ret;
148
149         if (!slave_need_to_reactivate_instances(slave)) {
150                 DbgPrint("Do not need to reactivate instances\n");
151                 return 0;
152         }
153
154         cnt = 0;
155         EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
156                 ret = instance_recover_state(inst);
157                 if (!ret) {
158                         continue;
159                 }
160
161                 instance_thaw_updator(inst);
162                 cnt++;
163         }
164
165         DbgPrint("Recover state for %d instances of %s\n", cnt, package_name(info));
166         return 0;
167 }
168
169 static int slave_fault_cb(struct slave_node *slave, void *data)
170 {
171         Eina_List *l;
172         Eina_List *n;
173         struct inst_info *inst;
174         struct pkg_info *info = (struct pkg_info *)data;
175
176         if (package_is_fault(info)) {
177                 ErrPrint("Already faulted package: %s\n", package_name(info));
178                 return 0;
179         }
180
181         (void)package_set_fault_info(info, util_timestamp(), slave_name(slave), __func__);
182         fault_broadcast_info(package_name(info), slave_name(slave), __func__);
183
184         DbgPrint("Slave critical fault - package: %s (by slave fault %s\n", package_name(info), slave_name(slave));
185         EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
186                 DbgPrint("Destroy instance %p\n", inst);
187                 instance_destroyed(inst);
188         }
189
190         return 0;
191 }
192
193 static int slave_deactivated_cb(struct slave_node *slave, void *data)
194 {
195         struct pkg_info *info = data;
196         struct inst_info *inst;
197         Eina_List *l;
198         Eina_List *n;
199         int cnt = 0;
200
201         if (info->fault_info) {
202                 EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
203                         instance_destroyed(inst);
204                 }
205         } else {
206                 EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
207                         cnt += instance_need_slave(inst);
208                         /*!
209                          * instance_deactivated will call the slave_unload_instance.
210                          * if the loaded instance counter meets 0,
211                          * the slave will be deactivated.
212                          * so we should not call the instance activate function
213                          * from here.
214                          *
215                          * activate slave when the slave is reactivated
216                          */
217                 }
218         }
219
220         return cnt ? SLAVE_NEED_TO_REACTIVATE : 0;
221 }
222
223 static int xmonitor_paused_cb(void *data)
224 {
225         struct pkg_info *info = (struct pkg_info *)data;
226         struct inst_info *inst;
227         Eina_List *l;
228
229         if (slave_state(info->slave) != SLAVE_TERMINATED) {
230                 return 0;
231         }
232
233         EINA_LIST_FOREACH(info->inst_list, l, inst) {
234                 instance_freeze_updator(inst);
235         }
236
237         return 0;
238 }
239
240 static int xmonitor_resumed_cb(void *data)
241 {
242         struct pkg_info *info = data;
243         struct inst_info *inst;
244         Eina_List *l;
245
246         if (slave_state(info->slave) != SLAVE_TERMINATED) {
247                 return 0;
248         }
249
250         EINA_LIST_FOREACH(info->inst_list, l, inst) {
251                 instance_thaw_updator(inst);
252         }
253
254         return 0;
255 }
256
257 static int slave_paused_cb(struct slave_node *slave, void *data)
258 {
259         struct pkg_info *info = (struct pkg_info *)data;
260         struct inst_info *inst;
261         Eina_List *l;
262
263         EINA_LIST_FOREACH(info->inst_list, l, inst) {
264                 instance_freeze_updator(inst);
265         }
266
267         return 0;
268 }
269
270 static int slave_resumed_cb(struct slave_node *slave, void *data)
271 {
272         struct pkg_info *info = (struct pkg_info *)data;
273         struct inst_info *inst;
274         Eina_List *l;
275
276         EINA_LIST_FOREACH(info->inst_list, l, inst) {
277                 instance_thaw_updator(inst);
278         }
279
280         return 0;
281 }
282
283 static inline void destroy_package(struct pkg_info *info)
284 {
285         struct context_info *ctx_info;
286         EINA_LIST_FREE(info->ctx_list, ctx_info) {
287                 /* This items will be deleted from group_del_livebox */
288         }
289
290         group_del_livebox(info->lbid);
291         package_clear_fault(info);
292
293         s_info.pkg_list = eina_list_remove(s_info.pkg_list, info);
294
295         if (info->lb.type == LB_TYPE_SCRIPT) {
296                 DbgFree(info->lb.info.script.path);
297                 DbgFree(info->lb.info.script.group);
298         }
299
300         if (info->pd.type == PD_TYPE_SCRIPT) {
301                 DbgFree(info->pd.info.script.path);
302                 DbgFree(info->pd.info.script.group);
303         }
304
305         DbgFree(info->script);
306         DbgFree(info->abi);
307         DbgFree(info->lbid);
308         DbgFree(info->lb.libexec);
309         DbgFree(info->lb.auto_launch);
310         DbgFree(info->pkgid);
311
312         DbgFree(info);
313 }
314
315 static inline int load_conf(struct pkg_info *info)
316 {
317         struct parser *parser;
318         const char *str;
319         const char *group;
320
321         parser = parser_load(info->lbid);
322         if (!parser) {
323                 info->lb.size_list = 0x01; /* Default */
324
325                 info->script = strdup(DEFAULT_SCRIPT);
326                 if (!info->script) {
327                         ErrPrint("Heap: %s\n", strerror(errno));
328                         return LB_STATUS_ERROR_MEMORY;
329                 }
330
331                 info->abi = strdup(DEFAULT_ABI);
332                 if (!info->abi) {
333                         ErrPrint("Heap: %s\n", strerror(errno));
334                         DbgFree(info->script);
335                         info->script = NULL;
336                         return LB_STATUS_ERROR_MEMORY;
337                 }
338
339                 info->pd.width = g_conf.width;
340                 info->pd.height = g_conf.height >> 2;
341                 info->lb.pinup = 1;
342                 return LB_STATUS_SUCCESS;
343         }
344
345         info->lb.type = LB_TYPE_FILE;
346         if (parser_text_lb(parser)) {
347                 info->lb.type = LB_TYPE_TEXT;
348         } else if (parser_buffer_lb(parser)) {
349                 info->lb.type = LB_TYPE_BUFFER;
350         } else {
351                 str = parser_lb_path(parser);
352                 if (str) {
353                         info->lb.type = LB_TYPE_SCRIPT;
354
355                         info->lb.info.script.path = strdup(str);
356                         if (!info->lb.info.script.path) {
357                                 ErrPrint("Heap: %s\n", strerror(errno));
358                                 parser_unload(parser);
359                                 return LB_STATUS_ERROR_MEMORY;
360                         }
361
362                         str = parser_lb_group(parser);
363                         if (str) {
364                                 info->lb.info.script.group = strdup(str);
365                                 if (!info->lb.info.script.group) {
366                                         ErrPrint("Heap: %s\n", strerror(errno));
367                                         DbgFree(info->lb.info.script.path);
368                                         parser_unload(parser);
369                                         return LB_STATUS_ERROR_MEMORY;
370                                 }
371                         }
372                 }
373         }
374
375         if (parser_text_pd(parser)) {
376                 info->pd.type = PD_TYPE_TEXT;
377         } else if (parser_buffer_pd(parser)) {
378                 info->pd.type = PD_TYPE_BUFFER;
379         } else {
380                 str = parser_pd_path(parser);
381                 if (str) {
382                         info->pd.type = PD_TYPE_SCRIPT;
383                         info->pd.info.script.path = strdup(str);
384                         if (!info->pd.info.script.path) {
385                                 ErrPrint("Heap: %s\n", strerror(errno));
386                                 if (info->lb.type == LB_TYPE_SCRIPT) {
387                                         DbgFree(info->lb.info.script.path);
388                                         DbgFree(info->lb.info.script.group);
389                                 }
390                                 parser_unload(parser);
391                                 return LB_STATUS_ERROR_MEMORY;
392                         }
393
394                         str = parser_pd_group(parser);
395                         if (str) {
396                                 info->pd.info.script.group = strdup(str);
397                                 if (!info->pd.info.script.group) {
398                                         ErrPrint("Heap: %s\n", strerror(errno));
399                                         DbgFree(info->pd.info.script.path);
400                                         if (info->lb.type == LB_TYPE_SCRIPT) {
401                                                 DbgFree(info->lb.info.script.path);
402                                                 DbgFree(info->lb.info.script.group);
403                                         }
404                                         parser_unload(parser);
405                                         return LB_STATUS_ERROR_MEMORY;
406                                 }
407                         }
408                 }
409         }
410
411         str = parser_script(parser);
412         str = str ? str : DEFAULT_SCRIPT;
413         info->script = strdup(str);
414         if (!info->script) {
415                 ErrPrint("Heap: %s\n", strerror(errno));
416                 if (info->pd.type == PD_TYPE_SCRIPT) {
417                         DbgFree(info->pd.info.script.path);
418                         DbgFree(info->pd.info.script.group);
419                 }
420
421                 if (info->lb.type == LB_TYPE_SCRIPT) {
422                         DbgFree(info->lb.info.script.path);
423                         DbgFree(info->lb.info.script.group);
424                 }
425
426                 parser_unload(parser);
427                 return LB_STATUS_ERROR_MEMORY;
428         }
429
430         str = parser_abi(parser);
431         str = str ? str : DEFAULT_ABI;
432         info->abi = strdup(str);
433         if (!info->abi) {
434                 ErrPrint("Heap: %s\n", strerror(errno));
435                 DbgFree(info->script);
436                 if (info->pd.type == PD_TYPE_SCRIPT) {
437                         DbgFree(info->pd.info.script.path);
438                         DbgFree(info->pd.info.script.group);
439                 }
440
441                 if (info->lb.type == LB_TYPE_SCRIPT) {
442                         DbgFree(info->lb.info.script.path);
443                         DbgFree(info->lb.info.script.group);
444                 }
445                 parser_unload(parser);
446                 return LB_STATUS_ERROR_MEMORY;
447         }
448
449         info->lb.timeout = parser_timeout(parser);
450         info->network = parser_network(parser);
451
452         info->lb.period = parser_period(parser);
453         if (info->lb.period < 0.0f) {
454                 info->lb.period = 0.0f;
455         } else if (info->lb.period > 0.0f && info->lb.period < MINIMUM_PERIOD) {
456                 info->lb.period = MINIMUM_PERIOD;
457         }
458
459         info->lb.size_list = parser_size(parser);
460
461         str = parser_auto_launch(parser);
462         str = str ? str : "";
463         info->lb.auto_launch = strdup(str);
464         if (!info->lb.auto_launch) {
465                 ErrPrint("Heap: %s\n", strerror(errno));
466                 DbgFree(info->abi);
467                 DbgFree(info->script);
468                 if (info->pd.type == PD_TYPE_SCRIPT) {
469                         DbgFree(info->pd.info.script.path);
470                         DbgFree(info->pd.info.script.group);
471                 }
472
473                 if (info->lb.type == LB_TYPE_SCRIPT) {
474                         DbgFree(info->lb.info.script.path);
475                         DbgFree(info->lb.info.script.group);
476                 }
477                 parser_unload(parser);
478                 return LB_STATUS_ERROR_MEMORY;
479         }
480
481         info->secured = parser_secured(parser);
482         info->lb.pinup = parser_pinup(parser);
483
484         parser_get_pdsize(parser, &info->pd.width, &info->pd.height);
485
486         group = parser_group_str(parser);
487         if (group && group_add_livebox(group, info->lbid) < 0) {
488                 ErrPrint("Failed to build cluster tree for %s{%s}\n", info->lbid, group);
489         }
490
491         parser_unload(parser);
492         return LB_STATUS_SUCCESS;
493 }
494
495 HAPI struct pkg_info *package_create(const char *pkgid, const char *lbid)
496 {
497         struct pkg_info *pkginfo;
498
499         pkginfo = calloc(1, sizeof(*pkginfo));
500         if (!pkginfo) {
501                 ErrPrint("Heap: %s\n", strerror(errno));
502                 return NULL;
503         }
504
505         pkginfo->pkgid = strdup(pkgid);
506         if (!pkginfo->pkgid) {
507                 ErrPrint("Heap: %s\n", strerror(errno));
508                 DbgFree(pkginfo);
509                 return NULL;
510         }
511
512         pkginfo->lbid = io_livebox_pkgname(lbid);
513         if (!pkginfo->lbid) {
514                 ErrPrint("Failed to get pkgname, fallback to fs checker\n");
515                 if (util_validate_livebox_package(lbid) < 0) {
516                         ErrPrint("Invalid package name: %s\n", lbid);
517                         DbgFree(pkginfo->pkgid);
518                         DbgFree(pkginfo);
519                         return NULL;
520                 }
521
522                 pkginfo->lbid = strdup(lbid);
523                 if (!pkginfo->lbid) {
524                         ErrPrint("Heap: %s\n", strerror(errno));
525                         DbgFree(pkginfo->pkgid);
526                         DbgFree(pkginfo);
527                         return NULL;
528                 }
529         }
530
531         if (io_load_package_db(pkginfo) < 0) {
532                 ErrPrint("Failed to load DB, fall back to conf file loader\n");
533                 if (load_conf(pkginfo) < 0) {
534                         ErrPrint("Failed to initiate the conf file loader\n");
535                         DbgFree(pkginfo->lbid);
536                         DbgFree(pkginfo->pkgid);
537                         DbgFree(pkginfo);
538                         return NULL;
539                 }
540         }
541
542         package_ref(pkginfo);
543
544         s_info.pkg_list = eina_list_append(s_info.pkg_list, pkginfo);
545
546         return pkginfo;
547 }
548
549 HAPI int package_destroy(struct pkg_info *info)
550 {
551         package_unref(info);
552         return LB_STATUS_SUCCESS;
553 }
554
555 HAPI Eina_List *package_ctx_info(struct pkg_info *pkginfo)
556 {
557         return pkginfo->ctx_list;
558 }
559
560 HAPI void package_add_ctx_info(struct pkg_info *pkginfo, struct context_info *info)
561 {
562         pkginfo->ctx_list = eina_list_append(pkginfo->ctx_list, info);
563 }
564
565 HAPI void package_del_ctx_info(struct pkg_info *pkginfo, struct context_info *info)
566 {
567         pkginfo->ctx_list = eina_list_remove(pkginfo->ctx_list, info);
568 }
569
570 HAPI char *package_lb_pkgname(const char *pkgname)
571 {
572         char *lbid;
573
574         lbid = io_livebox_pkgname(pkgname);
575         if (!lbid) {
576                 if (util_validate_livebox_package(pkgname) < 0) {
577                         return NULL;
578                 }
579
580                 lbid = strdup(pkgname);
581                 if (!lbid) {
582                         ErrPrint("Heap: %s\n", strerror(errno));
583                         return NULL;
584                 }
585         }
586
587         return lbid;
588 }
589
590 HAPI int package_is_lb_pkgname(const char *pkgname)
591 {
592         char *lbid;
593         int ret;
594
595         lbid = package_lb_pkgname(pkgname);
596         ret = !!lbid;
597         DbgFree(lbid);
598
599         return ret;
600 }
601
602 HAPI struct pkg_info *package_find(const char *lbid)
603 {
604         Eina_List *l;
605         struct pkg_info *info;
606
607         if (!lbid) {
608                 return NULL;
609         }
610
611         EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
612                 if (!strcmp(info->lbid, lbid)) {
613                         return info;
614                 }
615         }
616
617         return NULL;
618 }
619
620 HAPI struct inst_info *package_find_instance_by_id(const char *lbid, const char *id)
621 {
622         Eina_List *l;
623         struct inst_info *inst;
624         struct pkg_info *info;
625
626         info = package_find(lbid);
627         if (!info) {
628                 ErrPrint("Package %s is not exists\n", lbid);
629                 return NULL;
630         }
631
632         EINA_LIST_FOREACH(info->inst_list, l, inst) {
633                 if (!strcmp(instance_id(inst), id)) {
634                         return inst;
635                 }
636         }
637
638         return NULL;
639 }
640
641 HAPI struct inst_info *package_find_instance_by_timestamp(const char *lbid, double timestamp)
642 {
643         Eina_List *l;
644         struct inst_info *inst;
645         struct pkg_info *info;
646
647         info = package_find(lbid);
648         if (!info) {
649                 ErrPrint("Package %s is not exists\n", lbid);
650                 return NULL;
651         }
652
653         EINA_LIST_FOREACH(info->inst_list, l, inst) {
654                 if (instance_timestamp(inst) == timestamp) {
655                         return inst;
656                 }
657         }
658
659         return NULL;
660 }
661
662 HAPI int package_dump_fault_info(struct pkg_info *info)
663 {
664         if (!info->fault_info) {
665                 return LB_STATUS_ERROR_NOT_EXIST;
666         }
667
668         CRITICAL_LOG("=============\n");
669         CRITICAL_LOG("faulted at %lf\n", info->fault_info->timestamp);
670         CRITICAL_LOG("Package: %s\n", info->lbid);
671         CRITICAL_LOG("Function: %s\n", info->fault_info->function);
672         CRITICAL_LOG("InstanceID: %s\n", info->fault_info->filename);
673         return LB_STATUS_SUCCESS;
674 }
675
676 HAPI int package_get_fault_info(struct pkg_info *info, double *timestamp, const char **filename, const char **function)
677 {
678         if (!info->fault_info) {
679                 return LB_STATUS_ERROR_NOT_EXIST;
680         }
681
682         *timestamp = info->fault_info->timestamp;
683         *filename = info->fault_info->filename;
684         *function = info->fault_info->function;
685         return LB_STATUS_SUCCESS;
686 }
687
688 HAPI int package_set_fault_info(struct pkg_info *info, double timestamp, const char *filename, const char *function)
689 {
690         struct fault_info *fault;
691
692         package_clear_fault(info);
693
694         fault = calloc(1, sizeof(*fault));
695         if (!fault) {
696                 ErrPrint("Heap: %s\n", strerror(errno));
697                 return LB_STATUS_ERROR_MEMORY;
698         }
699
700         fault->timestamp = timestamp;
701         if (!filename) {
702                 filename = "unknown";
703         }
704         if (!function) {
705                 function = "unknown";
706         }
707
708         fault->filename = strdup(filename);
709         if (!fault->filename) {
710                 ErrPrint("Heap: %s\n", strerror(errno));
711                 DbgFree(fault);
712                 return LB_STATUS_ERROR_MEMORY;
713         }
714
715         fault->function = strdup(function);
716         if (!fault->function) {
717                 ErrPrint("Heap: %s\n", strerror(errno));
718                 DbgFree(fault->filename);
719                 DbgFree(fault);
720                 return LB_STATUS_ERROR_MEMORY;
721         }
722
723         info->fault_info = fault;
724         info->fault_count++;
725         return LB_STATUS_SUCCESS;
726 }
727
728 HAPI int package_clear_fault(struct pkg_info *info)
729 {
730         if (!info->fault_info) {
731                 return LB_STATUS_ERROR_INVALID;
732         }
733         
734         package_dump_fault_info(info);
735
736         DbgFree(info->fault_info->function);
737         DbgFree(info->fault_info->filename);
738         DbgFree(info->fault_info);
739         info->fault_info = NULL;
740         return LB_STATUS_SUCCESS;
741 }
742
743 HAPI const int const package_is_fault(const struct pkg_info *info)
744 {
745         return !!info->fault_info;
746 }
747
748 HAPI struct slave_node * const package_slave(const struct pkg_info *info)
749 {
750         return info->slave;
751 }
752
753 HAPI const int const package_timeout(const struct pkg_info *info)
754 {
755         return info->lb.timeout;
756 }
757
758 HAPI void package_set_timeout(struct pkg_info *info, int timeout)
759 {
760         info->lb.timeout = timeout;
761 }
762
763 HAPI const double const package_period(const struct pkg_info *info)
764 {
765         return info->lb.period;
766 }
767
768 HAPI void package_set_period(struct pkg_info *info, double period)
769 {
770         info->lb.period = period;
771 }
772
773 HAPI const int const package_secured(const struct pkg_info *info)
774 {
775         return info->secured;
776 }
777
778 HAPI void package_set_secured(struct pkg_info *info, int secured)
779 {
780         info->secured = secured;
781 }
782
783 HAPI const char * const package_script(const struct pkg_info *info)
784 {
785         return info->script;
786 }
787
788 HAPI int package_set_script(struct pkg_info *info, const char *script)
789 {
790         char *tmp;
791
792         tmp = strdup(script);
793         if (!tmp) {
794                 ErrPrint("Heap: %s\n", strerror(errno));
795                 return LB_STATUS_ERROR_MEMORY;
796         }
797
798         DbgFree(info->script);
799         info->script = tmp;
800         return LB_STATUS_SUCCESS;
801 }
802
803 HAPI const char * const package_abi(const struct pkg_info *info)
804 {
805         return info->abi;
806 }
807
808 HAPI int package_set_abi(struct pkg_info *info, const char *abi)
809 {
810         char *tmp;
811         tmp = strdup(abi);
812         if (!tmp) {
813                 ErrPrint("Heap: %s\n", strerror(errno));
814                 return LB_STATUS_ERROR_MEMORY;
815         }
816
817         DbgFree(info->abi);
818         info->abi = tmp;
819         return LB_STATUS_SUCCESS;
820 }
821
822 HAPI const char * const package_lb_path(const struct pkg_info *info)
823 {
824         if (info->lb.type != LB_TYPE_SCRIPT) {
825                 return NULL;
826         }
827
828         return info->lb.info.script.path;
829 }
830
831 HAPI int package_set_lb_path(struct pkg_info *info, const char *path)
832 {
833         char *tmp;
834
835         if (info->lb.type != LB_TYPE_SCRIPT) {
836                 return LB_STATUS_ERROR_INVALID;
837         }
838
839         tmp = strdup(path);
840         if (!tmp) {
841                 ErrPrint("Heap: %s\n", strerror(errno));
842                 return LB_STATUS_ERROR_MEMORY;
843         }
844
845         DbgFree(info->lb.info.script.path);
846         info->lb.info.script.path = tmp;
847         return LB_STATUS_SUCCESS;
848 }
849
850 HAPI const char * const package_lb_group(const struct pkg_info *info)
851 {
852         if (info->lb.type != LB_TYPE_SCRIPT) {
853                 return NULL;
854         }
855
856         return info->lb.info.script.group;
857 }
858
859 HAPI int package_set_lb_group(struct pkg_info *info, const char *group)
860 {
861         char *tmp;
862
863         if (info->lb.type != LB_TYPE_SCRIPT) {
864                 return LB_STATUS_ERROR_INVALID;
865         }
866
867         tmp = strdup(group);
868         if (!tmp) {
869                 ErrPrint("Heap: %s\n", strerror(errno));
870                 return LB_STATUS_ERROR_MEMORY;
871         }
872
873         DbgFree(info->lb.info.script.group);
874         info->lb.info.script.group = tmp;
875         return LB_STATUS_SUCCESS;
876 }
877
878 HAPI const char * const package_pd_path(const struct pkg_info *info)
879 {
880         if (info->pd.type != PD_TYPE_SCRIPT) {
881                 return NULL;
882         }
883
884         return info->pd.info.script.path;
885 }
886
887 HAPI int package_set_pd_path(struct pkg_info *info, const char *path)
888 {
889         char *tmp;
890
891         if (info->pd.type != PD_TYPE_SCRIPT) {
892                 return LB_STATUS_ERROR_INVALID;
893         }
894
895         tmp = strdup(path);
896         if (!tmp) {
897                 ErrPrint("Heap: %s\n", strerror(errno));
898                 return LB_STATUS_ERROR_MEMORY;
899         }
900
901         DbgFree(info->pd.info.script.path);
902         info->pd.info.script.path = tmp;
903         return LB_STATUS_SUCCESS;
904 }
905
906 HAPI const char * const package_pd_group(const struct pkg_info *info)
907 {
908         if (info->pd.type != PD_TYPE_SCRIPT) {
909                 return NULL;
910         }
911
912         return info->pd.info.script.group;
913 }
914
915 HAPI int package_set_pd_group(struct pkg_info *info, const char *group)
916 {
917         char *tmp;
918
919         if (info->pd.type != PD_TYPE_SCRIPT) {
920                 return LB_STATUS_ERROR_INVALID;
921         }
922
923         tmp = strdup(group);
924         if (!tmp) {
925                 ErrPrint("Heap: %s\n", strerror(errno));
926                 return LB_STATUS_ERROR_MEMORY;
927         }
928
929         DbgFree(info->pd.info.script.group);
930         info->pd.info.script.group = tmp;
931         return LB_STATUS_SUCCESS;
932 }
933
934 HAPI const int const package_pinup(const struct pkg_info *info)
935 {
936         return info->lb.pinup;
937 }
938
939 HAPI void package_set_pinup(struct pkg_info *info, int pinup)
940 {
941         info->lb.pinup = pinup;
942 }
943
944 HAPI const char * const package_auto_launch(const struct pkg_info *info)
945 {
946         return info->lb.auto_launch;
947 }
948
949 HAPI void package_set_auto_launch(struct pkg_info *info, const char *auto_launch)
950 {
951         if (!auto_launch) {
952                 auto_launch = "";
953         }
954
955         info->lb.auto_launch = strdup(auto_launch);
956         if (!info->lb.auto_launch) {
957                 ErrPrint("Heap: %s\n", strerror(errno));
958                 return;
959         }
960 }
961
962 HAPI const unsigned int const package_size_list(const struct pkg_info *info)
963 {
964         return info->lb.size_list;
965 }
966
967 HAPI void package_set_size_list(struct pkg_info *info, unsigned int size_list)
968 {
969         info->lb.size_list = size_list;
970 }
971
972 HAPI const int const package_pd_width(const struct pkg_info *info)
973 {
974         return info->pd.width;
975 }
976
977 HAPI void package_set_pd_width(struct pkg_info *info, int width)
978 {
979         info->pd.width = width;
980 }
981
982 HAPI const int const package_pd_height(const struct pkg_info *info)
983 {
984         return info->pd.height;
985 }
986
987 HAPI void package_set_pd_height(struct pkg_info *info, int height)
988 {
989         info->pd.height = height;
990 }
991
992 HAPI struct pkg_info * const package_ref(struct pkg_info *info)
993 {
994         info->refcnt++;
995         return info;
996 }
997
998 HAPI struct pkg_info * const package_unref(struct pkg_info *info)
999 {
1000         if (info->refcnt == 0) {
1001                 ErrPrint("Invalid request\n");
1002                 return NULL;
1003         }
1004
1005         info->refcnt--;
1006         if (info->refcnt == 0) {
1007                 destroy_package(info);
1008                 info = NULL;
1009         }
1010
1011         return info;
1012 }
1013
1014 HAPI const int const package_refcnt(const struct pkg_info *info)
1015 {
1016         return info->refcnt;
1017 }
1018
1019 HAPI const enum lb_type package_lb_type(const struct pkg_info *info)
1020 {
1021         return info->lb.type;
1022 }
1023
1024 HAPI void package_set_lb_type(struct pkg_info *info, enum lb_type type)
1025 {
1026         info->lb.type = type;
1027 }
1028
1029 HAPI const char * const package_libexec(struct pkg_info *info)
1030 {
1031         return info->lb.libexec;
1032 }
1033
1034 HAPI int package_set_libexec(struct pkg_info *info, const char *libexec)
1035 {
1036         char *tmp;
1037
1038         tmp = strdup(libexec);
1039         if (!tmp) {
1040                 ErrPrint("Heap: %s\n", strerror(errno));
1041                 return LB_STATUS_ERROR_MEMORY;
1042         }
1043
1044         DbgFree(info->lb.libexec);
1045         info->lb.libexec = tmp;
1046         return LB_STATUS_SUCCESS;
1047 }
1048
1049 HAPI int package_network(struct pkg_info *info)
1050 {
1051         return info->network;
1052 }
1053
1054 HAPI void package_set_network(struct pkg_info *info, int network)
1055 {
1056         info->network = network;
1057 }
1058
1059 HAPI const enum pd_type const package_pd_type(const struct pkg_info *info)
1060 {
1061         return info->pd.type;
1062 }
1063
1064 HAPI void package_set_pd_type(struct pkg_info *info, enum pd_type type)
1065 {
1066         info->pd.type = type;
1067 }
1068
1069 /*!
1070  * \note
1071  * Add the instance to the package info.
1072  * If a package has no slave, assign a new slave.
1073  */
1074 static inline int assign_new_slave(struct pkg_info *info)
1075 {
1076         char *s_name;
1077         char *s_pkgname;
1078         const char *tmp;
1079
1080         s_name = util_slavename();
1081         if (!s_name) {
1082                 ErrPrint("Failed to get a new slave name\n");
1083                 return LB_STATUS_ERROR_FAULT;
1084         }
1085
1086         tmp = abi_find_slave(info->abi);
1087         if (!tmp) {
1088                 DbgFree(s_name);
1089                 ErrPrint("Failed to find a proper pkgname of a slave\n");
1090                 return LB_STATUS_ERROR_INVALID;
1091         }
1092
1093         s_pkgname = util_replace_string(tmp, REPLACE_TAG_APPID, info->lbid);
1094         if (!s_pkgname) {
1095                 DbgPrint("Failed to get replaced string\n");
1096                 s_pkgname = strdup(tmp);
1097                 if (!s_pkgname) {
1098                         ErrPrint("Heap: %s\n", strerror(errno));
1099                         DbgFree(s_name);
1100                         return LB_STATUS_ERROR_MEMORY;
1101                 }
1102         }
1103
1104         DbgPrint("New slave[%s] is assigned for %s (using %s / abi[%s])\n", s_name, info->lbid, s_pkgname, info->abi);
1105         info->slave = slave_create(s_name, info->secured, info->abi, s_pkgname, info->network);
1106
1107         DbgFree(s_name);
1108         DbgFree(s_pkgname);
1109
1110         if (!info->slave) {
1111                 /*!
1112                  * \note
1113                  * package_destroy will try to remove "info" from the pkg_list.
1114                  * but we didn't add this to it yet.
1115                  * If the list method couldn't find an "info" from the list,
1116                  * it just do nothing so I'll leave this.
1117                  */
1118                 return LB_STATUS_ERROR_FAULT;
1119         }
1120         /*!
1121          * \note
1122          * Slave is not activated yet.
1123          */
1124         return LB_STATUS_SUCCESS;
1125 }
1126
1127 HAPI int package_add_instance(struct pkg_info *info, struct inst_info *inst)
1128 {
1129         if (!info->inst_list) {
1130                 info->slave = slave_find_available(info->abi, info->secured, info->network);
1131
1132                 if (!info->slave) {
1133                         int ret;
1134
1135                         ret = assign_new_slave(info);
1136                         if (ret < 0) {
1137                                 return ret;
1138                         }
1139                 } else {
1140                         DbgPrint("Slave %s is used for %s\n", slave_name(info->slave), info->lbid);
1141                 }
1142
1143                 slave_ref(info->slave);
1144                 slave_load_package(info->slave);
1145                 slave_event_callback_add(info->slave, SLAVE_EVENT_DEACTIVATE, slave_deactivated_cb, info);
1146                 slave_event_callback_add(info->slave, SLAVE_EVENT_ACTIVATE, slave_activated_cb, info);
1147                 slave_event_callback_add(info->slave, SLAVE_EVENT_FAULT, slave_fault_cb, info);
1148
1149                 if (info->secured) {
1150                         slave_event_callback_add(info->slave, SLAVE_EVENT_PAUSE, slave_paused_cb, info);
1151                         slave_event_callback_add(info->slave, SLAVE_EVENT_RESUME, slave_resumed_cb, info);
1152
1153                         /*!
1154                          * \note
1155                          * In case of the slave is terminated because of expired TTL timer,
1156                          * Master should freeze the all update time.
1157                          * But the callback should check the slave's state to prevent from duplicated freezing.
1158                          *
1159                          * This callback will freeze the timer only if a slave doesn't running.
1160                          */
1161                         xmonitor_add_event_callback(XMONITOR_PAUSED, xmonitor_paused_cb, info);
1162                         xmonitor_add_event_callback(XMONITOR_RESUMED, xmonitor_resumed_cb, info);
1163                 }
1164         }
1165
1166         info->inst_list = eina_list_append(info->inst_list, inst);
1167         return LB_STATUS_SUCCESS;
1168 }
1169
1170 HAPI int package_del_instance(struct pkg_info *info, struct inst_info *inst)
1171 {
1172         info->inst_list = eina_list_remove(info->inst_list, inst);
1173
1174         if (info->inst_list) {
1175                 return LB_STATUS_SUCCESS;
1176         }
1177
1178         if (info->slave) {
1179                 slave_unload_package(info->slave);
1180
1181                 slave_event_callback_del(info->slave, SLAVE_EVENT_FAULT, slave_fault_cb, info);
1182                 slave_event_callback_del(info->slave, SLAVE_EVENT_DEACTIVATE, slave_deactivated_cb, info);
1183                 slave_event_callback_del(info->slave, SLAVE_EVENT_ACTIVATE, slave_activated_cb, info);
1184
1185                 if (info->secured) {
1186                         slave_event_callback_del(info->slave, SLAVE_EVENT_PAUSE, slave_paused_cb, info);
1187                         slave_event_callback_del(info->slave, SLAVE_EVENT_RESUME, slave_resumed_cb, info);
1188
1189                         xmonitor_del_event_callback(XMONITOR_PAUSED, xmonitor_paused_cb, info);
1190                         xmonitor_del_event_callback(XMONITOR_RESUMED, xmonitor_resumed_cb, info);
1191                 }
1192
1193                 slave_unref(info->slave);
1194                 info->slave = NULL;
1195         }
1196
1197         if (info->is_uninstalled) {
1198                 package_destroy(info);
1199         }
1200
1201         return LB_STATUS_SUCCESS;
1202 }
1203
1204 HAPI Eina_List *package_instance_list(struct pkg_info *info)
1205 {
1206         return info->inst_list;
1207 }
1208
1209 static int client_created_cb(struct client_node *client, void *data)
1210 {
1211         struct pkg_info *info;
1212         Eina_List *l;
1213
1214         struct inst_info *inst;
1215         Eina_List *i_l;
1216
1217         EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
1218                 if (info->fault_info) {
1219                         fault_unicast_info(client, info->lbid, info->fault_info->filename, info->fault_info->function);
1220                         continue;
1221                 }
1222
1223                 EINA_LIST_FOREACH(info->inst_list, i_l, inst) {
1224                         switch (instance_state(inst)) {
1225                         case INST_INIT:
1226                                 /* Will be send a created event after the instance gets created event */
1227                                 break;
1228                         case INST_ACTIVATED: /*!< This instance is actiavted, and used */
1229                         case INST_REQUEST_TO_REACTIVATE: /*!< This instance will be reactivated soon */
1230                         case INST_REQUEST_TO_DESTROY: /*!< This instance will be destroy soon */
1231                                 if (instance_client(inst) == client) {
1232                                         instance_unicast_created_event(inst, client);
1233                                 } else if (instance_client(inst) == NULL) {
1234                                         /*!
1235                                          * \note
1236                                          * Instances are lives in the system cluster/sub-cluster
1237                                          */
1238                                         if (client_is_subscribed(client, instance_cluster(inst), instance_category(inst))) {
1239                                                 instance_unicast_created_event(inst, client);
1240                                                 DbgPrint("(Subscribed) Created package: %s\n", info->lbid);
1241                                         }
1242                                 }
1243
1244                                 break;
1245                         default:
1246                                 DbgPrint("%s(%s) is not activated (%d)\n",
1247                                                 package_name(info), instance_id(inst), instance_state(inst));
1248                                 break;
1249                         }
1250                 }
1251         }
1252
1253         return 0;
1254 }
1255
1256 static int io_uninstall_cb(const char *pkgid, const char *lbid, int prime, void *data)
1257 {
1258         struct pkg_info *info;
1259         Eina_List *l;
1260         Eina_List *n;
1261         struct inst_info *inst;
1262
1263         DbgPrint("Package %s is uninstalled\n", lbid);
1264         info = package_find(lbid);
1265         if (!info) {
1266                 DbgPrint("%s is not yet loaded\n", lbid);
1267                 return 0;
1268         }
1269
1270         info->is_uninstalled = 1;
1271
1272         /*!
1273          * \NOTE
1274          * Don't delete an item from the inst_list.
1275          * destroy callback will use this list again.
1276          * So, Don't touch it from here.
1277          */
1278         if (info->inst_list) {
1279                 EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
1280                         instance_destroy(inst, INSTANCE_DESTROY_PKGMGR);
1281                 }
1282         } else {
1283                 package_destroy(info);
1284         }
1285
1286         return 0;
1287 }
1288
1289 static inline void reload_package_info(struct pkg_info *info)
1290 {
1291         Eina_List *l;
1292         Eina_List *n;
1293         struct inst_info *inst;
1294         unsigned int size_type;
1295         int width;
1296         int height;
1297
1298         DbgPrint("Already exists, try to update it\n");
1299
1300         group_del_livebox(info->lbid);
1301         package_clear_fault(info);
1302
1303         /*!
1304          * \NOTE:
1305          * Nested DB I/O
1306          */
1307         io_load_package_db(info);
1308
1309         /*!
1310          * \note
1311          * Without "is_uninstalled", the package will be kept
1312          */
1313         EINA_LIST_FOREACH_SAFE(info->inst_list, l, n, inst) {
1314                 width = instance_lb_width(inst);
1315                 height = instance_lb_height(inst);
1316                 size_type = livebox_service_size_type(width, height);
1317                 if (info->lb.size_list & size_type) {
1318                         instance_reload(inst, INSTANCE_DESTROY_PKGMGR);
1319                 } else {
1320                         instance_destroy(inst, INSTANCE_DESTROY_PKGMGR);
1321                 }
1322         }
1323 }
1324
1325 static int io_install_cb(const char *pkgid, const char *lbid, int prime, void *data)
1326 {
1327         struct pkg_info *info;
1328
1329         info = package_find(lbid);
1330         if (info) {
1331                 /*!
1332                  * Already exists. skip to create this.
1333                  */
1334                 return 0;
1335         }
1336
1337         info = package_create(pkgid, lbid);
1338         if (!info) {
1339                 ErrPrint("Failed to build an info %s\n", lbid);
1340         } else {
1341                 DbgPrint("Livebox %s is built\n", lbid);
1342         }
1343
1344         return 0;
1345 }
1346
1347 static int uninstall_cb(const char *pkgname, enum pkgmgr_status status, double value, void *data)
1348 {
1349         Eina_List *l;
1350         Eina_List *n;
1351         struct pkg_info *info;
1352
1353         if (status != PKGMGR_STATUS_END) {
1354                 return 0;
1355         }
1356
1357         EINA_LIST_FOREACH_SAFE(s_info.pkg_list, l, n, info) {
1358                 if (!strcmp(info->pkgid, pkgname)) {
1359                         io_uninstall_cb(pkgname, info->lbid, -1, NULL);
1360                 }
1361         }
1362
1363         return 0;
1364 }
1365
1366 static int update_cb(const char *pkgname, enum pkgmgr_status status, double value, void *data)
1367 {
1368         Eina_List *l;
1369         Eina_List *n;
1370         struct pkg_info *info;
1371
1372         if (status != PKGMGR_STATUS_END) {
1373                 return 0;
1374         }
1375
1376         EINA_LIST_FOREACH_SAFE(s_info.pkg_list, l, n, info) {
1377                 if (!strcmp(info->pkgid, pkgname)) {
1378                         DbgPrint("Update lbid: %s\n", info->lbid);
1379                         if (io_is_exists(info->lbid) == 1) {
1380                                 reload_package_info(info);
1381                         } else {
1382                                 io_uninstall_cb(pkgname, info->lbid, -1, NULL);
1383                         }
1384                 }
1385         }
1386
1387         (void)io_update_livebox_package(pkgname, io_install_cb, NULL);
1388         return 0;
1389 }
1390
1391 static int crawling_liveboxes(const char *pkgid, const char *lbid, int prime, void *data)
1392 {
1393         if (package_find(lbid)) {
1394                 ErrPrint("Information of %s is already built\n", lbid);
1395         } else {
1396                 struct pkg_info *info;
1397                 info = package_create(pkgid, lbid);
1398                 if (info) {
1399                         DbgPrint("[%s] information is built prime(%d)\n", lbid, prime);
1400                 }
1401         }
1402
1403         return 0;
1404 }
1405
1406 HAPI int package_init(void)
1407 {
1408         client_global_event_handler_add(CLIENT_GLOBAL_EVENT_CREATE, client_created_cb, NULL);
1409         pkgmgr_init();
1410
1411         pkgmgr_add_event_callback(PKGMGR_EVENT_INSTALL, update_cb, NULL);
1412         pkgmgr_add_event_callback(PKGMGR_EVENT_UNINSTALL, uninstall_cb, NULL);
1413         pkgmgr_add_event_callback(PKGMGR_EVENT_UPDATE, update_cb, NULL);
1414
1415         io_crawling_liveboxes(crawling_liveboxes, NULL);
1416         return 0;
1417 }
1418
1419 HAPI int package_fini(void)
1420 {
1421         Eina_List *p_l;
1422         Eina_List *p_n;
1423         Eina_List *i_l;
1424         Eina_List *i_n;
1425         struct pkg_info *info;
1426         struct inst_info *inst;
1427
1428         pkgmgr_del_event_callback(PKGMGR_EVENT_INSTALL, update_cb, NULL);
1429         pkgmgr_del_event_callback(PKGMGR_EVENT_UNINSTALL, uninstall_cb, NULL);
1430         pkgmgr_del_event_callback(PKGMGR_EVENT_UPDATE, update_cb, NULL);
1431         pkgmgr_fini();
1432         client_global_event_handler_del(CLIENT_GLOBAL_EVENT_CREATE, client_created_cb, NULL);
1433
1434         EINA_LIST_FOREACH_SAFE(s_info.pkg_list, p_l, p_n, info) {
1435                 EINA_LIST_FOREACH_SAFE(info->inst_list, i_l, i_n, inst) {
1436                         instance_state_reset(inst);
1437                         instance_destroy(inst, INSTANCE_DESTROY_TERMINATE);
1438                 }
1439
1440                 package_destroy(info);
1441         }
1442
1443         return 0;
1444 }
1445
1446 HAPI const char *package_find_by_secured_slave(struct slave_node *slave)
1447 {
1448         Eina_List *l;
1449         struct pkg_info *info;
1450
1451         if (!slave_is_secured(slave)) {
1452                 return NULL;
1453         }
1454
1455         EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
1456                 if (info->slave == slave) {
1457                         return info->lbid;
1458                 }
1459         }
1460
1461         return NULL;
1462 }
1463
1464 HAPI const char * const package_name(const struct pkg_info *info)
1465 {
1466         return info->lbid;
1467 }
1468
1469 /*!
1470  * del_or_creat : 1 == create, 0 == delete
1471  */
1472 HAPI int package_alter_instances_to_client(struct client_node *client, enum alter_type alter)
1473 {
1474         struct pkg_info *info;
1475         Eina_List *l;
1476
1477         struct inst_info *inst;
1478         Eina_List *i_l;
1479
1480         EINA_LIST_FOREACH(s_info.pkg_list, l, info) {
1481                 EINA_LIST_FOREACH(info->inst_list, i_l, inst) {
1482                         if (instance_client(inst)) {
1483                                 continue;
1484                         }
1485
1486                         if (!client_is_subscribed(client, instance_cluster(inst), instance_category(inst))) {
1487                                 continue;
1488                         }
1489
1490                         switch (instance_state(inst)) {
1491                         case INST_INIT:
1492                         case INST_REQUEST_TO_ACTIVATE:
1493                                 /* Will be send a created event after the instance gets created event */
1494                                 switch (alter) {
1495                                 case ALTER_CREATE:
1496                                         if (!instance_has_client(inst, client)) {
1497                                                 instance_add_client(inst, client);
1498                                         }
1499                                         break;
1500                                 case ALTER_DESTROY:
1501                                         if (instance_has_client(inst, client)) {
1502                                                 instance_del_client(inst, client);
1503                                         }
1504                                         break;
1505                                 default:
1506                                         break;
1507                                 }
1508                                 break;
1509                         case INST_ACTIVATED: /*!< This instance is actiavted, and used */
1510                         case INST_REQUEST_TO_REACTIVATE: /*!< This instance will be reactivated soon */
1511                         case INST_REQUEST_TO_DESTROY: /*!< This instance will be destroy soon */
1512                                 /*!
1513                                  * \note
1514                                  * Instances are lives in the system cluster/sub-cluster
1515                                  */
1516                                 switch (alter) {
1517                                 case ALTER_CREATE:
1518                                         if (!instance_has_client(inst, client)) {
1519                                                 instance_unicast_created_event(inst, client);
1520                                                 instance_add_client(inst, client);
1521                                                 DbgPrint("(Subscribed) Created package: %s\n", info->lbid);
1522                                         }
1523                                         break;
1524                                 case ALTER_DESTROY:
1525                                         if (instance_has_client(inst, client)) {
1526                                                 instance_unicast_deleted_event(inst, client);
1527                                                 instance_del_client(inst, client);
1528                                         }
1529                                         break;
1530                                 default:
1531                                         break;
1532                                 }
1533
1534                                 break;
1535                         default:
1536                                 DbgPrint("%s(%s) is not activated (%d)\n",
1537                                                 package_name(info), instance_id(inst), instance_state(inst));
1538                                 break;
1539                         }
1540                 }
1541         }
1542
1543         return 0;
1544 }
1545
1546 HAPI const Eina_List *package_list(void)
1547 {
1548         return s_info.pkg_list;
1549 }
1550
1551 HAPI int const package_fault_count(struct pkg_info *info)
1552 {
1553         return info ? info->fault_count : 0;
1554 }
1555
1556 HAPI int package_is_enabled(const char *appid)
1557 {
1558         ail_appinfo_h ai;
1559         bool enabled;
1560         int ret;
1561
1562         ret = ail_get_appinfo(appid, &ai);
1563         if (ret != AIL_ERROR_OK) {
1564                 ErrPrint("Unable to get appinfo: %d\n", ret);
1565                 return 0;
1566         }
1567
1568         if (ail_appinfo_get_bool(ai, AIL_PROP_X_SLP_ENABLED_BOOL, &enabled) != AIL_ERROR_OK) {
1569                 enabled = false;
1570         }
1571
1572         ail_destroy_appinfo(ai);
1573
1574         return enabled == true;
1575 }
1576
1577 /* End of a file */