84c932fff47189a4e80ec57e60ef6cf3085c8107
[apps/agl-service-windowmanager-2017.git] / src / main.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
17 #include <unistd.h>
18 #include <algorithm>
19 #include <mutex>
20 #include <json.h>
21 #include "window_manager.hpp"
22 #include "json_helper.hpp"
23
24 extern "C"
25 {
26 #include <afb/afb-binding.h>
27 #include <systemd/sd-event.h>
28 }
29
30 typedef struct WMClientCtxt
31 {
32     std::string name;
33     std::string role;
34     WMClientCtxt(const char *appName, const char* appRole)
35     {
36         name = appName;
37         role = appRole;
38     }
39 } WMClientCtxt;
40
41 struct afb_instance
42 {
43     wm::WindowManager wmgr;
44
45     afb_instance() : wmgr() {}
46     ~afb_instance() = default;
47
48     int init();
49 };
50
51 struct afb_instance *g_afb_instance;
52 std::mutex binding_m;
53
54 int afb_instance::init()
55 {
56     return this->wmgr.init();
57 }
58
59 int _binding_init()
60 {
61     HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
62
63     g_afb_instance = new afb_instance;
64
65     if (g_afb_instance->init() == -1)
66     {
67         HMI_ERROR("Could not connect to compositor");
68         goto error;
69     }
70
71     atexit([] { delete g_afb_instance; });
72
73     return 0;
74
75 error:
76     delete g_afb_instance;
77     g_afb_instance = nullptr;
78     return -1;
79 }
80
81 int binding_init() noexcept
82 {
83     try
84     {
85         return _binding_init();
86     }
87     catch (std::exception &e)
88     {
89         HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
90     }
91     return -1;
92 }
93
94 static void cbRemoveClientCtxt(void *data)
95 {
96     WMClientCtxt *ctxt = (WMClientCtxt *)data;
97     if (ctxt == nullptr)
98     {
99         return;
100     }
101     HMI_DEBUG("remove app %s", ctxt->name.c_str());
102
103     // Policy Manager does not know this app was killed,
104     // so notify it by deactivate request.
105     g_afb_instance->wmgr.api_deactivate_surface(
106         ctxt->name.c_str(), ctxt->role.c_str(),
107         [](const char *) {});
108
109     g_afb_instance->wmgr.removeClient(ctxt->name);
110     delete ctxt;
111 }
112
113 static void createSecurityContext(afb_req req, const char* appid, const char* role)
114 {
115     WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
116     if (!ctxt)
117     {
118         // Create Security Context at first time
119         const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
120         WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
121         HMI_DEBUG("create session for %s", ctxt->name.c_str());
122         afb_req_session_set_LOA(req, 1);
123         afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
124     }
125 }
126
127 void windowmanager_requestsurface(afb_req req) noexcept
128 {
129     std::lock_guard<std::mutex> guard(binding_m);
130
131     if (g_afb_instance == nullptr)
132     {
133         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
134         return;
135     }
136
137     try
138     {
139         const char *a_drawing_name = afb_req_value(req, "drawing_name");
140         if (!a_drawing_name)
141         {
142             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
143             return;
144         }
145
146         const char *appid = afb_req_get_application_id(req);
147         auto ret = g_afb_instance->wmgr.api_request_surface(
148             appid, a_drawing_name);
149         if (ret.is_err())
150         {
151             afb_req_fail(req, "failed", ret.unwrap_err());
152             return;
153         }
154
155         createSecurityContext(req, appid, a_drawing_name);
156
157         afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
158     }
159     catch (std::exception &e)
160     {
161         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
162         return;
163     }
164 }
165
166 void windowmanager_requestsurfacexdg(afb_req req) noexcept
167 {
168     std::lock_guard<std::mutex> guard(binding_m);
169
170     if (g_afb_instance == nullptr)
171     {
172         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
173         return;
174     }
175
176     try
177     {
178         json_object *jreq = afb_req_json(req);
179
180         json_object *j_drawing_name = nullptr;
181         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
182         {
183             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
184             return;
185         }
186         char const *a_drawing_name = json_object_get_string(j_drawing_name);
187
188         json_object *j_ivi_id = nullptr;
189         if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
190         {
191             afb_req_fail(req, "failed", "Need char const* argument ivi_id");
192             return;
193         }
194         char const *a_ivi_id = json_object_get_string(j_ivi_id);
195         char const *appid = afb_req_get_application_id(req);
196         auto ret = g_afb_instance->wmgr.api_request_surface(
197             appid, a_drawing_name, a_ivi_id);
198
199         if (ret != nullptr)
200         {
201             afb_req_fail(req, "failed", ret);
202             return;
203         }
204
205         createSecurityContext(req, appid, a_drawing_name);
206
207         afb_req_success(req, NULL, "success");
208     }
209     catch (std::exception &e)
210     {
211         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
212         return;
213     }
214 }
215
216 void windowmanager_setrole(afb_req req) noexcept
217 {
218     std::lock_guard<std::mutex> guard(binding_m);
219     if (g_afb_instance == nullptr)
220     {
221         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
222         return;
223     }
224     try
225     {
226         unsigned pid = 0;
227         char const *appid = afb_req_get_application_id(req);
228         json_object *jreq = afb_req_json(req);
229
230         json_object *j_role = nullptr;
231         if (!json_object_object_get_ex(jreq, "role", &j_role))
232         {
233             afb_req_fail(req, "failed", "Need char const* argument role");
234             return;
235         }
236         char const *a_role = json_object_get_string(j_role);
237
238         json_object *j_pid = nullptr;
239         if (json_object_object_get_ex(jreq, "pid", &j_pid))
240         {
241             HMI_DEBUG("PID is set");
242             char const *a_pid = json_object_get_string(j_pid);
243             pid = std::stol(a_pid);
244         }
245
246         auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role, pid);
247         if (!ret)
248         {
249             afb_req_fail(req, "failed", "Couldn't register");
250             return;
251         }
252
253         createSecurityContext(req, appid, a_role);
254
255         afb_req_success(req, NULL, "success");
256     }
257     catch (std::exception &e)
258     {
259         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
260         return;
261     }
262 }
263
264 void windowmanager_activatewindow(afb_req req) noexcept
265 {
266     std::lock_guard<std::mutex> guard(binding_m);
267
268     if (g_afb_instance == nullptr)
269     {
270         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
271         return;
272     }
273
274     try
275     {
276         const char *a_drawing_name = afb_req_value(req, "drawing_name");
277         if (!a_drawing_name)
278         {
279             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
280             return;
281         }
282
283         const char *a_drawing_area = afb_req_value(req, "drawing_area");
284         if (!a_drawing_area)
285         {
286             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
287             return;
288         }
289
290         g_afb_instance->wmgr.api_activate_surface(
291             afb_req_get_application_id(req),
292             a_drawing_name, a_drawing_area,
293             [&req](const char *errmsg) {
294                 if (errmsg != nullptr)
295                 {
296                     HMI_ERROR(errmsg);
297                     afb_req_fail(req, "failed", errmsg);
298                     return;
299                 }
300                 afb_req_success(req, NULL, "success");
301             });
302     }
303     catch (std::exception &e)
304     {
305         HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
306         g_afb_instance->wmgr.exceptionProcessForTransition();
307         return;
308     }
309 }
310
311 void windowmanager_deactivatewindow(afb_req req) noexcept
312 {
313     std::lock_guard<std::mutex> guard(binding_m);
314
315     if (g_afb_instance == nullptr)
316     {
317         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
318         return;
319     }
320
321     try
322     {
323         const char *a_drawing_name = afb_req_value(req, "drawing_name");
324         if (!a_drawing_name)
325         {
326             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
327             return;
328         }
329
330         g_afb_instance->wmgr.api_deactivate_surface(
331             afb_req_get_application_id(req), a_drawing_name,
332             [&req](const char *errmsg) {
333                 if (errmsg != nullptr)
334                 {
335                     HMI_ERROR(errmsg);
336                     afb_req_fail(req, "failed", errmsg);
337                     return;
338                 }
339                 afb_req_success(req, NULL, "success");
340             });
341     }
342     catch (std::exception &e)
343     {
344         HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
345         g_afb_instance->wmgr.exceptionProcessForTransition();
346         return;
347     }
348 }
349
350 void windowmanager_enddraw(afb_req req) noexcept
351 {
352     std::lock_guard<std::mutex> guard(binding_m);
353
354     if (g_afb_instance == nullptr)
355     {
356         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
357         return;
358     }
359
360     try
361     {
362         const char *a_drawing_name = afb_req_value(req, "drawing_name");
363         if (!a_drawing_name)
364         {
365             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
366             return;
367         }
368         afb_req_success(req, NULL, "success");
369
370         g_afb_instance->wmgr.api_enddraw(
371             afb_req_get_application_id(req), a_drawing_name);
372     }
373     catch (std::exception &e)
374     {
375         HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
376         g_afb_instance->wmgr.exceptionProcessForTransition();
377         return;
378     }
379 }
380
381 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
382 {
383     std::lock_guard<std::mutex> guard(binding_m);
384
385     if (g_afb_instance == nullptr)
386     {
387         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
388         return;
389     }
390
391     try
392     {
393         auto ret = g_afb_instance->wmgr.api_get_display_info();
394         if (ret.is_err())
395         {
396             afb_req_fail(req, "failed", ret.unwrap_err());
397             return;
398         }
399
400         afb_req_success(req, ret.unwrap(), "success");
401     }
402     catch (std::exception &e)
403     {
404         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
405         return;
406     }
407 }
408
409 void windowmanager_getareainfo_thunk(afb_req req) noexcept
410 {
411     std::lock_guard<std::mutex> guard(binding_m);
412
413     if (g_afb_instance == nullptr)
414     {
415         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
416         return;
417     }
418
419     try
420     {
421         json_object *jreq = afb_req_json(req);
422
423         json_object *j_drawing_name = nullptr;
424         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
425         {
426             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
427             return;
428         }
429         char const *a_drawing_name = json_object_get_string(j_drawing_name);
430
431         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
432         if (ret.is_err())
433         {
434             afb_req_fail(req, "failed", ret.unwrap_err());
435             return;
436         }
437
438         afb_req_success(req, ret.unwrap(), "success");
439     }
440     catch (std::exception &e)
441     {
442         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
443         return;
444     }
445 }
446
447 void windowmanager_wm_subscribe(afb_req req) noexcept
448 {
449     std::lock_guard<std::mutex> guard(binding_m);
450
451     if (g_afb_instance == nullptr)
452     {
453         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
454         return;
455     }
456
457     try
458     {
459         json_object *jreq = afb_req_json(req);
460         json_object *j = nullptr;
461         if (!json_object_object_get_ex(jreq, "event", &j))
462         {
463             afb_req_fail(req, "failed", "Need char const* argument event");
464             return;
465         }
466         int event_type = json_object_get_int(j);
467         const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
468         struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
469         int ret = afb_req_subscribe(req, event);
470         if (ret)
471         {
472             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
473             return;
474         }
475         afb_req_success(req, NULL, "success");
476     }
477     catch (std::exception &e)
478     {
479         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
480         return;
481     }
482 }
483
484 void windowmanager_list_drawing_names(afb_req req) noexcept
485 {
486     std::lock_guard<std::mutex> guard(binding_m);
487
488     /* if (g_afb_instance == nullptr)
489     {
490         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
491         return;
492     }
493
494     try
495     {
496
497         nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
498         auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
499         if (ret.is_err())
500         {
501             afb_req_fail(req, "failed", ret.unwrap_err());
502             return;
503         }
504
505         afb_req_success(req, ret.unwrap(), "success");
506     }
507     catch (std::exception &e)
508     {
509         afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
510         return;
511     } */
512 }
513
514 void windowmanager_ping(afb_req req) noexcept
515 {
516     std::lock_guard<std::mutex> guard(binding_m);
517
518     if (g_afb_instance == nullptr)
519     {
520         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
521         return;
522     }
523     else
524     {
525         afb_req_success(req, NULL, "success");
526     }
527 }
528
529 void windowmanager_debug_status(afb_req req) noexcept
530 {
531     std::lock_guard<std::mutex> guard(binding_m);
532
533     /* if (g_afb_instance == nullptr)
534     {
535         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
536         return;
537     }
538
539     try
540     {
541
542         json_object *jr = json_object_new_object();
543         json_object_object_add(jr, "surfaces",
544                                to_json(g_afb_instance->wmgr.controller->sprops));
545         json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));
546
547         afb_req_success(req, jr, "success");
548     }
549     catch (std::exception &e)
550     {
551         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
552         return;
553     } */
554 }
555
556 void windowmanager_debug_layers(afb_req req) noexcept
557 {
558     std::lock_guard<std::mutex> guard(binding_m);
559
560     /* if (g_afb_instance == nullptr)
561     {
562         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
563         return;
564     }
565
566     try
567     {
568         auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));
569
570         afb_req_success(req, ret, "success");
571     }
572     catch (std::exception &e)
573     {
574         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
575         return;
576     } */
577 }
578
579 void windowmanager_debug_surfaces(afb_req req) noexcept
580 {
581     std::lock_guard<std::mutex> guard(binding_m);
582
583     /* if (g_afb_instance == nullptr)
584     {
585         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
586         return;
587     }
588
589     try
590     {
591
592         auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
593         if (ret.is_err())
594         {
595             afb_req_fail(req, "failed", ret.unwrap_err());
596             return;
597         }
598
599         afb_req_success(req, ret.unwrap(), "success");
600     }
601     catch (std::exception &e)
602     {
603         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
604         return;
605     } */
606 }
607
608 void windowmanager_debug_terminate(afb_req req) noexcept
609 {
610     std::lock_guard<std::mutex> guard(binding_m);
611
612     if (g_afb_instance == nullptr)
613     {
614         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
615         return;
616     }
617
618     try
619     {
620
621         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
622         {
623             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
624                             // doesn't play well with perf
625         }
626
627         afb_req_success(req, NULL, "success");
628     }
629     catch (std::exception &e)
630     {
631         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
632         return;
633     }
634 }
635
636 const struct afb_verb_v2 windowmanager_verbs[] = {
637     {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
638     {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
639     {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
640     {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
641     {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
642     {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
643     {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
644     {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
645     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
646     {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
647     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
648     {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
649     {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
650     {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
651     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
652     {}};
653
654 extern "C" const struct afb_binding_v2 afbBindingV2 = {
655     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};