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