351c7cec2e84214279ac2daae48fe3831fa0b84d
[apps/agl-service-windowmanager.git] / src / policy_manager / policy_manager.cpp
1 /*
2  * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17
18 #include <fstream>
19 #include <sstream>
20 #include <istream>
21 #include <thread>
22 #include <systemd/sd-event.h>
23 #include <json-c/json.h>
24 #include "policy_manager.hpp"
25 #include "hmi-debug.h"
26
27 namespace stm {
28 extern "C" {
29 #include "dummy_stm.h"
30 }
31 } // namespace stm
32
33
34 namespace pm {
35 struct EventData {
36     explicit EventData(int event, PolicyManager::Handler handler) {
37         this->event = event;
38         this->handler = handler;
39     };
40     ~EventData() = default;
41
42     int event;
43     PolicyManager::Handler handler;
44 };
45 }  // namespace pm
46
47 PolicyManager::PolicyManager() :
48   eventname2no_(),
49   categoryname2no_(),
50   areaname2no_(),
51   role2category_(),
52   category2role_(),
53   role2defaultarea_()
54 {
55     HMI_DEBUG("wm:pm", "Call");
56 }
57
58 int PolicyManager::initialize() {
59     HMI_DEBUG("wm:pm", "Call");
60
61     int ret = 0;
62
63     // Create convert map
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];
67     }
68
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];
72     }
73
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];
77     }
78
79     // Load role.db
80     ret = this->loadRoleDb();
81     if (0 > ret) {
82         HMI_ERROR("wm:pm", "Load role.db Error!!");
83         return ret;
84     }
85
86     // Initialize StateTransitioner
87     stm::stmInitialize();
88
89     // Initialize sd_event loop
90     ret = this->initializeSdEventLoop();
91     if (0 > ret) {
92         HMI_ERROR("wm:pm", "Failed to initializeSdEventLoop!!");
93         return ret;
94     }
95
96     return ret;
97 }
98
99 int PolicyManager::initializeSdEventLoop() {
100     // Get default event loop object
101     int ret = sd_event_new(&(this->sd_event_));
102     if (0 > ret) {
103         HMI_ERROR("wm:pm", "Faild to sd_event_default: errno:%d", ret);
104         return -1;
105     }
106
107     // Create thread for sd_event and detach
108     std::thread sd_event_loop([this]() {
109         while (1) {
110             sd_event_run(this->sd_event_, 1000);
111         }
112     });
113     sd_event_loop.detach();
114
115     return 0;
116 }
117
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!!!");
122         return;
123     }
124
125     json_object* json_obj = json_object_new_object();
126     json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed));
127     if (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));
130     }
131     json_object_object_add(*json_out, key, json_obj);
132 }
133
134 static int checkPolicy(sd_event_source *source, uint64_t usec, void *data) {
135     HMI_DEBUG("wm:pm", "Call");
136
137     pm::EventData *event_data = (pm::EventData*)data;
138
139     // Transition state
140     stm::stm_state_t crr_state;
141     int ret = stm::stmTransitionState(event_data->event, &crr_state);
142     if (0 > ret) {
143         HMI_ERROR("wm:pm", "Error!!");
144         return -1;
145     }
146
147     json_object* json_out = json_object_new_object();
148
149     // Create result
150     // {
151     //     "parking_brake": {
152     //         "is_changed": <bool>,
153     //         "state": <const char*>
154     //     },
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],
162                          &json_out);
163
164     //     "accel_pedal": {
165     //         "is_changed": <bool>,
166     //         "state": <const char*>
167     //     },
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],
175                          &json_out);
176
177     //     "lightstatus_brake": {
178     //         "is_changed": <bool>,
179     //         "state": <const char*>
180     //     },
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],
188                          &json_out);
189
190     //     "car": {
191     //         "is_changed": <bool>,
192     //         "state": <const char*>
193     //     },
194     HMI_DEBUG("wm", "car state (is_changed:%d state:%d:%s)",
195               crr_state.car.is_changed,
196               crr_state.car.state,
197               stm::gStmCarStateNo2Name[crr_state.car.state]);
198     addStateToJson("car",
199                          crr_state.car.is_changed,
200                          stm::gStmCarStateNo2Name[crr_state.car.state],
201                          &json_out);
202
203     //     "lamp": {
204     //         "is_changed": <bool>,
205     //         "state": <const char*>
206     //     },
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],
214                          &json_out);
215
216     //     "layers": [
217     json_object* json_layer = json_object_new_array();
218     json_object* json_tmp;
219
220     //         {
221     //             "homescreen": {
222     //                 "is_changed": <bool>,
223     //                 "state": <const char*>
224     //             }
225     //         },
226     //     ]
227     // }
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],
236                          &json_tmp);
237     json_object_array_add(json_layer, json_tmp);
238
239     //         {
240     //             "apps": {
241     //                 "is_changed": <bool>,
242     //                 "state": <const char*>
243     //             }
244     //         },
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],
253                          &json_tmp);
254     json_object_array_add(json_layer, json_tmp);
255
256     //         {
257     //             "restriction": {
258     //                 "is_changed": <bool>,
259     //                 "state": <const char*>
260     //             }
261     //         },
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],
270                          &json_tmp);
271     json_object_array_add(json_layer, json_tmp);
272
273     //         {
274     //             "on_screen": {
275     //                 "is_changed": <bool>,
276     //                 "state": <const char*>
277     //             }
278     //         },
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],
287                          &json_tmp);
288     json_object_array_add(json_layer, json_tmp);
289
290     // Add json array of layer
291     json_object_object_add(json_out, "layers", json_layer);
292
293     // Call event handler
294     event_data->handler(json_out);
295
296     // Release json_object
297     json_object_put(json_out);
298
299     // Release data
300     delete (pm::EventData*)data;
301
302     // Destroy sd_event_soutce object
303     sd_event_source_unref(source);
304
305     return 0;
306 }
307
308 void PolicyManager::checkPolicyEntry(int event, int delay_ms, PolicyManager::Handler handler)
309 {
310     HMI_DEBUG("wm:pm", "Call");
311
312     // Create event data
313     pm::EventData *event_data = new pm::EventData(event, handler);
314
315     // Get current time
316     struct timespec time_spec;
317     clock_gettime(CLOCK_MONOTONIC, &time_spec);
318
319     // Calculate timer fired time
320     uint64_t usec = (time_spec.tv_sec * 1000000)
321                     + (time_spec.tv_nsec / 1000)
322                     + (delay_ms * 1000);
323
324     // Set timer
325     int ret = sd_event_add_time(this->sd_event_, NULL, CLOCK_MONOTONIC, usec, 1,
326                                 &checkPolicy, event_data);
327     if (0 > ret) {
328         HMI_ERROR("wm:pm", "Faild to sd_event_add_time: errno:%d", ret);
329         return;
330     }
331 }
332
333 int PolicyManager::inputEvent(json_object* json_in, PolicyManager::Handler notify_state) {
334     HMI_DEBUG("wm:pm", "Call");
335
336     // Check arguments
337     if (nullptr == json_in) {
338         HMI_ERROR("wm:pm", "Argument is NULL!!");
339         return -1;
340     }
341
342     // Get event from json_object
343     const char* event = this->getStringFromJson(json_in, "event");
344     int event_no = 0;
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);
349     }
350
351     // Get role from json_object
352     const char* role = this->getStringFromJson(json_in, "role");
353     int category_no = 0;
354     if (nullptr != role) {
355         HMI_DEBUG("wm:pm", "role(%s)", role);
356
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!!");
361             return -1;
362         }
363         HMI_DEBUG("wm:pm", "category(%s)", category);
364
365         // Convert name to number
366         category_no = categoryname2no_[category];
367         HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
368     }
369
370     // Get areat from json_object
371     const char* area = this->getStringFromJson(json_in, "area");
372     int area_no = 0;
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);
377     }
378
379     HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no));
380
381     // Check policy
382     this->checkPolicyEntry((event_no | category_no | area_no), 0, notify_state);
383
384     return 0;
385 }
386
387 std::string PolicyManager::roleToCategory(const char* role) {
388     return this->role2category_[role];
389 }
390
391 extern const char* kDefaultRoleDb;
392 int PolicyManager::loadRoleDb() {
393     HMI_DEBUG("wm:pm", "Call");
394
395     std::string file_name;
396
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);
400
401     if (!afm_app_install_dir) {
402         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
403     }
404     else {
405         file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
406     }
407
408     // Load role.db
409     json_object* json_obj;
410     int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
411     if (0 > ret) {
412         HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
413         json_obj = json_tokener_parse(kDefaultRoleDb);
414     }
415     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
416
417     json_object* json_roles;
418     if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
419         HMI_ERROR("wm:pm", "Parse Error!!");
420         return -1;
421     }
422
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));
426
427     json_object* json_tmp;
428     const char* category;
429     const char* roles;
430     const char* areas;
431     for (int i=0; i<len; i++) {
432         json_tmp = json_object_array_get_idx(json_roles, i);
433
434         category = this->getStringFromJson(json_tmp, "category");
435         roles =  this->getStringFromJson(json_tmp, "role");
436         areas =  this->getStringFromJson(json_tmp, "area");
437
438         if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
439             HMI_ERROR("wm:pm", "Parse Error!!");
440             return -1;
441         }
442
443         // Parse roles by '|'
444         std::vector<std::string> vct_roles;
445         vct_roles = this->parseString(std::string(roles), '|');
446
447         // Parse areas by '|'
448         std::vector<std::string> vct_areas;
449         vct_areas = this->parseString(std::string(areas), '|');
450
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]);
456
457             this->role2category_[role] = std::string(category);
458             this->role2defaultarea_[role] = area;
459         }
460
461         this->category2role_[std::string(category)] = std::string(roles);
462     }
463
464     // Check
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());
468     }
469
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());
473     }
474
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());
478     }
479
480     return 0;
481 }
482
483 // TODO:
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!!!");
489         return nullptr;
490     }
491
492     json_object* tmp;
493     if (!json_object_object_get_ex(obj, key, &tmp)) {
494         HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
495         return nullptr;
496     }
497
498     return json_object_get_string(tmp);
499 }
500
501 // TODO:
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;
506     int ret = -1;
507
508     if ((nullptr == file) || (nullptr == obj)) {
509         HMI_ERROR("wm:jh", "Argument is nullptr!!!");
510         return ret;
511     }
512
513     HMI_DEBUG("wm:jh", "Input file: %s", file);
514
515     // Open json file
516     FILE *fp = fopen(file, "rb");
517     if (nullptr == fp) {
518         HMI_ERROR("wm:jh", "Could not open file");
519         return ret;
520     }
521
522     // Parse file data
523     struct json_tokener *tokener = json_tokener_new();
524     enum json_tokener_error json_error;
525     char buffer[input_size];
526     int block_cnt = 1;
527     while (1) {
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");
532             ret = 0;
533             break;
534         }
535
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);
542             *obj = nullptr;
543             break;
544         }
545         block_cnt++;
546     }
547
548     // Close json file
549     fclose(fp);
550
551     // Free json_tokener
552     json_tokener_free(tokener);
553
554     return ret;
555 }
556
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};
561     std::string buf;
562     while (std::getline(ss, buf, delimiter)) {
563       if (!buf.empty()) {
564         vct.push_back(buf);
565       }
566     }
567     return vct;
568 }
569
570 std::string PolicyManager::deleteSpace(std::string str) {
571     std::string ret = str;
572     size_t pos;
573     while ((pos = ret.find_first_of(" ")) != std::string::npos) {
574       ret.erase(pos, 1);
575     }
576     return ret;
577 }
578
579 const char* kDefaultRoleDb = "{ \
580     \"roles\":[ \
581     { \
582         \"category\": \"homescreen\", \
583         \"role\": \"homescreen\", \
584         \"area\": \"full\", \
585     }, \
586     { \
587         \"category\": \"map\", \
588         \"role\": \"map\", \
589         \"area\": \"full | normal | split.main\", \
590     }, \
591     { \
592         \"category\": \"general\", \
593         \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
594         \"area\": \"normal\", \
595     }, \
596     { \
597         \"category\": \"phone\", \
598         \"role\": \"phone\", \
599         \"area\": \"normal\", \
600     }, \
601     { \
602         \"category\": \"splitable\", \
603         \"role\": \"splitable1 | splitable2\", \
604         \"area\": \"normal | split.main | split.sub\", \
605     }, \
606     { \
607         \"category\": \"popup\", \
608         \"role\": \"popup\", \
609         \"area\": \"on_screen\", \
610     }, \
611     { \
612         \"category\": \"system_alert\", \
613         \"role\": \"system_alert\", \
614         \"area\": \"on_screen\", \
615     }, \
616     { \
617         \"category\": \"tbt\", \
618         \"role\": \"tbt\", \
619         \"area\": \"hud\", \
620     } \
621     ] \
622 }";