halapi: Replace destructor with reference count method to free memory
[platform/hal/api/common.git] / src / hal-api-conf.c
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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 #include <stdlib.h>
18
19 #include <gio/gio.h>
20 #include <glib-object.h>
21 #include <json-glib/json-glib.h>
22
23 #include "hal-common.h"
24 #include "hal-common-interface.h"
25
26 #include "hal-api-conf.h"
27
28 #include "common.h"
29
30 static enum hal_abi_version _platform_abi_version = HAL_ABI_VERSION_END;
31
32 static JsonParser *_parser = NULL;
33 static JsonObject *_root_object = NULL;
34
35 static GHashTable *_module_hash = NULL;
36
37 static int _usage_count = 0;
38
39 static enum hal_abi_version __convert_abi_version_str_to_enum(const char *abi_version) {
40         int version;
41         for (version = HAL_ABI_VERSION_UNKNOWN + 1; version < HAL_ABI_VERSION_END; version++){
42                 if (g_strcmp0(abi_version, hal_abi_version_str[version]) == 0)
43                         return (enum hal_abi_version)version;
44         }
45
46         return HAL_ABI_VERSION_UNKNOWN;
47 }
48
49 static const char *__convert_module_to_string(enum hal_module module)
50 {
51         return hal_module_string[module];
52 }
53
54 static enum hal_group __convert_group_str_to_enum(const char * group)
55 {
56         enum hal_group group_idx;
57
58         for (group_idx = HAL_GROUP_UNKNOWN + 1; group_idx < HAL_GROUP_END; group_idx++) {
59                 if (g_strcmp0(group, hal_group_string[group_idx]) == 0)
60                         return group_idx;
61         }
62
63         return HAL_GROUP_UNKNOWN;
64 }
65
66 static enum hal_license __convert_license_str_to_enum(const char *license)
67 {
68         if (g_strcmp0(license, "APACHE_2_0") == 0)
69                 return HAL_LICENSE_APACHE_2_0;
70
71         if (g_strcmp0(license, "FLORA") == 0)
72                 return HAL_LICENSE_FLORA;
73
74         if (g_strcmp0(license, "MIT") == 0)
75                 return HAL_LICENSE_MIT;
76
77         return HAL_LICENSE_UNKNOWN;
78 }
79
80 __attribute__ ((visibility("default")))
81 void _destroy_module_info(gpointer data)
82 {
83 #define SAFE_FREE_AND_NULL(x) \
84 do { \
85         if (x) { \
86                 free(x); \
87                 x = NULL; \
88         } \
89 } while (0);
90
91         struct __hal_module_info *info = (struct __hal_module_info *)data;
92         gboolean is_contained = false;
93
94         if (info) {
95                 is_contained = g_hash_table_contains(_module_hash, GINT_TO_POINTER(info->module));
96                 if (is_contained)
97                         g_hash_table_steal(_module_hash, GINT_TO_POINTER(info->module));
98
99                 SAFE_FREE_AND_NULL(info->module_name);
100                 SAFE_FREE_AND_NULL(info->library_name);
101                 SAFE_FREE_AND_NULL(info->library_name_64bit);
102                 SAFE_FREE_AND_NULL(info->symbol_name);
103                 SAFE_FREE_AND_NULL(info->abi_versions);
104                 SAFE_FREE_AND_NULL(info);
105         }
106 }
107
108 static struct __hal_module_info *__create_hal_module_info(enum hal_module module, JsonObject *object)
109 {
110         struct __hal_module_info *info;
111         JsonArray *abi_versions_array = NULL;
112         GList *abi_list = NULL;
113         GList *iter_list = NULL;
114         int list_index = 0;
115         const char *tmp;
116
117         info = (struct __hal_module_info *)calloc(1, sizeof(struct __hal_module_info));
118         if (info == NULL) {
119                 _E("Out of Memory\n");
120                 return NULL;
121         }
122
123         info->module = module;
124         info->module_name = g_strdup(__convert_module_to_string(module));
125
126         tmp = json_object_get_string_member(object, "group");
127         info->group = __convert_group_str_to_enum(tmp);
128
129         tmp = json_object_get_string_member(object, "license");
130         info->license = __convert_license_str_to_enum(tmp);
131
132         info->library_name = g_strdup(json_object_get_string_member(object, "library_name"));
133         info->library_name_64bit = g_strdup(json_object_get_string_member(object, "library_name_64bit"));
134         info->symbol_name = g_strdup(json_object_get_string_member(object, "symbol_name"));
135
136         if (info->library_name && info->library_name_64bit && info->symbol_name)
137                 info->hal_api = true;
138
139         abi_versions_array = json_object_get_array_member(object, "abi_versions");
140         if (abi_versions_array == NULL)
141                 return info;
142
143         abi_list = json_array_get_elements(abi_versions_array);
144         info->num_abi_versions = g_list_length(abi_list);
145         if (info->num_abi_versions > 0) {
146                 info->abi_versions = (struct hal_abi_version_match*)calloc(info->num_abi_versions,
147                                 sizeof(struct hal_abi_version_match));
148                 if (info->abi_versions == NULL) {
149                         _E("Out of Memory\n");
150                         _destroy_module_info(info);
151                         g_list_free(abi_list);
152                         return NULL;
153                 }
154
155                 for (iter_list = abi_list; iter_list != NULL; iter_list = iter_list->next) {
156                         JsonObject *tmp_object = json_node_get_object(iter_list->data);
157
158                         tmp = json_object_get_string_member(tmp_object, "platform_abi_version");
159                         info->abi_versions[list_index].platform_abi_version =
160                                 __convert_abi_version_str_to_enum(tmp);
161
162                         tmp = json_object_get_string_member(tmp_object, "backend_min_abi_version");
163                         info->abi_versions[list_index].backend_min_abi_version =
164                                 __convert_abi_version_str_to_enum(tmp);
165                         list_index++;
166                 }
167         }
168
169         if (abi_list)
170                 g_list_free(abi_list);
171
172         return info;
173 }
174
175 __attribute__ ((visibility("default")))
176 struct __hal_module_info* _hal_api_conf_get_module_info(enum hal_module module)
177 {
178         struct __hal_module_info *info = NULL;
179         JsonArray *module_array = NULL;
180         GList *module_list = NULL;
181         GList *iter_list;
182         const char *group_name = NULL;
183         const char *module_name = NULL;
184
185         if (!_root_object || !_module_hash)
186                 return NULL;
187
188         info = (struct __hal_module_info*)g_hash_table_lookup(_module_hash, GINT_TO_POINTER(module));
189         if (info != NULL)
190                 return info;
191
192         module_array = json_object_get_array_member(_root_object, "MODULE_INFO");
193         module_list = json_array_get_elements(module_array);
194         module_name = __convert_module_to_string(module);
195
196         for (iter_list = module_list; iter_list != NULL; iter_list = iter_list->next) {
197                 JsonObject *tmp_object = json_node_get_object(iter_list->data);
198                 const char *value = json_object_get_string_member(tmp_object, "module");
199                 if (g_strcmp0(value, module_name) == 0) {
200                         info = __create_hal_module_info(module, tmp_object);
201                         if (info == NULL)
202                                 _E("Failed to create hal module info\n");
203                         else
204                                 g_hash_table_insert(_module_hash, GINT_TO_POINTER(module), info);
205                         break;
206                 }
207         }
208
209 ret:
210         if (module_list)
211                 g_list_free(module_list);
212
213         return info;
214 }
215
216 enum hal_abi_version _hal_api_conf_get_platform_abi_version(void)
217 {
218         const char *abi_version = NULL;
219         bool ret_initialized;
220
221         if (_platform_abi_version != HAL_ABI_VERSION_END)
222                 return _platform_abi_version;
223
224         if (!_root_object || !_module_hash)
225                 return HAL_ABI_VERSION_UNKNOWN;
226
227         abi_version = json_object_get_string_member(_root_object, "PLATFORM_ABI_VERSION");
228         _platform_abi_version = __convert_abi_version_str_to_enum(abi_version);
229
230         return _platform_abi_version;
231 }
232
233 __attribute__ ((visibility("default")))
234 int _hal_api_conf_init(void)
235 {
236         JsonNode *root_node = NULL;
237         GError *error = NULL;
238         gboolean result;
239
240         if (_usage_count++ > 0)
241                 return 0;
242
243         _parser = json_parser_new();
244         result = json_parser_load_from_file(_parser, HAL_CONFIGURATION_PATH, &error);
245         if (result == FALSE) {
246                 _E("Failed to parsing json configuration file : %s\n", error->message);
247                 goto err;
248         }
249
250         root_node = json_parser_get_root(_parser);
251         if (JSON_NODE_HOLDS_OBJECT(root_node) == FALSE) {
252                 _E("There is no object in root node\n");
253                 goto err;
254         }
255
256         _root_object = json_node_get_object(root_node);
257         _module_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, _destroy_module_info);
258
259         return 0;
260
261 err:
262         _usage_count--;
263
264         if (error)
265                 g_error_free(error);
266         if (_parser)
267                 g_object_unref(_parser);
268
269         if (_module_hash) {
270                 g_hash_table_remove_all(_module_hash);
271                 g_hash_table_unref(_module_hash);
272         }
273
274         return -EINVAL;
275 }
276
277 __attribute__ ((visibility("default")))
278 void _hal_api_conf_exit(void)
279 {
280         _usage_count--;
281         if (_usage_count != 0)
282                 return;
283
284         if (_parser)
285                 g_object_unref(_parser);
286
287         if (_module_hash) {
288                 g_hash_table_remove_all(_module_hash);
289                 g_hash_table_unref(_module_hash);
290         }
291 }