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;
56 struct afb_instance *g_afb_instance;
59 int afb_instance::init()
61 return this->wmgr.init();
66 HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
68 g_afb_instance = new afb_instance;
70 if (g_afb_instance->init() == -1)
72 HMI_ERROR("Could not connect to compositor");
76 g_afb_instance->testFlg = false;
78 atexit([] { delete g_afb_instance; });
83 delete g_afb_instance;
84 g_afb_instance = nullptr;
88 int binding_init() noexcept
92 return _binding_init();
94 catch (std::exception &e)
96 HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
101 static void cbRemoveClientCtxt(void *data)
103 WMClientCtxt *ctxt = (WMClientCtxt *)data;
108 HMI_DEBUG("remove app %s", ctxt->name.c_str());
110 // Policy Manager does not know this app was killed,
111 // so notify it by deactivate request.
112 g_afb_instance->wmgr.api_deactivate_window(
113 ctxt->name.c_str(), ctxt->role.c_str(),
114 [](const char *) {});
116 g_afb_instance->wmgr.removeClient(ctxt->name);
120 static void createSecurityContext(afb_req req, const char* appid, const char* role)
122 WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
125 // Create Security Context at first time
126 const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
127 WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
128 HMI_DEBUG("create session for %s", ctxt->name.c_str());
129 afb_req_session_set_LOA(req, 1);
130 afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
134 void windowmanager_requestsurface(afb_req req) noexcept
136 std::lock_guard<std::mutex> guard(binding_m);
137 if (g_afb_instance == nullptr)
139 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
145 const char *a_drawing_name = afb_req_value(req, "drawing_name");
148 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
152 char *appid = afb_req_get_application_id(req);
155 auto ret = g_afb_instance->wmgr.api_request_surface(
156 appid, a_drawing_name);
159 afb_req_fail(req, "failed", ret.unwrap_err());
163 createSecurityContext(req, appid, a_drawing_name);
164 afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
170 afb_req_fail(req, "failed", nullptr);
173 catch (std::exception &e)
175 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
180 void windowmanager_requestsurfacexdg(afb_req req) noexcept
182 std::lock_guard<std::mutex> guard(binding_m);
183 if (g_afb_instance == nullptr)
185 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
191 json_object *jreq = afb_req_json(req);
193 json_object *j_drawing_name = nullptr;
194 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
196 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
199 char const *a_drawing_name = json_object_get_string(j_drawing_name);
201 json_object *j_ivi_id = nullptr;
202 if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
204 afb_req_fail(req, "failed", "Need char const* argument ivi_id");
207 char const *a_ivi_id = json_object_get_string(j_ivi_id);
208 char *appid = afb_req_get_application_id(req);
211 auto ret = g_afb_instance->wmgr.api_request_surface(
212 appid, a_drawing_name, a_ivi_id);
216 afb_req_fail(req, "failed", ret);
220 createSecurityContext(req, appid, a_drawing_name);
221 afb_req_success(req, NULL, "success");
226 catch (std::exception &e)
228 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
233 void windowmanager_setrole(afb_req req) noexcept
235 std::lock_guard<std::mutex> guard(binding_m);
236 if (g_afb_instance == nullptr)
238 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
243 json_object *jreq = afb_req_json(req);
245 json_object *j_role = nullptr;
246 if (!json_object_object_get_ex(jreq, "role", &j_role))
248 afb_req_fail(req, "failed", "Need char const* argument role");
251 char const *a_role = json_object_get_string(j_role);
252 char *appid = afb_req_get_application_id(req);
256 auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role);
259 afb_req_fail(req, "failed", "Couldn't register");
263 createSecurityContext(req, appid, a_role);
264 afb_req_success(req, NULL, "success");
269 catch (std::exception &e)
271 afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
276 void windowmanager_activatewindow(afb_req req) noexcept
278 std::lock_guard<std::mutex> guard(binding_m);
279 if (g_afb_instance == nullptr)
281 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
287 const char *a_drawing_name = afb_req_value(req, "drawing_name");
290 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
294 const char *a_drawing_area = afb_req_value(req, "drawing_area");
297 afb_req_fail(req, "failed", "Need char const* argument drawing_area");
301 char* appid = afb_req_get_application_id(req);
304 auto reply = [&req](const char *errmsg) {
305 if (errmsg != nullptr)
308 afb_req_fail(req, "failed", errmsg);
311 afb_req_success(req, NULL, "success");
314 HMI_DEBUG("activateWindow role:%s area:%s", appid, a_drawing_area);
317 std::string appidString = appid;
318 HMI_DEBUG("flg: %d", g_afb_instance->testFlg);
319 if ((appidString == "dashboard" && g_afb_instance->testFlg) || appidString == "hudspeed")
321 HMI_DEBUG("%s is remote transfer", appid);
322 g_afb_instance->wmgr.api_activate_surface_to_master(
323 appid, a_drawing_name, "hud.upper.left", reply);
325 g_afb_instance->testFlg = false;
330 if (!g_afb_instance->wmgr.wmcon.isRemoteArea(a_drawing_area))
332 g_afb_instance->wmgr.api_activate_window(
333 appid, a_drawing_name, a_drawing_area, reply);
337 std::string ecu_name;
338 ecu_name = g_afb_instance->wmgr.wmcon.getAreaToEcuName(a_drawing_area);
341 if (!g_afb_instance->wmgr.wmcon.isConnectionMode())
343 HMI_ERROR("WM Standalone Mode");
344 afb_req_fail(req, "failed", "Standalone Mode");
348 // If Window Manager is slave and this request is for master,
349 // request activateWindow to master
350 g_afb_instance->wmgr.api_activate_surface_to_master(
351 appid, a_drawing_name, a_drawing_area, reply);
355 if (appidString == "dashboard")
357 g_afb_instance->testFlg = true;
363 catch (std::exception &e)
365 HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
366 g_afb_instance->wmgr.exceptionProcessForTransition();
371 void windowmanager_deactivatewindow(afb_req req) noexcept
373 std::lock_guard<std::mutex> guard(binding_m);
374 if (g_afb_instance == nullptr)
376 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
382 const char *a_drawing_name = afb_req_value(req, "drawing_name");
385 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
389 char* appid = afb_req_get_application_id(req);
392 auto reply = [&req](const char *errmsg) {
393 if (errmsg != nullptr)
396 afb_req_fail(req, "failed", errmsg);
399 afb_req_success(req, NULL, "success");
402 // TODO: Check whether role is tbtnavi to request remote invisible
403 if (g_afb_instance->wmgr.wmcon.getAppIdToEcuName(appid) == "" ||
404 ("tbtnavi" != std::string(a_drawing_name)))
406 g_afb_instance->wmgr.api_deactivate_window(
407 appid, a_drawing_name, reply);
411 // If Window Manager is slave and this request is for master,
412 // request deactivateWindow to master
413 g_afb_instance->wmgr.api_deactivate_surface_to_master(
414 appid, a_drawing_name, reply);
419 catch (std::exception &e)
421 HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
422 g_afb_instance->wmgr.exceptionProcessForTransition();
427 void windowmanager_enddraw(afb_req req) noexcept
429 std::lock_guard<std::mutex> guard(binding_m);
430 if (g_afb_instance == nullptr)
432 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
438 const char *a_drawing_name = afb_req_value(req, "drawing_name");
441 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
444 afb_req_success(req, NULL, "success");
446 char* appid = afb_req_get_application_id(req);
450 if (!g_afb_instance->wmgr.wmcon.isRemoteEcu(appid) ||
451 !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid))
453 g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
457 // If Window Manager is slave and requesting app is syncDrawing,
458 // request endDraw to master
459 g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name);
464 catch (std::exception &e)
466 HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
467 g_afb_instance->wmgr.exceptionProcessForTransition();
472 void windowmanager_getdisplayinfo_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 auto ret = g_afb_instance->wmgr.api_get_display_info();
486 afb_req_fail(req, "failed", ret.unwrap_err());
490 afb_req_success(req, ret.unwrap(), "success");
492 catch (std::exception &e)
494 afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
499 void windowmanager_getareainfo_thunk(afb_req req) noexcept
501 std::lock_guard<std::mutex> guard(binding_m);
502 if (g_afb_instance == nullptr)
504 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
510 json_object *jreq = afb_req_json(req);
512 json_object *j_drawing_name = nullptr;
513 if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
515 afb_req_fail(req, "failed", "Need char const* argument drawing_name");
518 char const *a_drawing_name = json_object_get_string(j_drawing_name);
520 auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
523 afb_req_fail(req, "failed", ret.unwrap_err());
527 afb_req_success(req, ret.unwrap(), "success");
529 catch (std::exception &e)
531 afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
536 void windowmanager_getcarinfo_thunk(afb_req req) noexcept
538 std::lock_guard<std::mutex> guard(binding_m);
539 if (g_afb_instance == nullptr)
541 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
547 json_object *jreq = afb_req_json(req);
549 json_object *j_label = nullptr;
550 if (! json_object_object_get_ex(jreq, "label", &j_label))
552 afb_req_fail(req, "failed", "Need char const* argument label");
555 char const* a_label = json_object_get_string(j_label);
557 auto ret = g_afb_instance->wmgr.api_get_car_info(a_label);
560 afb_req_fail(req, "failed", ret.unwrap_err());
564 afb_req_success(req, ret.unwrap(), "success");
566 catch (std::exception &e)
568 afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what());
573 void windowmanager_set_render_order(afb_req req) noexcept
575 std::lock_guard<std::mutex> guard(binding_m);
576 if (g_afb_instance == nullptr)
578 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
582 char* appid = afb_req_get_application_id(req);
585 json_object *jreq = afb_req_json(req);
586 json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro
587 if (json_object_object_get_ex(jreq, "render_order", &j_ro))
589 int size = json_object_array_length(j_ro);
590 std::vector<std::string> ro(size);
591 for(int i = 0; i < size; i++)
593 ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i));
596 auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro);
599 afb_req_fail(req, "failed", nullptr);
603 afb_req_success(req, nullptr, nullptr);
610 afb_req_fail(req, "failed", nullptr);
614 void windowmanager_attach_app(afb_req req) noexcept
616 std::lock_guard<std::mutex> guard(binding_m);
617 if (g_afb_instance == nullptr)
619 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
623 char* appid = afb_req_get_application_id(req);
626 json_object *jreq = afb_req_json(req);
627 json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro
628 if (json_object_object_get_ex(jreq, "destination", &j_dest) &&
629 json_object_object_get_ex(jreq, "service_surface", &j_id))
631 const char* dest_app = json_object_get_string(j_dest);
632 const char* service = json_object_get_string(j_id);
634 std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service);
637 afb_req_fail(req, "failed", nullptr);
641 json_object *resp = json_object_new_object();
642 json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str()));
643 afb_req_success(req, resp, nullptr);
650 afb_req_fail(req, "failed", nullptr);
654 void windowmanager_get_area_list(afb_req req) noexcept
656 std::lock_guard<std::mutex> guard(binding_m);
657 json_object* ret = g_afb_instance->wmgr.api_get_area_list();
658 afb_req_success(req, ret, nullptr);
661 void windowmanager_change_area_size(afb_req req) noexcept
663 std::lock_guard<std::mutex> guard(binding_m);
664 if (g_afb_instance == nullptr)
666 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
670 char* appid = afb_req_get_application_id(req);
673 ChangeAreaReq change_req;
674 change_req.appname = appid;
675 change_req.save = false;
676 json_object *jreq = afb_req_json(req);
677 json_object *jsave, *jareas;
678 HMI_INFO("json_check, %s", json_object_get_string(jreq));
679 if(json_object_object_get_ex(jreq, "save", &jsave))
681 change_req.save = json_object_get_boolean(jsave);
683 if (json_object_object_get_ex(jreq, "areas", &jareas))
685 int size = json_object_array_length(jareas);
686 for(int i = 0; i < size; i++)
688 json_object* elem = json_object_array_get_idx(jareas, i);
690 std::string name = jh::getStringFromJson(elem, "name");
692 if(json_object_object_get_ex(elem, "rect", &jrect))
694 rect.x = jh::getIntFromJson(jrect, "x");
695 rect.y = jh::getIntFromJson(jrect, "y");
696 rect.w = jh::getIntFromJson(jrect, "w");
697 rect.h = jh::getIntFromJson(jrect, "h");
701 HMI_ERROR("bad request @area name :%s", name.c_str());
702 afb_req_fail(req, "failed", "bad request");
705 change_req.area_req[name] = rect;
707 if(change_req.area_req.size() != 0)
709 g_afb_instance->wmgr.api_change_area_size(change_req);
711 afb_req_success(req, nullptr, nullptr);
717 afb_req_fail(req, "failed", nullptr);
721 void windowmanager_wm_subscribe(afb_req req) noexcept
723 std::lock_guard<std::mutex> guard(binding_m);
724 if (g_afb_instance == nullptr)
726 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
732 json_object *jreq = afb_req_json(req);
733 json_object *j = nullptr;
734 if (!json_object_object_get_ex(jreq, "event", &j))
736 afb_req_fail(req, "failed", "Need char const* argument event");
739 int event_id = json_object_get_int(j);
740 int ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
744 afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
747 afb_req_success(req, NULL, "success");
751 //g_afb_instance->wmgr.api_handshake();
752 g_afb_instance->wmgr.setSubscribed(true);
755 catch (std::exception &e)
757 afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
762 void windowmanager_connect(afb_req req) noexcept
764 std::lock_guard<std::mutex> guard(binding_m);
766 HMI_DEBUG("WM - HS Connect");
768 if (g_afb_instance == nullptr)
770 afb_req_fail(req, "Failed", "Not Start WindowManager");
775 afb_req_success(req, NULL, "success");
779 void windowmanager_ping(afb_req req) noexcept
781 std::lock_guard<std::mutex> guard(binding_m);
783 if (g_afb_instance == nullptr)
785 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
790 afb_req_success(req, NULL, "success");
794 void windowmanager_debug_terminate(afb_req req) noexcept
796 std::lock_guard<std::mutex> guard(binding_m);
797 if (g_afb_instance == nullptr)
799 afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
806 if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
808 raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
809 // doesn't play well with perf
812 afb_req_success(req, NULL, "success");
814 catch (std::exception &e)
816 afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
821 void on_event(const char *event, struct json_object *object)
823 g_afb_instance->wmgr.analyzeReceivedEvent(event, object);
826 const struct afb_verb_v2 windowmanager_verbs[] = {
827 {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
828 {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
829 {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
830 {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
831 {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
832 {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
833 {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
834 {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
835 {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE },
836 {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE},
837 {"changeAreaSize", windowmanager_change_area_size, nullptr, nullptr, AFB_SESSION_NONE},
838 {"getAreaList", windowmanager_get_area_list, nullptr, nullptr, AFB_SESSION_NONE},
839 {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE},
840 {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
841 {"wm_connect", windowmanager_connect, nullptr, nullptr, AFB_SESSION_NONE},
842 {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
843 {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
846 extern "C" const struct afb_binding_v2 afbBindingV2 = {
847 "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};