From 8756a58db5971eec1864c27da179966aa8050b76 Mon Sep 17 00:00:00 2001 From: Kyungwook Tak Date: Thu, 29 Dec 2016 19:44:13 +0900 Subject: Handle symbolic links in app directory App directory hierarchy is changed. Non global apps have symbolic link which points under TZ_SYS_RW_APPS(/opt/usr/globalapps/...) because non global app's binary and resources are duplicated if such app installed by multiple users. So FsVisitor traverses through symlink either only in app directory which is defined in AppDir class in regular expression. Change-Id: I3049fcb92258fc8d8b4123d74856a4d584ebcdfe Signed-off-by: Kyungwook Tak --- src/framework/service/file-system.cpp | 97 +++++++++++++++---------- src/framework/service/file-system.h | 2 + test/engine/content-screening/sample-engine.cpp | 24 ++++-- 3 files changed, 79 insertions(+), 44 deletions(-) diff --git a/src/framework/service/file-system.cpp b/src/framework/service/file-system.cpp index 2422a4d..8458052 100644 --- a/src/framework/service/file-system.cpp +++ b/src/framework/service/file-system.cpp @@ -301,54 +301,73 @@ void FsVisitor::run(const DirPtr &dirptr, const FilePtr ¤tdir) auto fullpath = (parent_dirpath.back() == '/') ? (parent_dirpath + name) : (parent_dirpath + "/" + name); - if (result->d_type == DT_DIR) { + INFO("start to traverse file: " << fullpath); + + if (result->d_type == DT_LNK) { + if (!currentdir->isInApp()) + continue; + + auto stat = getStat(fullpath); + if (S_ISREG(stat->st_mode)) + this->visitFile(fullpath, currentdir); + else if (S_ISDIR(stat->st_mode)) + this->visitDir(fullpath, currentdir); + + } else if (result->d_type == DT_DIR) { if ((name_size == 1 && name[0] == '.') || (name_size == 2 && name[0] == '.' && name[1] == '.')) continue; - FilePtr ncurrentdir; - try { - ncurrentdir = File::create(fullpath, currentdir); - } catch (const Exception &e) { - if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) { - WARN("Perm denied to create file on pkg path: " << fullpath); - continue; - } else { - throw; - } - } - - if (this->m_isBasedOnName && ncurrentdir->isInApp()) { - this->m_targetHandler(ncurrentdir); - } else { - auto ndirptr = openDir(fullpath); - if (ndirptr == nullptr) { - WARN("Failed to open dir: " << fullpath << " with errno: " << errno); - continue; - } - - DEBUG("recurse dir : " << fullpath); - this->run(ndirptr, ncurrentdir); - } + this->visitDir(fullpath, currentdir); } else if (result->d_type == DT_REG) { - try { - auto fileptr = File::createIfModified(fullpath, currentdir, this->m_since); - - if (fileptr) - this->m_targetHandler(fileptr); - } catch (const Exception &e) { - if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) - WARN("file not exist: " << fullpath << " msg: " << e.what()); - else if (e.error() == CSR_ERROR_FILE_SYSTEM) - WARN("file type is not regular...? can it be happened?" - " :" << fullpath << " msg: " << e.what()); - else - throw; - } + this->visitFile(fullpath, currentdir); } } } +void FsVisitor::visitDir(const std::string &fullpath, const FilePtr ¤tdir) +{ + FilePtr ncurrentdir; + + try { + ncurrentdir = File::create(fullpath, currentdir); + } catch (const Exception &e) { + if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) { + WARN("Perm denied to create file on pkg path: " << fullpath); + return; + } else { + throw; + } + } + + if (this->m_isBasedOnName && ncurrentdir->isInApp()) { + this->m_targetHandler(ncurrentdir); + } else { + if (auto ndirptr = openDir(fullpath)) { + DEBUG("recurse dir: " << fullpath); + this->run(ndirptr, ncurrentdir); + } else { + WARN("Failed to open dir: " << fullpath << " with errno: " << errno); + } + } +} + +void FsVisitor::visitFile(const std::string &fullpath, const FilePtr ¤tdir) +{ + try { + if (auto fileptr = File::createIfModified(fullpath, currentdir, this->m_since)) + this->m_targetHandler(fileptr); + } catch (const Exception &e) { + if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST) + WARN("file not exist: " << fullpath << " msg: " << e.what()); + else if (e.error() == CSR_ERROR_FILE_SYSTEM) + WARN("file type is not regular...? can it be happened?" + " :" << fullpath << " msg: " << e.what()); + else + throw; + } +} + void FsVisitor::run() { auto currentdir = File::create(this->m_path, nullptr); diff --git a/src/framework/service/file-system.h b/src/framework/service/file-system.h index ee73279..7166c47 100644 --- a/src/framework/service/file-system.h +++ b/src/framework/service/file-system.h @@ -170,6 +170,8 @@ private: using DirPtr = std::unique_ptr; void run(const DirPtr &dirptr, const FilePtr ¤tdir); + void visitDir(const std::string &fullpath, const FilePtr ¤tdir); + void visitFile(const std::string &fullpath, const FilePtr ¤tdir); static DirPtr openDir(const std::string &); diff --git a/test/engine/content-screening/sample-engine.cpp b/test/engine/content-screening/sample-engine.cpp index 34afff7..29634e8 100644 --- a/test/engine/content-screening/sample-engine.cpp +++ b/test/engine/content-screening/sample-engine.cpp @@ -477,14 +477,28 @@ int csre_cs_scan_app_on_cloud(csre_cs_context_h handle, int ret = CSRE_ERROR_NONE; - if (result->d_type & (DT_REG | DT_LNK)) + if (result->d_type == DT_LNK) { + // when the file type is link, check the real file's type(dir or reg file) + // and go ahead to traverse + struct stat s; + if (stat(fullpath.c_str(), &s) != 0) + continue; // failed to get stat + + if (S_ISREG(s.st_mode)) + ret = csre_cs_scan_file(handle, fullpath.c_str(), &detected); + else if (S_ISDIR(s.st_mode)) + ret = csre_cs_scan_app_on_cloud(handle, fullpath.c_str(), &detected); + else + continue; + } else if (result->d_type == DT_REG) { ret = csre_cs_scan_file(handle, fullpath.c_str(), &detected); - else if ((result->d_type & DT_DIR) - && filename.compare("..") != 0 - && filename.compare(".") != 0) + } else if ((result->d_type & DT_DIR) && + filename.compare("..") != 0 && + filename.compare(".") != 0) { ret = csre_cs_scan_app_on_cloud(handle, fullpath.c_str(), &detected); - else + } else { continue; + } if (ret != CSRE_ERROR_NONE) return ret; -- cgit v1.2.3 From 29fa466ca487fbec2e3574e7c4ce7bab2f95df8a Mon Sep 17 00:00:00 2001 From: Kyungwook Tak Date: Tue, 27 Dec 2016 20:42:35 +0900 Subject: Add mainloop interface and backend layer popup service needs to use ecore loop based mainloop so as to expand ecore main loop life cycle to process life cycle to fix restart ecore loop bug. Make Mainloop class abstract and declare Event which can converted to backend specific event enums(e.g., epoll events, ecore events) then mainloop and service class can be defined generically. Mainloop backend is selected in each service impl's constructor. Change-Id: Ie965bbcca45c31a950cbb86649a2d22dd0d494d1 Signed-off-by: Kyungwook Tak --- src/framework/CMakeLists.txt | 2 +- src/framework/client/async-logic.cpp | 20 +-- src/framework/client/async-logic.h | 2 +- src/framework/common/mainloop.cpp | 165 ------------------- src/framework/common/mainloop.h | 96 +++++++----- src/framework/common/native-mainloop.cpp | 188 ++++++++++++++++++++++ src/framework/common/native-mainloop.h | 56 +++++++ src/framework/common/service.cpp | 65 ++++---- src/framework/common/service.h | 8 +- src/framework/common/socket.h | 1 - src/framework/service/server-service.cpp | 8 +- src/framework/ui/popup/CMakeLists.txt | 1 + src/framework/ui/popup/ecore-mainloop.cpp | 161 +++++++++++++++++++ src/framework/ui/popup/ecore-mainloop.h | 59 +++++++ src/framework/ui/popup/logic.cpp | 252 ++++++++++++++---------------- src/framework/ui/popup/logic.h | 32 ++-- src/framework/ui/popup/popup-service.cpp | 83 +++++----- src/framework/ui/popup/popup.cpp | 67 +++++--- src/framework/ui/popup/popup.h | 27 +++- 19 files changed, 826 insertions(+), 467 deletions(-) delete mode 100644 src/framework/common/mainloop.cpp create mode 100644 src/framework/common/native-mainloop.cpp create mode 100644 src/framework/common/native-mainloop.h create mode 100644 src/framework/ui/popup/ecore-mainloop.cpp create mode 100644 src/framework/ui/popup/ecore-mainloop.h mode change 100755 => 100644 src/framework/ui/popup/logic.cpp diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 1db36f9..8cad4a3 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -48,7 +48,7 @@ SET(${TARGET_CSR_COMMON}_SRCS common/em-context.cpp common/kvp-container.cpp common/dispatcher.cpp - common/mainloop.cpp + common/native-mainloop.cpp common/service.cpp common/socket.cpp common/socket-descriptor.cpp diff --git a/src/framework/client/async-logic.cpp b/src/framework/client/async-logic.cpp index 43ca501..ebe97f7 100644 --- a/src/framework/client/async-logic.cpp +++ b/src/framework/client/async-logic.cpp @@ -23,19 +23,22 @@ #include #include -#include #include "common/exception.h" #include "common/cs-detected.h" #include "common/connection.h" #include "common/async-protocol.h" +#include "common/native-mainloop.h" #include "common/audit/logger.h" namespace Csr { namespace Client { AsyncLogic::AsyncLogic(HandleExt *handle, void *userdata) : - m_handle(handle), m_userdata(userdata), m_dispatcherAsync(new Dispatcher(SockId::CS)) + m_loop(new NativeMainloop()), + m_handle(handle), + m_userdata(userdata), + m_dispatcherAsync(new Dispatcher(SockId::CS)) { } @@ -63,15 +66,15 @@ void AsyncLogic::scanHelper(const CommandId &id, const StrSet &s) auto fd = this->m_dispatcherAsync->getFd(); auto cancelEventFd = this->m_cancelSignal.getFd(); - this->m_loop.addEventSource(cancelEventFd, EPOLLIN, - [&](uint32_t) { + this->m_loop->addEventSource(cancelEventFd, Mainloop::Event::READ, + [&](Mainloop::Event) { this->m_cancelSignal.receive(); ThrowExcInfo(ASYNC_EVENT_CANCEL, "Async event cancelled on fd: " << fd); }); - this->m_loop.addEventSource(fd, EPOLLIN | EPOLLHUP | EPOLLRDHUP, - [&](uint32_t e) { - if (e & (EPOLLHUP | EPOLLRDHUP)) + this->m_loop->addEventSource(fd, Mainloop::Event::READ | Mainloop::Event::CLOSE, + [&](Mainloop::Event e) { + if ((e & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) ThrowExc(CSR_ERROR_SOCKET, "csr-server might be crashed. Finish async client loop"); // read event @@ -121,8 +124,7 @@ void AsyncLogic::scanHelper(const CommandId &id, const StrSet &s) }); try { - while (true) - this->m_loop.dispatch(-1); + this->m_loop->run(-1); } catch (const Exception &e) { switch (e.error()) { case ASYNC_EVENT_COMPLETE: diff --git a/src/framework/client/async-logic.h b/src/framework/client/async-logic.h index 7e82857..6ef4b58 100644 --- a/src/framework/client/async-logic.h +++ b/src/framework/client/async-logic.h @@ -46,9 +46,9 @@ public: private: void scanHelper(const CommandId &id, const StrSet &s); + std::unique_ptr m_loop; HandleExt *m_handle; // for registering results for auto-release void *m_userdata; - Mainloop m_loop; EventFd m_cancelSignal; std::unique_ptr m_dispatcherAsync; }; diff --git a/src/framework/common/mainloop.cpp b/src/framework/common/mainloop.cpp deleted file mode 100644 index 55eb7c8..0000000 --- a/src/framework/common/mainloop.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 - */ -/* - * @file mainloop.cpp - * @author Kyungwook Tak (k.tak@samsung.com) - * @version 1.0 - * @brief Mainloop of csr-server with epoll - */ -#include "common/mainloop.h" - -#include -#include -#include - -#include "common/audit/logger.h" -#include "common/exception.h" - -namespace Csr { - -Mainloop::Mainloop() : - m_isTimedOut(false), - m_pollfd(::epoll_create1(EPOLL_CLOEXEC)) -{ - if (this->m_pollfd == -1) - throw std::system_error( - std::error_code(errno, std::generic_category()), - "Failed to epoll_create1"); -} - -Mainloop::~Mainloop() -{ - if (!this->m_isTimedOut && !this->m_callbacks.empty()) - ERROR("mainloop registered callbacks should be empty except timed out case"); - - ::close(m_pollfd); -} - -void Mainloop::run(int timeout) -{ - this->m_isTimedOut = false; - - while (!this->m_isTimedOut) { - this->dispatch(timeout); - } - - DEBUG("Mainloop run stopped"); -} - -void Mainloop::addEventSource(int fd, uint32_t event, Callback &&callback) -{ - std::lock_guard l(this->m_mutex); - - if (this->m_callbacks.count(fd) != 0) - ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!"); - - DEBUG("Add event[" << event << "] source on fd[" << fd << "]"); - - epoll_event e; - - e.events = event; - e.data.fd = fd; - - if (::epoll_ctl(m_pollfd, EPOLL_CTL_ADD, fd, &e) == -1) - throw std::system_error( - std::error_code(errno, std::generic_category()), - "epoll_ctl failed to EPOLL_CTL_ADD."); - - this->m_callbacks[fd] = std::move(callback); -} - -void Mainloop::removeEventSource(int fd) -{ - std::lock_guard l(this->m_mutex); - - if (this->m_callbacks.count(fd) == 0) - ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] isn't added at all"); - - DEBUG("Remove event source on fd[" << fd << "]"); - - this->m_callbacks.erase(fd); - - if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) { - if (errno == ENOENT) - ThrowExc(CSR_ERROR_SERVER, "Tried to delete epoll item which wasn't added"); - else - throw std::system_error( - std::error_code(errno, std::generic_category()), - "epoll_ctl failed to EPOLL_CTL_DEL."); - } -} - -size_t Mainloop::countEventSource() const -{ - std::lock_guard l(this->m_mutex); - return this->m_callbacks.size(); -} - -void Mainloop::dispatch(int timeout) -{ - int nfds = -1; - epoll_event event[MAX_EPOLL_EVENTS]; - - DEBUG("Mainloop dispatched with timeout: " << timeout); - - do { - nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS, - ((timeout < 0) ? -1 : (timeout * 1000))); - } while ((nfds == -1) && (errno == EINTR)); - - if (nfds < 0) - throw std::system_error( - std::error_code(errno, std::generic_category()), - "epoll_wait failed!"); - - if (nfds == 0) { - DEBUG("Mainloop timed out!"); - if (this->m_isIdle && !this->m_isIdle()) { - INFO("Mainloop timed out but there's running task on upper layer. " - "Re-dispatch."); - this->m_isTimedOut = false; - } else { - INFO("Mainloop timed out! stop the loop!"); - this->m_isTimedOut = true; - } - - return; - } - - for (int i = 0; i < nfds; i++) { - int fd = event[i].data.fd; - - if (this->m_callbacks.count(fd) == 0) - ThrowExc(CSR_ERROR_SERVER, "event in on fd[" << fd << - "] but associated callback isn't exist!"); - - if (event[i].events & (EPOLLHUP | EPOLLRDHUP)) { - INFO("peer connection closed on fd[" << fd << "]"); - event[i].events &= ~EPOLLIN; - } - - DEBUG("event[" << event[i].events << "] polled on fd[" << fd << "]"); - - this->m_callbacks[fd](event[i].events); - } -} - -void Mainloop::setIdleChecker(std::function &&idleChecker) -{ - this->m_isIdle = std::move(idleChecker); -} - -} diff --git a/src/framework/common/mainloop.h b/src/framework/common/mainloop.h index 18b04d2..3333214 100644 --- a/src/framework/common/mainloop.h +++ b/src/framework/common/mainloop.h @@ -1,40 +1,41 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * 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 + * 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 + * 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 mainloop.h - * @author Kyungwook Tak (k.tak@samsung.com) - * @version 1.0 - * @brief Manageloop of csr-server with epoll + * 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. */ #pragma once #include -#include -#include +#include +#include #include "common/macros.h" namespace Csr { -class API Mainloop { +class Mainloop { public: - using Callback = std::function; + enum class Event : uint32_t { + NONE = 0, + READ = 1 << 0, + WRITE = 1 << 1, + CLOSE = 1 << 2 + }; + + using Callback = std::function; - Mainloop(); - virtual ~Mainloop(); + Mainloop() : m_domainSourceNum(0) {} + virtual ~Mainloop() {} Mainloop(const Mainloop &) = delete; Mainloop &operator=(const Mainloop &) = delete; @@ -43,27 +44,48 @@ public: // timeout unit: seconds // if timeout is negative value, no timeout on idle. - void run(int timeout); + virtual void run(int timeout) = 0; - // Moved to public to customize stop condition - void dispatch(int timeout); + virtual void addEventSource(int fd, Event event, Callback &&callback) = 0; + virtual void removeEventSource(int fd) = 0; - void addEventSource(int fd, uint32_t event, Callback &&callback); - void removeEventSource(int fd); - size_t countEventSource(void) const; + void addDomainEventSource(int fd, Event event, Callback &&callback) + { + ++this->m_domainSourceNum; + this->addEventSource(fd, event, std::move(callback)); + } - void setIdleChecker(std::function &&idleChecker); +protected: + size_t m_domainSourceNum; +}; -private: +template using Underlying = typename std::underlying_type::type; +template +constexpr Underlying underlying(T t) { return Underlying(t); } - bool m_isTimedOut; - int m_pollfd; - mutable std::mutex m_mutex; - std::unordered_map m_callbacks; +inline constexpr Mainloop::Event operator&(Mainloop::Event e1, Mainloop::Event e2) +{ + return Mainloop::Event(underlying(e1) & underlying(e2)); +} - std::function m_isIdle; +inline Mainloop::Event &operator&=(Mainloop::Event &e1, Mainloop::Event e2) +{ + return e1 = e1 & e2; +} - constexpr static size_t MAX_EPOLL_EVENTS = 32; -}; +inline constexpr Mainloop::Event operator|(Mainloop::Event e1, Mainloop::Event e2) +{ + return Mainloop::Event(underlying(e1) | underlying(e2)); +} +inline Mainloop::Event &operator|=(Mainloop::Event &e1, Mainloop::Event e2) +{ + return e1 = e1 | e2; } + +inline constexpr Mainloop::Event operator~(Mainloop::Event e) +{ + return Mainloop::Event(~underlying(e)); +} + +} // namespace Csr diff --git a/src/framework/common/native-mainloop.cpp b/src/framework/common/native-mainloop.cpp new file mode 100644 index 0000000..8e2de51 --- /dev/null +++ b/src/framework/common/native-mainloop.cpp @@ -0,0 +1,188 @@ +/* + * 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 + */ +/* + * @file native-mainloop.cpp + * @author Kyungwook Tak (k.tak@samsung.com) + * @version 1.0 + * @brief Mainloop of csr-server with epoll + */ +#include "common/native-mainloop.h" + +#include +#include +#include + +#include "common/audit/logger.h" +#include "common/exception.h" + +namespace Csr { + +uint32_t NativeMainloop::convertFlags(Mainloop::Event events) +{ + uint32_t flags = 0; + + if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE) + flags |= EPOLLIN; + if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE) + flags |= EPOLLOUT; + if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) + flags |= (EPOLLHUP | EPOLLRDHUP); + + return flags; +} + +Mainloop::Event NativeMainloop::convertFlags(uint32_t events) +{ + Mainloop::Event flags = Mainloop::Event::NONE; + + if (events & EPOLLIN) + flags |= Mainloop::Event::READ; + if (events & EPOLLOUT) + flags |= Mainloop::Event::WRITE; + if (events & (EPOLLHUP | EPOLLRDHUP)) + flags |= Mainloop::Event::CLOSE; + + return flags; +} + +NativeMainloop::NativeMainloop() : + m_isTimedOut(false), + m_pollfd(::epoll_create1(EPOLL_CLOEXEC)) +{ + if (this->m_pollfd == -1) + throw std::system_error( + std::error_code(errno, std::generic_category()), + "Failed to epoll_create1"); +} + +NativeMainloop::~NativeMainloop() +{ + if (!this->m_isTimedOut && !this->m_callbacks.empty()) + ERROR("mainloop registered callbacks should be empty except timed out case"); + + ::close(m_pollfd); +} + +void NativeMainloop::run(int timeout) +{ + this->m_isTimedOut = false; + + while (!this->m_isTimedOut) { + this->dispatch(timeout); + } + + DEBUG("NativeMainloop run stopped"); +} + +void NativeMainloop::addEventSource( + int fd, Mainloop::Event event, Mainloop::Callback &&callback) +{ + std::lock_guard l(this->m_mutex); + + if (this->m_callbacks.count(fd) != 0) + ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!"); + + DEBUG("Add event[" << static_cast(event) + << "] source on fd[" << fd << "]"); + + epoll_event e; + + e.events = NativeMainloop::convertFlags(event); + e.data.fd = fd; + + if (::epoll_ctl(m_pollfd, EPOLL_CTL_ADD, fd, &e) == -1) + throw std::system_error( + std::error_code(errno, std::generic_category()), + "epoll_ctl failed to EPOLL_CTL_ADD."); + + this->m_callbacks[fd] = std::move(callback); +} + +void NativeMainloop::removeEventSource(int fd) +{ + std::lock_guard l(this->m_mutex); + + auto it = this->m_callbacks.find(fd); + if (it == this->m_callbacks.end()) + ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] isn't added at all"); + + DEBUG("Remove event source on fd[" << fd << "]"); + + this->m_callbacks.erase(it); + + if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) { + if (errno == ENOENT) + ThrowExc(CSR_ERROR_SERVER, "Tried to delete epoll item which wasn't added"); + else + throw std::system_error( + std::error_code(errno, std::generic_category()), + "epoll_ctl failed to EPOLL_CTL_DEL."); + } +} + +void NativeMainloop::dispatch(int timeout) +{ + int nfds = -1; + epoll_event event[MAX_EPOLL_EVENTS]; + + DEBUG("NativeMainloop dispatched with timeout: " << timeout); + + do { + nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS, + ((timeout < 0) ? -1 : (timeout * 1000))); + } while ((nfds == -1) && (errno == EINTR)); + + if (nfds < 0) + throw std::system_error( + std::error_code(errno, std::generic_category()), + "epoll_wait failed!"); + + if (nfds == 0) { + DEBUG("NativeMainloop timed out!"); + if (this->m_callbacks.size() > this->m_domainSourceNum) { + INFO("NativeMainloop timed out but there's running task on upper layer. " + "Re-dispatch."); + this->m_isTimedOut = false; + } else { + INFO("NativeMainloop timed out! stop the loop!"); + this->m_isTimedOut = true; + } + + return; + } + + for (int i = 0; i < nfds; i++) { + int fd = event[i].data.fd; + + auto it = this->m_callbacks.find(fd); + if (it == this->m_callbacks.end()) + ThrowExc(CSR_ERROR_SERVER, "event in on fd[" << fd << + "] but associated callback isn't exist!"); + + auto events = convertFlags(event[i].events); + if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) { + INFO("peer connection closed on fd[" << fd << "]"); + events &= ~Mainloop::Event::READ; + } + + DEBUG("event[" << static_cast(events) + << "] polled on fd[" << fd << "]"); + + it->second(events); + } +} + +} diff --git a/src/framework/common/native-mainloop.h b/src/framework/common/native-mainloop.h new file mode 100644 index 0000000..04d6fa1 --- /dev/null +++ b/src/framework/common/native-mainloop.h @@ -0,0 +1,56 @@ +/* + * 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 + */ +/* + * @file native-mainloop.h + * @author Kyungwook Tak (k.tak@samsung.com) + * @version 1.0 + * @brief Manageloop of csr-server with epoll + */ +#pragma once + +#include +#include +#include + +#include "common/mainloop.h" +#include "common/macros.h" + +namespace Csr { + +class API NativeMainloop : public Mainloop { +public: + NativeMainloop(); + virtual ~NativeMainloop(); + + virtual void run(int timeout) override; + virtual void addEventSource( + int fd, Mainloop::Event event, Mainloop::Callback &&callback) override; + virtual void removeEventSource(int fd) override; + +private: + void dispatch(int timeout); + static uint32_t convertFlags(Mainloop::Event events); + static Mainloop::Event convertFlags(uint32_t events); + + bool m_isTimedOut; + int m_pollfd; + mutable std::mutex m_mutex; + std::unordered_map m_callbacks; + + constexpr static size_t MAX_EPOLL_EVENTS = 32; +}; + +} diff --git a/src/framework/common/service.cpp b/src/framework/common/service.cpp index aef65e6..36430d0 100644 --- a/src/framework/common/service.cpp +++ b/src/framework/common/service.cpp @@ -30,8 +30,12 @@ namespace Csr { -Service::Service() noexcept +Service::Service(Mainloop *mainloop) { + if (mainloop == nullptr) + throw std::invalid_argument("mainloop shouldn't be null"); + + this->m_loop.reset(mainloop); } Service::~Service() @@ -53,16 +57,18 @@ void Service::start(int timeout) DEBUG("Get systemd socket[" << socket->getFd() << "] for sock id: " << static_cast(id)); - this->m_loop.addEventSource(socket->getFd(), EPOLLIN | EPOLLHUP | EPOLLRDHUP, - [this, socket](uint32_t event) { - if (event != EPOLLIN) - return; + this->m_loop->addDomainEventSource( + socket->getFd(), + Mainloop::Event::READ | Mainloop::Event::CLOSE, + [this, socket](Mainloop::Event events) { + if ((events & Mainloop::Event::READ) == Mainloop::Event::NONE) + return; - this->onNewConnection(std::make_shared(socket->accept())); - }); + this->onNewConnection(std::make_shared(socket->accept())); + }); } - this->m_loop.run(timeout); + this->m_loop->run(timeout); } void Service::onNewConnection(ConnShPtr &&connection) @@ -74,28 +80,29 @@ void Service::onNewConnection(ConnShPtr &&connection) INFO("welcome! accepted client socket fd[" << fd << "]"); - this->m_loop.addEventSource(fd, EPOLLIN | EPOLLHUP | EPOLLRDHUP, - [&, fd](uint32_t event) { - std::lock_guard lock(this->m_crMtx); + this->m_loop->addEventSource(fd, + Mainloop::Event::READ | Mainloop::Event::CLOSE, + [&, fd](Mainloop::Event events) { + std::lock_guard lock(this->m_crMtx); - DEBUG("read event comes in to fd[" << fd << "]"); + DEBUG("read event comes in to fd[" << fd << "]"); - if (this->m_connectionRegistry.count(fd) == 0) - ThrowExc(CSR_ERROR_SERVER, "get event on fd[" << fd << - "] but no associated connection exist"); + auto it = this->m_connectionRegistry.find(fd); + if (it == this->m_connectionRegistry.end()) + ThrowExc(CSR_ERROR_SERVER, "get event on fd[" << fd << + "] but no associated connection exist"); - auto &conn = this->m_connectionRegistry[fd]; - - if (event & (EPOLLHUP | EPOLLRDHUP)) { - DEBUG("event of epoll hup. close connection on fd[" << fd << "]"); - this->onCloseConnection(conn); - return; - } + auto &conn = it->second; - DEBUG("Start message process on fd[" << fd << "]"); + if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) { + DEBUG("close event occured. close connection on fd[" << fd << "]"); + this->onCloseConnection(conn); + return; + } - onMessageProcess(conn); - }); + this->onMessageProcess(conn); + } + ); std::lock_guard lock(this->m_crMtx); this->m_connectionRegistry[fd] = std::move(connection); @@ -108,15 +115,15 @@ void Service::onCloseConnection(const ConnShPtr &connection) auto fd = connection->getFd(); - if (this->m_connectionRegistry.count(fd) == 0) + auto it = this->m_connectionRegistry.find(fd); + if (it == this->m_connectionRegistry.end()) ThrowExc(CSR_ERROR_SERVER, "no connection in registry to remove " "associated to fd[" << fd << "]"); INFO("good-bye! close socket fd[" << fd << "]"); - this->m_loop.removeEventSource(fd); - - this->m_connectionRegistry.erase(fd); + this->m_loop->removeEventSource(fd); + this->m_connectionRegistry.erase(it); } } diff --git a/src/framework/common/service.h b/src/framework/common/service.h index 0e4195c..77ca336 100644 --- a/src/framework/common/service.h +++ b/src/framework/common/service.h @@ -21,9 +21,9 @@ */ #pragma once -#include -#include #include +#include +#include #include #include "common/macros.h" @@ -35,7 +35,7 @@ namespace Csr { class API Service { public: - Service() noexcept; + Service(Mainloop *mainloop); virtual ~Service(); Service(const Service &) = delete; @@ -47,7 +47,7 @@ public: virtual void start(int timeout) final; protected: - Mainloop m_loop; + std::unique_ptr m_loop; private: virtual void onMessageProcess(const ConnShPtr &) = 0; diff --git a/src/framework/common/socket.h b/src/framework/common/socket.h index 52a6a8a..24fd296 100644 --- a/src/framework/common/socket.h +++ b/src/framework/common/socket.h @@ -23,7 +23,6 @@ #include -#include "common/macros.h" #include "common/types.h" #include "common/socket-descriptor.h" diff --git a/src/framework/service/server-service.cpp b/src/framework/service/server-service.cpp index 24bd1bf..b540269 100644 --- a/src/framework/service/server-service.cpp +++ b/src/framework/service/server-service.cpp @@ -34,6 +34,7 @@ #include "common/wp-result.h" #include "common/exception.h" #include "common/async-protocol.h" +#include "common/native-mainloop.h" #include "service/exception.h" #include "service/access-control.h" #include "service/core-usage.h" @@ -84,7 +85,7 @@ inline CommandId extractCommandId(BinaryQueue &q) } // namespace anonymous -ServerService::ServerService() : Service(), m_workqueue(5) +ServerService::ServerService() : Service(new NativeMainloop()), m_workqueue(5) { this->m_db = std::make_shared(RW_DBSPACE "/.csr.db", RO_DBSPACE); @@ -111,11 +112,6 @@ ServerService::ServerService() : Service(), m_workqueue(5) this->add(SockId::CS); this->add(SockId::WP); this->add(SockId::ADMIN); - - // if task is not running in workqueue, it's idle. - this->m_loop.setIdleChecker([this]()->bool { - return (!this->m_workqueue.isTaskRunning() && this->m_loop.countEventSource() == 3); - }); } RawBuffer ServerService::processCs(const ConnShPtr &conn, RawBuffer &data) diff --git a/src/framework/ui/popup/CMakeLists.txt b/src/framework/ui/popup/CMakeLists.txt index 6f8dd01..ddc667b 100644 --- a/src/framework/ui/popup/CMakeLists.txt +++ b/src/framework/ui/popup/CMakeLists.txt @@ -39,6 +39,7 @@ SET(${TARGET_CSR_POPUP}_SRCS logic.cpp popup.cpp popup-service.cpp + ecore-mainloop.cpp package-info.cpp ${PROJECT_SOURCE_DIR}/src/framework/ui/common.cpp ) diff --git a/src/framework/ui/popup/ecore-mainloop.cpp b/src/framework/ui/popup/ecore-mainloop.cpp new file mode 100644 index 0000000..4e97e60 --- /dev/null +++ b/src/framework/ui/popup/ecore-mainloop.cpp @@ -0,0 +1,161 @@ +/* + * 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 "ecore-mainloop.h" + +#include +#include + +#include "common/audit/logger.h" + +namespace Csr { +namespace Ui { + +Ecore_Fd_Handler_Flags EcoreMainloop::convertFlags(Mainloop::Event events) +{ + uint32_t flags = 0; + + if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE) + flags |= ECORE_FD_READ; + if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE) + flags |= ECORE_FD_WRITE; + + return static_cast(flags); +} + +Mainloop::Event EcoreMainloop::convertFlags(Ecore_Fd_Handler *handler) +{ + Mainloop::Event flags = Mainloop::Event::NONE; + + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) + flags |= Mainloop::Event::READ; + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE)) + flags |= Mainloop::Event::WRITE; + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) + flags |= Mainloop::Event::CLOSE; + + return flags; +} + +EcoreMainloop::EcoreMainloop() : m_isExitCalled(false), m_timer(nullptr) {} + +EcoreMainloop::~EcoreMainloop() +{ + if (this->m_timer) + ecore_timer_del(this->m_timer); + + if (!this->m_isExitCalled) + elm_exit(); +} + +void EcoreMainloop::run(int timeout) +{ + this->dispatch(timeout); +} + +void EcoreMainloop::dispatch(int timeout) +{ + if (timeout >= 0) { + this->m_timer = ecore_timer_add( + static_cast(timeout), &EcoreMainloop::ecoreTimeoutCb, this); + + if (this->m_timer == nullptr) { + ERROR("Failed to ecore_timer_add()..."); + } + } + + elm_run(); +} + +void EcoreMainloop::addEventSource( + int fd, Mainloop::Event events, Mainloop::Callback &&callback) +{ + auto handler = ecore_main_fd_handler_add( + fd, convertFlags(events), + &EcoreMainloop::ecoreFdCallback, this, nullptr, nullptr); + + if (handler == nullptr) { + ERROR("failed to handle fd(" << fd << ") by ecore_main_fd_handler_add()"); + return; + } + + std::unique_ptr source(new EventSource); + source->callback = std::move(callback); + source->handler = handler; + + this->m_sources[fd] = std::move(source); +} + +void EcoreMainloop::removeEventSource(int fd) +{ + auto it = this->m_sources.find(fd); + + if (it == this->m_sources.end()) { + ERROR("fd(" << fd << ") associated source is not found"); + return; + } + + ecore_main_fd_handler_del(it->second->handler); + + this->m_sources.erase(it); +} + +Eina_Bool EcoreMainloop::ecoreFdCallback(void *data, Ecore_Fd_Handler *handler) +{ + auto mainloop = static_cast(data); + + if (mainloop == nullptr) + throw std::invalid_argument("userdata for ecore fd callback is invalid"); + + int fd = ecore_main_fd_handler_fd_get(handler); + + auto it = mainloop->m_sources.find(fd); + if (it == mainloop->m_sources.end() || it->second == nullptr) { + ERROR("no associated source found with fd: " << fd); + return ECORE_CALLBACK_CANCEL; + } + + it->second->callback(convertFlags(handler)); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool EcoreMainloop::ecoreTimeoutCb(void *data) +{ + auto mainloop = static_cast(data); + + if (mainloop == nullptr) + throw std::invalid_argument("userdata for ecore timeout callback is invalid"); + + if (mainloop->m_sources.size() == mainloop->m_domainSourceNum) { + INFO("There's no alive connection. Only listening socket opened. " + "Let's exit the ecore main loop!"); + + elm_exit(); + + mainloop->m_timer = nullptr; + mainloop->m_isExitCalled = true; + + return ECORE_CALLBACK_CANCEL; + } else { + INFO("Time out expired but there's alive connection " + "so go ahead to next tick!"); + return ECORE_CALLBACK_RENEW; + } +} + +} // namespace Ui +} // namespace Csr diff --git a/src/framework/ui/popup/ecore-mainloop.h b/src/framework/ui/popup/ecore-mainloop.h new file mode 100644 index 0000000..271b011 --- /dev/null +++ b/src/framework/ui/popup/ecore-mainloop.h @@ -0,0 +1,59 @@ +/* + * 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. + */ +#pragma once + +#include +#include +#include + +#include "common/mainloop.h" + +namespace Csr { +namespace Ui { + +class EcoreMainloop : public Mainloop { +public: + EcoreMainloop(); + virtual ~EcoreMainloop(); + + virtual void run(int timeout) override; + + virtual void addEventSource( + int fd, Mainloop::Event event, Mainloop::Callback &&callback) override; + virtual void removeEventSource(int fd) override; + +private: + struct EventSource { + Mainloop::Callback callback; + Ecore_Fd_Handler *handler; + }; + + void dispatch(int timeout); + + static Ecore_Fd_Handler_Flags convertFlags(Mainloop::Event events); + static Mainloop::Event convertFlags(Ecore_Fd_Handler *handler); + + static Eina_Bool ecoreFdCallback(void *data, Ecore_Fd_Handler *handler); + static Eina_Bool ecoreTimeoutCb(void *data); + + std::unordered_map> m_sources; + + bool m_isExitCalled; + Ecore_Timer *m_timer; +}; + +} // namespace Ui +} // namespace Csr diff --git a/src/framework/ui/popup/logic.cpp b/src/framework/ui/popup/logic.cpp old mode 100755 new mode 100644 index ce8c83b..7cb5999 --- a/src/framework/ui/popup/logic.cpp +++ b/src/framework/ui/popup/logic.cpp @@ -65,254 +65,230 @@ std::string formatToString(const char *form, std::string arg) } } // namespace anonymous -RawBuffer Logic::csPromptData(const std::string &message, const CsDetected &d) const +void Logic::csPromptData(const std::string &message, const CsDetected &d) { std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); - Popup p(2); + m_popup.setButtons(2); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_PROMPT_DATA_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_PROMPT_DATA_HEADER); + m_popup.setBody(FORMAT( "- " << LABEL_RISK << risk << " (" << d.malwareName << ")")); - p.setFooter(CS_PROMPT_DATA_FOOTER); + m_popup.setFooter(CS_PROMPT_DATA_FOOTER); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_OPEN); + m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); + m_popup.setText(m_popup.m_buttons[1], BTN_OPEN); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); + m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); } -RawBuffer Logic::csPromptFile(const std::string &message, const CsDetected &d) const +void Logic::csPromptFile(const std::string &message, const CsDetected &d) { std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); std::string fileName, extraPath; split(d.targetName, fileName, extraPath); - Popup p(3); + m_popup.setButtons(3); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_PROMPT_FILE_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_PROMPT_FILE_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_FILE_NAME, fileName) << "
" << "- " << formatToString(LABEL_FILE_PATH, extraPath) << "
" << "- " << LABEL_RISK << risk << " (" << d.malwareName << ")")); std::string prefix(CS_NOTIFY_FILE_FOOTER); - p.setFooter(FORMAT(prefix << "
" << CS_PROMPT_FILE_FOOTER)); + m_popup.setFooter(FORMAT(prefix << "
" << CS_PROMPT_FILE_FOOTER)); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_OPEN); - p.setText(p.m_buttons[2], BTN_DELETE); + m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); + m_popup.setText(m_popup.m_buttons[1], BTN_OPEN); + m_popup.setText(m_popup.m_buttons[2], BTN_DELETE); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_REMOVE)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_buttons[2], &p.m_types[2]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); + m_popup.callbackRegister(m_popup.m_buttons[2], &m_popup.m_types[2]); + m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); } -RawBuffer Logic::csPromptApp(const std::string &message, const CsDetected &d) const +void Logic::csPromptApp(const std::string &message, const CsDetected &d) { std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); PackageInfo info(d.pkgId); - Popup p(3); + m_popup.setButtons(3); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_PROMPT_APP_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_PROMPT_APP_HEADER); + m_popup.setBody(FORMAT( LABEL_APP_NAME << info.getLabel() << "
" << LABEL_VERSION << info.getVersion() << "
" << LABEL_RISK << risk << " (" << d.malwareName << ")")); - p.setIcon(info.getIconPath()); + m_popup.setIcon(info.getIconPath()); std::string prefix = formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL); - p.setFooter(FORMAT(prefix << "
" << CS_PROMPT_APP_FOOTER)); + m_popup.setFooter(FORMAT(prefix << "
" << CS_PROMPT_APP_FOOTER)); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_OPEN); - p.setText(p.m_buttons[2], BTN_UNINSTALL); + m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); + m_popup.setText(m_popup.m_buttons[1], BTN_OPEN); + m_popup.setText(m_popup.m_buttons[2], BTN_UNINSTALL); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_REMOVE)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_buttons[2], &p.m_types[2]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); + m_popup.callbackRegister(m_popup.m_buttons[2], &m_popup.m_types[2]); + m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); } -RawBuffer Logic::csNotifyData(const std::string &message, const CsDetected &d) const +void Logic::csNotifyData(const std::string &message, const CsDetected &d) { - Popup p(1); + m_popup.setButtons(1); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_NOTIFY_DATA_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_NOTIFY_DATA_HEADER); + m_popup.setBody(FORMAT( "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); - p.setFooter(CS_NOTIFY_DATA_FOOTER); + m_popup.setFooter(CS_NOTIFY_DATA_FOOTER); - p.setText(p.m_buttons[0], BTN_OK); + m_popup.setText(m_popup.m_buttons[0], BTN_OK); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); } -RawBuffer Logic::csNotifyFile(const std::string &message, const CsDetected &d) const +void Logic::csNotifyFile(const std::string &message, const CsDetected &d) { - Popup p(2); + m_popup.setButtons(2); std::string fileName, extraPath; split(d.targetName, fileName, extraPath); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_NOTIFY_FILE_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_NOTIFY_FILE_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_FILE_NAME, fileName) << "
" << "- " << formatToString(LABEL_FILE_PATH, extraPath) << "
" << "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); - p.setFooter(CS_NOTIFY_FILE_FOOTER); + m_popup.setFooter(CS_NOTIFY_FILE_FOOTER); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_DELETE); + m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); + m_popup.setText(m_popup.m_buttons[1], BTN_DELETE); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_REMOVE)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); + m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); } -RawBuffer Logic::csNotifyApp(const std::string &message, const CsDetected &d) const +void Logic::csNotifyApp(const std::string &message, const CsDetected &d) { PackageInfo info(d.pkgId); - Popup p(2); + m_popup.setButtons(2); - p.setMessage(message); - p.setTitle(CS_TITLE); - p.setHeader(CS_NOTIFY_APP_HEADER); - p.setIcon(info.getIconPath()); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(CS_TITLE); + m_popup.setHeader(CS_NOTIFY_APP_HEADER); + m_popup.setIcon(info.getIconPath()); + m_popup.setBody(FORMAT( LABEL_APP_NAME << info.getLabel() << "
" << LABEL_VERSION << info.getVersion() << "
" << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); - p.setFooter(formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL)); + m_popup.setFooter(formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL)); - p.setText(p.m_buttons[0], BTN_CANCEL); - p.setText(p.m_buttons[1], BTN_UNINSTALL); + m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); + m_popup.setText(m_popup.m_buttons[1], BTN_UNINSTALL); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, d.detailedUrl); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); + m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); } -RawBuffer Logic::wpPrompt(const std::string &message, const UrlItem &item) const +void Logic::wpPrompt(const std::string &message, const UrlItem &item) { std::string risk(item.risk == CSR_WP_RISK_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); - Popup p(2); + m_popup.setButtons(2); - p.setMessage(message); - p.setTitle(WP_TITLE); - p.setHeader(WP_PROMPT_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(WP_TITLE); + m_popup.setHeader(WP_PROMPT_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_URL, item.url) << "
" << "- " << LABEL_RISK << risk)); - p.setFooter(WP_PROMPT_FOOTER); + m_popup.setFooter(WP_PROMPT_FOOTER); - p.setText(p.m_buttons[0], BTN_BLOCK); - p.setText(p.m_buttons[1], BTN_VIEW); + m_popup.setText(m_popup.m_buttons[0], BTN_BLOCK); + m_popup.setText(m_popup.m_buttons[1], BTN_VIEW); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.m_types.emplace_back( + m_popup.m_types.emplace_back( static_cast(CSR_WP_USER_RESPONSE_PROCESSING_ALLOWED)); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_buttons[1], &p.m_types[1]); - p.callbackRegister(p.m_hypertext, item.url); - - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); + m_popup.callbackRegister(m_popup.m_hypertext, item.url); } -RawBuffer Logic::wpNotify(const std::string &message, const UrlItem &item) const +void Logic::wpNotify(const std::string &message, const UrlItem &item) { - Popup p(1); + m_popup.setButtons(1); - p.setMessage(message); - p.setTitle(WP_TITLE); - p.setHeader(WP_NOTIFY_HEADER); - p.setBody(FORMAT( + m_popup.setMessage(message); + m_popup.setTitle(WP_TITLE); + m_popup.setHeader(WP_NOTIFY_HEADER); + m_popup.setBody(FORMAT( "- " << formatToString(LABEL_URL, item.url) << "
" << "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH)); - p.setFooter(WP_NOTIFY_FOOTER); - - p.setText(p.m_buttons[0], BTN_OK); + m_popup.setFooter(WP_NOTIFY_FOOTER); - p.m_types.emplace_back(static_cast(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); + m_popup.setText(m_popup.m_buttons[0], BTN_OK); - p.callbackRegister(p.m_buttons[0], &p.m_types[0]); - p.callbackRegister(p.m_hypertext, item.url); + m_popup.m_types.emplace_back(static_cast(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); - p.run(); - return p.getResult(); + m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); + m_popup.callbackRegister(m_popup.m_hypertext, item.url); } } // namespace Ui } // namespace Csr diff --git a/src/framework/ui/popup/logic.h b/src/framework/ui/popup/logic.h index 50a50dd..bdde6cd 100644 --- a/src/framework/ui/popup/logic.h +++ b/src/framework/ui/popup/logic.h @@ -26,24 +26,32 @@ #include "common/types.h" #include "common/cs-detected.h" #include "ui/common.h" +#include "popup.h" namespace Csr { namespace Ui { class Logic { public: - Logic() = default; - virtual ~Logic() = default; - - RawBuffer csPromptData(const std::string &, const CsDetected &) const; - RawBuffer csPromptApp(const std::string &, const CsDetected &) const; - RawBuffer csPromptFile(const std::string &, const CsDetected &) const; - RawBuffer csNotifyData(const std::string &, const CsDetected &) const; - RawBuffer csNotifyApp(const std::string &, const CsDetected &) const; - RawBuffer csNotifyFile(const std::string &, const CsDetected &) const; - - RawBuffer wpPrompt(const std::string &, const UrlItem &) const; - RawBuffer wpNotify(const std::string &, const UrlItem &) const; + Logic() {} + virtual ~Logic() {} + + void csPromptData(const std::string &, const CsDetected &); + void csPromptApp(const std::string &, const CsDetected &); + void csPromptFile(const std::string &, const CsDetected &); + void csNotifyData(const std::string &, const CsDetected &); + void csNotifyApp(const std::string &, const CsDetected &); + void csNotifyFile(const std::string &, const CsDetected &); + + void wpPrompt(const std::string &, const UrlItem &); + void wpNotify(const std::string &, const UrlItem &); + + void setSender(Popup::Sender &&sender) { + m_popup.setSender(std::move(sender)); + } + +private: + Popup m_popup; }; } // namespace Ui diff --git a/src/framework/ui/popup/popup-service.cpp b/src/framework/ui/popup/popup-service.cpp index 186b847..43ed62f 100644 --- a/src/framework/ui/popup/popup-service.cpp +++ b/src/framework/ui/popup/popup-service.cpp @@ -1,30 +1,27 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * 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 + * 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 + * 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 popup-service.cpp - * @author Kyungwook Tak (k.tak@samsung.com) - * @version 1.0 - * @brief + * 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 "popup-service.h" #include "common/binary-queue.h" #include "common/audit/logger.h" +#include "common/types.h" #include "common/exception.h" -#include "common/cs-detected.h" + +#include "ecore-mainloop.h" namespace Csr { namespace Ui { @@ -51,22 +48,30 @@ bool isCsCommand(const CommandId &cid) } } -} // namespace nonymous +} // namespace anonymous -PopupService::PopupService() : Service() +PopupService::PopupService() : Csr::Service(new EcoreMainloop()) { this->add(SockId::POPUP); } -RawBuffer PopupService::process(const ConnShPtr &, RawBuffer &data) +void PopupService::onMessageProcess(const ConnShPtr &conn) { + auto in = conn->receive(); + + // some fd handler from mainloop makes empty read event when client + // close connection. returning false from process() means connection + // is closed + if (in.empty()) + throw std::invalid_argument("empty read event!"); + BinaryQueue q; - q.push(data); + q.push(std::move(in)); int intCid; q.Deserialize(intCid); - INFO("Request dispatch on popup-service. CommandId: " << static_cast(intCid)); + INFO("Request dispatch on popup service. CommandId: " << static_cast(intCid)); if (isCsCommand(static_cast(intCid))) { std::string message; @@ -75,22 +80,28 @@ RawBuffer PopupService::process(const ConnShPtr &, RawBuffer &data) switch (static_cast(intCid)) { case CommandId::CS_PROMPT_DATA: - return m_logic.csPromptData(message, d); + m_logic.csPromptData(message, d); + break; case CommandId::CS_PROMPT_APP: - return m_logic.csPromptApp(message, d); + m_logic.csPromptApp(message, d); + break; case CommandId::CS_PROMPT_FILE: - return m_logic.csPromptFile(message, d); + m_logic.csPromptFile(message, d); + break; case CommandId::CS_NOTIFY_DATA: - return m_logic.csNotifyData(message, d); + m_logic.csNotifyData(message, d); + break; case CommandId::CS_NOTIFY_APP: - return m_logic.csNotifyApp(message, d); + m_logic.csNotifyApp(message, d); + break; case CommandId::CS_NOTIFY_FILE: - return m_logic.csNotifyFile(message, d); + m_logic.csNotifyFile(message, d); + break; default: ThrowExc(CSR_ERROR_SERVER, "protocol error. invalid ui command id."); @@ -102,25 +113,19 @@ RawBuffer PopupService::process(const ConnShPtr &, RawBuffer &data) switch (static_cast(intCid)) { case CommandId::WP_PROMPT: - return m_logic.wpPrompt(message, item); + m_logic.wpPrompt(message, item); + break; case CommandId::WP_NOTIFY: - return m_logic.wpNotify(message, item); + m_logic.wpNotify(message, item); + break; default: ThrowExc(CSR_ERROR_SERVER, "protocol error. invalid ui command id."); } } -} - -void PopupService::onMessageProcess(const ConnShPtr &connection) -{ - DEBUG("process message on popup service"); - - auto in = connection->receive(); - connection->send(this->process(connection, in)); - DEBUG("process done on popup service"); + m_logic.setSender([conn](const RawBuffer &out) { conn->send(out); }); } } // namespace Ui diff --git a/src/framework/ui/popup/popup.cpp b/src/framework/ui/popup/popup.cpp index 46a0cd3..844f1fb 100644 --- a/src/framework/ui/popup/popup.cpp +++ b/src/framework/ui/popup/popup.cpp @@ -43,8 +43,19 @@ namespace { } -Popup::Popup(int buttonN) +void Popup::setSender(Sender &&sender) { + m_sender = std::move(sender); +} + +Popup::Popup() : m_win(nullptr) +{ +} + +void Popup::setButtons(int n) +{ + clear(); + // Set win properties. m_win = elm_win_add(nullptr, "CSR popup", ELM_WIN_NOTIFICATION); elm_win_indicator_opacity_set(m_win, ELM_WIN_INDICATOR_TRANSLUCENT); @@ -56,7 +67,7 @@ Popup::Popup(int buttonN) setRotationToWin(m_win); eext_win_keygrab_set(m_win, HOME_KEY.c_str()); - ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keyDownCb, NULL); + ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keyDownCb, this); // Set popup properties. m_popup = elm_popup_add(m_win); @@ -111,8 +122,7 @@ Popup::Popup(int buttonN) elm_box_horizontal_set(m_btnBox, EINA_TRUE); elm_box_padding_set(m_btnBox, 0, 0); - for(int i=1 ; i <= buttonN; i++) { - std::string id("button" + std::to_string(i)); + for (int i = 0; i < n; ++i) { Evas_Object *button = elm_button_add(m_popup); elm_object_style_set(button, "bottom"); setDefaultProperties(button); @@ -132,7 +142,8 @@ Popup::Popup(int buttonN) Popup::~Popup() { - evas_object_del(m_win); + if (m_win != nullptr) + evas_object_del(m_win); } void Popup::setHeader(const std::string &header) noexcept @@ -163,11 +174,6 @@ void Popup::setIcon(const std::string &path) noexcept elm_image_file_set(m_icon, path.c_str(), NULL); } -void Popup::run(void) -{ - elm_run(); -} - int Popup::response = -1; RawBuffer Popup::getResult(void) @@ -211,7 +217,8 @@ void Popup::setText(Evas_Object *obj, const std::string &text) noexcept void Popup::callbackRegister(Evas_Object *obj, int *type) { - evas_object_smart_callback_add(obj, "clicked", btnClickedCb, type); + m_buttonSelectorMap[obj] = [type]() { return *type; }; + evas_object_smart_callback_add(obj, "clicked", btnClickedCb, this); } void Popup::callbackRegister(Evas_Object *obj, const std::string &url) @@ -274,26 +281,50 @@ void Popup::hypertextClickedCb(void *data, Evas_Object *, void *) } } -void Popup::btnClickedCb(void *data, Evas_Object *, void *) +void Popup::btnClickedCb(void *data, Evas_Object *obj, void *) { - response = *(reinterpret_cast(data)); - elm_exit(); -} + auto popup = reinterpret_cast(data); + if (popup == nullptr) + throw std::invalid_argument("Popup instance is null in static btnClickedCb"); + response = popup->m_buttonSelectorMap.at(obj)(); + popup->terminateWindow(); +} -Eina_Bool Popup::keyDownCb(void *, int , void *ev) +Eina_Bool Popup::keyDownCb(void *data, int , void *ev) { DEBUG("Key down event caught."); auto event = reinterpret_cast(ev); - if(event->key == HOME_KEY) { + if (event->key == HOME_KEY) { + auto popup = reinterpret_cast(data); response = -1; - elm_exit(); + popup->terminateWindow(); } // Let the event continue to other callbacks. return ECORE_CALLBACK_PASS_ON; } +void Popup::terminateWindow() +{ + INFO("send result based on response and sender"); + m_sender(getResult()); + + clear(); +} + +void Popup::clear() +{ + if (m_win != nullptr) { + // clear all resources + evas_object_del(m_win); + m_win = nullptr; + } + + m_buttons.clear(); + m_types.clear(); +} + } // namespace Ui } // namespace Csr diff --git a/src/framework/ui/popup/popup.h b/src/framework/ui/popup/popup.h index 4475d96..821c7ec 100644 --- a/src/framework/ui/popup/popup.h +++ b/src/framework/ui/popup/popup.h @@ -32,6 +32,7 @@ #include "common/audit/logger.h" #include "common/binary-queue.h" +#include "common/types.h" namespace Csr { namespace Ui { @@ -55,10 +56,11 @@ namespace Ui { class Popup { public: - Popup(int buttonN); + Popup(); virtual ~Popup(); - void run(void); + void setButtons(int n); + RawBuffer getResult(void); void setMessage(const std::string &msg) noexcept; @@ -67,6 +69,9 @@ public: Popup(Popup &&) = delete; Popup &operator=(Popup &&) = delete; + using Sender = std::function; + void setSender(Sender &&sender); + void setTitle(const std::string &title) noexcept; void setHeader(const std::string &header) noexcept; void setBody(const std::string &body) noexcept; @@ -76,9 +81,6 @@ public: void callbackRegister(Evas_Object *obj, int *type); void callbackRegister(Evas_Object *obj, const std::string &url); - static void btnClickedCb(void *data, Evas_Object *, void *); - static void hypertextClickedCb(void *data, Evas_Object *, void *); - static void rotationChangedCb(void *data, Evas_Object *, void *); static Eina_Bool keyDownCb(void *, int, void *); std::vector m_buttons; @@ -86,6 +88,15 @@ public: std::vector m_types; private: + static void btnClickedCb(void *data, Evas_Object *, void *); + static void hypertextClickedCb(void *data, Evas_Object *, void *); + static void rotationChangedCb(void *data, Evas_Object *, void *); + + using ButtonSelector = std::function; + std::map m_buttonSelectorMap; + void terminateWindow(); + void clear(); + void setDefaultProperties(Evas_Object *obj) noexcept; void setRotationToWin(Evas_Object *obj) noexcept; @@ -103,10 +114,12 @@ private: std::string m_iconPath; std::string m_hypertextUrl; - static int response; - int m_winW; int m_winH; + + Sender m_sender; + + static int response; }; } // namespace Ui -- cgit v1.2.3 From bde7fd6367ced76dd35bfc3e14e0d375b39998f4 Mon Sep 17 00:00:00 2001 From: Kyungwook Tak Date: Mon, 2 Jan 2017 13:45:43 +0900 Subject: Hide some members from popup class hypertext object, button object and some related setters can be hided as private in popup class. It's provided as setButtons function with button parameter which contains text and return type. Related resource(types, hypertext string) are managed internally in popup class. Change-Id: I3264db77b4c29ae409bb7d928473bf7a74930fac Signed-off-by: Kyungwook Tak --- src/framework/ui/popup/logic.cpp | 144 +++++++++++---------------------------- src/framework/ui/popup/popup.cpp | 59 ++++++++-------- src/framework/ui/popup/popup.h | 60 ++++++++-------- 3 files changed, 103 insertions(+), 160 deletions(-) diff --git a/src/framework/ui/popup/logic.cpp b/src/framework/ui/popup/logic.cpp index 7cb5999..5b1a135 100644 --- a/src/framework/ui/popup/logic.cpp +++ b/src/framework/ui/popup/logic.cpp @@ -57,7 +57,7 @@ void split(const std::string &s, std::string &fileName, std::string &extraPath) extraPath = s.substr(0, idx); } -std::string formatToString(const char *form, std::string arg) +std::string formatToString(const char *form, const std::string &arg) { std::vector buf(PATH_MAX, '\0'); snprintf(buf.data(), buf.size(), form, arg.c_str()); @@ -70,26 +70,18 @@ void Logic::csPromptData(const std::string &message, const CsDetected &d) std::string risk(d.severity == CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); - m_popup.setButtons(2); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(CS_TITLE); m_popup.setHeader(CS_PROMPT_DATA_HEADER); m_popup.setBody(FORMAT( "- " << LABEL_RISK << risk << " (" << d.malwareName << ")")); m_popup.setFooter(CS_PROMPT_DATA_FOOTER); + m_popup.setDetailedUrl(d.detailedUrl); - m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); - m_popup.setText(m_popup.m_buttons[1], BTN_OPEN); - - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); - m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_OPEN, CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)}); } void Logic::csPromptFile(const std::string &message, const CsDetected &d) @@ -99,8 +91,7 @@ void Logic::csPromptFile(const std::string &message, const CsDetected &d) std::string fileName, extraPath; split(d.targetName, fileName, extraPath); - m_popup.setButtons(3); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(CS_TITLE); m_popup.setHeader(CS_PROMPT_FILE_HEADER); @@ -110,22 +101,12 @@ void Logic::csPromptFile(const std::string &message, const CsDetected &d) "- " << LABEL_RISK << risk << " (" << d.malwareName << ")")); std::string prefix(CS_NOTIFY_FILE_FOOTER); m_popup.setFooter(FORMAT(prefix << "
" << CS_PROMPT_FILE_FOOTER)); + m_popup.setDetailedUrl(d.detailedUrl); - m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); - m_popup.setText(m_popup.m_buttons[1], BTN_OPEN); - m_popup.setText(m_popup.m_buttons[2], BTN_DELETE); - - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_REMOVE)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); - m_popup.callbackRegister(m_popup.m_buttons[2], &m_popup.m_types[2]); - m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_OPEN, CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED), + Popup::Button(BTN_DELETE, CSR_CS_USER_RESPONSE_REMOVE)}); } void Logic::csPromptApp(const std::string &message, const CsDetected &d) @@ -134,8 +115,7 @@ void Logic::csPromptApp(const std::string &message, const CsDetected &d) CSR_CS_SEVERITY_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); PackageInfo info(d.pkgId); - m_popup.setButtons(3); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(CS_TITLE); m_popup.setHeader(CS_PROMPT_APP_HEADER); @@ -146,28 +126,17 @@ void Logic::csPromptApp(const std::string &message, const CsDetected &d) m_popup.setIcon(info.getIconPath()); std::string prefix = formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL); m_popup.setFooter(FORMAT(prefix << "
" << CS_PROMPT_APP_FOOTER)); + m_popup.setDetailedUrl(d.detailedUrl); - m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); - m_popup.setText(m_popup.m_buttons[1], BTN_OPEN); - m_popup.setText(m_popup.m_buttons[2], BTN_UNINSTALL); - - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_REMOVE)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); - m_popup.callbackRegister(m_popup.m_buttons[2], &m_popup.m_types[2]); - m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_OPEN, CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED), + Popup::Button(BTN_UNINSTALL, CSR_CS_USER_RESPONSE_REMOVE)}); } void Logic::csNotifyData(const std::string &message, const CsDetected &d) { - m_popup.setButtons(1); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(CS_TITLE); m_popup.setHeader(CS_NOTIFY_DATA_HEADER); @@ -175,22 +144,18 @@ void Logic::csNotifyData(const std::string &message, const CsDetected &d) "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); m_popup.setFooter(CS_NOTIFY_DATA_FOOTER); + m_popup.setDetailedUrl(d.detailedUrl); - m_popup.setText(m_popup.m_buttons[0], BTN_OK); - - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); + m_popup.setButtons({ + Popup::Button(BTN_OK, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)}); } void Logic::csNotifyFile(const std::string &message, const CsDetected &d) { - m_popup.setButtons(2); std::string fileName, extraPath; split(d.targetName, fileName, extraPath); + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(CS_TITLE); m_popup.setHeader(CS_NOTIFY_FILE_HEADER); @@ -200,26 +165,18 @@ void Logic::csNotifyFile(const std::string &message, const CsDetected &d) "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); m_popup.setFooter(CS_NOTIFY_FILE_FOOTER); + m_popup.setDetailedUrl(d.detailedUrl); - m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); - m_popup.setText(m_popup.m_buttons[1], BTN_DELETE); - - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_REMOVE)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); - m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_DELETE, CSR_CS_USER_RESPONSE_REMOVE)}); } void Logic::csNotifyApp(const std::string &message, const CsDetected &d) { PackageInfo info(d.pkgId); - m_popup.setButtons(2); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(CS_TITLE); m_popup.setHeader(CS_NOTIFY_APP_HEADER); @@ -229,18 +186,11 @@ void Logic::csNotifyApp(const std::string &message, const CsDetected &d) LABEL_VERSION << info.getVersion() << "
" << LABEL_RISK << LABEL_RISK_LEVEL_HIGH << " (" << d.malwareName << ")")); m_popup.setFooter(formatToString(CS_NOTIFY_APP_FOOTER, BTN_UNINSTALL)); + m_popup.setDetailedUrl(d.detailedUrl); - m_popup.setText(m_popup.m_buttons[0], BTN_CANCEL); - m_popup.setText(m_popup.m_buttons[1], BTN_UNINSTALL); - - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_CS_USER_RESPONSE_PROCESSING_ALLOWED)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); - m_popup.callbackRegister(m_popup.m_hypertext, d.detailedUrl); + m_popup.setButtons({ + Popup::Button(BTN_CANCEL, CSR_CS_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_UNINSTALL, CSR_CS_USER_RESPONSE_REMOVE)}); } void Logic::wpPrompt(const std::string &message, const UrlItem &item) @@ -248,8 +198,7 @@ void Logic::wpPrompt(const std::string &message, const UrlItem &item) std::string risk(item.risk == CSR_WP_RISK_LOW ? LABEL_RISK_LEVEL_LOW : LABEL_RISK_LEVEL_MEDIUM); - m_popup.setButtons(2); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(WP_TITLE); m_popup.setHeader(WP_PROMPT_HEADER); @@ -257,24 +206,16 @@ void Logic::wpPrompt(const std::string &message, const UrlItem &item) "- " << formatToString(LABEL_URL, item.url) << "
" << "- " << LABEL_RISK << risk)); m_popup.setFooter(WP_PROMPT_FOOTER); + m_popup.setDetailedUrl(item.url); - m_popup.setText(m_popup.m_buttons[0], BTN_BLOCK); - m_popup.setText(m_popup.m_buttons[1], BTN_VIEW); - - m_popup.m_types.emplace_back( - static_cast(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); - m_popup.m_types.emplace_back( - static_cast(CSR_WP_USER_RESPONSE_PROCESSING_ALLOWED)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_buttons[1], &m_popup.m_types[1]); - m_popup.callbackRegister(m_popup.m_hypertext, item.url); + m_popup.setButtons({ + Popup::Button(BTN_BLOCK, CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED), + Popup::Button(BTN_VIEW, CSR_WP_USER_RESPONSE_PROCESSING_ALLOWED)}); } void Logic::wpNotify(const std::string &message, const UrlItem &item) { - m_popup.setButtons(1); - + m_popup.reset(); m_popup.setMessage(message); m_popup.setTitle(WP_TITLE); m_popup.setHeader(WP_NOTIFY_HEADER); @@ -282,13 +223,10 @@ void Logic::wpNotify(const std::string &message, const UrlItem &item) "- " << formatToString(LABEL_URL, item.url) << "
" << "- " << LABEL_RISK << LABEL_RISK_LEVEL_HIGH)); m_popup.setFooter(WP_NOTIFY_FOOTER); + m_popup.setDetailedUrl(item.url); - m_popup.setText(m_popup.m_buttons[0], BTN_OK); - - m_popup.m_types.emplace_back(static_cast(CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)); - - m_popup.callbackRegister(m_popup.m_buttons[0], &m_popup.m_types[0]); - m_popup.callbackRegister(m_popup.m_hypertext, item.url); + m_popup.setButtons({ + Popup::Button(BTN_OK, CSR_WP_USER_RESPONSE_PROCESSING_DISALLOWED)}); } } // namespace Ui } // namespace Csr diff --git a/src/framework/ui/popup/popup.cpp b/src/framework/ui/popup/popup.cpp index 844f1fb..7c8d3ec 100644 --- a/src/framework/ui/popup/popup.cpp +++ b/src/framework/ui/popup/popup.cpp @@ -50,9 +50,10 @@ void Popup::setSender(Sender &&sender) Popup::Popup() : m_win(nullptr) { + ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keyDownCb, this); } -void Popup::setButtons(int n) +void Popup::reset() { clear(); @@ -67,7 +68,6 @@ void Popup::setButtons(int n) setRotationToWin(m_win); eext_win_keygrab_set(m_win, HOME_KEY.c_str()); - ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keyDownCb, this); // Set popup properties. m_popup = elm_popup_add(m_win); @@ -116,21 +116,11 @@ void Popup::setButtons(int n) elm_box_pack_end(m_box, m_footer); evas_object_show(m_footer); - // Add buttons dynamically. m_btnBox = elm_box_add(m_popup); setDefaultProperties(m_btnBox); elm_box_horizontal_set(m_btnBox, EINA_TRUE); elm_box_padding_set(m_btnBox, 0, 0); - for (int i = 0; i < n; ++i) { - Evas_Object *button = elm_button_add(m_popup); - elm_object_style_set(button, "bottom"); - setDefaultProperties(button); - elm_box_pack_end(m_btnBox, button); - evas_object_show(button); - m_buttons.emplace_back(button); - } - elm_box_pack_end(m_box, m_btnBox); evas_object_show(m_btnBox); @@ -146,6 +136,23 @@ Popup::~Popup() evas_object_del(m_win); } +void Popup::setButtons(const std::vector &buttons) +{ + for (auto &button : buttons) { + Evas_Object *obj = elm_button_add(m_btnBox); + + elm_object_style_set(obj, "bottom"); + setDefaultProperties(obj); + + setText(obj, button.text); + m_buttonTypeMap[obj] = button.type; + evas_object_smart_callback_add(obj, "clicked", btnClickedCb, this); + + elm_box_pack_end(m_btnBox, obj); + evas_object_show(obj); + } +} + void Popup::setHeader(const std::string &header) noexcept { setText(m_header, header); @@ -215,20 +222,15 @@ void Popup::setText(Evas_Object *obj, const std::string &text) noexcept elm_object_text_set(obj, text.c_str()); } -void Popup::callbackRegister(Evas_Object *obj, int *type) -{ - m_buttonSelectorMap[obj] = [type]() { return *type; }; - evas_object_smart_callback_add(obj, "clicked", btnClickedCb, this); -} - -void Popup::callbackRegister(Evas_Object *obj, const std::string &url) +void Popup::setDetailedUrl(const std::string &url) { if (url.empty()) - evas_object_smart_callback_add( - obj, "anchor,clicked", hypertextClickedCb, &DEFAULT_URL); + m_hypertextUrl = DEFAULT_URL; else - evas_object_smart_callback_add( - obj, "anchor,clicked", hypertextClickedCb, &url); + m_hypertextUrl = url; + + evas_object_smart_callback_add( + m_hypertext, "anchor,clicked", hypertextClickedCb, this); } void Popup::rotationChangedCb(void *data, Evas_Object *, void *) @@ -258,8 +260,12 @@ void Popup::rotationChangedCb(void *data, Evas_Object *, void *) void Popup::hypertextClickedCb(void *data, Evas_Object *, void *) { DEBUG("Launch browser for detailed url."); + auto popup = reinterpret_cast(data); + if (popup == nullptr) + throw std::invalid_argument("Popup instance is null in static callback"); + + auto &url = popup->m_hypertextUrl; - std::string url = *(reinterpret_cast(data)); std::unique_ptr ac(new AppControl); auto ret = app_control_set_operation(ac->handle, APP_CONTROL_OPERATION_VIEW); @@ -287,7 +293,7 @@ void Popup::btnClickedCb(void *data, Evas_Object *obj, void *) if (popup == nullptr) throw std::invalid_argument("Popup instance is null in static btnClickedCb"); - response = popup->m_buttonSelectorMap.at(obj)(); + response = popup->m_buttonTypeMap.at(obj); popup->terminateWindow(); } @@ -322,8 +328,7 @@ void Popup::clear() m_win = nullptr; } - m_buttons.clear(); - m_types.clear(); + m_buttonTypeMap.clear(); } } // namespace Ui diff --git a/src/framework/ui/popup/popup.h b/src/framework/ui/popup/popup.h index 821c7ec..b60bfc7 100644 --- a/src/framework/ui/popup/popup.h +++ b/src/framework/ui/popup/popup.h @@ -38,65 +38,64 @@ namespace Csr { namespace Ui { /* - * -------------------- - * | title | - * ========box========= - * | content(header) | - * |------subBox------| - * |icon|content(body)| - * |------------------| - * | -hypertext | - * | | - * | content(footer) | - * ==================== - * |------btnBox------| - * | button(N) | - * -------------------- + * ------------------------ + * | title | + * |==========box=========| + * || content(header) || + * ||-------subBox-------|| + * |||icon|content(body)||| + * ||--------------------|| + * || -hypertext || + * || content(footer) || + * ||-------btnBox-------|| + * ||| button(N) ||| + * ||--------------------|| + * |======================| */ class Popup { public: - Popup(); - virtual ~Popup(); + struct Button { + Button(const char *text, int type) : text(text), type(type) {} - void setButtons(int n); + const char *text; + int type; + }; - RawBuffer getResult(void); - void setMessage(const std::string &msg) noexcept; + Popup(); + virtual ~Popup(); Popup(const Popup &) = delete; Popup &operator=(const Popup &) = delete; Popup(Popup &&) = delete; Popup &operator=(Popup &&) = delete; + void reset(); + using Sender = std::function; void setSender(Sender &&sender); + void setMessage(const std::string &msg) noexcept; void setTitle(const std::string &title) noexcept; void setHeader(const std::string &header) noexcept; void setBody(const std::string &body) noexcept; void setFooter(const std::string &footer) noexcept; void setIcon(const std::string &path) noexcept; - void setText(Evas_Object *obj, const std::string &text) noexcept; - - void callbackRegister(Evas_Object *obj, int *type); - void callbackRegister(Evas_Object *obj, const std::string &url); - static Eina_Bool keyDownCb(void *, int, void *); - - std::vector m_buttons; - Evas_Object *m_hypertext; - std::vector m_types; + void setDetailedUrl(const std::string &url); + void setButtons(const std::vector