Add boot sequence and multi ecu transfer
[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
54 struct afb_instance *g_afb_instance;
55 std::mutex binding_m;
56
57 int afb_instance::init()
58 {
59     return this->wmgr.init();
60 }
61
62 int _binding_init()
63 {
64     HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
65
66     g_afb_instance = new afb_instance;
67
68     if (g_afb_instance->init() == -1)
69     {
70         HMI_ERROR("Could not connect to compositor");
71         goto error;
72     }
73
74     atexit([] { delete g_afb_instance; });
75
76     return 0;
77
78 error:
79     delete g_afb_instance;
80     g_afb_instance = nullptr;
81     return -1;
82 }
83
84 int binding_init() noexcept
85 {
86     try
87     {
88         return _binding_init();
89     }
90     catch (std::exception &e)
91     {
92         HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
93     }
94     return -1;
95 }
96
97 static void cbRemoveClientCtxt(void *data)
98 {
99     WMClientCtxt *ctxt = (WMClientCtxt *)data;
100     if (ctxt == nullptr)
101     {
102         return;
103     }
104     HMI_DEBUG("remove app %s", ctxt->name.c_str());
105
106     // Policy Manager does not know this app was killed,
107     // so notify it by deactivate request.
108     g_afb_instance->wmgr.api_deactivate_window(
109         ctxt->name.c_str(), ctxt->role.c_str(),
110         [](const char *) {});
111
112     g_afb_instance->wmgr.removeClient(ctxt->name);
113     delete ctxt;
114 }
115
116 static void createSecurityContext(afb_req req, const char* appid, const char* role)
117 {
118     WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
119     if (!ctxt)
120     {
121         // Create Security Context at first time
122         const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
123         WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
124         HMI_DEBUG("create session for %s", ctxt->name.c_str());
125         afb_req_session_set_LOA(req, 1);
126         afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
127     }
128 }
129
130 void windowmanager_requestsurface(afb_req req) noexcept
131 {
132     std::lock_guard<std::mutex> guard(binding_m);
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     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     if (g_afb_instance == nullptr)
276     {
277         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
278         return;
279     }
280
281     try
282     {
283         const char *a_drawing_name = afb_req_value(req, "drawing_name");
284         if (!a_drawing_name)
285         {
286             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
287             return;
288         }
289
290         const char *a_drawing_area = afb_req_value(req, "drawing_area");
291         if (!a_drawing_area)
292         {
293             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
294             return;
295         }
296
297         char* appid = afb_req_get_application_id(req);
298         if(appid)
299         {
300             auto reply = [&req](const char *errmsg) {
301                 if (errmsg != nullptr)
302                 {
303                     HMI_ERROR(errmsg);
304                     afb_req_fail(req, "failed", errmsg);
305                     return;
306                 }
307                 afb_req_success(req, NULL, "success");
308             };
309
310             if (!g_afb_instance->wmgr.wmcon.isRemoteArea(a_drawing_area))
311             {
312                 g_afb_instance->wmgr.api_activate_window(
313                     appid, a_drawing_name, a_drawing_area, reply);
314             }
315             else
316             {
317                 std::string ecu_name;
318                 ecu_name = g_afb_instance->wmgr.wmcon.getAreaToEcuName(a_drawing_area);
319
320                 // TODO: temporarily
321                 if (!g_afb_instance->wmgr.wmcon.isConnectionMode())
322                 {
323                     HMI_ERROR("WM Standalone Mode");
324                     afb_req_fail(req, "failed", "Standalone Mode");
325                 }
326                 else
327                 {
328                     // If Window Manager is slave and this request is for master,
329                     // request activateWindow to master
330                     g_afb_instance->wmgr.api_activate_surface_to_master(
331                         appid, a_drawing_name, a_drawing_area, reply);
332                 }
333             }
334             free(appid);
335         }
336     }
337     catch (std::exception &e)
338     {
339         HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
340         g_afb_instance->wmgr.exceptionProcessForTransition();
341         return;
342     }
343 }
344
345 void windowmanager_deactivatewindow(afb_req req) noexcept
346 {
347     std::lock_guard<std::mutex> guard(binding_m);
348     if (g_afb_instance == nullptr)
349     {
350         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
351         return;
352     }
353
354     try
355     {
356         const char *a_drawing_name = afb_req_value(req, "drawing_name");
357         if (!a_drawing_name)
358         {
359             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
360             return;
361         }
362
363         char* appid = afb_req_get_application_id(req);
364         if(appid)
365         {
366             auto reply = [&req](const char *errmsg) {
367                 if (errmsg != nullptr)
368                 {
369                     HMI_ERROR(errmsg);
370                     afb_req_fail(req, "failed", errmsg);
371                     return;
372                 }
373                 afb_req_success(req, NULL, "success");
374             };
375
376             // TODO: Check whether role is tbtnavi to request remote invisible
377             if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" ||
378                 ("tbtnavi" != std::string(a_drawing_name)))
379             {
380                 g_afb_instance->wmgr.api_deactivate_window(
381                     appid, a_drawing_name, reply);
382             }
383             else
384             {
385                 // If Window Manager is slave and this request is for master,
386                 // request deactivateWindow to master
387                 g_afb_instance->wmgr.api_deactivate_surface_to_master(
388                     appid, a_drawing_name, reply);
389             }
390             free(appid);
391         }
392     }
393     catch (std::exception &e)
394     {
395         HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
396         g_afb_instance->wmgr.exceptionProcessForTransition();
397         return;
398     }
399 }
400
401 void windowmanager_enddraw(afb_req req) noexcept
402 {
403     std::lock_guard<std::mutex> guard(binding_m);
404     if (g_afb_instance == nullptr)
405     {
406         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
407         return;
408     }
409
410     try
411     {
412         const char *a_drawing_name = afb_req_value(req, "drawing_name");
413         if (!a_drawing_name)
414         {
415             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
416             return;
417         }
418         afb_req_success(req, NULL, "success");
419
420         char* appid = afb_req_get_application_id(req);
421         if(appid)
422         {
423             if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" ||
424                 !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid))
425             {
426                 g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
427             }
428             else
429             {
430                 // If Window Manager is slave and requesting app is syncDrawing,
431                 // request endDraw to master
432                 g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name);
433             }
434            free(appid);
435         }
436     }
437     catch (std::exception &e)
438     {
439         HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
440         g_afb_instance->wmgr.exceptionProcessForTransition();
441         return;
442     }
443 }
444
445 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
446 {
447     std::lock_guard<std::mutex> guard(binding_m);
448     if (g_afb_instance == nullptr)
449     {
450         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
451         return;
452     }
453
454     try
455     {
456         auto ret = g_afb_instance->wmgr.api_get_display_info();
457         if (ret.is_err())
458         {
459             afb_req_fail(req, "failed", ret.unwrap_err());
460             return;
461         }
462
463         afb_req_success(req, ret.unwrap(), "success");
464     }
465     catch (std::exception &e)
466     {
467         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
468         return;
469     }
470 }
471
472 void windowmanager_getareainfo_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         json_object *jreq = afb_req_json(req);
484
485         json_object *j_drawing_name = nullptr;
486         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
487         {
488             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
489             return;
490         }
491         char const *a_drawing_name = json_object_get_string(j_drawing_name);
492
493         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
494         if (ret.is_err())
495         {
496             afb_req_fail(req, "failed", ret.unwrap_err());
497             return;
498         }
499
500         afb_req_success(req, ret.unwrap(), "success");
501     }
502     catch (std::exception &e)
503     {
504         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
505         return;
506     }
507 }
508
509 void windowmanager_getcarinfo_thunk(afb_req req) noexcept
510 {
511     std::lock_guard<std::mutex> guard(binding_m);
512     if (g_afb_instance == nullptr)
513     {
514         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
515         return;
516     }
517
518     try
519     {
520         json_object *jreq = afb_req_json(req);
521
522         json_object *j_label = nullptr;
523         if (! json_object_object_get_ex(jreq, "label", &j_label))
524         {
525             afb_req_fail(req, "failed", "Need char const* argument label");
526             return;
527         }
528         char const* a_label = json_object_get_string(j_label);
529
530         auto ret = g_afb_instance->wmgr.api_get_car_info(a_label);
531         if (ret.is_err())
532         {
533             afb_req_fail(req, "failed", ret.unwrap_err());
534             return;
535         }
536
537         afb_req_success(req, ret.unwrap(), "success");
538     }
539     catch (std::exception &e)
540     {
541         afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what());
542         return;
543     }
544 }
545
546 void windowmanager_set_render_order(afb_req req) noexcept
547 {
548     std::lock_guard<std::mutex> guard(binding_m);
549     if (g_afb_instance == nullptr)
550     {
551         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
552         return;
553     }
554
555     char* appid = afb_req_get_application_id(req);
556     if(appid)
557     {
558         json_object *jreq = afb_req_json(req);
559         json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro
560         if (json_object_object_get_ex(jreq, "render_order", &j_ro))
561         {
562             int size = json_object_array_length(j_ro);
563             std::vector<std::string> ro(size);
564             for(int i = 0; i < size; i++)
565             {
566                 ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i));
567             }
568
569             auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro);
570             if (!ret)
571             {
572                 afb_req_fail(req, "failed", nullptr);
573             }
574             else
575             {
576                 afb_req_success(req, nullptr, nullptr);
577             }
578         }
579         free(appid);
580     }
581     else
582     {
583         afb_req_fail(req, "failed", nullptr);
584     }
585 }
586
587 void windowmanager_attach_app(afb_req req) noexcept
588 {
589     std::lock_guard<std::mutex> guard(binding_m);
590     if (g_afb_instance == nullptr)
591     {
592         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
593         return;
594     }
595
596     char* appid = afb_req_get_application_id(req);
597     if(appid)
598     {
599         json_object *jreq = afb_req_json(req);
600         json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro
601         if (json_object_object_get_ex(jreq, "destination", &j_dest) &&
602             json_object_object_get_ex(jreq, "service_surface", &j_id))
603         {
604             const char* dest_app = json_object_get_string(j_dest);
605             const char* service = json_object_get_string(j_id);
606
607             std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service);
608             if (uuid.empty())
609             {
610                 afb_req_fail(req, "failed", nullptr);
611             }
612             else
613             {
614                 json_object *resp = json_object_new_object();
615                 json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str()));
616                 afb_req_success(req, resp, nullptr);
617             }
618         }
619         free(appid);
620     }
621     else
622     {
623         afb_req_fail(req, "failed", nullptr);
624     }
625 }
626
627 void windowmanager_get_area_list(afb_req req) noexcept
628 {
629     std::lock_guard<std::mutex> guard(binding_m);
630     json_object* ret = g_afb_instance->wmgr.api_get_area_list();
631     afb_req_success(req, ret, nullptr);
632 }
633
634 void windowmanager_change_area_size(afb_req req) noexcept
635 {
636     std::lock_guard<std::mutex> guard(binding_m);
637     if (g_afb_instance == nullptr)
638     {
639         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
640         return;
641     }
642
643     char* appid = afb_req_get_application_id(req);
644     if(appid)
645     {
646         ChangeAreaReq change_req;
647         change_req.appname = appid;
648         change_req.save = false;
649         json_object *jreq = afb_req_json(req);
650         json_object *jsave, *jareas;
651         HMI_INFO("json_check, %s", json_object_get_string(jreq));
652         if(json_object_object_get_ex(jreq, "save", &jsave))
653         {
654             change_req.save = json_object_get_boolean(jsave);
655         }
656         if (json_object_object_get_ex(jreq, "areas", &jareas))
657         {
658             int size = json_object_array_length(jareas);
659             for(int i = 0; i < size; i++)
660             {
661                 json_object* elem = json_object_array_get_idx(jareas, i);
662                 struct rect rect;
663                 std::string name = jh::getStringFromJson(elem, "name");
664                 json_object* jrect;
665                 if(json_object_object_get_ex(elem, "rect", &jrect))
666                 {
667                     rect.x = jh::getIntFromJson(jrect, "x");
668                     rect.y = jh::getIntFromJson(jrect, "y");
669                     rect.w = jh::getIntFromJson(jrect, "w");
670                     rect.h = jh::getIntFromJson(jrect, "h");
671                 }
672                 else
673                 {
674                     HMI_ERROR("bad request @area name :%s", name.c_str());
675                     afb_req_fail(req, "failed", "bad request");
676                     return;
677                 }
678                 change_req.area_req[name] = rect;
679             }
680             if(change_req.area_req.size() != 0)
681             {
682                 g_afb_instance->wmgr.api_change_area_size(change_req);
683             }
684             afb_req_success(req, nullptr, nullptr);
685         }
686         free(appid);
687     }
688     else
689     {
690         afb_req_fail(req, "failed", nullptr);
691     }
692 }
693
694 void windowmanager_wm_subscribe(afb_req req) noexcept
695 {
696     std::lock_guard<std::mutex> guard(binding_m);
697     if (g_afb_instance == nullptr)
698     {
699         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
700         return;
701     }
702
703     try
704     {
705         json_object *jreq = afb_req_json(req);
706         json_object *j = nullptr;
707         if (!json_object_object_get_ex(jreq, "event", &j))
708         {
709             afb_req_fail(req, "failed", "Need char const* argument event");
710             return;
711         }
712         int event_id = json_object_get_int(j);
713         int ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
714
715         if (ret)
716         {
717             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
718             return;
719         }
720         afb_req_success(req, NULL, "success");
721
722         if (event_id == g_afb_instance->wmgr.Event_Handshake)
723         {
724             g_afb_instance->wmgr.api_handshake();
725         }
726     }
727     catch (std::exception &e)
728     {
729         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
730         return;
731     }
732 }
733
734 void windowmanager_connect(afb_req req) noexcept
735 {
736     std::lock_guard<std::mutex> guard(binding_m);
737
738     HMI_DEBUG("WM - HS Connect");
739
740     if (g_afb_instance == nullptr)
741     {
742         afb_req_fail(req, "Failed", "Not Start WindowManager");
743         return;
744     }
745     else
746     {
747         afb_req_success(req, NULL, "success");
748     }
749 }
750
751 void windowmanager_ping(afb_req req) noexcept
752 {
753     std::lock_guard<std::mutex> guard(binding_m);
754
755     if (g_afb_instance == nullptr)
756     {
757         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
758         return;
759     }
760     else
761     {
762         afb_req_success(req, NULL, "success");
763     }
764 }
765
766 void windowmanager_debug_terminate(afb_req req) noexcept
767 {
768     std::lock_guard<std::mutex> guard(binding_m);
769     if (g_afb_instance == nullptr)
770     {
771         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
772         return;
773     }
774
775     try
776     {
777
778         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
779         {
780             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
781                             // doesn't play well with perf
782         }
783
784         afb_req_success(req, NULL, "success");
785     }
786     catch (std::exception &e)
787     {
788         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
789         return;
790     }
791 }
792
793 void on_event(const char *event, struct json_object *object)
794 {
795     g_afb_instance->wmgr.analyzeReceivedEvent(event, object);
796 }
797
798 const struct afb_verb_v2 windowmanager_verbs[] = {
799     {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
800     {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
801     {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
802     {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
803     {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
804     {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
805     {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
806     {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
807     {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE },
808     {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE},
809     {"changeAreaSize", windowmanager_change_area_size, nullptr, nullptr, AFB_SESSION_NONE},
810     {"getAreaList", windowmanager_get_area_list, nullptr, nullptr, AFB_SESSION_NONE},
811     {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE},
812     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
813     {"wm_connect", windowmanager_connect, nullptr, nullptr, AFB_SESSION_NONE},
814     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
815     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
816     {}};
817
818 extern "C" const struct afb_binding_v2 afbBindingV2 = {
819     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};