tizen 2.4 release
[framework/appfw/aul-1.git] / src / aul_rsc_mgr.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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
18 #define _GNU_SOURCE
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <glib/gstdio.h>
24 #include <bundle_internal.h>
25 #include <assert.h>
26 #include <dlog.h>
27 #include <vconf.h>
28 #include <system_info.h>
29 #include <pkgmgr-info.h>
30 #include <pkgmgrinfo_resource.h>
31
32 #include "aul.h"
33 #include "aul_api.h"
34 #include "aul_rsc_mgr.h"
35
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #endif
39
40 #define LOG_TAG "AUL_RESOURCE_MANAGER"
41
42 #define WEIGHT_SCREEN_DPI 10000
43 #define WEIGHT_SCREEN_DPI_RANGE 10000
44 #define WEIGHT_SCREEN_BPP 1000
45 #define WEIGHT_SCREEN_WIDTH_RANGE 100
46 #define WEIGHT_SCREEN_LARGE 10
47 #define WEIGHT_PLATFORM_VERSION 1000000
48 #define WEIGHT_LANGUAGE 100000
49
50 #define THRESHOLD_TO_CLEAN 50   /* app_resource_manager_trim_cache */
51
52 #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
53 #define MAX_PATH  1024
54
55 typedef struct {
56         resource_data_t *data;
57         GHashTable *cache;
58 } resource_manager_t;
59
60 typedef struct {
61         char *output;
62         int hit_cnt;
63         bool remove;
64 } resource_cache_context_t;
65
66 typedef struct {
67         const char *bundle_attr_key;
68         unsigned int bundle_attr_value;
69 } resource_node_attr_t;
70
71 typedef struct {
72         char *folder;
73         char *type;
74 } resource_node_list_t;
75
76 enum {
77         NODE_ATTR_MIN = 0,
78         NODE_ATTR_SCREEN_DPI,
79         NODE_ATTR_SCREEN_DPI_RANGE,
80         NODE_ATTR_SCREEN_WIDTH_RANGE,
81         NODE_ATTR_SCREEN_LARGE,
82         NODE_ATTR_SCREEN_BPP,
83         NODE_ATTR_PLATFORM_VER,
84         NODE_ATTR_LANGUAGE,
85         NODE_ATTR_MAX
86 };
87
88 static resource_manager_t *resource_handle = NULL;
89
90 static resource_node_attr_t map[] = {
91                 { RSC_NODE_ATTR_SCREEN_DPI, NODE_ATTR_SCREEN_DPI },
92                 { RSC_NODE_ATTR_SCREEN_DPI_RANGE, NODE_ATTR_SCREEN_DPI_RANGE },
93                 { RSC_NODE_ATTR_SCREEN_WIDTH_RANGE, NODE_ATTR_SCREEN_WIDTH_RANGE },
94                 { RSC_NODE_ATTR_SCREEN_LARGE, NODE_ATTR_SCREEN_LARGE },
95                 { RSC_NODE_ATTR_SCREEN_BPP, NODE_ATTR_SCREEN_BPP },
96                 { RSC_NODE_ATTR_PLATFORM_VER, NODE_ATTR_PLATFORM_VER },
97                 { RSC_NODE_ATTR_LANGUAGE, NODE_ATTR_LANGUAGE },
98 };
99
100 static GHashTable *attr_key = NULL;
101 static const char *res_path = NULL;
102 static char *cur_language = NULL;
103 static bool is_slice = FALSE;
104
105 static GHashTable *valid_path_list = NULL;
106 static GHashTable *supported_lang_list = NULL;
107 static GHashTable *id_list = NULL;
108 static GList *all_node_list = NULL;
109 static bundle *given_attr_list = NULL;
110
111 static gint __resource_manager_comp(gconstpointer a, gconstpointer b)
112 {
113         resource_group_t *rsc_group = (resource_group_t *) a;
114
115         return strcmp(rsc_group->type, b);
116 }
117
118 static gint __compare_path(gconstpointer a, gconstpointer b)
119 {
120         char tmp_path[MAX_PATH] = {0, };
121         resource_node_list_t *tmp_node_info= (resource_node_list_t *)a;
122
123         snprintf(tmp_path, MAX_PATH - 1, "%s%s", res_path, tmp_node_info->folder);
124         return strncmp(tmp_path, (char *)b, strlen(tmp_path));
125 }
126
127
128 static int __get_dpi(void)
129 {
130         int dpi = 0;
131         char *tmp = NULL;
132         if (is_slice) {
133                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_DPI, &tmp);
134                 if (tmp == NULL) {
135                         LOGE("Failed to retrieve DPI");
136                         dpi = 0;
137                 } else
138                         dpi = atoi(tmp);
139         } else
140                 system_info_get_platform_int("http://tizen.org/feature/screen.dpi", &dpi);
141
142         return dpi;
143 }
144
145 static int __get_screen_width(void)
146 {
147         int screen_width = 0;
148         char *tmp = NULL;
149
150         if (is_slice) {
151                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_WIDTH_RANGE, &tmp);
152                 if (tmp == NULL) {
153                         LOGE("Failed to retrieve screen width");
154                         screen_width = 0;
155                 } else
156                         screen_width = atoi(tmp);
157         } else
158                 system_info_get_platform_int("http://tizen.org/feature/screen.width", &screen_width);
159
160         return screen_width;
161 }
162
163 static bool __get_screen_large(void)
164 {
165         bool screen_large = true;
166         char *tmp = NULL;
167
168         if (is_slice) {
169                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_LARGE, &tmp);
170                 if (tmp == NULL) {
171                         LOGE("Failed to retrieve screen large");
172                         screen_large = false;
173                 } else
174                         screen_large = atoi(tmp);
175         } else {
176                 if (system_info_get_platform_bool("http://tizen.org/feature/screen.size.large", &screen_large) != SYSTEM_INFO_ERROR_NONE) {
177                         LOGE("Failed to get info of screen.size.large");
178                         screen_large = false;
179                 }
180         }
181
182         return screen_large;
183 }
184
185 static int __get_screen_bpp(void)
186 {
187         int screen_bpp = 0;
188         char *tmp = NULL;
189
190         if (is_slice) {
191                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_BPP, &tmp);
192                 if (tmp == NULL) {
193                         LOGE("Failed to retrieve screen bpp");
194                         screen_bpp = 0;
195                 } else
196                         screen_bpp = atoi(tmp);
197         } else
198                 system_info_get_platform_int("http://tizen.org/feature/screen.bpp", &screen_bpp);
199
200         return screen_bpp;
201 }
202
203 static char *__get_platform_version(void)
204 {
205         char *version = NULL;
206         if (is_slice)
207                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_PLATFORM_VER, &version);
208         else
209                 system_info_get_platform_string("http://tizen.org/feature/platform.version", &version);
210
211         return version;
212 }
213
214 static void __bundle_iterator_get_valid_nodes(const char *key, const int type,
215                 const bundle_keyval_t *kv, void *data)
216 {
217         unsigned int node_attr;
218         bool *invalid = (bool *) data;
219         bool ret_bool = true;
220         int min, max;
221         char from[5] = { 0, };
222         char to[3] = { 0, };
223         bool t_val;
224         char *val;
225         size_t size;
226         static int screen_dpi = -1;
227         static int screen_width = -1;
228         static int screen_size_large = -1;
229         static char *version = NULL;
230         static int screen_bpp = -1;
231
232         if (*invalid)
233                 return;
234
235         bundle_keyval_get_basic_val((bundle_keyval_t *) kv, (void**) &val, &size);
236
237         node_attr = (guint) g_hash_table_lookup(attr_key, key);
238         if (node_attr <= NODE_ATTR_MIN || node_attr >= NODE_ATTR_MAX) {
239                 LOGE("INVALID_PARAMETER(0x%08x), node_attr(%d)",
240                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, node_attr);
241                 *invalid = true;
242                 return;
243         }
244
245         switch (node_attr) {
246                 case NODE_ATTR_SCREEN_DPI:
247                         if (screen_dpi == -1)
248                                 screen_dpi =__get_dpi();
249                         if (screen_dpi != atoi(val))
250                                 *invalid = true;
251                         break;
252
253                 case NODE_ATTR_SCREEN_DPI_RANGE:
254                         sscanf(val, "%s %d %s %d", from, &min, to, &max);
255                         if (screen_dpi == -1)
256                                 screen_dpi =__get_dpi();
257                         if (!(min <= screen_dpi && screen_dpi <= max))
258                                 *invalid = true;
259                         break;
260
261                 case NODE_ATTR_SCREEN_WIDTH_RANGE:
262                         sscanf(val, "%s %d %s %d", from, &min, to, &max);
263                         if (screen_width == -1)
264                                 screen_width = __get_screen_width();
265                         if (!(min <= screen_width && screen_width <= max))
266                                 *invalid = true;
267                         break;
268
269                 case NODE_ATTR_SCREEN_LARGE:
270                         if (!(strcmp(val, "true")))
271                                 t_val = true;
272                         else
273                                 t_val = false;
274                         if (screen_size_large == -1) {
275                                 ret_bool = __get_screen_large();
276                                 if (ret_bool)
277                                         screen_size_large = 1;
278                                 else
279                                         screen_size_large = 0;
280                         }
281                         if (((bool)screen_size_large) != t_val)
282                                 *invalid = true;
283                         break;
284
285                 case NODE_ATTR_SCREEN_BPP:
286                         if (screen_bpp == -1)
287                                 screen_bpp = __get_screen_bpp();
288                         if (screen_bpp != atoi(val))
289                                 *invalid = true;
290                         break;
291
292                 case NODE_ATTR_PLATFORM_VER:
293                         if (version == NULL)
294                                 version = __get_platform_version();
295                         if (strcmp(version, val))
296                                 *invalid = true;
297                         break;
298
299                 case NODE_ATTR_LANGUAGE:
300                         if (cur_language == NULL)
301                                         cur_language = vconf_get_str(VCONFKEY_LANGSET);
302
303                         if (strncmp(cur_language, val, strlen(val)))
304                                 *invalid = true;
305                         break;
306         }
307 }
308
309 static void __bundle_iterator_get_best_node(const char *key, const char *val,
310                 void *data)
311 {
312         unsigned int node_attr;
313         unsigned int *weight = (unsigned int *) data;
314
315         node_attr = (guint) g_hash_table_lookup(attr_key, key);
316         if (node_attr <= NODE_ATTR_MIN || node_attr >= NODE_ATTR_MAX) {
317                 LOGE("INVALID_PARAMETER(0x%08x), node_attr(%d)",
318                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, node_attr);
319                 return;
320         }
321
322         switch (node_attr) {
323                 case NODE_ATTR_SCREEN_DPI:
324                         *weight += WEIGHT_SCREEN_DPI;
325                         break;
326
327                 case NODE_ATTR_SCREEN_DPI_RANGE:
328                         *weight += WEIGHT_SCREEN_DPI_RANGE;
329                         break;
330
331                 case NODE_ATTR_SCREEN_WIDTH_RANGE:
332                         *weight += WEIGHT_SCREEN_WIDTH_RANGE;
333                         break;
334
335                 case NODE_ATTR_SCREEN_LARGE:
336                         *weight += WEIGHT_SCREEN_LARGE;
337                         break;
338
339                 case NODE_ATTR_SCREEN_BPP:
340                         *weight += WEIGHT_SCREEN_BPP;
341                         break;
342
343                 case NODE_ATTR_PLATFORM_VER:
344                         *weight += WEIGHT_PLATFORM_VERSION;
345                         break;
346
347                 case NODE_ATTR_LANGUAGE:
348                         *weight += WEIGHT_LANGUAGE;
349                         break;
350         }
351 }
352
353 static const char *__get_cache(aul_resource_e type,
354                 const char *id)
355 {
356         unsigned int total_len = 0;
357         char *key = NULL;
358         char *rsc_type;
359         resource_cache_context_t *resource_cache = NULL;
360
361         if (is_slice == TRUE)
362                 return NULL;
363
364         if (id == NULL) {
365                 LOGE("INVALID_PARAMETER(0x%08x), id",
366                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
367                 return NULL;
368         }
369
370         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
371                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
372                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
373                 return NULL;
374         } else {
375                 switch (type) {
376                         case AUL_RESOURCE_TYPE_IMAGE:
377                                 rsc_type = RSC_GROUP_TYPE_IMAGE;
378                                 break;
379
380                         case AUL_RESOURCE_TYPE_LAYOUT:
381                                 rsc_type = RSC_GROUP_TYPE_LAYOUT;
382                                 break;
383
384                         case AUL_RESOURCE_TYPE_SOUND:
385                                 rsc_type = RSC_GROUP_TYPE_SOUND;
386                                 break;
387
388                         case AUL_RESOURCE_TYPE_BIN:
389                                 rsc_type = RSC_GROUP_TYPE_BIN;
390                                 break;
391                 }
392         }
393
394         if (resource_handle->cache == NULL) {
395                 LOGE("INVALID_PARAMETER(0x%08x), hashtable",
396                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
397                 return NULL;
398         } else {
399                 total_len = strlen(rsc_type) + strlen(id) + 2;
400
401                 key = (char *) calloc(1, total_len);
402                 if (key == NULL) {
403                         LOGE("failed to create a resource_cache(0x%08x)",
404                                         AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
405                         free(resource_cache);
406                         return NULL;
407                 }
408
409                 snprintf(key, total_len, "%s:%s", rsc_type, id);
410                 LOGD("key : %s", key);
411
412                 resource_cache = g_hash_table_lookup(resource_handle->cache, key);
413                 free(key);
414                 if (resource_cache == NULL) {
415                         LOGE("IO_ERROR(0x%08x), find list resource_cache",
416                                         AUL_RESOURCE_ERROR_IO_ERROR);
417                         return NULL;
418                 }
419
420                 resource_cache->hit_cnt++;
421         }
422
423         return resource_cache->output;
424 }
425
426 static gint __cache_hit_compare(gconstpointer a, gconstpointer b)
427 {
428         const resource_cache_context_t *lhs = (const resource_cache_context_t *) a;
429         const resource_cache_context_t *rhs = (const resource_cache_context_t *) b;
430
431         return lhs->hit_cnt - rhs->hit_cnt;
432 }
433
434 static gboolean __cache_remove(gpointer key, gpointer value, gpointer user_data)
435 {
436         resource_cache_context_t *c = (resource_cache_context_t *) (value);
437
438         if (c->remove) {
439                 free(key);
440                 free(c->output);
441                 free(c);
442                 return TRUE;
443         }
444
445         return FALSE;
446 }
447
448 static void __trim_cache(void)
449 {
450         GList *values = g_hash_table_get_values(resource_handle->cache);
451         values = g_list_sort(values, __cache_hit_compare);
452
453         int i = 0;
454         GList *iter_list = values;
455         while (iter_list != NULL) {
456                 if (i >= (THRESHOLD_TO_CLEAN / 2))
457                         break;
458
459                 resource_cache_context_t *c =
460                                 (resource_cache_context_t *) (iter_list->data);
461                 c->remove = true;
462                 iter_list = g_list_next(iter_list);
463                 i++;
464         }
465
466         g_list_free(values);
467         g_hash_table_foreach_remove(resource_handle->cache, __cache_remove, NULL);
468
469 }
470
471 static void __put_cache(aul_resource_e type, const char *id,
472                 const char *val)
473 {
474         unsigned int total_len = 0;
475         char *key;
476         char *rsc_type;
477         resource_cache_context_t *resource_cache;
478
479         if (is_slice == TRUE)
480                 return;
481
482         /* To remove chache from the low frequency of use. */
483         if (val == NULL) {
484                 LOGE("INVALID_PARAMETER(0x%08x), fname",
485                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
486                 return;
487         }
488
489         if (id == NULL) {
490                 LOGE("INVALID_PARAMETER(0x%08x), id",
491                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
492                 return;
493         }
494
495         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
496                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
497                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
498                 return;
499         } else {
500                 switch (type) {
501                         case AUL_RESOURCE_TYPE_IMAGE:
502                                 rsc_type = RSC_GROUP_TYPE_IMAGE;
503                                 break;
504
505                         case AUL_RESOURCE_TYPE_LAYOUT:
506                                 rsc_type = RSC_GROUP_TYPE_LAYOUT;
507                                 break;
508
509                         case AUL_RESOURCE_TYPE_SOUND:
510                                 rsc_type = RSC_GROUP_TYPE_SOUND;
511                                 break;
512
513                         case AUL_RESOURCE_TYPE_BIN:
514                                 rsc_type = RSC_GROUP_TYPE_BIN;
515                                 break;
516                 }
517         }
518
519         if (g_hash_table_size(resource_handle->cache) > THRESHOLD_TO_CLEAN)
520                 __trim_cache();
521
522         resource_cache = (resource_cache_context_t *) calloc(1,
523                         sizeof(resource_cache_context_t));
524         if (resource_cache == NULL) {
525                 LOGE("failed to create a resource_group(0x%08x)",
526                                 AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
527                 return;
528         }
529
530         total_len = strlen(rsc_type) + strlen(id) + 2;
531
532         key = (char *) calloc(1, total_len);
533         if (key == NULL) {
534                 LOGE("failed to create a resource_cache(0x%08x)",
535                                 AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
536                 free(resource_cache);
537                 return;
538         }
539
540         snprintf(key, total_len, "%s:%s", rsc_type, id);
541         LOGD("key : %s", key);
542
543         resource_cache->output = strdup(val);
544         resource_cache->hit_cnt = 0;
545         resource_cache->remove = false;
546
547         g_hash_table_insert(resource_handle->cache, key, resource_cache);
548 }
549
550 static resource_group_t *__find_group(resource_data_t *data,
551                 int type)
552 {
553         resource_group_t *rsc_group = NULL;
554         char *rsc_type;
555
556         if (data == NULL) {
557                 LOGE("INVALID_PARAMETER(0x%08x), resource_data_t",
558                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
559                 return NULL;
560         }
561
562         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
563                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
564                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
565                 return NULL;
566         } else {
567                 switch (type) {
568                         case AUL_RESOURCE_TYPE_IMAGE:
569                                 rsc_type = RSC_GROUP_TYPE_IMAGE;
570                                 break;
571
572                         case AUL_RESOURCE_TYPE_LAYOUT:
573                                 rsc_type = RSC_GROUP_TYPE_LAYOUT;
574                                 break;
575
576                         case AUL_RESOURCE_TYPE_SOUND:
577                                 rsc_type = RSC_GROUP_TYPE_SOUND;
578                                 break;
579
580                         case AUL_RESOURCE_TYPE_BIN:
581                                 rsc_type = RSC_GROUP_TYPE_BIN;
582                                 break;
583                 }
584         }
585
586         GList* found = g_list_find_custom(data->group_list, rsc_type,
587                         __resource_manager_comp);
588         if (found == NULL) {
589                 LOGE("IO_ERROR(0x%08x), find list resource_group %s",
590                                 AUL_RESOURCE_ERROR_IO_ERROR, rsc_type);
591                 return NULL;
592         }
593
594         rsc_group = (resource_group_t *) (found->data);
595
596         return rsc_group;
597 }
598
599 static GList *__get_valid_nodes(resource_group_t *group,
600                 const char *id)
601 {
602         GList *list = NULL;
603         GList *valid_list = NULL;
604         resource_node_t *valid_node = NULL;
605         resource_node_t *rsc_node = NULL;
606
607         if (group->node_list == NULL) {
608                 LOGE("INVALID_PARAMETER(0x%08x), resource_group",
609                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
610                 return NULL;
611         }
612
613         list = g_list_first(group->node_list);
614
615         char path_buf[MAX_PATH] = { 0, };
616         while (list) {
617                 bool invalid = false;
618                 rsc_node = (resource_node_t *) list->data;
619
620                 snprintf(path_buf, MAX_PATH - 1, "%s%s/%s", res_path,
621                                 rsc_node->folder, id);
622                 if (access(path_buf, R_OK) == 0) {
623                         bundle_foreach(rsc_node->attr, __bundle_iterator_get_valid_nodes,
624                                         &invalid);
625
626                         if (!invalid) {
627                                 valid_node = (resource_node_t *) list->data;
628                                 valid_list = g_list_append(valid_list, valid_node);
629                         }
630                 }
631
632                 list = g_list_next(list);
633         }
634
635         return valid_list;
636 }
637
638 static resource_node_t *__get_best_node(GList *nodes)
639 {
640         unsigned int weight_tmp = 0;
641         resource_node_t *best_node = NULL;
642         GList *list = NULL;
643
644         if (nodes == NULL) {
645                 LOGE("INVALID_PARAMETER(0x%08x), resource_node lists",
646                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
647                 return NULL;
648         }
649
650         list = g_list_first(nodes);
651
652         while (list != NULL) {
653                 unsigned int weight = 0;
654                 resource_node_t *res_node = (resource_node_t *) (list->data);
655
656                 bundle_iterate(res_node->attr, __bundle_iterator_get_best_node, &weight);
657                 if (weight > weight_tmp) {
658                         best_node = res_node;
659                         weight_tmp = weight;
660                 }
661                 list = g_list_next(list);
662         }
663
664         return best_node;
665 }
666
667 static int __open(resource_manager_t **handle)
668 {
669         int retval = AUL_RESOURCE_ERROR_NONE;
670         resource_manager_t *rsc_manager = NULL;
671         char buf[MAX_PATH] = { 0, };
672
673         rsc_manager = (resource_manager_t *) calloc(1, sizeof(resource_manager_t));
674         if (!rsc_manager) {
675                 LOGE("failed to create a resource_manager(0x%08x)",
676                                 AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
677                 return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
678         }
679
680         snprintf(buf, MAX_PATH - 1, "%sres.xml", res_path);
681         retval = pkgmgrinfo_resource_open(buf, &(rsc_manager->data));
682         if (retval != PMINFO_R_OK) {
683                 LOGE("IO_ERROR(0x%08x), failed to get db for resource manager",
684                                 AUL_RESOURCE_ERROR_IO_ERROR);
685                 free(rsc_manager);
686                 return AUL_RESOURCE_ERROR_IO_ERROR;
687         }
688
689         rsc_manager->cache = g_hash_table_new(g_str_hash, g_str_equal);
690         *handle = rsc_manager;
691
692         return AUL_RESOURCE_ERROR_NONE;
693 }
694
695 static void __invalidate_cache()
696 {
697         if (resource_handle != NULL) {
698                 if (resource_handle->cache != NULL) {
699                         GHashTableIter iter;
700                         gpointer key, value;
701
702                         g_hash_table_iter_init(&iter, resource_handle->cache);
703                         while (g_hash_table_iter_next(&iter, &key, &value)) {
704                                 free(key);
705                                 resource_cache_context_t *c = (resource_cache_context_t *) value;
706                                 free(c->output);
707                                 free(value);
708                         }
709                         g_hash_table_remove_all(resource_handle->cache);
710                         if (cur_language) {
711                                 free(cur_language);
712                                 cur_language = NULL;
713                         }
714                 }
715         }
716 }
717
718 static int __close(resource_manager_t *handle)
719 {
720         if (handle == NULL) {
721                 LOGE("INVALID_PARAMETER(0x%08x), resource_manager",
722                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
723                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
724         }
725
726         __invalidate_cache();
727         if (handle->cache != NULL) {
728                 g_hash_table_destroy(handle->cache);
729         }
730
731         if (handle->data != NULL) {
732                 pkgmgrinfo_resource_close(handle->data);
733         }
734
735         free(handle);
736
737         return AUL_RESOURCE_ERROR_NONE;
738 }
739
740 static void __vconf_cb(keynode_t *key, void *data)
741 {
742         __invalidate_cache();
743 }
744
745 static const char *_get_app_resource_path(const char *rsc_folder_path)
746 {
747         if (is_slice == FALSE)
748                 return aul_get_app_resource_path();
749
750         if (rsc_folder_path == NULL)
751                 return NULL;
752
753         return rsc_folder_path;
754 }
755
756 static void path_callback(char *path)
757 {
758         char orig_path[MAX_PATH] = {0, };
759         char *path_ptr = NULL;
760         int path_len = 0;
761         GList *tmp_list = g_list_find_custom(all_node_list, path, __compare_path);
762
763         resource_node_list_t *tmp_node_info = NULL;
764         if (tmp_list == NULL)
765                 g_hash_table_add(valid_path_list, strdup(path));
766         else {
767                 tmp_node_info = (resource_node_list_t *)tmp_list->data;
768                 path_len = strlen(path);
769                 if (path_len >= MAX_PATH) {
770                         LOGE("path[%s] is too long", path);
771                         return;
772                 }
773                 strncpy(orig_path, path, path_len);
774                 path_ptr = &orig_path[strlen(res_path) + strlen(tmp_node_info->folder)];
775                 g_hash_table_insert(id_list, strdup(path_ptr), strdup(tmp_node_info->type));
776         }
777 }
778
779 static void __scan_dir(const char *path, void (*func)(char *))
780 {
781         struct dirent **items;
782         int nitems, i;
783         struct stat fstat;
784         char abs_path[MAX_PATH] = {0, };
785         char cwd[MAX_PATH] = {0, };
786         char *tmp = NULL;
787
788         if (chdir(path) < 0) {
789                 LOGE("failed to chdir[%s]", path);
790                 return;
791         }
792
793         tmp = getcwd(cwd, MAX_PATH - 1);
794         if (tmp == NULL) {
795                 LOGE("failed to get cwd");
796                 return;
797         }
798         nitems = scandir("./", &items, NULL, alphasort);
799
800         for (i = 0; i < nitems; i++) {
801                 if (items[i]->d_name[0] == '.')
802                         continue;
803
804                 snprintf(abs_path, MAX_PATH - 1, "%s/%s", cwd, items[i]->d_name);
805
806                 if (g_lstat(abs_path, &fstat) != 0) {
807                         LOGE("failed to retrieve info[%s]", abs_path);
808                         return;
809                 }
810                 if ((fstat.st_mode & S_IFDIR) == S_IFDIR)
811                         __scan_dir(abs_path, path_callback);
812                 else
813                         func(abs_path);
814         }
815
816 }
817
818 static aul_resource_e __get_resource_type(char *type)
819 {
820         if (type == NULL)
821                 return -1;
822
823         if (strcmp(type, RSC_GROUP_TYPE_IMAGE) == 0)
824                 return AUL_RESOURCE_TYPE_IMAGE;
825         else if(strcmp(type, RSC_GROUP_TYPE_LAYOUT) == 0)
826                 return AUL_RESOURCE_TYPE_LAYOUT;
827         else if(strcmp(type, RSC_GROUP_TYPE_SOUND) == 0)
828                 return AUL_RESOURCE_TYPE_SOUND;
829         else if(strcmp(type, RSC_GROUP_TYPE_BIN) == 0)
830                 return AUL_RESOURCE_TYPE_BIN;
831         else
832                 return -1;
833 }
834
835 static int __set_valid_filelist(bundle *b)
836 {
837         if (b == NULL || supported_lang_list == NULL) {
838                 LOGE("INVALID_PARAMETER(0x%08x), bundle",
839                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
840                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
841         }
842
843         int retval = AUL_RESOURCE_ERROR_NONE;
844         char *path = NULL;
845         GHashTableIter id_list_iter;
846         GHashTableIter lang_list_iter;
847         gpointer id_key, lang_key, id_type;
848         aul_resource_e rsc_type = AUL_RESOURCE_TYPE_MIN;
849
850         given_attr_list = b;
851         g_hash_table_iter_init(&id_list_iter, id_list);
852
853         while (g_hash_table_iter_next(&id_list_iter, &id_key, &id_type)) {
854                 rsc_type = __get_resource_type((char *)id_type);
855                 if (rsc_type == -1) {
856                         LOGE("failed to get resource type[%s]", (char *)id_type);
857                         return AUL_RESOURCE_ERROR_IO_ERROR;
858                 }
859
860                 g_hash_table_iter_init(&lang_list_iter, supported_lang_list);
861                 while (g_hash_table_iter_next(&lang_list_iter, &lang_key, NULL)) {
862                         cur_language = strdup(lang_key);
863                         if (cur_language == NULL) {
864                                 LOGE("failed to strdup");
865                                 return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
866                         }
867
868                         retval = aul_resource_manager_get(rsc_type, id_key, &path);
869                         if (retval == AUL_RESOURCE_ERROR_NONE)
870                                 g_hash_table_add(valid_path_list, path);
871                         else
872                                 LOGE("failed to get value with given type[%d], key[%s]", rsc_type, id_key);
873
874                         if (cur_language) {
875                                 free(cur_language);
876                                 cur_language = NULL;
877                         }
878                 }
879         }
880         return AUL_RESOURCE_ERROR_NONE;
881 }
882
883 static int __make_list(void)
884 {
885         resource_group_t *tmp_group = NULL;
886         resource_node_t  *tmp_node = NULL;
887         resource_node_list_t *tmp_node_struct = NULL;
888         char *group_type = NULL;
889         char folder[MAX_PATH] = {0 ,};
890         char *node_lang = NULL;
891         GList *group_list = NULL;
892         GList *node_list = NULL;
893         bundle *b = NULL;
894
895
896         /* make node folder list */
897         group_list = resource_handle->data->group_list;
898         if (group_list == NULL)
899                 return AUL_RESOURCE_ERROR_IO_ERROR;
900
901         while (group_list != NULL) {
902                 tmp_group = (resource_group_t *)group_list->data;
903                 if (tmp_group == NULL)
904                         return AUL_RESOURCE_ERROR_IO_ERROR;
905
906                 group_type = tmp_group->type;
907                 node_list = tmp_group->node_list;
908                 memset(folder, '\0', MAX_PATH);
909                 snprintf(folder, MAX_PATH - 1, "%s/",tmp_group->folder);
910
911                 /*make struct and put it into all node list*/
912                 tmp_node_struct = (resource_node_list_t *)calloc(1, sizeof(resource_node_list_t));
913                 if (tmp_node_struct == NULL) {
914                         LOGE("calloc failed");
915                         return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
916                 }
917
918                 tmp_node_struct->folder = strdup(folder);
919                 tmp_node_struct->type = strdup(group_type);
920                 all_node_list = g_list_append(all_node_list, tmp_node_struct);
921
922                 while (node_list != NULL) {
923                         tmp_node = (resource_node_t *)node_list->data;
924                         if (tmp_node == NULL)
925                                 return AUL_RESOURCE_ERROR_IO_ERROR;
926
927                         /*retrieve language value from each node*/
928                         b = tmp_node->attr;
929                         if (b == NULL)
930                                 return AUL_RESOURCE_ERROR_IO_ERROR;
931                         bundle_get_str(b, RSC_NODE_ATTR_LANGUAGE, &node_lang);
932                         if (node_lang != NULL)
933                                 g_hash_table_add(supported_lang_list, strdup(node_lang));
934
935                         memset(folder, '\0', MAX_PATH);
936                         snprintf(folder, MAX_PATH - 1, "%s/",tmp_node->folder);
937
938                         /*make struct and put it into all node list*/
939                         tmp_node_struct = (resource_node_list_t *)calloc(1, sizeof(resource_node_list_t));
940                         if (tmp_node_struct == NULL) {
941                                 LOGE("calloc failed");
942                                 return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
943                         }
944
945                         tmp_node_struct->folder = strdup(folder);
946                         tmp_node_struct->type = strdup(group_type);
947                         all_node_list = g_list_prepend(all_node_list, tmp_node_struct);
948
949                         node_list = g_list_next(node_list);
950                 }
951                 group_list = g_list_next(group_list);
952         }
953
954         __scan_dir(res_path, path_callback);
955
956         /* add language which is not existed to find default resources */
957         g_hash_table_add(supported_lang_list, strdup("NoLang"));
958         return AUL_RESOURCE_ERROR_NONE;
959 }
960
961 static void __free_str(gpointer data)
962 {
963         if (data == NULL)
964                 return;
965
966         char *char_data = (char *)data;
967         free(char_data);
968         data = NULL;
969 }
970
971 static int __init(const char *rsc_folder_path, bundle *b)
972 {
973         if (rsc_folder_path != NULL && b != NULL)
974                 is_slice = TRUE;
975         else
976                 is_slice = FALSE;
977
978         if (resource_handle != NULL)
979                 return AUL_RESOURCE_ERROR_NONE;
980
981         int retval = AUL_RESOURCE_ERROR_NONE;
982
983         res_path = _get_app_resource_path(rsc_folder_path);
984         if (res_path == NULL) {
985                 LOGE("IO_ERROR(0x%08x), failed to get resource path",
986                                 AUL_RESOURCE_ERROR_IO_ERROR);
987                 return AUL_RESOURCE_ERROR_IO_ERROR;
988         }
989
990         retval = __open(&resource_handle);
991         if (retval != AUL_RESOURCE_ERROR_NONE) {
992                 LOGE("IO_ERROR(0x%08x), failed to get resource_handle(%d)",
993                                 AUL_RESOURCE_ERROR_IO_ERROR, retval);
994                 return AUL_RESOURCE_ERROR_IO_ERROR;
995         }
996
997         if (attr_key == NULL) {
998                 attr_key = g_hash_table_new(g_str_hash, g_str_equal);
999
1000                 if (attr_key == NULL)
1001                         return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
1002
1003                 unsigned int i;
1004                 for (i = 0; i < ARRAY_SIZE(map); i++) {
1005                         g_hash_table_insert(attr_key, (char *) map[i].bundle_attr_key,
1006                                         (gpointer) (map[i].bundle_attr_value));
1007                 }
1008         }
1009
1010         if (is_slice == FALSE) {
1011                 int r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, NULL);
1012
1013                 if (r < 0) {
1014                         LOGE("IO_ERROR(0x%08x), failed to register vconf(%d)",
1015                                         AUL_RESOURCE_ERROR_IO_ERROR, r);
1016                         return AUL_RESOURCE_ERROR_IO_ERROR;
1017                 }
1018         } else {
1019                 /* make ID list */
1020                 if (id_list == NULL)
1021                         id_list = g_hash_table_new_full(g_str_hash, g_str_equal, __free_str, __free_str);
1022
1023                 if (supported_lang_list == NULL)
1024                         supported_lang_list = g_hash_table_new_full(g_str_hash, g_str_equal, __free_str, NULL);
1025
1026                 if (valid_path_list == NULL)
1027                         valid_path_list = g_hash_table_new_full(g_str_hash, g_str_equal, __free_str, NULL);
1028
1029                 retval = __make_list();
1030                 if (retval < 0) {
1031                         LOGE("Failed to initialize filelist");
1032                         return AUL_RESOURCE_ERROR_IO_ERROR;
1033                 }
1034
1035                 retval = __set_valid_filelist(b);
1036                 if (retval < 0) {
1037                         LOGE("Failed to get valid filelist");
1038                         return AUL_RESOURCE_ERROR_IO_ERROR;
1039                 }
1040
1041         }
1042
1043         return AUL_RESOURCE_ERROR_NONE;
1044 }
1045
1046 SLPAPI int aul_resource_manager_init(void)
1047 {
1048         return __init(NULL, NULL);
1049 }
1050
1051 SLPAPI int aul_resource_manager_init_slice(const char *rsc_folder_path, bundle *b)
1052 {
1053         if (rsc_folder_path == NULL || b == NULL)
1054                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
1055
1056         return __init(rsc_folder_path, b);
1057 }
1058
1059
1060 SLPAPI int aul_resource_manager_get_path_list(GHashTable **list)
1061 {
1062         if (is_slice == FALSE)
1063                 return AUL_RESOURCE_ERROR_IO_ERROR;
1064
1065         if (valid_path_list != NULL)
1066                 *list = valid_path_list;
1067         else
1068                 return AUL_RESOURCE_ERROR_IO_ERROR;
1069
1070         return AUL_RESOURCE_ERROR_NONE;
1071 }
1072
1073 SLPAPI int aul_resource_manager_get(aul_resource_e type, const char *id, char **path)
1074 {
1075         int retval = AUL_RESOURCE_ERROR_NONE;
1076         char *put_fname = NULL;
1077         const char *cached_path = NULL;
1078         GList *list = NULL;
1079         resource_group_t *resource_group = NULL;
1080         resource_node_t *resource_node = NULL;
1081
1082         *path = NULL;
1083
1084         if (id == NULL) {
1085                 LOGE("INVALID_PARAMETER(0x%08x), resource_data_t",
1086                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
1087                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
1088         }
1089
1090         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
1091                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
1092                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
1093                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
1094         }
1095
1096         if (is_slice == FALSE) {
1097                 if (resource_handle == NULL) {
1098                         retval = aul_resource_manager_init();
1099                         if (retval != AUL_RESOURCE_ERROR_NONE)
1100                                 return retval;
1101                 }
1102
1103                 /* To get fname from cache */
1104                 cached_path = __get_cache(type, id);
1105                 if (cached_path != NULL) {
1106                         *path = strdup(cached_path);
1107                         return AUL_RESOURCE_ERROR_NONE;
1108                 }
1109         }
1110
1111         if (resource_handle == NULL)
1112                 return AUL_RESOURCE_ERROR_IO_ERROR;
1113
1114         resource_group = __find_group(resource_handle->data, type);
1115         if (resource_group == NULL) {
1116                 LOGE("IO_ERROR(0x%08x), failed to get resource_group",
1117                                 AUL_RESOURCE_ERROR_IO_ERROR);
1118                 retval = AUL_RESOURCE_ERROR_IO_ERROR;
1119                 goto Exception;
1120         }
1121
1122         list = __get_valid_nodes(resource_group, id);
1123         if (list == NULL) {
1124                 retval = AUL_RESOURCE_ERROR_IO_ERROR;
1125                 goto Exception;
1126         }
1127
1128         resource_node = __get_best_node(list);
1129         if (resource_node == NULL) {
1130                 retval = AUL_RESOURCE_ERROR_IO_ERROR;
1131                 goto Exception;
1132         } else {
1133                 unsigned int total_len = strlen(res_path)
1134                                 + strlen(resource_node->folder) + strlen(id) + 3;
1135                 put_fname = (char *) calloc(1, total_len);
1136                 if (!put_fname) {
1137                         if (list != NULL)
1138                                 g_list_free(list);
1139                         return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
1140                 }
1141                 snprintf(put_fname, total_len, "%s%s/%s", res_path,
1142                                 resource_node->folder, id);
1143                 *path = strdup(put_fname);
1144         }
1145
1146         __put_cache(type, id, put_fname);
1147
1148
1149 Exception:
1150         if (list != NULL)
1151                 g_list_free(list);
1152
1153         if (put_fname == NULL && resource_group != NULL) {
1154                 char path_buf[MAX_PATH] = { 0, };
1155                 char group_path_buf[MAX_PATH] = { 0, };
1156
1157                 snprintf(path_buf, MAX_PATH - 1, "%s%s/%s", res_path,
1158                                 resource_group->folder, id);
1159                 snprintf(group_path_buf, MAX_PATH - 1, "%s/%s", resource_group->folder, id);
1160
1161                 list = g_list_first(resource_group->node_list);
1162                 while (list) {
1163                         resource_node = (resource_node_t *) list->data;
1164                         if (strncmp(group_path_buf, resource_node->folder, strlen(resource_node->folder)) == 0) {
1165                                 *path = NULL;
1166                                 return AUL_RESOURCE_ERROR_IO_ERROR;
1167                         }
1168                         list = g_list_next(list);
1169                 }
1170
1171                 if (access(path_buf, R_OK) == 0) {
1172                         __put_cache(type, id, path_buf);
1173                         *path = strdup(path_buf);
1174                         retval = AUL_RESOURCE_ERROR_NONE;
1175                 }
1176         }
1177
1178         if (put_fname != NULL)
1179                 free(put_fname);
1180
1181         return retval;
1182 }
1183
1184 static void __free_node_folder_list(gpointer data)
1185 {
1186         resource_node_list_t *node_data = (resource_node_list_t *)data;
1187         if (node_data == NULL)
1188                 return;
1189
1190         if (node_data->folder != NULL) {
1191                 free(node_data->folder);
1192                 node_data->folder = NULL;
1193         }
1194
1195         if (node_data->type != NULL) {
1196                 free(node_data->type);
1197                 node_data->type = NULL;
1198         }
1199
1200         free(node_data);
1201 }
1202
1203 SLPAPI int aul_resource_manager_release(void)
1204 {
1205         if (resource_handle != NULL) {
1206                 __close(resource_handle);
1207                 resource_handle = NULL;
1208         }
1209
1210         if (attr_key != NULL) {
1211                 g_hash_table_destroy(attr_key);
1212                 attr_key = NULL;
1213         }
1214
1215         if (cur_language) {
1216                 free(cur_language);
1217                 cur_language = NULL;
1218         }
1219
1220         if (is_slice == FALSE)
1221                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
1222         else {
1223                 if (valid_path_list != NULL) {
1224                         g_hash_table_destroy(valid_path_list);
1225                         valid_path_list = NULL;
1226                 }
1227
1228                 if (supported_lang_list != NULL) {
1229                         g_hash_table_destroy(supported_lang_list);
1230                         supported_lang_list = NULL;
1231                 }
1232
1233                 if (id_list != NULL) {
1234                         g_hash_table_destroy(id_list);
1235                         id_list = NULL;
1236                 }
1237
1238                 if (all_node_list != NULL) {
1239                         g_list_free_full(all_node_list, __free_node_folder_list);
1240                         all_node_list = NULL;
1241                 }
1242         }
1243         return AUL_RESOURCE_ERROR_NONE;
1244 }