From: SangYoun Kwak Date: Tue, 22 Apr 2025 06:20:20 +0000 (+0900) Subject: [WIP]test X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=558ace0c4c6cd868fc675fee2c17ef977f189b32;p=platform%2Fhal%2Fapi%2Fcommon.git [WIP]test Change-Id: Id54a3f9984e180c580d17fc14dbdefe3b0f623f4 Signed-off-by: SangYoun Kwak --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 0553a4a..084ed0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,5 +79,6 @@ ADD_SUBDIRECTORY(tools/hal-compatibility-checker) endif() if (${ENABLE_HAL_BACKEND_SERVICE}) -ADD_SUBDIRECTORY(hal-backend-service) +ADD_SUBDIRECTORY(hal-backend-service-with-dbus) +ADD_SUBDIRECTORY(hal-backend-service-without-dbus) endif() diff --git a/hal-backend-service-with-dbus/CMakeLists.txt b/hal-backend-service-with-dbus/CMakeLists.txt new file mode 100644 index 0000000..925d7cb --- /dev/null +++ b/hal-backend-service-with-dbus/CMakeLists.txt @@ -0,0 +1,23 @@ +PROJECT(hal-backend-service C) + +INCLUDE(FindPkgConfig) +pkg_check_modules(gtest_pkgs REQUIRED dbus-1) + +FOREACH(flag ${gtest_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -fPIC") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -Wl,-z,relro") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -lrt") +SET(CMAKE_EXE_LINKER_FLAGS "-pie") + +SET(EXEC_NAME "${PROJECT_NAME}-with-dbus") +SET(src ${CMAKE_SOURCE_DIR}/hal-backend-service-with-dbus/hal-backend-service.c) +ADD_EXECUTABLE(${EXEC_NAME} ${src}) +TARGET_LINK_LIBRARIES(${EXEC_NAME} ${gtest_LDFLAGS} ${gtest_pkgs_LDFLAGS} -ldl -L${LIBDIR}/hal) +INSTALL(TARGETS ${EXEC_NAME} DESTINATION /usr/bin/hal) + +INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION lib/systemd/system + FILES_MATCHING PATTERN "hal-backend-service-with-dbus.service") diff --git a/hal-backend-service-with-dbus/config/hal-backend-service-config-da.json b/hal-backend-service-with-dbus/config/hal-backend-service-config-da.json new file mode 100644 index 0000000..d0e2aff --- /dev/null +++ b/hal-backend-service-with-dbus/config/hal-backend-service-config-da.json @@ -0,0 +1,26 @@ +{ + "process": [ + { + "type": "systemd", + "property": { + "name": "hal-backend-service" + }, + "thread": [ + { "hal_module_name": [ "device_display" ] }, + { "hal_module_name": [ "device_led" ] }, + { "hal_module_name": [ "device_battery" ] }, + { "hal_module_name": [ "device_bezel" ] }, + { "hal_module_name": [ "device_external_connection" ] } + ] + }, + { + "type": "systemd", + "property": { + "name": "hal-backend-service-codec" + }, + "thread": [ + { "hal_module_name": [ "codec" ] } + ] + } + ] +} diff --git a/hal-backend-service-with-dbus/config/hal-backend-service-config-vd.json b/hal-backend-service-with-dbus/config/hal-backend-service-config-vd.json new file mode 100644 index 0000000..e69de29 diff --git a/hal-backend-service-with-dbus/config/hal-backend-service-config.json b/hal-backend-service-with-dbus/config/hal-backend-service-config.json new file mode 100644 index 0000000..1f47f21 --- /dev/null +++ b/hal-backend-service-with-dbus/config/hal-backend-service-config.json @@ -0,0 +1,17 @@ +{ + "process": [ + { + "type": "systemd", + "property": { + "name": "hal-backend-service-with-dbus" + }, + "thread": [ + { "hal_module_name": [ "device_display" ] }, + { "hal_module_name": [ "device_led" ] }, + { "hal_module_name": [ "device_battery" ] }, + { "hal_module_name": [ "device_bezel" ] }, + { "hal_module_name": [ "device_external_connection" ] } + ] + } + ] +} diff --git a/hal-backend-service-with-dbus/config_types.py b/hal-backend-service-with-dbus/config_types.py new file mode 100644 index 0000000..76e084e --- /dev/null +++ b/hal-backend-service-with-dbus/config_types.py @@ -0,0 +1,167 @@ +import errno + +class InvalidJsonStructException(Exception): + errno = errno.EINVAL + +class InvalidJsonValueException(Exception): + errno = errno.EINVAL + +class JsonConfigEntity: + def get_name(self): + return None + def get_hal_module_names(self): + return None + def map_json_obj(self, json_obj): + return None + +class ThreadConfig(JsonConfigEntity): + hal_module_names: list + + def __init__(self, json_obj): + self.map_json_obj(json_obj) + + def __str__(self): + result = "" + result += f"\t\tThread:\n" + result += f"\t\t\thal module names: " + ", ".join(self.hal_module_names) + "\n" + return result + + def map_json_obj(self, json_obj): + if type(json_obj) != dict: + raise InvalidJsonStructException("Invalid json struct: thread should be a json object") + if "hal_module_name" not in json_obj: + raise InvalidJsonStructException("Invalid json struct: thread should have \"hal_module_name\"") + + hal_module_name_obj = json_obj["hal_module_name"] + if type(hal_module_name_obj) != list: + raise InvalidJsonStructException("Invalid json struct: hal_module_name should be a list") + + if any(filter(lambda x: type(x) != str, hal_module_name_obj)): + raise InvalidJsonStructException("Invalid json struct: hal_module_name should be a list of strings") + + self.hal_module_names = [ str(obj) for obj in hal_module_name_obj ] + +class ThreadsConfig(JsonConfigEntity): + threads: list + + def __init__(self, json_obj): + self.map_json_obj(json_obj) + + def __str__(self): + result = "" + result += f"\tThreads:\n" + for thread in self.threads: + result += f"{str(thread)}" + return result + + def map_json_obj(self, json_obj): + if type(json_obj) != list: + raise InvalidJsonStructException("Invalid json struct: thread should be a list") + + threads = list() + + for obj in json_obj: + threads.append(ThreadConfig(obj)) + + self.threads = threads + + def get_hal_module_names(self): + hal_module_names = list() + + for thread in self.threads: + hal_module_names += thread.hal_module_names + + return hal_module_names + +class HalBackendServiceSystemdPropertyConfig(JsonConfigEntity): + name: str + + def __init__(self, json_obj): + self.map_json_obj(json_obj) + + def __str__(self): + result = "" + result += f"\tProperties:\n" + result += f"\t\tname: {self.name}\n" + return result + + def map_json_obj(self, json_obj): + if type(json_obj) != dict: + raise InvalidJsonStructException("Invalid json struct: systemd property should be a json object") + if "name" not in json_obj: + raise InvalidJsonStructException("Invalid json struct: systemd property should have \"name\"") + + name_obj = json_obj["name"] + if type(name_obj) != str: + raise InvalidJsonStructException("Invalid json struct: systemd name should be a string") + + service_name_prefix = "hal-backend-service" + if not name_obj.startswith(service_name_prefix): + raise InvalidJsonValueException(f"Invalid json value: systemd name should start with {service_name_prefix}") + + self.name = name_obj + +class HalBackendServiceSystemdConfig(JsonConfigEntity): + properties: HalBackendServiceSystemdPropertyConfig + thread_config: ThreadsConfig + + def __init__(self, json_obj): + self.type = "systemd" + self.map_json_obj(json_obj) + + def __str__(self): + result = "" + result += f"Service:\n" + result += f"{str(self.properties)}" + result += f"{str(self.thread_config)}" + return result + + def map_json_obj(self, json_obj): + if type(json_obj) != dict: + raise InvalidJsonStructException("Invalid json struct: systemd process should be a json object") + if "property" not in json_obj: + raise InvalidJsonStructException("Invalid json struct: systemd process should have \"properties\"") + if "thread" not in json_obj: + raise InvalidJsonStructException("Invalid json struct: systemd process should have \"thread\"") + + property_obj = json_obj["property"] + self.properties = HalBackendServiceSystemdPropertyConfig(property_obj) + + thread_obj = json_obj["thread"] + self.thread_config = ThreadsConfig(thread_obj) + + def get_name(self): + return self.properties.name + + def get_hal_module_names(self): + return self.thread_config.get_hal_module_names() + +class HalBackendServiceConfig(JsonConfigEntity): + processes: list + type_classes = { "systemd": HalBackendServiceSystemdConfig } + + def __init__(self, json_obj): + self.map_json_obj(json_obj) + + def __str__(self): + return '\n'.join([ str(process) for process in self.processes ]) + + def map_json_obj(self, json_obj): + if "process" not in json_obj: + raise InvalidJsonStructException("No process element") + + process_obj = json_obj["process"] + if type(process_obj) != list: + raise InvalidJsonStructException(f"Invalid json struct: \"process\" should be a list, not {type(process_obj)}") + + processes = list() + + for obj in process_obj: + if "type" not in obj: + raise InvalidJsonStructException(f"Invalid json struct: process should have \"type\"") + process_type = obj["type"] + if process_type not in self.type_classes: + raise InvalidJsonValueException(f"Invalid json value: unknown type({process_type})") + processes.append(self.type_classes[process_type](obj)) + + self.processes = processes diff --git a/hal-backend-service-with-dbus/hal-api-backend-service-list.h.in b/hal-backend-service-with-dbus/hal-api-backend-service-list.h.in new file mode 100644 index 0000000..7023fe2 --- /dev/null +++ b/hal-backend-service-with-dbus/hal-api-backend-service-list.h.in @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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. + */ + +#pragma once + +static const char *g_hal_module_stub_proc_name[] = { + [HAL_MODULE_UNKNOWN] = NULL, +@HAL_MODULE_STUB_PROC_NAME_MAP@ + [HAL_MODULE_END] = NULL, +}; diff --git a/hal-backend-service-with-dbus/hal-backend-service-generator.py b/hal-backend-service-with-dbus/hal-backend-service-generator.py new file mode 100755 index 0000000..0d57c47 --- /dev/null +++ b/hal-backend-service-with-dbus/hal-backend-service-generator.py @@ -0,0 +1,232 @@ +#!/usr/bin/python3 + +import errno +import json + +from getopt import getopt, GetoptError +from sys import exit, argv + +from config_types import * + +def log(message): + message_lines = message.split('\n') + for line in message_lines: + print(f"[hal-backend-service-generator] {line}") + +def parse_hal_backend_service_configs(config_file_path): + with open(config_file_path, "r") as f: + json_object = json.load(f) + return HalBackendServiceConfig(json_object) + +def check_hal_backend_service_configs_duplications(configs): + names_set = set() + hal_module_names_set = set() + + for config in configs.processes: + name = config.get_name() + if name not in names_set: + names_set.add(name) + continue + raise InvalidJsonValueException(f"Invalid json value: duplicated name({name})") + + for config in configs.processes: + for hal_module_name in config.get_hal_module_names(): + if hal_module_name not in hal_module_names_set: + hal_module_names_set.add(hal_module_name) + continue + raise InvalidJsonValueException(f"Invalid json value: duplicated hal module name({hal_module_name})") + +def create_empty_hal_backend_service_list_header(prototype_path, header_file_path): + with open(prototype_path, "r") as f: + prototype = f.read() + + module_name_map = prototype.replace("@HAL_MODULE_STUB_PROC_NAME_MAP@", "") + + with open(header_file_path, "w") as f: + f.write(module_name_map) + +def create_hal_backend_service_list_header(prototype_path, configs, header_file_path): + with open(prototype_path, "r") as f: + prototype = f.read() + + module_name_map_list = list() + for config in configs.processes: + name = config.get_name() + for hal_module_name in config.get_hal_module_names(): + hal_module_enum = f"HAL_MODULE_{hal_module_name.upper()}" + stub_proc_name = f"d::{name}" + module_name_map_list.append(f"\t[{hal_module_enum}] = \"{stub_proc_name}\",") + module_name_map = prototype.replace("@HAL_MODULE_STUB_PROC_NAME_MAP@", '\n'.join(module_name_map_list)) + + with open(header_file_path, "w") as f: + f.write(module_name_map) + +def create_hal_backend_service_service(prototype_path, configs, install_dir): + with open(prototype_path, "r") as f: + prototype = f.read() + + for config in configs.processes: + if config.type != "systemd": + continue + service_name = config.get_name() + service_file_name = f"{service_name}.service" + stub_proc_name = f"d::{service_name}" + threads = ' '.join(map(lambda thread: ','.join(thread.hal_module_names), config.thread_config.threads)) + threads = threads.replace('_', '-') + + service_content = prototype.replace("@SERVICE_NAME@", service_name)\ + .replace("@PROC_NAME@", stub_proc_name)\ + .replace("@THREADS@", threads) + + with open(f"{install_dir}/{service_file_name}", "w") as f: + f.write(service_content) + +def create_hal_backend_service_socket(prototype_path, configs, install_dir): + with open(prototype_path, "r") as f: + prototype = f.read() + + for config in configs.processes: + if config.type != "systemd": + continue + service_name = config.get_name() + socket_file_name = f"{service_name}.socket" + stub_proc_name = f"d::{service_name}" + listen_streams = list() + + for thread_config in config.thread_config.threads: + for hal_module_name in thread_config.hal_module_names: + listen_streams.append(f"ListenStream=/run/aul/rpcport/.{stub_proc_name}::{hal_module_name}") + + socket_content = prototype.replace("@SERVICE_NAME@", service_name)\ + .replace("@LISTEN_STREAMS@", '\n'.join(listen_streams)) + + with open(f"{install_dir}/{socket_file_name}", "w") as f: + f.write(socket_content) + +def print_usage(exec_name): + print(f"usage: {exec_name}