From: Jan Cybulski Date: Tue, 14 Jul 2015 09:38:19 +0000 (+0200) Subject: USD: Add dbus thread X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=caefacf9b870d12246b573709ebd06026593c6ab;p=platform%2Fcore%2Fapi%2Fusb-host.git USD: Add dbus thread Add class for maintaining thread needed for dbus main loop. Dbus communication is needed because popup mechanism used this IPC. Change-Id: Ifd5c34dac3144906d156ad14e151f0684bfa790f Signed-off-by: Jan Cybulski Signed-off-by: Stanislaw Wadas --- diff --git a/USD/src/CMakeLists.txt b/USD/src/CMakeLists.txt index ecad22b..223adfc 100644 --- a/USD/src/CMakeLists.txt +++ b/USD/src/CMakeLists.txt @@ -2,6 +2,7 @@ PKG_CHECK_MODULES(USD_DEP dlog libsmack libsystemd-daemon + dbus-1 REQUIRED ) @@ -14,6 +15,9 @@ SET(USD_SOURCES ${SERVER2_PATH}/main/socket-manager.cpp ${SERVER2_PATH}/main/server2-main.cpp ${SERVER2_PATH}/service/usb-access.cpp + ${SERVER2_PATH}/main/dbus-manager.cpp + ${SERVER2_PATH}/client/usb-access-client.cpp + ${SERVER2_PATH}/client/client-common.cpp ) SET_SOURCE_FILES_PROPERTIES( diff --git a/USD/src/client/client-common.cpp b/USD/src/client/client-common.cpp index 8d57fd8..b0ce9c6 100644 --- a/USD/src/client/client-common.cpp +++ b/USD/src/client/client-common.cpp @@ -37,9 +37,9 @@ #include #include - +/* IMPLEMENT_SAFE_SINGLETON(USD::Log::LogSystem); - +*/ namespace { const int POLL_TIMEOUT = 2000; diff --git a/USD/src/common/usb-access-map.cpp b/USD/src/common/usb-access-map.cpp index 97a5922..ae95162 100644 --- a/USD/src/common/usb-access-map.cpp +++ b/USD/src/common/usb-access-map.cpp @@ -148,6 +148,12 @@ const std::string &USBDevicePath::getSysFSPath() const return m_sysPath; } +const std::string &USBDevicePath::getTopology() const +{ + //todo get topology! + return m_sysPath; +} + dev_t USBDevicePath::getDev() const { return m_dev; diff --git a/USD/src/common/usb-access-map.h b/USD/src/common/usb-access-map.h index 5f7be9c..65d06a4 100644 --- a/USD/src/common/usb-access-map.h +++ b/USD/src/common/usb-access-map.h @@ -46,6 +46,7 @@ public: /* Never call this constructor with SysFS path received from user! */ USBDevicePath(const std::string &path, PathType path_type); const std::string &getSysFSPath() const; + const std::string &getTopology() const; dev_t getDev() const; friend std::ostream &operator<<(std::ostream &stream, @@ -75,6 +76,7 @@ public: friend std::ostream &operator<<(std::ostream &stream, const USBDeviceId &id); + const char *getTopology() {return m_path.getTopology().c_str();} private: void initDevId(const std::string &sys_path); @@ -117,6 +119,7 @@ public: friend std::ostream& operator<<(std::ostream& stream, const PolicySubjectId& id); + const char *getAppData() {return m_smk.c_str();} private: std::string m_smk; @@ -136,6 +139,8 @@ public: bool operator==(const USBAccessMapKey &r) const; friend std::ostream& operator<<(std::ostream& stream, const USBAccessMapKey& key); + const char* getDeviceTopology() {return m_device.getTopology();} + const char* getAppData() {return m_subject.getAppData();} private: PolicySubjectId m_subject; diff --git a/USD/src/main/dbus-manager.cpp b/USD/src/main/dbus-manager.cpp new file mode 100644 index 0000000..8c2a852 --- /dev/null +++ b/USD/src/main/dbus-manager.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Karol Lewandowski + * + * 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 dbus-manager.cpp + * @author Jan Cybulski + * @version 1.0 + * @brief Implementation of dbus communication threads. + */ + + +#include "dbus-manager.h" +#include +#include +#include +#include + + +#include +#include +#include + + +namespace USD { + +#define USD_USB_DEVICE_CONFIRM_SIGNAL "USBDeviceOpenResult" +#define USD_INTERFACE "org.tizen.system.usd" +#define USD_PATH "/Org/Tizen/System/USD" + +#define DEST_NAME "org.tizen.system.popup" +#define DEST_IFACE "org.tizen.system.popup.System" +#define DEST_PATH "/Org/Tizen/System/Popup/System" +#define DEST_METHOD "PopupLaunch" + +const std::string CONTENT = "_SYSPOPUP_CONTENT_"; +const std::string POPUP_NAME = "usb_device_confirm"; + + +//#define BUS_TYPE (DBUS_BUS_SESSION) +#define BUS_TYPE (DBUS_BUS_SYSTEM) + + +enum button_selected_e { + USB_DEVICE_CONFIRM_OK, + USB_DEVICE_CONFIRM_NOK, + }; + +int done; +int get_sender_pid(DBusConnection *conn, const char *sender); + +static DBusHandlerResult filter_func(DBusConnection *conn, + DBusMessage *msg, + void *data) +{ + DBusError err; + dbus_bool_t handled = FALSE; + int result = 0; + DbusManager *pDM = (DbusManager *)data; + + LogError("filter_func"); + + if (dbus_message_is_signal(msg, USD_INTERFACE, USD_USB_DEVICE_CONFIRM_SIGNAL)) + { + dbus_error_init(&err); + dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&err)) + { + LogError("dbus_message_get_args failed: " << err.message); + dbus_error_free(&err); + handled = TRUE; + //handle error? + } + else + { + + int recv_pid = get_sender_pid(conn, dbus_message_get_sender(msg)); + handled = pDM->handlePopup(recv_pid, result); + LogDebug("Popup sender pid:" << recv_pid); + + } + } + + return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED); +} + +int add_dict_entries(DBusMessage *msg, const char *str1, const char *str2) +{ + DBusMessageIter args, array_iter, dict_iter; + dbus_message_iter_init_append(msg, &args); + + if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &array_iter)) + return 0; + + if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter)) + return 0; + + if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &str1)) + return 0; + + if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &str2)) + return 0; + + if (!dbus_message_iter_close_container(&array_iter, &dict_iter)) + return 0; + + if (!dbus_message_iter_close_container(&args, &array_iter)) + return 0; + return 1; +} + +int get_sender_pid(DBusConnection *conn, const char *sender) +{ + int pid = 0; + DBusMessage *msg = NULL, *reply = NULL; + DBusError err; + + if (!conn || !sender) + goto cleanup; + + msg = dbus_message_new_method_call("org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID"); + if (msg == NULL) + goto cleanup; + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &sender, DBUS_TYPE_INVALID); + + dbus_error_init(&err); + reply = dbus_connection_send_with_reply_and_block(conn, msg, 1000, &err); + if (dbus_error_is_set(&err)) + { + LogError("dbus_connection_send_with_reply_and_block: " << err.message); + dbus_error_free(&err); + goto cleanup; + } + + dbus_message_get_args(reply, &err, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&err)) + { + LogError("dbus_message_get_args: " << err.message); + dbus_error_free(&err); + goto cleanup; + } + + cleanup: + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + return pid; +} + +int request_popup(DBusConnection *conn, PopupData dp) +{ + int pid = 0; + DBusMessage *msg = NULL, *reply = NULL; + DBusError err; + (void) dp;/* This should be used to present user with proper data. + As for now popup mechanism does not provide functionality allowing to pass + additional data to popup to be displayed. Popup prints fixed text. + We may and should change it later and construct some text out of "dp" + and pass it to popup mechanism.*/ + + if (!conn) + { + LogError("Connection was not setup before"); + goto cleanup; + } + + msg = dbus_message_new_method_call(DEST_NAME, DEST_PATH, DEST_IFACE, DEST_METHOD); + if (!msg) + { + LogError("Method call was not created"); + goto cleanup; + } + + if (!add_dict_entries(msg, CONTENT.c_str(), POPUP_NAME.c_str())) + { + LogError("add_dict_entries failed"); + goto cleanup; + } + + dbus_error_init(&err); + reply = dbus_connection_send_with_reply_and_block(conn, msg, 1000/*one second*/, &err); + if (dbus_error_is_set(&err)) + { + LogError("dbus_connection_send_with_reply_and_block failed " << err.message); + dbus_error_free(&err); + goto cleanup; + } + + dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID); + if (dbus_error_is_set(&err)) + { + LogError("dbus_message_get_args failed: " << err.message); + dbus_error_free(&err); + goto cleanup; + } + + cleanup: + if (msg) + dbus_message_unref(msg); + if (reply) + dbus_message_unref(reply); + LogError("Got answer with pid:" << pid); + return pid; +} + +DbusManager::DbusManager(): m_state(State::NoThread), m_quit(false){;} + +void DbusManager::Create() { + LogDebug("Creating dbus thread"); + assert(m_state == State::NoThread); + m_conn = setupDbusConnection(); + if (!m_conn) { + LogError("Could not setup Dbus Connection"); + throw -1; //TODO + } + m_thread = std::thread(ThreadLoopStatic, this); + m_state = State::Work; +} + +void DbusManager::notifyPopupHandled(pid_t pid) { + LogDebug("Got popup answer notify"); + m_popupHandleMutex.lock(); + this->m_popupMap.erase(pid); + m_popupHandleMutex.unlock(); +} + +bool DbusManager::waitForPopupHandled(pid_t popup_pid) { + int delay = 50; + while (delay > 0) { + delay--; + LogDebug("Waiting for popup, popup pid: " << popup_pid); + { + std::lock_guard lock(m_popupHandleMutex); + if(this->m_popupMap.find(popup_pid) == m_popupMap.end()) { + return true; + } + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + return false; +} + + +bool DbusManager::handlePopup(pid_t pid, int popupResult) { + std::lock_guard lock(m_popupHandleMutex); + + //PopupData *popupData; + auto it = m_popupMap.find(pid); + if (it != m_popupMap.end()) { + //popupData = &*it; + const char *device = getPopupDevice(pid); + const char *application = getPopupApp(pid); + bool allow = (popupResult == USB_DEVICE_CONFIRM_OK); + LogDebug("Got popup answer notify from pid" << pid); + this->m_popupMap.erase(pid); + usd_setup_usb_device_access(device, application, allow); + return true; + } + LogWarning("Someone tries to fake popup answer data... "); + return false; + +} + +void DbusManager::Join() { + LogDebug("Joining dbus thread"); + assert(m_state != State::NoThread); + { + std::lock_guard lock(m_popupHandleMutex); + m_quit = true; + m_state = State::NoThread; + + } + m_thread.join(); + LogDebug("Joined dbus thread"); + +} + +DBusConnection* DbusManager::setupDbusConnection() +{ + DBusError err; + DBusConnection *conn; + + + dbus_error_init(&err); + conn = dbus_bus_get(BUS_TYPE, &err); + if (dbus_error_is_set(&err)) + { + LogError("Could not get bus" << err.message); + dbus_error_free(&err); + + return NULL; + } + assert(conn != NULL); + LogDebug("Bus obtained"); + + dbus_bus_add_match(conn, + "type='signal',interface='" USD_INTERFACE "'", + &err); + if (dbus_error_is_set(&err)) + { + dbus_error_free(&err); + LogError("Could not add match"); + return NULL; + } + LogDebug("Match added"); + + if (!dbus_connection_add_filter(conn, filter_func, this, NULL)) + { + LogError("Could not add filter"); + return NULL; + } + LogDebug("Filter added"); + return conn; +} + + +pid_t DbusManager::addPopupRequest(const PopupData &popupData) +{ + LogDebug("Pushing popup request " << popupData); + std::lock_guard lock(m_eventQueueMutex); + pid_t newPopupPid = request_popup(this->m_conn, popupData); + m_popupMap.insert(std::pair(newPopupPid, popupData)); + return newPopupPid; + +} + +const char *DbusManager::getPopupDevice(pid_t pid) { + return m_popupMap.at(pid).getDeviceTopology(); +} +const char *DbusManager::getPopupApp(pid_t pid) { + return m_popupMap.at(pid).getAppData(); +} + +void DbusManager::ThreadLoop() { + for (;;) { + + { + std::lock_guard lock(m_eventQueueMutex); + if (m_quit) { + LogDebug("Quitting dbus loop"); + return; + } + } + dbus_connection_read_write_dispatch(m_conn, 100); + + } +} + + +}/*namespace usd*/ diff --git a/USD/src/main/dbus-manager.h b/USD/src/main/dbus-manager.h new file mode 100644 index 0000000..f69c746 --- /dev/null +++ b/USD/src/main/dbus-manager.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Karol Lewandowski + * + * 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 dbus-manager.h + * @author Jan Cybulski + * @version 1.0 + * @brief Header for dbus communication threads classes. + */ + +#ifndef _DBUS_MANAGER_H_ +#define _DBUS_MANAGER_H_ + + +#include +#include +#include +#include +#include +#include + +namespace USD { + +typedef USBAccessMapKey PopupData; + + +class DbusManager{ +public: + pid_t addPopupRequest(const PopupData &popupData); + const char *getPopupDevice(pid_t pid); + const char *getPopupApp(pid_t pid); + + enum class State { + NoThread, + Work, + Wait, + }; + + DbusManager(); + void Create(); + void Join(); + virtual ~DbusManager() + { + if (m_state != State::NoThread) + Join(); + } + + void notifyPopupHandled(pid_t pid); + bool waitForPopupHandled(pid_t pid); + bool isPidActivePopup(pid_t pid); + bool handlePopup(pid_t pid, int popupResult); + + protected: + std::mutex m_popupHandleMutex; + DBusConnection *m_conn; + std::thread m_thread; + std::mutex m_eventQueueMutex; + + + // std::condition_variable m_waitCondition; + std::map m_popupMap; + std::queue m_popupQueue; + State m_state; + bool m_quit; + + DBusConnection* setupDbusConnection(); + static void ThreadLoopStatic(DbusManager *ptr) { ptr->ThreadLoop(); } + void ThreadLoop(); +}; + +} + + +#endif /*_DBUS_MANAGER_H_*/ diff --git a/USD/src/main/server2-main.cpp b/USD/src/main/server2-main.cpp index 3429abb..0431c3f 100644 --- a/USD/src/main/server2-main.cpp +++ b/USD/src/main/server2-main.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include @@ -60,6 +62,9 @@ void registerSocketService(USD::SocketManager &manager, const std::string& servi delete service; } + +USD::DbusManager dbusmanager; + int main(void) { UNHANDLED_EXCEPTION_HANDLER_BEGIN @@ -78,9 +83,13 @@ int main(void) { LogInfo("Start!"); USD::SocketManager manager; - REGISTER_SOCKET_SERVICE(manager, USD::USBAccessService); + REGISTER_SOCKET_SERVICE(manager, USD::USBAccessService); + dbusmanager.Create(); manager.MainLoop(); + dbusmanager.Join(); + LogDebug("Quit"); + } UNHANDLED_EXCEPTION_HANDLER_END return 0; diff --git a/USD/src/main/socket-manager.cpp b/USD/src/main/socket-manager.cpp index 935635c..fa073b4 100644 --- a/USD/src/main/socket-manager.cpp +++ b/USD/src/main/socket-manager.cpp @@ -391,6 +391,10 @@ void SocketManager::MainLoop() { int ret = select(m_maxDesc+1, &readSet, &writeSet, NULL, ptrTimeout); if (0 == ret) { // timeout + if (m_timeoutQueue.empty()) { + LogError("would abort"); + continue; + } Assert(!m_timeoutQueue.empty()); Timeout pqTimeout = m_timeoutQueue.top(); diff --git a/packaging/capi-system-usbhost.spec b/packaging/capi-system-usbhost.spec index 1e08622..870aeae 100644 --- a/packaging/capi-system-usbhost.spec +++ b/packaging/capi-system-usbhost.spec @@ -20,6 +20,7 @@ BuildRequires: libcap-devel BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(libsystemd-daemon) BuildRequires: pkgconfig(libsystemd-journal) +BuildRequires: pkgconfig(dbus-1) %{?systemd_requires} %description