PolicyManager can judge the current car state
[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 <json-c/json.h>
22 #include "policy_manager.hpp"
23 #include "hmi-debug.h"
24
25 namespace stm {
26 extern "C" {
27 #include "dummy_stm.h"
28 }
29 } // namespace stm
30
31
32 PolicyManager::PolicyManager() :
33   eventname2no_(),
34   categoryname2no_(),
35   areaname2no_(),
36   role2category_(),
37   category2role_(),
38   role2defaultarea_()
39 {
40     HMI_DEBUG("wm:pm", "Call");
41 }
42
43 int PolicyManager::initialize() {
44     HMI_DEBUG("wm:pm", "Call");
45
46     int ret = 0;
47
48     // Create convert map
49     for (unsigned int i=0; i<STM_NUM_EVT; i++) {
50         HMI_DEBUG("wm:pm", "event name:%s no:%d", stm::gStmEventName[i], stm::gStmEventNo[i]);
51         this->eventname2no_[stm::gStmEventName[i]] = stm::gStmEventNo[i];
52     }
53
54     for (unsigned int i=0; i<STM_NUM_CTG; i++) {
55         HMI_DEBUG("wm:pm", "category name:%s no:%d", stm::gStmCategoryName[i], stm::gStmCategoryNo[i]);
56         this->categoryname2no_[stm::gStmCategoryName[i]] = stm::gStmCategoryNo[i];
57     }
58
59     for (unsigned int i=0; i<STM_NUM_ARA; i++) {
60         HMI_DEBUG("wm:pm", "area name:%s no:%d", stm::gStmAreaName[i], stm::gStmAreaNo[i]);
61         this->areaname2no_[stm::gStmAreaName[i]] = stm::gStmAreaNo[i];
62     }
63
64     // Load role.db
65     ret = loadRoleDb();
66     if (0 > ret) {
67         HMI_ERROR("wm:pm", "Load role.db Error!!");
68         return ret;
69     }
70
71     // Initialize StateTransitioner
72     stm::stmInitialize();
73
74     return ret;
75 }
76
77 int PolicyManager::checkPolicy(json_object* json_in, json_object** json_out) {
78     HMI_DEBUG("wm:pm", "Call");
79
80     // Check arguments
81     if ((nullptr == json_in) || (nullptr == json_out)) {
82         HMI_ERROR("wm:pm", "Argument is NULL!!");
83         return -1;
84     }
85
86     // Get event from json_object
87     const char* event = this->getStringFromJson(json_in, "event");
88     int event_no = 0;
89     if (nullptr != event) {
90         // Convert name to number
91         event_no = this->eventname2no_[event];
92         HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no);
93     }
94
95     // Get role from json_object
96     const char* role = this->getStringFromJson(json_in, "role");
97     int category_no = 0;
98     if (nullptr != role) {
99         HMI_DEBUG("wm:pm", "role(%s)", role);
100
101         // Convert role to category
102         const char* category = this->role2category_[role].c_str();
103         if (0 == strcmp("", category)) {
104             HMI_ERROR("wm:pm", "Error!!");
105             return -1;
106         }
107         HMI_DEBUG("wm:pm", "category(%s)", category);
108
109         // Convert name to number
110         category_no = categoryname2no_[category];
111         HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
112     }
113
114     // Get areat from json_object
115     const char* area = this->getStringFromJson(json_in, "area");
116     int area_no = 0;
117     if (nullptr != area) {
118         // Convert name to number
119         area_no = areaname2no_[area];
120         HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no);
121     }
122
123     HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no));
124
125     // Transition state
126     stm::stm_state_t crr_state;
127     int ret = stm::stmTransitionState((event_no | category_no | area_no), &crr_state);
128     if (0 > ret) {
129         HMI_ERROR("wm:pm", "Error!!");
130         return -1;
131     }
132
133     // Create result
134     // {
135     //     "parking_brake": {
136     //         "is_changed": <bool>,
137     //         "state": <const char*>
138     //     },
139     HMI_DEBUG("wm", "parking brake state (is_changed:%d state:%d:%s)",
140               crr_state.parking_brake.is_changed,
141               crr_state.parking_brake.state,
142               stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state]);
143     this->addStateToJson("parking_brake",
144                          crr_state.parking_brake.is_changed,
145                          stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state],
146                          json_out);
147
148     //     "accel_pedal": {
149     //         "is_changed": <bool>,
150     //         "state": <const char*>
151     //     },
152     HMI_DEBUG("wm", "accelerator pedal state (is_changed:%d state:%d:%s)",
153               crr_state.accel_pedal.is_changed,
154               crr_state.accel_pedal.state,
155               stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state]);
156     this->addStateToJson("accel_pedal",
157                          crr_state.accel_pedal.is_changed,
158                          stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state],
159                          json_out);
160
161     //     "car": {
162     //         "is_changed": <bool>,
163     //         "state": <const char*>
164     //     },
165     HMI_DEBUG("wm", "car state (is_changed:%d state:%d:%s)",
166               crr_state.car.is_changed,
167               crr_state.car.state,
168               stm::gStmCarStateNo2Name[crr_state.car.state]);
169     this->addStateToJson("car",
170                          crr_state.car.is_changed,
171                          stm::gStmCarStateNo2Name[crr_state.car.state],
172                          json_out);
173
174     //     "lamp": {
175     //         "is_changed": <bool>,
176     //         "state": <const char*>
177     //     },
178     HMI_DEBUG("wm", "lamp state (is_changed:%d state:%d:%s)",
179               crr_state.lamp.is_changed,
180               crr_state.lamp.state,
181               stm::gStmLampStateNo2Name[crr_state.lamp.state]);
182     this->addStateToJson("lamp",
183                          crr_state.lamp.is_changed,
184                          stm::gStmLampStateNo2Name[crr_state.lamp.state],
185                          json_out);
186
187     //     "layers": [
188     //         {
189     //             "on_screen": {
190     //                 "is_changed": <bool>,
191     //                 "state": <const char*>
192     //             }
193     //         },
194     json_object* json_layer = json_object_new_array();
195     json_object* json_tmp = json_object_new_object();
196     HMI_DEBUG("wm", "on_screen state (is_changed:%d state:%d:%s)",
197               crr_state.layer.on_screen.is_changed,
198               crr_state.layer.on_screen.state,
199               stm::gStmLayoutNo2Name[crr_state.layer.on_screen.state]);
200     this->addStateToJson("on_screen",
201                          crr_state.layer.on_screen.is_changed,
202                          stm::gStmLayoutNo2Name[crr_state.layer.on_screen.state],
203                          &json_tmp);
204     json_object_array_add(json_layer, json_tmp);
205
206     //         {
207     //             "restriction": {
208     //                 "is_changed": <bool>,
209     //                 "state": <const char*>
210     //             }
211     //         },
212     HMI_DEBUG("wm", "restriction state (is_changed:%d state:%d:%s)",
213               crr_state.layer.restriction.is_changed,
214               crr_state.layer.restriction.state,
215               stm::gStmLayoutNo2Name[crr_state.layer.restriction.state]);
216     json_tmp = json_object_new_object();
217     this->addStateToJson("restriction",
218                          crr_state.layer.restriction.is_changed,
219                          stm::gStmLayoutNo2Name[crr_state.layer.restriction.state],
220                          &json_tmp);
221     json_object_array_add(json_layer, json_tmp);
222
223     //         {
224     //             "apps": {
225     //                 "is_changed": <bool>,
226     //                 "state": <const char*>
227     //             }
228     //         },
229     HMI_DEBUG("wm", "apps state (is_changed:%d state:%d:%s)",
230               crr_state.layer.apps.is_changed,
231               crr_state.layer.apps.state,
232               stm::gStmLayoutNo2Name[crr_state.layer.apps.state]);
233     json_tmp = json_object_new_object();
234     this->addStateToJson("apps",
235                          crr_state.layer.apps.is_changed,
236                          stm::gStmLayoutNo2Name[crr_state.layer.apps.state],
237                          &json_tmp);
238     json_object_array_add(json_layer, json_tmp);
239
240     //         {
241     //             "homescreen": {
242     //                 "is_changed": <bool>,
243     //                 "state": <const char*>
244     //             }
245     //         },
246     //     ]
247     // }
248     HMI_DEBUG("wm", "homescreen state (is_changed:%d state:%d:%s)",
249               crr_state.layer.homescreen.is_changed,
250               crr_state.layer.homescreen.state,
251               stm::gStmLayoutNo2Name[crr_state.layer.homescreen.state]);
252     json_tmp = json_object_new_object();
253     this->addStateToJson("homescreen",
254                          crr_state.layer.homescreen.is_changed,
255                          stm::gStmLayoutNo2Name[crr_state.layer.homescreen.state],
256                          &json_tmp);
257     json_object_array_add(json_layer, json_tmp);
258
259     // Add json array of layer
260     json_object_object_add(*json_out, "layers", json_layer);
261
262     return 0;
263 }
264
265 std::string PolicyManager::roleToCategory(const char* role) {
266     return this->role2category_[role];
267 }
268
269 extern const char* kDefaultRoleDb;
270 int PolicyManager::loadRoleDb() {
271     HMI_DEBUG("wm:pm", "Call");
272
273     std::string file_name;
274
275     // Get afm application installed dir
276     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
277     HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
278
279     if (!afm_app_install_dir) {
280         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
281     }
282     else {
283         file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
284     }
285
286     // Load role.db
287     json_object* json_obj;
288     int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
289     if (0 > ret) {
290         HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
291         json_obj = json_tokener_parse(kDefaultRoleDb);
292     }
293     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
294
295     json_object* json_roles;
296     if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
297         HMI_ERROR("wm:pm", "Parse Error!!");
298         return -1;
299     }
300
301     int len = json_object_array_length(json_roles);
302     HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
303     HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles));
304
305     json_object* json_tmp;
306     const char* category;
307     const char* roles;
308     const char* areas;
309     for (int i=0; i<len; i++) {
310         json_tmp = json_object_array_get_idx(json_roles, i);
311
312         category = this->getStringFromJson(json_tmp, "category");
313         roles =  this->getStringFromJson(json_tmp, "role");
314         areas =  this->getStringFromJson(json_tmp, "area");
315
316         if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
317             HMI_ERROR("wm:pm", "Parse Error!!");
318             return -1;
319         }
320
321         // Parse roles by '|'
322         std::vector<std::string> vct_roles;
323         vct_roles = this->parseString(std::string(roles), '|');
324
325         // Parse areas by '|'
326         std::vector<std::string> vct_areas;
327         vct_areas = this->parseString(std::string(areas), '|');
328
329         // Set role, category, default area
330         for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) {
331             // Delete space from role and area name
332             std::string role = this->deleteSpace(*itr);
333             std::string area = this->deleteSpace(vct_areas[0]);
334
335             this->role2category_[role] = std::string(category);
336             this->role2defaultarea_[role] = area;
337         }
338
339         this->category2role_[std::string(category)] = std::string(roles);
340     }
341
342     // Check
343     HMI_DEBUG("wm:pm", "Check role2category_");
344     for (auto& x:this->role2category_){
345         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
346     }
347
348     HMI_DEBUG("wm:pm", "Check role2defaultarea_");
349     for (auto& x:this->role2defaultarea_){
350         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
351     }
352
353     HMI_DEBUG("wm:pm", "Check category2role_");
354     for (auto& x:this->category2role_){
355         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
356     }
357
358     return 0;
359 }
360
361 // TODO:
362 // This function will be removed because json_helper has same function.
363 // json_helper should be library.
364 const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) {
365     if ((nullptr == obj) || (nullptr == key)) {
366         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
367         return nullptr;
368     }
369
370     json_object* tmp;
371     if (!json_object_object_get_ex(obj, key, &tmp)) {
372         HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
373         return nullptr;
374     }
375
376     return json_object_get_string(tmp);
377 }
378
379 // TODO:
380 // This function will be removed because json_helper has same function.
381 // json_helper should be library.
382 int PolicyManager::inputJsonFilie(const char* file, json_object** obj) {
383     const int input_size = 128;
384     int ret = -1;
385
386     if ((nullptr == file) || (nullptr == obj)) {
387         HMI_ERROR("wm:jh", "Argument is nullptr!!!");
388         return ret;
389     }
390
391     HMI_DEBUG("wm:jh", "Input file: %s", file);
392
393     // Open json file
394     FILE *fp = fopen(file, "rb");
395     if (nullptr == fp) {
396         HMI_ERROR("wm:jh", "Could not open file");
397         return ret;
398     }
399
400     // Parse file data
401     struct json_tokener *tokener = json_tokener_new();
402     enum json_tokener_error json_error;
403     char buffer[input_size];
404     int block_cnt = 1;
405     while (1) {
406         size_t len = fread(buffer, sizeof(char), input_size, fp);
407         *obj = json_tokener_parse_ex(tokener, buffer, len);
408         if (nullptr != *obj) {
409             HMI_DEBUG("wm:jh", "File input is success");
410             ret = 0;
411             break;
412         }
413
414         json_error = json_tokener_get_error(tokener);
415         if ((json_tokener_continue != json_error)
416             || (input_size > len)) {
417             HMI_ERROR("wm:jh", "Failed to parse file (byte:%d err:%s)",
418                       (input_size * block_cnt), json_tokener_error_desc(json_error));
419             HMI_ERROR("wm:jh", "\n%s", buffer);
420             *obj = nullptr;
421             break;
422         }
423         block_cnt++;
424     }
425
426     // Close json file
427     fclose(fp);
428
429     // Free json_tokener
430     json_tokener_free(tokener);
431
432     return ret;
433 }
434
435 void PolicyManager::addStateToJson(
436   const char* key, int is_changed, const char* state, json_object** json_out) {
437     if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) {
438         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
439         return;
440     }
441
442     json_object* json_obj = json_object_new_object();
443     json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed));
444     if (is_changed) {
445         HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state);
446         json_object_object_add(json_obj, "state", json_object_new_string(state));
447     }
448     json_object_object_add(*json_out, key, json_obj);
449 }
450
451 std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) {
452     // Parse string by delimiter
453     std::vector<std::string> vct;
454     std::stringstream ss{str};
455     std::string buf;
456     while (std::getline(ss, buf, delimiter)) {
457       if (!buf.empty()) {
458         vct.push_back(buf);
459       }
460     }
461     return vct;
462 }
463
464 std::string PolicyManager::deleteSpace(std::string str) {
465     std::string ret = str;
466     size_t pos;
467     while ((pos = ret.find_first_of(" ")) != std::string::npos) {
468       ret.erase(pos, 1);
469     }
470     return ret;
471 }
472
473 const char* kDefaultRoleDb = "{ \
474     \"roles\":[ \
475     { \
476         \"category\": \"homescreen\", \
477         \"role\": \"homescreen\", \
478         \"area\": \"full\", \
479     }, \
480     { \
481         \"category\": \"map\", \
482         \"role\": \"map\", \
483         \"area\": \"full | normal | split.main\", \
484     }, \
485     { \
486         \"category\": \"general\", \
487         \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
488         \"area\": \"normal\", \
489     }, \
490     { \
491         \"category\": \"phone\", \
492         \"role\": \"phone\", \
493         \"area\": \"normal\", \
494     }, \
495     { \
496         \"category\": \"splitable\", \
497         \"role\": \"splitable1 | splitable2\", \
498         \"area\": \"normal | split.main | split.sub\", \
499     }, \
500     { \
501         \"category\": \"popup\", \
502         \"role\": \"popup\", \
503         \"area\": \"on_screen\", \
504     }, \
505     { \
506         \"category\": \"system_alert\", \
507         \"role\": \"system_alert\", \
508         \"area\": \"on_screen\", \
509     }, \
510     { \
511         \"category\": \"tbt\", \
512         \"role\": \"tbt\", \
513         \"area\": \"hud\", \
514     } \
515     ] \
516 }";