From 980f857486e1a1ca3686f264e15242853971bce0 Mon Sep 17 00:00:00 2001 From: Tomasz Swierczek Date: Thu, 27 Feb 2020 10:36:20 +0100 Subject: [PATCH] Integration with new askuser UI apps This patch adds implementation of ppm_popup_send_response API as well as new implementation of requesting a popup, using askuser-popup external application. Internally the patch removes m_currentEvent usage, allowing the popups to be processed, theoretically, in parallel for many requests. Patch does not: * add security check to ppm_popup_send_response * remove not-needed EFL code Above things will be done in separate patches. Change-Id: Iaeb1d797141b750b462d21bd619e92e0c647e235 --- src/capi/impl/privacy_privilege_manager.c | 43 +++- src/capi/test/privacy_privilege_manager_test.cpp | 9 +- src/client/api/ApiInterface.h | 3 +- src/client/api/askuser-notification-client.cpp | 43 +++- src/client/impl/ApiInterfaceImpl.cpp | 7 +- src/client/impl/ApiInterfaceImpl.h | 3 +- src/client/include/askuser-notification-client.h | 24 +- src/ipc/client-channel.cpp | 31 ++- src/ipc/client-channel.h | 3 +- src/ipc/common-types.h | 4 +- src/ipc/credentials.cpp | 15 +- src/ipc/credentials.h | 3 +- src/ipc/message-utils.h | 38 ++- src/ipc/server-channel.cpp | 30 ++- src/ipc/server-channel.h | 11 +- src/ipc/test/main.cpp | 9 +- src/notification-daemon/CMakeLists.txt | 2 + src/notification-daemon/Logic.cpp | 291 +++++++++++------------ src/notification-daemon/Logic.h | 47 ++-- src/notification-daemon/PolicyUpdater.cpp | 4 +- src/notification-daemon/PolicyUpdater.h | 4 +- src/notification-daemon/ServerCallbacks.cpp | 6 +- src/notification-daemon/ServerCallbacks.h | 5 +- src/notification-daemon/event/Event.h | 26 +- src/notification-daemon/ui/UIAppInvoker.cpp | 139 +++++++++++ src/notification-daemon/ui/UIAppInvoker.h | 39 +++ 26 files changed, 636 insertions(+), 203 deletions(-) create mode 100644 src/notification-daemon/ui/UIAppInvoker.cpp create mode 100644 src/notification-daemon/ui/UIAppInvoker.h diff --git a/src/capi/impl/privacy_privilege_manager.c b/src/capi/impl/privacy_privilege_manager.c index 0aa75fa..49efb1f 100644 --- a/src/capi/impl/privacy_privilege_manager.c +++ b/src/capi/impl/privacy_privilege_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2020 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -502,10 +502,41 @@ int ppm_popup_send_response(int popup_id, ppm_popup_response_e *responses, size_t privacies_count) { - (void) popup_id; - (void) privacies; - (void) responses; - (void) privacies_count; + if (!privacies || !responses || privacies_count < 1) { + return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER; + } + + int ret = ppm_init_client(); + if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) { + return ret; + } + + askuser_popup_result* aresults = (askuser_popup_result*) calloc(1, sizeof(askuser_popup_result) * privacies_count); + if (!aresults) { + return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY; + } + + for (size_t i = 0; i < privacies_count; ++i) { + switch( responses[i] ) { + case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESPONSE_ALLOW_FOREVER : + aresults[i] = ASKUSER_POPUP_RESULT_ALLOW_FOREVER; + break; + case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESPONSE_DENY_FOREVER : + aresults[i] = ASKUSER_POPUP_RESULT_DENY_FOREVER; + break; + case PRIVACY_PRIVILEGE_MANAGER_POPUP_RESPONSE_DENY_ONCE : + aresults[i] = ASKUSER_POPUP_RESULT_DENY_ONCE; + break; + default: + free(aresults); + return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER; + } + } + + ret = askuser_popup_send_ext_response(ppm_handle->client, popup_id, + privacies, aresults, privacies_count); + + free(aresults); - return PRIVACY_PRIVILEGE_MANAGER_ERROR_UNKNOWN; + return ret != ASKUSER_API_SUCCESS ? ask_user_to_ppm_error(ret) : PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE; } diff --git a/src/capi/test/privacy_privilege_manager_test.cpp b/src/capi/test/privacy_privilege_manager_test.cpp index da16dfe..05a197a 100644 --- a/src/capi/test/privacy_privilege_manager_test.cpp +++ b/src/capi/test/privacy_privilege_manager_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -311,6 +311,13 @@ struct ServerSimulator : public IServerCallbacks { printPrompt(Mode::SERVER); } + virtual void extResponse(int popup_id, std::vector &&privacies, std::vector &&responses) { + // TODO + (void) popup_id; + (void) privacies; + (void) responses; + } + void addRequest(ConnectionFd fd, RequestId id, const Privilege &privilege) { auto &s = m_requests[fd]; diff --git a/src/client/api/ApiInterface.h b/src/client/api/ApiInterface.h index 25cd4f3..8d4c741 100644 --- a/src/client/api/ApiInterface.h +++ b/src/client/api/ApiInterface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -49,6 +49,7 @@ public: virtual RequestId popupRequest(const std::vector &privileges, const askuser_popup_multiple_response_callback callback, void *userData) = 0; + virtual int popupResponseExt(int popup_id, const std::vector &privacies, std::vector &responses) = 0; virtual bool popupRequestInProgress(const std::string &privilege) const = 0; }; diff --git a/src/client/api/askuser-notification-client.cpp b/src/client/api/askuser-notification-client.cpp index 6377128..9f10b45 100644 --- a/src/client/api/askuser-notification-client.cpp +++ b/src/client/api/askuser-notification-client.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -236,3 +236,44 @@ int askuser_client_popup_multiple_request(askuser_client *p_client, const char * }); } + +API +int askuser_popup_send_ext_response(askuser_client *p_client, int popup_id, + const char **privacies, + const askuser_popup_result responses[], + size_t privacies_count) +{ + if (!privacies || !responses || privacies_count < 1) { + return ASKUSER_API_INVALID_PARAM; + } + + return AskUser::Client::tryCatch([&]() { + std::vector vprivacies(privacies_count); + std::vector vresponses(privacies_count); + + for (size_t i = 0; i < privacies_count; ++i) { + switch(responses[i]) { + case ASKUSER_POPUP_RESULT_ALLOW_FOREVER : + vresponses[i] = ASKUSER_ALLOW_FOREVER; + break; + case ASKUSER_POPUP_RESULT_DENY_FOREVER : + vresponses[i] = ASKUSER_DENY_FOREVER; + break; + case ASKUSER_POPUP_RESULT_DENY_ONCE : + vresponses[i] = ASKUSER_DENY_ONCE; + break; + default: + return ASKUSER_API_INVALID_PARAM; + } + vprivacies[i] = privacies[i]; + } + + + int ret = p_client->impl->popupResponseExt(popup_id, vprivacies, vresponses); + + // TODO there is no privilege check on server side now + // TODO we should be able to return ASKUSER_API_PERMISSION_DENIED in case when + // caller doesn't have a privilege (ie. http://tizen.org/privilege/internal/default/platform) + return ret != 0 ? ASKUSER_API_CONNECTION_ERROR : ASKUSER_API_SUCCESS; + }); +} diff --git a/src/client/impl/ApiInterfaceImpl.cpp b/src/client/impl/ApiInterfaceImpl.cpp index cf7d75b..fe59c56 100644 --- a/src/client/impl/ApiInterfaceImpl.cpp +++ b/src/client/impl/ApiInterfaceImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -173,6 +173,11 @@ RequestId ApiInterfaceImpl::popupRequestInternal(const std::vector return conCtx.m_requestId; } +int ApiInterfaceImpl::popupResponseExt(int popup_id, const std::vector &privacies, std::vector &responses) +{ + return m_channel->popupResponseExt(popup_id, privacies, responses); +} + bool ApiInterfaceImpl::popupRequestInProgress(const std::string &privilege) const { auto samePrivilege = [&] (const Request &req) { diff --git a/src/client/impl/ApiInterfaceImpl.h b/src/client/impl/ApiInterfaceImpl.h index d70d80c..2aa8ca5 100644 --- a/src/client/impl/ApiInterfaceImpl.h +++ b/src/client/impl/ApiInterfaceImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -60,6 +60,7 @@ public: virtual RequestId popupRequest(const std::vector &privileges, const askuser_popup_multiple_response_callback callback, void *userData); + virtual int popupResponseExt(int popup_id, const std::vector &privacies, std::vector &responses); virtual bool popupRequestInProgress(const std::string &privilege) const; void updateConnection(Protocol::ConnectionFd fd, int mask); diff --git a/src/client/include/askuser-notification-client.h b/src/client/include/askuser-notification-client.h index 7d1b840..cddce18 100644 --- a/src/client/include/askuser-notification-client.h +++ b/src/client/include/askuser-notification-client.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2017-2020 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. @@ -687,6 +687,28 @@ int askuser_client_popup_multiple_request(askuser_client *p_client, const char * //TODO: add sample code +/** + * \brief Allows external UI popup app to pass per-privacy answers to askuser daemon + * + * \since_tizen 6.0 + * + * \privlevel platform + * + * \param[in] p_client An instance of the askuser_client structure + * previously created by askuser_client_initialize(). + * \param[in] popup_id The ID of the popup assigned by askuser daemon when UI popup app + * was invoked. + * \param[in] privacies The privacies array for which user response has been acquired. + * \param[in] responses The responses array for corresponding privacies. + * \param[in] privacies_count The number of elements in the privacies and results arrays. + * + * \return ASKUSER_API_SUCCESS on success + * \return a negative value in case of an error (see "Status return codes") + */ +int askuser_popup_send_ext_response(askuser_client *p_client, int popup_id, + const char **privacies, + const askuser_popup_result responses[], + size_t privacies_count); #ifdef __cplusplus } diff --git a/src/ipc/client-channel.cpp b/src/ipc/client-channel.cpp index 4b5b4f2..232f43c 100644 --- a/src/ipc/client-channel.cpp +++ b/src/ipc/client-channel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -82,6 +82,35 @@ Protocol::ConnectionContext ClientChannel::popupRequest(const std::vector &privacies, std::vector &responses) +{ + int fd = connect(); + + std::stringstream ss; + + ss << MSGID_EXT_POPUP_RESPONSE << " " << popup_id << " " << privacies.size(); + + for (auto &p : privacies) + ss << " " << base64Encode(p); + + for (auto &r : responses) + ss << " " << r; + + ss << '\n'; + + std::string str = ss.str(); + + ALOGD("popupResponseExt: sending message: " << str); + + std::copy(str.begin(), str.end(), std::back_inserter(m_sockets[fd].output)); + + int ret = process(fd, FdMask::WRITE); + + closeConnection(fd); + + return ret; +} + void ClientChannel::onAccept(int) { } diff --git a/src/ipc/client-channel.h b/src/ipc/client-channel.h index cc63dce..3ec8cba 100644 --- a/src/ipc/client-channel.h +++ b/src/ipc/client-channel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -68,6 +68,7 @@ public: virtual ~ClientChannel(); virtual ConnectionContext popupRequest(const std::vector &privileges); + virtual int popupResponseExt(int popup_id, const std::vector &privacies, std::vector &responses); private: virtual void onAccept(int fd); diff --git a/src/ipc/common-types.h b/src/ipc/common-types.h index aecafec..c147984 100644 --- a/src/ipc/common-types.h +++ b/src/ipc/common-types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -41,6 +41,7 @@ enum FdMask { typedef int ConnectionFd; typedef int RequestId; +typedef int PopupId; typedef std::string Privilege; typedef std::vector PrivilegeVector; @@ -56,6 +57,7 @@ const RequestId INVALID_ID = -1; const int MSGID_POPUP = 1; const int MSGID_TOAST1 = 2; const int MSGID_TOAST2 = 3; +const int MSGID_EXT_POPUP_RESPONSE = 4; const int MSGID_POPUP_RESPONSE = 1; } // namespace Protocol diff --git a/src/ipc/credentials.cpp b/src/ipc/credentials.cpp index 8e1b98b..337bf08 100644 --- a/src/ipc/credentials.cpp +++ b/src/ipc/credentials.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -41,6 +41,18 @@ std::string getUIDFromSocket(int sockFd) return std::to_string(cr.uid); } +pid_t getPIDFromSocket(int sockFd) +{ + struct ucred cr; + socklen_t len = sizeof(cr); + + if (getsockopt(sockFd, SOL_SOCKET, SO_PEERCRED, &cr, &len) == -1) { + throw AskUser::Protocol::CredentialsException("Couldn't fetch credentials from a socket"); + } + + return cr.pid; +} + std::string getSmackLabelFromSocket(int sockFd) { char *label; @@ -61,6 +73,7 @@ namespace Protocol { Credentials::Credentials(int sockFd) : label(getSmackLabelFromSocket(sockFd)) , uid(getUIDFromSocket(sockFd)) +, pid(getPIDFromSocket(sockFd)) { } diff --git a/src/ipc/credentials.h b/src/ipc/credentials.h index cecb0cf..4cb92de 100644 --- a/src/ipc/credentials.h +++ b/src/ipc/credentials.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -32,6 +32,7 @@ struct Credentials { std::string label; std::string uid; + pid_t pid; }; } // namespace Protocol diff --git a/src/ipc/message-utils.h b/src/ipc/message-utils.h index a842433..00aeb32 100644 --- a/src/ipc/message-utils.h +++ b/src/ipc/message-utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -76,6 +76,34 @@ const std::size_t MAX_RESPONSE_STATUS_LEN = maxNumberOfChars(); const std::size_t MIN_PRIVILEGE_ENC_LENGTH = lengthOfEncodedBase64(MIN_PRIVILEGE_LENGTH); const std::size_t MAX_PRIVILEGE_ENC_LENGTH = lengthOfEncodedBase64(MAX_PRIVILEGE_LENGTH); const std::size_t SEP_LEN = 1; // space or \n +const std::size_t MIN_EXT_RESPONSE_POPUP_ID_LEN = 1; +const std::size_t MAX_EXT_RESPONSE_POPUP_ID_LEN = maxNumberOfChars(); + +const std::size_t MIN_EXT_RESPONSE_MESSAGE_LENGHT = MIN_COMMAND_LENGTH + + SEP_LEN + // space + MIN_EXT_RESPONSE_POPUP_ID_LEN + + SEP_LEN + // space + MIN_PRIVS_NUMBER_LENGTH + + MIN_PRIVS_NUMBER * ( + SEP_LEN + // space + MIN_PRIVILEGE_ENC_LENGTH + // assuming privacy can't be longer than privilege + SEP_LEN + // space + MIN_RESPONSE_STATUS_LEN) + // response + SEP_LEN; // new line + +const std::size_t MAX_EXT_RESPONSE_MESSAGE_LENGHT = MAX_COMMAND_LENGTH + + SEP_LEN + // space + MAX_EXT_RESPONSE_POPUP_ID_LEN + + SEP_LEN + // space + MAX_PRIVS_NUMBER_LENGTH + + MAX_PRIVS_NUMBER * ( + SEP_LEN + // space + MAX_PRIVILEGE_ENC_LENGTH) + // assuming privacy can't be longer than privilege + SEP_LEN + // space + MAX_PRIVS_NUMBER * ( + SEP_LEN + // space + MAX_RESPONSE_STATUS_LEN) + + SEP_LEN; // new line const std::size_t MIN_REQUEST_MESSAGE_LENGTH = MIN_COMMAND_LENGTH + SEP_LEN + // space @@ -117,14 +145,18 @@ const std::size_t MAX_RESPONSE_MESSAGE_LENGTH = MAX_COMMAND_LENGTH + MAX_RESPONSE_STATUS_LEN) + SEP_LEN; // new line -const std::size_t MIN_MESSAGE_LENGTH = std::min(MIN_REQUEST_MESSAGE_LENGTH, MIN_RESPONSE_MESSAGE_LENGTH); -const std::size_t MAX_MESSAGE_LENGTH = std::max(MAX_REQUEST_MESSAGE_LENGTH, MAX_RESPONSE_MESSAGE_LENGTH); +const std::size_t MIN_MESSAGE_LENGTH = std::min(MIN_EXT_RESPONSE_MESSAGE_LENGHT,std::min(MIN_REQUEST_MESSAGE_LENGTH, MIN_RESPONSE_MESSAGE_LENGTH)); +const std::size_t MAX_MESSAGE_LENGTH = std::max(MAX_EXT_RESPONSE_MESSAGE_LENGHT,std::max(MAX_REQUEST_MESSAGE_LENGTH, MAX_RESPONSE_MESSAGE_LENGTH)); const unsigned int ASKUSER_MESSAGE_CMD_POS = 0; const unsigned int ASKUSER_MESSAGE_REQUESTID_POS = 1; const unsigned int ASKUSER_MESSAGE_PRIVILEGES_COUNT_POS = 2; const unsigned int ASKUSER_MESSAGE_FIRST_PRIVILEGE_POS = 3; const unsigned int ASKUSER_MESSAGE_MIN_MSG_PARAM_COUNT = 4; //cmd, requestId, privilegeCount, privilege +const unsigned int ASKUSER_MESSAGE_MIN_EXT_RESPONSE_MSG_PARAM_COUNT = 5; //cmd, popup_id, privacyCount, privacy, response +const unsigned int ASKUSER_MESSAGE_EXT_RESPONSE_POPUP_ID_POS = 1; +const unsigned int ASKUSER_MESSAGE_EXT_RESPONSE_PRIV_COUNT_POS = 2; +const unsigned int ASKUSER_MESSAGE_EXT_RESPONSE_FIRST_PRIV_POS = 3; std::string base64Encode(std::string input); std::string base64Decode(std::string input); diff --git a/src/ipc/server-channel.cpp b/src/ipc/server-channel.cpp index 9c83931..e129716 100644 --- a/src/ipc/server-channel.cpp +++ b/src/ipc/server-channel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -125,6 +125,34 @@ int ServerChannel::onReceive(int fd, std::vector &&message) { break; } + case MSGID_EXT_POPUP_RESPONSE: + { + // TODO privilege check with Cynara should be here if we want to add it (ie. http://tizen.org/privilege/internal/default/platform) + // TODO how to return with access denied in this case? + unsigned int privaciesCount; + int popup_id; + if (message.size() < ASKUSER_MESSAGE_MIN_EXT_RESPONSE_MSG_PARAM_COUNT) { + ALOGE("Inappropriate message size for MSGID_EXT_POPUP_RESPONSE command, size: " << message.size()); + return -EINVAL; + } + popup_id = std::stoi(message[ASKUSER_MESSAGE_EXT_RESPONSE_POPUP_ID_POS]); + privaciesCount = std::stoul(message[ASKUSER_MESSAGE_EXT_RESPONSE_PRIV_COUNT_POS]); + if (message.size() != 2 * privaciesCount + ASKUSER_MESSAGE_MIN_EXT_RESPONSE_MSG_PARAM_COUNT - 2) { + ALOGE("Inappropriate message size for MSGID_EXT_POPUP_RESPONSE command, size: " << message.size()); + return -EINVAL; + } + ALOGD("privaciesCount: " << privaciesCount); + std::vector privacies(privaciesCount); + std::vector responses(privaciesCount); + + for (unsigned int i = 0; i < privaciesCount; ++i) { + privacies[i] = base64Decode(message[ASKUSER_MESSAGE_EXT_RESPONSE_FIRST_PRIV_POS + i]); + responses[i] = std::stoi(message[ASKUSER_MESSAGE_EXT_RESPONSE_FIRST_PRIV_POS + privaciesCount + i]); + } + m_callbacks->extResponse(popup_id, std::move(privacies), std::move(responses)); + + break; + } default : ALOGE("Server received unknown message, command: " << command); return -EINVAL; diff --git a/src/ipc/server-channel.h b/src/ipc/server-channel.h index ca0b913..c6e492c 100644 --- a/src/ipc/server-channel.h +++ b/src/ipc/server-channel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -68,6 +68,15 @@ struct IServerCallbacks { * \param[in] privileges Privileges for which permissions are asked for */ virtual void popup(ConnectionFd fd, RequestId id, std::vector &&privileges) = 0; + + /** + * This function is called when external UI app retrived answer and askuser needs to answer to app + * + * \param[in] popup_id the ID (cookie) passed to UI app when requesting popup, identifies application request (its ConnectionFd and RequestId) + * \param[in] privacies the privacies for which the UI app is returning an answer (it can be a list smaller than originally requested) + * \param[in] responses the list of policy responses (Allow/Deny) for each privacy; vector size must be equal to privacies.size() + */ + virtual void extResponse(int popup_id, std::vector &&privacies, std::vector &&responses) = 0; }; typedef std::unique_ptr ServerCallbacksPtr; diff --git a/src/ipc/test/main.cpp b/src/ipc/test/main.cpp index 6f130a0..365acbb 100644 --- a/src/ipc/test/main.cpp +++ b/src/ipc/test/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -62,6 +62,13 @@ struct ServerCallbacks : public IServerCallbacks { } } + virtual void extResponse(int popup_id, std::vector &&privacies, std::vector &&responses) { + // TODO + (void) popup_id; + (void) privacies; + (void) responses; + } + void setChannel(ServerChannel *ptr) { m_channel = ptr; } diff --git a/src/notification-daemon/CMakeLists.txt b/src/notification-daemon/CMakeLists.txt index 77d8df2..83917c6 100644 --- a/src/notification-daemon/CMakeLists.txt +++ b/src/notification-daemon/CMakeLists.txt @@ -13,6 +13,7 @@ PKG_CHECK_MODULES(ASKUSER_NOTIFICATION_DEP capi-ui-efl-util capi-system-info efl-extension + aul ) INCLUDE_DIRECTORIES(SYSTEM @@ -33,6 +34,7 @@ SET(ASKUSER_NOTIFICATION_SOURCES ${NOTIF_PATH}/ServerCallbacks.cpp ${NOTIF_PATH}/ui/Po.cpp ${NOTIF_PATH}/ui/Popupper.cpp + ${NOTIF_PATH}/ui/UIAppInvoker.cpp ) ADD_EXECUTABLE(${TARGET_ASKUSER_NOTIFICATION} ${ASKUSER_NOTIFICATION_SOURCES}) diff --git a/src/notification-daemon/Logic.cpp b/src/notification-daemon/Logic.cpp index c2027ef..8f58f02 100644 --- a/src/notification-daemon/Logic.cpp +++ b/src/notification-daemon/Logic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -34,6 +34,7 @@ #include #include #include +#include #include "PolicyUpdater.h" #include "ServerCallbacks.h" @@ -46,33 +47,6 @@ namespace { int ASKUSER_IDLE_TIMER_SEC = 4; -int uiResponseToClientResponse(NResponseType response) { - int clientResponse; - - switch (response) { - case NResponseType::Deny: - clientResponse = ASKUSER_DENY_ONCE; - break; - case NResponseType::DenyAlways: - clientResponse = ASKUSER_DENY_FOREVER; - break; - case NResponseType::Allow: - case NResponseType::AllowAlways: - clientResponse = ASKUSER_ALLOW_FOREVER; - break; - case NResponseType::None: - clientResponse = ASKUSER_NONE; - break; - case NResponseType::Error: - clientResponse = ASKUSER_UNKNOWN_ERROR; - break; - default: - clientResponse = ASKUSER_UNKNOWN_ERROR; - } - - return clientResponse; -} - std::string clientResponseToPolicy(int clientResponse) { std::string level; @@ -115,7 +89,7 @@ void Logic::addChannelFd(Protocol::ConnectionFd fd, const Protocol::Credentials ALOGD("Proper client connected"); stopTimer(); - ConnectionInfo connInfo{appId, pkgId, creds.uid, isHybrid}; + ConnectionInfo connInfo{appId, pkgId, creds.uid, creds.pid, isHybrid}; m_connToInfo.insert(it, std::make_pair(fd, connInfo)); } catch (const std::exception &e) { ALOGE("Failed to add channel fd " << fd); @@ -187,18 +161,13 @@ Eina_Bool Logic::processChannel(int fd, int mask) { auto queueIt = std::remove_if(m_pendingEvents.begin(), m_pendingEvents.end(), [fd](const FdEvent &fdEvent) {return fdEvent.id.fd == fd;}); m_pendingEvents.erase(queueIt, m_pendingEvents.end()); - - // Ignore error in policy setting, we can't do anything about it nor we can inform user about error - (void)setPolicy(m_connToInfo[fd]); // TODO: now it doesn't set "Ask user" again m_connToInfo.erase(fd); m_fdInfo.erase(fd); m_serverChannel->process(fd, 0); // Handle next event if removed active fd - if (fd == m_currentEvent.fd) { - finishCurrentRequest(); - processEvents(); - } + // TODO remove eventInfo like: m_eventInfo.erase(respEvent.id); + return ECORE_CALLBACK_CANCEL; } case FdChange::CHANGE: @@ -209,7 +178,12 @@ Eina_Bool Logic::processChannel(int fd, int mask) { } } -void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, +Protocol::PopupId Logic::genUniquePopupId() { + static int counter = 0; + return counter++; +} + +void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, Protocol::PopupId popup_id, const std::vector &privacies, const std::vector &privilegesStructure) { EventId eventId{fd, id}; @@ -221,7 +195,8 @@ void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, ConnectionInfo &conn = m_connToInfo[fd]; - FdEvent fdEvent{eventId, std::unique_ptr(new EventPopupCheck(&m_popupper, conn.pkgId, privacies))}; + FdEvent fdEvent{eventId, popup_id, std::shared_ptr(new ExtUIEvent(popup_id, conn.pid, conn.pkgId, privacies))}; + fdEvent.event->process(); m_pendingEvents.emplace_back(std::move(fdEvent)); } @@ -280,11 +255,9 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std:: return; } - // we do have privacies to ask about, we need to generate event + int unique_id = genUniquePopupId(); std::vector privacies(uniquePrivacies.begin(), uniquePrivacies.end()); - addEvent(fd, id, privacies, privilegesStructure); - processEvents(); - + addEvent(fd, id, unique_id, privacies, privilegesStructure); } catch (const std::exception &e) { ALOGE("Failed to handle popup request : " << e.what()); std::vector responses(privileges.size(), ASKUSER_DENY_ONCE); @@ -292,36 +265,132 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std:: } } -Logic::~Logic() +void Logic::extResponse(Protocol::PopupId popup_id, const std::vector &privacies, const std::vector &responses) { - m_serverChannel.reset(); -} + ALOGD("Got response for popup_id : " << popup_id << " for privacies: "); + for (auto &p : privacies) { + ALOGD("---- privacy : " << p); + } -bool Logic::isEventProcessed() { - return m_currentEvent.fd != Protocol::INVALID_FD; -} + FdEvent respEvent; + size_t pendingEventsIndex = 0; + for (FdEvent &ev : m_pendingEvents) { + if (ev.popup_id == popup_id) { + respEvent = ev; + break; + } + ++pendingEventsIndex; + } -void Logic::finishCurrentRequest() { - m_eventInfo.erase(m_currentEvent); - m_popupper.popupClose(); + if (respEvent.popup_id == -1) { + ALOGE("Got response for nonexisting popup_id : " << popup_id); + return; + } - m_currentEvent = EventId(); - if (!m_pendingEvents.empty()) - m_pendingEvents.pop_front(); -} + auto it = m_eventInfo.find(respEvent.id); -void Logic::processEvents() { - // Active event processing - if (isEventProcessed()) + if (it == m_eventInfo.end()) { + ALOGE("Got response from strange event id "); return; + } - // No pending events - if (m_pendingEvents.empty()) + EventInfo &eventInfo = it->second; + + auto itc = m_connToInfo.find(respEvent.id.fd); + + if (itc == m_connToInfo.end()) { + ALOGE("Got response from inactive fd " << respEvent.id.fd); return; + } - FdEvent &fdEvent = m_pendingEvents.front(); - m_currentEvent = fdEvent.id; - fdEvent.event->process(); + ConnectionInfo &conn = itc->second; + + try { + if (privacies.size() != responses.size()) { + ALOGE("Got improper answer from UI app, privacies size doesn't match responses size (" + << privacies.size() << " vs. "<< responses.size() << "); popup_id: " << popup_id); + throw Exception("Got improper answer from UI app"); + } + + std::map received; + unsigned int i = 0; + for (auto p : privacies) { + received[p] = responses[i++]; + + if (received[p] != ASKUSER_DENY_ONCE && + received[p] != ASKUSER_DENY_FOREVER && + received[p] != ASKUSER_ALLOW_FOREVER) { + ALOGE("Got improper answer from UI app, answers are improper for privacy: " << p << " answer: " << received[p]); + throw Exception("Got improper answer from UI app"); + } + } + + // fill missing responses (some privacies may have not received any answer) + // also, calculate final policy levels + std::map finalPrivacyResponses; + std::vector levels(eventInfo.uniquePrivacies.size()); + i = 0; + + for (auto p : eventInfo.uniquePrivacies) { + finalPrivacyResponses[p] = (received.find(p) == received.end()) ? ASKUSER_UNKNOWN_ERROR : received[p]; + levels[i] = clientResponseToPolicy(finalPrivacyResponses[p]); + ++i; + } + + // set policy + ALOGD("Setting policy for app " << conn.appId); + + if (!PolicyUpdater::update(conn.pkgId, conn.appId, conn.isHybrid, eventInfo.uniquePrivacies, levels)) { + ALOGE("Couldn't set policy for " << conn.appId); + throw Exception("Couldn't set policy"); + } + + std::vector privResponses(eventInfo.privilegesStructure.size(), ASKUSER_UNKNOWN_ERROR); + + for (i = 0; i < privResponses.size(); ++i) { + const auto &privilegeStruct = eventInfo.privilegesStructure[i]; + const auto &policy = privilegeStruct.policy; + if (policy == "Allow") { + privResponses[i] = ASKUSER_ALLOW_FOREVER; + } else if (policy == "Deny") { + privResponses[i] = ASKUSER_DENY_FOREVER; + } else if (policy != "Ask user") { + privResponses[i] = ASKUSER_DENY_ONCE; + } else { + // Ask user policy - need to calcualte from existing responses to privacies + // but only privacies askable for this privilege should be used! + privResponses[i] = ASKUSER_ALLOW_FOREVER; + for (auto &privacy : privilegeStruct.askablePrivacies) { + const auto &privResponseIt = finalPrivacyResponses.find(privacy); + if (privResponseIt != finalPrivacyResponses.end()) { + privResponses[i] = std::min(privResponseIt->second, privResponses[i]); + } + else { + ALOGE("Unable to response for askable privacy: " << privacy); + privResponses[i] = ASKUSER_DENY_ONCE; + break; + } + } + } + } + + // answer to application + m_serverChannel->popupResponses(respEvent.id.fd, respEvent.id.id, std::move(privResponses)); + + // remove event & info information + m_eventInfo.erase(respEvent.id); + m_pendingEvents.erase(m_pendingEvents.begin() + pendingEventsIndex); + + } catch(const std::exception &e) { + ALOGE("Failed to handle popup request : " << e.what()); + std::vector responses(eventInfo.privilegesStructure.size(), ASKUSER_DENY_ONCE); + m_serverChannel->popupResponses(respEvent.id.fd, respEvent.id.id, std::move(responses)); + } +} + +Logic::~Logic() +{ + m_serverChannel.reset(); } void Logic::registerSignalFd() { @@ -345,11 +414,6 @@ void Logic::registerSignalFd() { } void Logic::stop() { - if (isEventProcessed()) { - ConnectionInfo &conn = m_connToInfo[m_currentEvent.fd]; - processResponse(conn); // TODO used to be ASKUSER_DENY_ONCE, "Ask user" - finishCurrentRequest(); - } m_popupper.stop(); } @@ -401,7 +465,6 @@ void Logic::init() { init_agent_log(); m_popupper.initialize(); Po::setLocale(); - m_popupper.registerPopupResponseHandler([&](std::vector responses) { popupResponses(responses);}); registerSignalFd(); @@ -409,94 +472,8 @@ void Logic::init() { } void Logic::run() { - // TODO ensure we won't throw inside ecore loop - m_popupper.start(); - m_popupper.shutdown(); -} - -bool Logic::setPolicy(const ConnectionInfo &conn) { - ALOGD("Setting policy for app " << conn.appId); - auto ¤tEvent = m_eventInfo[m_currentEvent]; - std::vector levels(currentEvent.uniquePrivacies.size()); - - for (size_t i = 0; i < levels.size(); ++i) { - const auto &privacy = currentEvent.uniquePrivacies[i]; - levels[i] = clientResponseToPolicy(currentEvent.privacyResponses[privacy]); - } - - if (!PolicyUpdater::update(conn.pkgId, conn.appId, conn.isHybrid, currentEvent.uniquePrivacies, levels)) { - ALOGE("Couldn't set policy for " << conn.appId); - return false; - } - - return true; -} - -void Logic::processResponse(const ConnectionInfo &conn) { - auto ¤tEvent = m_eventInfo[m_currentEvent]; - std::vector responses(currentEvent.privilegesStructure.size(), ASKUSER_UNKNOWN_ERROR); - - if (setPolicy(conn)) { - for (size_t i = 0; i < responses.size(); ++i) { - const auto &privilegeStruct = currentEvent.privilegesStructure[i]; - const auto &policy = privilegeStruct.policy; - if (policy == "Allow") { - responses[i] = ASKUSER_ALLOW_FOREVER; - } else if (policy == "Deny") { - responses[i] = ASKUSER_DENY_FOREVER; - } else if (policy != "Ask user") { - responses[i] = ASKUSER_DENY_ONCE; - } else { - // Ask user policy - need to calcualte from existing responses to privacies - // but only privacies askable for this privilege should be used! - responses[i] = ASKUSER_ALLOW_FOREVER; - for (auto &privacy : privilegeStruct.askablePrivacies) { - const auto &privResponseIt = currentEvent.privacyResponses.find(privacy); - if (privResponseIt != currentEvent.privacyResponses.end()) { - responses[i] = std::min(privResponseIt->second, responses[i]); - } - else { - ALOGE("Unable to response for askable privacy: " << privacy); - responses[i] = ASKUSER_DENY_ONCE; - break; - } - } - } - } - } - m_serverChannel->popupResponses(m_currentEvent.fd, m_currentEvent.id, std::move(responses)); -} - -void Logic::popupResponses(const std::vector &responses) { - auto it = m_connToInfo.find(m_currentEvent.fd); - - if (it == m_connToInfo.end()) { - ALOGE("Got response from inactive fd " << m_currentEvent.fd); - return; - } - - ConnectionInfo &conn = it->second; - auto ¤tEvent = m_eventInfo[m_currentEvent]; - - if (responses.size() != currentEvent.uniquePrivacies.size()) { - ALOGE("Got invalid number of responses: " << responses.size() << " but expected: " - << currentEvent.uniquePrivacies.size()); - finishCurrentRequest(); - processEvents(); - return; - } - - for (size_t i = 0; i < responses.size(); ++i) { - int clientResponse = uiResponseToClientResponse(responses[i]); - const auto &privacy = currentEvent.uniquePrivacies[i]; - ALOGD("Client response for privacy " << privacy << " is " << clientResponse); - currentEvent.privacyResponses[privacy] = clientResponse; - } - - // No more privacies, since all are answered by one popup - request is ready for response - processResponse(conn); - finishCurrentRequest(); - processEvents(); + m_popupper.start(); + m_popupper.shutdown(); } } // namespace Notification diff --git a/src/notification-daemon/Logic.h b/src/notification-daemon/Logic.h index dd7243f..01bf193 100644 --- a/src/notification-daemon/Logic.h +++ b/src/notification-daemon/Logic.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -17,7 +17,7 @@ * @file src/agent/notification-daemon/Service.h * @author Zofia Abramowska * @author Tomasz Swierczek - * @brief Declaration of Popupper class + * @brief Declaration of Logic class */ #pragma once @@ -45,7 +45,7 @@ public: private: std::string m_msg; }; - Logic() : m_currentEvent{-1, -1}, m_timer(nullptr) {} + Logic() : m_timer(nullptr) {} void init(); void run(); void stop(); @@ -56,6 +56,8 @@ public: void popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::vector &privileges); + void extResponse(int popup_id, const std::vector &privacies, const std::vector &responses); + ~Logic(); private: struct EventId { @@ -73,6 +75,7 @@ private: std::string appId; std::string pkgId; std::string user; + pid_t pid; bool isHybrid; }; @@ -82,6 +85,9 @@ private: std::vector askablePrivacies; }; + //Generate popup ID (cookie) for external UI app + Protocol::PopupId genUniquePopupId(); + //Initialization void registerSignalFd(); void prepareChannel(); @@ -93,34 +99,47 @@ private: static Eina_Bool timerHandler(void *data); //static Eina_Bool signalHandler(void *data, int type, void *event); - void addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, + void addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, Protocol::PopupId popup_id, const std::vector &privacies, const std::vector &privilegesStructure); Eina_Bool processChannel(int fd, int mask); bool identifyClient(const std::string &label, std::string &appId, std::string &pkgId); - void processEvents(); - void processResponse(const ConnectionInfo &conn); - bool isEventProcessed(); - void finishCurrentRequest(); - void startTimer(); void stopTimer(); - void popupResponses(const std::vector &response); - bool processError(EventId id, int error); - bool setPolicy(const ConnectionInfo &conn); std::unique_ptr m_serverChannel; Popupper m_popupper; struct FdEvent { EventId id; - std::unique_ptr event; + Protocol::PopupId popup_id; + std::shared_ptr event; + FdEvent(): + id{-1, -1}, + popup_id (-1) + {} + FdEvent(EventId an_id, Protocol::PopupId an_popup_id, std::shared_ptr an_event): + id(an_id.fd, an_id.id), + popup_id(an_popup_id), + event(an_event) + {} + FdEvent(const FdEvent &other): + id(other.id.fd, other.id.id), + popup_id(other.popup_id), + event(other.event) + {} + FdEvent& operator=(const FdEvent &other) { + id.fd = other.id.fd; + id.id = other.id.id; + popup_id = other.popup_id; + event = other.event; + return *this; + } }; - EventId m_currentEvent; std::deque m_pendingEvents; enum class FdChange { diff --git a/src/notification-daemon/PolicyUpdater.cpp b/src/notification-daemon/PolicyUpdater.cpp index 068c17f..28aa76f 100644 --- a/src/notification-daemon/PolicyUpdater.cpp +++ b/src/notification-daemon/PolicyUpdater.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016-2020 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. @@ -108,6 +108,6 @@ bool PolicyUpdater::update(const std::string &pkgId, const std::string &appId, b return false; } -} // namespace Agent +} // namespace Notification } // namespace AskUser diff --git a/src/notification-daemon/PolicyUpdater.h b/src/notification-daemon/PolicyUpdater.h index 15815fe..cc3d8ed 100644 --- a/src/notification-daemon/PolicyUpdater.h +++ b/src/notification-daemon/PolicyUpdater.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016-2020 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. @@ -35,6 +35,6 @@ namespace PolicyUpdater { const std::vector &levels); }; -} // namespace Agent +} // namespace Notification } // namespace AskUser diff --git a/src/notification-daemon/ServerCallbacks.cpp b/src/notification-daemon/ServerCallbacks.cpp index dece9b2..555ab57 100644 --- a/src/notification-daemon/ServerCallbacks.cpp +++ b/src/notification-daemon/ServerCallbacks.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -53,5 +53,9 @@ void ServerCallbacks::popup(ConnectionFd fd, RequestId id, std::vectorpopup(fd, id, privileges); } +void ServerCallbacks::extResponse(int popup_id, std::vector &&privacies, std::vector &&responses) { + m_service->extResponse(popup_id, privacies, responses); +} + } /* namespace Notification */ } /* namespace Askuser */ diff --git a/src/notification-daemon/ServerCallbacks.h b/src/notification-daemon/ServerCallbacks.h index d8f1c27..ed4d6bb 100644 --- a/src/notification-daemon/ServerCallbacks.h +++ b/src/notification-daemon/ServerCallbacks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -40,8 +40,9 @@ public: virtual void newConnection(ConnectionFd fd, const Credentials &creds); virtual void updateConnection(ConnectionFd fd, int mask); virtual void popup(ConnectionFd fd, RequestId id, std::vector &&privileges); + virtual void extResponse(int popup_id, std::vector &&privacies, std::vector &&responses); - virtual ~ServerCallbacks() {} + virtual ~ServerCallbacks() {}; private: AskUser::Notification::Logic *m_service; }; diff --git a/src/notification-daemon/event/Event.h b/src/notification-daemon/event/Event.h index f0dbff0..79003e8 100644 --- a/src/notification-daemon/event/Event.h +++ b/src/notification-daemon/event/Event.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2018 Samsung Electronics Co. + * Copyright (c) 2017-2020 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. @@ -25,7 +25,9 @@ #include #include +#include #include +#include namespace AskUser { namespace Notification { @@ -39,6 +41,25 @@ protected: Popupper *m_popupper; }; +class ExtUIEvent : public IUIEvent { +public: + ExtUIEvent(int popup_id, pid_t caller_app_pid, std::string pkg_id, std::vector privacies) + : IUIEvent(NULL), + m_popup_id(popup_id), + m_caller_app_pid(caller_app_pid), + m_pkg_id(pkg_id), + m_privacies(privacies) + {} + virtual void process() { + (void)UIAppInvoker::invoke(m_popup_id, m_caller_app_pid, m_pkg_id, m_privacies); + } +private: + int m_popup_id; + pid_t m_caller_app_pid; + std::string m_pkg_id; + std::vector m_privacies; +}; + class EventPopupCheck : public IUIEvent { public: EventPopupCheck(Popupper *popupper, const std::string &pkgId, const std::vector &privacies) @@ -46,7 +67,8 @@ public: {} virtual void process() { - m_popupper->popupCheck(m_pkgId, m_privacies); + // TODO we don't want askuser popups now, just the external app UI + // m_popupper->popupCheck(m_pkgId, m_privacies); } private: std::string m_pkgId; diff --git a/src/notification-daemon/ui/UIAppInvoker.cpp b/src/notification-daemon/ui/UIAppInvoker.cpp new file mode 100644 index 0000000..b545d1f --- /dev/null +++ b/src/notification-daemon/ui/UIAppInvoker.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2020 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. + */ +/** + * @file UIAppInvoker.cpp + * @author Tomasz Swierczek + * @brief This file implements API used to call external UI app for popup using AUL bundle API + */ +#include "UIAppInvoker.h" + +#include + +#include +#include + +#define PID_BUFFER_SIZE 64 + +namespace AskUser { + +namespace Notification { + +bool UIAppInvoker::invoke(int popup_id, pid_t caller_app_pid, const std::string &pkg_id, const std::vector &privacies) { + ALOGD("Launching popup app for popup_id: " << popup_id << ", pkg_id of requestor app: " << pkg_id); + + char buf[PID_BUFFER_SIZE]; + bundle *b = NULL; + char** privacies_c = NULL; + int ret = -1; + size_t i = 0; + + b = bundle_create(); + + if (!b) { + ALOGE("Cannot allocate memory for bundle creation"); + return false; + } + + /* Sets the caller process ID - TODO: should it be the applications PID like it is now? */ + snprintf(buf, sizeof(buf), "%d", caller_app_pid); + ret = bundle_add_str(b, AUL_K_CALLER_PID, buf); + if (ret < 0) { + ALOGE("bundle_add_str() failed. ret = " << ret); + goto error_exit; + } + + /* Sets the caller user ID - askuser notification works in user domain, has same UID as the apps have */ + snprintf(buf, sizeof(buf), "%u", getuid()); + ret = bundle_add_str(b, AUL_K_CALLER_UID, buf); + if (ret < 0) { + ALOGE("bundle_add_str() failed. ret = " << ret); + goto error_exit; + } + + /* Sets caller appid, assuming here we need pkg id */ + snprintf(buf, sizeof(buf), "%s", pkg_id.c_str()); + ret = bundle_add_str(b, AUL_K_CALLER_APPID, buf); + if (ret < 0) { + ALOGE("bundle_add_str() failed. ret = " << ret); + goto error_exit; + } + + /* Sets privacies to show */ + privacies_c = new char*[privacies.size()]; + if (!privacies_c) { + ALOGE("Cannot allocate memory for bundle creation"); + ret = -1; + goto error_exit; + } + + memset(privacies_c, 0, privacies.size()); + + for (auto p : privacies) { + if (!(privacies_c[i] = new char[p.size() + 1])){ + ALOGE("Cannot allocate memory for bundle creation"); + ret = -1; + goto error_exit; + } + strcpy(privacies_c[i], p.c_str()); + ++i; + } + + ret = bundle_add_str_array(b, "privacy_list", const_cast(privacies_c), privacies.size()); + if (ret < 0) { + ALOGE("bundle_add_str_array() failed. ret = " << ret); + goto error_exit; + } + + /* Add popup_id - here its int, but it can be arbitrary buffer */ + ret = bundle_add_byte(b, "popup_id", &popup_id, sizeof(popup_id)); + if (ret < 0) { + ALOGE("bundle_add_byte() failed. ret = " << ret); + goto error_exit; + } + + /* Sets App Group Launch Mode */ + ret = aul_svc_set_launch_mode(b, "group"); + if (ret < 0) { + ALOGE("aul_svc_set_launch_mode() failed. ret = " << ret); + goto error_exit; + } + + /* Set Popup UI style */ + ret = aul_svc_add_data(b, "launch_type", "single"); + if (ret < 0) { + ALOGE("aul_svc_add_data() failed. ret = " << ret); + goto error_exit; + } + /* Launch askuser-popup */ + ret = aul_forward_app("org.tizen.askuser-popup", b); + if (ret < 0) + ALOGE("aul_forward_app() failed. ret = " << ret); + else + ALOGD("Launched app pid " << ret); + +error_exit: + bundle_free(b); + if (privacies_c) + for (i = 0; i < privacies.size(); ++i) + delete [] privacies_c[i]; + delete [] privacies_c; + + return ret >= 0; +} + +} // namespace Notification + +} // namespace AskUser diff --git a/src/notification-daemon/ui/UIAppInvoker.h b/src/notification-daemon/ui/UIAppInvoker.h new file mode 100644 index 0000000..ba83eaa --- /dev/null +++ b/src/notification-daemon/ui/UIAppInvoker.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 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. + */ +/** + * @file UIAppInvoker.h + * @author Tomasz Swierczek + * @brief This file defines API used to call external UI app for popup + */ + +#pragma once + +#include +#include +#include +#include + +namespace AskUser { + +namespace Notification { + +namespace UIAppInvoker { + bool invoke(int popup_id, pid_t caller_app_pid, const std::string &pkg_id, const std::vector &privacies); +} // UIAppInvoker + +} // namespace Notification + +} // namespace AskUser -- 2.7.4