Remove pid in args in setRole
[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         char const *appid = afb_req_get_application_id(req);
227         json_object *jreq = afb_req_json(req);
228
229         json_object *j_role = nullptr;
230         if (!json_object_object_get_ex(jreq, "role", &j_role))
231         {
232             afb_req_fail(req, "failed", "Need char const* argument role");
233             return;
234         }
235         char const *a_role = json_object_get_string(j_role);
236
237         auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role);
238         if (!ret)
239         {
240             afb_req_fail(req, "failed", "Couldn't register");
241             return;
242         }
243
244         createSecurityContext(req, appid, a_role);
245
246         afb_req_success(req, NULL, "success");
247     }
248     catch (std::exception &e)
249     {
250         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
251         return;
252     }
253 }
254
255 void windowmanager_activatewindow(afb_req req) noexcept
256 {
257     std::lock_guard<std::mutex> guard(binding_m);
258
259     if (g_afb_instance == nullptr)
260     {
261         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
262         return;
263     }
264
265     try
266     {
267         const char *a_drawing_name = afb_req_value(req, "drawing_name");
268         if (!a_drawing_name)
269         {
270             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
271             return;
272         }
273
274         const char *a_drawing_area = afb_req_value(req, "drawing_area");
275         if (!a_drawing_area)
276         {
277             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
278             return;
279         }
280
281         g_afb_instance->wmgr.api_activate_surface(
282             afb_req_get_application_id(req),
283             a_drawing_name, a_drawing_area,
284             [&req](const char *errmsg) {
285                 if (errmsg != nullptr)
286                 {
287                     HMI_ERROR(errmsg);
288                     afb_req_fail(req, "failed", errmsg);
289                     return;
290                 }
291                 afb_req_success(req, NULL, "success");
292             });
293     }
294     catch (std::exception &e)
295     {
296         HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
297         g_afb_instance->wmgr.exceptionProcessForTransition();
298         return;
299     }
300 }
301
302 void windowmanager_deactivatewindow(afb_req req) noexcept
303 {
304     std::lock_guard<std::mutex> guard(binding_m);
305
306     if (g_afb_instance == nullptr)
307     {
308         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
309         return;
310     }
311
312     try
313     {
314         const char *a_drawing_name = afb_req_value(req, "drawing_name");
315         if (!a_drawing_name)
316         {
317             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
318             return;
319         }
320
321         g_afb_instance->wmgr.api_deactivate_surface(
322             afb_req_get_application_id(req), a_drawing_name,
323             [&req](const char *errmsg) {
324                 if (errmsg != nullptr)
325                 {
326                     HMI_ERROR(errmsg);
327                     afb_req_fail(req, "failed", errmsg);
328                     return;
329                 }
330                 afb_req_success(req, NULL, "success");
331             });
332     }
333     catch (std::exception &e)
334     {
335         HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
336         g_afb_instance->wmgr.exceptionProcessForTransition();
337         return;
338     }
339 }
340
341 void windowmanager_enddraw(afb_req req) noexcept
342 {
343     std::lock_guard<std::mutex> guard(binding_m);
344
345     if (g_afb_instance == nullptr)
346     {
347         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
348         return;
349     }
350
351     try
352     {
353         const char *a_drawing_name = afb_req_value(req, "drawing_name");
354         if (!a_drawing_name)
355         {
356             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
357             return;
358         }
359         afb_req_success(req, NULL, "success");
360
361         g_afb_instance->wmgr.api_enddraw(
362             afb_req_get_application_id(req), a_drawing_name);
363     }
364     catch (std::exception &e)
365     {
366         HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
367         g_afb_instance->wmgr.exceptionProcessForTransition();
368         return;
369     }
370 }
371
372 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
373 {
374     std::lock_guard<std::mutex> guard(binding_m);
375
376     if (g_afb_instance == nullptr)
377     {
378         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
379         return;
380     }
381
382     try
383     {
384         auto ret = g_afb_instance->wmgr.api_get_display_info();
385         if (ret.is_err())
386         {
387             afb_req_fail(req, "failed", ret.unwrap_err());
388             return;
389         }
390
391         afb_req_success(req, ret.unwrap(), "success");
392     }
393     catch (std::exception &e)
394     {
395         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
396         return;
397     }
398 }
399
400 void windowmanager_getareainfo_thunk(afb_req req) noexcept
401 {
402     std::lock_guard<std::mutex> guard(binding_m);
403
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         json_object *jreq = afb_req_json(req);
413
414         json_object *j_drawing_name = nullptr;
415         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
416         {
417             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
418             return;
419         }
420         char const *a_drawing_name = json_object_get_string(j_drawing_name);
421
422         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
423         if (ret.is_err())
424         {
425             afb_req_fail(req, "failed", ret.unwrap_err());
426             return;
427         }
428
429         afb_req_success(req, ret.unwrap(), "success");
430     }
431     catch (std::exception &e)
432     {
433         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
434         return;
435     }
436 }
437
438 void windowmanager_wm_subscribe(afb_req req) noexcept
439 {
440     std::lock_guard<std::mutex> guard(binding_m);
441
442     if (g_afb_instance == nullptr)
443     {
444         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
445         return;
446     }
447
448     try
449     {
450         json_object *jreq = afb_req_json(req);
451         json_object *j = nullptr;
452         if (!json_object_object_get_ex(jreq, "event", &j))
453         {
454             afb_req_fail(req, "failed", "Need char const* argument event");
455             return;
456         }
457         int event_type = json_object_get_int(j);
458         const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
459         struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
460         int ret = afb_req_subscribe(req, event);
461         if (ret)
462         {
463             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
464             return;
465         }
466         afb_req_success(req, NULL, "success");
467     }
468     catch (std::exception &e)
469     {
470         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
471         return;
472     }
473 }
474
475 void windowmanager_list_drawing_names(afb_req req) noexcept
476 {
477     std::lock_guard<std::mutex> guard(binding_m);
478
479     /* if (g_afb_instance == nullptr)
480     {
481         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
482         return;
483     }
484
485     try
486     {
487
488         nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
489         auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
490         if (ret.is_err())
491         {
492             afb_req_fail(req, "failed", ret.unwrap_err());
493             return;
494         }
495
496         afb_req_success(req, ret.unwrap(), "success");
497     }
498     catch (std::exception &e)
499     {
500         afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
501         return;
502     } */
503 }
504
505 void windowmanager_ping(afb_req req) noexcept
506 {
507     std::lock_guard<std::mutex> guard(binding_m);
508
509     if (g_afb_instance == nullptr)
510     {
511         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
512         return;
513     }
514     else
515     {
516         afb_req_success(req, NULL, "success");
517     }
518 }
519
520 void windowmanager_debug_status(afb_req req) noexcept
521 {
522     std::lock_guard<std::mutex> guard(binding_m);
523
524     /* if (g_afb_instance == nullptr)
525     {
526         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
527         return;
528     }
529
530     try
531     {
532
533         json_object *jr = json_object_new_object();
534         json_object_object_add(jr, "surfaces",
535                                to_json(g_afb_instance->wmgr.controller->sprops));
536         json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));
537
538         afb_req_success(req, jr, "success");
539     }
540     catch (std::exception &e)
541     {
542         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
543         return;
544     } */
545 }
546
547 void windowmanager_debug_layers(afb_req req) noexcept
548 {
549     std::lock_guard<std::mutex> guard(binding_m);
550
551     /* if (g_afb_instance == nullptr)
552     {
553         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
554         return;
555     }
556
557     try
558     {
559         auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));
560
561         afb_req_success(req, ret, "success");
562     }
563     catch (std::exception &e)
564     {
565         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
566         return;
567     } */
568 }
569
570 void windowmanager_debug_surfaces(afb_req req) noexcept
571 {
572     std::lock_guard<std::mutex> guard(binding_m);
573
574     /* if (g_afb_instance == nullptr)
575     {
576         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
577         return;
578     }
579
580     try
581     {
582
583         auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
584         if (ret.is_err())
585         {
586             afb_req_fail(req, "failed", ret.unwrap_err());
587             return;
588         }
589
590         afb_req_success(req, ret.unwrap(), "success");
591     }
592     catch (std::exception &e)
593     {
594         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
595         return;
596     } */
597 }
598
599 void windowmanager_debug_terminate(afb_req req) noexcept
600 {
601     std::lock_guard<std::mutex> guard(binding_m);
602
603     if (g_afb_instance == nullptr)
604     {
605         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
606         return;
607     }
608
609     try
610     {
611
612         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
613         {
614             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
615                             // doesn't play well with perf
616         }
617
618         afb_req_success(req, NULL, "success");
619     }
620     catch (std::exception &e)
621     {
622         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
623         return;
624     }
625 }
626
627 const struct afb_verb_v2 windowmanager_verbs[] = {
628     {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
629     {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
630     {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
631     {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
632     {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
633     {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
634     {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
635     {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
636     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
637     {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
638     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
639     {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
640     {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
641     {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
642     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
643     {}};
644
645 extern "C" const struct afb_binding_v2 afbBindingV2 = {
646     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};