Add policy table generated by ZIPC for EXAMPLE
[apps/agl-service-windowmanager-2017.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     ST();
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             STN(display_read_events);
78             g_afb_instance->wmgr.display->read_events();
79             g_afb_instance->wmgr.set_pending_events();
80         }
81         {
82             // We want do dispatch pending wayland events from within
83             // the API context
84             STN(winman_ping_api_call);
85             afb_service_call("windowmanager", "ping", json_object_new_object(),
86                             [](void *c, int st, json_object *j) {
87                                 STN(winman_ping_api_call_return);
88                             },
89                             nullptr);
90         }
91     }
92
93     return 0;
94
95 error:
96     sd_event_source_unref(evs);
97     if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr)
98     {
99         exit(1);
100     }
101     return -1;
102 }
103
104 int _binding_init()
105 {
106     HMI_NOTICE("wm", "WinMan ver. %s", WINMAN_VERSION_STRING);
107
108     if (g_afb_instance != nullptr)
109     {
110         HMI_ERROR("wm", "Wayland context already initialized?");
111         return 0;
112     }
113
114     if (getenv("XDG_RUNTIME_DIR") == nullptr)
115     {
116         HMI_ERROR("wm", "Environment variable XDG_RUNTIME_DIR not set");
117         goto error;
118     }
119
120     {
121         // wait until wayland compositor starts up.
122         int cnt = 0;
123         g_afb_instance = new afb_instance;
124         while (!g_afb_instance->display->ok())
125         {
126             cnt++;
127             if (20 <= cnt)
128             {
129                 HMI_ERROR("wm", "Could not connect to compositor");
130                 goto error;
131             }
132             HMI_ERROR("wm", "Wait to start weston ...");
133             sleep(1);
134             delete g_afb_instance;
135             g_afb_instance = new afb_instance;
136         }
137     }
138
139     if (g_afb_instance->init() == -1)
140     {
141         HMI_ERROR("wm", "Could not connect to compositor");
142         goto error;
143     }
144
145     {
146         int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
147                                   g_afb_instance->display->get_fd(), EPOLLIN,
148                                   display_event_callback, g_afb_instance);
149         if (ret < 0)
150         {
151             HMI_ERROR("wm", "Could not initialize afb_instance event handler: %d", -ret);
152             goto error;
153         }
154     }
155
156     atexit([] { delete g_afb_instance; });
157
158     return 0;
159
160 error:
161     delete g_afb_instance;
162     g_afb_instance = nullptr;
163     return -1;
164 }
165
166 int binding_init() noexcept
167 {
168     try
169     {
170         return _binding_init();
171     }
172     catch (std::exception &e)
173     {
174         HMI_ERROR("wm", "Uncaught exception in binding_init(): %s", e.what());
175     }
176     return -1;
177 }
178
179 static bool checkFirstReq(afb_req req)
180 {
181     WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
182     return (ctxt) ? false : true;
183 }
184
185 static void cbRemoveClientCtxt(void *data)
186 {
187     WMClientCtxt *ctxt = (WMClientCtxt *)data;
188     if (ctxt == nullptr)
189     {
190         return;
191     }
192     HMI_DEBUG("wm", "remove app %s", ctxt->name.c_str());
193     // Lookup surfaceID and remove it because App is dead.
194     auto pSid = g_afb_instance->wmgr.id_alloc.lookup(ctxt->role.c_str());
195     if (pSid)
196     {
197         auto sid = *pSid;
198         g_afb_instance->wmgr.id_alloc.remove_id(sid);
199         g_afb_instance->wmgr.layers.remove_surface(sid);
200         g_afb_instance->wmgr.controller->sprops.erase(sid);
201         g_afb_instance->wmgr.controller->surfaces.erase(sid);
202         HMI_DEBUG("wm", "delete surfaceID %d", sid);
203     }
204     g_afb_instance->wmgr.removeClient(ctxt->name);
205     delete ctxt;
206 }
207
208 void windowmanager_requestsurface(afb_req req) noexcept
209 {
210     std::lock_guard<std::mutex> guard(binding_m);
211 #ifdef ST
212     ST();
213 #endif
214     if (g_afb_instance == nullptr)
215     {
216         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
217         return;
218     }
219
220     try
221     {
222         const char *a_drawing_name = afb_req_value(req, "drawing_name");
223         if (!a_drawing_name)
224         {
225             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
226             return;
227         }
228
229         /* Create Security Context */
230         bool isFirstReq = checkFirstReq(req);
231         if (!isFirstReq)
232         {
233             WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
234             HMI_DEBUG("wm", "You're %s.", ctxt->name.c_str());
235             if (ctxt->name != std::string(a_drawing_name))
236             {
237                 afb_req_fail_f(req, "failed", "Dont request with other name: %s for now", a_drawing_name);
238                 HMI_DEBUG("wm", "Don't request with other name: %s for now", a_drawing_name);
239                 return;
240             }
241         }
242
243         auto ret = g_afb_instance->wmgr.api_request_surface(
244             afb_req_get_application_id(req), a_drawing_name);
245
246         if (isFirstReq)
247         {
248             WMClientCtxt *ctxt = new WMClientCtxt(afb_req_get_application_id(req), a_drawing_name);
249             HMI_DEBUG("wm", "create session for %s", ctxt->name.c_str());
250             afb_req_session_set_LOA(req, 1);
251             afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
252         }
253         else
254         {
255             HMI_DEBUG("wm", "session already created for %s", a_drawing_name);
256         }
257
258         if (ret.is_err())
259         {
260             afb_req_fail(req, "failed", ret.unwrap_err());
261             return;
262         }
263
264         afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
265     }
266     catch (std::exception &e)
267     {
268         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
269         return;
270     }
271 }
272
273 void windowmanager_requestsurfacexdg(afb_req req) noexcept
274 {
275     std::lock_guard<std::mutex> guard(binding_m);
276 #ifdef ST
277     ST();
278 #endif
279     if (g_afb_instance == nullptr)
280     {
281         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
282         return;
283     }
284
285     try
286     {
287         json_object *jreq = afb_req_json(req);
288
289         json_object *j_drawing_name = nullptr;
290         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
291         {
292             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
293             return;
294         }
295         char const *a_drawing_name = json_object_get_string(j_drawing_name);
296
297         json_object *j_ivi_id = nullptr;
298         if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
299         {
300             afb_req_fail(req, "failed", "Need char const* argument ivi_id");
301             return;
302         }
303         char const *a_ivi_id = json_object_get_string(j_ivi_id);
304
305         auto ret = g_afb_instance->wmgr.api_request_surface(
306             afb_req_get_application_id(req), a_drawing_name, a_ivi_id);
307         if (ret != nullptr)
308         {
309             afb_req_fail(req, "failed", ret);
310             return;
311         }
312
313         afb_req_success(req, NULL, "success");
314     }
315     catch (std::exception &e)
316     {
317         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
318         return;
319     }
320 }
321
322 void windowmanager_activatewindow(afb_req req) noexcept
323 {
324     std::lock_guard<std::mutex> guard(binding_m);
325 #ifdef ST
326     ST();
327 #endif
328     if (g_afb_instance == nullptr)
329     {
330         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
331         return;
332     }
333
334     try
335     {
336         const char *a_drawing_name = afb_req_value(req, "drawing_name");
337         if (!a_drawing_name)
338         {
339             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
340             return;
341         }
342
343         const char *a_drawing_area = afb_req_value(req, "drawing_area");
344         if (!a_drawing_area)
345         {
346             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
347             return;
348         }
349
350         g_afb_instance->wmgr.api_activate_surface(
351             afb_req_get_application_id(req),
352             a_drawing_name, a_drawing_area,
353             [&req](const char *errmsg) {
354                 if (errmsg != nullptr)
355                 {
356                     HMI_ERROR("wm", errmsg);
357                     afb_req_fail(req, "failed", errmsg);
358                     return;
359                 }
360                 afb_req_success(req, NULL, "success");
361             });
362     }
363     catch (std::exception &e)
364     {
365         HMI_WARNING("wm", "failed: Uncaught exception while calling activatesurface: %s", e.what());
366         g_afb_instance->wmgr.exceptionProcessForTransition();
367         return;
368     }
369 }
370
371 void windowmanager_deactivatewindow(afb_req req) noexcept
372 {
373     std::lock_guard<std::mutex> guard(binding_m);
374 #ifdef ST
375     ST();
376 #endif
377     if (g_afb_instance == nullptr)
378     {
379         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
380         return;
381     }
382
383     try
384     {
385         const char *a_drawing_name = afb_req_value(req, "drawing_name");
386         if (!a_drawing_name)
387         {
388             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
389             return;
390         }
391
392         g_afb_instance->wmgr.api_deactivate_surface(
393             afb_req_get_application_id(req), a_drawing_name,
394             [&req](const char *errmsg) {
395                 if (errmsg != nullptr)
396                 {
397                     HMI_ERROR("wm", errmsg);
398                     afb_req_fail(req, "failed", errmsg);
399                     return;
400                 }
401                 afb_req_success(req, NULL, "success");
402             });
403     }
404     catch (std::exception &e)
405     {
406         HMI_WARNING("wm", "failed: Uncaught exception while calling deactivatesurface: %s", e.what());
407         g_afb_instance->wmgr.exceptionProcessForTransition();
408         return;
409     }
410 }
411
412 void windowmanager_enddraw(afb_req req) noexcept
413 {
414     std::lock_guard<std::mutex> guard(binding_m);
415 #ifdef ST
416     ST();
417 #endif
418     if (g_afb_instance == nullptr)
419     {
420         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
421         return;
422     }
423
424     try
425     {
426         const char *a_drawing_name = afb_req_value(req, "drawing_name");
427         if (!a_drawing_name)
428         {
429             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
430             return;
431         }
432         afb_req_success(req, NULL, "success");
433
434         g_afb_instance->wmgr.api_enddraw(
435             afb_req_get_application_id(req), a_drawing_name);
436     }
437     catch (std::exception &e)
438     {
439         HMI_WARNING("wm", "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 #ifdef ST
449     ST();
450 #endif
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         auto ret = g_afb_instance->wmgr.api_get_display_info();
460         if (ret.is_err())
461         {
462             afb_req_fail(req, "failed", ret.unwrap_err());
463             return;
464         }
465
466         afb_req_success(req, ret.unwrap(), "success");
467     }
468     catch (std::exception &e)
469     {
470         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
471         return;
472     }
473 }
474
475 void windowmanager_getareainfo_thunk(afb_req req) noexcept
476 {
477     std::lock_guard<std::mutex> guard(binding_m);
478 #ifdef ST
479     ST();
480 #endif
481     if (g_afb_instance == nullptr)
482     {
483         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
484         return;
485     }
486
487     try
488     {
489         json_object *jreq = afb_req_json(req);
490
491         json_object *j_drawing_name = nullptr;
492         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
493         {
494             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
495             return;
496         }
497         char const *a_drawing_name = json_object_get_string(j_drawing_name);
498
499         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
500         if (ret.is_err())
501         {
502             afb_req_fail(req, "failed", ret.unwrap_err());
503             return;
504         }
505
506         afb_req_success(req, ret.unwrap(), "success");
507     }
508     catch (std::exception &e)
509     {
510         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
511         return;
512     }
513 }
514
515 void windowmanager_wm_subscribe(afb_req req) noexcept
516 {
517     std::lock_guard<std::mutex> guard(binding_m);
518 #ifdef ST
519     ST();
520 #endif
521     if (g_afb_instance == nullptr)
522     {
523         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
524         return;
525     }
526
527     try
528     {
529         json_object *jreq = afb_req_json(req);
530         json_object *j = nullptr;
531         if (!json_object_object_get_ex(jreq, "event", &j))
532         {
533             afb_req_fail(req, "failed", "Need char const* argument event");
534             return;
535         }
536         int event_type = json_object_get_int(j);
537         const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
538         struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
539         int ret = afb_req_subscribe(req, event);
540         if (ret)
541         {
542             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
543             return;
544         }
545         afb_req_success(req, NULL, "success");
546     }
547     catch (std::exception &e)
548     {
549         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
550         return;
551     }
552 }
553
554 void windowmanager_list_drawing_names(afb_req req) noexcept
555 {
556     std::lock_guard<std::mutex> guard(binding_m);
557 #ifdef ST
558     ST();
559 #endif
560     if (g_afb_instance == nullptr)
561     {
562         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
563         return;
564     }
565
566     try
567     {
568
569         nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
570         auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
571         if (ret.is_err())
572         {
573             afb_req_fail(req, "failed", ret.unwrap_err());
574             return;
575         }
576
577         afb_req_success(req, ret.unwrap(), "success");
578     }
579     catch (std::exception &e)
580     {
581         afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
582         return;
583     }
584 }
585
586 void windowmanager_ping(afb_req req) noexcept
587 {
588     std::lock_guard<std::mutex> guard(binding_m);
589 #ifdef ST
590     ST();
591 #endif
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         g_afb_instance->wmgr.api_ping();
602
603         afb_req_success(req, NULL, "success");
604     }
605     catch (std::exception &e)
606     {
607         afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what());
608         return;
609     }
610 }
611
612 void windowmanager_debug_status(afb_req req) noexcept
613 {
614     std::lock_guard<std::mutex> guard(binding_m);
615 #ifdef ST
616     ST();
617 #endif
618     if (g_afb_instance == nullptr)
619     {
620         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
621         return;
622     }
623
624     try
625     {
626
627         json_object *jr = json_object_new_object();
628         json_object_object_add(jr, "surfaces",
629                                to_json(g_afb_instance->wmgr.controller->sprops));
630         json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));
631
632         afb_req_success(req, jr, "success");
633     }
634     catch (std::exception &e)
635     {
636         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
637         return;
638     }
639 }
640
641 void windowmanager_debug_layers(afb_req req) noexcept
642 {
643     std::lock_guard<std::mutex> guard(binding_m);
644 #ifdef ST
645     ST();
646 #endif
647     if (g_afb_instance == nullptr)
648     {
649         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
650         return;
651     }
652
653     try
654     {
655         auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));
656
657         afb_req_success(req, ret, "success");
658     }
659     catch (std::exception &e)
660     {
661         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
662         return;
663     }
664 }
665
666 void windowmanager_debug_surfaces(afb_req req) noexcept
667 {
668     std::lock_guard<std::mutex> guard(binding_m);
669 #ifdef ST
670     ST();
671 #endif
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 #ifdef ST
701     ST();
702 #endif
703     if (g_afb_instance == nullptr)
704     {
705         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
706         return;
707     }
708
709     try
710     {
711
712         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
713         {
714             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
715                             // doesn't play well with perf
716         }
717
718         afb_req_success(req, NULL, "success");
719     }
720     catch (std::exception &e)
721     {
722         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
723         return;
724     }
725 }
726
727 const struct afb_verb_v2 windowmanager_verbs[] = {
728     {"requestsurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
729     {"requestsurfacexdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
730     {"activatewindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
731     {"deactivatewindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
732     {"enddraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
733     {"getdisplayinfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
734     {"getareainfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
735     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
736     {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
737     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
738     {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
739     {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
740     {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
741     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
742     {}};
743
744 extern "C" const struct afb_binding_v2 afbBindingV2 = {
745     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};