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