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