From: Zofia Abramowska Date: Mon, 3 Apr 2017 17:51:22 +0000 (+0200) Subject: Implement logic X-Git-Tag: submit/tizen/20170405.143506~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=823792d66cf52727b75ffdc271c2d0a79ab535a8;p=platform%2Fcore%2Fsecurity%2Faskuser.git Implement logic Implement whole logic of new askuser-notification. Change-Id: I9d8f2df3530c1607020ee058028617e3c6f92800 --- diff --git a/src/agent/notification-daemon/CMakeLists.txt b/src/agent/notification-daemon/CMakeLists.txt index 83b671f..30ce27b 100644 --- a/src/agent/notification-daemon/CMakeLists.txt +++ b/src/agent/notification-daemon/CMakeLists.txt @@ -25,12 +25,14 @@ INCLUDE_DIRECTORIES( ${ASKUSER_PATH} ${ASKUSER_PATH}/common ${ASKUSER_PATH}/common/protocol + ${ASKUSER_PATH}/agent/notification-daemon ) SET(ASKUSER_NOTIFICATION_SOURCES ${NOTIF_PATH}/main.cpp ${NOTIF_PATH}/GuiRunner.cpp ${NOTIF_PATH}/AskUserTalker.cpp + ${NOTIF_PATH}/Logic.cpp ${NOTIF_PATH}/ServerCallbacks.cpp ${NOTIF_PATH}/ui/Po.cpp ${ASKUSER_PATH}/common/log/alog.cpp diff --git a/src/agent/notification-daemon/Logic.cpp b/src/agent/notification-daemon/Logic.cpp new file mode 100644 index 0000000..272201e --- /dev/null +++ b/src/agent/notification-daemon/Logic.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co. + * + * 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 src/agent/notification-daemon/Service.cpp + * @author Zofia Abramowska + * @brief Declaration of Popupper class + */ + +#include "Logic.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ServerCallbacks.h" + +namespace AskUser { + +namespace Notification { + +void Logic::addChannelFd(int fd, Ecore_Fd_Handler_Flags flags) { + auto it = m_fdInfo.find(fd); + if (it != m_fdInfo.end()) { + m_fdInfo[fd].status = FdChange::CHANGE; + ecore_main_fd_handler_del(m_fdInfo[fd].handler); + } + + auto handler = ecore_main_fd_handler_add(fd, flags, &Logic::clientChHandler, this, nullptr, nullptr); + if (handler == nullptr) { + ALOGE("Couldn't set fd handler"); + return; + } + m_fdInfo[fd].handler = handler; + m_fdInfo[fd].status = FdChange::NONE; +} + +void Logic::removeChannelFd(int fd) { + auto it = m_fdInfo.find(fd); + if (it == m_fdInfo.end()) { + return; + } + it->second.status = FdChange::DEL; + ecore_main_fd_handler_del(it->second.handler); +} + +Eina_Bool Logic::clientChHandler(void *data, Ecore_Fd_Handler *handler) { + Logic *service = static_cast(data); + int fd = ecore_main_fd_handler_fd_get(handler); + if (fd == -1) { + ALOGE("Failed to fetch fd from handler"); + return ECORE_CALLBACK_CANCEL; + } + int mask = 0; + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) { + mask = AskUser::Protocol::READ; + } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE)) { + mask = AskUser::Protocol::WRITE; + } + return service->processChannel(fd, mask); +} + +Eina_Bool Logic::processChannel(int fd, int mask) { + m_fdInfo[fd].status = FdChange::NONE; + updateChannel(fd, mask); + + switch (m_fdInfo[fd].status) { + case FdChange::NONE: + return ECORE_CALLBACK_RENEW; + case FdChange::DEL: { + // Remove all pending events from this fd + auto queueIt = std::remove_if(m_pendingEvents.begin(), m_pendingEvents.end(), [fd](const FdEvent &fdEvent) {return fdEvent.fd == fd;}); + m_pendingEvents.erase(queueIt, m_pendingEvents.end()); + + // Handle next event if removed active fd + if (fd == m_currentFd) { + finishCurrentEvent(); + processEvents(); + } + m_fdInfo.erase(fd); + return ECORE_CALLBACK_CANCEL; + } + case FdChange::CHANGE: + return ECORE_CALLBACK_CANCEL; + default: + ALOGE("Unexpected fd change value : " << static_cast(m_fdInfo[fd].status)); + return ECORE_CALLBACK_CANCEL; + } +} + +void Logic::addEvent(IUIEvent *event) { + FdEvent fdEvent{m_currentFd, std::unique_ptr(event)}; + m_pendingEvents.emplace_back(std::move(fdEvent)); + processEvents(); +} + +bool Logic::isEventProcessed() { + return m_currentEventId != -1; +} + +void Logic::finishCurrentEvent() { + m_popupper.popupClose(m_currentEventId); + m_currentEventId = -1; + m_currentFd = -1; +} + +void Logic::processEvents() { + // Active event processing + if (isEventProcessed()) + return; + + // No pending events + if (m_pendingEvents.empty()) + return; + + FdEvent fdEvent = std::move(m_pendingEvents.front()); + m_currentFd = fdEvent.fd; + m_currentEventId = fdEvent.event->getId(); + m_pendingEvents.pop_front(); + + fdEvent.event->process(); +} + +void Logic::registerSignalFd() { + // TODO use ecore event EXIT? + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + + if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) { + throw ErrnoException("Couldn't set signal mask"); + } + + int signalFd = signalfd(-1, &mask, 0); + if (signalFd < 0) { + throw ErrnoException("Couldn't create signalfd"); + } + auto handler = ecore_main_fd_handler_add(signalFd, ECORE_FD_READ, &Logic::signalHandler, this, nullptr, nullptr); + if (handler == nullptr) { + throw Exception("Couldn't set fd handler"); + } +} + +void Logic::stop() { + if (isEventProcessed()) + finishCurrentEvent(); + m_popupper.stop(); +} + +Eina_Bool Logic::signalHandler(void *data, Ecore_Fd_Handler *) { + Logic *logic = static_cast(data); + logic->stop(); + return ECORE_CALLBACK_CANCEL; +} + +void Logic::prepareChannel() { + m_clientChannel = AskUser::Protocol::createChannel( + std::unique_ptr(new AskUser::Protocol::ServerCallbacks(this, &m_popupper))); +} + +void Logic::updateChannel(int fd, int mask) { + // TODO errors? + m_clientChannel->process(fd, mask); +} + +void Logic::init() { + init_agent_log(); + m_popupper.setLocale(); + m_popupper.initialize(); + m_popupper.registerPopupResponseHandler([&](int popupId, NResponseType response) { popupResponse(popupId, response);}); + m_popupper.registerToastFinishedHandler([&](int toastId) {toastFinished(toastId);}); + + registerSignalFd(); + + prepareChannel(); +} + +void Logic::run() { + // TODO ensure we won't throw inside ecore loop + m_popupper.start(); + m_popupper.shutdown(); +} + +void Logic::popupResponse(int popupId, NResponseType response) { + if (popupId != m_currentEventId) { + ALOGD("Got different popup id than is being processed"); + return; + } + int clientResponse; + // TODO translate ui response to policy result + switch (response) { + case NResponseType::Deny: + clientResponse = 0; + break; + case NResponseType::DenyAlways: + clientResponse = 1; + break; + case NResponseType::Allow: + clientResponse = 2; + break; + case NResponseType::AllowAlways: + clientResponse = 3; + break; + case NResponseType::None: + clientResponse = 0; + break; + case NResponseType::Error: + clientResponse = -255; + break; + default: + clientResponse = -255; // error + } + m_clientChannel->popupResponse(popupId, clientResponse); + finishCurrentEvent(); + processEvents(); +} + +void Logic::toastFinished(int toastId) { + if (toastId != m_currentEventId) { + ALOGD("Got different toast id than is being processed"); + return; + } + finishCurrentEvent(); + processEvents(); +} + +} // namespace Notification + +} // namepsace AskUser diff --git a/src/agent/notification-daemon/Logic.h b/src/agent/notification-daemon/Logic.h new file mode 100644 index 0000000..95fe8bc --- /dev/null +++ b/src/agent/notification-daemon/Logic.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co. + * + * 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 src/agent/notification-daemon/Service.h + * @author Zofia Abramowska + * @brief Declaration of Popupper class + */ + +#pragma once + +#include +#include +#include +#include + +namespace AskUser { + +namespace Notification { + +class Logic { +public: + class Exception : public std::exception { + public: + Exception(std::string &&s) : m_msg(std::move(s)) {} + const char *what() const throw () { + return m_msg.c_str(); + } + private: + std::string m_msg; + }; + Logic() : m_currentFd(-1), m_currentEventId(-1), m_isFdDeleted(false) {} + void init(); + void run(); + void stop(); + + void addChannelFd(int fd, Ecore_Fd_Handler_Flags flags); + void removeChannelFd(int fd); + + void addEvent(IUIEvent *event); + + ~Logic() {} +private: + //Initialization + void registerSignalFd(); + void prepareChannel(); + void updateChannel(int fd, int mask); + + // Descriptor handlers + static Eina_Bool clientChHandler(void *data, Ecore_Fd_Handler *handler); + static Eina_Bool signalHandler(void *data, Ecore_Fd_Handler *handler); + //static Eina_Bool signalHandler(void *data, int type, void *event); + + Eina_Bool processChannel(int fd, int mask); + void processEvents(); + bool isEventProcessed(); + void finishCurrentEvent(); + void popupResponse(int popupId, NResponseType response); + void toastFinished(int toastId); + + AskUser::Protocol::ChannelPtr m_clientChannel; + Popupper m_popupper; + + struct FdEvent { + int fd; + std::unique_ptr event; + }; + + // Workaround for no information about to which fd event belongs to + int m_currentFd; + int m_currentEventId; + int m_isFdDeleted; + std::deque m_pendingEvents; + + enum class FdChange { + NONE, + ADD, + CHANGE, + DEL + }; + struct FdInfo { + Ecore_Fd_Handler* handler; + FdChange status; + }; + + std::map m_fdInfo; +}; + +} // namespace Notification + +} // namespace AskUser