47d9eac52954e161bed257d9003ed3079253332e
[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 #if 0
24 extern "C" {
25 #include "dummy_stm.h"
26 }
27 #endif
28 #include "hmi-debug.h"
29
30
31 PolicyManager::PolicyManager() :
32   eventname2no_(),
33   categoryname2no_(),
34   areaname2no_(),
35   role2category_(),
36   category2role_(),
37   role2defaultarea_(),
38   current_state_()
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     // TODO:
72     // Initialize StateTransitioner
73     // stmInitialize();
74
75     return ret;
76 }
77
78 int PolicyManager::checkPolicy(json_object* json_in, json_object** json_out) {
79     HMI_DEBUG("wm:pm", "Call");
80
81     // Check arguments
82     if ((nullptr == json_in) || (nullptr == json_out)) {
83         HMI_ERROR("wm:pm", "Argument is NULL!!");
84         return -1;
85     }
86
87     // Get event from json_object
88     const char* event = getStringFromJson(json_in, "event");
89     int event_no = 0;
90     if (nullptr != event) {
91         // Convert name to number
92         event_no = this->eventname2no_[event];
93         HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no);
94     }
95
96     // Get role from json_object
97     const char* role = getStringFromJson(json_in, "role");
98     int category_no = 0;
99     if (nullptr != role) {
100         HMI_DEBUG("wm:pm", "role(%s)", role);
101
102         // Convert role to category
103         const char* category = this->role2category_[role].c_str();
104         if (0 == strcmp("", category)) {
105             HMI_ERROR("wm:pm", "Error!!");
106             return -1;
107         }
108         HMI_DEBUG("wm:pm", "category(%s)", category);
109
110         // Convert name to number
111         category_no = categoryname2no_[category];
112         HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
113     }
114
115     // Get areat from json_object
116     const char* area = getStringFromJson(json_in, "area");
117     int area_no = 0;
118     if (nullptr != area) {
119         // Convert name to number
120         area_no = areaname2no_[area];
121         HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no);
122     }
123
124     // Transition state
125     HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no));
126     int ret = stmTransitionState((event_no | category_no | area_no),
127                                        &(this->current_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               this->current_state_.parking_brake.is_changed,
141               this->current_state_.parking_brake.state,
142               stm::gStmCarStateNo2Name[this->current_state_.parking_brake.state]);
143     this->addStateToJson("parking_brake",
144                          this->current_state_.parking_brake.is_changed,
145                          stm::gStmParkingBrakeStateNo2Name[this->current_state_.parking_brake.state],
146                          json_out);
147
148     //     "car": {
149     //         "is_changed": <bool>,
150     //         "state": <const char*>
151     //     },
152     HMI_DEBUG("wm", "car state (is_changed:%d state:%d:%s)",
153               this->current_state_.car.is_changed,
154               this->current_state_.car.state,
155               stm::gStmCarStateNo2Name[this->current_state_.car.state]);
156     this->addStateToJson("car",
157                          this->current_state_.car.is_changed,
158                          stm::gStmCarStateNo2Name[this->current_state_.car.state],
159                          json_out);
160
161     //     "lamp": {
162     //         "is_changed": <bool>,
163     //         "state": <const char*>
164     //     },
165     HMI_DEBUG("wm", "lamp state (is_changed:%d state:%d:%s)",
166               this->current_state_.lamp.is_changed,
167               this->current_state_.lamp.state,
168               stm::gStmLampStateNo2Name[this->current_state_.lamp.state]);
169     this->addStateToJson("lamp",
170                          this->current_state_.lamp.is_changed,
171                          stm::gStmLampStateNo2Name[this->current_state_.lamp.state],
172                          json_out);
173
174     //     "layers": [
175     //         {
176     //             "on_screen": {
177     //                 "is_changed": <bool>,
178     //                 "state": <const char*>
179     //             }
180     //         },
181     json_object* json_layer = json_object_new_array();
182     json_object* json_tmp = json_object_new_object();
183     this->addStateToJson("on_screen",
184                          this->current_state_.layer.on_screen.is_changed,
185                          stm::gStmLayoutNo2Name[this->current_state_.layer.on_screen.state],
186                          &json_tmp);
187     json_object_array_add(json_layer, json_tmp);
188
189     //         {
190     //             "apps": {
191     //                 "is_changed": <bool>,
192     //                 "state": <const char*>
193     //             }
194     //         },
195     json_tmp = json_object_new_object();
196     this->addStateToJson("apps",
197                          this->current_state_.layer.apps.is_changed,
198                          stm::gStmLayoutNo2Name[this->current_state_.layer.apps.state],
199                          &json_tmp);
200     json_object_array_add(json_layer, json_tmp);
201
202     //         {
203     //             "homescreen": {
204     //                 "is_changed": <bool>,
205     //                 "state": <const char*>
206     //             }
207     //         },
208     //     ]
209     // }
210     json_tmp = json_object_new_object();
211     this->addStateToJson("homescreen",
212                          this->current_state_.layer.homescreen.is_changed,
213                          stm::gStmLayoutNo2Name[this->current_state_.layer.homescreen.state],
214                          &json_tmp);
215     json_object_array_add(json_layer, json_tmp);
216
217     // Add json array of layer
218     json_object_object_add(*json_out, "layers", json_layer);
219
220     HMI_DEBUG("wm:pm", "json_out.dump:%s", json_object_get_string(*json_out));
221
222     return 0;
223 }
224
225 std::string PolicyManager::roleToCategory(const char* role) {
226     return this->role2category_[role];
227 }
228
229 extern const char* kDefaultRoleDb;
230 int PolicyManager::loadRoleDb() {
231     HMI_DEBUG("wm:pm", "Call");
232
233     std::string file_name;
234
235     // Get afm application installed dir
236     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
237     HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
238
239     if (!afm_app_install_dir) {
240         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
241     }
242     else {
243         file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
244     }
245
246     // Load role.db
247     HMI_DEBUG("wm:pm", "file_name:%s", file_name.c_str());
248     json_object* json_obj = json_object_from_file(file_name.c_str());
249     if (nullptr == json_obj) {
250         HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
251         json_obj = json_tokener_parse(kDefaultRoleDb);
252     }
253     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
254
255     json_object* json_roles;
256     if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
257         HMI_ERROR("wm:pm", "Parse Error!!");
258         return -1;
259     }
260
261     int len = json_object_array_length(json_roles);
262     HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
263     HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles));
264
265     json_object* json_tmp;
266     const char* category;
267     const char* roles;
268     const char* areas;
269     for (int i=0; i<len; i++) {
270         json_tmp = json_object_array_get_idx(json_roles, i);
271
272         category = this->getStringFromJson(json_tmp, "category");
273         roles =  this->getStringFromJson(json_tmp, "role");
274         areas =  this->getStringFromJson(json_tmp, "area");
275
276         if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
277             HMI_ERROR("wm:pm", "Parse Error!!");
278             return -1;
279         }
280
281         // Parse roles by '|'
282         std::vector<std::string> vct_roles;
283         vct_roles = this->parseString(std::string(roles), '|');
284
285         // Parse areas by '|'
286         std::vector<std::string> vct_areas;
287         vct_areas = this->parseString(std::string(areas), '|');
288
289         // Set role, category, default area
290         for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) {
291             // Delete space from role and area name
292             std::string role = this->deleteSpace(*itr);
293             std::string area = this->deleteSpace(vct_areas[0]);
294
295             this->role2category_[role] = std::string(category);
296             this->role2defaultarea_[role] = area;
297         }
298
299         this->category2role_[std::string(category)] = std::string(roles);
300     }
301
302     // Check
303     HMI_DEBUG("wm:pm", "Check role2category_");
304     for (auto& x:this->role2category_){
305         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
306     }
307
308     HMI_DEBUG("wm:pm", "Check role2defaultarea_");
309     for (auto& x:this->role2defaultarea_){
310         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
311     }
312
313     HMI_DEBUG("wm:pm", "Check category2role_");
314     for (auto& x:this->category2role_){
315         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
316     }
317
318     return 0;
319 }
320
321 const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) {
322     if ((nullptr == obj) || (nullptr == key)) {
323         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
324         return nullptr;
325     }
326
327     json_object* tmp;
328     if (!json_object_object_get_ex(obj, key, &tmp)) {
329         HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
330         return nullptr;
331     }
332
333     return json_object_get_string(tmp);
334 }
335
336 int PolicyManager::getIntFromJson(json_object* obj, const char* key) {
337     if ((nullptr == obj) || (nullptr == key)) {
338         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
339         return 0;
340     }
341
342     json_object* tmp;
343     if (!json_object_object_get_ex(obj, key, &tmp)) {
344         HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
345         return 0;
346     }
347
348     return json_object_get_int(tmp);
349 }
350
351 void PolicyManager::addStateToJson(
352   const char* key, int is_changed, const char* state, json_object** json_out) {
353     if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) {
354         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
355         return;
356     }
357
358     json_object* json_obj = json_object_new_object();
359     json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed));
360     if (is_changed) {
361         HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state);
362         json_object_object_add(json_obj, "state", json_object_new_string(state));
363     }
364     json_object_object_add(*json_out, key, json_obj);
365 }
366
367 std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) {
368     // Parse string by delimiter
369     std::vector<std::string> vct;
370     std::stringstream ss{str};
371     std::string buf;
372     while (std::getline(ss, buf, delimiter)) {
373       if (!buf.empty()) {
374         vct.push_back(buf);
375       }
376     }
377     return vct;
378 }
379
380 std::string PolicyManager::deleteSpace(std::string str) {
381     std::string ret = str;
382     size_t pos;
383     while ((pos = ret.find_first_of(" ")) != std::string::npos) {
384       ret.erase(pos, 1);
385     }
386     return ret;
387 }
388
389 const char* kDefaultRoleDb = "{ \
390     \"roles\":[ \
391     { \
392         \"category\": \"homescreen\", \
393         \"role\": \"homescreen\", \
394         \"area\": \"full\", \
395     }, \
396     { \
397         \"category\": \"map\", \
398         \"role\": \"map\", \
399         \"area\": \"full | normal | split.main\", \
400     }, \
401     { \
402         \"category\": \"general\", \
403         \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
404         \"area\": \"normal\", \
405     }, \
406     { \
407         \"category\": \"phone\", \
408         \"role\": \"phone\", \
409         \"area\": \"normal\", \
410     }, \
411     { \
412         \"category\": \"splitable\", \
413         \"role\": \"splitable1 | splitable2\", \
414         \"area\": \"normal | split.main | split.sub\", \
415     }, \
416     { \
417         \"category\": \"popup\", \
418         \"role\": \"popup\", \
419         \"area\": \"on_screen\", \
420     }, \
421     { \
422         \"category\": \"system_alert\", \
423         \"role\": \"system_alert\", \
424         \"area\": \"on_screen\", \
425     }, \
426     { \
427         \"category\": \"tbt\", \
428         \"role\": \"tbt\", \
429         \"area\": \"hud\", \
430     } \
431     ] \
432 }";