halapi: Add new get_backend and put_backend with specific library name
[platform/hal/api/common.git] / src / hal-api-common.c
1 /*
2  * HAL Common API
3  *
4  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <dlfcn.h>
23 #include <dlog.h>
24
25 #include <glib-object.h>
26
27 #include "common.h"
28 #include "hal-api-conf.h"
29
30 #ifndef EXPORT
31 #define EXPORT __attribute__ ((visibility("default")))
32 #endif
33
34 static enum hal_abi_version g_platform_curr_abi_version;
35 G_LOCK_DEFINE_STATIC(hal_common_lock);
36
37 EXPORT
38 int hal_common_get_backend_library_name(enum hal_module module, char *name, int size)
39 {
40         const char *library_name = NULL;
41         struct __hal_module_info *info = NULL;
42         int ret;
43         int len_library_name;
44
45         /* Check parameter whether is valid or not */
46         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
47                 _E("Invalid parameter of HAL module (%d)\n", module);
48                 return TIZEN_ERROR_INVALID_PARAMETER;
49         }
50
51         if (_hal_api_conf_init())
52                 return TIZEN_ERROR_UNKNOWN;
53
54         info = _hal_api_conf_get_module_info(module, NULL);
55         if (info == NULL) {
56                 _E("Failed to get HAL module(%d) information\n", module);
57                 ret = TIZEN_ERROR_UNKNOWN;
58                 goto out;
59         }
60
61         library_name = get_backend_library_name(info);
62         if (!library_name) {
63                 _E("%s backend library name is NULL\n", info->module_name);
64                 ret = TIZEN_ERROR_NONE;
65                 goto out;
66         }
67
68         len_library_name = strlen(library_name);
69         if (!name || (len_library_name + 1 > size)) {
70                 ret = TIZEN_ERROR_UNKNOWN;
71                 name = NULL;
72                 goto out;
73         }
74         strncpy(name, library_name, len_library_name);
75         name[len_library_name] = '\0';
76
77         ret = TIZEN_ERROR_NONE;
78 out:
79         _hal_api_conf_exit();
80
81         return ret;
82 }
83
84 EXPORT
85 int hal_common_get_backend_symbol_name(enum hal_module module, char *name, int size)
86 {
87         struct __hal_module_info *info = NULL;
88         char *symbol_name = NULL;
89         int ret;
90         int len_symbol_name;
91
92         /* Check parameter whether is valid or not */
93         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
94                 _E("Invalid paramer of HAL module (%d)\n", module);
95                 return TIZEN_ERROR_INVALID_PARAMETER;
96         }
97
98         if (_hal_api_conf_init())
99                 return TIZEN_ERROR_UNKNOWN;
100
101         info = _hal_api_conf_get_module_info(module, NULL);
102         if (info == NULL) {
103                 _E("Failed to get HAL module(%d) information\n", module);
104                 ret = TIZEN_ERROR_UNKNOWN;
105                 goto out;
106         }
107         symbol_name = info->symbol_name;
108         if (!symbol_name) {
109                 _E("%s backend symbol name is NULL\n", info->module_name);
110                 ret = TIZEN_ERROR_NONE;
111                 goto out;
112         }
113
114         len_symbol_name = strlen(symbol_name);
115         if (!name || (len_symbol_name + 1 > size)) {
116                 ret = TIZEN_ERROR_UNKNOWN;
117                 name = NULL;
118                 goto out;
119         }
120         strncpy(name, symbol_name, len_symbol_name);
121         name[len_symbol_name] = '\0';
122
123         ret = TIZEN_ERROR_NONE;
124 out:
125         _hal_api_conf_exit();
126
127         return ret;
128 }
129
130 static int __get_backend(enum hal_module module, void **data, const char *library_name)
131 {
132         struct __hal_module_info *info = NULL;
133         void *handle = NULL;
134         hal_backend *backend;
135         const char *symbol_name;
136         const char *backend_library_name;
137         int ret = 0;
138
139         /* Check parameter whether is valid or not */
140         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
141                 _E("Invalid parameter of HAL module (%d)\n", module);
142                 return TIZEN_ERROR_INVALID_PARAMETER;
143         }
144
145         G_LOCK(hal_common_lock);
146
147         if (_hal_api_conf_init()) {
148                 ret = TIZEN_ERROR_UNKNOWN;
149                 goto err;
150         }
151
152         info = _hal_api_conf_get_module_info(module, library_name);
153         if (info == NULL) {
154                 if (!library_name)
155                         _E("Failed to get HAL module(%d) information\n", module);
156                 else
157                         _E("Failed to get HAL module(%d) information (%s)\n",
158                                 module, library_name);
159                 ret = TIZEN_ERROR_UNKNOWN;
160                 goto err;
161         }
162
163         if (info->usage_count == 0) {
164                 /*
165                  * Load HAL backend library at first loading time
166                  * when usage_count is 0.
167                  */
168                 backend_library_name = get_backend_library_name(info);
169                 if (!backend_library_name) {
170                         _E("%s: Failed to get backend library name\n",
171                                         info->module_name);
172                         ret = TIZEN_ERROR_INVALID_PARAMETER;
173                         goto err;
174                 }
175
176                 ret = access(backend_library_name, F_OK);
177                 if (ret < 0) {
178                         _E("%s: Failed to find backend library (%s)\n",
179                                         info->module_name, backend_library_name);
180                         ret = TIZEN_ERROR_INVALID_PARAMETER;
181                         goto err;
182                 }
183
184                 handle = dlopen(backend_library_name, RTLD_LAZY);
185                 if (!handle) {
186                         _E("%s: Failed to load backend library (%s)\n",
187                                         info->module_name, dlerror());
188                         ret = TIZEN_ERROR_INVALID_PARAMETER;
189                         goto err;
190                 }
191
192                 symbol_name = info->symbol_name;
193                 if (!symbol_name) {
194                         _E("%s: Failed to get backend symbol name\n",
195                                         info->module_name);
196                         ret = TIZEN_ERROR_INVALID_PARAMETER;
197                         goto err_dlclose;
198                 }
199
200                 backend = dlsym(handle, symbol_name);
201                 if (!backend) {
202                         _E("%s: Failed to find backend data (%s)\n",
203                                         info->module_name, dlerror());
204                         ret = TIZEN_ERROR_INVALID_PARAMETER;
205                         goto err_dlclose;
206                 }
207
208                 info->library_backend = backend;
209                 info->library_handle = handle;
210         } else {
211                 /*
212                  * Re-use the already loaded HAL backend instance
213                  * when usage_count is larger than 0.
214                  */
215                 backend = info->library_backend;
216         }
217
218         /* Check HAL ABI Version */
219         ret = hal_common_check_backend_abi_version(module, backend->abi_version);
220         if (ret < 0) {
221                 _E("%s: Failed to check ABI version\n",
222                                 info->module_name);
223                 ret = TIZEN_ERROR_INVALID_PARAMETER;
224                 goto err_dlclose;
225         }
226
227         /* Get the backend module data */
228         if (!backend->init) {
229                 _E("%s: hal_backend->init() is NULL\n",
230                                 info->module_name);
231                 ret = TIZEN_ERROR_INVALID_PARAMETER;
232                 goto err_dlclose;
233         }
234
235         ret = backend->init(data);
236         if (ret < 0) {
237                 _E("%s: Failed to initialize backend: name(%s)/vendor(%s)\n",
238                                 info->module_name, backend->name, backend->vendor);
239                 ret = TIZEN_ERROR_INVALID_PARAMETER;
240                 goto err_dlclose;
241         }
242
243         info->usage_count++;
244
245         _I("%s: Get HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d)\n",
246                 info->module_name, backend->name, backend->vendor,
247                 backend_library_name, info->usage_count);
248
249         G_UNLOCK(hal_common_lock);
250         return TIZEN_ERROR_NONE;
251
252 err_dlclose:
253         _hal_api_conf_exit();
254         dlclose(handle);
255 err:
256         G_UNLOCK(hal_common_lock);
257         return ret;
258 }
259
260 static int __put_backend(enum hal_module module, void *data, const char *library_name)
261 {
262         struct __hal_module_info *info = NULL;
263         hal_backend *backend = NULL;
264         void *handle = NULL;
265         int ret;
266
267         /* Check parameter whether is valid or not */
268         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
269                 _E("Invalid parameter of HAL module (%d)\n", module);
270                 return TIZEN_ERROR_INVALID_PARAMETER;
271         }
272
273         G_LOCK(hal_common_lock);
274
275         info = _hal_api_conf_get_module_info(module, library_name);
276         if (info == NULL) {
277                 _E("Failed to get HAL module(%d) information\n", module);
278                 ret =  TIZEN_ERROR_UNKNOWN;
279                 goto out;
280         }
281
282         backend = info->library_backend;
283         handle = info->library_handle;
284
285         if (!backend || info->usage_count == 0) {
286                 _I("%s: Already fully put for HAL module\n", info->module_name);
287                 ret = TIZEN_ERROR_NONE;
288                 goto out;
289         }
290
291         info->usage_count--;
292         if (info->usage_count > 0) {
293                 ret = TIZEN_ERROR_NONE;
294                 goto out;
295         }
296
297         if (backend->exit) {
298                 ret = backend->exit(data);
299                 if (ret < 0) {
300                         _E("%s: Failed to exit backend: name(%s)/vendor(%s)\n",
301                                 info->module_name, backend->name, backend->vendor);
302                         ret = TIZEN_ERROR_INVALID_PARAMETER;
303                         goto out;
304                 }
305         }
306
307         _I("%s: Put HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d)\n",
308                 info->module_name, backend->name, backend->vendor,
309                 get_backend_library_name(info), info->usage_count);
310
311         if (handle)
312                 dlclose(handle);
313
314         info->library_backend = NULL;
315         info->library_handle = NULL;
316
317         _hal_api_conf_exit();
318
319         ret = TIZEN_ERROR_NONE;
320
321 out:
322         G_UNLOCK(hal_common_lock);
323         return ret;
324 }
325
326 EXPORT
327 int hal_common_get_backend(enum hal_module module, void **data)
328 {
329         return __get_backend(module, data, NULL);
330 }
331
332 EXPORT
333 int hal_common_put_backend(enum hal_module module, void *data)
334 {
335         return __put_backend(module, data, NULL);
336 }
337
338 EXPORT
339 int hal_common_get_backend_with_library_name(enum hal_module module,
340                                         void **data, const char *library_name)
341 {
342         return __get_backend(module, data, library_name);
343 }
344
345 EXPORT
346 int hal_common_put_backend_with_library_name(enum hal_module module,
347                                         void *data, const char *library_name)
348 {
349         return __put_backend(module, data, library_name);
350 }
351
352 EXPORT
353 int hal_common_check_backend_abi_version(enum hal_module module,
354                                 enum hal_abi_version abi_version)
355 {
356         struct __hal_module_info *info = NULL;
357         int i;
358         int ret;
359
360         /* Check parameter whether is valid or not */
361         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
362                 _E("Invalid paramer of HAL module(%d)\n", module);
363                 return TIZEN_ERROR_INVALID_PARAMETER;
364         }
365
366         if (abi_version <= HAL_ABI_VERSION_UNKNOWN
367                         || abi_version >= HAL_ABI_VERSION_END) {
368                 _E("Invalid paramer of HAL ABI version(%d) for HAL module(%d)\n",
369                                 abi_version, module);
370                 return TIZEN_ERROR_INVALID_PARAMETER;
371         }
372
373         if (_hal_api_conf_init())
374                 return TIZEN_ERROR_UNKNOWN;
375
376         info = _hal_api_conf_get_module_info(module, NULL);
377         if (info == NULL) {
378                 _E("Failed to get HAL module(%d) information\n", module);
379                 ret = TIZEN_ERROR_UNKNOWN;
380                 goto out;
381         }
382
383         /* Check abi_version whether is supported or not */
384         if (!info->hal_api) {
385                 _E("%s: Doesn't support HAL API\n", info->module_name);
386                 ret = TIZEN_ERROR_INVALID_PARAMETER;
387                 goto out;
388         }
389
390         if (!info->num_abi_versions
391                         || !info->abi_versions) {
392                 _E("%s: Doesn't have the ABI version information\n",
393                                                 info->module_name);
394                 ret = TIZEN_ERROR_INVALID_PARAMETER;
395                 goto out;
396         }
397
398         g_platform_curr_abi_version = _hal_api_conf_get_platform_abi_version();
399         for (i = 0; i < info->num_abi_versions; i++) {
400                 struct hal_abi_version_match *data
401                                 = &info->abi_versions[i];
402
403                 if (g_platform_curr_abi_version != data->platform_abi_version)
404                         continue;
405
406                 if (data->backend_min_abi_version <= HAL_ABI_VERSION_UNKNOWN ||
407                         data->backend_min_abi_version >= HAL_ABI_VERSION_END) {
408                         _E("%s: abi_versions[%d].backend_min_abi_version(%d) is invalid\n",
409                                 info->module_name, i, data->backend_min_abi_version);
410                         ret = TIZEN_ERROR_INVALID_PARAMETER;
411                         goto out;
412                 }
413
414                 if (abi_version <= data->platform_abi_version
415                                 && abi_version >= data->backend_min_abi_version) {
416                         ret = TIZEN_ERROR_NONE;
417                         goto out;
418                 }
419
420                 _E("%s: \'%s\' doesn't support \'%s\'\n",
421                                 info->module_name,
422                                 hal_abi_version_str[g_platform_curr_abi_version],
423                                 hal_abi_version_str[abi_version]);
424                 _E("%s: Must use ABI versions from \'%s\' to \'%s\'\n",
425                                 info->module_name,
426                                 hal_abi_version_str[data->backend_min_abi_version],
427                                 hal_abi_version_str[data->platform_abi_version]);
428         }
429         ret = TIZEN_ERROR_INVALID_PARAMETER;
430
431 out:
432         _hal_api_conf_exit();
433         return ret;
434 }