Add mutex lock
[apps/agl-service-windowmanager.git] / src / applist.cpp
1 /*
2  * Copyright (c) 2017 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 #include <iostream>
17 #include <algorithm>
18 #include "applist.hpp"
19 #include "../include/hmi-debug.h"
20
21 using std::shared_ptr;
22 using std::string;
23 using std::vector;
24
25 namespace wm
26 {
27
28 AppList::AppList()
29     : req_list(0),
30       app2client(0),
31       current_req(1)
32 {
33 }
34
35 AppList::~AppList() {}
36
37 void AppList::addClient(const string &appid, const string &role)
38 {
39     std::lock_guard<std::mutex> lock(mtx);
40     shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, role);
41     this->app2client[appid] = client;
42     this->clientDump();
43 }
44
45 void AppList::addClient(const std::string &appid, unsigned layer, unsigned surface, const std::string &role)
46 {
47     std::lock_guard<std::mutex> lock(mtx);
48     shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, surface, role);
49     this->app2client[appid] = client;
50     this->clientDump();
51 }
52
53 void AppList::removeClient(const string &appid)
54 {
55     std::lock_guard<std::mutex> lock(mtx);
56     this->app2client.erase(appid);
57     HMI_INFO("wm", "Remove client %s", appid.c_str());
58 }
59
60 bool AppList::contains(const string &appid) const
61 {
62     auto result = this->app2client.find(appid);
63     return (this->app2client.end() != result) ? true : false;
64 }
65
66 void AppList::removeSurface(unsigned surface_id){
67     // This function may be very slow
68     std::lock_guard<std::mutex> lock(mtx);
69     bool ret = false;
70     for (auto &x : this->app2client)
71     {
72         ret = x.second->removeSurfaceIfExist(surface_id);
73         if(ret){
74             HMI_DEBUG("wm", "remove surface %d from Client %s finish", surface_id, x.second->appID().c_str());
75             break;
76         }
77     }
78
79 }
80
81 /**
82  * @brief  get WMClient object. Before call this function, must call "contains"
83  * to check the key is contained, otherwise, you have to take care of std::out_of_range.
84  * @param string[in] application id(key)
85  * @return WMClient object
86  */
87 shared_ptr<WMClient> AppList::lookUpClient(const string &appid)
88 {
89     return this->app2client.at(appid);
90 }
91
92 int AppList::countClient() const
93 {
94     return this->app2client.size();
95 }
96
97 unsigned AppList::currentRequestNumber() const
98 {
99     return this->current_req;
100 }
101
102 unsigned AppList::getRequestNumber(const string &appid) const
103 {
104     for (const auto &x : this->req_list)
105     {
106         // Since app will not request twice and more, comparing appid is enough?
107         if ((x.trigger.appid == appid))
108         {
109             return x.req_num;
110         }
111     }
112     return 0;
113 }
114
115 unsigned AppList::addAllocateRequest(WMRequest req)
116 {
117     std::lock_guard<std::mutex> lock(mtx);
118     if (this->req_list.size() == 0)
119     {
120         req.req_num = current_req;
121     }
122     else
123     {
124         HMI_SEQ_INFO(this->current_req, "add: %d", this->req_list.back().req_num + 1);
125         req.req_num = this->req_list.back().req_num + 1;
126     }
127     this->req_list.push_back(req);
128     return req.req_num;
129 }
130
131 struct WMTrigger AppList::getRequest(unsigned req_num, bool *found)
132 {
133     *found = false;
134     for (const auto &x : this->req_list)
135     {
136         if (req_num == x.req_num)
137         {
138             *found = true;
139             return x.trigger;
140         }
141     }
142     HMI_SEQ_ERROR(req_num, "Couldn't get request : %d", req_num);
143     return WMTrigger{"", "", "", Task::TASK_INVALID};
144 }
145
146 const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found)
147 {
148     *found = false;
149     for (auto &x : this->req_list)
150     {
151         if (req_num == x.req_num)
152         {
153             *found = true;
154             return x.sync_draw_req;
155         }
156     }
157     HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num);
158 }
159
160 WMError AppList::setAction(unsigned req_num, const struct WMAction &action)
161 {
162     std::lock_guard<std::mutex> lock(mtx);
163     WMError result = WMError::FAIL;
164     for (auto &x : this->req_list)
165     {
166         if (req_num != x.req_num)
167         {
168             continue;
169         }
170         x.sync_draw_req.push_back(action);
171         result = WMError::SUCCESS;
172         break;
173     }
174     return result;
175 }
176
177 /**
178  * Note:
179  * This function set action with parameters.
180  * if visible is true, it means app should be visible, so enddraw_finished parameter should be false.
181  * otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
182  * This function doesn't support actions for focus yet.
183  */
184 WMError AppList::setAction(unsigned req_num, const string &appid, const string &role, const string &area, bool visible)
185 {
186     std::lock_guard<std::mutex> lock(mtx);
187     WMError result = WMError::NOT_REGISTERED;
188     for (auto &x : req_list)
189     {
190         if (req_num != x.req_num)
191         {
192             continue;
193         }
194         bool edraw_f = (visible) ? false : true;
195         WMAction action{appid, role, area, visible, edraw_f};
196
197         x.sync_draw_req.push_back(action);
198         result = WMError::SUCCESS;
199         break;
200     }
201     return result;
202 }
203
204 /**
205  * This function checks
206  *   * req_num is equal to current request number
207  *   * appid and role are equeal to the appid and role stored in action list(sync_draw_req)
208  */
209 bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const string &role)
210 {
211     std::lock_guard<std::mutex> lock(mtx);
212     bool result = false;
213     for (auto &x : req_list)
214     {
215         if (req_num < x.req_num)
216         {
217             break;
218         }
219         if (req_num == x.req_num)
220         {
221             for (auto &y : x.sync_draw_req)
222             {
223                 if (y.appid == appid && y.role == role)
224                 {
225                     y.end_draw_finished = true;
226                     result = true;
227                 }
228             }
229         }
230     }
231     this->reqDump();
232     return result;
233 }
234
235 /**
236  * @brief  check all actions of the requested sequence is finished
237  * @param  unsigned request_number
238  * @return true if all action is set.
239  */
240 bool AppList::endDrawFullfilled(unsigned req_num)
241 {
242     bool result = false;
243     for (const auto &x : req_list)
244     {
245         if (req_num < x.req_num)
246         {
247             break;
248         }
249         if (req_num == x.req_num)
250         {
251             result = true;
252             for (const auto &y : x.sync_draw_req)
253             {
254                 result &= y.end_draw_finished;
255                 if (!result)
256                 {
257                     break;
258                 }
259             }
260         }
261     }
262     return result;
263 }
264
265 void AppList::removeRequest(unsigned req_num)
266 {
267     std::lock_guard<std::mutex> lock(mtx);
268     this->req_list.erase(remove_if(this->req_list.begin(), this->req_list.end(),
269                                    [req_num](WMRequest x) {
270                                        return x.req_num == req_num;
271                                    }));
272 }
273
274 void AppList::next()
275 {
276     std::lock_guard<std::mutex> lock(mtx);
277     ++this->current_req;
278     if (0 == this->current_req)
279     {
280         this->current_req = 1;
281     }
282 }
283
284 bool AppList::haveRequest() const
285 {
286     return !this->req_list.empty();
287 }
288
289 void AppList::clientDump()
290 {
291     DUMP("======= client dump =====");
292     for (const auto &x : this->app2client)
293     {
294         const auto &y = x.second;
295         y->dumpInfo();
296     }
297     DUMP("======= client dump end=====");
298 }
299
300 void AppList::reqDump()
301 {
302     DUMP("======= req dump =====");
303     DUMP("current request : %d", current_req);
304     for (const auto &x : req_list)
305     {
306         DUMP("requested with  : %d", x.req_num);
307         DUMP("Trigger : (APPID :%s, ROLE :%s, AREA :%s, TASK: %d)",
308              x.trigger.appid.c_str(),
309              x.trigger.role.c_str(),
310              x.trigger.area.c_str(),
311              x.trigger.task);
312
313         for (const auto &y : x.sync_draw_req)
314         {
315             DUMP(
316                 "Action  : (APPID :%s, ROLE :%s, AREA :%s, END_DRAW_FINISHED: %d)",
317                 y.appid.c_str(),
318                 y.role.c_str(),
319                 y.area.c_str(),
320                 y.end_draw_finished);
321         }
322     }
323     DUMP("======= req dump end =====\n");
324 }
325 } // namespace wm