From 1d410b7d63066f6156997e50b93cb2a7ce6b74bc Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Mon, 14 Mar 2016 20:52:55 +0900 Subject: [PATCH] add app signal listening functions at app-manager Signed-off-by: Junghyun Yeon Change-Id: I4a86707a94af2ae4fb4c9b9db1161ca8d09f9d69 --- CMakeLists.txt | 7 +- include/app_manager.h | 155 +++++++++++++++++++++++++- include/app_manager_event.h | 64 +++++++++++ packaging/capi-appfw-app-manager.spec | 6 +- src/app_manager.c | 115 ++++++++++++++++++++ src/app_manager_event.c | 199 ++++++++++++++++++++++++++++++++++ 6 files changed, 542 insertions(+), 4 deletions(-) create mode 100644 include/app_manager_event.h create mode 100644 src/app_manager_event.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f8edd0..f6ea2c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(capi-appfw-app-manager C) SET(SOURCES src/app_context.c src/app_info.c + src/app_manager_event.c src/app_manager.c) INCLUDE(FindPkgConfig) @@ -36,7 +37,11 @@ SET(PC_PREFIX ${CMAKE_INSTALL_PREFIX}) CONFIGURE_FILE(capi-appfw-app-manager.pc.in ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc @ONLY) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) -INSTALL(DIRECTORY ${INC_DIR}/ DESTINATION include/appfw) +INSTALL(FILES ${INC_DIR}/app_context.h DESTINATION include/appfw) +INSTALL(FILES ${INC_DIR}/app_manager_extension.h DESTINATION include/appfw) +INSTALL(FILES ${INC_DIR}/app_manager.h DESTINATION include/appfw) +INSTALL(FILES ${INC_DIR}/app_info.h DESTINATION include/appfw) + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) ADD_SUBDIRECTORY(tool) diff --git a/include/app_manager.h b/include/app_manager.h index 0e17b4c..9f43cc9 100644 --- a/include/app_manager.h +++ b/include/app_manager.h @@ -54,6 +54,64 @@ typedef enum { } app_manager_error_e; /** + * @brief Enumeration for app manager status type. + * @since_tizen 3.0 + */ +typedef enum { + APP_MANAGER_EVENT_STATUS_TYPE_ALL = 0x00, /**< All Status */ + APP_MANAGER_EVENT_STATUS_TYPE_ENABLE = 0x01, /**< Application enable status */ + APP_MANAGER_EVENT_STATUS_TYPE_DISABLE = 0x02, /**< Application disable status */ +} app_manager_event_status_type_e; + +/** + * @brief Enumeration for app manager event type. + * @since_tizen 3.0 + */ +typedef enum { + APP_MANAGER_EVENT_ENABLE_APP = 0, /**< Application enable event */ + APP_MANAGER_EVENT_DISABLE_APP, /**< Application disable event. */ +} app_manager_event_type_e; + +/** + * @brief Enumeration for app manager event state. + * @since_tizen 3.0 + */ +typedef enum { + APP_MANAGER_EVENT_STATE_STARTED = 0, /**< Started event state */ + APP_MANAGER_EVENT_STATE_COMPLETED, /**< Completed event state */ + APP_MANAGER_EVENT_STATE_FAILED, /**< Failed event state */ +} app_manager_event_state_e; + +/** + * @brief App manager event handle. + * @since_tizen 3.0 + */ +typedef struct _app_manager_event_s *app_manager_event_h; + +/** + * @brief Called when the application is enabled or disabled. + * @since_tizen 3.0 + * + * @param[in] type The type of the app to be enabled or disabled + * @param[in] app_id The app id to be enabled or disabled + * @param[in] event_type The event type of the app + * @param[in] event_state The current event state of the app + * @param[in] handle The app manager event handle + * @param[in] user_data The user data passed from app_manager_set_event_cb() + * @pre This function is called when an application being disabled or enabled, after you register this callback using app_manager_set_event_cb(). + * + * @see app_manager_set_event_cb() + * @see app_manager_unset_event_cb() + */ +typedef void (*app_manager_event_cb) ( + const char *type, + const char *app_id, + app_manager_event_type_e event_type, + app_manager_event_state_e event_state, + app_manager_event_h handle, + void *user_data); + +/** * @brief Called when an application is launched or terminated. * @since_tizen @if MOBILE 2.4 @elseif WEARABLE 3.0 @endif * @param[in] app_context The application context of the application launched or terminated @@ -108,7 +166,6 @@ int app_manager_set_app_context_event_cb(app_manager_app_context_event_cb callba /** * @brief Unregisters the callback function. * @since_tizen @if MOBILE 2.4 @elseif WEARABLE 3.0 @endif - * @see app_manager_set_app_event_cb() * @see app_manager_app_context_event_cb() */ void app_manager_unset_app_context_event_cb(void); @@ -349,6 +406,102 @@ int app_manager_get_shared_trusted_path(const char *app_id, char **path); int app_manager_get_external_shared_data_path(const char *app_id, char **path); /** + * @brief Creates a app manager event handle. + * @since_tizen 3.0 + * @remarks You must release @a handle using app_manager_event_destroy(). + * + * @param[out] handle The app manager event handle that is newly created on success + * + * @return @c 0 on success, + * otherwise a negative error value + * + * @retval #APP_MANAGER_ERROR_NONE Successful + * @retval #APP_MANAGER_ERROR_OUT_OF_MEMORY Out of memory + * @retval #APP_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @see app_manager_event_destroy() + */ +int app_manager_event_create(app_manager_event_h *handle); + +/** + * @brief Sets the event to handle to listen. + * You can combine multiple status using OR operation which you want to listen. + * @since_tizen 3.0 + * + * @param [in] handle The app manager event handle + * @param [in] status_type The status of the application + * + * @return @c 0 on success, + * otherwise a negative error value + * + * @retval #APP_MANAGER_ERROR_NONE Successful + * @retval #APP_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_MANAGER_ERROR_REQUEST_FAILED Internal error + * + * @see app_manager_event_status_type_e + * @see app_manager_set_event_cb() + */ +int app_manager_event_set_status(app_manager_event_h handle, int status_type); + +/** + * @brief Registers a callback function to be invoked when the app is event has occurred + * @since_tizen 3.0 + * @param[in] handle The app manager event handle + * @param[in] callback The callback function to be registered + * @param[in] user_data The user data to be passed to the callback function + * + * @return @c 0 on success, + * otherwise a negative error value + * + * @retval #APP_MANAGER_ERROR_NONE Successful + * @retval #APP_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_MANAGER_ERROR_REQUEST_FAILED Internal error + * @post app_manager_event_cb() will be invoked. + * + * @see app_manager_event_set_status() + * @see app_manager_event_cb() + * @see app_manager_unset_event_cb() + */ +int app_manager_set_event_cb(app_manager_event_h handle, + app_manager_event_cb callback, + void *user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * + * @param[in] handle The app manager event handle + * + * @return @c 0 on success, + * otherwise a negative error value + * + * @retval #APP_MANAGER_ERROR_NONE Successful + * @retval #APP_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_MANAGER_ERROR_REQUEST_FAILED Internal error + * + * @see app_manager_event_cb() + * @see app_manager_set_event_cb() + */ +int app_manager_unset_event_cb(app_manager_event_h handle); + +/** + * @brief Destroys the app manager event handle. + * @since_tizen 3.0 + * + * @param[in] handle The app manager event handle + * + * @return @c 0 on success, + * otherwise a negative error value + * + * @retval #APP_MANAGER_ERROR_NONE Successful + * @retval #APP_MANAGER_ERROR_REQUEST_FAILED Internal error + * @retval #APP_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see app_manager_event_create() + */ +int app_manager_event_destroy(app_manager_event_h handle); + + +/** * @} */ diff --git a/include/app_manager_event.h b/include/app_manager_event.h new file mode 100644 index 0000000..011fc21 --- /dev/null +++ b/include/app_manager_event.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 __TIZEN_APPFW_APP_MANAGER_EVENT_H +#define __TIZEN_APPFW_APP_MANAGER_EVENT_H + +#include +#include + +#include "app_manager.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _app_manager_event_info { + int req_id; + app_manager_event_type_e event_type; + app_manager_event_state_e event_state; + struct _app_manager_event_info *next; +} app_manager_event_info; + +typedef struct _app_manager_event_s { + int req_id; + pkgmgr_client *pc; + app_manager_event_cb event_cb; + void *user_data; + app_manager_event_info *head; +} app_manager_event; + +int app_event_handler(uid_t target_uid, int req_id, + const char *pkg_type, const char *pkgid, const char *appid, + const char *key, const char *val, const void *pmsg, void *data); + +int convert_status_type(int status_type); + +void remove_app_manager_event_info_list(app_manager_event_info *head); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_APPFW_APP_MANAGER_EVENT_H */ + diff --git a/packaging/capi-appfw-app-manager.spec b/packaging/capi-appfw-app-manager.spec index a9d9aa2..d37e372 100644 --- a/packaging/capi-appfw-app-manager.spec +++ b/packaging/capi-appfw-app-manager.spec @@ -54,8 +54,10 @@ rm -rf %{buildroot} %license LICENSE %files devel -%{_includedir}/appfw/*.h +%{_includedir}/appfw/app_context.h +%{_includedir}/appfw/app_manager_extension.h +%{_includedir}/appfw/app_manager.h +%{_includedir}/appfw/app_info.h %{_libdir}/libcapi-appfw-app-manager.so %{_libdir}/pkgconfig/*.pc - diff --git a/src/app_manager.c b/src/app_manager.c index e578baa..b7c0261 100644 --- a/src/app_manager.c +++ b/src/app_manager.c @@ -28,6 +28,7 @@ #include "app_manager.h" #include "app_manager_internal.h" +#include "app_manager_event.h" #ifdef LOG_TAG #undef LOG_TAG @@ -476,3 +477,117 @@ API int app_manager_set_splash_screen_display(const char *app_id, bool display) return r; } +API int app_manager_event_create(app_manager_event_h *handle) +{ + pkgmgr_client *pc = NULL; + app_manager_event *app_mgr_evt = NULL; + + if (handle == NULL) + return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + app_mgr_evt = (app_manager_event *)calloc(1, sizeof(app_manager_event)); + if (app_mgr_evt == NULL) + return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, + __FUNCTION__, NULL); + + pc = pkgmgr_client_new(PC_LISTENING); + if (pc == NULL) + return app_manager_error(APP_MANAGER_ERROR_OUT_OF_MEMORY, + __FUNCTION__, NULL); + + app_mgr_evt->pc = pc; + *handle = app_mgr_evt; + return APP_MANAGER_ERROR_NONE; +} + +API int app_manager_event_set_status(app_manager_event_h handle, int status_type) +{ + int ret = APP_MANAGER_ERROR_NONE; + int pkgmgr_status_type = -1; + + if (handle == NULL || status_type < 0) + return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + pkgmgr_status_type = convert_status_type(status_type); + if (pkgmgr_status_type < 0) + return app_manager_error(APP_MANAGER_ERROR_REQUEST_FAILED, + __FUNCTION__, NULL); + + ret = pkgmgr_client_set_status_type(handle->pc, pkgmgr_status_type); + if (ret != PKGMGR_R_OK) { + LOGE("[%s] APP_MANAGER_ERROR_REQUEST_FAILED(0x%08x) : " \ + "Failed to set event status", __FUNCTION__, + APP_MANAGER_ERROR_REQUEST_FAILED); + return APP_MANAGER_ERROR_REQUEST_FAILED; + } + + return APP_MANAGER_ERROR_NONE; +} + +API int app_manager_set_event_cb(app_manager_event_h handle, + app_manager_event_cb callback, + void *user_data) +{ + int ret = APP_MANAGER_ERROR_NONE; + + if (handle == NULL || callback == NULL) + return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + handle->event_cb = callback; + handle->user_data = user_data; + + ret = pkgmgr_client_listen_app_status(handle->pc, + app_event_handler, handle); + if (ret < PKGMGR_R_OK) { + LOGE("[%s] APP_MANAGER_ERROR_REQUEST_FAILED(0x%08x) : " \ + "Failed to set event callback", __FUNCTION__, + APP_MANAGER_ERROR_REQUEST_FAILED); + return APP_MANAGER_ERROR_REQUEST_FAILED; + } + + handle->req_id = ret; + return APP_MANAGER_ERROR_NONE; +} + +API int app_manager_unset_event_cb(app_manager_event_h handle) +{ + int ret = APP_MANAGER_ERROR_NONE; + + if (handle == NULL || handle->pc == NULL) + return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + ret = pkgmgr_client_remove_listen_status(handle->pc); + if (ret != 0) { + LOGE("[%s] APP_MANAGER_ERROR_REQUEST_FAILED(0x%08x) : " \ + "Failed to unset event callback", __FUNCTION__, + APP_MANAGER_ERROR_REQUEST_FAILED); + return APP_MANAGER_ERROR_REQUEST_FAILED; + } + + return APP_MANAGER_ERROR_NONE; +} + +API int app_manager_event_destroy(app_manager_event_h handle) +{ + int ret = APP_MANAGER_ERROR_NONE; + + if (handle == NULL) + return app_manager_error(APP_MANAGER_ERROR_INVALID_PARAMETER, + __FUNCTION__, NULL); + + ret = pkgmgr_client_free(handle->pc); + if (ret != 0) { + LOGE("[%s] APP_MANAGER_ERROR_REQUEST_FAILED(0x%08x) : " \ + "Failed to destroy handle", __FUNCTION__, + APP_MANAGER_ERROR_REQUEST_FAILED); + return APP_MANAGER_ERROR_REQUEST_FAILED; + } + remove_app_manager_event_info_list(handle->head); + + free(handle); + return APP_MANAGER_ERROR_NONE; +} diff --git a/src/app_manager_event.c b/src/app_manager_event.c new file mode 100644 index 0000000..fcdea81 --- /dev/null +++ b/src/app_manager_event.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#include +#include + +#include "app_manager_event.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "CAPI_APPFW_APP_MANAGER" + +static int __remove_app_manager_event_info(app_manager_event_info *head, int req_id) +{ + app_manager_event_info *prev; + app_manager_event_info *current; + + current = prev = head; + if (current == NULL) + return APP_MANAGER_ERROR_INVALID_PARAMETER; + + while (current) { + if (current->req_id == req_id) { + prev->next = current->next; + free(current); + current = NULL; + return APP_MANAGER_ERROR_NONE; + } + prev = current; + current = current->next; + } + + return APP_MANAGER_ERROR_NONE; +} + +static int __find_app_manager_event_info(app_manager_event_info **head, + int req_id, app_manager_event_type_e *event_type) +{ + app_manager_event_info *tmp; + + tmp = *head; + + if (tmp == NULL) { + LOGE("head is null"); + return APP_MANAGER_ERROR_INVALID_PARAMETER; + } + + while (tmp) { + if (tmp->req_id == req_id) { + *event_type = tmp->event_type; + return APP_MANAGER_ERROR_NONE; + } + tmp = tmp->next; + } + + return APP_MANAGER_ERROR_REQUEST_FAILED; +} + +static int __add_app_manager_event_info(app_manager_event_info **head, + int req_id, app_manager_event_type_e event_type) +{ + app_manager_event_info *event_info; + app_manager_event_info *current; + app_manager_event_info *prev; + + event_info = (app_manager_event_info *)calloc(1, sizeof(app_manager_event_info)); + if (event_info == NULL) + return APP_MANAGER_ERROR_OUT_OF_MEMORY; + + event_info->req_id = req_id; + event_info->event_type = event_type; + event_info->next = NULL; + + if (*head == NULL) { + *head = event_info; + } else { + current = prev = *head; + while (current) { + prev = current; + current = current->next; + } + prev->next = event_info; + } + + return APP_MANAGER_ERROR_NONE; +} + +static int __get_app_manager_event_type(const char *key, app_manager_event_type_e *event_type) +{ + if (key == NULL) + return APP_MANAGER_ERROR_INVALID_PARAMETER; + + if (strcasecmp(key, "disable_app") == 0 || + strcasecmp(key, "disable_global_app_for_uid") == 0) + *event_type = APP_MANAGER_EVENT_DISABLE_APP; + else if (strcasecmp(key, "enable_app") == 0 || + strcasecmp(key, "enable_global_app_for_uid") == 0) + *event_type = APP_MANAGER_EVENT_ENABLE_APP; + else + return APP_MANAGER_ERROR_INVALID_PARAMETER; + return APP_MANAGER_ERROR_NONE; +} + +void remove_app_manager_event_info_list(app_manager_event_info *head) +{ + if (head == NULL) + return; + + app_manager_event_info *current = head; + + if (current->next != NULL) + remove_app_manager_event_info_list(current->next); + + free(current); + return; +} + +int app_event_handler(uid_t target_uid, int req_id, + const char *pkg_type, const char *pkgid, const char *appid, + const char *key, const char *val, const void *pmsg, void *data) +{ + app_manager_event *app_evt = (app_manager_event *)data; + app_manager_event_type_e event_type = -1; + int ret = -1; + + LOGI("app_event_handler called"); + + if (app_evt == NULL || app_evt->event_cb == NULL) + return APP_MANAGER_ERROR_INVALID_PARAMETER; + + if (strcasecmp(key, "start") == 0) { + ret = __get_app_manager_event_type(val, &event_type); + if (ret != APP_MANAGER_ERROR_NONE) + return APP_MANAGER_ERROR_INVALID_PARAMETER; + + ret = __add_app_manager_event_info(&(app_evt->head), req_id, event_type); + if (ret != APP_MANAGER_ERROR_NONE) + return APP_MANAGER_ERROR_REQUEST_FAILED; + + app_evt->event_cb(pkg_type, appid, event_type, + APP_MANAGER_EVENT_STATE_STARTED, app_evt, app_evt->user_data); + } else if (strcasecmp(key, "end") == 0) { + if (__find_app_manager_event_info(&(app_evt->head), req_id, &event_type) + != APP_MANAGER_ERROR_NONE) + return APP_MANAGER_ERROR_REQUEST_FAILED; + + if (strcasecmp(val, "ok") == 0) + app_evt->event_cb(pkg_type, appid, event_type, + APP_MANAGER_EVENT_STATE_COMPLETED, app_evt, app_evt->user_data); + else if (strcasecmp(val, "fail") == 0) + app_evt->event_cb(pkg_type, appid, event_type, + APP_MANAGER_EVENT_STATE_FAILED, app_evt, app_evt->user_data); + + ret = __remove_app_manager_event_info(app_evt->head, req_id); + if (ret != APP_MANAGER_ERROR_NONE) { + LOGE("failed to remove app event info"); + return APP_MANAGER_ERROR_REQUEST_FAILED; + } + + } else { + return APP_MANAGER_ERROR_INVALID_PARAMETER; + } + + return APP_MANAGER_ERROR_NONE; +} + +int convert_status_type(int status_type) +{ + int result = 0; + + if (status_type == 0) + return PKGMGR_CLIENT_STATUS_ALL; + + if ((status_type & APP_MANAGER_EVENT_STATUS_TYPE_ENABLE) + == APP_MANAGER_EVENT_STATUS_TYPE_ENABLE) + result += PKGMGR_CLIENT_STATUS_ENABLE_APP; + + if ((status_type & APP_MANAGER_EVENT_STATUS_TYPE_DISABLE) + == APP_MANAGER_EVENT_STATUS_TYPE_DISABLE) + result += PKGMGR_CLIENT_STATUS_DISABLE_APP; + + return result; +} + -- 2.7.4