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