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