Fix place of connection.json
[apps/agl-service-windowmanager.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 "util.hpp"
24 #include "window_manager.hpp"
25 #include "json_helper.hpp"
26
27 extern "C"
28 {
29 #include <afb/afb-binding.h>
30 #include <systemd/sd-event.h>
31 }
32
33 typedef struct WMClientCtxt
34 {
35     std::string name;
36     std::string role;
37     WMClientCtxt(const char *appName, const char* appRole)
38     {
39         name = appName;
40         role = appRole;
41     }
42 } WMClientCtxt;
43
44 struct afb_instance
45 {
46     wm::WindowManager wmgr;
47
48     afb_instance() : wmgr() {}
49     ~afb_instance() = default;
50
51     int init();
52
53     bool testFlg;
54 };
55
56 struct afb_instance *g_afb_instance;
57 std::mutex binding_m;
58
59 int afb_instance::init()
60 {
61     return this->wmgr.init();
62 }
63
64 int _binding_init()
65 {
66     HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
67
68     g_afb_instance = new afb_instance;
69
70     if (g_afb_instance->init() == -1)
71     {
72         HMI_ERROR("Could not connect to compositor");
73         goto error;
74     }
75
76     g_afb_instance->testFlg = false;
77
78     atexit([] { delete g_afb_instance; });
79
80     return 0;
81
82 error:
83     delete g_afb_instance;
84     g_afb_instance = nullptr;
85     return -1;
86 }
87
88 int binding_init() noexcept
89 {
90     try
91     {
92         return _binding_init();
93     }
94     catch (std::exception &e)
95     {
96         HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
97     }
98     return -1;
99 }
100
101 static void cbRemoveClientCtxt(void *data)
102 {
103     WMClientCtxt *ctxt = (WMClientCtxt *)data;
104     if (ctxt == nullptr)
105     {
106         return;
107     }
108     HMI_DEBUG("remove app %s", ctxt->name.c_str());
109
110     // Policy Manager does not know this app was killed,
111     // so notify it by deactivate request.
112     g_afb_instance->wmgr.api_deactivate_window(
113         ctxt->name.c_str(), ctxt->role.c_str(),
114         [](const char *) {});
115
116     g_afb_instance->wmgr.removeClient(ctxt->name);
117     delete ctxt;
118 }
119
120 static void createSecurityContext(afb_req req, const char* appid, const char* role)
121 {
122     WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
123     if (!ctxt)
124     {
125         // Create Security Context at first time
126         const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
127         WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
128         HMI_DEBUG("create session for %s", ctxt->name.c_str());
129         afb_req_session_set_LOA(req, 1);
130         afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
131     }
132 }
133
134 void windowmanager_requestsurface(afb_req req) noexcept
135 {
136     std::lock_guard<std::mutex> guard(binding_m);
137     if (g_afb_instance == nullptr)
138     {
139         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
140         return;
141     }
142
143     try
144     {
145         const char *a_drawing_name = afb_req_value(req, "drawing_name");
146         if (!a_drawing_name)
147         {
148             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
149             return;
150         }
151
152         char *appid = afb_req_get_application_id(req);
153         if(appid)
154         {
155             auto ret = g_afb_instance->wmgr.api_request_surface(
156                 appid, a_drawing_name);
157             if (ret.is_err())
158             {
159                 afb_req_fail(req, "failed", ret.unwrap_err());
160             }
161             else
162             {
163                 createSecurityContext(req, appid, a_drawing_name);
164                 afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
165             }
166             free(appid);
167         }
168         else
169         {
170             afb_req_fail(req, "failed", nullptr);
171         }
172     }
173     catch (std::exception &e)
174     {
175         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
176         return;
177     }
178 }
179
180 void windowmanager_requestsurfacexdg(afb_req req) noexcept
181 {
182     std::lock_guard<std::mutex> guard(binding_m);
183     if (g_afb_instance == nullptr)
184     {
185         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
186         return;
187     }
188
189     try
190     {
191         json_object *jreq = afb_req_json(req);
192
193         json_object *j_drawing_name = nullptr;
194         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
195         {
196             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
197             return;
198         }
199         char const *a_drawing_name = json_object_get_string(j_drawing_name);
200
201         json_object *j_ivi_id = nullptr;
202         if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
203         {
204             afb_req_fail(req, "failed", "Need char const* argument ivi_id");
205             return;
206         }
207         char const *a_ivi_id = json_object_get_string(j_ivi_id);
208         char *appid = afb_req_get_application_id(req);
209         if(appid)
210         {
211             auto ret = g_afb_instance->wmgr.api_request_surface(
212                 appid, a_drawing_name, a_ivi_id);
213
214             if (ret != nullptr)
215             {
216                 afb_req_fail(req, "failed", ret);
217             }
218             else
219             {
220                 createSecurityContext(req, appid, a_drawing_name);
221                 afb_req_success(req, NULL, "success");
222             }
223             free(appid);
224         }
225     }
226     catch (std::exception &e)
227     {
228         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
229         return;
230     }
231 }
232
233 void windowmanager_setrole(afb_req req) noexcept
234 {
235     std::lock_guard<std::mutex> guard(binding_m);
236     if (g_afb_instance == nullptr)
237     {
238         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
239         return;
240     }
241     try
242     {
243         json_object *jreq = afb_req_json(req);
244
245         json_object *j_role = nullptr;
246         if (!json_object_object_get_ex(jreq, "role", &j_role))
247         {
248             afb_req_fail(req, "failed", "Need char const* argument role");
249             return;
250         }
251         char const *a_role = json_object_get_string(j_role);
252         char *appid = afb_req_get_application_id(req);
253
254         if(appid)
255         {
256             auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role);
257             if (!ret)
258             {
259                 afb_req_fail(req, "failed", "Couldn't register");
260             }
261             else
262             {
263                 createSecurityContext(req, appid, a_role);
264                 afb_req_success(req, NULL, "success");
265             }
266             free(appid);
267         }
268     }
269     catch (std::exception &e)
270     {
271         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
272         return;
273     }
274 }
275
276 void windowmanager_activatewindow(afb_req req) noexcept
277 {
278     std::lock_guard<std::mutex> guard(binding_m);
279     if (g_afb_instance == nullptr)
280     {
281         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
282         return;
283     }
284
285     try
286     {
287         const char *a_drawing_name = afb_req_value(req, "drawing_name");
288         if (!a_drawing_name)
289         {
290             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
291             return;
292         }
293
294         const char *a_drawing_area = afb_req_value(req, "drawing_area");
295         if (!a_drawing_area)
296         {
297             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
298             return;
299         }
300
301         char* appid = afb_req_get_application_id(req);
302         if(appid)
303         {
304             auto reply = [&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
314             HMI_DEBUG("activateWindow role:%s area:%s", appid, a_drawing_area);
315
316 #if 0
317             std::string appidString = appid;
318             HMI_DEBUG("flg: %d", g_afb_instance->testFlg);
319             if ((appidString == "dashboard" && g_afb_instance->testFlg) || appidString == "hudspeed")
320             { 
321                 HMI_DEBUG("%s is remote transfer", appid);
322                 g_afb_instance->wmgr.api_activate_surface_to_master(
323                     appid, a_drawing_name, "hud.upper.left", reply);
324
325                 g_afb_instance->testFlg = false;
326                 return;
327             }
328
329 #endif
330             if (!g_afb_instance->wmgr.wmcon.isRemoteArea(a_drawing_area))
331             {
332                 g_afb_instance->wmgr.api_activate_window(
333                     appid, a_drawing_name, a_drawing_area, reply);
334             }
335             else
336             {
337                 std::string ecu_name;
338                 ecu_name = g_afb_instance->wmgr.wmcon.getAreaToEcuName(a_drawing_area);
339
340                 // TODO: temporarily
341                 if (!g_afb_instance->wmgr.wmcon.isConnectionMode())
342                 {
343                     HMI_ERROR("WM Standalone Mode");
344                     afb_req_fail(req, "failed", "Standalone Mode");
345                 }
346                 else
347                 {
348                     // If Window Manager is slave and this request is for master,
349                     // request activateWindow to master
350                     g_afb_instance->wmgr.api_activate_surface_to_master(
351                         appid, a_drawing_name, a_drawing_area, reply);
352                 }
353             }
354 #if 0
355             if (appidString == "dashboard")
356             {
357                 g_afb_instance->testFlg = true;
358             }
359 #endif
360             free(appid);
361         }
362     }
363     catch (std::exception &e)
364     {
365         HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
366         g_afb_instance->wmgr.exceptionProcessForTransition();
367         return;
368     }
369 }
370
371 void windowmanager_deactivatewindow(afb_req req) noexcept
372 {
373     std::lock_guard<std::mutex> guard(binding_m);
374     if (g_afb_instance == nullptr)
375     {
376         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
377         return;
378     }
379
380     try
381     {
382         const char *a_drawing_name = afb_req_value(req, "drawing_name");
383         if (!a_drawing_name)
384         {
385             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
386             return;
387         }
388
389         char* appid = afb_req_get_application_id(req);
390         if(appid)
391         {
392             auto reply = [&req](const char *errmsg) {
393                 if (errmsg != nullptr)
394                 {
395                     HMI_ERROR(errmsg);
396                     afb_req_fail(req, "failed", errmsg);
397                     return;
398                 }
399                 afb_req_success(req, NULL, "success");
400             };
401
402             // TODO: Check whether role is tbtnavi to request remote invisible
403             if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" ||
404                 ("tbtnavi" != std::string(a_drawing_name)))
405             {
406                 g_afb_instance->wmgr.api_deactivate_window(
407                     appid, a_drawing_name, reply);
408             }
409             else
410             {
411                 // If Window Manager is slave and this request is for master,
412                 // request deactivateWindow to master
413                 g_afb_instance->wmgr.api_deactivate_surface_to_master(
414                     appid, a_drawing_name, reply);
415             }
416             free(appid);
417         }
418     }
419     catch (std::exception &e)
420     {
421         HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
422         g_afb_instance->wmgr.exceptionProcessForTransition();
423         return;
424     }
425 }
426
427 void windowmanager_enddraw(afb_req req) noexcept
428 {
429     std::lock_guard<std::mutex> guard(binding_m);
430     if (g_afb_instance == nullptr)
431     {
432         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
433         return;
434     }
435
436     try
437     {
438         const char *a_drawing_name = afb_req_value(req, "drawing_name");
439         if (!a_drawing_name)
440         {
441             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
442             return;
443         }
444         afb_req_success(req, NULL, "success");
445
446         char* appid = afb_req_get_application_id(req);
447
448         if(appid)
449         {
450             if (!g_afb_instance->wmgr.wmcon.isRemoteEcu(appid) ||
451                 !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid))
452             {
453                 g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
454             }
455             else
456             {
457                 // If Window Manager is slave and requesting app is syncDrawing,
458                 // request endDraw to master
459                 g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name);
460             }
461            free(appid);
462         }
463     }
464     catch (std::exception &e)
465     {
466         HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
467         g_afb_instance->wmgr.exceptionProcessForTransition();
468         return;
469     }
470 }
471
472 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
473 {
474     std::lock_guard<std::mutex> guard(binding_m);
475     if (g_afb_instance == nullptr)
476     {
477         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
478         return;
479     }
480
481     try
482     {
483         auto ret = g_afb_instance->wmgr.api_get_display_info();
484         if (ret.is_err())
485         {
486             afb_req_fail(req, "failed", ret.unwrap_err());
487             return;
488         }
489
490         afb_req_success(req, ret.unwrap(), "success");
491     }
492     catch (std::exception &e)
493     {
494         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
495         return;
496     }
497 }
498
499 void windowmanager_getareainfo_thunk(afb_req req) noexcept
500 {
501     std::lock_guard<std::mutex> guard(binding_m);
502     if (g_afb_instance == nullptr)
503     {
504         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
505         return;
506     }
507
508     try
509     {
510         json_object *jreq = afb_req_json(req);
511
512         json_object *j_drawing_name = nullptr;
513         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
514         {
515             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
516             return;
517         }
518         char const *a_drawing_name = json_object_get_string(j_drawing_name);
519
520         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
521         if (ret.is_err())
522         {
523             afb_req_fail(req, "failed", ret.unwrap_err());
524             return;
525         }
526
527         afb_req_success(req, ret.unwrap(), "success");
528     }
529     catch (std::exception &e)
530     {
531         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
532         return;
533     }
534 }
535
536 void windowmanager_getcarinfo_thunk(afb_req req) noexcept
537 {
538     std::lock_guard<std::mutex> guard(binding_m);
539     if (g_afb_instance == nullptr)
540     {
541         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
542         return;
543     }
544
545     try
546     {
547         json_object *jreq = afb_req_json(req);
548
549         json_object *j_label = nullptr;
550         if (! json_object_object_get_ex(jreq, "label", &j_label))
551         {
552             afb_req_fail(req, "failed", "Need char const* argument label");
553             return;
554         }
555         char const* a_label = json_object_get_string(j_label);
556
557         auto ret = g_afb_instance->wmgr.api_get_car_info(a_label);
558         if (ret.is_err())
559         {
560             afb_req_fail(req, "failed", ret.unwrap_err());
561             return;
562         }
563
564         afb_req_success(req, ret.unwrap(), "success");
565     }
566     catch (std::exception &e)
567     {
568         afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what());
569         return;
570     }
571 }
572
573 void windowmanager_set_render_order(afb_req req) noexcept
574 {
575     std::lock_guard<std::mutex> guard(binding_m);
576     if (g_afb_instance == nullptr)
577     {
578         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
579         return;
580     }
581
582     char* appid = afb_req_get_application_id(req);
583     if(appid)
584     {
585         json_object *jreq = afb_req_json(req);
586         json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro
587         if (json_object_object_get_ex(jreq, "render_order", &j_ro))
588         {
589             int size = json_object_array_length(j_ro);
590             std::vector<std::string> ro(size);
591             for(int i = 0; i < size; i++)
592             {
593                 ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i));
594             }
595
596             auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro);
597             if (!ret)
598             {
599                 afb_req_fail(req, "failed", nullptr);
600             }
601             else
602             {
603                 afb_req_success(req, nullptr, nullptr);
604             }
605         }
606         free(appid);
607     }
608     else
609     {
610         afb_req_fail(req, "failed", nullptr);
611     }
612 }
613
614 void windowmanager_attach_app(afb_req req) noexcept
615 {
616     std::lock_guard<std::mutex> guard(binding_m);
617     if (g_afb_instance == nullptr)
618     {
619         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
620         return;
621     }
622
623     char* appid = afb_req_get_application_id(req);
624     if(appid)
625     {
626         json_object *jreq = afb_req_json(req);
627         json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro
628         if (json_object_object_get_ex(jreq, "destination", &j_dest) &&
629             json_object_object_get_ex(jreq, "service_surface", &j_id))
630         {
631             const char* dest_app = json_object_get_string(j_dest);
632             const char* service = json_object_get_string(j_id);
633
634             std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service);
635             if (uuid.empty())
636             {
637                 afb_req_fail(req, "failed", nullptr);
638             }
639             else
640             {
641                 json_object *resp = json_object_new_object();
642                 json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str()));
643                 afb_req_success(req, resp, nullptr);
644             }
645         }
646         free(appid);
647     }
648     else
649     {
650         afb_req_fail(req, "failed", nullptr);
651     }
652 }
653
654 void windowmanager_get_area_list(afb_req req) noexcept
655 {
656     std::lock_guard<std::mutex> guard(binding_m);
657     json_object* ret = g_afb_instance->wmgr.api_get_area_list();
658     afb_req_success(req, ret, nullptr);
659 }
660
661 void windowmanager_change_area_size(afb_req req) noexcept
662 {
663     std::lock_guard<std::mutex> guard(binding_m);
664     if (g_afb_instance == nullptr)
665     {
666         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
667         return;
668     }
669
670     char* appid = afb_req_get_application_id(req);
671     if(appid)
672     {
673         ChangeAreaReq change_req;
674         change_req.appname = appid;
675         change_req.save = false;
676         json_object *jreq = afb_req_json(req);
677         json_object *jsave, *jareas;
678         HMI_INFO("json_check, %s", json_object_get_string(jreq));
679         if(json_object_object_get_ex(jreq, "save", &jsave))
680         {
681             change_req.save = json_object_get_boolean(jsave);
682         }
683         if (json_object_object_get_ex(jreq, "areas", &jareas))
684         {
685             int size = json_object_array_length(jareas);
686             for(int i = 0; i < size; i++)
687             {
688                 json_object* elem = json_object_array_get_idx(jareas, i);
689                 struct rect rect;
690                 std::string name = jh::getStringFromJson(elem, "name");
691                 json_object* jrect;
692                 if(json_object_object_get_ex(elem, "rect", &jrect))
693                 {
694                     rect.x = jh::getIntFromJson(jrect, "x");
695                     rect.y = jh::getIntFromJson(jrect, "y");
696                     rect.w = jh::getIntFromJson(jrect, "w");
697                     rect.h = jh::getIntFromJson(jrect, "h");
698                 }
699                 else
700                 {
701                     HMI_ERROR("bad request @area name :%s", name.c_str());
702                     afb_req_fail(req, "failed", "bad request");
703                     return;
704                 }
705                 change_req.area_req[name] = rect;
706             }
707             if(change_req.area_req.size() != 0)
708             {
709                 g_afb_instance->wmgr.api_change_area_size(change_req);
710             }
711             afb_req_success(req, nullptr, nullptr);
712         }
713         free(appid);
714     }
715     else
716     {
717         afb_req_fail(req, "failed", nullptr);
718     }
719 }
720
721 void windowmanager_wm_subscribe(afb_req req) noexcept
722 {
723     std::lock_guard<std::mutex> guard(binding_m);
724     if (g_afb_instance == nullptr)
725     {
726         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
727         return;
728     }
729
730     try
731     {
732         json_object *jreq = afb_req_json(req);
733         json_object *j = nullptr;
734         if (!json_object_object_get_ex(jreq, "event", &j))
735         {
736             afb_req_fail(req, "failed", "Need char const* argument event");
737             return;
738         }
739         int event_id = json_object_get_int(j);
740         int ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
741
742         if (ret)
743         {
744             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
745             return;
746         }
747         afb_req_success(req, NULL, "success");
748
749         if (event_id == 7)
750         {
751             //g_afb_instance->wmgr.api_handshake();
752             g_afb_instance->wmgr.setSubscribed(true);
753         }
754     }
755     catch (std::exception &e)
756     {
757         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
758         return;
759     }
760 }
761
762 void windowmanager_connect(afb_req req) noexcept
763 {
764     std::lock_guard<std::mutex> guard(binding_m);
765
766     HMI_DEBUG("WM - HS Connect");
767
768     if (g_afb_instance == nullptr)
769     {
770         afb_req_fail(req, "Failed", "Not Start WindowManager");
771         return;
772     }
773     else
774     {
775         afb_req_success(req, NULL, "success");
776     }
777 }
778
779 void windowmanager_ping(afb_req req) noexcept
780 {
781     std::lock_guard<std::mutex> guard(binding_m);
782
783     if (g_afb_instance == nullptr)
784     {
785         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
786         return;
787     }
788     else
789     {
790         afb_req_success(req, NULL, "success");
791     }
792 }
793
794 void windowmanager_debug_terminate(afb_req req) noexcept
795 {
796     std::lock_guard<std::mutex> guard(binding_m);
797     if (g_afb_instance == nullptr)
798     {
799         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
800         return;
801     }
802
803     try
804     {
805
806         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
807         {
808             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
809                             // doesn't play well with perf
810         }
811
812         afb_req_success(req, NULL, "success");
813     }
814     catch (std::exception &e)
815     {
816         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
817         return;
818     }
819 }
820
821 void on_event(const char *event, struct json_object *object)
822 {
823     g_afb_instance->wmgr.analyzeReceivedEvent(event, object);
824 }
825
826 const struct afb_verb_v2 windowmanager_verbs[] = {
827     {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
828     {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
829     {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
830     {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
831     {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
832     {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
833     {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
834     {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
835     {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE },
836     {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE},
837     {"changeAreaSize", windowmanager_change_area_size, nullptr, nullptr, AFB_SESSION_NONE},
838     {"getAreaList", windowmanager_get_area_list, nullptr, nullptr, AFB_SESSION_NONE},
839     {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE},
840     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
841     {"wm_connect", windowmanager_connect, nullptr, nullptr, AFB_SESSION_NONE},
842     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
843     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
844     {}};
845
846 extern "C" const struct afb_binding_v2 afbBindingV2 = {
847     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};