Add chage remote app
[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
422         if(appid)
423         {
424             if (!g_afb_instance->wmgr.wmcon.isRemoteEcu(appid) ||
425                 !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid))
426             {
427                 g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
428             }
429             else
430             {
431                 // If Window Manager is slave and requesting app is syncDrawing,
432                 // request endDraw to master
433                 g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name);
434             }
435            free(appid);
436         }
437     }
438     catch (std::exception &e)
439     {
440         HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
441         g_afb_instance->wmgr.exceptionProcessForTransition();
442         return;
443     }
444 }
445
446 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
447 {
448     std::lock_guard<std::mutex> guard(binding_m);
449     if (g_afb_instance == nullptr)
450     {
451         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
452         return;
453     }
454
455     try
456     {
457         auto ret = g_afb_instance->wmgr.api_get_display_info();
458         if (ret.is_err())
459         {
460             afb_req_fail(req, "failed", ret.unwrap_err());
461             return;
462         }
463
464         afb_req_success(req, ret.unwrap(), "success");
465     }
466     catch (std::exception &e)
467     {
468         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
469         return;
470     }
471 }
472
473 void windowmanager_getareainfo_thunk(afb_req req) noexcept
474 {
475     std::lock_guard<std::mutex> guard(binding_m);
476     if (g_afb_instance == nullptr)
477     {
478         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
479         return;
480     }
481
482     try
483     {
484         json_object *jreq = afb_req_json(req);
485
486         json_object *j_drawing_name = nullptr;
487         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
488         {
489             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
490             return;
491         }
492         char const *a_drawing_name = json_object_get_string(j_drawing_name);
493
494         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
495         if (ret.is_err())
496         {
497             afb_req_fail(req, "failed", ret.unwrap_err());
498             return;
499         }
500
501         afb_req_success(req, ret.unwrap(), "success");
502     }
503     catch (std::exception &e)
504     {
505         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
506         return;
507     }
508 }
509
510 void windowmanager_getcarinfo_thunk(afb_req req) noexcept
511 {
512     std::lock_guard<std::mutex> guard(binding_m);
513     if (g_afb_instance == nullptr)
514     {
515         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
516         return;
517     }
518
519     try
520     {
521         json_object *jreq = afb_req_json(req);
522
523         json_object *j_label = nullptr;
524         if (! json_object_object_get_ex(jreq, "label", &j_label))
525         {
526             afb_req_fail(req, "failed", "Need char const* argument label");
527             return;
528         }
529         char const* a_label = json_object_get_string(j_label);
530
531         auto ret = g_afb_instance->wmgr.api_get_car_info(a_label);
532         if (ret.is_err())
533         {
534             afb_req_fail(req, "failed", ret.unwrap_err());
535             return;
536         }
537
538         afb_req_success(req, ret.unwrap(), "success");
539     }
540     catch (std::exception &e)
541     {
542         afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what());
543         return;
544     }
545 }
546
547 void windowmanager_set_render_order(afb_req req) noexcept
548 {
549     std::lock_guard<std::mutex> guard(binding_m);
550     if (g_afb_instance == nullptr)
551     {
552         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
553         return;
554     }
555
556     char* appid = afb_req_get_application_id(req);
557     if(appid)
558     {
559         json_object *jreq = afb_req_json(req);
560         json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro
561         if (json_object_object_get_ex(jreq, "render_order", &j_ro))
562         {
563             int size = json_object_array_length(j_ro);
564             std::vector<std::string> ro(size);
565             for(int i = 0; i < size; i++)
566             {
567                 ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i));
568             }
569
570             auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro);
571             if (!ret)
572             {
573                 afb_req_fail(req, "failed", nullptr);
574             }
575             else
576             {
577                 afb_req_success(req, nullptr, nullptr);
578             }
579         }
580         free(appid);
581     }
582     else
583     {
584         afb_req_fail(req, "failed", nullptr);
585     }
586 }
587
588 void windowmanager_attach_app(afb_req req) noexcept
589 {
590     std::lock_guard<std::mutex> guard(binding_m);
591     if (g_afb_instance == nullptr)
592     {
593         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
594         return;
595     }
596
597     char* appid = afb_req_get_application_id(req);
598     if(appid)
599     {
600         json_object *jreq = afb_req_json(req);
601         json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro
602         if (json_object_object_get_ex(jreq, "destination", &j_dest) &&
603             json_object_object_get_ex(jreq, "service_surface", &j_id))
604         {
605             const char* dest_app = json_object_get_string(j_dest);
606             const char* service = json_object_get_string(j_id);
607
608             std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service);
609             if (uuid.empty())
610             {
611                 afb_req_fail(req, "failed", nullptr);
612             }
613             else
614             {
615                 json_object *resp = json_object_new_object();
616                 json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str()));
617                 afb_req_success(req, resp, nullptr);
618             }
619         }
620         free(appid);
621     }
622     else
623     {
624         afb_req_fail(req, "failed", nullptr);
625     }
626 }
627
628 void windowmanager_get_area_list(afb_req req) noexcept
629 {
630     std::lock_guard<std::mutex> guard(binding_m);
631     json_object* ret = g_afb_instance->wmgr.api_get_area_list();
632     afb_req_success(req, ret, nullptr);
633 }
634
635 void windowmanager_change_area_size(afb_req req) noexcept
636 {
637     std::lock_guard<std::mutex> guard(binding_m);
638     if (g_afb_instance == nullptr)
639     {
640         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
641         return;
642     }
643
644     char* appid = afb_req_get_application_id(req);
645     if(appid)
646     {
647         ChangeAreaReq change_req;
648         change_req.appname = appid;
649         change_req.save = false;
650         json_object *jreq = afb_req_json(req);
651         json_object *jsave, *jareas;
652         HMI_INFO("json_check, %s", json_object_get_string(jreq));
653         if(json_object_object_get_ex(jreq, "save", &jsave))
654         {
655             change_req.save = json_object_get_boolean(jsave);
656         }
657         if (json_object_object_get_ex(jreq, "areas", &jareas))
658         {
659             int size = json_object_array_length(jareas);
660             for(int i = 0; i < size; i++)
661             {
662                 json_object* elem = json_object_array_get_idx(jareas, i);
663                 struct rect rect;
664                 std::string name = jh::getStringFromJson(elem, "name");
665                 json_object* jrect;
666                 if(json_object_object_get_ex(elem, "rect", &jrect))
667                 {
668                     rect.x = jh::getIntFromJson(jrect, "x");
669                     rect.y = jh::getIntFromJson(jrect, "y");
670                     rect.w = jh::getIntFromJson(jrect, "w");
671                     rect.h = jh::getIntFromJson(jrect, "h");
672                 }
673                 else
674                 {
675                     HMI_ERROR("bad request @area name :%s", name.c_str());
676                     afb_req_fail(req, "failed", "bad request");
677                     return;
678                 }
679                 change_req.area_req[name] = rect;
680             }
681             if(change_req.area_req.size() != 0)
682             {
683                 g_afb_instance->wmgr.api_change_area_size(change_req);
684             }
685             afb_req_success(req, nullptr, nullptr);
686         }
687         free(appid);
688     }
689     else
690     {
691         afb_req_fail(req, "failed", nullptr);
692     }
693 }
694
695 void windowmanager_wm_subscribe(afb_req req) noexcept
696 {
697     std::lock_guard<std::mutex> guard(binding_m);
698     if (g_afb_instance == nullptr)
699     {
700         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
701         return;
702     }
703
704     try
705     {
706         json_object *jreq = afb_req_json(req);
707         json_object *j = nullptr;
708         if (!json_object_object_get_ex(jreq, "event", &j))
709         {
710             afb_req_fail(req, "failed", "Need char const* argument event");
711             return;
712         }
713         int event_id = json_object_get_int(j);
714         int ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
715
716         if (ret)
717         {
718             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
719             return;
720         }
721         afb_req_success(req, NULL, "success");
722
723         g_afb_instance->wmgr.setSubscribed(true);
724     }
725     catch (std::exception &e)
726     {
727         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
728         return;
729     }
730 }
731
732 void windowmanager_connect(afb_req req) noexcept
733 {
734     std::lock_guard<std::mutex> guard(binding_m);
735
736     HMI_DEBUG("WM - HS Connect");
737
738     if (g_afb_instance == nullptr)
739     {
740         afb_req_fail(req, "Failed", "Not Start WindowManager");
741         return;
742     }
743     else
744     {
745         afb_req_success(req, NULL, "success");
746     }
747 }
748
749 void windowmanager_ping(afb_req req) noexcept
750 {
751     std::lock_guard<std::mutex> guard(binding_m);
752
753     if (g_afb_instance == nullptr)
754     {
755         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
756         return;
757     }
758     else
759     {
760         afb_req_success(req, NULL, "success");
761     }
762 }
763
764 void windowmanager_debug_terminate(afb_req req) noexcept
765 {
766     std::lock_guard<std::mutex> guard(binding_m);
767     if (g_afb_instance == nullptr)
768     {
769         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
770         return;
771     }
772
773     try
774     {
775
776         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
777         {
778             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
779                             // doesn't play well with perf
780         }
781
782         afb_req_success(req, NULL, "success");
783     }
784     catch (std::exception &e)
785     {
786         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
787         return;
788     }
789 }
790
791 void on_event(const char *event, struct json_object *object)
792 {
793     g_afb_instance->wmgr.analyzeReceivedEvent(event, object);
794 }
795
796 const struct afb_verb_v2 windowmanager_verbs[] = {
797     {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
798     {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
799     {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
800     {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
801     {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
802     {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
803     {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
804     {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
805     {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE },
806     {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE},
807     {"changeAreaSize", windowmanager_change_area_size, nullptr, nullptr, AFB_SESSION_NONE},
808     {"getAreaList", windowmanager_get_area_list, nullptr, nullptr, AFB_SESSION_NONE},
809     {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE},
810     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
811     {"wm_connect", windowmanager_connect, nullptr, nullptr, AFB_SESSION_NONE},
812     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
813     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
814     {}};
815
816 extern "C" const struct afb_binding_v2 afbBindingV2 = {
817     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};