概述
前言
非常抱歉,因为个人原因,之前说到的策略解析部分的分析拖到现在。
之前我们主要针对服务的启动和使用来进行分析。但是在整个使用过程中,也不可避免的需要进行相关的配置。
而目前vsomeip提供的配置是比较丰富的,但是官方文档介绍的比较少,以及对应策略插件的相关信息也没有介绍。
本文主要从策略加载,使用配置等等方面进行介绍。
init
之前的文章中,我们知道,整个application在init的时候会去初始化configuration相关的逻辑。
configuration是以插件的形式加载的,在编译完成之后,我们也可以看到对应的libvsomeipv3-cfg.so
插件的好处就是,在后续,如果我们觉得vsomeip本身的配置逻辑不好,也可以自己实现相关的接口进行替换。
这里init过程中主要做了如下的几件事:
- 加载我们在启动时配置的环境变量,如果没有指定的话,就去取默认的/etc/vsomeip路径下查找。
- 加载对应的so
- 加载自身配置
bool application_impl::init() {
...
std::string configuration_path;
// load configuration from module
std::string config_module = "";
//获取启动时设置的configuration文件的位置 环境变量
const char *its_config_module = getenv(VSOMEIP_ENV_CONFIGURATION_MODULE);
if (nullptr != its_config_module) {
std::cerr << "test its_config_module not nullptr" << std::endl;
// TODO: Add loading of custom configuration module
} else { // load default module
#ifndef VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS
std::cerr << "test its_config_module is nullptr" << std::endl;
//加载libvsomeipv3-cfg.so,并将对应的函数指针保存
auto its_plugin = plugin_manager::get()->get_plugin(
plugin_type_e::CONFIGURATION_PLUGIN, VSOMEIP_CFG_LIBRARY);
if (its_plugin) {
auto its_configuration_plugin
= std::dynamic_pointer_cast<configuration_plugin>(its_plugin);
if (its_configuration_plugin) {
//通过application name加载对应的configuration文件
configuration_ = its_configuration_plugin->get_configuration(name_);
VSOMEIP_INFO << "Configuration module loaded.";
} else {
std::cerr << "Invalid configuration module!" << std::endl;
std::exit(EXIT_FAILURE);
}
} else {
std::cerr << "Configuration module could not be loaded!" << std::endl;
std::exit(EXIT_FAILURE);
}
#else
configuration_ = std::dynamic_pointer_cast<configuration>(
std::make_shared<vsomeip_v3::cfg::configuration_impl>());
if (configuration_path.length()) {
configuration_->set_configuration_path(configuration_path);
}
configuration_->load(name_);
#endif // VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS
}
...
}
加载so
其实加载so过程主要做的就是吧对应的函数保存到plugin manager里面,方便后续调用方便。
首先时判断是否已经加载过了,如果没有再去加载。
std::shared_ptr<plugin> plugin_manager_impl::get_plugin(plugin_type_e _type, std::string _name) {
std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
auto its_type = plugins_.find(_type);
if (its_type != plugins_.end()) {
auto its_name = its_type->second.find(_name);
if (its_name != its_type->second.end()) {
return its_name->second;
}
}
return load_plugin(_name, _type, 1);
}
这里先去load_symbol,内部实际上就是dlsym操作
std::shared_ptr<plugin> plugin_manager_impl::load_plugin(const std::string& _library,
plugin_type_e _type, uint32_t _version) {
void* handle = load_library(_library);
plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>(
load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL));
if (its_init_func) {
create_plugin_func its_create_func = (*its_init_func)();
if (its_create_func) {
handles_[_type][_library] = handle;
auto its_plugin = (*its_create_func)();
if (its_plugin) {
if (its_plugin->get_plugin_type() == _type
&& its_plugin->get_plugin_version() == _version) {
add_plugin(its_plugin, _library);
return its_plugin;
} else {
VSOMEIP_ERROR << "Plugin version mismatch. Ignoring plugin "
<< its_plugin->get_plugin_name();
}
}
}
}
return nullptr;
}
之后就是add_plugin,主要就是吧加载的插件加入到plugin_manager管理的map里面。
void plugin_manager_impl::add_plugin(const std::shared_ptr<plugin> &_plugin, const std::string& _name) {
plugins_[_plugin->get_plugin_type()][_name] = _plugin;
}
加载策略
加载完plugin之后,就是加载 策略了。
这里主要时去加载默认的策略。
//cfg插件通过application name加载对应的配置信息
std::shared_ptr<configuration>
configuration_plugin_impl::get_configuration(const std::string &_name) {
std::lock_guard<std::mutex> its_lock(mutex_);
if (!default_) {
default_ = std::make_shared<cfg::configuration_impl>();
default_->load(_name);
}
#ifdef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
auto its_configuration(default_);
if (its_configuration->has_overlay(_name)) {
VSOMEIP_INFO << "Loading configuration overlay for "" << _name << """;
auto its_iterator = configurations_.find(_name);
if (its_iterator != configurations_.end()) {
its_configuration = its_iterator->second;
} else {
its_configuration = std::make_shared<cfg::configuration_impl>(
*(its_configuration.get()));
its_configuration->load_overlay(_name);
configurations_[_name] = its_configuration;
}
}
return its_configuration;
#else
return default_;
#endif // VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
}
初始化configuration_impl,主要指定了一些默认的参数。
configuration_impl::configuration_impl()
: default_unicast_("local"),
is_loaded_(false),
is_logging_loaded_(false),
is_overlay_(false),
diagnosis_(VSOMEIP_DIAGNOSIS_ADDRESS),
diagnosis_mask_(0xFF00),
has_console_log_(true),
has_file_log_(false),
has_dlt_log_(false),
logfile_("/tmp/vsomeip.log"),
loglevel_(vsomeip_v3::logger::level_e::LL_INFO),
is_sd_enabled_(VSOMEIP_SD_DEFAULT_ENABLED),
sd_protocol_(VSOMEIP_SD_DEFAULT_PROTOCOL),
sd_multicast_(VSOMEIP_SD_DEFAULT_MULTICAST),
sd_port_(VSOMEIP_SD_DEFAULT_PORT),
sd_initial_delay_min_(VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MIN),
sd_initial_delay_max_(VSOMEIP_SD_DEFAULT_INITIAL_DELAY_MAX),
sd_repetitions_base_delay_(VSOMEIP_SD_DEFAULT_REPETITIONS_BASE_DELAY),
sd_repetitions_max_(VSOMEIP_SD_DEFAULT_REPETITIONS_MAX),
sd_ttl_(VSOMEIP_SD_DEFAULT_TTL),
sd_cyclic_offer_delay_(VSOMEIP_SD_DEFAULT_CYCLIC_OFFER_DELAY),
sd_request_response_delay_(VSOMEIP_SD_DEFAULT_REQUEST_RESPONSE_DELAY),
sd_offer_debounce_time_(VSOMEIP_SD_DEFAULT_OFFER_DEBOUNCE_TIME),
max_configured_message_size_(0),
max_local_message_size_(0),
max_reliable_message_size_(0),
max_unreliable_message_size_(0),
buffer_shrink_threshold_(VSOMEIP_DEFAULT_BUFFER_SHRINK_THRESHOLD),
trace_(std::make_shared<trace>()),
watchdog_(std::make_shared<watchdog>()),
log_version_(true),
log_version_interval_(10),
permissions_shm_(VSOMEIP_DEFAULT_SHM_PERMISSION),
permissions_uds_(VSOMEIP_DEFAULT_UDS_PERMISSIONS),
network_("vsomeip"),
e2e_enabled_(false),
log_memory_(false),
log_memory_interval_(0),
log_status_(false),
log_status_interval_(0),
endpoint_queue_limit_external_(QUEUE_SIZE_UNLIMITED),
endpoint_queue_limit_local_(QUEUE_SIZE_UNLIMITED),
tcp_restart_aborts_max_(VSOMEIP_MAX_TCP_RESTART_ABORTS),
tcp_connect_time_max_(VSOMEIP_MAX_TCP_CONNECT_TIME),
has_issued_methods_warning_(false),
has_issued_clients_warning_(false),
udp_receive_buffer_size_(VSOMEIP_DEFAULT_UDP_RCV_BUFFER_SIZE),
npdu_default_debounce_requ_(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO),
npdu_default_debounce_resp_(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO),
npdu_default_max_retention_requ_(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO),
npdu_default_max_retention_resp_(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO),
shutdown_timeout_(VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT),
log_statistics_(true),
statistics_interval_(VSOMEIP_DEFAULT_STATISTICS_INTERVAL),
statistics_min_freq_(VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ),
statistics_max_messages_(VSOMEIP_DEFAULT_STATISTICS_MAX_MSG) {
unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS);
netmask_ = netmask_.from_string(VSOMEIP_NETMASK);
for (auto i = 0; i < ET_MAX; i++)
is_configured_[i] = false;
}
接下来就是加载对应配置的逻辑了,这里 load 函数主要做了如下的事情 :
- 加载默认的配置文件,这部分主要时系统/etc/下面的内容
- 设置默认的本地配置文件内,./vsomeip.json
- 如果本地存在配置目录,替换掉之前默认的目录
- 如果在启动的时候,有主动设置过对应的配置信息,就加载设置的参数。
- 加载一些系统强制的相关策略
- 解析对应的 策略json文件
- 如果时routing进程 的话,加载全部的配置信息
bool configuration_impl::load(const std::string &_name) {
std::lock_guard<std::mutex> its_lock(mutex_);
if (is_loaded_)
return true;
//对应的配置文件先设置默认值
// /etc/vsomeip.json ; /etc/vsomeip
// Predefine file / folder
std::string its_file(VSOMEIP_DEFAULT_CONFIGURATION_FILE); // configuration file
std::string its_folder(VSOMEIP_DEFAULT_CONFIGURATION_FOLDER); // configuration folder
// Override with local file / folder (if existing)
//设置默认的本地配置文件./vsomeip.json
//如果存在,覆盖之前的默认文件
std::string its_local_file(VSOMEIP_LOCAL_CONFIGURATION_FILE);
if (utility::is_file(its_local_file)) {
its_file = its_local_file;
}
//设置本地默认配置文件目录./vsomip
//如果存在,覆盖之前的默认文件
std::string its_local_folder(VSOMEIP_LOCAL_CONFIGURATION_FOLDER);
if (utility::is_folder(its_local_folder)) {
its_folder = its_local_folder;
}
// Override with path from environment (if existing)
//这里读取对应的env信息(启动服务时指定的),如果存在对应的文件或者目录,替换之前的文件或者目录。
const char *its_env = getenv(VSOMEIP_ENV_CONFIGURATION);
if (nullptr != its_env) {
if (utility::is_file(its_env)) {
its_file = its_env;
its_folder = "";
} else if (utility::is_folder(its_env)) {
its_folder = its_env;
its_file = "";
}
}
//创建一个set,用来存储需要加载配置文件的目录或者文件
std::set<std::string> its_input;
if (its_file != "") {
its_input.insert(its_file);
}
if (its_folder != "") {
its_input.insert(its_folder);
#ifndef _WIN32
// load security configuration files from UID_GID sub folder if existing
// 如果是非win系统,那么从对应的目录中查找以UID_GID为名字的子目录
//例如:its_folder = /etc/vsomeip
//当前进程的uid=1000,gid=1000,对应的安全配置目录应该是 /etc/vsomeip/1000_1000
std::stringstream its_security_config_folder;
its_security_config_folder << its_folder << "/" << getuid() << "_" << getgid();
if (utility::is_folder(its_security_config_folder.str())) {
its_input.insert(its_security_config_folder.str());
}
#endif
}
// Determine standard configuration file
its_env = getenv(VSOMEIP_ENV_MANDATORY_CONFIGURATION_FILES);
if (nullptr != its_env) {
std::string its_temp(its_env);
set_mandatory(its_temp);
} else {
//设置相关强制性信息文件
//vsomeip这里应该定义了很多规范化的文件名,来处理不同的配置文件,这些文件的含义目前还不清楚,后续需要继续分析
//vsomeip_std.json,vsomeip_app.json,vsomeip_plc.json,vsomeip_log.json,vsomeip_security.json,vsomeip_whitelist.json
set_mandatory(VSOMEIP_MANDATORY_CONFIGURATION_FILES);
}
// Start reading
std::set<std::string> its_failed;
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::vector<configuration_element> its_mandatory_elements;
std::vector<configuration_element> its_optional_elements;
// Dummy initialization; maybe we'll find no logging configuration
logger::logger_impl::init(shared_from_this());
// Look for the standard configuration file
/** void configuration_impl::read_data(const std::set<std::string> &_input,
* std::vector<configuration_element> &_elements, std::set<std::string> &_failed,
* bool _mandatory_only)
**/
//将对应的文件读出对应json的对象,然后存储再its_mandatory_elements中。这里先去读对应的规范化的文件
read_data(its_input, its_mandatory_elements, its_failed, true);
load_data(its_mandatory_elements, true, false);
// If the configuration is incomplete, this is the routing manager configuration or
// the routing is yet unknown, read the full set of configuration files
//如果配置是不完全的,routing信息没有配置的话,那么继续加载全部的配置到routing
if (its_mandatory_elements.empty() ||
_name == get_routing_host() ||
"" == get_routing_host()) {
read_data(its_input, its_optional_elements, its_failed, false);
load_data(its_mandatory_elements, false, true);
load_data(its_optional_elements, true, true);
}
// Tell, if reading of configuration file(s) failed.
// (This may file if the logger configuration is incomplete/missing).
for (auto f : its_failed)
VSOMEIP_WARNING << "Reading of configuration file ""
<< f << "" failed. Configuration may be incomplete.";
// set global unicast address for all services with magic cookies enabled
set_magic_cookies_unicast_address();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
VSOMEIP_INFO << "Parsed vsomeip configuration in "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
<< "ms";
for (auto i : its_input) {
if (utility::is_file(i))
VSOMEIP_INFO << "Using configuration file: "" << i << "".";
if (utility::is_folder(i))
VSOMEIP_INFO << "Using configuration folder: "" << i << "".";
}
is_loaded_ = true;
return is_loaded_;
}
这里readdata主要就是调用json解析库去解析json信息。
void configuration_impl::read_data(const std::set<std::string> &_input,
std::vector<configuration_element> &_elements, std::set<std::string> &_failed,
bool _mandatory_only) {
for (auto i : _input) {
//如果是文件的话,直接解析json
if (utility::is_file(i)) {
//判断当前文件是否是mandatory文件,并和传入的参数比较
if (is_mandatory(i) == _mandatory_only) {
boost::property_tree::ptree its_tree;
try {
boost::property_tree::json_parser::read_json(i, its_tree);
_elements.push_back({ i, its_tree });
}
catch (boost::property_tree::json_parser_error &e) {
#ifdef _WIN32
e; // silence MSVC warning C4101
#endif
_failed.insert(i);
}
}
} else if (utility::is_folder(i)) {
//如果是目录,那么遍历目录内的文件。
boost::filesystem::path its_path(i);
for (auto j = boost::filesystem::directory_iterator(its_path);
j != boost::filesystem::directory_iterator();
j++) {
auto its_file_path = j->path();
if (!boost::filesystem::is_directory(its_file_path)) {
const std::string& its_name = its_file_path.string();
if (is_mandatory(its_name) == _mandatory_only) {
boost::property_tree::ptree its_tree;
try {
boost::property_tree::json_parser::read_json(its_name, its_tree);
_elements.push_back({its_name, its_tree});
}
catch (...) {
_failed.insert(its_name);
}
}
}
}
}
}
}
之后是load_data操作主要就是加载对应的具体配置信息到内存对应的结构上了。
bool configuration_impl::load_data(const std::vector<configuration_element> &_elements,
bool _load_mandatory, bool _load_optional) {
// Load logging configuration data
std::set<std::string> its_warnings;
//日志相关信息
if (!is_logging_loaded_) {
for (const auto& e : _elements)
is_logging_loaded_
= load_logging(e, its_warnings) || is_logging_loaded_;
if (is_logging_loaded_) {
logger::logger_impl::init(shared_from_this());
for (auto w : its_warnings)
VSOMEIP_WARNING << w;
}
}
bool has_routing(false);
bool has_applications(false);
if (_load_mandatory) {
// Load mandatory configuration data
for (const auto& e : _elements) {
//加载routing信息
has_routing = load_routing(e) || has_routing;
//加载applications信息
has_applications = load_applications(e) || has_applications;
//加载网络相关信息
load_network(e);
//诊断地址?
load_diagnosis_address(e);
//关机超时时间?
load_shutdown_timeout(e);
//payload大小
load_payload_sizes(e);
//todo
load_endpoint_queue_sizes(e);
// todo
load_tcp_restart_settings(e);
// 加载files-permissions信息
load_permissions(e);
//加载安全插件信息
load_security(e);
load_tracing(e);
load_udp_receive_buffer_size(e);
}
}
if (_load_optional) {
for (const auto& e : _elements) {
load_unicast_address(e);
load_netmask(e);
load_device(e);
load_service_discovery(e);
load_npdu_default_timings(e);
load_services(e);
load_internal_services(e);
load_clients(e);
load_watchdog(e);
load_selective_broadcasts_support(e);
load_e2e(e);
load_debounce(e);
load_acceptances(e);
load_secure_services(e);
}
}
return is_logging_loaded_ && has_routing && has_applications;
}
最后
以上就是忧虑背包为你收集整理的SOME/IP开源库Vsomeip分析5 - 策略加载的全部内容,希望文章能够帮你解决SOME/IP开源库Vsomeip分析5 - 策略加载所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复