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