halapi: Add new helper functions to get multiple library names
[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 #include <dirent.h>
25
26 #define _GNU_SOURCE
27 #include <errno.h>
28
29 #include <glib-object.h>
30
31 #include "common.h"
32 #include "hal-api-conf.h"
33
34 extern char *program_invocation_name;
35
36 #ifndef EXPORT
37 #define EXPORT __attribute__ ((visibility("default")))
38 #endif
39
40 static enum hal_abi_version g_platform_curr_abi_version;
41 G_LOCK_DEFINE_STATIC(hal_common_lock);
42
43 EXPORT
44 int hal_common_get_backend_library_name(enum hal_module module, char *name, int size)
45 {
46         const char *library_name = NULL;
47         struct __hal_module_info *info = NULL;
48         int ret;
49         int len_library_name;
50
51         /* Check parameter whether is valid or not */
52         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
53                 _E("Invalid parameter of HAL module (%d)\n", module);
54                 return TIZEN_ERROR_INVALID_PARAMETER;
55         }
56
57         if (_hal_api_conf_init())
58                 return TIZEN_ERROR_UNKNOWN;
59
60         info = _hal_api_conf_get_module_info(module, NULL);
61         if (info == NULL) {
62                 _E("Failed to get HAL module(%d) information\n", module);
63                 ret = TIZEN_ERROR_UNKNOWN;
64                 goto out;
65         }
66
67         library_name = get_backend_library_name(info);
68         if (!library_name) {
69                 _E("%s backend library name is NULL\n", info->module_name);
70                 ret = TIZEN_ERROR_NONE;
71                 goto out;
72         }
73
74         len_library_name = strlen(library_name);
75         if (!name || (len_library_name + 1 > size)) {
76                 ret = TIZEN_ERROR_UNKNOWN;
77                 name = NULL;
78                 goto out;
79         }
80         strncpy(name, library_name, len_library_name);
81         name[len_library_name] = '\0';
82
83         ret = TIZEN_ERROR_NONE;
84 out:
85         _hal_api_conf_exit();
86
87         return ret;
88 }
89
90 EXPORT
91 int hal_common_get_backend_symbol_name(enum hal_module module, char *name, int size)
92 {
93         struct __hal_module_info *info = NULL;
94         char *symbol_name = NULL;
95         int ret;
96         int len_symbol_name;
97
98         /* Check parameter whether is valid or not */
99         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
100                 _E("Invalid paramer of HAL module (%d)\n", module);
101                 return TIZEN_ERROR_INVALID_PARAMETER;
102         }
103
104         if (_hal_api_conf_init())
105                 return TIZEN_ERROR_UNKNOWN;
106
107         info = _hal_api_conf_get_module_info(module, NULL);
108         if (info == NULL) {
109                 _E("Failed to get HAL module(%d) information\n", module);
110                 ret = TIZEN_ERROR_UNKNOWN;
111                 goto out;
112         }
113         symbol_name = info->symbol_name;
114         if (!symbol_name) {
115                 _E("%s backend symbol name is NULL\n", info->module_name);
116                 ret = TIZEN_ERROR_NONE;
117                 goto out;
118         }
119
120         len_symbol_name = strlen(symbol_name);
121         if (!name || (len_symbol_name + 1 > size)) {
122                 ret = TIZEN_ERROR_UNKNOWN;
123                 name = NULL;
124                 goto out;
125         }
126         strncpy(name, symbol_name, len_symbol_name);
127         name[len_symbol_name] = '\0';
128
129         ret = TIZEN_ERROR_NONE;
130 out:
131         _hal_api_conf_exit();
132
133         return ret;
134 }
135
136 static int __open_backend(struct __hal_module_info *info)
137 {
138         const char *backend_library_name = NULL;
139         int ret;
140
141         if (info->backend && info->handle)
142                 return 0;
143
144         backend_library_name = get_backend_library_name(info);
145         if (!backend_library_name) {
146                 _E("%s: Failed to get backend library name\n",
147                                 info->module_name);
148                 ret = TIZEN_ERROR_INVALID_PARAMETER;
149                 goto err;
150         }
151
152         if (!info->symbol_name) {
153                 _E("%s: Failed to get backend symbol name\n",
154                                 info->module_name);
155                 ret = TIZEN_ERROR_INVALID_PARAMETER;
156                 goto err;
157         }
158
159         info->handle = dlopen(backend_library_name, RTLD_LAZY);
160         if (!info->handle) {
161                 _E("%s: Failed to load backend library (%s)\n",
162                                 info->module_name, dlerror());
163                 ret = TIZEN_ERROR_INVALID_PARAMETER;
164                 goto err;
165         }
166
167         info->backend = dlsym(info->handle, info->symbol_name);
168         if (!info->backend) {
169                 _E("%s: Failed to find backend data (%s)\n",
170                                 info->module_name, dlerror());
171                 ret = TIZEN_ERROR_INVALID_PARAMETER;
172                 goto err_dlclose;
173         }
174
175         _I("%s: Open HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
176                 info->module_name, info->backend->name, info->backend->vendor,
177                 backend_library_name, info->usage_count,
178                 program_invocation_name);
179
180         return 0;
181
182 err_dlclose:
183         dlclose(info->handle);
184 err:
185         info->backend = NULL;
186         info->handle = NULL;
187
188         return ret;
189 }
190
191 static void __close_backend(struct __hal_module_info *info)
192 {
193         if (!info->backend || !info->handle)
194                 return;
195
196         _I("%s: Close HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
197                 info->module_name, info->backend->name, info->backend->vendor,
198                 get_backend_library_name(info), info->usage_count,
199                 program_invocation_name);
200
201         if (info->handle)
202                 dlclose(info->handle);
203
204         info->backend = NULL;
205         info->handle = NULL;
206 }
207
208 static int __init_backend(struct __hal_module_info *info, void **data,
209                                 const char *library_name)
210 {
211         int ret;
212
213         if (!info->handle || !info->backend) {
214                 _I("%s: Has not yet dlopend backend\n", info->module_name);
215                 return TIZEN_ERROR_NONE;
216         }
217
218         if (!info->backend->init) {
219                 _E("%s: hal_backend->init() is NULL\n", info->module_name);
220                 return TIZEN_ERROR_INVALID_PARAMETER;
221         }
222
223         /* Check HAL ABI Version */
224         ret = hal_common_check_backend_abi_version(info->module,
225                                                 info->backend->abi_version);
226         if (ret < 0) {
227                 _E("%s: Failed to check ABI version\n", info->module_name);
228                 return TIZEN_ERROR_INVALID_PARAMETER;
229         }
230
231         /* Initialize backend */
232         ret = info->backend->init(data);
233         if (ret < 0) {
234                 _E("%s: Failed to initialize backend: name(%s)/vendor(%s)\n",
235                         info->module_name, info->backend->name,
236                         info->backend->vendor);
237                 return TIZEN_ERROR_INVALID_PARAMETER;
238         }
239
240         return TIZEN_ERROR_NONE;
241 }
242
243 static int __exit_backend(struct __hal_module_info *info, void *data,
244                                 const char *library_name)
245 {
246         int ret;
247
248         if (!info->handle || !info->backend) {
249                 _I("%s: Has not yet dlopend backend\n", info->module_name);
250                 return TIZEN_ERROR_NONE;
251         }
252
253         /* Exit backend */
254         if (info->backend->exit) {
255                 ret = info->backend->exit(data);
256                 if (ret < 0) {
257                         _E("%s: Failed to exit backend: name(%s)/vendor(%s)\n",
258                                 info->module_name, info->backend->name,
259                                 info->backend->vendor);
260                         return TIZEN_ERROR_INVALID_PARAMETER;
261                 }
262         }
263
264         return 0;
265 }
266
267 static int __get_backend(enum hal_module module, void **data,
268                                 const char *library_name)
269 {
270         struct __hal_module_info *info = NULL;
271         int ret;
272
273         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
274                 _E("Invalid parameter of HAL module (%d)\n", module);
275                 return TIZEN_ERROR_INVALID_PARAMETER;
276         }
277
278         G_LOCK(hal_common_lock);
279         if (_hal_api_conf_init()) {
280                 ret = TIZEN_ERROR_UNKNOWN;
281                 goto err;
282         }
283
284         info = _hal_api_conf_get_module_info(module, library_name);
285         if (info == NULL) {
286                 if (!library_name)
287                         _E("Failed to get HAL module(%d) information\n", module);
288                 else
289                         _E("Failed to get HAL module(%d) information (%s)\n",
290                                 module, library_name);
291                 ret = TIZEN_ERROR_UNKNOWN;
292                 goto err;
293         }
294
295         ret = __open_backend(info);
296         if (ret < 0) {
297                 _E("%s: Failed to get the backend library by dlopen\n",
298                                 info->module_name);
299                 ret = TIZEN_ERROR_INVALID_PARAMETER;
300                 goto err;
301         }
302
303         ret = __init_backend(info, data, NULL);
304         if (ret < 0) {
305                 _E("%s: Failed to initialize the backend library\n",
306                                 info->module_name);
307                 ret = TIZEN_ERROR_INVALID_PARAMETER;
308                 goto err_dlclose;
309         }
310
311         info->usage_count++;
312
313         _I("%s: Get HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
314                 info->module_name, info->backend->name, info->backend->vendor,
315                 get_backend_library_name(info), info->usage_count,
316                 program_invocation_name);
317
318         G_UNLOCK(hal_common_lock);
319         return TIZEN_ERROR_NONE;
320
321 err_dlclose:
322         _hal_api_conf_exit();
323         __close_backend(info);
324 err:
325         G_UNLOCK(hal_common_lock);
326         return ret;
327 }
328
329 static int __put_backend(enum hal_module module, void *data,
330                                 const char *library_name)
331 {
332         struct __hal_module_info *info = NULL;
333         int ret;
334
335         /* Check parameter whether is valid or not */
336         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
337                 _E("Invalid parameter of HAL module (%d)\n", module);
338                 return TIZEN_ERROR_INVALID_PARAMETER;
339         }
340
341         G_LOCK(hal_common_lock);
342
343         info = _hal_api_conf_get_module_info(module, library_name);
344         if (info == NULL) {
345                 _E("Failed to get HAL module(%d) information\n", module);
346                 ret =  TIZEN_ERROR_UNKNOWN;
347                 goto out;
348         }
349
350         if (!info->handle || !info->backend) {
351                 _I("%s: Has not yet dlopend backend\n", info->module_name);
352                 ret = TIZEN_ERROR_NONE;
353                 goto out;
354         }
355
356         if (!info->usage_count) {
357                 _I("%s: Already fully put for HAL module\n", info->module_name);
358                 ret =  TIZEN_ERROR_NONE;
359                 goto out;
360         }
361
362         ret = __exit_backend(info, data, NULL);
363         if (ret < 0) {
364                 _E("%s: Failed to exit the backend library\n",
365                                 info->module_name);
366                 ret = TIZEN_ERROR_INVALID_PARAMETER;
367                 goto out;
368         }
369
370         info->usage_count--;
371
372         _I("%s: Put HAL backend: name(%s)/vendor(%s)/library(%s)/count(%d) by %s\n",
373                 info->module_name, info->backend->name, info->backend->vendor,
374                 get_backend_library_name(info), info->usage_count,
375                 program_invocation_name);
376
377         if (info->usage_count > 0) {
378                 ret = TIZEN_ERROR_NONE;
379                 goto out;
380         }
381
382         __close_backend(info);
383         _hal_api_conf_exit();
384
385         ret = TIZEN_ERROR_NONE;
386
387 out:
388         G_UNLOCK(hal_common_lock);
389         return ret;
390 }
391
392 static int __get_backend_data(enum hal_module module, unsigned int *abi_version,
393                         char *name, int name_size, char *vendor, int vendor_size)
394 {
395         struct __hal_module_info *info = NULL;
396         int ret, len;
397
398         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
399                 _E("Invalid parameter of HAL module (%d)\n", module);
400                 return 0;
401         }
402
403         G_LOCK(hal_common_lock);
404
405         if (_hal_api_conf_init()) {
406                 ret = HAL_ABI_VERSION_UNKNOWN;
407                 goto err_unlock;
408         }
409
410         info = _hal_api_conf_get_module_info(module, NULL);
411         if (info == NULL) {
412                 _E("Failed to get HAL module(%d) information\n", module);
413                 ret = HAL_ABI_VERSION_UNKNOWN;
414                 goto err_conf_exit;
415         }
416
417         ret = __open_backend(info);
418         if (ret < 0) {
419                 _E("%s: Failed to get the backend library by dlopen\n",
420                                 info->module_name);
421                 ret = TIZEN_ERROR_INVALID_PARAMETER;
422                 goto err_conf_exit;
423         }
424
425         /* Return abi_verion of hal_backend structure */
426         if (!name_size && !vendor_size) {
427                 *abi_version = info->backend->abi_version;
428
429         /* Return name of hal_backend structure */
430         } else if (info->backend->name && name_size && !vendor_size) {
431                 len = strlen(info->backend->name);
432
433                 if (!info->backend->name || (len + 1 > name_size)) {
434                         _E("%s: Invalid size of name[] array\n", info->module_name);
435                         ret = TIZEN_ERROR_INVALID_PARAMETER;
436                         goto err_conf_exit;
437                 }
438
439                 strncpy(name, info->backend->name, len);
440                 name[len] = '\0';
441
442         /* Return vendor of hal_backend structure */
443         } else if (info->backend->vendor && !name_size && vendor_size) {
444                 len = strlen(info->backend->vendor);
445
446                 if (!info->backend->vendor || (len + 1 > vendor_size)) {
447                         _E("%s: Invalid size of vendor[] array\n", info->module_name);
448                         ret = TIZEN_ERROR_INVALID_PARAMETER;
449                         goto err_conf_exit;
450                 }
451
452                 strncpy(vendor, info->backend->vendor, len);
453                 vendor[len] = '\0';
454         } else {
455                 _E("%s: Failed to get backend data\n", info->module_name);
456                 ret = TIZEN_ERROR_INVALID_PARAMETER;
457                 goto err_conf_exit;
458         }
459         ret = TIZEN_ERROR_NONE;
460
461 err_conf_exit:
462         _hal_api_conf_exit();
463 err_unlock:
464         G_UNLOCK(hal_common_lock);
465         return ret;
466 }
467
468 EXPORT
469 int hal_common_get_backend(enum hal_module module, void **data)
470 {
471         return __get_backend(module, data, NULL);
472 }
473
474 EXPORT
475 int hal_common_put_backend(enum hal_module module, void *data)
476 {
477         return __put_backend(module, data, NULL);
478 }
479
480 EXPORT
481 int hal_common_get_backend_with_library_name(enum hal_module module,
482                                         void **data, const char *library_name)
483 {
484         return __get_backend(module, data, library_name);
485 }
486
487 EXPORT
488 int hal_common_put_backend_with_library_name(enum hal_module module,
489                                         void *data, const char *library_name)
490 {
491         return __put_backend(module, data, library_name);
492 }
493
494 EXPORT
495 int hal_common_check_backend_abi_version(enum hal_module module,
496                                 enum hal_abi_version abi_version)
497 {
498         struct __hal_module_info *info = NULL;
499         int i;
500         int ret;
501
502         /* Check parameter whether is valid or not */
503         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
504                 _E("Invalid paramer of HAL module(%d)\n", module);
505                 return TIZEN_ERROR_INVALID_PARAMETER;
506         }
507
508         if (abi_version <= HAL_ABI_VERSION_UNKNOWN
509                         || abi_version >= HAL_ABI_VERSION_END) {
510                 _E("Invalid paramer of HAL ABI version(%d) for HAL module(%d)\n",
511                                 abi_version, module);
512                 return TIZEN_ERROR_INVALID_PARAMETER;
513         }
514
515         if (_hal_api_conf_init())
516                 return TIZEN_ERROR_UNKNOWN;
517
518         info = _hal_api_conf_get_module_info(module, NULL);
519         if (info == NULL) {
520                 _E("Failed to get HAL module(%d) information\n", module);
521                 ret = TIZEN_ERROR_UNKNOWN;
522                 goto out;
523         }
524
525         /* Check abi_version whether is supported or not */
526         if (!info->hal_api) {
527                 _E("%s: Doesn't support HAL API\n", info->module_name);
528                 ret = TIZEN_ERROR_INVALID_PARAMETER;
529                 goto out;
530         }
531
532         if (!info->num_abi_versions
533                         || !info->abi_versions) {
534                 _E("%s: Doesn't have the ABI version information\n",
535                                                 info->module_name);
536                 ret = TIZEN_ERROR_INVALID_PARAMETER;
537                 goto out;
538         }
539
540         g_platform_curr_abi_version = _hal_api_conf_get_platform_abi_version();
541         for (i = 0; i < info->num_abi_versions; i++) {
542                 struct hal_abi_version_match *data
543                                 = &info->abi_versions[i];
544
545                 if (g_platform_curr_abi_version != data->platform_abi_version)
546                         continue;
547
548                 if (data->backend_min_abi_version <= HAL_ABI_VERSION_UNKNOWN ||
549                         data->backend_min_abi_version >= HAL_ABI_VERSION_END) {
550                         _E("%s: abi_versions[%d].backend_min_abi_version(%d) is invalid\n",
551                                 info->module_name, i, data->backend_min_abi_version);
552                         ret = TIZEN_ERROR_INVALID_PARAMETER;
553                         goto out;
554                 }
555
556                 if (abi_version <= data->platform_abi_version
557                                 && abi_version >= data->backend_min_abi_version) {
558                         ret = TIZEN_ERROR_NONE;
559                         goto out;
560                 }
561
562                 _E("%s: \'%s\' doesn't support \'%s\'\n",
563                                 info->module_name,
564                                 hal_abi_version_str[g_platform_curr_abi_version],
565                                 hal_abi_version_str[abi_version]);
566                 _E("%s: Must use ABI versions from \'%s\' to \'%s\'\n",
567                                 info->module_name,
568                                 hal_abi_version_str[data->backend_min_abi_version],
569                                 hal_abi_version_str[data->platform_abi_version]);
570         }
571         ret = TIZEN_ERROR_INVALID_PARAMETER;
572
573 out:
574         _hal_api_conf_exit();
575         return ret;
576 }
577
578 EXPORT
579 unsigned int hal_common_get_backend_abi_version(enum hal_module module)
580 {
581         unsigned int abi_version;
582         int ret;
583
584         ret = __get_backend_data(module, &abi_version, NULL, 0, NULL, 0);
585         if (ret < 0)
586                 return HAL_ABI_VERSION_UNKNOWN;
587
588         return abi_version;
589 }
590
591 EXPORT
592 int hal_common_get_backend_name(enum hal_module module, char *name, int size)
593 {
594         return __get_backend_data(module, NULL, name, size, NULL, 0);
595 }
596
597 EXPORT
598 int hal_common_get_backend_vendor(enum hal_module module, char *vendor, int size)
599 {
600         return __get_backend_data(module, NULL, NULL, 0, vendor, size);
601 }
602
603
604 static int __get_backend_library_data(enum hal_module module,
605                                         char **lib_names,
606                                         int lib_count,
607                                         int lib_name_size)
608 {
609         struct __hal_module_info *info = NULL;
610         struct dirent *de;
611         DIR *dir;
612         const char *backend_module_name = NULL;
613         int count, i, ret, len;
614 #if defined(__aarch64__)
615         const char hal_backend_path[] = "/hal/lib64";
616 #else
617         const char hal_backend_path[] = "/hal/lib";
618 #endif
619
620         /* Check parameter whether is valid or not */
621         if (module <= HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) {
622                 _E("Invalid parameter of HAL module (%d)\n", module);
623                 return TIZEN_ERROR_INVALID_PARAMETER;
624         }
625
626         if (_hal_api_conf_init())
627                 return TIZEN_ERROR_UNKNOWN;
628
629         info = _hal_api_conf_get_module_info(module, NULL);
630         if (info == NULL) {
631                 _E("Failed to get HAL module(%d) information\n", module);
632                 ret = TIZEN_ERROR_INVALID_PARAMETER;
633                 goto err;
634         }
635
636         if (info->backend_module_name == NULL) {
637                 _E("Don't support HAL backend of HAL module(%s)\n",
638                                         info->module_name);
639                 ret = TIZEN_ERROR_INVALID_PARAMETER;
640                 goto err;
641         }
642         backend_module_name = g_strdup_printf("libhal-backend-%s",
643                                         info->backend_module_name);
644         if (!backend_module_name) {
645                 _E("Failed to allocate the backend_module_name of HAL module(%s)\n",
646                                         info->module_name);
647                 ret = TIZEN_ERROR_UNKNOWN;
648                 goto err;
649         }
650
651         /* Find HAL backend libraries */
652         dir = opendir(hal_backend_path);
653         if (!dir) {
654                 _E("Failed to find HAL backend path(%s) for HAL module(%s)\n",
655                                         hal_backend_path, info->module_name);
656                 ret = TIZEN_ERROR_UNKNOWN;
657                 goto err_free_backend_module_name;
658         }
659
660         count = 0;
661         while ((de = readdir(dir)) != NULL) {
662                 if (!g_str_has_prefix(de->d_name, backend_module_name))
663                         continue;
664
665                 if (lib_count == 0)
666                         count++;
667                 else if (lib_count > 0) {
668                         len = strlen(de->d_name) + 1;
669
670                         if (len > lib_name_size)
671                                 len = lib_name_size;
672
673                         strncpy(lib_names[count++], de->d_name, len);
674                 }
675         }
676
677         if (lib_count > 0 && count != lib_count) {
678                 ret = TIZEN_ERROR_INVALID_PARAMETER;
679                 goto err_mismatch_count;
680         }
681
682         closedir(dir);
683         _hal_api_conf_exit();
684         g_free(backend_module_name);
685
686         return count;
687
688 err_mismatch_count:
689         for (i = count - 1; i >= 0; i--)
690                 memset(lib_names[i], 0, strlen(lib_names[i]));
691
692         closedir(dir);
693 err_free_backend_module_name:
694         g_free(backend_module_name);
695 err:
696         _hal_api_conf_exit();
697         return ret;
698 }
699
700 EXPORT
701 int hal_common_get_backend_count(enum hal_module module)
702 {
703         return __get_backend_library_data(module, NULL, 0, 0);
704 }
705
706 EXPORT
707 int hal_common_get_backend_library_names(enum hal_module module,
708                                         char **library_names,
709                                         int library_count,
710                                         int library_name_size)
711 {
712         int ret = __get_backend_library_data(module, library_names,
713                                         library_count, library_name_size);
714         return (ret < 0) ? ret : 0;
715 }