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