2 * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include "window_manager.hpp"
25 #include "json_helper.hpp"
29 #include <afb/afb-binding.h>
30 #include <systemd/sd-event.h>
33 typedef struct WMClientCtxt
37 WMClientCtxt(const char *appName, const char* appRole)
46 wm::WindowManager wmgr;
48 afb_instance() : wmgr() {}
49 ~afb_instance() = default;
54 struct afb_instance *g_afb_instance;
57 int afb_instance::init()
59 return this->wmgr.init();
64 HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
66 g_afb_instance = new afb_instance;
68 if (g_afb_instance->init() == -1)
70 HMI_ERROR("Could not connect to compositor");
74 atexit([] { delete g_afb_instance; });
79 delete g_afb_instance;
80 g_afb_instance = nullptr;
84 int binding_init() noexcept
88 return _binding_init();
90 catch (std::exception &e)
92 HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
97 static void cbRemoveClientCtxt(void *data)
99 WMClientCtxt *ctxt = (WMClientCtxt *)data;
104 HMI_DEBUG("remove app %s", ctxt->name.c_str());
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 *) {});
112 g_afb_instance->wmgr.removeClient(ctxt->name);
116 static void createSecurityContext(afb_req req, const char* appid, const char* role)
118 WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
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);
130 void windowmanager_requestsurface(afb_req req) noexcept
132 std::lock_guard<std::mutex> guard(binding_m);
133 if (g_afb_instance == nullptr)
135 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
141 const char *a_drawing_name = afb_req_value(req, "drawing_name");
144 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
148 char *appid = afb_req_get_application_id(req);
151 auto ret = g_afb_instance->wmgr.api_request_surface(
152 appid, a_drawing_name);
155 afb_req_fail(req, "failed", ret.unwrap_err());
159 createSecurityContext(req, appid, a_drawing_name);
160 afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
166 afb_req_fail(req, "failed", nullptr);
169 catch (std::exception &e)
171 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
176 void windowmanager_requestsurfacexdg(afb_req req) noexcept
178 std::lock_guard<std::mutex> guard(binding_m);
179 if (g_afb_instance == nullptr)
181 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
187 json_object *jreq = afb_req_json(req);
189 json_object *j_drawing_name = nullptr;
190 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
192 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
195 char const *a_drawing_name = json_object_get_string(j_drawing_name);
197 json_object *j_ivi_id = nullptr;
198 if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
200 afb_req_fail(req, "failed", "Need char const* argument ivi_id");
203 char const *a_ivi_id = json_object_get_string(j_ivi_id);
204 char *appid = afb_req_get_application_id(req);
207 auto ret = g_afb_instance->wmgr.api_request_surface(
208 appid, a_drawing_name, a_ivi_id);
212 afb_req_fail(req, "failed", ret);
216 createSecurityContext(req, appid, a_drawing_name);
217 afb_req_success(req, NULL, "success");
222 catch (std::exception &e)
224 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
229 void windowmanager_setrole(afb_req req) noexcept
231 std::lock_guard<std::mutex> guard(binding_m);
232 if (g_afb_instance == nullptr)
234 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
239 json_object *jreq = afb_req_json(req);
241 json_object *j_role = nullptr;
242 if (!json_object_object_get_ex(jreq, "role", &j_role))
244 afb_req_fail(req, "failed", "Need char const* argument role");
247 char const *a_role = json_object_get_string(j_role);
248 char *appid = afb_req_get_application_id(req);
252 auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role);
255 afb_req_fail(req, "failed", "Couldn't register");
259 createSecurityContext(req, appid, a_role);
260 afb_req_success(req, NULL, "success");
265 catch (std::exception &e)
267 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
272 void windowmanager_activatewindow(afb_req req) noexcept
274 std::lock_guard<std::mutex> guard(binding_m);
275 if (g_afb_instance == nullptr)
277 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
283 const char *a_drawing_name = afb_req_value(req, "drawing_name");
286 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
290 const char *a_drawing_area = afb_req_value(req, "drawing_area");
293 afb_req_fail(req, "failed", "Need char const* argument drawing_area");
297 char* appid = afb_req_get_application_id(req);
300 auto reply = [&req](const char *errmsg) {
301 if (errmsg != nullptr)
304 afb_req_fail(req, "failed", errmsg);
307 afb_req_success(req, NULL, "success");
310 if (!g_afb_instance->wmgr.wmcon.isRemoteArea(a_drawing_area))
312 g_afb_instance->wmgr.api_activate_window(
313 appid, a_drawing_name, a_drawing_area, reply);
317 std::string ecu_name;
318 ecu_name = g_afb_instance->wmgr.wmcon.getAreaToEcuName(a_drawing_area);
321 if (!g_afb_instance->wmgr.wmcon.isConnectionMode())
323 HMI_ERROR("WM Standalone Mode");
324 afb_req_fail(req, "failed", "Standalone Mode");
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);
337 catch (std::exception &e)
339 HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
340 g_afb_instance->wmgr.exceptionProcessForTransition();
345 void windowmanager_deactivatewindow(afb_req req) noexcept
347 std::lock_guard<std::mutex> guard(binding_m);
348 if (g_afb_instance == nullptr)
350 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
356 const char *a_drawing_name = afb_req_value(req, "drawing_name");
359 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
363 char* appid = afb_req_get_application_id(req);
366 auto reply = [&req](const char *errmsg) {
367 if (errmsg != nullptr)
370 afb_req_fail(req, "failed", errmsg);
373 afb_req_success(req, NULL, "success");
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)))
380 g_afb_instance->wmgr.api_deactivate_window(
381 appid, a_drawing_name, reply);
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);
393 catch (std::exception &e)
395 HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
396 g_afb_instance->wmgr.exceptionProcessForTransition();
401 void windowmanager_enddraw(afb_req req) noexcept
403 std::lock_guard<std::mutex> guard(binding_m);
404 if (g_afb_instance == nullptr)
406 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
412 const char *a_drawing_name = afb_req_value(req, "drawing_name");
415 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
418 afb_req_success(req, NULL, "success");
420 char* appid = afb_req_get_application_id(req);
423 if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" ||
424 !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid))
426 g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
430 // If Window Manager is slave and requesting app is syncDrawing,
431 // request endDraw to master
432 g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name);
437 catch (std::exception &e)
439 HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
440 g_afb_instance->wmgr.exceptionProcessForTransition();
445 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
447 std::lock_guard<std::mutex> guard(binding_m);
448 if (g_afb_instance == nullptr)
450 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
456 auto ret = g_afb_instance->wmgr.api_get_display_info();
459 afb_req_fail(req, "failed", ret.unwrap_err());
463 afb_req_success(req, ret.unwrap(), "success");
465 catch (std::exception &e)
467 afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
472 void windowmanager_getareainfo_thunk(afb_req req) noexcept
474 std::lock_guard<std::mutex> guard(binding_m);
475 if (g_afb_instance == nullptr)
477 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
483 json_object *jreq = afb_req_json(req);
485 json_object *j_drawing_name = nullptr;
486 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
488 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
491 char const *a_drawing_name = json_object_get_string(j_drawing_name);
493 auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
496 afb_req_fail(req, "failed", ret.unwrap_err());
500 afb_req_success(req, ret.unwrap(), "success");
502 catch (std::exception &e)
504 afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
509 void windowmanager_getcarinfo_thunk(afb_req req) noexcept
511 std::lock_guard<std::mutex> guard(binding_m);
512 if (g_afb_instance == nullptr)
514 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
520 json_object *jreq = afb_req_json(req);
522 json_object *j_label = nullptr;
523 if (! json_object_object_get_ex(jreq, "label", &j_label))
525 afb_req_fail(req, "failed", "Need char const* argument label");
528 char const* a_label = json_object_get_string(j_label);
530 auto ret = g_afb_instance->wmgr.api_get_car_info(a_label);
533 afb_req_fail(req, "failed", ret.unwrap_err());
537 afb_req_success(req, ret.unwrap(), "success");
539 catch (std::exception &e)
541 afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what());
546 void windowmanager_set_render_order(afb_req req) noexcept
548 std::lock_guard<std::mutex> guard(binding_m);
549 if (g_afb_instance == nullptr)
551 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
555 char* appid = afb_req_get_application_id(req);
558 json_object *jreq = afb_req_json(req);
559 json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro
560 if (json_object_object_get_ex(jreq, "render_order", &j_ro))
562 int size = json_object_array_length(j_ro);
563 std::vector<std::string> ro(size);
564 for(int i = 0; i < size; i++)
566 ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i));
569 auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro);
572 afb_req_fail(req, "failed", nullptr);
576 afb_req_success(req, nullptr, nullptr);
583 afb_req_fail(req, "failed", nullptr);
587 void windowmanager_attach_app(afb_req req) noexcept
589 std::lock_guard<std::mutex> guard(binding_m);
590 if (g_afb_instance == nullptr)
592 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
596 char* appid = afb_req_get_application_id(req);
599 json_object *jreq = afb_req_json(req);
600 json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro
601 if (json_object_object_get_ex(jreq, "destination", &j_dest) &&
602 json_object_object_get_ex(jreq, "service_surface", &j_id))
604 const char* dest_app = json_object_get_string(j_dest);
605 const char* service = json_object_get_string(j_id);
607 std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service);
610 afb_req_fail(req, "failed", nullptr);
614 json_object *resp = json_object_new_object();
615 json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str()));
616 afb_req_success(req, resp, nullptr);
623 afb_req_fail(req, "failed", nullptr);
627 void windowmanager_get_area_list(afb_req req) noexcept
629 std::lock_guard<std::mutex> guard(binding_m);
630 json_object* ret = g_afb_instance->wmgr.api_get_area_list();
631 afb_req_success(req, ret, nullptr);
634 void windowmanager_change_area_size(afb_req req) noexcept
636 std::lock_guard<std::mutex> guard(binding_m);
637 if (g_afb_instance == nullptr)
639 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
643 char* appid = afb_req_get_application_id(req);
646 ChangeAreaReq change_req;
647 change_req.appname = appid;
648 change_req.save = false;
649 json_object *jreq = afb_req_json(req);
650 json_object *jsave, *jareas;
651 HMI_INFO("json_check, %s", json_object_get_string(jreq));
652 if(json_object_object_get_ex(jreq, "save", &jsave))
654 change_req.save = json_object_get_boolean(jsave);
656 if (json_object_object_get_ex(jreq, "areas", &jareas))
658 int size = json_object_array_length(jareas);
659 for(int i = 0; i < size; i++)
661 json_object* elem = json_object_array_get_idx(jareas, i);
663 std::string name = jh::getStringFromJson(elem, "name");
665 if(json_object_object_get_ex(elem, "rect", &jrect))
667 rect.x = jh::getIntFromJson(jrect, "x");
668 rect.y = jh::getIntFromJson(jrect, "y");
669 rect.w = jh::getIntFromJson(jrect, "w");
670 rect.h = jh::getIntFromJson(jrect, "h");
674 HMI_ERROR("bad request @area name :%s", name.c_str());
675 afb_req_fail(req, "failed", "bad request");
678 change_req.area_req[name] = rect;
680 if(change_req.area_req.size() != 0)
682 g_afb_instance->wmgr.api_change_area_size(change_req);
684 afb_req_success(req, nullptr, nullptr);
690 afb_req_fail(req, "failed", nullptr);
694 void windowmanager_wm_subscribe(afb_req req) noexcept
696 std::lock_guard<std::mutex> guard(binding_m);
697 if (g_afb_instance == nullptr)
699 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
705 json_object *jreq = afb_req_json(req);
706 json_object *j = nullptr;
707 if (!json_object_object_get_ex(jreq, "event", &j))
709 afb_req_fail(req, "failed", "Need char const* argument event");
712 int event_id = json_object_get_int(j);
713 int ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
717 afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
720 afb_req_success(req, NULL, "success");
722 if (event_id == g_afb_instance->wmgr.Event_Handshake)
724 g_afb_instance->wmgr.api_handshake();
727 catch (std::exception &e)
729 afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
734 void windowmanager_connect(afb_req req) noexcept
736 std::lock_guard<std::mutex> guard(binding_m);
738 HMI_DEBUG("WM - HS Connect");
740 if (g_afb_instance == nullptr)
742 afb_req_fail(req, "Failed", "Not Start WindowManager");
747 afb_req_success(req, NULL, "success");
751 void windowmanager_ping(afb_req req) noexcept
753 std::lock_guard<std::mutex> guard(binding_m);
755 if (g_afb_instance == nullptr)
757 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
762 afb_req_success(req, NULL, "success");
766 void windowmanager_debug_terminate(afb_req req) noexcept
768 std::lock_guard<std::mutex> guard(binding_m);
769 if (g_afb_instance == nullptr)
771 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
778 if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
780 raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
781 // doesn't play well with perf
784 afb_req_success(req, NULL, "success");
786 catch (std::exception &e)
788 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
793 void on_event(const char *event, struct json_object *object)
795 g_afb_instance->wmgr.analyzeReceivedEvent(event, object);
798 const struct afb_verb_v2 windowmanager_verbs[] = {
799 {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
800 {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
801 {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
802 {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
803 {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
804 {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
805 {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
806 {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
807 {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE },
808 {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE},
809 {"changeAreaSize", windowmanager_change_area_size, nullptr, nullptr, AFB_SESSION_NONE},
810 {"getAreaList", windowmanager_get_area_list, nullptr, nullptr, AFB_SESSION_NONE},
811 {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE},
812 {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
813 {"wm_connect", windowmanager_connect, nullptr, nullptr, AFB_SESSION_NONE},
814 {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
815 {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
818 extern "C" const struct afb_binding_v2 afbBindingV2 = {
819 "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};