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