From: Tadao Tanikawa Date: Tue, 4 Dec 2018 01:13:04 +0000 (+0000) Subject: POI: AGL LifeCycle Management X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=commitdiff_plain;h=e35c4bf9b16927829e1741b9d9c08294f0cbed29;p=apps%2Fagl-service-windowmanager.git POI: AGL LifeCycle Management Limited function are supported for CES2019 demo. API: registerActivityObserver { "target": $appid } unregisterActivityObserver { "target": $appid } getActivityStatus { "target" : $appid } reply { "response": { "api": "getActivityStatus", "target": $appid, "state": $activity_status } Event: statusChanged { "jtype": "afb-event", "event": "windowmanager/statusChanged", "data": { "state": "CREATED|DESTROYED|STARTED|STOPPED|FOREGROUND|BACKGROUND", "target": $appid } } Change-Id: Ie54c7f379df58667bd5878b4115a3c763c761a83 Signed-off-by: Tadao Tanikawa --- diff --git a/src/activity_manager.hpp b/src/activity_manager.hpp new file mode 100644 index 0000000..0663003 --- /dev/null +++ b/src/activity_manager.hpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 Panasonic Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ACTIVITY_MANAGER_HPP +#define ACTIVITY_MANAGER_HPP + +#include + +extern "C" +{ +#include +} + +namespace lcm +{ + +#define LCM_EVENT_STATUS_CHANGED "statusChanged" +#define LCM_API_GET_ACTIVITY_STATUS "getActivityStatus" +#define LCM_API "api" +#define LCM_TARGET "target" +#define LCM_STATE "state" + +enum activity_status +{ + NOTEXISTS, + + CREATED, // after ON_CREATE + DESTROYED,// after ON_DESTROY + + STARTED, // after ON_START, ON_RESTART + STOPPED, // after ON_STOP + + FOREGROUND, // after ON_FOREGROUND + BACKGROUND, // after ON_BACKGROUND + + NUM_STATUS, +}; + +#define ACTIVITY_FILTER_ALL_SET "111111" // For demo, always notify all states + +struct _observer_context { + afb_event_t event; // onStatusChanged + std::bitset filter; // not supported yet +}; + +using observer = struct _observer_context; + +// map of <"id:appid", "context of observer"> +using observers = std::map; + +class ActivityManager +{ + public: + explicit ActivityManager(); + ~ActivityManager() = default; + + void api_register_activity_observer (afb_req_t req); + void api_unregister_activity_observer (afb_req_t req); + wm::result api_get_activity_status(const char *appid); + + public: + void emit_activity_status_changed(const char* appid, const char* state); + + // map of <"id:target", "registered observers"> + std::map map_observers; + // map of <"id:target", "current_state"> + std::map states; + + const char *states_s[NUM_STATUS]; +}; + +} // namespace lcm +#endif /* ACTIVITY_MANAGER_HPP */ diff --git a/src/main.cpp b/src/main.cpp index 333df70..8e37d10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -490,6 +490,70 @@ void windowmanager_debug_terminate(afb_req_t req) noexcept } } +/* AGL Lifecycle Management API */ +static void lcm_register_activity_observer (afb_req_t req) +{ + std::lock_guard guard(binding_m); + if (g_afb_instance == nullptr) { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + // register new activity observer + // { + // id: "app id of target to observe", + // type: "type of lifecycle, APP, HMI or GUI to observe", + // filter: { states which observer wants to know } + // } + g_afb_instance->wmgr.amgr.api_register_activity_observer(req); + + afb_req_success(req, NULL, "success"); +} + +static void lcm_unregister_activity_observer (afb_req_t req) +{ + std::lock_guard guard(binding_m); + if (g_afb_instance == nullptr) + { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + return; + } + + // unregister activity observer + // { + // id: "uniq id of observer" + // } + g_afb_instance->wmgr.amgr.api_unregister_activity_observer(req); + + afb_req_success(req, NULL, "success"); +} + +static void lcm_get_activity_status(afb_req_t req) +{ + std::lock_guard guard(binding_m); + + if (g_afb_instance == nullptr) { + afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?"); + } else { + json_object *object = afb_req_json(req); + json_object *j_target = nullptr; + if (!json_object_object_get_ex(object, "target", &j_target)) { + afb_req_fail(req, "failed", "Need const char* argument target"); + return; + } + + const char *target_id = json_object_get_string(j_target); + + auto ret = g_afb_instance->wmgr.amgr.api_get_activity_status(target_id); + + if (ret.is_err()) { + afb_req_fail(req, "failed", ret.unwrap_err()); + } else { + afb_req_success(req, ret.unwrap(), "success"); + } + } +} + const afb_verb_t windowmanager_verbs[] = { { .verb = "requestSurface", .callback = windowmanager_requestsurface }, { .verb = "requestSurfaceXDG", .callback = windowmanager_requestsurfacexdg }, @@ -501,6 +565,10 @@ const afb_verb_t windowmanager_verbs[] = { { .verb = "wm_subscribe", .callback = windowmanager_wm_subscribe }, { .verb = "ping", .callback = windowmanager_ping }, { .verb = "debug_terminate", .callback = windowmanager_debug_terminate }, + /* AGL Lifecycle Management API */ + { .verb = "registerActivityObserver", .callback = lcm_register_activity_observer }, + { .verb = "unregisterActivityObserver", .callback = lcm_unregister_activity_observer }, + { .verb = "getActivityStatus", .callback = lcm_get_activity_status }, {} }; extern "C" const afb_binding_t afbBindingExport = { diff --git a/src/window_manager.cpp b/src/window_manager.cpp index cd7d2e5..06f7793 100644 --- a/src/window_manager.cpp +++ b/src/window_manager.cpp @@ -187,6 +187,11 @@ result WindowManager::api_request_surface(char const *appid, char const *dr auto id = int(this->id_alloc.generate_id(role)); this->tmp_surface2app[id] = {str_id, lid}; + // POI: AGL LifeCycle Management + this->amgr.states[str_id] = lcm::CREATED; + this->amgr.emit_activity_status_changed(str_id.c_str(), + this->amgr.states_s[lcm::CREATED]); + return Ok(id); } @@ -246,6 +251,11 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr auto client = g_app_list.lookUpClient(str_id); client->addSurface(sid); + // POI: AGL LifeCycle Management + this->amgr.states[str_id] = lcm::CREATED; + this->amgr.emit_activity_status_changed(str_id.c_str(), + this->amgr.states_s[lcm::CREATED]); + return nullptr; } @@ -285,7 +295,7 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n } // Do allocate tasks - + ret = this->checkPolicy(req_num); if (ret != WMError::SUCCESS) @@ -294,6 +304,13 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n HMI_SEQ_ERROR(req_num, errorDescription(ret)); g_app_list.removeRequest(req_num); this->processNextRequest(); + } else { + // POI: AGL LifeCycle Management + if (this->amgr.states[id] == lcm::CREATED) { + this->amgr.states[id] = lcm::STARTED; + this->amgr.emit_activity_status_changed(id.c_str(), + this->amgr.states_s[lcm::STARTED]); + } } } @@ -334,6 +351,14 @@ void WindowManager::api_deactivate_window(char const *appid, char const *drawing HMI_SEQ_ERROR(req_num, errorDescription(ret)); g_app_list.removeRequest(req_num); this->processNextRequest(); + } else { + // POI: AGL LifeCycle Management + int state = this->amgr.states[id]; + if (state == lcm::STARTED || state == lcm::BACKGROUND) { + this->amgr.states[id] = lcm::STOPPED; + this->amgr.emit_activity_status_changed(id.c_str(), + this->amgr.states_s[lcm::STOPPED]); + } } } @@ -492,6 +517,12 @@ void WindowManager::removeClient(const string &appid) auto client = g_app_list.lookUpClient(appid); this->lc->appTerminated(client); g_app_list.removeClient(appid); + // POI: AGL LifeCycle Management + if (this->amgr.states[appid] != lcm::DESTROYED) { + this->amgr.states[appid] = lcm::DESTROYED; + this->amgr.emit_activity_status_changed(appid.c_str(), + this->amgr.states_s[lcm::DESTROYED]); + } } void WindowManager::exceptionProcessForTransition() @@ -853,9 +884,22 @@ void WindowManager::emitScreenUpdated(unsigned req_num) for(const auto& action: actions) { + std::string appid = action.client->appID(); + if(action.visible != TaskVisible::INVISIBLE) { - json_object_array_add(jarray, json_object_new_string(action.client->appID().c_str())); + json_object_array_add(jarray, json_object_new_string(appid.c_str())); + // POI: AGL LifeCycle Management + if (this->amgr.states[appid] != lcm::FOREGROUND) { + this->amgr.states[appid] = lcm::FOREGROUND; + this->amgr.emit_activity_status_changed(appid.c_str(), this->amgr.states_s[lcm::FOREGROUND]); + } + } else { + // POI: AGL LifeCycle Management + if (this->amgr.states[appid] != lcm::BACKGROUND) { + this->amgr.states[appid] = lcm::BACKGROUND; + this->amgr.emit_activity_status_changed(appid.c_str(), this->amgr.states_s[lcm::BACKGROUND]); + } } } json_object_object_add(j, kKeyIds, jarray); @@ -928,3 +972,127 @@ void WindowManager::processNextRequest() } } // namespace wm + +namespace lcm +{ + +ActivityManager::ActivityManager (void) + : states_s { "NOTEXISTS", + "CREATED", + "DESTROYED", + "STARTED", + "STOPPED", + "FOREGROUND", + "BACKGROUND" } +{ + ; +} + +void ActivityManager::api_register_activity_observer (afb_req_t req) +{ + std::string observer = afb_req_get_application_id(req); + + json_object *j_data = afb_req_json(req); + json_object *j_target; + if (!json_object_object_get_ex(j_data, LCM_TARGET, &j_target)) { + afb_req_fail(req, "failed", "Need char const* argument target"); + return; + } + std::string target(json_object_get_string(j_target)); + + for (auto itr = this->map_observers.begin(); itr != this->map_observers.end(); ++itr) { + observers mp = itr->second; + if (mp.count(observer)) { + // Already exist + HMI_DEBUG("observer(%s) is already exist", observer.c_str()); + if (this->map_observers[target].count(observer)) { + // Aready registered + HMI_DEBUG("observer(%s->%s) is already registered", observer.c_str(), target.c_str()); + } else { + HMI_DEBUG("observer(%s->%s) is registered", observer.c_str(), target.c_str()); + + (this->map_observers[target])[observer] = mp[observer]; + } + return; + } + } + + // New observer + afb_event_t event = afb_daemon_make_event(LCM_EVENT_STATUS_CHANGED); + //afb_event_t event = afb_daemon_make_event(LCM_EVENT_STATUS_CHANGED); + (this->map_observers[target])[observer] = { + event, + std::bitset(ACTIVITY_FILTER_ALL_SET) + }; + + if (afb_req_subscribe(req, event) != 0) { + HMI_ERROR("cannot subscribe event"); + } +} + +void ActivityManager::api_unregister_activity_observer (afb_req_t req) +{ + std::string observer = afb_req_get_application_id(req); + + json_object *j_data = afb_req_json(req); + json_object *j_target; + + if (!json_object_object_get_ex(j_data, LCM_TARGET, &j_target)) { + afb_req_fail(req, "failed", "Need char const* argument target"); + return; + } + std::string target(json_object_get_string(j_target)); + + HMI_DEBUG("observer(%s->%s) is unregistered.", observer.c_str(), target.c_str()); +} + +wm::result ActivityManager::api_get_activity_status (const char *appid) +{ + std::string id = appid; + int st = NOTEXISTS; + + if (this->states.count(id)) { + st = this->states[id]; + + if (st < 0 || st >= NUM_STATUS) { + HMI_ERROR("Illegal lifecycle state (%d) of [%s]", st, appid); + return wm::Err("Illegal lifecycle state"); + } + } + + const char * state = this->states_s[st]; + + json_object *object = json_object_new_object(); + json_object_object_add(object, LCM_API, json_object_new_string(LCM_API_GET_ACTIVITY_STATUS)); + json_object_object_add(object, LCM_TARGET, json_object_new_string(appid)); + json_object_object_add(object, LCM_STATE, json_object_new_string(state)); + + return wm::Ok(object); +} + +void ActivityManager::emit_activity_status_changed (const char* appid, const char* state) +{ + // POI: AGL LifeCycle Management + // E.g. statusChanged(CREATED->STARTED) + std::string id = appid; + + if (this->map_observers.count(id)) { + observers mp = this->map_observers[id]; + for (auto itr = mp.begin(); itr != mp.end(); ++itr) { + afb_event_t event = itr->second.event; + if (afb_event_is_valid(event)) { + HMI_DEBUG("emit_activity_status_changed(%s, %s)", appid, state); + json_object *data = json_object_new_object(); + json_object_object_add(data, LCM_STATE, json_object_new_string(state)); + json_object_object_add(data, LCM_TARGET, json_object_new_string(appid)); + + afb_event_push(event, json_object_get(data)); + json_object_put(data); + } else { + HMI_ERROR("afb_event is not valid"); + } + } + } +} + +} // namespace lcm diff --git a/src/window_manager.hpp b/src/window_manager.hpp index 30deb4b..582a74d 100644 --- a/src/window_manager.hpp +++ b/src/window_manager.hpp @@ -32,6 +32,8 @@ extern "C" #include } +#include "activity_manager.hpp" + struct json_object; namespace wm @@ -177,8 +179,10 @@ class WindowManager void api_deactivate_window(char const *appid, char const *role, const reply_func &reply); void api_enddraw(char const *appid, char const *role); int api_subscribe(afb_req_t req, int event_id); + result api_get_display_info(); result api_get_area_info(char const *role); + void send_event(const std::string& evname, const std::string& role); void send_event(const std::string& evname, const std::string& role, const std::string& area, int x, int y, int w, int h); @@ -194,6 +198,10 @@ class WindowManager void startTransitionWrapper(std::vector &actions); void processError(WMError error); + public: + // AGL Lifecycle Management API + lcm::ActivityManager amgr; + private: // WM Events to clients void emit_activated(const std::string& role);