From: Youngjae Cho Date: Thu, 11 Apr 2024 03:30:37 +0000 (+0900) Subject: halapi: Add function checking all of the HAL compatibility X-Git-Tag: accepted/tizen/unified/20240611.122614~31 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6e0aedbb65029691428a719ebac813b7a070633c;p=platform%2Fhal%2Fapi%2Fcommon.git halapi: Add function checking all of the HAL compatibility Previously, the API provides callbacks that give responsibility to the caller that storing compatibility result in their own way. However, to provide a unified way of storing and loading HAL compatibility, hal-api-common has become responsible for storing and loading compatibility in a unified manner. int hal_common_check_backend_compatibility_all() : It gets compatibility of all the hal modules. Additionally, it stores compatibility of all modules to backing storage if there hasn't been for later use. Currently, the result is stored in /opt/etc/hal/.hal-compatibility and the below is an example of result generated by hal-compatibility-checker: root:/opt/etc/hal> cat .hal-compatibility 0:Not defined:0:Manifest hasn't specified the module 1:HAL_MODULE_TBM:0:Manifest hasn't specified the module 2:HAL_MODULE_TDM:0:Manifest hasn't specified the module ... 26:HAL_MODULE_DEVICE_DISPLAY:2:Compatible 27:HAL_MODULE_DEVICE_IR:0:Manifest hasn't specified the module 28:HAL_MODULE_DEVICE_TOUCHSCREEN:1:Backend has incompatible version 29:HAL_MODULE_DEVICE_LED:2:Compatible 30:HAL_MODULE_DEVICE_BOARD:0:Manifest hasn't specified the module ... It has foramt of "{index}:{module_name}:{compatibility}:{description}" The tool hal-compatibility-checker, therefore, has changed to just call the API, and removed callback code. Change-Id: I4e1319bb98c81e1389e22924ae4ed70a66e46f7b Signed-off-by: Youngjae Cho --- diff --git a/include/hal-common.h b/include/hal-common.h index 4243829..9a9dced 100644 --- a/include/hal-common.h +++ b/include/hal-common.h @@ -218,24 +218,13 @@ int hal_common_get_backend_library_names(enum hal_module module, int library_name_size); - /** - * @brief Called for every hal backend module. - * @param[out] module HAL module - * @param[out] compatibility Compatibility of the HAL module - * @param[out] user_data The user data passed from the callback registration function - */ -typedef void (*hal_common_backend_compatibility_cb) (enum hal_module module, - enum hal_common_backend_compatibility compatibility, void *user_data); - -/** - * @brief Check version compatibility of modules specified in manifests. - * @param[in] manifest_dir Directory of manifest files - * @param[in] callback Callback for each specified module - * @param[in] user_data The user data to be passed to the callback function + * @brief Check version compatibility of modules specified in manifests and stores its result + * @param[out] arr_compatibility Pointer for storing array of compatibilities about all modules. The data is owned by caller, so it is responsible for caller to free it using free() + * @param[out] len Pointer for retrieving length of array + * @return @c 0 on success, otherwise a negative error value */ -int hal_common_check_backend_compatibility(const char *manifest_dir, - hal_common_backend_compatibility_cb callback, void *user_data); +int hal_common_check_backend_compatibility_all(enum hal_common_backend_compatibility **arr_compatibility, int *len); #ifdef __cplusplus } diff --git a/src/hal-api-compatibility-checker.c b/src/hal-api-compatibility-checker.c index f0ca812..660e4fb 100644 --- a/src/hal-api-compatibility-checker.c +++ b/src/hal-api-compatibility-checker.c @@ -17,23 +17,92 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include "common.h" +#include "hal-api-list.h" #include "hal-api-compatibility-checker-object.h" #include "hal-api-compatibility-checker-parser.h" #include "hal-api-compatibility-checker-util.h" -struct callback_data { - hal_common_backend_compatibility_cb func; - void *user_data; +#define HAL_COMMON_DEFAULT_HAL_INFO_INI "/hal/etc/hal-info.ini" +#define HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH "/opt/etc/hal/.hal-backend-compatibility" + +#define COMPAT_INFO_MODULE_NAME_MAX 64 +#define COMPAT_INFO_COMPAT_DESC_MAX 64 +#define COMPAT_INFO_FILE_ALIGN_BYTE ((COMPAT_INFO_MODULE_NAME_MAX + COMPAT_INFO_COMPAT_DESC_MAX) + 32) + +struct compatibility_info { + enum hal_module module; + char module_name[COMPAT_INFO_MODULE_NAME_MAX]; + enum hal_common_backend_compatibility compat; + char compat_desc[COMPAT_INFO_COMPAT_DESC_MAX]; }; +static struct compatibility_info g_compatibility_info[HAL_MODULE_END]; +static bool g_compatibility_info_loaded = false; + +static void set_compatibility_info_compat(enum hal_module module, + enum hal_common_backend_compatibility compat, const char *desc) +{ + if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) + return; + + g_compatibility_info[module].compat = compat; + + if (!desc) + return; + + snprintf(g_compatibility_info[module].compat_desc, + COMPAT_INFO_COMPAT_DESC_MAX, "%s", desc); +} + +static void init_compatibility_info(enum hal_module module) +{ + if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) + return; + + g_compatibility_info[module].module = module; + snprintf(g_compatibility_info[module].module_name, COMPAT_INFO_MODULE_NAME_MAX, + "%s", g_hal_module_info[module].module_name ? : "Not defined"); + set_compatibility_info_compat(module, HAL_COMMON_BACKEND_COMPATIBILITY_UNKNOWN, + "Manifest hasn't specified the module"); +} + +static int write_compatibility_info(int fd, enum hal_module module) +{ + char buffer[COMPAT_INFO_FILE_ALIGN_BYTE] = { 0 , }; + struct compatibility_info *ci = NULL; + ssize_t ret; + int len = 0; + + if (fd == -1) + return -EINVAL; + + if (module < HAL_MODULE_UNKNOWN || module >= HAL_MODULE_END) + return -EINVAL; + + ci = &g_compatibility_info[module]; + + len = snprintf(buffer, sizeof(buffer), "%d:%s:%d:%s\n", + ci->module, ci->module_name, ci->compat, ci->compat_desc); + + ret = write(fd, buffer, len); + if (ret == -1) + return -errno; + + return 0; +} + static int parse_directory(const char *manifest_dir, halcc_manifest *manifest) { DIR *dir; @@ -45,7 +114,7 @@ static int parse_directory(const char *manifest_dir, halcc_manifest *manifest) dir = opendir(manifest_dir); if (!dir) { - printf("Failed to opendir '%s', %m\n", manifest_dir); + _E("Failed to opendir '%s', %m\n", manifest_dir); return -errno; } @@ -60,13 +129,13 @@ static int parse_directory(const char *manifest_dir, halcc_manifest *manifest) fd = openat(dfd, entry->d_name, O_RDONLY); if (fd < 0) { - printf("Failed to openat(), %m\n"); + _E("Failed to openat(), %m\n"); continue; } ret = halcc_parse_fd(fd, manifest); if (ret < 0) { - printf("Failed to parse xml, ret=%d\n", ret); + _E("Failed to parse xml, ret=%d\n", ret); close(fd); continue; } @@ -79,105 +148,218 @@ static int parse_directory(const char *manifest_dir, halcc_manifest *manifest) return 0; } -static enum hal_common_backend_compatibility is_compatible(int platform_major, int platform_minor, +static enum hal_common_backend_compatibility is_compatible(int manifest_major, int manifest_minor, int backend_major, int backend_minor) { - if (platform_major != backend_major) + if (manifest_major != backend_major) return HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE; - if (platform_minor < backend_minor) + if (manifest_minor < backend_minor) return HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE; return HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE; } -static void foreach_hal(void *data, void *user_data) +static void make_compatibility_info(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; + int manifest_major, manifest_minor; + int backend_major, backend_minor; halcc_dependency_state_e state; - enum hal_common_backend_compatibility compatible = HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE; + int ret; + enum hal_common_backend_compatibility compat = HAL_COMMON_BACKEND_COMPATIBILITY_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; - - if (halcc_hal_get_dependency_state(hal, &state) != 0) - return; - - if (state != HALCC_DEPENDENCY_STATE_SUCCESS) - return; - for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) { char module_name[128] = { 0 , }; - int backend_major, backend_minor; - 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; + if (ret == 0) + break; + } - ret = hal_common_get_backend_version(module, &backend_major, &backend_minor); - if (ret != 0) - continue; + if (module >= HAL_MODULE_END) { + _E("Unknown hal module: %s\n", hal_name); + return; + } - compatible = is_compatible(major, minor, backend_major, backend_minor); - break; + if (halcc_hal_get_dependency_state(hal, &state) != 0) { + set_compatibility_info_compat(module, + HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE, + "Manifest failed to resolve dependency"); + return; } - if (module >= HAL_MODULE_END) { - printf("Unknown hal module: %s\n", hal_name); + if (halcc_hal_get_version(hal, &manifest_major, &manifest_minor, NULL) < 0) { + set_compatibility_info_compat(module, + HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE, + "Manifest has invalid version"); return; } - printf("%s: %s\n", hal_name, compatible ? "Compatible" : "Incompatible"); + ret = hal_common_get_backend_version(module, &backend_major, &backend_minor); + if (ret != 0) { + set_compatibility_info_compat(module, + HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE, + "Backend has invalid version"); + return; + } - callback_data->func(module, compatible, callback_data->user_data); + compat = is_compatible(manifest_major, manifest_minor, backend_major, backend_minor); + if (compat == HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE) + set_compatibility_info_compat(module, + HAL_COMMON_BACKEND_COMPATIBILITY_COMPATIBLE, + "Compatible"); + else + set_compatibility_info_compat(module, + HAL_COMMON_BACKEND_COMPATIBILITY_INCOMPATIBLE, + "Backend has incompatible version"); } -EXPORT -int hal_common_check_backend_compatibility(const char *hal_api_manifest_dir, - hal_common_backend_compatibility_cb callback, void *user_data) +static int get_tizen_hal_version(int *major, int *minor) { - halcc_manifest *manifest = NULL; - struct callback_data callback_data = { 0 , }; - int ret = 0; + FILE *fp = NULL; + char *line = NULL; + size_t len = 0; + int found = 0; - if (!hal_api_manifest_dir) + assert(major); + assert(minor); + + fp = fopen(HAL_COMMON_DEFAULT_HAL_INFO_INI, "r"); + if (!fp) { + _E("Failed to open %s, %m\n", HAL_COMMON_DEFAULT_HAL_INFO_INI); + return -errno; + } + + while (getline(&line, &len, fp) != EOF) { + if (fscanf(fp, "Model=Tizen%d.%d", major, minor) == 2) { + found = 1; + break; + } + } + + fclose(fp); + fp = NULL; + free(line); + line = NULL; + + return found ? 0 : -EINVAL; +} + +static int build_compatibility_manifest_dir(char *manifest_dir, int len) +{ + int manifest_major = 0; + int manifest_minor = 0; + int ret; + + if (!manifest_dir || len <= 0) return -EINVAL; - if (!callback) + ret = get_tizen_hal_version(&manifest_major, &manifest_minor); + if (ret != 0) { + _E("Failed to get hal version, ret=%d\n", ret); + return ret; + } + + ret = snprintf(manifest_dir, len, "/etc/hal/%d.%d", manifest_major, manifest_minor); + if (ret >= len) { + _E("Buffer is too small for manifest directory\n"); + return -EOVERFLOW; + } + + return 0; +} + +static int set_owner(int fd) +{ + static uid_t uid_system_fw = -1; + static gid_t gid_system_fw = -1; + + if (fd == -1) return -EINVAL; + if (uid_system_fw == -1) { + struct passwd *p = getpwnam("system_fw"); + if (!p) + return -errno; + + uid_system_fw = p->pw_uid; + } + + if (gid_system_fw == -1) { + struct group *g = getgrnam("system_fw"); + if (!g) + return -errno; + + gid_system_fw = g->gr_gid; + } + + return fchown(fd, uid_system_fw, gid_system_fw); +} + +static void store_backend_compatibility_to_storage(void) +{ + int fd = -1; + int ret; + + assert(g_compatibility_info_loaded); + + fd = open(HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) + return; + + ret = set_owner(fd); // system_fw:system_fw + if (ret != 0) { + close(fd); + return; + } + + for (enum hal_module module = 0; module < HAL_MODULE_END; ++module) + write_compatibility_info(fd, module); + + close(fd); +} + +static int load_backend_compatibility_from_manifest(void) +{ + char manifest_dir[64] = { 0, }; + halcc_manifest *manifest = NULL; + int ret = 0; + + ret = build_compatibility_manifest_dir(manifest_dir, sizeof(manifest_dir)); + if (ret != 0) + return ret; + ret = halcc_manifest_new(&manifest); if (ret < 0) return ret; - ret = parse_directory(hal_api_manifest_dir, manifest); + ret = parse_directory(manifest_dir, manifest); if (ret < 0) goto out; halcc_manifest_validate_hal_dependency(manifest); - callback_data = (struct callback_data) { callback, user_data }; + g_compatibility_info_loaded = false; + + for (enum hal_module module = 0; module < HAL_MODULE_END; ++module) + init_compatibility_info(module); + halcc_manifest_foreach_hal(manifest, make_compatibility_info, NULL); - halcc_manifest_foreach_hal(manifest, foreach_hal, &callback_data); + g_compatibility_info_loaded = true; out: if (manifest) @@ -185,3 +367,87 @@ out: return ret; } + +static int load_backend_compatibility_from_storage(void) +{ + FILE *fp = NULL; + char *line = NULL; + size_t len = 0; + enum hal_module module; + int ret; + + if (g_compatibility_info_loaded) + return 0; + + fp = fopen(HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH, "r"); + if (!fp) + return -errno; + + for (module = 0; module < HAL_MODULE_END; ++module) + init_compatibility_info(module); + + module = 0; + while (getline(&line, &len, fp) != EOF) { + struct compatibility_info *ci = NULL; + + if (module >= HAL_MODULE_END) + break; + + ci = &g_compatibility_info[module++]; + ret = sscanf(line, "%d:%63[^:]:%d:%63s", + (int *) &ci->module, ci->module_name, (int *) &ci->compat, ci->compat_desc); + if (ret != 4) + _E("Failed to load %d module", module); + } + + free(line); + line = NULL; + fclose(fp); + fp = NULL; + + g_compatibility_info_loaded = true; + + return 0; +} + +EXPORT +int hal_common_check_backend_compatibility_all(enum hal_common_backend_compatibility **arr_compatibility, int *len) +{ + enum hal_common_backend_compatibility *arr = NULL; + + if (g_compatibility_info_loaded) + goto load_success; + + load_backend_compatibility_from_storage(); + if (g_compatibility_info_loaded) + goto load_success; + + load_backend_compatibility_from_manifest(); + if (g_compatibility_info_loaded) + goto load_success; + + return -ENODATA; + +load_success: + if (access(HAL_COMMON_DEFAULT_BACKEND_COMPATIBILITY_PATH, F_OK) != 0) + store_backend_compatibility_to_storage(); + + if (!arr_compatibility) + return 0; + + if (!len) + return -EINVAL; + + arr = calloc(HAL_MODULE_END, sizeof(enum hal_common_backend_compatibility)); + if (!arr) + return -ENOMEM; + + for (int i = 0; i < HAL_MODULE_END; ++i) + arr[i] = g_compatibility_info[i].compat; + + *len = HAL_MODULE_END; + *arr_compatibility = arr; + arr = NULL; + + return 0; +} diff --git a/tools/hal-compatibility-checker/main.c b/tools/hal-compatibility-checker/main.c index 13f345d..8ec6790 100644 --- a/tools/hal-compatibility-checker/main.c +++ b/tools/hal-compatibility-checker/main.c @@ -39,7 +39,6 @@ enum { OPT_START = 0, OPT_HELP = OPT_START, - OPT_PLATFORM, OPT_SKIP_IF_RESULT_EXIST, OPT_REDIRECT_ALL, OPT_REDIRECT_STDOUT, @@ -51,9 +50,6 @@ static const struct option long_option[] = { [OPT_HELP] = { "help", no_argument, NULL, 'h' }, - [OPT_PLATFORM] - = { "platform", required_argument, NULL, 'p' }, - [OPT_SKIP_IF_RESULT_EXIST] = { "skip-if-result-exist", optional_argument, NULL, 0 }, @@ -99,22 +95,6 @@ static int get_tizen_hal_version(int *major, int *minor) return found ? 0 : -EINVAL; } -static const char* default_platform_manifest_dir(void) -{ - static char dirpath[HCC_BUF_MAX] = { 0 , }; - int major; - int minor; - int ret; - - ret = get_tizen_hal_version(&major, &minor); - if (ret != 0) - return NULL; - - snprintf(dirpath, sizeof(dirpath), DEFAULT_PLATFORM_MANIFEST_DIR"/%d.%d", major, minor); - - return dirpath; -} - // check result is exist, return true on exist. static bool result_exist(const char *dir) { @@ -161,10 +141,6 @@ static void show_help(void) "\t-h, --help\n" "\t\tshow this help.\n" "\n" - "\t-p, --platform=DIRECTORY\n" - "\t\tspecify directory that holds platform manifest xml\n" - "\t\twhen it is not specified, use default path: %s\n" - "\n" "\t--skip-if-result-exist[=DIRECTORY]\n" "\t\tskip compatibility check if there exists a result of compatibility.\n" "\t\tif DIRECTORY is given, locate a result based on the given DIRECTORY.\n" @@ -177,16 +153,9 @@ static void show_help(void) "\n" "\t--redirect-stderr=FILE|dlog\n" "\t\tredirect stderr to FILE or dlog with tag "LOG_TAG_HAL_COMPATIBILITY_CHECKER".\n" - , default_platform_manifest_dir() ); } -static void compatibility_cb(enum hal_module module, - enum hal_common_backend_compatibility is_compatible, void *user_data) -{ - // do something -} - int main(int argc, char *argv[]) { int opt; @@ -199,7 +168,7 @@ int main(int argc, char *argv[]) const char *errfile = NULL; for (;;) { - opt = getopt_long(argc, argv, "hp:", long_option, &index); + opt = getopt_long(argc, argv, "h", long_option, &index); if (opt == -1) break; @@ -207,9 +176,6 @@ int main(int argc, char *argv[]) case 'h': help = 1; break; - case 'p': - platform_manifest_dir = optarg; - break; case 0: // long-only options { switch (index) { @@ -254,10 +220,8 @@ int main(int argc, char *argv[]) return 0; } - if (!platform_manifest_dir) - platform_manifest_dir = default_platform_manifest_dir(); - - hal_common_check_backend_compatibility(platform_manifest_dir, compatibility_cb, NULL); + // Not for getting result, but for storing result to backing storage + hal_common_check_backend_compatibility_all(NULL, NULL); return 0; }