merge vui
[apps/agl-service-homescreen.git] / src / hs-appinfo.cpp
1 /*
2  * Copyright (c) 2019 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 #include <unistd.h>
18 #include <cstring>
19 #include "hs-appinfo.h"
20 #include "hs-helper.h"
21 #include "hs-clientmanager.h"
22
23 #define RETRY_CNT 10
24
25 const char _keyName[] = "name";
26 const char _keyVersion[] = "version";
27 const char _keyInstall[] = "install";
28 const char _keyUninstall[] = "uninstall";
29 const char _keyOperation[] = "operation";
30 const char _keyRunnables[] = "runnables";
31 const char _keyStart[] = "start";
32 const char _keyApplistChanged[] = "application-list-changed";
33
34 HS_AppInfo* HS_AppInfo::me = nullptr;
35 const std::unordered_map<std::string, HS_AppInfo::func_handler> HS_AppInfo::concerned_event_list {
36     {"afm-main/application-list-changed",    &HS_AppInfo::updateAppDetailList}
37 };
38
39
40 /**
41  * event hook function
42  *
43  * #### Parameters
44  *  - api : the api serving the request
45  *  - event  : event name
46  *  - object : event json object
47  *
48  * #### Return
49  * 0 : continue transfer
50  * 1 : blocked
51  *
52  */
53 static int eventHandler(afb_api_t api, const char *event, struct json_object *object)
54 {
55     return HS_AppInfo::instance()->onEvent(api, event, object);
56 }
57
58 /**
59  * get application property function
60  *
61  * #### Parameters
62  *  - key : retrieve keyword
63  *
64  * #### Return
65  * retrieved property
66  *
67  */
68 std::string AppDetail::getProperty(std::string key) const
69 {
70     struct json_object *j_obj;
71     struct json_object *j_detail = json_tokener_parse(this->detail.c_str());
72     if(json_object_object_get_ex(j_detail, key.c_str(), &j_obj) == 0) {
73         AFB_WARNING("can't find key=%s.", key.c_str());
74         return std::string();
75     }
76     return std::string(json_object_get_string(j_obj));
77 }
78
79 /**
80  * HS_AppInfo destruction function
81  *
82  * #### Parameters
83  *  - Nothing
84  *
85  * #### Return
86  * None
87  *
88  */
89 HS_AppInfo::~HS_AppInfo()
90 {
91     if(afmmain)
92         delete afmmain;
93 }
94
95 /**
96  * get instance
97  *
98  * #### Parameters
99  *  - Nothing
100  *
101  * #### Return
102  * HS_AppInfo instance pointer
103  *
104  */
105 HS_AppInfo* HS_AppInfo::instance(void)
106 {
107     if(me == nullptr)
108         me = new HS_AppInfo();
109
110     return me;
111 }
112
113 /**
114  * HS_AppInfo initialize function
115  *
116  * #### Parameters
117  *  - api : the api serving the request
118  *
119  * #### Return
120  * 0 : init success
121  * 1 : init fail
122  *
123  */
124 int HS_AppInfo::init(afb_api_t api)
125 {
126     afmmain = new HS_AfmMainProxy();
127     if(afmmain == nullptr) {
128         AFB_ERROR("new HS_AfmMainProxy failed");
129         return -1;
130     }
131
132     struct json_object* j_runnable = nullptr;
133     int retry = 0;
134     do {
135         if(afmmain->runnables(api, &j_runnable) == 0) {
136             createAppDetailList(j_runnable);
137             json_object_put(j_runnable);
138             break;
139         }
140
141         ++retry;
142         if(retry == RETRY_CNT) {
143             AFB_ERROR("get runnables list failed");
144             json_object_put(j_runnable);
145             return -1;
146         }
147         AFB_DEBUG("retry to get runnables list %d", retry);
148         usleep(100000); // 100ms
149     } while(1);
150
151     for(auto &ref : concerned_event_list) {
152         setEventHook(ref.first.c_str(), eventHandler);
153     }
154
155     return 0;
156 }
157
158 /**
159  * onEvent function
160  *
161  * #### Parameters
162  *  - api : the api serving the request
163  *  - event  : event name
164  *  - object : event json object
165  *
166  * #### Return
167  * 0 : continue transfer
168  * 1 : blocked
169  */
170 int HS_AppInfo::onEvent(afb_api_t api, const char *event, struct json_object *object)
171 {
172     int ret = 0;
173     auto ip = concerned_event_list.find(std::string(event));
174     if(ip != concerned_event_list.end()) {
175         ret = (this->*(ip->second))(api, object);
176     }
177     return ret;
178 }
179
180 /**
181  * create application detail list function
182  *
183  * #### Parameters
184  *  - object : the detail of all applications
185  *
186  * #### Return
187  * None
188  *
189  */
190 void HS_AppInfo::createAppDetailList(struct json_object *object)
191 {
192     AFB_DEBUG("applist:%s", json_object_to_json_string(object));
193
194     if(json_object_get_type(object) ==  json_type_array) {
195         int array_len = json_object_array_length(object);
196         for (int i = 0; i < array_len; ++i) {
197             struct json_object *obj = json_object_array_get_idx(object, i);
198             addAppDetail(obj);
199         }
200     }
201     else {
202         AFB_ERROR("Apps information input error.");
203     }
204 }
205
206 /**
207  * update application detail function
208  *
209  * #### Parameters
210  *  - object : the detail of all applications
211  *
212  * #### Return
213  * 0 : continue transfer
214  * 1 : blocked
215  *
216  */
217 int HS_AppInfo::updateAppDetailList(afb_api_t api, struct json_object *object)
218 {
219     AFB_DEBUG("update:%s", json_object_to_json_string(object));
220     if(json_object_get_type(object) != json_type_object) {
221         AFB_ERROR("input detail object error.");
222         return 1;
223     }
224
225     struct json_object *obj_oper, *obj_data;
226     if(json_object_object_get_ex(object, _keyOperation, &obj_oper) == 0
227     ||  json_object_object_get_ex(object, _keyData, &obj_data) == 0) {
228         AFB_ERROR("can't find key=%s, %s.", _keyOperation, _keyData);
229         return 1;
230     }
231
232     std::string id = json_object_get_string(obj_data);
233     std::string appid = id2appid(id);
234     if(isPeripheryApp(appid.c_str())) {
235         AFB_INFO( "install/uninstall application is periphery.");
236         return 1;
237     }
238
239     std::string oper = json_object_get_string(obj_oper);
240     if(oper == _keyInstall) {
241         struct json_object* j_runnable = nullptr;
242         int ret = afmmain->runnables(api, &j_runnable);
243         if(!ret) {
244             struct json_object *j_found = retrieveRunnables(j_runnable, id);
245             if(j_found == nullptr) {
246                 AFB_INFO( "installed application isn't runnables.");
247                 json_object_put(j_runnable);
248                 return 1;
249             }
250             addAppDetail(j_found);
251             pushAppListChangedEvent(_keyInstall, j_found);
252         }
253         else {
254             AFB_ERROR("get runnalbes failed.");
255         }
256         json_object_put(j_runnable);
257     }
258     else if(oper == _keyUninstall) {
259         std::string appid_checked = checkAppId(appid);
260         if(appid_checked.empty()) {
261             AFB_INFO("uninstalled application isn't in runnables list, appid=%s.", appid.c_str());
262             return 1;
263         }
264         pushAppListChangedEvent(_keyUninstall, obj_data);
265         removeAppDetail(appid);
266     }
267     else {
268         AFB_ERROR("operation error.");
269     }
270     return 1;
271 }
272
273 /**
274  * parse application detail function
275  *
276  * #### Parameters
277  *  - object : [IN] the detail of application
278  *  - info   : [OUT] parsed application detail
279  *
280  * #### Return
281  * the appid of application liked "dashboard"
282  *
283  */
284 std::string HS_AppInfo::parseAppDetail(struct json_object *object, AppDetail &info) const
285 {
286     struct json_object *name, *id;
287     if(json_object_object_get_ex(object, _keyName, &name) == 0
288     || json_object_object_get_ex(object, _keyId, &id) == 0) {
289         AFB_ERROR("can't find key=%s, %s.", _keyName, _keyId);
290         return std::string();
291     }
292     std::string appid = id2appid(json_object_get_string(id));
293     bool periphery = isPeripheryApp(appid.c_str());
294
295     info = { json_object_get_string(name),
296              json_object_get_string(id),
297              json_object_to_json_string(object),
298              periphery
299     };
300     return appid;
301 }
302
303 /**
304  * add application detail to list function
305  *
306  * #### Parameters
307  *  - object : application detail
308  *
309  * #### Return
310  * None
311  *
312  */
313 void HS_AppInfo::addAppDetail(struct json_object *object)
314 {
315     AppDetail info;
316     std::string appid = parseAppDetail(object, info);
317     if(appid.empty()) {
318         AFB_ERROR("application id error");
319         return;
320     }
321
322     std::lock_guard<std::mutex> lock(this->mtx);
323     appid2name[appid] = info.name;
324     name2appid[info.name] = appid;
325     app_detail_list[appid] = std::move(info);
326 }
327
328 /**
329  * remove application detail from list function
330  *
331  * #### Parameters
332  *  - appid : application id
333  *
334  * #### Return
335  * None
336  *
337  */
338 void HS_AppInfo::removeAppDetail(std::string appid)
339 {
340     std::lock_guard<std::mutex> lock(this->mtx);
341     auto it = app_detail_list.find(appid);
342     if(it != app_detail_list.end()) {
343         appid2name.erase(appid);
344         name2appid.erase(it->second.name);
345         app_detail_list.erase(it);
346     }
347     else {
348         AFB_WARNING("erase application(%s) wasn't in applist.", appid.c_str());
349     }
350 }
351
352 /**
353  * push app_list_changed event function
354  *
355  * #### Parameters
356  *  - oper: install/uninstall
357  *  - object: event data
358  *
359  * #### Return
360  * None
361  *
362  */
363 void HS_AppInfo::pushAppListChangedEvent(const char *oper, struct json_object *object)
364 {
365     struct json_object *push_obj = json_object_new_object();
366     json_object_object_add(push_obj, _keyOperation, json_object_new_string(oper));
367     json_object_object_add(push_obj, _keyData, object);
368
369     HS_ClientManager::instance()->pushEvent(_keyApplistChanged, push_obj);
370 }
371
372 /**
373  * retrieve runnables function
374  *
375  * #### Parameters
376  *  - obj_runnables: runnables array
377  *  - id: application id
378  *
379  * #### Return
380  * found application detail
381  *
382  */
383 struct json_object* HS_AppInfo::retrieveRunnables(struct json_object *obj_runnables, std::string id)
384 {
385     struct json_object *j_found = nullptr;
386     if(json_object_get_type(obj_runnables) ==  json_type_array) {
387         int array_len = json_object_array_length(obj_runnables);
388         for (int i = 0; i < array_len; ++i) {
389             struct json_object *obj = json_object_array_get_idx(obj_runnables, i);
390             struct json_object *j_id;
391             if(json_object_object_get_ex(obj, _keyId, &j_id) == 0) {
392                 AFB_WARNING("can't find id.");
393                 continue;
394             }
395             if(id == json_object_get_string(j_id)) {
396                 j_found = obj;
397                 break;
398             }
399         }
400     }
401     else {
402         AFB_ERROR("Apps information input error.");
403     }
404     return j_found;
405 }
406
407 /**
408  * convert id to appid function
409  *
410  * #### Parameters
411  *  - id : the id of application liked "dashboard@0.1"
412  *
413  * #### Return
414  * the appid of application liked "dashboard"
415  *
416  */
417 std::string HS_AppInfo::id2appid(const std::string &id) const
418 {
419     std::string appid;
420     std::size_t pos = id.find("@");
421     if(pos != std::string::npos) {
422         appid = id.substr(0,pos);
423     }
424     else {
425         AFB_WARNING("input id error.");
426     }
427     return appid;
428 }
429
430 /**
431  * get runnables list
432  *
433  * #### Parameters
434  *  - object : runnables list,json array
435  *
436  * #### Return
437  * None
438  *
439  */
440 void HS_AppInfo::getRunnables(struct json_object **object)
441 {
442     if(json_object_get_type(*object) !=  json_type_array) {
443         AFB_ERROR("json type error.");
444         return;
445     }
446
447     std::lock_guard<std::mutex> lock(this->mtx);
448     for(auto it : app_detail_list) {
449         if(!it.second.periphery)
450             json_object_array_add(*object, json_tokener_parse(it.second.detail.c_str()));
451     }
452 }
453
454 /**
455  * check appid function
456  *
457  * #### Parameters
458  *  - appid : appid liked "dashboard"
459  *
460  * #### Return
461  * success : the correct appid
462  * fail : empty string
463  *
464  */
465 std::string HS_AppInfo::checkAppId(const std::string &appid)
466 {
467     std::lock_guard<std::mutex> lock(this->mtx);
468     auto it_appid = appid2name.find(appid);
469     if(it_appid != appid2name.end())
470         return it_appid->first;
471
472     auto it_name = name2appid.find(appid);
473     if(it_name != name2appid.end())
474         return it_name->second;
475
476     return std::string();
477 }
478
479 /**
480  * check if application is a runnable periphery application function
481  *
482  * #### Parameters
483  *  - appid : appid liked "launcher"
484  *
485  * #### Return
486  * true : periphery
487  * false : not periphery
488  *
489  */
490 bool HS_AppInfo::isPeripheryApp(const char *appid) const
491 {
492     bool ret = false;
493     for(auto m : periphery_app_list) {
494         if(strcasecmp(appid, m) == 0) {
495             ret = true;
496             break;
497         }
498     }
499     return ret;
500 }
501
502 /**
503  * get application specific property
504  *
505  * #### Parameters
506  *  - appid : appid liked "launcher"
507  *  - key : the keyword
508  *
509  * #### Return
510  * application property
511  *
512  */
513 std::string HS_AppInfo::getAppProperty(const std::string appid, std::string key) const
514 {
515     std::string value = "";
516     auto it = app_detail_list.find(appid);
517     if(it != app_detail_list.end()) {
518         value = it->second.getProperty(key);
519     }
520     return value;
521 }