From 0bae662a9fe3b876c0e5491a8e99e541cddfe018 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 19 Dec 2023 15:24:38 +0900 Subject: [PATCH] halcc: Introduce halcc library The halcc stands for hal compatibility checker. Tizen hal-apis can specify what feature and version it expects to hal-backends in manifest file. The halcc library deserializes and utilizes the information for checking compatibility between hal-api and hal-backend. For example, a hal-api specifies what it needs in xml file: | | | | | AAA | 3.1 | passthrough | | ... | It means that the hal-api expects and requires hal-backend module name of AAA, and version of 3.x where x >= 1. (See semantic versioning, https://semver.org) These are collected and tested by the halcc library. Currently only the function below is provieded - int halcc_check_compatibility(const char *hal_api_manifest_dir, halcc_compatibility_cb callback, void *user_data) : It collects manifest files at hal_api_manifest_dir and checks whether the hal-backends have compatible what hal-apis have specified. For each specified in manifests, callback is invoked. Change-Id: Ibb16c378f6fbe08750b6df7db99ee6626bcfd033 Signed-off-by: Youngjae Cho --- CMakeLists.txt | 2 + halcc/CMakeLists.txt | 26 + halcc/include/halcc/hal-compatibility-checker.h | 41 ++ halcc/src/hal-compatibility-checker.c | 174 +++++ halcc/src/halcc-object.c | 773 +++++++++++++++++++++++ halcc/src/halcc-object.h | 108 ++++ halcc/src/halcc-parser.c | 365 +++++++++++ halcc/src/halcc-parser.h | 34 + halcc/src/halcc-util.c | 40 ++ halcc/src/halcc-util.h | 40 ++ packaging/hal-api-common.pc.in | 9 +- packaging/hal-api-common.spec | 2 + tests/unittest/CMakeLists.txt | 12 +- tests/unittest/test-hal-compatibility-checker.cc | 233 +++++++ 14 files changed, 1851 insertions(+), 8 deletions(-) create mode 100644 halcc/CMakeLists.txt create mode 100644 halcc/include/halcc/hal-compatibility-checker.h create mode 100644 halcc/src/hal-compatibility-checker.c create mode 100644 halcc/src/halcc-object.c create mode 100644 halcc/src/halcc-object.h create mode 100644 halcc/src/halcc-parser.c create mode 100644 halcc/src/halcc-parser.h create mode 100644 halcc/src/halcc-util.c create mode 100644 halcc/src/halcc-util.h create mode 100644 tests/unittest/test-hal-compatibility-checker.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index f88a4f1..6c1e84a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,8 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/${PROJECT_NAME}.pc INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/hal-rpmdb-checker.conf DESTINATION /usr/lib/tmpfiles.d) +ADD_SUBDIRECTORY(halcc) + ADD_SUBDIRECTORY(tests) ADD_SUBDIRECTORY(tools/lshal) diff --git a/halcc/CMakeLists.txt b/halcc/CMakeLists.txt new file mode 100644 index 0000000..9b427ee --- /dev/null +++ b/halcc/CMakeLists.txt @@ -0,0 +1,26 @@ +PROJECT(libhalcc C) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED glib-2.0 libxml-2.0) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +SET(LIBHALCC_SRCS + ./src/hal-compatibility-checker.c + ./src/halcc-object.c + ./src/halcc-util.c + ./src/halcc-parser.c) + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${LIBHALCC_SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -ldl hal-api-common) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-Wno-pointer-sign") +SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME halcc) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIBDIR}/hal) +INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${INCLUDEDIR}) diff --git a/halcc/include/halcc/hal-compatibility-checker.h b/halcc/include/halcc/hal-compatibility-checker.h new file mode 100644 index 0000000..414c82a --- /dev/null +++ b/halcc/include/halcc/hal-compatibility-checker.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HAL_COMPATIBILITY_CHECKER_H__ +#define __HAL_COMPATIBILITY_CHECKER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef enum halcc_compatibility_e { + HALCC_INCOMPATIBLE, + HALCC_COMPATIBLE, +} halcc_compatibility_e; + +typedef void (*halcc_compatibility_cb) (enum hal_module module, + halcc_compatibility_e is_compatible, void *user_data); + +int halcc_check_compatibility(const char *hal_api_manifest_dir, + halcc_compatibility_cb callback, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif //__HAL_COMPATIBILITY_CHECKER_H__ diff --git a/halcc/src/hal-compatibility-checker.c b/halcc/src/hal-compatibility-checker.c new file mode 100644 index 0000000..1ee3f64 --- /dev/null +++ b/halcc/src/hal-compatibility-checker.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "halcc-object.h" +#include "halcc-parser.h" +#include "halcc-util.h" + +struct callback_data { + halcc_compatibility_cb func; + void *user_data; +}; + +static int parse_directory(const char *manifest_dir, halcc_manifest *manifest) +{ + DIR *dir; + int dfd; + struct dirent *entry; + + if (!manifest_dir || !manifest) + return -EINVAL; + + dir = opendir(manifest_dir); + if (!dir) { + printf("Failed to opendir '%s', %m\n", manifest_dir); + return -errno; + } + + dfd = dirfd(dir); + + while ((entry = readdir(dir))) { + int fd = -1; + int ret; + + if (entry->d_type != DT_REG) + continue; + + fd = openat(dfd, entry->d_name, O_RDONLY); + if (fd < 0) { + printf("Failed to openat(), %m\n"); + continue; + } + + ret = halcc_parse_fd(fd, manifest); + if (ret < 0) { + printf("Failed to parse xml, ret=%d\n", ret); + close(fd); + continue; + } + + close(fd); + } + + closedir(dir); + + return 0; +} + +static halcc_compatibility_e is_compatible(int major, int minor, unsigned int abi_version) +{ + if (abi_version == HAL_ABI_VERSION_UNKNOWN) + return HALCC_INCOMPATIBLE; + + return HALCC_COMPATIBLE; +} + +static void foreach_hal(void *data, void *user_data) +{ + struct callback_data *callback_data = NULL; + enum hal_module module; + halcc_hal *hal; + const char *hal_name = NULL; + int major, minor; + halcc_compatibility_e compatible = HALCC_INCOMPATIBLE; + + hal = (halcc_hal *) data; + callback_data = (struct callback_data *) user_data; + + assert(hal); + assert(callback_data); + assert(callback_data->func); + + if (halcc_hal_get_name(hal, &hal_name) < 0 || hal_name == NULL) + return; + + if (halcc_hal_get_version(hal, &major, &minor, NULL) < 0) + return; + + for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) { + char module_name[128] = { 0 , }; + unsigned int abi_version; + int ret; + + ret = hal_common_get_backend_module_name(module, module_name, sizeof(module_name)); + if (ret < 0) + continue; + + ret = strncmp(hal_name, module_name, strlen(hal_name) + 1); + if (ret != 0) + continue; + + abi_version = hal_common_get_backend_abi_version(module); + if (abi_version == HAL_ABI_VERSION_UNKNOWN) + break; + + compatible = is_compatible(major, minor, abi_version); + break; + } + + if (module >= HAL_MODULE_END) { + printf("Unknown hal module: %s\n", hal_name); + return; + } + + printf("%s: %s\n", hal_name, compatible ? "Compatible" : "Incompatible"); + + callback_data->func(module, compatible, callback_data->user_data); +} + +EXPORT +int halcc_check_compatibility(const char *hal_api_manifest_dir, + halcc_compatibility_cb callback, void *user_data) +{ + halcc_manifest *manifest = NULL; + struct callback_data callback_data = { 0 , }; + int ret = 0; + + if (!hal_api_manifest_dir) + return -EINVAL; + + if (!callback) + return -EINVAL; + + ret = halcc_manifest_new(&manifest); + if (ret < 0) + return ret; + + ret = parse_directory(hal_api_manifest_dir, manifest); + if (ret < 0) + goto out; + + callback_data = (struct callback_data) { callback, user_data }; + + halcc_manifest_foreach_hal(manifest, foreach_hal, &callback_data); + +out: + if (manifest) + halcc_manifest_free(g_steal_pointer(&manifest)); + + return ret; +} diff --git a/halcc/src/halcc-object.c b/halcc/src/halcc-object.c new file mode 100644 index 0000000..96698db --- /dev/null +++ b/halcc/src/halcc-object.c @@ -0,0 +1,773 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "halcc-object.h" +#include "halcc-parser.h" +#include "halcc-util.h" + +#define HALCC_TRANSPORT_DEFAULT HALCC_TRANSPORT_PASSTHROUGH + +typedef struct halcc_version { + int major; + union { + /** + * Can be used interchangeably. + * min_minor might be useful if max_minor is specified. + */ + int minor; + int min_minor; + }; + int max_minor; +} halcc_version; + +typedef struct halcc_interface { + char *name; + char *instance_id; +} halcc_interface; + +typedef struct halcc_hal { + char *name; + halcc_version version; + halcc_transport_e transport; + halcc_dependency_state_e dependency_state; + GHashTable *dependencies; + GHashTable *interfaces; +} halcc_hal; + +typedef struct halcc_manifest { + halcc_manifest_type_e manifest_type; + halcc_version version; + int level; + GHashTable *hals; +} halcc_manifest; + +typedef enum halcc_hash_compare_type_e { + HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION, + HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION, + HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION, +} halcc_hash_compare_type_e; + +typedef struct hash_hal_key { + halcc_hal hal; + halcc_hash_compare_type_e compare_type; +} hash_hal_key; + +#define HASH_HAL_KEY(_name, _major, _minor, _compare_type) \ + (hash_hal_key) { \ + .hal = { \ + .name = (char *) _name, \ + .version.major = _major, \ + .version.minor = _minor, \ + }, \ + .compare_type = _compare_type, \ + } + +#define HASH_HAL_KEY_RAW(_hal, _compare_type) \ + HASH_HAL_KEY((_hal)->name, \ + (_hal)->version.major, \ + (_hal)->version.minor, \ + _compare_type \ + ) + +static void hashtable_foreach(GHashTable *table, halcc_iter_cb cb, void *user_data) +{ + GHashTableIter iter; + void *data; + + if (!table || !cb) + return; + + g_hash_table_iter_init(&iter, table); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) + cb(data, user_data); +} + +static guint hal_hash(gconstpointer key) +{ + const halcc_hal *hal = (const halcc_hal *) key; + + assert(hal); + assert(hal->name); + + return g_str_hash(hal->name); +} + +static gboolean hal_hash_equal(gconstpointer a, gconstpointer b) +{ + const halcc_hal *hal = (const halcc_hal *) a; + const hash_hal_key *key = (const hash_hal_key *) b; + int compare_type; + + assert(hal); + assert(key); + + if (strncmp(hal->name, key->hal.name, strlen(hal->name) + 1) != 0) + return false; + + if (hal->version.major != key->hal.version.major) + return false; + + compare_type = key->compare_type; + + switch (compare_type) { + case HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION: + return hal->version.minor == key->hal.version.minor; + case HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION: + return hal->version.minor <= key->hal.version.minor; + case HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION: + return hal->version.minor >= key->hal.version.minor; + default: + break; + } + + assert(0); // unreachable + + return false; +} + +static void hal_hash_value_free(gpointer data) +{ + halcc_hal *hal = (halcc_hal *) data; + + halcc_hal_free(hal); +} + +static GHashTable* hashtable_hal_new(void) +{ + return g_hash_table_new_full(hal_hash, hal_hash_equal, NULL, hal_hash_value_free); +} + +static int hashtable_hal_insert(GHashTable *hal_table, halcc_hal *hal) +{ + hash_hal_key key; + + if (!hal_table || !hal) + return -EINVAL; + + key = HASH_HAL_KEY_RAW(hal, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION); + + if (g_hash_table_lookup_extended(hal_table, &key, NULL, NULL)) + return -EALREADY; + + g_hash_table_insert(hal_table, hal, hal); + + return 0; +} + +static halcc_hal* hashtable_hal_lookup(GHashTable *hal_table, + const char *name, int major, int minor, halcc_hash_compare_type_e type) +{ + hash_hal_key key; + + if (!hal_table || !name) + return NULL; + + key = HASH_HAL_KEY(name, major, minor, type); + + return g_hash_table_lookup(hal_table, &key); +} + +static halcc_hal* hashtable_hal_steal(GHashTable *hal_table, const char *name, int major, int minor) +{ + hash_hal_key key; + halcc_hal *hal = NULL; + + if (!hal_table || !name) + return NULL; + + key = HASH_HAL_KEY(name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION); + + if (!g_hash_table_steal_extended(hal_table, &key, NULL, (gpointer*) &hal)) + return NULL; + + return hal; +} + +static void hashtable_hal_remove(GHashTable *hal_table, const char *name, int major, int minor) +{ + hash_hal_key key; + + if (!hal_table || !name) + return; + + key = HASH_HAL_KEY(name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION); + + g_hash_table_remove(hal_table, &key); +} + +static guint interface_hash(gconstpointer key) +{ + const halcc_interface *interface = (const halcc_interface *) key; + char interface_str[HALCC_NAME_MAX * 2] = { 0 , }; + + assert(interface); + assert(interface->name); + + if (interface->instance_id) + snprintf(interface_str, sizeof(interface_str), "%s.%s", interface->name, interface->instance_id); + else + snprintf(interface_str, sizeof(interface_str), "%s.default", interface->name); + + return g_str_hash(interface_str); +} + +static gboolean interface_hash_equal(gconstpointer a, gconstpointer b) +{ + const halcc_interface *interface = (const halcc_interface *) a; + const halcc_interface *key = (const halcc_interface *) b; + + assert(interface); + assert(key); + + return strncmp(interface->name, key->name, strlen(interface->name) + 1) == 0; +} + +static void interface_hash_value_free(gpointer data) +{ + halcc_interface *interface = (halcc_interface *) data; + + halcc_interface_free(interface); +} + +static GHashTable* hashtable_interface_new(void) +{ + return g_hash_table_new_full(interface_hash, + interface_hash_equal, NULL, interface_hash_value_free); +} + +static int hashtable_interface_insert(GHashTable *interface_table, halcc_interface *interface) +{ + g_hash_table_insert(interface_table, interface, interface); + + return 0; +} + +/* +static halcc_interface* hashtable_interface_lookup(GHashTable *interface_table, + const char *name, const char *instance_id) +{ + halcc_interface key; + + if (!interface_table || !name) + return NULL; + + key = (halcc_interface) { + .name = (char *) name, + .instance_id = (char *) instance_id, + }; + + return g_hash_table_lookup(interface_table, &key); +} +*/ + +static void hashtable_interface_remove(GHashTable *interface_table, + const char *name, const char *instance_id) +{ + halcc_interface key; + + if (!interface_table || !name) + return; + + key = (halcc_interface) { + .name = (char *) name, + .instance_id = (char *) instance_id, + }; + + g_hash_table_remove(interface_table, &key); +} + +int halcc_manifest_new(halcc_manifest **manifest) +{ + halcc_manifest *m; + + if (!manifest) + return -EINVAL; + + m = calloc(1, sizeof(halcc_manifest)); + if (!m) + return -ENOMEM; + + *m = (halcc_manifest) { + .manifest_type = HALCC_UNINITIALIZED_INT, + .version.major = HALCC_UNINITIALIZED_INT, + .version.minor = HALCC_UNINITIALIZED_INT, + .level = HALCC_UNINITIALIZED_INT, + .hals = hashtable_hal_new(), + }; + + *manifest = g_steal_pointer(&m); + + return 0; +} + +void halcc_manifest_free(halcc_manifest *manifest) +{ + if (!manifest) + return; + + g_hash_table_destroy(g_steal_pointer(&manifest->hals)); + + free(manifest); +} + +int halcc_manifest_set_type(halcc_manifest *manifest, halcc_manifest_type_e type) +{ + if (!manifest) + return -EINVAL; + + if (type < HALCC_MANIFEST_TYPE_HAL_API || type > HALCC_MANIFEST_TYPE_HAL_BACKEND) + return -EINVAL; + + + return halcc_util_set_int_once(&manifest->manifest_type, type, "manifest.type"); +} + +int halcc_manifest_get_type(halcc_manifest *manifest, halcc_manifest_type_e *type) +{ + if (!manifest || !type) + return -EINVAL; + + *type = manifest->manifest_type; + + return 0; +} + +int halcc_manifest_set_version(halcc_manifest *manifest, int major, int minor) +{ + int ret; + + if (!manifest) + return -EINVAL; + + if (major < 0 || minor < 0) + return -EINVAL; + + ret = halcc_util_set_int_once(&manifest->version.major, major, "manifest.version.major"); + if (ret != 0) + return ret; + + ret = halcc_util_set_int_once(&manifest->version.minor, minor, "manifest.version.minor"); + if (ret != 0) + return ret; + + return 0; +} + +int halcc_manifest_get_version(halcc_manifest *manifest, int *major, int *minor) +{ + if (!manifest || !major || !minor) + return -EINVAL; + + *major = manifest->version.major; + *minor = manifest->version.minor; + + return 0; +} + +int halcc_manifest_set_level(halcc_manifest *manifest, int level) +{ + if (!manifest) + return -EINVAL; + + return halcc_util_set_int_once(&manifest->level, level, "manifest.level"); +} + +int halcc_manifest_get_level(halcc_manifest *manifest, int *level) +{ + if (!manifest || !level) + return -EINVAL; + + *level = manifest->level; + + return 0; +} + +int halcc_manifest_add_hal(halcc_manifest *manifest, halcc_hal *hal) +{ + if (!manifest || !hal) + return -EINVAL; + + assert(manifest->hals); + + if (!hal->name) + return -EINVAL; + + return hashtable_hal_insert(manifest->hals, hal); +} + +int halcc_manifest_find_hal(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal) +{ + halcc_hal *h; + + if (!manifest || !hal_name) + return -EINVAL; + + h = hashtable_hal_lookup(manifest->hals, + hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION); + if (!h) + return -ENOTSUP; + + if (hal) + *hal = g_steal_pointer(&h); + + return 0; +} + +int halcc_manifest_find_hal_raw(halcc_manifest *manifest, + halcc_hal *raw, halcc_hal **hal) +{ + return halcc_manifest_find_hal(manifest, + raw->name, raw->version.major, raw->version.minor, hal); +} + +int halcc_manifest_find_hal_backward_compatible(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal) +{ + halcc_hal *h; + + if (!manifest || !hal_name) + return -EINVAL; + + h = hashtable_hal_lookup(manifest->hals, + hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION); + if (!h) + return -ENOTSUP; + + if (hal) + *hal = g_steal_pointer(&h); + + return 0; +} + +int halcc_manifest_find_hal_backward_compatible_raw(halcc_manifest *manifest, + halcc_hal *raw, halcc_hal **hal) +{ + return halcc_manifest_find_hal_backward_compatible(manifest, + raw->name, raw->version.major, raw->version.minor, hal); +} + +int halcc_manifest_find_hal_forward_compatible(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal) +{ + halcc_hal *h; + + if (!manifest || !hal_name) + return -EINVAL; + + h = hashtable_hal_lookup(manifest->hals, + hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION); + if (!h) + return -ENOTSUP; + + if (hal) + *hal = g_steal_pointer(&h); + + return 0; +} + +int halcc_manifest_find_hal_forward_compatible_raw(halcc_manifest *manifest, + halcc_hal *raw, halcc_hal **hal) +{ + return halcc_manifest_find_hal_forward_compatible(manifest, + raw->name, raw->version.major, raw->version.minor, hal); +} + +int halcc_manifest_steal_hal(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal) +{ + halcc_hal *h = NULL; + + if (!manifest || !hal_name) + return -EINVAL; + + h = hashtable_hal_steal(manifest->hals, hal_name, major, minor); + if (!h) + return -ENOTSUP; + + if (hal) + *hal = g_steal_pointer(&h); + + return 0; +} + +void halcc_manifest_remove_hal(halcc_manifest *manifest, + const char *hal_name, int major, int minor) +{ + if (!manifest || !hal_name) + return; + + hashtable_hal_remove(manifest->hals, hal_name, major, minor); +} + +void halcc_manifest_foreach_hal(halcc_manifest *manifest, + halcc_iter_cb cb, void *user_data) +{ + if (!manifest || !manifest->hals || !cb) + return; + + hashtable_foreach(manifest->hals, cb, user_data); +} + +int halcc_hal_new(halcc_hal **hal) +{ + halcc_hal *h; + + if (!hal) + return -EINVAL; + + h = calloc(1, sizeof(halcc_hal)); + if (!h) + return -ENOMEM; + + h->transport = HALCC_TRANSPORT_DEFAULT; + h->dependency_state = HALCC_DEPENDENCY_STATE_NONE; + h->dependencies = hashtable_hal_new(); + h->interfaces = hashtable_interface_new(); + + *hal = g_steal_pointer(&h); + + return 0; +} + +void halcc_hal_free(halcc_hal *hal) +{ + if (!hal) + return; + + free(g_steal_pointer(&hal->name)); + g_hash_table_destroy(g_steal_pointer(&hal->dependencies)); + g_hash_table_destroy(g_steal_pointer(&hal->interfaces)); + free(hal); +} + +int halcc_hal_set_name(halcc_hal *hal, const char *hal_name) +{ + char *n; + + if (!hal) + return -EINVAL; + + if (hal->name) + free(g_steal_pointer(&hal->name)); + + if (!hal_name) + return 0; + + n = strndup(hal_name, HALCC_NAME_MAX); + if (!n) + return -ENOMEM; + + hal->name = g_steal_pointer(&n); + + return 0; +} + +int halcc_hal_get_name(halcc_hal *hal, const char **hal_name) +{ + if (!hal || !hal_name) + return -EINVAL; + + *hal_name = hal->name; + + return 0; +} + +int halcc_hal_set_version(halcc_hal *hal, int major, int min_minor, int max_minor) +{ + if (!hal) + return -EINVAL; + + hal->version.major = major; + hal->version.min_minor = min_minor; + hal->version.max_minor = max_minor; + + return 0; +} + +int halcc_hal_get_version(halcc_hal *hal, int *major, int *min_minor, int *max_minor) +{ + if (!hal || !major || !min_minor) + return -EINVAL; + + *major = hal->version.major; + *min_minor = hal->version.min_minor; + if (max_minor) + *max_minor = hal->version.max_minor; + + return 0; +} + +int halcc_hal_set_transport(halcc_hal *hal, halcc_transport_e transport) +{ + if (!hal) + return -EINVAL; + + hal->transport = transport; + + return 0; +} + +int halcc_hal_get_transport(halcc_hal *hal, halcc_transport_e *transport) +{ + if (!hal || !transport) + return -EINVAL; + + assert(hal->transport >= HALCC_TRANSPORT_PASSTHROUGH); + assert(hal->transport <= HALCC_TRANSPORT_IPC); + + *transport = hal->transport; + + return 0; +} + +int halcc_hal_add_dependency(halcc_hal *hal, halcc_hal *dependency) +{ + if (!hal || !dependency) + return -EINVAL; + + return hashtable_hal_insert(hal->dependencies, dependency); +} + +void halcc_hal_remove_dependency(halcc_hal *hal, + const char *dependency_hal_name, int major, int minor) +{ + if (!hal || !dependency_hal_name) + return; + + hashtable_hal_remove(hal->dependencies, dependency_hal_name, major, minor); +} + +void halcc_hal_foreach_dependency(halcc_hal *hal, halcc_iter_cb cb, void *user_data) +{ + if (!hal || !hal->dependencies || !cb) + return; + + hashtable_foreach(hal->dependencies, cb, user_data); +} + +int halcc_hal_add_interface(halcc_hal *hal, halcc_interface *interface) +{ + if (!hal || !interface) + return -EINVAL; + + return hashtable_interface_insert(hal->interfaces, interface); +} + +void halcc_hal_remove_interface(halcc_hal *hal, + const char *interface_name, const char *instance_id) +{ + if (!hal || !interface_name) + return; + + hashtable_interface_remove(hal->interfaces, interface_name, instance_id); +} + +void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_data) +{ + if (!hal || !hal->interfaces || !cb) + return; + + hashtable_foreach(hal->interfaces, cb, user_data); +} + +int halcc_interface_new(halcc_interface **interface) +{ + halcc_interface *iface; + + if (!interface) + return -EINVAL; + + iface = calloc(1, sizeof(halcc_interface)); + if (!iface) + return -ENOMEM; + + *interface = g_steal_pointer(&iface); + + return 0; +} + +void halcc_interface_free(halcc_interface *interface) +{ + if (!interface) + return; + + free(g_steal_pointer(&interface->name)); + free(g_steal_pointer(&interface->instance_id)); + free(g_steal_pointer(&interface)); +} + +int halcc_interface_set_name(halcc_interface *interface, const char *interface_name) +{ + char *n; + + if (!interface || !interface_name) + return -EINVAL; + + n = strndup(interface_name, HALCC_NAME_MAX); + if (!n) + return -ENOMEM; + + interface->name = g_steal_pointer(&n); + + return 0; +} + +int halcc_interface_get_name(halcc_interface *interface, const char **interface_name) +{ + if (!interface || !interface_name) + return -EINVAL; + + *interface_name = interface->name; + + return 0; +} + +int halcc_interface_set_instance_id(halcc_interface *interface, const char *instance_id) +{ + char *id = NULL; + + if (!interface || !instance_id) + return -EINVAL; + + id = strndup(instance_id, HALCC_NAME_MAX); + if (!id) + return -ENOMEM; + + interface->instance_id = g_steal_pointer(&id); + + return 0; +} + +int halcc_interface_get_instance_id(halcc_interface *interface, const char **instance_id) +{ + if (!interface || !instance_id) + return -EINVAL; + + *instance_id = interface->instance_id; + + return 0; +} diff --git a/halcc/src/halcc-object.h b/halcc/src/halcc-object.h new file mode 100644 index 0000000..799b984 --- /dev/null +++ b/halcc/src/halcc-object.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HALCC_OBJECT_H__ +#define __HALCC_OBJECT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef enum halcc_manifest_type_e { + HALCC_MANIFEST_TYPE_NONE = 0, + HALCC_MANIFEST_TYPE_HAL_API, + HALCC_MANIFEST_TYPE_HAL_BACKEND, +} halcc_manifest_type_e; + +typedef enum halcc_transport_e { + HALCC_TRANSPORT_NONE = 0, + HALCC_TRANSPORT_PASSTHROUGH, + HALCC_TRANSPORT_IPC, +} halcc_transport_e; + +typedef enum halcc_dependency_state_e { + HALCC_DEPENDENCY_STATE_NONE = 0, + HALCC_DEPENDENCY_STATE_VALIDATING, + HALCC_DEPENDENCY_STATE_SUCCESS, + HALCC_DEPENDENCY_STATE_FAIL, +} halcc_dependency_state_e; + +typedef struct halcc_manifest halcc_manifest; +typedef struct halcc_hal halcc_hal; +typedef struct halcc_interface halcc_interface; + +typedef void (*halcc_iter_cb) (void *, void *); + +int halcc_manifest_new(halcc_manifest **manifest); +void halcc_manifest_free(halcc_manifest *manifest); +int halcc_manifest_set_type(halcc_manifest *manifest, halcc_manifest_type_e type); +int halcc_manifest_get_type(halcc_manifest *manifest, halcc_manifest_type_e *type); +int halcc_manifest_set_version(halcc_manifest *manifest, int major, int minor); +int halcc_manifest_get_version(halcc_manifest *manifest, int *major, int *minor); +int halcc_manifest_set_level(halcc_manifest *manifest, int level); +int halcc_manifest_get_level(halcc_manifest *manifest, int *level); +int halcc_manifest_add_hal(halcc_manifest *manifest, halcc_hal *hal); +int halcc_manifest_find_hal(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal); +int halcc_manifest_find_hal_raw(halcc_manifest *manifest, + halcc_hal *raw, halcc_hal **hal); +int halcc_manifest_find_hal_backward_compatible(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal); +int halcc_manifest_find_hal_backward_compatible_raw(halcc_manifest *manifest, + halcc_hal *raw, halcc_hal **hal); +int halcc_manifest_find_hal_forward_compatible(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal); +int halcc_manifest_find_hal_forward_compatible_raw(halcc_manifest *manifest, + halcc_hal *raw, halcc_hal **hal); +int halcc_manifest_steal_hal(halcc_manifest *manifest, + const char *hal_name, int major, int minor, halcc_hal **hal); +void halcc_manifest_remove_hal(halcc_manifest *manifest, + const char *hal_name, int major, int minor); +void halcc_manifest_foreach_hal(halcc_manifest *manifest, + halcc_iter_cb cb, void *user_data); + +int halcc_hal_new(halcc_hal **hal); +void halcc_hal_free(halcc_hal *hal); +int halcc_hal_set_name(halcc_hal *hal, const char *hal_name); +int halcc_hal_get_name(halcc_hal *hal, const char **hal_name); +int halcc_hal_set_version(halcc_hal *hal, int major, int min_minor, int max_minor); +int halcc_hal_get_version(halcc_hal *hal, int *major, int *min_minor, int *max_minor); +int halcc_hal_set_transport(halcc_hal *hal, halcc_transport_e transport); +int halcc_hal_get_transport(halcc_hal *hal, halcc_transport_e *transport); +int halcc_hal_add_dependency(halcc_hal *hal, halcc_hal *dependency); +void halcc_hal_remove_dependency(halcc_hal *hal, + const char *dependency_hal_name, int major, int minor); +void halcc_hal_foreach_dependency(halcc_hal *hal, halcc_iter_cb cb, void *user_data); +int halcc_hal_add_interface(halcc_hal *hal, halcc_interface *interface); +void halcc_hal_remove_interface(halcc_hal *hal, + const char *interface_name, const char *instance_id); +void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_data); + +int halcc_interface_new(halcc_interface **interface); +void halcc_interface_free(halcc_interface *interface); +int halcc_interface_set_name(halcc_interface *interface, const char *interface_name); +int halcc_interface_get_name(halcc_interface *interface, const char **interface_name); +int halcc_interface_set_instance_id(halcc_interface *interface, const char *instance_id); +int halcc_interface_get_instance_id(halcc_interface *interface, const char **instance_id); + +#ifdef __cplusplus +} +#endif + +#endif // __HALCC_OBJECT_H__ diff --git a/halcc/src/halcc-parser.c b/halcc/src/halcc-parser.c new file mode 100644 index 0000000..4b12c2f --- /dev/null +++ b/halcc/src/halcc-parser.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + + +#include "halcc-object.h" +#include "halcc-parser.h" +#include "halcc-util.h" + +#define HALCC_DESERIALIZER_VERSION_MAJOR 1 +#define HALCC_DESERIALIZER_VERSION_MINOR 0 + +#define __xmlchar__ __attribute__((__cleanup__(free_xmlstr))) + +static void free_xmlstr(unsigned char **str) +{ + xmlFree(*str); +} + +static int parse_interface(xmlNode *node, halcc_interface *interface) +{ + assert(node); + assert(interface); + + if (!xmlStrEqual(node->name, "interface")) { + printf("Invalid interface node, %s\n", node->name); + return -EINVAL; + } + + for (xmlNode *child = node->children; child; child = child->next) { + if (xmlStrEqual(child->name, "name")) { + __xmlchar__ xmlChar *name = xmlNodeGetContent(child); + halcc_interface_set_name(interface, name); + } else if (xmlStrEqual(child->name, "instance")) { + __xmlchar__ xmlChar *instance = xmlNodeGetContent(child); + halcc_interface_set_instance_id(interface, (char *) instance); + } + } + + return 0; +} + +static int parse_hal(xmlNode *node, halcc_hal *hal) +{ + int ret = 0; + + assert(node); + assert(hal); + + if (!xmlStrEqual(node->name, "hal")) { + printf("Invalid hal node, %s\n", node->name); + return -EINVAL; + } + + for (xmlNode *child = node->children; child; child = child->next) { + if (xmlStrEqual(child->name, "name")) { + __xmlchar__ xmlChar *name = xmlNodeGetContent(child); + + ret = halcc_hal_set_name(hal, name); + if (ret != 0) + printf("Failed to halcc_hal_set_name(), name=%s, ret=%d\n", name, ret); + } else if (xmlStrEqual(child->name, "version")) { + int major, min_minor, max_minor; + int scanned; + __xmlchar__ xmlChar *version = xmlNodeGetContent(child); + + scanned = sscanf(version, "%d.%d-%d", &major, &min_minor, &max_minor); + switch (scanned) { + case 2: // 3.5 is equal to 3.5-5 + max_minor = min_minor; + ret = halcc_hal_set_version(hal, major, min_minor, max_minor); + break; + case 3: // 3.5-8 + ret = halcc_hal_set_version(hal, major, min_minor, max_minor); + break; + default: + ret = -EINVAL; + break; + } + + if (ret != 0) + printf("Failed to halcc_hal_set_version(), ret=%d\n", ret); + } else if (xmlStrEqual(child->name, "transport")) { + __xmlchar__ xmlChar *transport = xmlNodeGetContent(child); + + if (xmlStrEqual(transport, "passthrough")) + ret = halcc_hal_set_transport(hal, HALCC_TRANSPORT_PASSTHROUGH); + else if (xmlStrEqual(transport, "IPC")) + ret = halcc_hal_set_transport(hal, HALCC_TRANSPORT_IPC); + else + ret = -EINVAL; + + if (ret != 0) + printf("Failed to halcc_hal_set_transport(), %s, ret=%d\n", transport, ret); + } else if (xmlStrEqual(child->name, "interface")) { + halcc_interface *iface; + + ret = halcc_interface_new(&iface); + if (ret != 0) { + printf("Failed to halcc_interface_new(), ret=%d\n", ret); + continue; + } + + ret = parse_interface(child, iface); + if (ret != 0) { + printf("Failed to parse_interface(), ret=%d\n", ret); + halcc_interface_free(iface); + continue; + } + + halcc_hal_add_interface(hal, iface); + iface = NULL; + } else if (xmlStrEqual(child->name, "dependency")) { + for (xmlNode *grand_child = child->children; grand_child; grand_child = grand_child->next) { + halcc_hal *h; + + if (!xmlStrEqual(grand_child->name, "hal")) + continue; + + ret = halcc_hal_new(&h); + if (ret != 0) + continue; + + ret = parse_hal(grand_child, h); + if (ret != 0) { + halcc_hal_free(h); + h = NULL; + continue; + } + + halcc_hal_add_dependency(hal, h); + h = NULL; + } + } + } + + return 0; +} + +static int parse_manifest(xmlNode *node, halcc_manifest *manifest) +{ + int ret; + xmlChar *prop; + int major; + int minor; + int level; + + assert(node); + assert(manifest); + + if (!xmlStrEqual(node->name, "manifest")) { + printf("Invalid manifest node, %s\n", node->name); + return -EINVAL; + } + + // version + prop = xmlGetProp(node, "version"); + if (!prop) { + printf("Failed to xmlGetProp() \"version\"\n"); + return -EINVAL; + } + + ret = sscanf(prop, "%d.%d", &major, &minor); + xmlFree(prop); + + if (ret != 2) { + printf("Failed to scan version, ret=%d\n", ret); + return -EINVAL; + } + + if (major != HALCC_DESERIALIZER_VERSION_MAJOR || minor != HALCC_DESERIALIZER_VERSION_MINOR) { + printf("Manifest scheme doesn't match. Requires manifest version %d.%d\n", + HALCC_DESERIALIZER_VERSION_MAJOR, HALCC_DESERIALIZER_VERSION_MINOR); + return -ENOTSUP; + } + + ret = halcc_manifest_set_version(manifest, major, minor); + if (ret != 0) { + printf("Failed to halcc_manifest_set_version(), ret=%d\n", ret); + return -EINVAL; + } + + // type + prop = xmlGetProp(node, "type"); + if (!prop) { + printf("Failed to xmlGetProp() \"type\"\n"); + return -EINVAL; + } + + if (xmlStrEqual(prop, "platform")) { + ret = halcc_manifest_set_type(manifest, HALCC_MANIFEST_TYPE_HAL_API); + if (ret != 0) + printf("Failed to halcc_manifest_set_type() HALCC_MANIFEST_TYPE_HAL_API, ret=%d\n", ret); + } else if (xmlStrEqual(prop, "device")) { + ret = halcc_manifest_set_type(manifest, HALCC_MANIFEST_TYPE_HAL_BACKEND); + if (ret != 0) + printf("Failed to halcc_manifest_set_type() HALCC_MANIFEST_TYPE_HAL_BACKEND, ret=%d\n", ret); + } else { + printf("Invalid type property=%s\n", prop); + ret = -EINVAL; + } + + xmlFree(prop); + + if (ret != 0) + return ret; + + // level + prop = xmlGetProp(node, "level"); + if (!prop) { + printf("Failed to xmlGetProp() \"level\"\n"); + return -EINVAL; + } + + ret = sscanf(prop, "%d", &level); + xmlFree(prop); + + if (ret != 1) { + printf("Failed to scan manifest level\n"); + return -EINVAL; + } + + ret = halcc_manifest_set_level(manifest, level); + if (ret != 0) { + printf("Failed to halcc_manifest_set_level(), ret=%d\n", ret); + return ret; + } + + for (xmlNode *child = node->children; child; child = child->next) { + halcc_hal *h; + + if (!xmlStrEqual(child->name, "hal")) + continue; + + ret = halcc_hal_new(&h); + if (ret != 0) { + printf("Failed to halcc_hal_new(), ret=%d\n", ret); + continue; + } + + ret = parse_hal(child, h); + if (ret != 0) { + printf("Failed to parse_hal(), ret=%d\n", ret); + halcc_hal_free(h); + h = NULL; + continue; + } + + halcc_manifest_add_hal(manifest, h); + h = NULL; + } + + return 0; +} + + +static int parse_xml_doc(xmlDoc *doc, halcc_manifest *manifest) +{ + xmlNode *root = NULL; + int ret; + + if (!doc || !manifest) + return -EINVAL; + + root = xmlDocGetRootElement(doc); + if (!root) { + printf("Failed to get root element\n"); + return -EINVAL; + } + + ret = parse_manifest(root, manifest); + if (ret != 0) { + printf("Failed to parse_manifest(), ret=%d\n", ret); + return ret; + } + + return 0; +} + +int halcc_parse_fd(int fd, halcc_manifest *manifest) +{ + xmlDoc *doc = NULL; + int ret = 0; + + if (!manifest) { + printf("Invalid manifest\n"); + return -EINVAL; + } + + doc = xmlReadFd(fd, NULL, NULL, 0); + if (!doc) { + printf("Failed to read doc %d\n", fd); + return -ENOENT; + } + + ret = parse_xml_doc(doc, manifest); + + xmlFreeDoc(doc); + + return ret; +} + +int halcc_parse_path(const char *filepath, halcc_manifest *manifest) +{ + xmlDoc *doc = NULL; + int ret = 0; + + if (!filepath || !manifest) { + printf("Invalid filepath or manifest\n"); + return -EINVAL; + } + + doc = xmlReadFile(filepath, NULL, 0); + if (!doc) { + printf("Failed to read doc %s\n", filepath); + return -ENOENT; + } + + ret = parse_xml_doc(doc, manifest); + + xmlFreeDoc(doc); + + return ret; +} + +int halcc_parse_string(const char *string, int len, halcc_manifest *manifest) +{ + xmlDoc *doc = NULL; + int ret = 0; + + if (!string || !manifest) { + printf("Invalid string or manifest\n"); + return -EINVAL; + } + + doc = xmlReadMemory(string, len, NULL, NULL, 0); + if (!doc) { + printf("Failed to read xml string\n"); + return -ENOENT; + } + + ret = parse_xml_doc(doc, manifest); + + xmlFreeDoc(doc); + + return ret; +} diff --git a/halcc/src/halcc-parser.h b/halcc/src/halcc-parser.h new file mode 100644 index 0000000..4bc8c2b --- /dev/null +++ b/halcc/src/halcc-parser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HALCC_PARSER_H__ +#define __HALCC_PARSER_H__ + +#include "halcc-object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int halcc_parse_fd(int fd, halcc_manifest *manifest); +int halcc_parse_path(const char *filepath, halcc_manifest *manifest); +int halcc_parse_string(const char *string, int len, halcc_manifest *manifest); + +#ifdef __cplusplus +} +#endif + +#endif // __HALCC_PARSER_H__ diff --git a/halcc/src/halcc-util.c b/halcc/src/halcc-util.c new file mode 100644 index 0000000..eeb96e8 --- /dev/null +++ b/halcc/src/halcc-util.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "halcc-util.h" + +int halcc_util_set_int_once(void *buf, int value, const char *buf_desc) +{ + int old_value; + + if (!buf) + return -EINVAL; + + old_value = *(int *) buf; + + if (old_value != HALCC_UNINITIALIZED_INT && old_value != value) { + printf("Cannot modify initialized value, %s, %d to %d\n", + buf_desc ? : "Unknown", old_value, value); + return -EALREADY; + } + + *(int *) buf = value; + + return 0; +} diff --git a/halcc/src/halcc-util.h b/halcc/src/halcc-util.h new file mode 100644 index 0000000..80b9f25 --- /dev/null +++ b/halcc/src/halcc-util.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HALCC_UTIL_H__ +#define __HALCC_UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXPORT __attribute__((visibility("default"))) +#define HALCC_NAME_MAX 128 +#define HALCC_UNINITIALIZED_INT (-1) + +/** + * Modifies buffer pointed by 'buf' to 'value' only when the buffer + * has value of HALCC_UNINITIALIZED_INT. Once it has changed to value other + * than HALCC_UNINITIALIZED_INT and trying to change the value, the buffer + * remains unchanged and this function returns -EALREADY. + */ +int halcc_util_set_int_once(void *buf, int value, const char *buf_desc); + +#ifdef __cplusplus +} +#endif + +#endif // __HALCC_UTIL_H__ diff --git a/packaging/hal-api-common.pc.in b/packaging/hal-api-common.pc.in index 782a604..e5bca25 100644 --- a/packaging/hal-api-common.pc.in +++ b/packaging/hal-api-common.pc.in @@ -4,13 +4,14 @@ package_name=hal-api-common prefix=@PREFIX@ exec_prefix=@EXEC_PREFIX@/hal libdir=@LIBDIR@/hal -includedir=@INCLUDEDIR@/hal +include_halapi_dir=@INCLUDEDIR@/hal +include_halcc_dir=@INCLUDEDIR@/halcc Name: ${package_name} Description: ${package_name} interface Version: @VERSION@ Requires: -Libs: -L${libdir} -l${package_name} -Cflags: -I${includedir} -CXXflags: -I${includedir} +Libs: -L${libdir} -l${package_name} -lhalcc +Cflags: -I${include_halapi_dir} -I${include_halcc_dir} +CXXflags: -I${include_halapi_dir} -I${include_halcc_dir} diff --git a/packaging/hal-api-common.spec b/packaging/hal-api-common.spec index 058f19c..e728d5f 100644 --- a/packaging/hal-api-common.spec +++ b/packaging/hal-api-common.spec @@ -26,6 +26,7 @@ BuildRequires: cmake BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(gio-2.0) BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(gmock) BuildRequires: pkgconfig(systemd) @@ -112,6 +113,7 @@ systemd-tmpfiles /usr/lib/tmpfiles.d/hal-rpmdb-checker.conf --create %files -n %{devel_name} %defattr(-,root,root,-) %{_includedir}/hal/*.h +%{_includedir}/halcc/*.h %{_libdir}/pkgconfig/*.pc %{_sysconfdir}/rpm/macros.hal-api diff --git a/tests/unittest/CMakeLists.txt b/tests/unittest/CMakeLists.txt index 90dff51..b2c4e7b 100644 --- a/tests/unittest/CMakeLists.txt +++ b/tests/unittest/CMakeLists.txt @@ -1,18 +1,22 @@ ENABLE_TESTING() SET(HAL_API_COMMON_UNITTEST "hal-api-common-unittest") -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Werror") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Werror -Wno-pointer-sign") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++14 -Wall -Werror") +#INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/halcc/include) + AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ UNITTEST_SRCS) -ADD_EXECUTABLE(${HAL_API_COMMON_UNITTEST} ${UNITTEST_SRCS}) +AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/halcc/src/ LIBHALCC_SRCS) +ADD_EXECUTABLE(${HAL_API_COMMON_UNITTEST} ${UNITTEST_SRCS} ${LIBHALCC_SRCS}) TARGET_INCLUDE_DIRECTORIES(${HAL_API_COMMON_UNITTEST} PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/../../include" + "${CMAKE_SOURCE_DIR}/include" + "${CMAKE_SOURCE_DIR}/halcc/include" ) INCLUDE(FindPkgConfig) -pkg_check_modules(hal_api_common_unittest_pkgs REQUIRED gmock) +pkg_check_modules(hal_api_common_unittest_pkgs REQUIRED gmock glib-2.0 libxml-2.0) FOREACH(flag ${hal_api_common_unittest_pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/tests/unittest/test-hal-compatibility-checker.cc b/tests/unittest/test-hal-compatibility-checker.cc new file mode 100644 index 0000000..5c1bee6 --- /dev/null +++ b/tests/unittest/test-hal-compatibility-checker.cc @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include "../../halcc/src/halcc-object.h" +#include "../../halcc/src/halcc-parser.h" + +using namespace std; + +static char g_manifest_xml[] = +"" +" " +" hal.device.display" +" 1.5" +" passthrough" +" " +" hal_backend_device_display_data" +" " +" " +" " +" hal.device.board" +" 1.0" +" passthrough" +" " +" hal_backend_device_board_data" +" " +" " +" " +" hal.tdm" +" 1.0" +" passthrough" +" " +" hal_backend_tdm_data" +" " +" " +" " +" " +" " +" hal.something" +" 2.34" +" passthrough" +" " +" hal_backend_something_data" +" " +" " +" " +" hal.test" +" 4.8" +" passthrough" +" " +" hal_backend_test_data" +" " +" " +""; + +class HalccObjectTest : public ::testing::Test +{ + protected: + static void SetUpTestSuite() { + int ret; + + ret = halcc_manifest_new(&g_manifest); + ASSERT_EQ(ret, 0); + + ret = halcc_parse_string(g_manifest_xml, sizeof(g_manifest_xml), g_manifest); + ASSERT_EQ(ret, 0); + + ret = halcc_manifest_find_hal(g_manifest, "hal.test", 4, 8, &g_hal); + ASSERT_EQ(ret, 0); + } + + static void TearDownTestSuite() { + halcc_manifest_free(g_manifest); + g_manifest = NULL; + + } + + void SetUp() override { + + } + + void TearDown() override { + + } + + static halcc_manifest *g_manifest; + static halcc_hal *g_hal; + static halcc_interface *g_interface; +}; + +halcc_manifest* HalccObjectTest::g_manifest = NULL; +halcc_hal* HalccObjectTest::g_hal = NULL; +halcc_interface* HalccObjectTest::g_interface = NULL; + +TEST_F(HalccObjectTest, manifest_get_type) +{ + halcc_manifest_type_e type; + int ret; + + ret = halcc_manifest_get_type(g_manifest, &type); + ASSERT_EQ(ret, 0); + ASSERT_EQ(type, HALCC_MANIFEST_TYPE_HAL_API); +} + +TEST_F(HalccObjectTest, manifest_get_version) +{ + int major, minor; + int ret; + + ret = halcc_manifest_get_version(g_manifest, &major, &minor); + ASSERT_EQ(ret, 0); + ASSERT_EQ(major, 1); + ASSERT_EQ(minor, 0); +} + +TEST_F(HalccObjectTest, manifest_get_level) +{ + int level; + int ret; + + ret = halcc_manifest_get_level(g_manifest, &level); + ASSERT_EQ(ret, 0); + ASSERT_EQ(level, 7); +} + +TEST_F(HalccObjectTest, manifest_find_hal_success) +{ + halcc_hal *hal = NULL; + int ret; + + ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 1, 5, &hal); + ASSERT_EQ(ret, 0); +} + +TEST_F(HalccObjectTest, manifest_find_hal_fail) +{ + halcc_hal *hal = NULL; + int ret; + + ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 1, 4, &hal); + ASSERT_EQ(ret, -ENOTSUP); + + ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 1, 6, &hal); + ASSERT_EQ(ret, -ENOTSUP); + + ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 2, 4, &hal); + ASSERT_EQ(ret, -ENOTSUP); +} + +TEST_F(HalccObjectTest, manifest_find_hal_backward_compatible_success) +{ + halcc_hal *hal = NULL; + int ret; + + ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 5, &hal); + ASSERT_EQ(ret, 0); + + ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 6, &hal); + ASSERT_EQ(ret, 0); + + ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 100, &hal); + ASSERT_EQ(ret, 0); +} + +TEST_F(HalccObjectTest, manifest_find_hal_backward_compatible_fail) +{ + halcc_hal *hal = NULL; + int ret; + + ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 4, &hal); + ASSERT_EQ(ret, -ENOTSUP); + + ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 2, 4, &hal); + ASSERT_EQ(ret, -ENOTSUP); + + ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 2, 5, &hal); + ASSERT_EQ(ret, -ENOTSUP); +} + +TEST_F(HalccObjectTest, manifest_find_hal_steal_success) +{ + halcc_hal *hal = NULL; + const char *hal_name; + int major, minor; + int ret; + + ret = halcc_manifest_steal_hal(g_manifest, "hal.something", 2, 34, &hal); + ASSERT_EQ(ret, 0); + + ret = halcc_hal_get_name(hal, &hal_name); + ASSERT_EQ(ret, 0); + ASSERT_STREQ(hal_name, "hal.something"); + + ret = halcc_hal_get_version(hal, &major, &minor, NULL); + ASSERT_EQ(ret, 0); + ASSERT_EQ(major, 2); + ASSERT_EQ(minor, 34); + + // Shouldn't be there + ret = halcc_manifest_find_hal(g_manifest, "hal.something", 2, 34, &hal); + ASSERT_EQ(ret, -ENOTSUP); + + ret = halcc_manifest_add_hal(g_manifest, hal); + ASSERT_EQ(ret, 0); + + ret = halcc_manifest_find_hal(g_manifest, "hal.something", 2, 34, &hal); + ASSERT_EQ(ret, 0); + + ret = halcc_hal_get_name(hal, &hal_name); + ASSERT_EQ(ret, 0); + ASSERT_STREQ(hal_name, "hal.something"); + + ret = halcc_hal_get_version(hal, &major, &minor, NULL); + ASSERT_EQ(ret, 0); + ASSERT_EQ(major, 2); + ASSERT_EQ(minor, 34); +} -- 2.7.4