2 * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <systemd/sd-event.h>
23 #include <json-c/json.h>
24 #include "policy_manager.hpp"
25 #include "hmi-debug.h"
29 #include "dummy_stm.h"
36 explicit EventData(int event, PolicyManager::Handler handler) {
38 this->handler = handler;
40 ~EventData() = default;
43 PolicyManager::Handler handler;
47 PolicyManager::PolicyManager() :
55 HMI_DEBUG("wm:pm", "Call");
58 int PolicyManager::initialize() {
59 HMI_DEBUG("wm:pm", "Call");
64 for (unsigned int i=0; i<STM_NUM_EVT; i++) {
65 HMI_DEBUG("wm:pm", "event name:%s no:%d", stm::gStmEventName[i], stm::gStmEventNo[i]);
66 this->eventname2no_[stm::gStmEventName[i]] = stm::gStmEventNo[i];
69 for (unsigned int i=0; i<STM_NUM_CTG; i++) {
70 HMI_DEBUG("wm:pm", "category name:%s no:%d", stm::gStmCategoryName[i], stm::gStmCategoryNo[i]);
71 this->categoryname2no_[stm::gStmCategoryName[i]] = stm::gStmCategoryNo[i];
74 for (unsigned int i=0; i<STM_NUM_ARA; i++) {
75 HMI_DEBUG("wm:pm", "area name:%s no:%d", stm::gStmAreaName[i], stm::gStmAreaNo[i]);
76 this->areaname2no_[stm::gStmAreaName[i]] = stm::gStmAreaNo[i];
80 ret = this->loadRoleDb();
82 HMI_ERROR("wm:pm", "Load role.db Error!!");
86 // Initialize StateTransitioner
89 // Initialize sd_event loop
90 ret = this->initializeSdEventLoop();
92 HMI_ERROR("wm:pm", "Failed to initializeSdEventLoop!!");
99 int PolicyManager::initializeSdEventLoop() {
100 // Get default event loop object
101 int ret = sd_event_new(&(this->sd_event_));
103 HMI_ERROR("wm:pm", "Faild to sd_event_default: errno:%d", ret);
107 // Create thread for sd_event and detach
108 std::thread sd_event_loop([this]() {
110 sd_event_run(this->sd_event_, 1000);
113 sd_event_loop.detach();
118 static void addStateToJson(
119 const char* key, int is_changed, const char* state, json_object** json_out) {
120 if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) {
121 HMI_ERROR("wm:pm", "Argument is nullptr!!!");
125 json_object* json_obj = json_object_new_object();
126 json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed));
128 HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state);
129 json_object_object_add(json_obj, "state", json_object_new_string(state));
131 json_object_object_add(*json_out, key, json_obj);
134 static int checkPolicy(sd_event_source *source, uint64_t usec, void *data) {
135 HMI_DEBUG("wm:pm", "Call");
137 pm::EventData *event_data = (pm::EventData*)data;
140 stm::stm_state_t crr_state;
141 int ret = stm::stmTransitionState(event_data->event, &crr_state);
143 HMI_ERROR("wm:pm", "Error!!");
147 json_object* json_out = json_object_new_object();
151 // "parking_brake": {
152 // "is_changed": <bool>,
153 // "state": <const char*>
155 HMI_DEBUG("wm", "parking brake state (is_changed:%d state:%d:%s)",
156 crr_state.parking_brake.is_changed,
157 crr_state.parking_brake.state,
158 stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state]);
159 addStateToJson("parking_brake",
160 crr_state.parking_brake.is_changed,
161 stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state],
165 // "is_changed": <bool>,
166 // "state": <const char*>
168 HMI_DEBUG("wm", "accelerator pedal state (is_changed:%d state:%d:%s)",
169 crr_state.accel_pedal.is_changed,
170 crr_state.accel_pedal.state,
171 stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state]);
172 addStateToJson("accel_pedal",
173 crr_state.accel_pedal.is_changed,
174 stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state],
177 // "lightstatus_brake": {
178 // "is_changed": <bool>,
179 // "state": <const char*>
181 HMI_DEBUG("wm", "lightstatus brake state (is_changed:%d state:%d:%s)",
182 crr_state.lightstatus_brake.is_changed,
183 crr_state.lightstatus_brake.state,
184 stm::gStmLightstatusBrakeStateNo2Name[crr_state.lightstatus_brake.state]);
185 addStateToJson("lightstatus_brake",
186 crr_state.lightstatus_brake.is_changed,
187 stm::gStmLightstatusBrakeStateNo2Name[crr_state.lightstatus_brake.state],
191 // "is_changed": <bool>,
192 // "state": <const char*>
194 HMI_DEBUG("wm", "car state (is_changed:%d state:%d:%s)",
195 crr_state.car.is_changed,
197 stm::gStmCarStateNo2Name[crr_state.car.state]);
198 addStateToJson("car",
199 crr_state.car.is_changed,
200 stm::gStmCarStateNo2Name[crr_state.car.state],
204 // "is_changed": <bool>,
205 // "state": <const char*>
207 HMI_DEBUG("wm", "lamp state (is_changed:%d state:%d:%s)",
208 crr_state.lamp.is_changed,
209 crr_state.lamp.state,
210 stm::gStmLampStateNo2Name[crr_state.lamp.state]);
211 addStateToJson("lamp",
212 crr_state.lamp.is_changed,
213 stm::gStmLampStateNo2Name[crr_state.lamp.state],
217 json_object* json_layer = json_object_new_array();
218 json_object* json_tmp;
222 // "is_changed": <bool>,
223 // "state": <const char*>
228 HMI_DEBUG("wm", "homescreen state (is_changed:%d state:%d:%s)",
229 crr_state.layer.homescreen.is_changed,
230 crr_state.layer.homescreen.state,
231 stm::gStmLayoutNo2Name[crr_state.layer.homescreen.state]);
232 json_tmp = json_object_new_object();
233 addStateToJson("homescreen",
234 crr_state.layer.homescreen.is_changed,
235 stm::gStmLayoutNo2Name[crr_state.layer.homescreen.state],
237 json_object_array_add(json_layer, json_tmp);
241 // "is_changed": <bool>,
242 // "state": <const char*>
245 HMI_DEBUG("wm", "apps state (is_changed:%d state:%d:%s)",
246 crr_state.layer.apps.is_changed,
247 crr_state.layer.apps.state,
248 stm::gStmLayoutNo2Name[crr_state.layer.apps.state]);
249 json_tmp = json_object_new_object();
250 addStateToJson("apps",
251 crr_state.layer.apps.is_changed,
252 stm::gStmLayoutNo2Name[crr_state.layer.apps.state],
254 json_object_array_add(json_layer, json_tmp);
258 // "is_changed": <bool>,
259 // "state": <const char*>
262 HMI_DEBUG("wm", "restriction state (is_changed:%d state:%d:%s)",
263 crr_state.layer.restriction.is_changed,
264 crr_state.layer.restriction.state,
265 stm::gStmLayoutNo2Name[crr_state.layer.restriction.state]);
266 json_tmp = json_object_new_object();
267 addStateToJson("restriction",
268 crr_state.layer.restriction.is_changed,
269 stm::gStmLayoutNo2Name[crr_state.layer.restriction.state],
271 json_object_array_add(json_layer, json_tmp);
275 // "is_changed": <bool>,
276 // "state": <const char*>
279 HMI_DEBUG("wm", "on_screen state (is_changed:%d state:%d:%s)",
280 crr_state.layer.on_screen.is_changed,
281 crr_state.layer.on_screen.state,
282 stm::gStmLayoutNo2Name[crr_state.layer.on_screen.state]);
283 json_tmp = json_object_new_object();
284 addStateToJson("on_screen",
285 crr_state.layer.on_screen.is_changed,
286 stm::gStmLayoutNo2Name[crr_state.layer.on_screen.state],
288 json_object_array_add(json_layer, json_tmp);
290 // Add json array of layer
291 json_object_object_add(json_out, "layers", json_layer);
293 // Call event handler
294 event_data->handler(json_out);
296 // Release json_object
297 json_object_put(json_out);
300 delete (pm::EventData*)data;
302 // Destroy sd_event_soutce object
303 sd_event_source_unref(source);
308 void PolicyManager::checkPolicyEntry(int event, int delay_ms, PolicyManager::Handler handler)
310 HMI_DEBUG("wm:pm", "Call");
313 pm::EventData *event_data = new pm::EventData(event, handler);
316 struct timespec time_spec;
317 clock_gettime(CLOCK_MONOTONIC, &time_spec);
319 // Calculate timer fired time
320 uint64_t usec = (time_spec.tv_sec * 1000000)
321 + (time_spec.tv_nsec / 1000)
325 int ret = sd_event_add_time(this->sd_event_, NULL, CLOCK_MONOTONIC, usec, 1,
326 &checkPolicy, event_data);
328 HMI_ERROR("wm:pm", "Faild to sd_event_add_time: errno:%d", ret);
333 int PolicyManager::inputEvent(json_object* json_in, PolicyManager::Handler notify_state) {
334 HMI_DEBUG("wm:pm", "Call");
337 if (nullptr == json_in) {
338 HMI_ERROR("wm:pm", "Argument is NULL!!");
342 // Get event from json_object
343 const char* event = this->getStringFromJson(json_in, "event");
345 if (nullptr != event) {
346 // Convert name to number
347 event_no = this->eventname2no_[event];
348 HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no);
351 // Get role from json_object
352 const char* role = this->getStringFromJson(json_in, "role");
354 if (nullptr != role) {
355 HMI_DEBUG("wm:pm", "role(%s)", role);
357 // Convert role to category
358 const char* category = this->role2category_[role].c_str();
359 if (0 == strcmp("", category)) {
360 HMI_ERROR("wm:pm", "Error!!");
363 HMI_DEBUG("wm:pm", "category(%s)", category);
365 // Convert name to number
366 category_no = categoryname2no_[category];
367 HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
370 // Get areat from json_object
371 const char* area = this->getStringFromJson(json_in, "area");
373 if (nullptr != area) {
374 // Convert name to number
375 area_no = areaname2no_[area];
376 HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no);
379 HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no));
382 this->checkPolicyEntry((event_no | category_no | area_no), 0, notify_state);
387 std::string PolicyManager::roleToCategory(const char* role) {
388 return this->role2category_[role];
391 extern const char* kDefaultRoleDb;
392 int PolicyManager::loadRoleDb() {
393 HMI_DEBUG("wm:pm", "Call");
395 std::string file_name;
397 // Get afm application installed dir
398 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
399 HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
401 if (!afm_app_install_dir) {
402 HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
405 file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
409 json_object* json_obj;
410 int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
412 HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
413 json_obj = json_tokener_parse(kDefaultRoleDb);
415 HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
417 json_object* json_roles;
418 if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
419 HMI_ERROR("wm:pm", "Parse Error!!");
423 int len = json_object_array_length(json_roles);
424 HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
425 HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles));
427 json_object* json_tmp;
428 const char* category;
431 for (int i=0; i<len; i++) {
432 json_tmp = json_object_array_get_idx(json_roles, i);
434 category = this->getStringFromJson(json_tmp, "category");
435 roles = this->getStringFromJson(json_tmp, "role");
436 areas = this->getStringFromJson(json_tmp, "area");
438 if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
439 HMI_ERROR("wm:pm", "Parse Error!!");
443 // Parse roles by '|'
444 std::vector<std::string> vct_roles;
445 vct_roles = this->parseString(std::string(roles), '|');
447 // Parse areas by '|'
448 std::vector<std::string> vct_areas;
449 vct_areas = this->parseString(std::string(areas), '|');
451 // Set role, category, default area
452 for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) {
453 // Delete space from role and area name
454 std::string role = this->deleteSpace(*itr);
455 std::string area = this->deleteSpace(vct_areas[0]);
457 this->role2category_[role] = std::string(category);
458 this->role2defaultarea_[role] = area;
461 this->category2role_[std::string(category)] = std::string(roles);
465 HMI_DEBUG("wm:pm", "Check role2category_");
466 for (auto& x:this->role2category_){
467 HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
470 HMI_DEBUG("wm:pm", "Check role2defaultarea_");
471 for (auto& x:this->role2defaultarea_){
472 HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
475 HMI_DEBUG("wm:pm", "Check category2role_");
476 for (auto& x:this->category2role_){
477 HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
484 // This function will be removed because json_helper has same function.
485 // json_helper should be library.
486 const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) {
487 if ((nullptr == obj) || (nullptr == key)) {
488 HMI_ERROR("wm:pm", "Argument is nullptr!!!");
493 if (!json_object_object_get_ex(obj, key, &tmp)) {
494 HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
498 return json_object_get_string(tmp);
502 // This function will be removed because json_helper has same function.
503 // json_helper should be library.
504 int PolicyManager::inputJsonFilie(const char* file, json_object** obj) {
505 const int input_size = 128;
508 if ((nullptr == file) || (nullptr == obj)) {
509 HMI_ERROR("wm:jh", "Argument is nullptr!!!");
513 HMI_DEBUG("wm:jh", "Input file: %s", file);
516 FILE *fp = fopen(file, "rb");
518 HMI_ERROR("wm:jh", "Could not open file");
523 struct json_tokener *tokener = json_tokener_new();
524 enum json_tokener_error json_error;
525 char buffer[input_size];
528 size_t len = fread(buffer, sizeof(char), input_size, fp);
529 *obj = json_tokener_parse_ex(tokener, buffer, len);
530 if (nullptr != *obj) {
531 HMI_DEBUG("wm:jh", "File input is success");
536 json_error = json_tokener_get_error(tokener);
537 if ((json_tokener_continue != json_error)
538 || (input_size > len)) {
539 HMI_ERROR("wm:jh", "Failed to parse file (byte:%d err:%s)",
540 (input_size * block_cnt), json_tokener_error_desc(json_error));
541 HMI_ERROR("wm:jh", "\n%s", buffer);
552 json_tokener_free(tokener);
557 std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) {
558 // Parse string by delimiter
559 std::vector<std::string> vct;
560 std::stringstream ss{str};
562 while (std::getline(ss, buf, delimiter)) {
570 std::string PolicyManager::deleteSpace(std::string str) {
571 std::string ret = str;
573 while ((pos = ret.find_first_of(" ")) != std::string::npos) {
579 const char* kDefaultRoleDb = "{ \
582 \"category\": \"homescreen\", \
583 \"role\": \"homescreen\", \
584 \"area\": \"full\", \
587 \"category\": \"map\", \
589 \"area\": \"full | normal | split.main\", \
592 \"category\": \"general\", \
593 \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
594 \"area\": \"normal\", \
597 \"category\": \"phone\", \
598 \"role\": \"phone\", \
599 \"area\": \"normal\", \
602 \"category\": \"splitable\", \
603 \"role\": \"splitable1 | splitable2\", \
604 \"area\": \"normal | split.main | split.sub\", \
607 \"category\": \"popup\", \
608 \"role\": \"popup\", \
609 \"area\": \"on_screen\", \
612 \"category\": \"system_alert\", \
613 \"role\": \"system_alert\", \
614 \"area\": \"on_screen\", \
617 \"category\": \"tbt\", \