From 55be85ed4bdfea6fc037d781b8cd8f58487718d1 Mon Sep 17 00:00:00 2001 From: Yuta Doi Date: Fri, 27 Apr 2018 19:01:36 +0900 Subject: Add PolicyManager, related classes and some config files - PolicyManager Decide next layout by using occured event and current state based on policy table. This PolicyManger is reference and the OEMs can replace it. - LayoutManager Change the current layout to the layout which decided by PolicyManager. NOTE: The functions of this class had been included in App class. The part of function of this class remain there yet. - LowCanClient Receive the CAN signal from low level CAN service. - app.db Define the applications name and its role. This file will be deleted when the names and roles can be given by other module. - layout.cb Define the layouts and areas which are included by the layout. - role.db Define the roles of the applications. Change-Id: I2f84bdf5e68355e022f516cee9a1db88efe58825 Signed-off-by: Yuta Doi --- src/policy_manager/policy_manager.cpp | 497 ++++++++++++++++++++++++++++++++++ 1 file changed, 497 insertions(+) create mode 100644 src/policy_manager/policy_manager.cpp (limited to 'src/policy_manager/policy_manager.cpp') diff --git a/src/policy_manager/policy_manager.cpp b/src/policy_manager/policy_manager.cpp new file mode 100644 index 0000000..61d1d7c --- /dev/null +++ b/src/policy_manager/policy_manager.cpp @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * 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 "policy_manager.hpp" +#include "dummy_stm.h" +#include "hmi-debug.h" + + +namespace { + +static const char* kEventName[] = { + "activate", + "deactivate", + "car_stop", + "car_run", + "timer_expired", + "lamp_off", + "lamp_on" +}; + +static const int kEventNo[] = { + STM_EVT_NO_ACTIVATE, + STM_EVT_NO_DEACTIVATE, + STM_EVT_NO_CAR_STOP, + STM_EVT_NO_CAR_RUN, + STM_EVT_NO_TIMER_EXPIRED, + STM_EVT_NO_LAMP_OFF, + STM_EVT_NO_LAMP_ON +}; + +static const char* kCategoryName[] = { + "homescreen", + "map", + "general", + "splitable", + "popup", + "system_alert" +}; + +static const int kCategoryNo[] = { + STM_CTG_NO_HOMESCREEN, + STM_CTG_NO_MAP, + STM_CTG_NO_GENERAL, + STM_CTG_NO_SPLITABLE, + STM_CTG_NO_POPUP, + STM_CTG_NO_SYSTEM_ALERT +}; + +static const char* kAreaName[] = { + "full", + "normal", + "split.main", + "split.sub", + "onscreen" +}; + +static const int kAreaNo[] = { + STM_ARA_NO_FULL, + STM_ARA_NO_NORMAL, + STM_ARA_NO_SPLIT_MAIN, + STM_ARA_NO_SPLIT_SUB, + STM_ARA_NO_ON_SCREEN +}; + +// String for state +const char* gStmCarStateNo2Name[] = { + "car_stop", + "car_run" +}; + +const char* gStmLampStateNo2Name[] = { + "lamp_off", + "lamp_on" +}; + +const char* gStmLayoutNo2Name[] = { + "none", + "pu", + "sa", + "m1", + "m2", + "mf", + "s1", + "s2", + "g", + "hs", +}; + +} // namespace + +PolicyManager::PolicyManager() : + eventname2no_(), + categoryname2no_(), + areaname2no_(), + role2category_(), + category2role_(), + role2defaultarea_(), + current_state_() +{ + HMI_DEBUG("wm:pm", "Call"); +} + +int PolicyManager::initialize() { + HMI_DEBUG("wm:pm", "Call"); + + int ret = 0; + + // Create convert map + for (unsigned int i=0; i<(sizeof(kEventNo)/sizeof(int)); i++) { + HMI_DEBUG("wm:pm", "event name:%s no:%d", kEventName[i], kEventNo[i]); + this->eventname2no_[kEventName[i]] = kEventNo[i]; + } + + for (unsigned int i=0; i<(sizeof(kCategoryNo)/sizeof(int)); i++) { + HMI_DEBUG("wm:pm", "category name:%s no:%d", kCategoryName[i], kCategoryNo[i]); + this->categoryname2no_[kCategoryName[i]] = kCategoryNo[i]; + } + + for (unsigned int i=0; i<(sizeof(kAreaNo)/sizeof(int)); i++) { + HMI_DEBUG("wm:pm", "area name:%s no:%d", kAreaName[i], kAreaNo[i]); + this->areaname2no_[kAreaName[i]] = kAreaNo[i]; + } + + // Load role.db + ret = loadRoleDb(); + if (0 > ret) { + HMI_ERROR("wm:pm", "Load role.db Error!!"); + return ret; + } + + // TODO: + // Initialize StateTransitioner + // stmInitialize(); + + return ret; +} + +int PolicyManager::checkPolicy(json_object* json_in, json_object** json_out) { + HMI_DEBUG("wm:pm", "Call"); + + // Check arguments + if ((nullptr == json_in) || (nullptr == json_out)) { + HMI_ERROR("wm:pm", "Argument is NULL!!"); + return -1; + } + + // Get event from json_object + const char* event = getStringFromJson(json_in, "event"); + int event_no = 0; + if (nullptr != event) { + // Convert name to number + event_no = this->eventname2no_[event]; + HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no); + } + + // Get role from json_object + const char* role = getStringFromJson(json_in, "role"); + int category_no = 0; + if (nullptr != role) { + HMI_DEBUG("wm:pm", "role(%s)", role); + + // Convert role to category + const char* category = this->role2category_[role].c_str(); + if (0 == strcmp("", category)) { + HMI_ERROR("wm:pm", "Error!!"); + return -1; + } + HMI_DEBUG("wm:pm", "category(%s)", category); + + // Convert name to number + category_no = categoryname2no_[category]; + HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no); + } + + // Get areat from json_object + const char* area = getStringFromJson(json_in, "area"); + int area_no = 0; + if (nullptr != area) { + // Convert name to number + area_no = areaname2no_[area]; + HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no); + } + + // Transition state + HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no)); + int ret = stmTransitionState((event_no | category_no | area_no), + &(this->current_state_)); + if (0 > ret) { + HMI_ERROR("wm:pm", "Error!!"); + return -1; + } + + // Create result + // { + // "car": { + // "is_changed": , + // "state": + // }, + HMI_DEBUG("wm", "@@@@@ car state (is_changed:%d state:%d:%s)", + this->current_state_.car.is_changed, + this->current_state_.car.state, + gStmCarStateNo2Name[this->current_state_.car.state]); + this->addStateToJson("car", + this->current_state_.car.is_changed, + gStmCarStateNo2Name[this->current_state_.car.state], + json_out); + + // "lamp": { + // "is_changed": , + // "state": + // }, + HMI_DEBUG("wm", "@@@@@ lamp state (is_changed:%d state:%d:%s)", + this->current_state_.lamp.is_changed, + this->current_state_.lamp.state, + gStmLampStateNo2Name[this->current_state_.lamp.state]); + this->addStateToJson("lamp", + this->current_state_.lamp.is_changed, + gStmLampStateNo2Name[this->current_state_.lamp.state], + json_out); + + // "layers": [ + // { + // "on_screen": { + // "is_changed": , + // "state": + // } + // }, + json_object* json_layer = json_object_new_array(); + json_object* json_tmp = json_object_new_object(); + this->addStateToJson("on_screen", + this->current_state_.layer.on_screen.is_changed, + gStmLayoutNo2Name[this->current_state_.layer.on_screen.state], + &json_tmp); + json_object_array_add(json_layer, json_tmp); + + // { + // "apps": { + // "is_changed": , + // "state": + // } + // }, + json_tmp = json_object_new_object(); + this->addStateToJson("apps", + this->current_state_.layer.apps.is_changed, + gStmLayoutNo2Name[this->current_state_.layer.apps.state], + &json_tmp); + json_object_array_add(json_layer, json_tmp); + + // { + // "homescreen": { + // "is_changed": , + // "state": + // } + // }, + // ] + // } + json_tmp = json_object_new_object(); + this->addStateToJson("homescreen", + this->current_state_.layer.homescreen.is_changed, + gStmLayoutNo2Name[this->current_state_.layer.homescreen.state], + &json_tmp); + json_object_array_add(json_layer, json_tmp); + + // Add json array of layer + json_object_object_add(*json_out, "layers", json_layer); + + HMI_DEBUG("wm:pm", "json_out.dump:%s", json_object_get_string(*json_out)); + + return 0; +} + +std::string PolicyManager::roleToCategory(const char* role) { + return this->role2category_[role]; +} + +extern const char* kDefaultRoleDb; +int PolicyManager::loadRoleDb() { + HMI_DEBUG("wm:pm", "Call"); + + std::string file_name; + + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir); + + if (!afm_app_install_dir) { + HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined"); + } + else { + file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db"); + } + + // Load role.db + HMI_DEBUG("wm:pm", "file_name:%s", file_name.c_str()); + json_object* json_obj = json_object_from_file(file_name.c_str()); + if (nullptr == json_obj) { + HMI_ERROR("wm:pm", "Could not open role.db, so use default role information"); + json_obj = json_tokener_parse(kDefaultRoleDb); + } + HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj)); + + json_object* json_roles; + if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) { + HMI_ERROR("wm:pm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_roles); + HMI_DEBUG("wm:pm", "json_cfg len:%d", len); + HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles)); + + json_object* json_tmp; + const char* category; + const char* roles; + const char* areas; + for (int i=0; igetStringFromJson(json_tmp, "category"); + roles = this->getStringFromJson(json_tmp, "role"); + areas = this->getStringFromJson(json_tmp, "area"); + + if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) { + HMI_ERROR("wm:pm", "Parse Error!!"); + return -1; + } + + // Parse roles by '|' + std::vector vct_roles; + vct_roles = this->parseString(std::string(roles), '|'); + + // Parse areas by '|' + std::vector vct_areas; + vct_areas = this->parseString(std::string(areas), '|'); + + // Set role, category, default area + for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) { + // Delete space from role and area name + std::string role = this->deleteSpace(*itr); + std::string area = this->deleteSpace(vct_areas[0]); + + this->role2category_[role] = std::string(category); + this->role2defaultarea_[role] = area; + } + + this->category2role_[std::string(category)] = std::string(roles); + } + + // Check + HMI_DEBUG("wm:pm", "Check role2category_"); + for (auto& x:this->role2category_){ + HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + } + + HMI_DEBUG("wm:pm", "Check role2defaultarea_"); + for (auto& x:this->role2defaultarea_){ + HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + } + + HMI_DEBUG("wm:pm", "Check category2role_"); + for (auto& x:this->category2role_){ + HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str()); + } + + return 0; +} + +const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm:pm", "Argument is nullptr!!!"); + return nullptr; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm:pm", "Not found key \"%s\"", key); + return nullptr; + } + + return json_object_get_string(tmp); +} + +int PolicyManager::getIntFromJson(json_object* obj, const char* key) { + if ((nullptr == obj) || (nullptr == key)) { + HMI_ERROR("wm:pm", "Argument is nullptr!!!"); + return 0; + } + + json_object* tmp; + if (!json_object_object_get_ex(obj, key, &tmp)) { + HMI_DEBUG("wm:pm", "Not found key \"%s\"", key); + return 0; + } + + return json_object_get_int(tmp); +} + +void PolicyManager::addStateToJson( + const char* key, int is_changed, const char* state, json_object** json_out) { + if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) { + HMI_ERROR("wm:pm", "Argument is nullptr!!!"); + return; + } + + json_object* json_obj = json_object_new_object(); + json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed)); + if (is_changed) { + HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state); + json_object_object_add(json_obj, "state", json_object_new_string(state)); + } + json_object_object_add(*json_out, key, json_obj); +} + +std::vector PolicyManager::parseString(std::string str, char delimiter) { + // Parse string by delimiter + std::vector vct; + std::stringstream ss{str}; + std::string buf; + while (std::getline(ss, buf, delimiter)) { + if (!buf.empty()) { + vct.push_back(buf); + } + } + return vct; +} + +std::string PolicyManager::deleteSpace(std::string str) { + std::string ret = str; + size_t pos; + while ((pos = ret.find_first_of(" ")) != std::string::npos) { + ret.erase(pos, 1); + } + return ret; +} + +const char* kDefaultRoleDb = "{ \ + \"roles\":[ \ + { \ + \"category\": \"homescreen\", \ + \"role\": \"homescreen\", \ + \"area\": \"full\", \ + }, \ + { \ + \"category\": \"map\", \ + \"role\": \"map\", \ + \"area\": \"full | normal | split.main\", \ + }, \ + { \ + \"category\": \"general\", \ + \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \ + \"area\": \"normal\", \ + }, \ + { \ + \"category\": \"phone\", \ + \"role\": \"phone\", \ + \"area\": \"normal\", \ + }, \ + { \ + \"category\": \"splitable\", \ + \"role\": \"splitable1 | splitable2\", \ + \"area\": \"normal | split.main | split.sub\", \ + }, \ + { \ + \"category\": \"popup\", \ + \"role\": \"popup\", \ + \"area\": \"on_screen\", \ + }, \ + { \ + \"category\": \"system_alert\", \ + \"role\": \"system_alert\", \ + \"area\": \"on_screen\", \ + }, \ + { \ + \"category\": \"tbt\", \ + \"role\": \"tbt\", \ + \"area\": \"hud\", \ + } \ + ] \ +}"; -- cgit 1.2.3-korg