From 258956da72a4fb2899defa7ed589648c4345020a Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 20 Feb 2017 18:28:18 +0900 Subject: [PATCH 01/16] Switch to single-threading if only one service is supported Change-Id: If650d3f9a51cf13725de1f987820d97b51006519 Signed-off-by: Mu-Woong Lee --- src/ServiceLoader.cpp | 18 ++++++++++++++---- src/ServiceLoader.h | 6 +----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/ServiceLoader.cpp b/src/ServiceLoader.cpp index ec5e6f8..44fe578 100644 --- a/src/ServiceLoader.cpp +++ b/src/ServiceLoader.cpp @@ -31,10 +31,20 @@ ServiceLoader::ServiceLoader() bool ServiceLoader::load(GDBusConnection* conn) { - //__load(conn); - __load(conn); - __load(conn); - //__load(conn); + //__create(conn); + __create(conn); + __create(conn); + //__create(conn); + + if (__services.size() == 1) { + _I("Switch to single-threading"); + ServiceBase::setSingleThreading(); + } + + for (auto& svc : __services) { + if (!svc->start()) + return false; + } return !__services.empty(); } diff --git a/src/ServiceLoader.h b/src/ServiceLoader.h index ca87135..2819d0f 100644 --- a/src/ServiceLoader.h +++ b/src/ServiceLoader.h @@ -33,7 +33,7 @@ namespace ctx { static std::vector __services; - template static void __load(GDBusConnection* conn) + template static void __create(GDBusConnection* conn) { ServiceBase *svc = NULL; try { @@ -42,10 +42,6 @@ namespace ctx { _W("Service creation failed (%s)", e.what()); return; } - if (!svc->start()) { - delete svc; - return; - } __services.push_back(svc); } }; -- 2.7.4 From e61f29382c810b472556eb7a24aea23ad9808941 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 20 Feb 2017 18:44:34 +0900 Subject: [PATCH 02/16] Change the service restart option to on-failure Change-Id: I09b44f38c8d2f7db496d9807d7ad9975800a8823 Signed-off-by: Mu-Woong Lee --- packaging/context-service.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/context-service.service b/packaging/context-service.service index 22abc35..e5f2f31 100644 --- a/packaging/context-service.service +++ b/packaging/context-service.service @@ -7,7 +7,7 @@ Group=service_fw Type=dbus BusName=org.tizen.context ExecStart=/usr/bin/contextd -Restart=always +Restart=on-failure RestartSec=1 [Install] -- 2.7.4 From 4056fb4f17c7bc86738161fdce724ef477f1ccc3 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Fri, 3 Mar 2017 20:07:23 +0900 Subject: [PATCH 03/16] Selectively stop and restart the individual service when the active user changes Change-Id: I2a59124125ba4b6b20612f525aa56d93c1d78e80 Signed-off-by: Mu-Woong Lee --- CMakeLists.txt | 2 +- packaging/context-service.spec | 1 + src/ActiveUserMonitor.cpp | 129 +++++++++++++++++++++++++++++++++++++++++ src/ActiveUserMonitor.h | 56 ++++++++++++++++++ src/Main.cpp | 74 +++++++++++++++-------- src/ServiceLoader.cpp | 69 ++++++++++++++++++---- src/ServiceLoader.h | 25 +++++--- 7 files changed, 312 insertions(+), 44 deletions(-) create mode 100644 src/ActiveUserMonitor.cpp create mode 100644 src/ActiveUserMonitor.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e00aed2..04043ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ INCLUDE(GNUInstallDirs) SET(target "contextd") -SET(DEPS "glib-2.0 gio-2.0 dlog capi-base-common alarm-service") +SET(DEPS "libsystemd-login glib-2.0 gio-2.0 dlog capi-base-common alarm-service") SET(DEPS "${DEPS} context-common-server") SET(DEPS "${DEPS} sensor-recorder-server") SET(DEPS "${DEPS} context-store-server") diff --git a/packaging/context-service.spec b/packaging/context-service.spec index 6b7080c..ba0d993 100644 --- a/packaging/context-service.spec +++ b/packaging/context-service.spec @@ -9,6 +9,7 @@ Source1: context-service.service Source2: org.tizen.context.conf BuildRequires: cmake +BuildRequires: pkgconfig(libsystemd-login) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(gio-2.0) BuildRequires: pkgconfig(dlog) diff --git a/src/ActiveUserMonitor.cpp b/src/ActiveUserMonitor.cpp new file mode 100644 index 0000000..4571c08 --- /dev/null +++ b/src/ActiveUserMonitor.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "ActiveUserMonitor.h" + +#define ROOT_UID 0 + +using namespace ctx; + +ActiveUserMonitor::ActiveUserMonitor() : + __connection(NULL), + __activateUser(NULL), + __deactivateUser(NULL), + __activeUid(ROOT_UID), + __userNewSignalId(0), + __userRemovedSignalId(0) +{ +} + +ActiveUserMonitor::~ActiveUserMonitor() +{ +} + +void ActiveUserMonitor::start(GDBusConnection* conn, uid_cb_t activateUser, uid_cb_t deactivateUser) +{ + __connection = conn; + __activateUser = activateUser; + __deactivateUser = deactivateUser; + + __userNewSignalId = g_dbus_connection_signal_subscribe(__connection, + NULL, "org.freedesktop.login1.Manager", "UserNew", NULL, + NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserNew, this, NULL); + + __userRemovedSignalId = g_dbus_connection_signal_subscribe(__connection, + NULL, "org.freedesktop.login1.Manager", "UserRemoved", NULL, + NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserRemoved, this, NULL); + + g_idle_add(__checkCurrentUser, this); +} + +void ActiveUserMonitor::stop() +{ + g_dbus_connection_signal_unsubscribe(__connection, __userNewSignalId); + g_dbus_connection_signal_unsubscribe(__connection, __userRemovedSignalId); +} + +void ActiveUserMonitor::__onUserNew(GDBusConnection* conn, const gchar* sender, + const gchar* path, const gchar* iface, const gchar* name, + GVariant* param, gpointer userData) +{ + uint32_t uid = 0; + g_variant_get_child(param, 0, "u", &uid); + IF_FAIL_VOID_TAG(uid > 0, _W, "UID == 0"); + + _D("UID: %u", uid); + + ActiveUserMonitor* monitor = static_cast(userData); + + if (monitor->__activeUid == uid) + return; + + if (monitor->__activeUid > ROOT_UID) { + _W("Over-activation of the user %u", uid); + monitor->__deactivateUser(monitor->__activeUid); + } + + monitor->__activateUser(uid); + monitor->__activeUid = uid; +} + +void ActiveUserMonitor::__onUserRemoved(GDBusConnection* conn, const gchar* sender, + const gchar* path, const gchar* iface, const gchar* name, + GVariant* param, gpointer userData) +{ + uint32_t uid = 0; + g_variant_get_child(param, 0, "u", &uid); + IF_FAIL_VOID_TAG(uid > 0, _W, "UID == 0"); + + _D("UID: %u", uid); + + ActiveUserMonitor* monitor = static_cast(userData); + + if (monitor->__activeUid == ROOT_UID) { + _W("No active user"); + return; + } + + if (monitor->__activeUid != uid) { + _W("Mismatched uid"); + } + + monitor->__deactivateUser(uid); + monitor->__activeUid = ROOT_UID; +} + +gboolean ActiveUserMonitor::__checkCurrentUser(gpointer userData) +{ + ActiveUserMonitor* monitor = static_cast(userData); + IF_FAIL_RETURN(monitor->__activeUid == ROOT_UID, G_SOURCE_REMOVE); + + uid_t* users = NULL; + int numUsers = sd_get_active_uids(&users); + + if (numUsers > 0) + monitor->__activeUid = users[0]; + + g_free(users); + + if (monitor->__activeUid != ROOT_UID) { + _D("UID: %u", monitor->__activeUid); + monitor->__activateUser(monitor->__activeUid); + } + + return G_SOURCE_REMOVE; +} diff --git a/src/ActiveUserMonitor.h b/src/ActiveUserMonitor.h new file mode 100644 index 0000000..f349c85 --- /dev/null +++ b/src/ActiveUserMonitor.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CONTEXT_ACTIVE_USER_MONITOR_H__ +#define __CONTEXT_ACTIVE_USER_MONITOR_H__ + +#include + +namespace ctx { + + class ActiveUserMonitor { + + typedef void (*uid_cb_t)(uid_t); + + public: + ActiveUserMonitor(); + ~ActiveUserMonitor(); + + void start(GDBusConnection* conn, uid_cb_t activateUser, uid_cb_t deactivateUser); + void stop(); + + private: + static void __onUserNew(GDBusConnection* conn, const gchar* sender, + const gchar* path, const gchar* iface, const gchar* name, + GVariant* param, gpointer userData); + + static void __onUserRemoved(GDBusConnection* conn, const gchar* sender, + const gchar* path, const gchar* iface, const gchar* name, + GVariant* param, gpointer userData); + + static gboolean __checkCurrentUser(gpointer userData); + + GDBusConnection* __connection; + uid_cb_t __activateUser; + uid_cb_t __deactivateUser; + uid_t __activeUid; + guint __userNewSignalId; + guint __userRemovedSignalId; + }; + +} + +#endif diff --git a/src/Main.cpp b/src/Main.cpp index dba5144..38c976d 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -20,32 +20,25 @@ #include #include "DBusConnector.h" #include "ServiceLoader.h" +#include "ActiveUserMonitor.h" #include "AlarmInitializer.h" using namespace ctx; namespace { - class Server { + class MainLoop { public: static bool start(); static void stop(); private: - Server() {} + MainLoop() {} static GMainLoop* __mainLoop; }; } -static gboolean __stopService(gpointer data) -{ - _I("Unloading services"); - ServiceLoader::unload(); - ::Server::stop(); - return G_SOURCE_REMOVE; -} +GMainLoop* MainLoop::__mainLoop = NULL; -GMainLoop* ::Server::__mainLoop = NULL; - -bool ::Server::start() +bool MainLoop::start() { __mainLoop = g_main_loop_new(NULL, FALSE); IF_FAIL_RETURN_TAG(__mainLoop, false, _E, "Memory allocation failed"); @@ -58,35 +51,56 @@ bool ::Server::start() return true; } -void ::Server::stop() +void MainLoop::stop() { _I(PURPLE("Terminating...")); g_main_loop_quit(__mainLoop); } +static ServiceLoader __serviceLoader; +static ActiveUserMonitor __activeUserMonitor; static AlarmInitializer __alarmInit; -static void __signalHandler(int signum) +static void __activateUser(uid_t uid) { - _I(YELLOW("SIGNAL-%d: '%s'"), signum, strsignal(signum)); - static bool terminated = false; - if (!terminated) { - g_idle_add(__stopService, NULL); - terminated = true; - } + __serviceLoader.startUser(uid); } -static void __busAcquired(GDBusConnection* conn) +static void __deactivateUser(uid_t uid) +{ + __serviceLoader.stopUser(); +} + +static void __startService(GDBusConnection* conn) { Timer::setDBusConnection(conn); + __activeUserMonitor.start(conn, __activateUser, __deactivateUser); _I("Loading services"); - if (ServiceLoader::load(conn)) { - _I("Service loading successful"); + if (!__serviceLoader.load(conn)) { + _E(RED("No service loaded")); return; } - _E(RED("No service loaded.")); + _I("Service loading successful"); + __serviceLoader.startSystem(); +} + +static gboolean __stopService(gpointer data) +{ + __activeUserMonitor.stop(); + + _I("Unloading services"); + __serviceLoader.stopUser(); + __serviceLoader.stopSystem(); + + MainLoop::stop(); + return G_SOURCE_REMOVE; +} + +static void __busAcquired(GDBusConnection* conn) +{ + __startService(conn); } static void __busLost(GDBusConnection* conn) @@ -94,6 +108,16 @@ static void __busLost(GDBusConnection* conn) __stopService(NULL); } +static void __signalHandler(int signum) +{ + _I(YELLOW("SIGNAL-%d: '%s'"), signum, strsignal(signum)); + static bool terminated = false; + if (!terminated) { + g_idle_add(__stopService, NULL); + terminated = true; + } +} + int main(int argc, char* argv[]) { static struct sigaction signalAction; @@ -108,7 +132,7 @@ int main(int argc, char* argv[]) DBusConnector dbusConnector(__busAcquired, __busLost); - ::Server::start(); + MainLoop::start(); return EXIT_SUCCESS; } diff --git a/src/ServiceLoader.cpp b/src/ServiceLoader.cpp index 44fe578..9f4383a 100644 --- a/src/ServiceLoader.cpp +++ b/src/ServiceLoader.cpp @@ -21,12 +21,23 @@ #include "ServiceLoader.h" +#define ROOT_UID 0 + using namespace ctx; -std::vector ServiceLoader::__services; +ServiceLoader::ServiceLoader() : + __activeUser(ROOT_UID) +{ +} -ServiceLoader::ServiceLoader() +ServiceLoader::~ServiceLoader() { + for (auto& svc : __userServices) { + delete svc; + } + for (auto& svc : __systemServices) { + delete svc; + } } bool ServiceLoader::load(GDBusConnection* conn) @@ -36,24 +47,60 @@ bool ServiceLoader::load(GDBusConnection* conn) __create(conn); //__create(conn); - if (__services.size() == 1) { + if ((__userServices.size() + __systemServices.size()) == 1) { _I("Switch to single-threading"); ServiceBase::setSingleThreading(); } - for (auto& svc : __services) { - if (!svc->start()) - return false; + return (!__systemServices.empty() || !__userServices.empty()); +} + +void ServiceLoader::startSystem() +{ + for (auto& svc : __systemServices) { + svc->start(); } +} - return !__services.empty(); +void ServiceLoader::stopSystem() +{ + for (auto& svc : __systemServices) { + svc->stop(); + } } -void ServiceLoader::unload() +void ServiceLoader::startUser(uid_t uid) { - for (auto& svc : __services) { + IF_FAIL_VOID(__activeUser != uid); + _I("Starting services for %u", static_cast(uid)); + + ServiceBase::setActiveUser(uid); + + for (auto& svc : __userServices) { + svc->start(); + } + + for (auto& svc : __systemServices) { + svc->notifyUserNew(); + } + + __activeUser = uid; +} + +void ServiceLoader::stopUser() +{ + IF_FAIL_VOID(__activeUser != ROOT_UID); + _I("Stopping services for %u", static_cast(__activeUser)); + + for (auto& svc : __userServices) { svc->stop(); - delete svc; } - __services.clear(); + + ServiceBase::setActiveUser(ROOT_UID); + + for (auto& svc : __systemServices) { + svc->notifyUserRemoved(); + } + + __activeUser = ROOT_UID; } diff --git a/src/ServiceLoader.h b/src/ServiceLoader.h index 2819d0f..5bedbb2 100644 --- a/src/ServiceLoader.h +++ b/src/ServiceLoader.h @@ -25,15 +25,22 @@ namespace ctx { class ServiceLoader { public: - static bool load(GDBusConnection* conn); - static void unload(); - - private: ServiceLoader(); + ~ServiceLoader(); + + bool load(GDBusConnection* conn); - static std::vector __services; + void startUser(uid_t uid); + void stopUser(); + void startSystem(); + void stopSystem(); - template static void __create(GDBusConnection* conn) + private: + uid_t __activeUser; + std::vector __userServices; + std::vector __systemServices; + + template void __create(GDBusConnection* conn) { ServiceBase *svc = NULL; try { @@ -42,7 +49,11 @@ namespace ctx { _W("Service creation failed (%s)", e.what()); return; } - __services.push_back(svc); + if (svc->isUserService()) { + __userServices.push_back(svc); + } else { + __systemServices.push_back(svc); + } } }; -- 2.7.4 From 2c43f40899d631b0bf00d574ca233884f29aae40 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 6 Mar 2017 12:45:08 +0900 Subject: [PATCH 04/16] Enable app-history service Change-Id: Idc6d78341a44bd4c98891fe21738b2df5be4d8cc Signed-off-by: Mu-Woong Lee --- CMakeLists.txt | 1 + packaging/context-service.spec | 1 + src/ServiceLoader.cpp | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04043ff..6d7163c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ SET(target "contextd") SET(DEPS "libsystemd-login glib-2.0 gio-2.0 dlog capi-base-common alarm-service") SET(DEPS "${DEPS} context-common-server") +SET(DEPS "${DEPS} app-history-server") SET(DEPS "${DEPS} sensor-recorder-server") SET(DEPS "${DEPS} context-store-server") diff --git a/packaging/context-service.spec b/packaging/context-service.spec index ba0d993..cbe59f8 100644 --- a/packaging/context-service.spec +++ b/packaging/context-service.spec @@ -17,6 +17,7 @@ BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(alarm-service) BuildRequires: pkgconfig(context-common-server) +BuildRequires: pkgconfig(app-history-server) BuildRequires: pkgconfig(sensor-recorder-server) BuildRequires: pkgconfig(context-store-server) diff --git a/src/ServiceLoader.cpp b/src/ServiceLoader.cpp index 9f4383a..fc298ab 100644 --- a/src/ServiceLoader.cpp +++ b/src/ServiceLoader.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -//#include +#include #include #include //#include @@ -42,7 +42,7 @@ ServiceLoader::~ServiceLoader() bool ServiceLoader::load(GDBusConnection* conn) { - //__create(conn); + __create(conn); __create(conn); __create(conn); //__create(conn); -- 2.7.4 From d704ec6368ca8a2af8d3097ca8c18261c1a1bdec Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Tue, 14 Mar 2017 14:05:44 +0900 Subject: [PATCH 05/16] Add a short delay to the active user checking process to be sure that child mainloops are running Change-Id: Iaeda8f61209a14ad57204bb196bbcd208c0233a6 Signed-off-by: Mu-Woong Lee --- src/ActiveUserMonitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ActiveUserMonitor.cpp b/src/ActiveUserMonitor.cpp index 4571c08..7ed9f8e 100644 --- a/src/ActiveUserMonitor.cpp +++ b/src/ActiveUserMonitor.cpp @@ -49,7 +49,7 @@ void ActiveUserMonitor::start(GDBusConnection* conn, uid_cb_t activateUser, uid_ NULL, "org.freedesktop.login1.Manager", "UserRemoved", NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserRemoved, this, NULL); - g_idle_add(__checkCurrentUser, this); + g_timeout_add(200, __checkCurrentUser, this); } void ActiveUserMonitor::stop() -- 2.7.4 From 64140fd5dba798dbb8d94d5f5692b5b4fddd3f86 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Wed, 15 Mar 2017 12:32:51 +0900 Subject: [PATCH 06/16] Remove single-threading option Change-Id: Ibfb15fdcdfab0fa4c21d9b14a5ebf708520f5495 Signed-off-by: Mu-Woong Lee --- src/ServiceLoader.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ServiceLoader.cpp b/src/ServiceLoader.cpp index fc298ab..b41eff4 100644 --- a/src/ServiceLoader.cpp +++ b/src/ServiceLoader.cpp @@ -47,11 +47,6 @@ bool ServiceLoader::load(GDBusConnection* conn) __create(conn); //__create(conn); - if ((__userServices.size() + __systemServices.size()) == 1) { - _I("Switch to single-threading"); - ServiceBase::setSingleThreading(); - } - return (!__systemServices.empty() || !__userServices.empty()); } -- 2.7.4 From 333f0558de4c9875aed37105a9e7e8c3c445fcdf Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Thu, 16 Mar 2017 13:58:07 +0900 Subject: [PATCH 07/16] Sync with the renamed packages of app-history & sensor-recorder Change-Id: I285aaf1a0376cb5dbc613043434e887934bd819e Signed-off-by: Mu-Woong Lee --- CMakeLists.txt | 4 ++-- packaging/context-service.spec | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d7163c..6b85c19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ SET(target "contextd") SET(DEPS "libsystemd-login glib-2.0 gio-2.0 dlog capi-base-common alarm-service") SET(DEPS "${DEPS} context-common-server") -SET(DEPS "${DEPS} app-history-server") -SET(DEPS "${DEPS} sensor-recorder-server") +SET(DEPS "${DEPS} context-app-history-server") +SET(DEPS "${DEPS} context-sensor-recorder-server") SET(DEPS "${DEPS} context-store-server") FILE(GLOB_RECURSE SRCS src/*.cpp) diff --git a/packaging/context-service.spec b/packaging/context-service.spec index cbe59f8..fab54bb 100644 --- a/packaging/context-service.spec +++ b/packaging/context-service.spec @@ -17,8 +17,8 @@ BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(alarm-service) BuildRequires: pkgconfig(context-common-server) -BuildRequires: pkgconfig(app-history-server) -BuildRequires: pkgconfig(sensor-recorder-server) +BuildRequires: pkgconfig(context-app-history-server) +BuildRequires: pkgconfig(context-sensor-recorder-server) BuildRequires: pkgconfig(context-store-server) %description -- 2.7.4 From a20e44a4c4d02b10670f836be79505616d6d8f56 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Thu, 16 Mar 2017 15:41:26 +0900 Subject: [PATCH 08/16] Add job-scheduler service Change-Id: I38dcd315450223013d9804479b2c41f2e026c4d6 Signed-off-by: Mu-Woong Lee --- CMakeLists.txt | 1 + packaging/context-service.spec | 1 + src/ServiceLoader.cpp | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b85c19..e49d12c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ SET(DEPS "${DEPS} context-common-server") SET(DEPS "${DEPS} context-app-history-server") SET(DEPS "${DEPS} context-sensor-recorder-server") SET(DEPS "${DEPS} context-store-server") +SET(DEPS "${DEPS} context-job-scheduler-server") FILE(GLOB_RECURSE SRCS src/*.cpp) MESSAGE("Sources: ${SRCS}") diff --git a/packaging/context-service.spec b/packaging/context-service.spec index fab54bb..2b90a72 100644 --- a/packaging/context-service.spec +++ b/packaging/context-service.spec @@ -20,6 +20,7 @@ BuildRequires: pkgconfig(context-common-server) BuildRequires: pkgconfig(context-app-history-server) BuildRequires: pkgconfig(context-sensor-recorder-server) BuildRequires: pkgconfig(context-store-server) +BuildRequires: pkgconfig(context-job-scheduler-server) %description This is a systemd service that contains all features provided by the Tizen Contextual Service Framework. diff --git a/src/ServiceLoader.cpp b/src/ServiceLoader.cpp index b41eff4..03acfbc 100644 --- a/src/ServiceLoader.cpp +++ b/src/ServiceLoader.cpp @@ -17,7 +17,7 @@ #include #include #include -//#include +#include #include "ServiceLoader.h" @@ -45,7 +45,7 @@ bool ServiceLoader::load(GDBusConnection* conn) __create(conn); __create(conn); __create(conn); - //__create(conn); + __create(conn); return (!__systemServices.empty() || !__userServices.empty()); } -- 2.7.4 From 6d8af271f72d00abf8040157047927e4ac0f64a7 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 20 Mar 2017 00:01:56 +0900 Subject: [PATCH 09/16] Add include directory setting w.r.t. context-common Change-Id: I164a08b582621d4ebb923b998963b3d8ea0047c7 Signed-off-by: Mu-Woong Lee --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e49d12c..04c4f5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,12 @@ SET(DEPS "${DEPS} context-sensor-recorder-server") SET(DEPS "${DEPS} context-store-server") SET(DEPS "${DEPS} context-job-scheduler-server") +SET(INCDIR "${CMAKE_INSTALL_INCLUDEDIR}/context-service") + +INCLUDE_DIRECTORIES( + ${CMAKE_INSTALL_PREFIX}/${INCDIR}/private +) + FILE(GLOB_RECURSE SRCS src/*.cpp) MESSAGE("Sources: ${SRCS}") -- 2.7.4 From 685ac61a04fed608c83176930bf922f6a7b146ac Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 20 Mar 2017 00:30:16 +0900 Subject: [PATCH 10/16] Add build & packaging script of context-agent context-agent will be a user-level assistant service of the main context-service daemon. Change-Id: I74db377718ecd9883c3cb75bef556f32d02cc4d3 Signed-off-by: Mu-Woong Lee --- CMakeLists.txt | 32 ++---------------- packaging/context-service.spec | 38 +++++++++++++++++++--- packaging/contextd-agent.service | 9 +++++ .../{context-service.service => contextd.service} | 2 +- packaging/org.tizen.contextagent.conf | 15 +++++++++ packaging/org.tizen.contextagent.service | 7 ++++ src/agent/AgentMain.cpp | 22 +++++++++++++ src/agent/CMakeLists.txt | 21 ++++++++++++ src/{ => server}/ActiveUserMonitor.cpp | 0 src/{ => server}/ActiveUserMonitor.h | 0 src/{ => server}/AlarmInitializer.cpp | 0 src/{ => server}/AlarmInitializer.h | 0 src/server/CMakeLists.txt | 32 ++++++++++++++++++ src/{ => server}/DBusConnector.cpp | 0 src/{ => server}/DBusConnector.h | 0 src/{Main.cpp => server/ServerMain.cpp} | 0 src/{ => server}/ServiceLoader.cpp | 0 src/{ => server}/ServiceLoader.h | 0 18 files changed, 142 insertions(+), 36 deletions(-) create mode 100644 packaging/contextd-agent.service rename packaging/{context-service.service => contextd.service} (76%) create mode 100644 packaging/org.tizen.contextagent.conf create mode 100644 packaging/org.tizen.contextagent.service create mode 100644 src/agent/AgentMain.cpp create mode 100644 src/agent/CMakeLists.txt rename src/{ => server}/ActiveUserMonitor.cpp (100%) rename src/{ => server}/ActiveUserMonitor.h (100%) rename src/{ => server}/AlarmInitializer.cpp (100%) rename src/{ => server}/AlarmInitializer.h (100%) create mode 100644 src/server/CMakeLists.txt rename src/{ => server}/DBusConnector.cpp (100%) rename src/{ => server}/DBusConnector.h (100%) rename src/{Main.cpp => server/ServerMain.cpp} (100%) rename src/{ => server}/ServiceLoader.cpp (100%) rename src/{ => server}/ServiceLoader.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04c4f5a..ff2c8a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,36 +2,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(context-service) INCLUDE(GNUInstallDirs) -SET(target "contextd") - -SET(DEPS "libsystemd-login glib-2.0 gio-2.0 dlog capi-base-common alarm-service") -SET(DEPS "${DEPS} context-common-server") -SET(DEPS "${DEPS} context-app-history-server") -SET(DEPS "${DEPS} context-sensor-recorder-server") -SET(DEPS "${DEPS} context-store-server") -SET(DEPS "${DEPS} context-job-scheduler-server") - -SET(INCDIR "${CMAKE_INSTALL_INCLUDEDIR}/context-service") - -INCLUDE_DIRECTORIES( - ${CMAKE_INSTALL_PREFIX}/${INCDIR}/private -) - -FILE(GLOB_RECURSE SRCS src/*.cpp) -MESSAGE("Sources: ${SRCS}") - ADD_DEFINITIONS(-O2 -Wall -fPIC -fPIE -fdata-sections -ffunction-sections -fvisibility=hidden) -ADD_DEFINITIONS(-DLOG_TAG="CONTEXT") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIC -pie -Wl,--as-needed -Wl,--gc-section -Wl,--print-gc-section") -INCLUDE(FindPkgConfig) -pkg_check_modules(DEPS_PKG REQUIRED ${DEPS}) - -FOREACH(flag ${DEPS_PKG_CFLAGS}) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") -ENDFOREACH(flag) - -ADD_EXECUTABLE(${target} ${SRCS}) -TARGET_LINK_LIBRARIES(${target} ${DEPS_PKG_LDFLAGS}) - -INSTALL(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_BINDIR}) +ADD_SUBDIRECTORY(src/server) +ADD_SUBDIRECTORY(src/agent) diff --git a/packaging/context-service.spec b/packaging/context-service.spec index 2b90a72..5df292d 100644 --- a/packaging/context-service.spec +++ b/packaging/context-service.spec @@ -5,8 +5,11 @@ Release: 1 Group: Service/Context License: Apache-2.0 Source0: %{name}-%{version}.tar.gz -Source1: context-service.service +Source1: contextd.service Source2: org.tizen.context.conf +Source3: contextd-agent.service +Source4: org.tizen.contextagent.conf +Source5: org.tizen.contextagent.service BuildRequires: cmake BuildRequires: pkgconfig(libsystemd-login) @@ -25,6 +28,14 @@ BuildRequires: pkgconfig(context-job-scheduler-server) %description This is a systemd service that contains all features provided by the Tizen Contextual Service Framework. + +%package -n context-agent +Summary: User-level agent service of the Tizen Contextual Service Framework + +%description -n context-agent +This is a systemd service that runs in the user session to assist the main service daemon of the Contextual Service Framework. + + %prep %setup -q @@ -42,15 +53,32 @@ make %{?_smp_mflags} mkdir -p %{buildroot}%{_unitdir}/default.target.wants install -m 0644 %{SOURCE1} %{buildroot}%{_unitdir} -ln -s ../context-service.service %{buildroot}%{_unitdir}/default.target.wants/context-service.service +ln -s ../contextd.service %{buildroot}%{_unitdir}/default.target.wants/contextd.service mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/dbus-1/system.d/ +mkdir -p %{buildroot}%{_unitdir_user} +install -m 0644 %{SOURCE3} %{buildroot}%{_unitdir_user} + +mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/session.d +install -m 0644 %{SOURCE4} %{buildroot}%{_sysconfdir}/dbus-1/session.d/ + +mkdir -p %{buildroot}/usr/share/dbus-1/services +install -m 0644 %{SOURCE5} %{buildroot}/usr/share/dbus-1/services/ + %files %manifest packaging/%{name}.manifest %config %{_sysconfdir}/dbus-1/system.d/* -%{_bindir}/* -%{_unitdir}/context-service.service -%{_unitdir}/*/context-service.service +%{_bindir}/contextd +%{_unitdir}/contextd.service +%{_unitdir}/*/contextd.service +%license LICENSE + +%files -n context-agent +%manifest packaging/%{name}.manifest +%config %{_sysconfdir}/dbus-1/session.d/* +%{_bindir}/contextd-agent +%{_unitdir_user}/contextd-agent.service +/usr/share/dbus-1/services/* %license LICENSE diff --git a/packaging/contextd-agent.service b/packaging/contextd-agent.service new file mode 100644 index 0000000..e6e36b3 --- /dev/null +++ b/packaging/contextd-agent.service @@ -0,0 +1,9 @@ +[Unit] +Description=Contextual Service Framework User-Level Agent Daemon + +[Service] +Type=dbus +BusName=org.tizen.contextagent +ExecStart=/usr/bin/contextd-agent +Restart=on-failure +RestartSec=1 diff --git a/packaging/context-service.service b/packaging/contextd.service similarity index 76% rename from packaging/context-service.service rename to packaging/contextd.service index e5f2f31..0fb5d90 100644 --- a/packaging/context-service.service +++ b/packaging/contextd.service @@ -1,5 +1,5 @@ [Unit] -Description=Contextual Service Framework Daemon +Description=Contextual Service Framework Server Daemon [Service] User=service_fw diff --git a/packaging/org.tizen.contextagent.conf b/packaging/org.tizen.contextagent.conf new file mode 100644 index 0000000..3683fc7 --- /dev/null +++ b/packaging/org.tizen.contextagent.conf @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/packaging/org.tizen.contextagent.service b/packaging/org.tizen.contextagent.service new file mode 100644 index 0000000..198b7d1 --- /dev/null +++ b/packaging/org.tizen.contextagent.service @@ -0,0 +1,7 @@ +[Unit] +Description=Contextual Service Framework User-Level Agent D-Bus + +[D-BUS Service] +Name=org.tizen.contextagent +Exec=/bin/false +SystemdService=contextd-agent.service diff --git a/src/agent/AgentMain.cpp b/src/agent/AgentMain.cpp new file mode 100644 index 0000000..fc1dc8d --- /dev/null +++ b/src/agent/AgentMain.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 + +int main(int argc, char* argv[]) +{ + return EXIT_SUCCESS; +} diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt new file mode 100644 index 0000000..114362f --- /dev/null +++ b/src/agent/CMakeLists.txt @@ -0,0 +1,21 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(target "contextd-agent") + +SET(DEPS glib-2.0 gio-2.0 dlog capi-base-common) + +FILE(GLOB_RECURSE SRCS *.cpp) +MESSAGE("Sources: ${SRCS}") + +INCLUDE(FindPkgConfig) +pkg_check_modules(DEPS_AGENT_PKG REQUIRED ${DEPS}) + +FOREACH(flag ${DEPS_AGENT_PKG_CFLAGS}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") +ENDFOREACH(flag) + +ADD_EXECUTABLE(${target} ${SRCS}) +SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_DEFINITIONS "LOG_TAG=\"CONTEXT-AGENT\"") +TARGET_LINK_LIBRARIES(${target} ${DEPS_AGENT_PKG_LDFLAGS}) + +INSTALL(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/ActiveUserMonitor.cpp b/src/server/ActiveUserMonitor.cpp similarity index 100% rename from src/ActiveUserMonitor.cpp rename to src/server/ActiveUserMonitor.cpp diff --git a/src/ActiveUserMonitor.h b/src/server/ActiveUserMonitor.h similarity index 100% rename from src/ActiveUserMonitor.h rename to src/server/ActiveUserMonitor.h diff --git a/src/AlarmInitializer.cpp b/src/server/AlarmInitializer.cpp similarity index 100% rename from src/AlarmInitializer.cpp rename to src/server/AlarmInitializer.cpp diff --git a/src/AlarmInitializer.h b/src/server/AlarmInitializer.h similarity index 100% rename from src/AlarmInitializer.h rename to src/server/AlarmInitializer.h diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt new file mode 100644 index 0000000..170e43e --- /dev/null +++ b/src/server/CMakeLists.txt @@ -0,0 +1,32 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(target "contextd") + +SET(DEPS libsystemd-login glib-2.0 gio-2.0 dlog capi-base-common alarm-service) +SET(DEPS ${DEPS} context-common-server) +SET(DEPS ${DEPS} context-app-history-server) +SET(DEPS ${DEPS} context-sensor-recorder-server) +SET(DEPS ${DEPS} context-store-server) +SET(DEPS ${DEPS} context-job-scheduler-server) + +SET(INCDIR "${CMAKE_INSTALL_INCLUDEDIR}/context-service") + +INCLUDE_DIRECTORIES( + ${CMAKE_INSTALL_PREFIX}/${INCDIR}/private +) + +FILE(GLOB_RECURSE SRCS *.cpp) +MESSAGE("Sources: ${SRCS}") + +INCLUDE(FindPkgConfig) +pkg_check_modules(DEPS_SERVER_PKG REQUIRED ${DEPS}) + +FOREACH(flag ${DEPS_SERVER_PKG_CFLAGS}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") +ENDFOREACH(flag) + +ADD_EXECUTABLE(${target} ${SRCS}) +SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_DEFINITIONS "LOG_TAG=\"CONTEXT\"") +TARGET_LINK_LIBRARIES(${target} ${DEPS_SERVER_PKG_LDFLAGS}) + +INSTALL(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/DBusConnector.cpp b/src/server/DBusConnector.cpp similarity index 100% rename from src/DBusConnector.cpp rename to src/server/DBusConnector.cpp diff --git a/src/DBusConnector.h b/src/server/DBusConnector.h similarity index 100% rename from src/DBusConnector.h rename to src/server/DBusConnector.h diff --git a/src/Main.cpp b/src/server/ServerMain.cpp similarity index 100% rename from src/Main.cpp rename to src/server/ServerMain.cpp diff --git a/src/ServiceLoader.cpp b/src/server/ServiceLoader.cpp similarity index 100% rename from src/ServiceLoader.cpp rename to src/server/ServiceLoader.cpp diff --git a/src/ServiceLoader.h b/src/server/ServiceLoader.h similarity index 100% rename from src/ServiceLoader.h rename to src/server/ServiceLoader.h -- 2.7.4 From 4b3603b6a13652f6ea06dac245ef0bd23eedff13 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 27 Mar 2017 14:11:14 +0900 Subject: [PATCH 11/16] Switch to multi-user.target service Change-Id: I2c181dc9996a78208e4c9ee7bfe05ea8bb266eee Signed-off-by: Mu-Woong Lee --- packaging/context-service.spec | 4 ++-- packaging/contextd.service | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packaging/context-service.spec b/packaging/context-service.spec index 5df292d..14c6608 100644 --- a/packaging/context-service.spec +++ b/packaging/context-service.spec @@ -51,9 +51,9 @@ make %{?_smp_mflags} %install %make_install -mkdir -p %{buildroot}%{_unitdir}/default.target.wants +mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants install -m 0644 %{SOURCE1} %{buildroot}%{_unitdir} -ln -s ../contextd.service %{buildroot}%{_unitdir}/default.target.wants/contextd.service +ln -s ../contextd.service %{buildroot}%{_unitdir}/multi-user.target.wants/contextd.service mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/dbus-1/system.d/ diff --git a/packaging/contextd.service b/packaging/contextd.service index 0fb5d90..cae5d7f 100644 --- a/packaging/contextd.service +++ b/packaging/contextd.service @@ -1,5 +1,6 @@ [Unit] Description=Contextual Service Framework Server Daemon +After=lazy_mount.service systemd-logind.service [Service] User=service_fw @@ -11,4 +12,4 @@ Restart=on-failure RestartSec=1 [Install] -WantedBy=default.target +WantedBy=multi-user.target -- 2.7.4 From b0036b91d947bc7d11bcbbcb14cd43564bc04a8a Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Mon, 27 Mar 2017 18:32:55 +0900 Subject: [PATCH 12/16] Change the dbus signal listening to monitor new user activation Unlike the previous "UserNew" signal, "UserSessionStartupFinished" is called when the user session is actually ready, i.e., the necessary directories are mounted. Change-Id: I39894c7602698e65c0ab2a75a940885311556710 Signed-off-by: Mu-Woong Lee --- src/server/ActiveUserMonitor.cpp | 44 +++++++++++++++++++++++++++++----------- src/server/ActiveUserMonitor.h | 2 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/server/ActiveUserMonitor.cpp b/src/server/ActiveUserMonitor.cpp index 7ed9f8e..526b4ba 100644 --- a/src/server/ActiveUserMonitor.cpp +++ b/src/server/ActiveUserMonitor.cpp @@ -15,9 +15,11 @@ */ #include +#include #include "ActiveUserMonitor.h" #define ROOT_UID 0 +#define USER_CHK_DELAY 3000 using namespace ctx; @@ -42,14 +44,14 @@ void ActiveUserMonitor::start(GDBusConnection* conn, uid_cb_t activateUser, uid_ __deactivateUser = deactivateUser; __userNewSignalId = g_dbus_connection_signal_subscribe(__connection, - NULL, "org.freedesktop.login1.Manager", "UserNew", NULL, - NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserNew, this, NULL); + NULL, "org.freedesktop.systemd1.Manager", "UserSessionStartupFinished", NULL, + NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserSessionStarted, this, NULL); __userRemovedSignalId = g_dbus_connection_signal_subscribe(__connection, NULL, "org.freedesktop.login1.Manager", "UserRemoved", NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserRemoved, this, NULL); - g_timeout_add(200, __checkCurrentUser, this); + g_timeout_add(USER_CHK_DELAY, __checkCurrentUser, this); } void ActiveUserMonitor::stop() @@ -58,12 +60,16 @@ void ActiveUserMonitor::stop() g_dbus_connection_signal_unsubscribe(__connection, __userRemovedSignalId); } -void ActiveUserMonitor::__onUserNew(GDBusConnection* conn, const gchar* sender, +void ActiveUserMonitor::__onUserSessionStarted(GDBusConnection* conn, const gchar* sender, const gchar* path, const gchar* iface, const gchar* name, GVariant* param, gpointer userData) { uint32_t uid = 0; - g_variant_get_child(param, 0, "u", &uid); + guint64 uid64 = 0; + + g_variant_get_child(param, 0, "t", &uid64); + uid = static_cast(uid64); + IF_FAIL_VOID_TAG(uid > 0, _W, "UID == 0"); _D("UID: %u", uid); @@ -107,6 +113,18 @@ void ActiveUserMonitor::__onUserRemoved(GDBusConnection* conn, const gchar* send monitor->__activeUid = ROOT_UID; } +static bool __isUserDirectoryReady(uid_t uid) +{ + std::string dbDir = PathUtil::getUserPath(uid, TZ_USER_DB, EMPTY_STR); + DIR* dir = opendir(dbDir.c_str()); + if (!dir) { + _W("User not ready"); + return false; + } + closedir(dir); + return true; +} + gboolean ActiveUserMonitor::__checkCurrentUser(gpointer userData) { ActiveUserMonitor* monitor = static_cast(userData); @@ -114,16 +132,18 @@ gboolean ActiveUserMonitor::__checkCurrentUser(gpointer userData) uid_t* users = NULL; int numUsers = sd_get_active_uids(&users); + IF_FAIL_RETURN(numUsers > 0, G_SOURCE_CONTINUE); - if (numUsers > 0) - monitor->__activeUid = users[0]; - + uid_t activeUid = users[0]; g_free(users); - if (monitor->__activeUid != ROOT_UID) { - _D("UID: %u", monitor->__activeUid); - monitor->__activateUser(monitor->__activeUid); - } + if (activeUid == ROOT_UID || !__isUserDirectoryReady(activeUid)) + return G_SOURCE_CONTINUE; + + monitor->__activeUid = activeUid; + + _D("UID: %u", monitor->__activeUid); + monitor->__activateUser(monitor->__activeUid); return G_SOURCE_REMOVE; } diff --git a/src/server/ActiveUserMonitor.h b/src/server/ActiveUserMonitor.h index f349c85..7ed0fa2 100644 --- a/src/server/ActiveUserMonitor.h +++ b/src/server/ActiveUserMonitor.h @@ -33,7 +33,7 @@ namespace ctx { void stop(); private: - static void __onUserNew(GDBusConnection* conn, const gchar* sender, + static void __onUserSessionStarted(GDBusConnection* conn, const gchar* sender, const gchar* path, const gchar* iface, const gchar* name, GVariant* param, gpointer userData); -- 2.7.4 From 43a989d2cad81820c1255654b3f416ce2e71ffc7 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Tue, 28 Mar 2017 20:25:42 +0900 Subject: [PATCH 13/16] Update dbus conf files Change-Id: I7e81e9abec3c3fbc4605b0bd0992f2bf73a0e96c Signed-off-by: Mu-Woong Lee --- packaging/org.tizen.context.conf | 18 ++++++++++++------ packaging/org.tizen.contextagent.conf | 10 +++++----- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packaging/org.tizen.context.conf b/packaging/org.tizen.context.conf index b43e39b..e136a24 100644 --- a/packaging/org.tizen.context.conf +++ b/packaging/org.tizen.context.conf @@ -1,15 +1,21 @@ - + - - - - + + - + + + + + diff --git a/packaging/org.tizen.contextagent.conf b/packaging/org.tizen.contextagent.conf index 3683fc7..f5f075e 100644 --- a/packaging/org.tizen.contextagent.conf +++ b/packaging/org.tizen.contextagent.conf @@ -1,15 +1,15 @@ - - - + + - - + + Date: Wed, 29 Mar 2017 19:25:39 +0900 Subject: [PATCH 15/16] Remove dbus connection setting for Timer Change-Id: I4d7a1722abbc443ccdee7b074c12762eb62760d4 Signed-off-by: Mu-Woong Lee --- src/server/ServerMain.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/server/ServerMain.cpp b/src/server/ServerMain.cpp index 38c976d..530d65c 100644 --- a/src/server/ServerMain.cpp +++ b/src/server/ServerMain.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include "DBusConnector.h" #include "ServiceLoader.h" #include "ActiveUserMonitor.h" @@ -73,7 +72,6 @@ static void __deactivateUser(uid_t uid) static void __startService(GDBusConnection* conn) { - Timer::setDBusConnection(conn); __activeUserMonitor.start(conn, __activateUser, __deactivateUser); _I("Loading services"); -- 2.7.4 From db1c5eaf01761cba1b556d907a3d0446b84beb64 Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Thu, 30 Mar 2017 15:59:32 +0900 Subject: [PATCH 16/16] Integrate the legacy context-service into the agent service (1/2) This patch just copies the legacy code files from Tizen 3.0 context-service. Change-Id: Ie615be0baaf8997c895eb42a537722a1f28f6267 Signed-off-by: Mu-Woong Lee --- src/agent/CMakeLists.txt | 2 +- src/agent/legacy/ClientRequest.cpp | 116 +++++ src/agent/legacy/ClientRequest.h | 47 ++ src/agent/legacy/ContextManager.cpp | 237 +++++++++ src/agent/legacy/ContextManager.h | 63 +++ src/agent/legacy/DBusServer.cpp | 228 +++++++++ src/agent/legacy/DBusServer.h | 64 +++ src/agent/legacy/ProviderHandler.cpp | 310 ++++++++++++ src/agent/legacy/ProviderHandler.h | 78 +++ src/agent/legacy/ProviderLoader.cpp | 120 +++++ src/agent/legacy/ProviderLoader.h | 63 +++ src/agent/legacy/Request.cpp | 66 +++ src/agent/legacy/Request.h | 56 +++ src/agent/legacy/Server.cpp | 170 +++++++ src/agent/legacy/Server.h | 35 ++ src/agent/legacy/access_control/PeerCreds.cpp | 77 +++ src/agent/legacy/access_control/PeerCreds.h | 43 ++ src/agent/legacy/access_control/Privilege.cpp | 86 ++++ src/agent/legacy/access_control/Privilege.h | 32 ++ src/agent/legacy/policy/PolicyManager.cpp | 69 +++ src/agent/legacy/policy/PolicyManager.h | 43 ++ src/agent/legacy/policy/PolicyRequest.cpp | 53 ++ src/agent/legacy/policy/PolicyRequest.h | 39 ++ src/agent/legacy/trigger/ActionManager.cpp | 210 ++++++++ src/agent/legacy/trigger/ActionManager.h | 35 ++ src/agent/legacy/trigger/ContextMonitor.cpp | 318 ++++++++++++ src/agent/legacy/trigger/ContextMonitor.h | 92 ++++ src/agent/legacy/trigger/FactRequest.cpp | 68 +++ src/agent/legacy/trigger/FactRequest.h | 46 ++ src/agent/legacy/trigger/FactTypes.h | 26 + src/agent/legacy/trigger/IContextListener.h | 38 ++ src/agent/legacy/trigger/Rule.cpp | 209 ++++++++ src/agent/legacy/trigger/Rule.h | 80 +++ src/agent/legacy/trigger/RuleEvaluator.cpp | 385 ++++++++++++++ src/agent/legacy/trigger/RuleEvaluator.h | 53 ++ src/agent/legacy/trigger/RuleManager.cpp | 697 ++++++++++++++++++++++++++ src/agent/legacy/trigger/RuleManager.h | 71 +++ src/agent/legacy/trigger/TemplateManager.cpp | 196 ++++++++ src/agent/legacy/trigger/TemplateManager.h | 62 +++ src/agent/legacy/trigger/Trigger.cpp | 279 +++++++++++ src/agent/legacy/trigger/Trigger.h | 59 +++ 41 files changed, 5020 insertions(+), 1 deletion(-) create mode 100644 src/agent/legacy/ClientRequest.cpp create mode 100644 src/agent/legacy/ClientRequest.h create mode 100644 src/agent/legacy/ContextManager.cpp create mode 100644 src/agent/legacy/ContextManager.h create mode 100644 src/agent/legacy/DBusServer.cpp create mode 100644 src/agent/legacy/DBusServer.h create mode 100644 src/agent/legacy/ProviderHandler.cpp create mode 100644 src/agent/legacy/ProviderHandler.h create mode 100644 src/agent/legacy/ProviderLoader.cpp create mode 100644 src/agent/legacy/ProviderLoader.h create mode 100644 src/agent/legacy/Request.cpp create mode 100644 src/agent/legacy/Request.h create mode 100644 src/agent/legacy/Server.cpp create mode 100644 src/agent/legacy/Server.h create mode 100644 src/agent/legacy/access_control/PeerCreds.cpp create mode 100644 src/agent/legacy/access_control/PeerCreds.h create mode 100644 src/agent/legacy/access_control/Privilege.cpp create mode 100644 src/agent/legacy/access_control/Privilege.h create mode 100644 src/agent/legacy/policy/PolicyManager.cpp create mode 100644 src/agent/legacy/policy/PolicyManager.h create mode 100644 src/agent/legacy/policy/PolicyRequest.cpp create mode 100644 src/agent/legacy/policy/PolicyRequest.h create mode 100644 src/agent/legacy/trigger/ActionManager.cpp create mode 100644 src/agent/legacy/trigger/ActionManager.h create mode 100644 src/agent/legacy/trigger/ContextMonitor.cpp create mode 100644 src/agent/legacy/trigger/ContextMonitor.h create mode 100644 src/agent/legacy/trigger/FactRequest.cpp create mode 100644 src/agent/legacy/trigger/FactRequest.h create mode 100644 src/agent/legacy/trigger/FactTypes.h create mode 100644 src/agent/legacy/trigger/IContextListener.h create mode 100644 src/agent/legacy/trigger/Rule.cpp create mode 100644 src/agent/legacy/trigger/Rule.h create mode 100644 src/agent/legacy/trigger/RuleEvaluator.cpp create mode 100644 src/agent/legacy/trigger/RuleEvaluator.h create mode 100644 src/agent/legacy/trigger/RuleManager.cpp create mode 100644 src/agent/legacy/trigger/RuleManager.h create mode 100644 src/agent/legacy/trigger/TemplateManager.cpp create mode 100644 src/agent/legacy/trigger/TemplateManager.h create mode 100644 src/agent/legacy/trigger/Trigger.cpp create mode 100644 src/agent/legacy/trigger/Trigger.h diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt index 114362f..a97f2b1 100644 --- a/src/agent/CMakeLists.txt +++ b/src/agent/CMakeLists.txt @@ -4,7 +4,7 @@ SET(target "contextd-agent") SET(DEPS glib-2.0 gio-2.0 dlog capi-base-common) -FILE(GLOB_RECURSE SRCS *.cpp) +FILE(GLOB SRCS *.cpp) MESSAGE("Sources: ${SRCS}") INCLUDE(FindPkgConfig) diff --git a/src/agent/legacy/ClientRequest.cpp b/src/agent/legacy/ClientRequest.cpp new file mode 100644 index 0000000..e625bf0 --- /dev/null +++ b/src/agent/legacy/ClientRequest.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "DBusServer.h" +#include "access_control/PeerCreds.h" +#include "ClientRequest.h" + +ctx::ClientRequest::ClientRequest(int type, int reqId, const char *subj, const char *desc, + ctx::Credentials *creds, const char *sender, GDBusMethodInvocation *inv) : + RequestInfo(type, reqId, subj, desc), + __credentials(creds), + __dbusSender(sender), + __invocation(inv) +{ +} + +ctx::ClientRequest::~ClientRequest() +{ + if (__invocation) + g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT)); + + delete __credentials; +} + +const ctx::Credentials* ctx::ClientRequest::getCredentials() +{ + return __credentials; +} + +const char* ctx::ClientRequest::getPackageId() +{ + if (__credentials) + return __credentials->packageId; + + return NULL; +} + +const char* ctx::ClientRequest::getClient() +{ + if (__credentials) + return __credentials->client; + + return NULL; +} + +bool ctx::ClientRequest::reply(int error) +{ + IF_FAIL_RETURN(__invocation, true); + + _I("Reply %#x", error); + + g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", error, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT)); + __invocation = NULL; + return true; +} + +bool ctx::ClientRequest::reply(int error, ctx::Json& requestResult) +{ + IF_FAIL_RETURN(__invocation, true); + IF_FAIL_RETURN(error != ERR_NONE || __type != REQ_READ_SYNC, true); + + std::string result = requestResult.str(); + IF_FAIL_RETURN(!result.empty(), false); + + _I("Reply %#x", error); + _SD("Result: %s", result.c_str()); + + g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", error, result.c_str(), EMPTY_JSON_OBJECT)); + __invocation = NULL; + + return true; +} + +bool ctx::ClientRequest::reply(int error, ctx::Json& requestResult, ctx::Json& dataRead) +{ + if (__invocation == NULL) { + return publish(error, dataRead); + } + + std::string result = requestResult.str(); + std::string data = dataRead.str(); + IF_FAIL_RETURN(!result.empty() && !data.empty(), false); + + _I("Reply %#x", error); + _SD("Result: %s", result.c_str()); + _SD("Data: %s", data.c_str()); + + g_dbus_method_invocation_return_value(__invocation, g_variant_new("(iss)", error, result.c_str(), data.c_str())); + __invocation = NULL; + + return true; +} + +bool ctx::ClientRequest::publish(int error, ctx::Json& data) +{ + DBusServer::publish(__dbusSender, __reqId, __subject, error, data.str()); + return true; +} diff --git a/src/agent/legacy/ClientRequest.h b/src/agent/legacy/ClientRequest.h new file mode 100644 index 0000000..69d18e1 --- /dev/null +++ b/src/agent/legacy/ClientRequest.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_CLIENT_REQUEST_H_ +#define _CONTEXT_CLIENT_REQUEST_H_ + +#include +#include "Request.h" + +namespace ctx { + + class ClientRequest : public RequestInfo { + public: + ClientRequest(int type, int reqId, const char *subj, const char *desc, + Credentials *creds, const char *sender, GDBusMethodInvocation *inv); + ~ClientRequest(); + + const Credentials* getCredentials(); + const char* getPackageId(); + const char* getClient(); + bool reply(int error); + bool reply(int error, ctx::Json &requestResult); + bool reply(int error, ctx::Json &requestResult, ctx::Json &dataRead); + bool publish(int error, ctx::Json &data); + + private: + Credentials *__credentials; + std::string __dbusSender; + GDBusMethodInvocation *__invocation; + }; + +} /* namespace ctx */ + +#endif /* End of _CONTEXT_CLIENT_REQUEST_H_ */ diff --git a/src/agent/legacy/ContextManager.cpp b/src/agent/legacy/ContextManager.cpp new file mode 100644 index 0000000..7d07966 --- /dev/null +++ b/src/agent/legacy/ContextManager.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "access_control/Privilege.h" +#include "trigger/TemplateManager.h" +#include "Server.h" +#include "Request.h" +#include "ProviderHandler.h" +#include "ProviderLoader.h" +#include "ContextManager.h" + +using namespace ctx::trigger; +using namespace ctx; + +ContextManager::ContextManager() +{ + ContextProvider::__setContextManager(this); + CustomRegister::__setCustomRegister(this); + ProviderLoader::init(); +} + +ContextManager::~ContextManager() +{ + release(); +} + +bool ContextManager::init() +{ + return true; +} + +void ContextManager::release() +{ + ProviderHandler::purge(); +} + +void ContextManager::assignRequest(RequestInfo* request) +{ + std::string subject = request->getSubject(); + if (subject.empty()) { + _W("Empty subject name"); + request->reply(ERR_NOT_SUPPORTED); + delete request; + return; + } + + ProviderHandler *handle = ProviderHandler::getInstance(subject, true); + if (!handle || !handle->isSupported()) { + request->reply(ERR_NOT_SUPPORTED); + delete request; + return; + } + + if (request->getType() != REQ_SUPPORT && !handle->isAllowed(request->getCredentials())) { + _W("Permission denied"); + request->reply(ERR_PERMISSION_DENIED); + delete request; + return; + } + + switch (request->getType()) { + case REQ_SUBSCRIBE: + handle->subscribe(request); + break; + case REQ_UNSUBSCRIBE: + handle->unsubscribe(request); + break; + case REQ_READ: + case REQ_READ_SYNC: + handle->read(request); + break; + case REQ_WRITE: + handle->write(request); + break; + case REQ_SUPPORT: + request->reply(ERR_NONE); + delete request; + break; + default: + _E("Invalid type of request"); + delete request; + } +} + +bool ContextManager::isSupported(const char *subject) +{ + ProviderHandler *handle = ProviderHandler::getInstance(subject, true); + + if (!handle) + return false; + + return handle->isSupported(); +} + +bool ContextManager::isAllowed(const Credentials *creds, const char *subject) +{ + IF_FAIL_RETURN(creds, true); /* In case internal requests */ + + ProviderHandler *handle = ProviderHandler::getInstance(subject, true); + + if (!handle) + return false; + + return handle->isAllowed(creds); +} + +void ContextManager::__publish(const char* subject, Json &option, int error, Json &dataUpdated) +{ + _I("Publishing '%s'", subject); + _J("Option", option); + + ProviderHandler *handle = ProviderHandler::getInstance(subject, false); + IF_FAIL_VOID_TAG(handle, _W, "No corresponding provider"); + + handle->publish(option, error, dataUpdated); +} + +void ContextManager::__replyToRead(const char* subject, Json &option, int error, Json &dataRead) +{ + _I("Sending data of '%s'", subject); + _J("Option", option); + _J("Data", dataRead); + + ProviderHandler *handle = ProviderHandler::getInstance(subject, false); + IF_FAIL_VOID_TAG(handle, _W, "No corresponding provider"); + + handle->replyToRead(option, error, dataRead); +} + +struct PublishedData { + int type; + ContextManager *mgr; + std::string subject; + int error; + Json option; + Json data; + PublishedData(int t, ContextManager *m, const char* s, Json& o, int e, Json& d) + : type(t), mgr(m), subject(s), error(e) + { + option = o.str(); + data = d.str(); + } +}; + +gboolean ContextManager::__threadSwitcher(gpointer data) +{ + PublishedData *tuple = static_cast(data); + + switch (tuple->type) { + case REQ_SUBSCRIBE: + tuple->mgr->__publish(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data); + break; + case REQ_READ: + tuple->mgr->__replyToRead(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data); + break; + default: + _W("Invalid type"); + } + + delete tuple; + return FALSE; +} + +bool ContextManager::publish(const char* subject, Json& option, int error, Json& dataUpdated) +{ + IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter"); + + PublishedData *tuple = new(std::nothrow) PublishedData(REQ_SUBSCRIBE, this, subject, option, error, dataUpdated); + IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed"); + + g_idle_add(__threadSwitcher, tuple); + + return true; +} + +bool ContextManager::replyToRead(const char* subject, Json& option, int error, Json& dataRead) +{ + IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter"); + + PublishedData *tuple = new(std::nothrow) PublishedData(REQ_READ, this, subject, option, error, dataRead); + IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed"); + + g_idle_add(__threadSwitcher, tuple); + + return true; +} + +bool ContextManager::popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option) +{ + return ProviderLoader::popTriggerTemplate(subject, operation, attribute, option); +} + +/* Only for explicit request of custom provider */ +bool ContextManager::registerCustomProvider(const char* subject, int operation, ctx::Json &attribute, ctx::Json &option, const char* owner) +{ + IF_FAIL_RETURN_TAG(ProviderHandler::getInstance(subject, true), false, _E, "Register provider failed"); + + TemplateManager* tmplMgr = TemplateManager::getInstance(); + IF_FAIL_RETURN_TAG(tmplMgr, false, _E, "Memory allocation failed"); + tmplMgr->registerTemplate(subject, operation, attribute, option, owner); + + return true; +} + +bool ContextManager::unregisterCustomProvider(const char* subject) +{ + TemplateManager* tmplMgr = TemplateManager::getInstance(); + IF_FAIL_RETURN_TAG(tmplMgr, false, _E, "Memory allocation failed"); + tmplMgr->unregisterTemplate(subject); + + int error = ProviderHandler::unregisterCustomProvider(subject); + IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Unregister provider failed"); + + return true; +} diff --git a/src/agent/legacy/ContextManager.h b/src/agent/legacy/ContextManager.h new file mode 100644 index 0000000..9be24c1 --- /dev/null +++ b/src/agent/legacy/ContextManager.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_CONTEXT_MANAGER_H_ +#define _CONTEXT_CONTEXT_MANAGER_H_ + +#include +#include +#include + +namespace ctx { + + /* Forward declaration */ + class Credentials; + class RequestInfo; + + class ContextManager : public IContextManager, ICustomRegister { + public: + ~ContextManager(); + + bool init(); + void release(); + + void assignRequest(ctx::RequestInfo *request); + bool isSupported(const char *subject); + bool isAllowed(const Credentials *creds, const char *subject); + + /* From the interface class */ + bool publish(const char *subject, ctx::Json &option, int error, ctx::Json &dataUpdated); + bool replyToRead(const char *subject, ctx::Json &option, int error, ctx::Json &dataRead); + bool registerCustomProvider(const char* subject, int operation, ctx::Json &attribute, ctx::Json &option, const char* owner); + bool unregisterCustomProvider(const char* subject); + + bool popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option); + + private: + ContextManager(); + + static gboolean __threadSwitcher(gpointer data); + + void __publish(const char *subject, ctx::Json &option, int error, ctx::Json &dataUpdated); + void __replyToRead(const char *subject, ctx::Json &option, int error, ctx::Json &dataRead); + + friend class Server; + + }; /* class ContextManager */ + +} /* namespace ctx */ + +#endif /* _CONTEXT_CONTEXT_MANAGER_H_ */ diff --git a/src/agent/legacy/DBusServer.cpp b/src/agent/legacy/DBusServer.cpp new file mode 100644 index 0000000..ff43612 --- /dev/null +++ b/src/agent/legacy/DBusServer.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include "Server.h" +#include "ClientRequest.h" +#include "access_control/PeerCreds.h" +#include "DBusServer.h" + +using namespace ctx; + +static const gchar __introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +DBusServer *DBusServer::__theInstance = NULL; + +DBusServer::DBusServer() : + __owner(-1), + __connection(NULL), + __nodeInfo(NULL) +{ +} + +DBusServer::~DBusServer() +{ + __release(); +} + +void DBusServer::__processRequest(const char *sender, GVariant *param, GDBusMethodInvocation *invocation) +{ + gint reqType = 0; + const gchar *cookie = NULL; + gint reqId = 0; + const gchar *subject = NULL; + const gchar *input = NULL; + + g_variant_get(param, "(i&si&s&s)", &reqType, &cookie, &reqId, &subject, &input); + IF_FAIL_VOID_TAG(reqType > 0 && reqId > 0 && cookie && subject && input, _E, "Invalid request"); + + _I("[%d] ReqId: %d, Subject: %s", reqType, reqId, subject); + _SI("Input: %s", input); + + Credentials *creds = NULL; + + if (!peer_creds::get(__connection, sender, cookie, &creds)) { + _E("Peer credentialing failed"); + g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT)); + return; + } + + ClientRequest *request = new(std::nothrow) ClientRequest(reqType, reqId, subject, input, creds, sender, invocation); + if (!request) { + _E("Memory allocation failed"); + g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT)); + delete creds; + return; + } + + Server::sendRequest(request); +} + +void DBusServer::__reply(GDBusMethodInvocation *invocation, int error) +{ + g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", error)); +} + +void DBusServer::__onMethodCalled(GDBusConnection *conn, const gchar *sender, + const gchar *path, const gchar *iface, const gchar *name, + GVariant *param, GDBusMethodInvocation *invocation, gpointer userData) +{ + IF_FAIL_VOID_TAG(STR_EQ(path, DBUS_PATH), _W, "Invalid path: %s", path); + IF_FAIL_VOID_TAG(STR_EQ(iface, DBUS_IFACE), _W, "Invalid interface: %s", path); + + if (STR_EQ(name, METHOD_REQUEST)) { + __theInstance->__processRequest(sender, param, invocation); + } else { + __theInstance->__reply(invocation, ERR_NONE); + } +} + +void DBusServer::__onBusAcquired(GDBusConnection *conn, const gchar *name, gpointer userData) +{ + GDBusInterfaceVTable vtable; + vtable.method_call = __onMethodCalled; + vtable.get_property = NULL; + vtable.set_property = NULL; + + guint regId = g_dbus_connection_register_object(conn, DBUS_PATH, + __theInstance->__nodeInfo->interfaces[0], &vtable, NULL, NULL, NULL); + + if (regId <= 0) { + _E("Failed to acquire dbus"); + raise(SIGTERM); + } + + __theInstance->__connection = conn; + _I("Dbus connection acquired"); +} + +void DBusServer::__onNameAcquired(GDBusConnection *conn, const gchar *name, gpointer userData) +{ + _SI("Dbus name acquired: %s", name); + Server::activate(); +} + +void DBusServer::__onNameLost(GDBusConnection *conn, const gchar *name, gpointer userData) +{ + _E("Dbus name lost"); + raise(SIGTERM); +} + +void DBusServer::__onCallDone(GObject *source, GAsyncResult *res, gpointer userData) +{ + _I("Call %u done", *static_cast(userData)); + + GDBusConnection *conn = G_DBUS_CONNECTION(source); + GError *error = NULL; + g_dbus_connection_call_finish(conn, res, &error); + HANDLE_GERROR(error); +} + +bool DBusServer::__init() +{ + __nodeInfo = g_dbus_node_info_new_for_xml(__introspection_xml, NULL); + IF_FAIL_RETURN_TAG(__nodeInfo != NULL, false, _E, "Initialization failed"); + + __owner = g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_DEST, G_BUS_NAME_OWNER_FLAGS_NONE, + __onBusAcquired, __onNameAcquired, __onNameLost, NULL, NULL); + + __theInstance = this; + return true; +} + +void DBusServer::__release() +{ + if (__connection) { + g_dbus_connection_flush_sync(__connection, NULL, NULL); + } + + if (__owner > 0) { + g_bus_unown_name(__owner); + __owner = 0; + } + + if (__connection) { + g_dbus_connection_close_sync(__connection, NULL, NULL); + g_object_unref(__connection); + __connection = NULL; + } + + if (__nodeInfo) { + g_dbus_node_info_unref(__nodeInfo); + __nodeInfo = NULL; + } +} + +void DBusServer::__publish(const char *dest, int reqId, const char *subject, int error, const char *data) +{ + _SI("Publish: %s, %d, %s, %#x, %s", dest, reqId, subject, error, data); + + GVariant *param = g_variant_new("(isis)", reqId, subject, error, data); + IF_FAIL_VOID_TAG(param, _E, "Memory allocation failed"); + + g_dbus_connection_call(__connection, dest, DBUS_PATH, DBUS_IFACE, + METHOD_RESPOND, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, NULL, NULL); +} + +void DBusServer::__call(const char *dest, const char *obj, const char *iface, const char *method, GVariant *param) +{ + static unsigned int callCount = 0; + ++callCount; + + _SI("Call %u: %s, %s, %s.%s", callCount, dest, obj, iface, method); + + g_dbus_connection_call(__connection, dest, obj, iface, method, param, NULL, + G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, __onCallDone, &callCount); +} + +void DBusServer::publish(std::string dest, int reqId, std::string subject, int error, std::string data) +{ + IF_FAIL_VOID_TAG(__theInstance, _E, "Not initialized"); + __theInstance->__publish(dest.c_str(), reqId, subject.c_str(), error, data.c_str()); +} + +void DBusServer::call(std::string dest, std::string obj, std::string iface, std::string method, GVariant *param) +{ + IF_FAIL_VOID_TAG(__theInstance, _E, "Not initialized"); + __theInstance->__call(dest.c_str(), obj.c_str(), iface.c_str(), method.c_str(), param); +} diff --git a/src/agent/legacy/DBusServer.h b/src/agent/legacy/DBusServer.h new file mode 100644 index 0000000..c4b1c32 --- /dev/null +++ b/src/agent/legacy/DBusServer.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_DBUS_SERVER_H_ +#define _CONTEXT_DBUS_SERVER_H_ + +#include +#include +#include + +namespace ctx { + + class DBusServer { + public: + ~DBusServer(); + + static void publish(std::string dest, int reqId, std::string subject, int error, std::string data); + static void call(std::string dest, std::string obj, std::string iface, std::string method, GVariant *param); + + private: + DBusServer(); + + static void __onMethodCalled(GDBusConnection *conn, const gchar *sender, + const gchar *path, const gchar *iface, const gchar *name, + GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data); + static void __onBusAcquired(GDBusConnection *conn, const gchar *name, gpointer userData); + static void __onNameAcquired(GDBusConnection *conn, const gchar *name, gpointer userData); + static void __onNameLost(GDBusConnection *conn, const gchar *name, gpointer userData); + static void __onCallDone(GObject *source, GAsyncResult *res, gpointer userData); + + bool __init(); + void __release(); + void __publish(const char *dest, int reqId, const char *subject, int error, const char *data); + void __call(const char *dest, const char *obj, const char *iface, const char *method, GVariant *param); + + void __processRequest(const char *sender, GVariant *param, GDBusMethodInvocation *invocation); + void __reply(GDBusMethodInvocation *invocation, int error); + + static DBusServer *__theInstance; + + guint __owner; + GDBusConnection *__connection; + GDBusNodeInfo *__nodeInfo; + + friend class Server; + + }; /* class ctx::DBusServer */ + +} /* namespace ctx */ + +#endif /* End of _CONTEXT_DBUS_SERVER_H_ */ diff --git a/src/agent/legacy/ProviderHandler.cpp b/src/agent/legacy/ProviderHandler.cpp new file mode 100644 index 0000000..2ce7f69 --- /dev/null +++ b/src/agent/legacy/ProviderHandler.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "access_control/Privilege.h" +#include "Request.h" +#include "ProviderHandler.h" + +#define DELETE_DELAY 20 + +using namespace ctx; + +std::map ProviderHandler::__instanceMap; + +ProviderHandler::ProviderHandler(const std::string &subject) : + __subject(subject), + __deleteScheduled(false) +{ + _D("Subject: %s", __subject.c_str()); +} + +ProviderHandler::~ProviderHandler() +{ + _D("Subject: %s", __subject.c_str()); + + for (RequestInfo*& info : __subscribeRequests) { + delete info; + } + __subscribeRequests.clear(); + + for (RequestInfo*& info : __readRequests) { + delete info; + } + __readRequests.clear(); + + delete __provider; +} + +/* TODO: Return proper error code */ +ProviderHandler* ProviderHandler::getInstance(std::string subject, bool force) +{ + InstanceMap::iterator it = __instanceMap.find(subject); + + if (it != __instanceMap.end()) + return it->second; + + if (!force) + return NULL; + + ProviderHandler *handle = new(std::nothrow) ProviderHandler(subject); + IF_FAIL_RETURN_TAG(handle, NULL, _E, "Memory allocation failed"); + + if (!handle->__loadProvider()) { + delete handle; + return NULL; + } + + __instanceMap[subject] = handle; + + return handle; +} + +void ProviderHandler::purge() +{ + for (InstanceMap::iterator it = __instanceMap.begin(); it != __instanceMap.end(); ++it) { + delete it->second; + } + + __instanceMap.clear(); +} + +int ProviderHandler::unregisterCustomProvider(std::string subject) +{ + InstanceMap::iterator it = __instanceMap.find(subject); + IF_FAIL_RETURN_TAG(it != __instanceMap.end(), ERR_NOT_SUPPORTED, _E, "'%s' not found", subject.c_str()); + + __instanceMap.erase(subject); + delete it->second; + + _D("'%s' unregistered", subject.c_str()); + return ERR_NONE; +} + +bool ProviderHandler::isSupported() +{ + /* If idle, self destruct */ + __scheduleToDelete(); + + return __provider->isSupported(); +} + +bool ProviderHandler::isAllowed(const Credentials *creds) +{ + /* If idle, self destruct */ + __scheduleToDelete(); + + IF_FAIL_RETURN(creds, true); /* In case of internal requests */ + + std::vector priv; + __provider->getPrivilege(priv); + + for (unsigned int i = 0; i < priv.size(); ++i) { + if (!privilege_manager::isAllowed(creds, priv[i])) + return false; + } + + return true; +} + +void ProviderHandler::subscribe(RequestInfo *request) +{ + _I(CYAN("'%s' subscribes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId()); + + Json requestResult; + int error = __provider->subscribe(request->getDescription().str(), &requestResult); + + if (!request->reply(error, requestResult) || error != ERR_NONE) { + delete request; + /* If idle, self destruct */ + __scheduleToDelete(); + return; + } + + __subscribeRequests.push_back(request); +} + +void ProviderHandler::unsubscribe(RequestInfo *request) +{ + _I(CYAN("'%s' unsubscribes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId()); + + /* Search the subscribe request to be removed */ + auto target = __findRequest(__subscribeRequests, request->getClient(), request->getId()); + if (target == __subscribeRequests.end()) { + _W("Unknown request"); + delete request; + return; + } + + /* Keep the pointer to the request found */ + RequestInfo *reqFound = *target; + + /* Remove the request from the list */ + __subscribeRequests.erase(target); + + /* Check if there exist the same requests */ + if (__findRequest(__subscribeRequests, reqFound->getDescription()) != __subscribeRequests.end()) { + /* Do not stop detecting the subject */ + _D("A same request from '%s' exists", reqFound->getClient()); + request->reply(ERR_NONE); + delete request; + delete reqFound; + return; + } + + /* Stop detecting the subject */ + int error = __provider->unsubscribe(reqFound->getDescription()); + request->reply(error); + delete request; + delete reqFound; + + /* If idle, self destruct */ + __scheduleToDelete(); +} + +void ProviderHandler::read(RequestInfo *request) +{ + _I(CYAN("'%s' reads '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId()); + + Json requestResult; + int error = __provider->read(request->getDescription().str(), &requestResult); + + if (!request->reply(error, requestResult) || error != ERR_NONE) { + delete request; + /* If idle, self destruct */ + __scheduleToDelete(); + return; + } + + __readRequests.push_back(request); +} + +void ProviderHandler::write(RequestInfo *request) +{ + _I(CYAN("'%s' writes '%s' (RID-%d)"), request->getClient(), __subject.c_str(), request->getId()); + + Json requestResult; + request->getDescription().set(NULL, KEY_CLIENT_PKG_ID, request->getPackageId()? request->getPackageId() : "SYSTEM"); + int error = __provider->write(request->getDescription(), &requestResult); + + request->reply(error, requestResult); + delete request; + + /* If idle, self destruct */ + __scheduleToDelete(); +} + +bool ProviderHandler::publish(Json &option, int error, Json &dataUpdated) +{ + auto end = __subscribeRequests.end(); + auto target = __findRequest(__subscribeRequests.begin(), end, option); + + while (target != end) { + if (!(*target)->publish(error, dataUpdated)) { + return false; + } + target = __findRequest(++target, end, option); + } + + return true; +} + +bool ProviderHandler::replyToRead(Json &option, int error, Json &dataRead) +{ + auto end = __readRequests.end(); + auto target = __findRequest(__readRequests.begin(), end, option); + auto prev = target; + + Json dummy; + + while (target != end) { + (*target)->reply(error, dummy, dataRead); + prev = target; + target = __findRequest(++target, end, option); + + delete *prev; + __readRequests.erase(prev); + } + + /* If idle, self destruct */ + __scheduleToDelete(); + + return true; +} + +bool ProviderHandler::__loadProvider() +{ + __provider = __loader.load(__subject.c_str()); + return (__provider != NULL); +} + +bool ProviderHandler::__idle() +{ + return __subscribeRequests.empty() && __readRequests.empty(); +} + +void ProviderHandler::__scheduleToDelete() +{ + if (__provider->unloadable() && !__deleteScheduled && __idle()) { + __deleteScheduled = true; + g_timeout_add_seconds(DELETE_DELAY, __deletor, this); + _D("Delete scheduled for '%s' (%#x)", __subject.c_str(), this); + } +} + +gboolean ProviderHandler::__deletor(gpointer data) +{ + ProviderHandler *handle = static_cast(data); + + if (handle->__idle()) { + __instanceMap.erase(handle->__subject); + delete handle; + return FALSE; + } + + handle->__deleteScheduled = false; + return FALSE; +} + +ProviderHandler::RequestList::iterator +ProviderHandler::__findRequest(RequestList &reqList, Json &option) +{ + return __findRequest(reqList.begin(), reqList.end(), option); +} + +ProviderHandler::RequestList::iterator +ProviderHandler::__findRequest(RequestList &reqList, std::string client, int reqId) +{ + for (auto it = reqList.begin(); it != reqList.end(); ++it) { + if (client == (*it)->getClient() && reqId == (*it)->getId()) { + return it; + } + } + return reqList.end(); +} + +ProviderHandler::RequestList::iterator +ProviderHandler::__findRequest(RequestList::iterator begin, RequestList::iterator end, Json &option) +{ + for (auto it = begin; it != end; ++it) { + if (option == (*it)->getDescription()) { + return it; + } + } + return end; +} diff --git a/src/agent/legacy/ProviderHandler.h b/src/agent/legacy/ProviderHandler.h new file mode 100644 index 0000000..58225f7 --- /dev/null +++ b/src/agent/legacy/ProviderHandler.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_PROVIDER_HANDLER_H_ +#define _CONTEXT_PROVIDER_HANDLER_H_ + +#include +#include +#include +#include +#include "ProviderLoader.h" + +namespace ctx { + + class Credentials; + class RequestInfo; + + class ProviderHandler { + typedef std::list RequestList; + typedef std::map InstanceMap; + + public: + bool isSupported(); + bool isAllowed(const Credentials *creds); + + void subscribe(RequestInfo *request); + void unsubscribe(RequestInfo *request); + void read(RequestInfo *request); + void write(RequestInfo *request); + + bool publish(ctx::Json &option, int error, ctx::Json &dataUpdated); + bool replyToRead(ctx::Json &option, int error, ctx::Json &dataRead); + + static ProviderHandler* getInstance(std::string subject, bool force); + static void purge(); + static int unregisterCustomProvider(std::string subject); + + private: + std::string __subject; + ContextProvider *__provider; + RequestList __subscribeRequests; + RequestList __readRequests; + ProviderLoader __loader; + bool __deleteScheduled; + + static InstanceMap __instanceMap; + + ProviderHandler(const std::string &subject); + ~ProviderHandler(); + + bool __loadProvider(); + bool __idle(); + void __scheduleToDelete(); + + RequestList::iterator __findRequest(RequestList &reqList, Json &option); + RequestList::iterator __findRequest(RequestList &reqList, std::string client, int reqId); + RequestList::iterator __findRequest(RequestList::iterator begin, RequestList::iterator end, Json &option); + + static gboolean __deletor(gpointer data); + + }; /* class ProviderHandler */ + +} /* namespace ctx */ + +#endif /* _CONTEXT_PROVIDER_HANDLER_H_ */ diff --git a/src/agent/legacy/ProviderLoader.cpp b/src/agent/legacy/ProviderLoader.cpp new file mode 100644 index 0000000..8a7d6a6 --- /dev/null +++ b/src/agent/legacy/ProviderLoader.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "ProviderLoader.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +using namespace ctx; + +typedef ContextProvider* (*create_t)(const char *subject); + +std::map ProviderLoader::__providerLibMap; + +ProviderLoader::ProviderLoader() : + __soHandle(NULL) +{ +} + +ProviderLoader::~ProviderLoader() +{ + __unload(); +} + +ContextProvider* ProviderLoader::load(const char *subject) +{ + ProviderLibMap::iterator it = __providerLibMap.find(subject); + if (it == __providerLibMap.end()) { + _W("No provider for '%s'", subject); + return NULL; + } + + std::string path(_LIBDIR_ LIB_PREFIX); + path = path + it->second + LIB_EXTENSION; + + return __load(path.c_str(), subject); +} + +ContextProvider* ProviderLoader::__load(const char *soPath, const char *subject) +{ + _SI("Load '%s' from '%s'", subject, soPath); + + __soHandle = g_module_open(soPath, G_MODULE_BIND_LAZY); + IF_FAIL_RETURN_TAG(__soHandle, NULL, _E, "%s", g_module_error()); + + gpointer symbol; + + if (!g_module_symbol(__soHandle, "CreateProvider", &symbol) || symbol == NULL) { + _W("%s", g_module_error()); + g_module_close(__soHandle); + __soHandle = NULL; + return NULL; + } + + create_t create = reinterpret_cast(symbol); + + ContextProvider *prvd = create(subject); + if (!prvd) { + _W("No provider for '%s'", subject); + g_module_close(__soHandle); + __soHandle = NULL; + return NULL; + } + + return prvd; +} + +void ProviderLoader::__unload() +{ + if (!__soHandle) + return; + + g_module_close(__soHandle); + __soHandle = NULL; +} + +bool ProviderLoader::init() +{ + int size = ARRAY_SIZE(subjectLibraryList); + + for (int i = 0; i < size; ++i) { + __providerLibMap[subjectLibraryList[i].subject] = subjectLibraryList[i].library; + _SD("'%s' -> '%s'", subjectLibraryList[i].subject, subjectLibraryList[i].library); + } + + return true; +} + +bool ProviderLoader::popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option) +{ + static int i = 0; + static int size = ARRAY_SIZE(triggerTemplateList); + + if (i == size) + return false; + + subject = triggerTemplateList[i].subject; + operation = triggerTemplateList[i].operation; + attribute = triggerTemplateList[i].attribute; + option = triggerTemplateList[i].option; + + ++i; + return true; +} diff --git a/src/agent/legacy/ProviderLoader.h b/src/agent/legacy/ProviderLoader.h new file mode 100644 index 0000000..ab5a427 --- /dev/null +++ b/src/agent/legacy/ProviderLoader.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_PROVIDER_LOADER_H_ +#define _CONTEXT_PROVIDER_LOADER_H_ + +#include +#include + +namespace ctx { + + class ContextProvider; + + struct CompareSubjectName { + bool operator()(const char *left, const char *right) const { + while (*left != '\0' && *right != '\0') { + if (*left < *right) + return true; + if (*left > *right) + return false; + ++left; + ++right; + } + return false; + } + }; + + class ProviderLoader { + typedef std::map ProviderLibMap; + + public: + ProviderLoader(); + ~ProviderLoader(); + + ContextProvider* load(const char *subject); + + static bool init(); + static bool popTriggerTemplate(std::string &subject, int &operation, Json &attribute, Json &option); + + private: + ContextProvider* __load(const char *soPath, const char *subject); + void __unload(); + + GModule *__soHandle; + static ProviderLibMap __providerLibMap; + }; + +} + +#endif /* _CONTEXT_PROVIDER_LOADER_H_ */ diff --git a/src/agent/legacy/Request.cpp b/src/agent/legacy/Request.cpp new file mode 100644 index 0000000..d900fcc --- /dev/null +++ b/src/agent/legacy/Request.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "Request.h" + +ctx::RequestInfo::RequestInfo(int type, int reqId, const char* subj, const char* desc) : + __type(type), + __reqId(reqId), + __subject(subj), + __description(desc) +{ +} + +ctx::RequestInfo::~RequestInfo() +{ +} + +int ctx::RequestInfo::getType() +{ + return __type; +} + +int ctx::RequestInfo::getId() +{ + return __reqId; +} + +const ctx::Credentials* ctx::RequestInfo::getCredentials() +{ + return NULL; +} + +const char* ctx::RequestInfo::getPackageId() +{ + return NULL; +} + +const char* ctx::RequestInfo::getClient() +{ + return NULL; +} + +const char* ctx::RequestInfo::getSubject() +{ + return __subject.c_str(); +} + +ctx::Json& ctx::RequestInfo::getDescription() +{ + return __description; +} diff --git a/src/agent/legacy/Request.h b/src/agent/legacy/Request.h new file mode 100644 index 0000000..9750b2f --- /dev/null +++ b/src/agent/legacy/Request.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_REQUEST_INFO_H_ +#define _CONTEXT_REQUEST_INFO_H_ + +#include +#include + +namespace ctx { + + /* Forward declaration */ + class Credentials; + + class RequestInfo { + public: + RequestInfo(int type, int reqId, const char *subj, const char *desc); + virtual ~RequestInfo(); + + int getType(); + int getId(); + const char* getSubject(); + ctx::Json& getDescription(); + + virtual const Credentials* getCredentials(); + virtual const char* getPackageId(); + /* TODO: remove this getClient() */ + virtual const char* getClient(); + virtual bool reply(int error) = 0; + virtual bool reply(int error, ctx::Json &requestResult) = 0; + virtual bool reply(int error, ctx::Json &requestResult, ctx::Json &dataRead) = 0; + virtual bool publish(int error, ctx::Json &data) = 0; + + protected: + int __type; + int __reqId; + std::string __subject; + ctx::Json __description; + }; + +} /* namespace ctx */ + +#endif /* End of _CONTEXT_REQUEST_INFO_H_ */ diff --git a/src/agent/legacy/Server.cpp b/src/agent/legacy/Server.cpp new file mode 100644 index 0000000..197b0d6 --- /dev/null +++ b/src/agent/legacy/Server.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include "DBusServer.h" +#include "ContextManager.h" +#include "policy/PolicyManager.h" +#include "trigger/Trigger.h" +#include "Server.h" + +#define RUN(L) g_main_loop_run((L)) +#define QUIT(L) if (g_main_loop_is_running((L)) == TRUE) g_main_loop_quit((L)) + + +static GMainLoop *mainloop = NULL; +static bool started = false; + +static ctx::ContextManager *__contextMgr = NULL; +static ctx::DBusServer *__dbusHandle = NULL; +static ctx::PolicyManager *__policyMgr = NULL; +static ctx::trigger::Trigger *__contextTrigger = NULL; +static ctx::TimerManager __timerManager; + +/* TODO: re-organize activation & deactivation processes */ +void ctx::Server::initialize() +{ + _I("Init Dbus Connection"); + __dbusHandle = new(std::nothrow) ctx::DBusServer(); + IF_FAIL_VOID_TAG(__dbusHandle, _E, "Memory allocation failed"); + IF_FAIL_VOID_TAG(__dbusHandle->__init(), _E, "Initialization Failed"); + + // Start the main loop + _I(CYAN("Launching Context-Service")); + RUN(mainloop); +} + +void ctx::Server::activate() +{ + IF_FAIL_VOID(!started); + + bool result = false; + + _I("Init Database Manager"); + IF_FAIL_CATCH(DatabaseManager::__init()); + + _I("Init Context Manager"); + __contextMgr = new(std::nothrow) ctx::ContextManager(); + IF_FAIL_CATCH_TAG(__contextMgr, _E, "Memory allocation failed"); + result = __contextMgr->init(); + IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed"); + + _I("Init Context Trigger"); + __contextTrigger = new(std::nothrow) ctx::trigger::Trigger(); + IF_FAIL_CATCH_TAG(__contextTrigger, _E, "Memory allocation failed"); + result = __contextTrigger->init(__contextMgr); + IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed"); + + _I("Init Policy Manager"); + __policyMgr = new(std::nothrow) ctx::PolicyManager(__contextMgr); + IF_FAIL_CATCH_TAG(__policyMgr, _E, "Memory allocation failed"); + + started = true; + _I(CYAN("Context-Service Launched")); + return; + +CATCH: + _E(RED("Launching Failed")); + + // Stop the main loop + QUIT(mainloop); +} + +void ctx::Server::release() +{ + _I(CYAN("Terminating Context-Service")); + started = false; + + _I("Release Policy Manager"); + delete __policyMgr; + + _I("Release Context Trigger"); + if (__contextTrigger) + __contextTrigger->release(); + + _I("Release Context Manager"); + if (__contextMgr) + __contextMgr->release(); + + _I("Release Database Manager"); + DatabaseManager::__release(); + + delete __contextTrigger; + delete __contextMgr; + delete __dbusHandle; +} + +static gboolean __postponeRequestAssignment(gpointer data) +{ + ctx::Server::sendRequest(static_cast(data)); + return FALSE; +} + +void ctx::Server::sendRequest(ctx::RequestInfo* request) +{ + if (!started) { + _W("Service not ready..."); + g_idle_add(__postponeRequestAssignment, request); + return; + } + + if (__contextTrigger->assignRequest(request)) + return; + + __contextMgr->assignRequest(request); +} + +static void __signalHandler(int signo) +{ + _I("SIGNAL %d received", signo); + + // Stop the main loop + QUIT(mainloop); +} + +int main(int argc, char* argv[]) +{ + static struct sigaction signalAction; + signalAction.sa_handler = __signalHandler; + sigemptyset(&signalAction.sa_mask); + + sigaction(SIGINT, &signalAction, NULL); + sigaction(SIGHUP, &signalAction, NULL); + sigaction(SIGTERM, &signalAction, NULL); + sigaction(SIGQUIT, &signalAction, NULL); + sigaction(SIGABRT, &signalAction, NULL); + +#if !defined(GLIB_VERSION_2_36) + g_type_init(); +#endif + + _I("Init MainLoop"); + mainloop = g_main_loop_new(NULL, FALSE); + + ctx::Server::initialize(); + ctx::Server::release(); + + g_main_loop_unref(mainloop); + + return EXIT_SUCCESS; +} diff --git a/src/agent/legacy/Server.h b/src/agent/legacy/Server.h new file mode 100644 index 0000000..cd93bbf --- /dev/null +++ b/src/agent/legacy/Server.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_SERVER_H_ +#define _CONTEXT_SERVER_H_ + +namespace ctx { + + class RequestInfo; + + class Server { + public: + static void initialize(); + static void activate(); + static void release(); + static void sendRequest(RequestInfo* request); + + }; + +} /* namespace ctx */ + +#endif /* End of _CONTEXT_SERVER_H_ */ diff --git a/src/agent/legacy/access_control/PeerCreds.cpp b/src/agent/legacy/access_control/PeerCreds.cpp new file mode 100644 index 0000000..336da5a --- /dev/null +++ b/src/agent/legacy/access_control/PeerCreds.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "PeerCreds.h" + +ctx::Credentials::Credentials(char *pkgId, char *cli, char *sess, char *usr) : + packageId(pkgId), + client(cli), + session(sess), + user(usr) +{ +} + +ctx::Credentials::~Credentials() +{ + g_free(packageId); + g_free(client); + g_free(session); + g_free(user); +} + +bool ctx::peer_creds::get(GDBusConnection *connection, const char *uniqueName, const char *cookie, ctx::Credentials **creds) +{ + pid_t pid = 0; + char *app_id = NULL; + char *packageId = NULL; + gchar *client = NULL; + char *session = NULL; + gchar *user = NULL; + + int err = cynara_creds_gdbus_get_pid(connection, uniqueName, &pid); + IF_FAIL_RETURN_TAG(err == CYNARA_API_SUCCESS, false, _E, "Peer credentialing failed"); + + session = cynara_session_from_pid(pid); + IF_FAIL_CATCH_TAG(session, _E, "Peer credentialing failed"); + + err = cynara_creds_gdbus_get_client(connection, uniqueName, CLIENT_METHOD_DEFAULT, &client); + IF_FAIL_CATCH_TAG(err == CYNARA_API_SUCCESS, _E, "Peer credentialing failed"); + + err = cynara_creds_gdbus_get_user(connection, uniqueName, USER_METHOD_DEFAULT, &user); + IF_FAIL_CATCH_TAG(err == CYNARA_API_SUCCESS, _E, "Peer credentialing failed"); + + app_manager_get_app_id(pid, &app_id); + package_manager_get_package_id_by_app_id(app_id, &packageId); + _D("AppId: %s, PackageId: %s", app_id, packageId); + g_free(app_id); + + *creds = new(std::nothrow) Credentials(packageId, client, session, user); + IF_FAIL_CATCH_TAG(*creds, _E, "Memory allocation failed"); + + return true; + +CATCH: + g_free(packageId); + g_free(client); + g_free(session); + g_free(user); + return false; +} diff --git a/src/agent/legacy/access_control/PeerCreds.h b/src/agent/legacy/access_control/PeerCreds.h new file mode 100644 index 0000000..255244e --- /dev/null +++ b/src/agent/legacy/access_control/PeerCreds.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_PEER_CREDENTIALS_H_ +#define _CONTEXT_PEER_CREDENTIALS_H_ + +#include +#include +#include + +namespace ctx { + + class Credentials { + public: + char *packageId; + char *client; /* default: smack label */ + char *session; + char *user; /* default: UID */ + Credentials(char *pkgId, char *cli, char *sess, char *usr); + ~Credentials(); + }; + + namespace peer_creds { + + bool get(GDBusConnection *connection, const char *uniqueName, const char *cookie, Credentials **creds); + + } /* namespace peer_creds */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_PEER_CREDENTIALS_H_ */ diff --git a/src/agent/legacy/access_control/Privilege.cpp b/src/agent/legacy/access_control/Privilege.cpp new file mode 100644 index 0000000..da2bdae --- /dev/null +++ b/src/agent/legacy/access_control/Privilege.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "PeerCreds.h" +#include "Privilege.h" + +#define PRIV_PREFIX "http://tizen.org/privilege/" +#define CACHE_SIZE 100 + +class PermissionChecker { +private: + cynara *__cynara; + + PermissionChecker() + { + cynara_configuration *conf; + + int err = cynara_configuration_create(&conf); + IF_FAIL_VOID_TAG(err == CYNARA_API_SUCCESS, _E, "Cynara configuration creation failed"); + + err = cynara_configuration_set_cache_size(conf, CACHE_SIZE); + if (err != CYNARA_API_SUCCESS) { + _E("Cynara cache size set failed"); + cynara_configuration_destroy(conf); + return; + } + + err = cynara_initialize(&__cynara, conf); + cynara_configuration_destroy(conf); + if (err != CYNARA_API_SUCCESS) { + _E("Cynara initialization failed"); + __cynara = NULL; + return; + } + + _I("Cynara initialized"); + } + + ~PermissionChecker() + { + if (__cynara) + cynara_finish(__cynara); + + _I("Cynara deinitialized"); + } + +public: + static PermissionChecker& getInstance() + { + static PermissionChecker instance; + return instance; + } + + bool hasPermission(const ctx::Credentials *creds, const char *privilege) + { + IF_FAIL_RETURN_TAG(__cynara, false, _E, "Cynara not initialized"); + int ret = cynara_check(__cynara, creds->client, creds->session, creds->user, privilege); + return (ret == CYNARA_API_ACCESS_ALLOWED); + } +}; + +bool ctx::privilege_manager::isAllowed(const ctx::Credentials *creds, const char *privilege) +{ + IF_FAIL_RETURN(creds && privilege, true); + + std::string priv = PRIV_PREFIX; + priv += privilege; + + return PermissionChecker::getInstance().hasPermission(creds, priv.c_str()); +} diff --git a/src/agent/legacy/access_control/Privilege.h b/src/agent/legacy/access_control/Privilege.h new file mode 100644 index 0000000..6eb1198 --- /dev/null +++ b/src/agent/legacy/access_control/Privilege.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_PRIVILEGE_MANAGER_H_ +#define _CONTEXT_PRIVILEGE_MANAGER_H_ + +namespace ctx { + + /* Forward declaration */ + class Credentials; + + namespace privilege_manager { + + bool isAllowed(const Credentials *creds, const char *privilege); + + } /* namespace privilege_manager */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_PRIVILEGE_MANAGER_H_ */ diff --git a/src/agent/legacy/policy/PolicyManager.cpp b/src/agent/legacy/policy/PolicyManager.cpp new file mode 100644 index 0000000..3f97344 --- /dev/null +++ b/src/agent/legacy/policy/PolicyManager.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "../ContextManager.h" +#include "PolicyRequest.h" +#include "PolicyManager.h" + +using namespace ctx; + +PolicyManager::PolicyManager(ContextManager *contextMgr) : + __contextMgr(contextMgr) +{ + __subscribe(SUBJ_CUSTOM); + + __subscribe(SUBJ_APP_LOGGER); + __subscribe(SUBJ_BATTERY_LOGGER); + __subscribe(SUBJ_MEDIA_LOGGER); + __subscribe(SUBJ_PLACE_DETECTION); + __subscribe(SUBJ_STATE_WIFI); + + __subscribe(SUBJ_SENSOR_PEDOMETER); + __subscribe(SUBJ_SENSOR_PRESSURE); + __subscribe(SUBJ_SENSOR_SLEEP_MONITOR); + __subscribe(SUBJ_SENSOR_HEART_RATE); +} + +PolicyManager::~PolicyManager() +{ + for (auto &it : __subscriptionMap) { + PolicyRequest *req = new(std::nothrow) PolicyRequest(REQ_UNSUBSCRIBE, it.first, it.second, NULL); + if (!req) { + _E("Memory allocation failed"); + continue; + } + __contextMgr->assignRequest(req); + } + + __subscriptionMap.clear(); +} + +void PolicyManager::__subscribe(const char *subject) +{ + static int rid = 0; + ++rid; + + PolicyRequest *req = new(std::nothrow) PolicyRequest(REQ_SUBSCRIBE, rid, subject, NULL); + IF_FAIL_VOID_TAG(req, _E, "Memory allocation failed"); + + __contextMgr->assignRequest(req); + + __subscriptionMap[rid] = subject; +} diff --git a/src/agent/legacy/policy/PolicyManager.h b/src/agent/legacy/policy/PolicyManager.h new file mode 100644 index 0000000..ce9b315 --- /dev/null +++ b/src/agent/legacy/policy/PolicyManager.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_POLICY_MANAGER_H_ +#define _CONTEXT_POLICY_MANAGER_H_ + +#include + +namespace ctx { + + class ContextManger; + + class PolicyManager { + public: + ~PolicyManager(); + + private: + PolicyManager(ContextManager *contextMgr); + + void __subscribe(const char *subject); + + ContextManager *__contextMgr; + std::map __subscriptionMap; + + friend class Server; + }; + +} /* namespace ctx */ + +#endif /* _CONTEXT_POLICY_MANAGER_H_ */ diff --git a/src/agent/legacy/policy/PolicyRequest.cpp b/src/agent/legacy/policy/PolicyRequest.cpp new file mode 100644 index 0000000..63cf8ae --- /dev/null +++ b/src/agent/legacy/policy/PolicyRequest.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * 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 "PolicyRequest.h" + +using namespace ctx; + +PolicyRequest::PolicyRequest(int type, int reqId, const char *subj, const char *desc) : + RequestInfo(type, reqId, subj, desc) +{ +} + +PolicyRequest::~PolicyRequest() +{ +} + +const char* PolicyRequest::getClient() +{ + return "POLICY"; +} + +bool PolicyRequest::reply(int error) +{ + return true; +} + +bool PolicyRequest::reply(int error, ctx::Json &requestResult) +{ + return true; +} + +bool PolicyRequest::reply(int error, ctx::Json &requestResult, ctx::Json &dataRead) +{ + return true; +} + +bool PolicyRequest::publish(int error, ctx::Json &data) +{ + return true; +} diff --git a/src/agent/legacy/policy/PolicyRequest.h b/src/agent/legacy/policy/PolicyRequest.h new file mode 100644 index 0000000..2ed28c7 --- /dev/null +++ b/src/agent/legacy/policy/PolicyRequest.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_POLICY_REQUEST_H_ +#define _CONTEXT_POLICY_REQUEST_H_ + +#include "../Request.h" + +namespace ctx { + + class PolicyRequest : public RequestInfo { + public: + PolicyRequest(int type, int reqId, const char *subj, const char *desc); + ~PolicyRequest(); + + const char* getClient(); + + bool reply(int error); + bool reply(int error, ctx::Json &requestResult); + bool reply(int error, ctx::Json &requestResult, ctx::Json &dataRead); + bool publish(int error, ctx::Json &data); + }; + +} /* namespace ctx */ + +#endif /* End of _CONTEXT_POLICY_REQUEST_H_ */ diff --git a/src/agent/legacy/trigger/ActionManager.cpp b/src/agent/legacy/trigger/ActionManager.cpp new file mode 100644 index 0000000..b45671f --- /dev/null +++ b/src/agent/legacy/trigger/ActionManager.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../DBusServer.h" +#include "ActionManager.h" + +using namespace ctx; + +static void __triggerActionAppControl(Json& action); +static void __triggerActionNotification(Json& action, std::string pkgId); +static void __triggerActionDbusCall(Json& action); + +void trigger::action_manager::triggerAction(Json& action, std::string pkgId) +{ + std::list types; + action.getKeys(&types); + IF_FAIL_VOID_TAG(types.size() == 1, _E, "Invalid action"); + + std::string& type = *(types.begin()); + + if (type.compare(TRIG_RULE_KEY_APP_LAUNCH) == 0) { + __triggerActionAppControl(action); + } else if (type.compare(TRIG_RULE_KEY_NOTIFICATION) == 0) { + __triggerActionNotification(action, pkgId); + } else if (type.compare(TRIG_RULE_KEY_DBUS_CALL) == 0) { + __triggerActionDbusCall(action); + } +} + +void __triggerActionAppControl(Json& action) +{ + int error; + std::string appctlStr; + action.get(TRIG_RULE_KEY_APP_LAUNCH, TRIG_RULE_KEY_APP_LAUNCH_APP_CONTROL, &appctlStr); + + char* str = static_cast(malloc(appctlStr.length())); + if (str == NULL) { + _E("Memory allocation failed"); + return; + } + appctlStr.copy(str, appctlStr.length(), 0); + bundle_raw* encoded = reinterpret_cast(str); + bundle* appctlBundle = bundle_decode(encoded, appctlStr.length()); + + app_control_h app = NULL; + app_control_create(&app); + app_control_import_from_bundle(app, appctlBundle); + + error = app_control_send_launch_request(app, NULL, NULL); + if (error != APP_CONTROL_ERROR_NONE) { + _E("Launch request failed(%d)", error); + } else { + _D("Launch request succeeded"); + } + bundle_free(appctlBundle); + free(str); + app_control_destroy(app); + + error = device_display_change_state(DISPLAY_STATE_NORMAL); + if (error != DEVICE_ERROR_NONE) { + _E("Change display state failed(%d)", error); + } +} + +void __triggerActionNotification(Json& action, std::string pkgId) +{ + int error; + notification_h notification = notification_create(NOTIFICATION_TYPE_NOTI); + std::string title; + if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_TITLE, &title)) { + error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_TITLE, title.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set notification title failed(%d)", error); + } + } + + std::string content; + if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_CONTENT, &content)) { + error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_CONTENT, content.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set notification contents failed(%d)", error); + } + } + + std::string imagePath; + if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_ICON_PATH, &imagePath)) { + error = notification_set_image(notification, NOTIFICATION_IMAGE_TYPE_ICON, imagePath.c_str()); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set notification icon image failed(%d)", error); + } + } + + std::string appctlStr; + char* str = NULL; + bundle_raw* encoded = NULL; + bundle* appctlBundle = NULL; + app_control_h app = NULL; + if (action.get(TRIG_RULE_KEY_NOTIFICATION, TRIG_RULE_KEY_NOTI_APP_CONTROL, &appctlStr)) { + str = static_cast(malloc(appctlStr.length())); + if (str == NULL) { + _E("Memory allocation failed"); + notification_free(notification); + return; + } + appctlStr.copy(str, appctlStr.length(), 0); + encoded = reinterpret_cast(str); + appctlBundle = bundle_decode(encoded, appctlStr.length()); + + app_control_create(&app); + app_control_import_from_bundle(app, appctlBundle); + + error = notification_set_launch_option(notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, app); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set launch option failed(%d)", error); + } + } + + if (!pkgId.empty()) { + error = notification_set_pkgname(notification, pkgId.c_str()); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set package id(%s) failed(%#x)", pkgId.c_str(), error); + } + } + + int soundOn = 0; + error = vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &soundOn); + if (error < 0) { + _E("vconf error (%d)", error); + } else if (soundOn) { + error = notification_set_sound(notification, NOTIFICATION_SOUND_TYPE_DEFAULT, NULL); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set notification sound failed(%d)", error); + } + } + + int vibrationOn = 0; + error = vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibrationOn); + if (error < 0) { + _E("vconf error (%d)", error); + } else if (vibrationOn) { + error = notification_set_vibration(notification, NOTIFICATION_VIBRATION_TYPE_DEFAULT, NULL); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Set notification vibration failed(%d)", error); + } + } + + error = notification_post(notification); + if (error != NOTIFICATION_ERROR_NONE) { + _E("Post notification failed(%d)", error); + } else { + _D("Post notification succeeded"); + } + + bundle_free(appctlBundle); + free(str); + notification_free(notification); + if (app) { + app_control_destroy(app); + } + + error = device_display_change_state(DISPLAY_STATE_NORMAL); + if (error != DEVICE_ERROR_NONE) { + _E("Change display state failed(%d)", error); + } +} + +void __triggerActionDbusCall(Json& action) +{ + std::string busName, object, iface, method; + GVariant *param = NULL; + + action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_NAME, &busName); + IF_FAIL_VOID_TAG(!busName.empty(), _E, "No target bus name"); + + action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_OBJECT, &object); + IF_FAIL_VOID_TAG(!object.empty(), _E, "No object path"); + + action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_INTERFACE, &iface); + IF_FAIL_VOID_TAG(!iface.empty(), _E, "No interface name"); + + action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_METHOD, &method); + IF_FAIL_VOID_TAG(!method.empty(), _E, "No method name"); + + action.get(TRIG_RULE_KEY_DBUS_CALL, TRIG_RULE_KEY_DBUS_PARAMETER, ¶m); + + DBusServer::call(busName, object, iface, method, param); +} diff --git a/src/agent/legacy/trigger/ActionManager.h b/src/agent/legacy/trigger/ActionManager.h new file mode 100644 index 0000000..273f450 --- /dev/null +++ b/src/agent/legacy/trigger/ActionManager.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_ACTION_MANAGER_H_ +#define _CONTEXT_TRIGGER_ACTION_MANAGER_H_ + +namespace ctx { + /* Forward Declaration */ + class Json; + +namespace trigger { + + namespace action_manager { + + void triggerAction(Json& action, std::string pkgId); + + } /* namespace action_manager */ + +} /* namespace trigger*/ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_ACTION_MANAGER_H_ */ diff --git a/src/agent/legacy/trigger/ContextMonitor.cpp b/src/agent/legacy/trigger/ContextMonitor.cpp new file mode 100644 index 0000000..5dab7f5 --- /dev/null +++ b/src/agent/legacy/trigger/ContextMonitor.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "../access_control/Privilege.h" +#include "../ContextManager.h" +#include "ContextMonitor.h" +#include "IContextListener.h" +#include "FactRequest.h" + +using namespace ctx; +using namespace trigger; + +static int __lastRid; +static int __lastErr; + +ContextMonitor *ContextMonitor::__instance = NULL; +ContextManager *ContextMonitor::__contextMgr = NULL; + +static int __generateReqId() +{ + static int reqId = 0; + + if (++reqId < 0) { + // Overflow handling + reqId = 1; + } + + return reqId; +} + +ContextMonitor::ContextMonitor() +{ +} + +ContextMonitor::~ContextMonitor() +{ +} + +void ContextMonitor::setContextManager(ContextManager* ctxMgr) +{ + __contextMgr = ctxMgr; +} + +ContextMonitor* ContextMonitor::getInstance() +{ + IF_FAIL_RETURN_TAG(__contextMgr, NULL, _E, "Context manager is needed"); + + IF_FAIL_RETURN(!__instance, __instance); + + __instance = new(std::nothrow) ContextMonitor(); + IF_FAIL_RETURN_TAG(__instance, NULL, _E, "Memory alllocation failed"); + + return __instance; +} + +void ContextMonitor::destroy() +{ + if (__instance) { + delete __instance; + __instance = NULL; + } +} + +int ContextMonitor::subscribe(int ruleId, std::string subject, Json option, IContextListener* listener) +{ + int reqId = __subscribe(subject.c_str(), &option, listener); + IF_FAIL_RETURN_TAG(reqId > 0, reqId, _E, "Subscribe event failed"); + _D(YELLOW("Subscribe event(rule%d). req%d"), ruleId, reqId); + + return ERR_NONE; +} + +int ContextMonitor::__subscribe(const char* subject, Json* option, IContextListener* listener) +{ + IF_FAIL_RETURN(subject, ERR_INVALID_PARAMETER); + + int rid = __findSub(REQ_SUBSCRIBE, subject, option); + if (rid > 0) { + __addListener(REQ_SUBSCRIBE, rid, listener); + _D("Duplicated request for %s", subject); + return rid; + } + + rid = __generateReqId(); + + FactRequest *req = new(std::nothrow) FactRequest(REQ_SUBSCRIBE, + rid, subject, option ? option->str().c_str() : NULL, this); + IF_FAIL_RETURN_TAG(req, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed"); + + __contextMgr->assignRequest(req); + __addSub(REQ_SUBSCRIBE, rid, subject, option, listener); + + if (__lastErr != ERR_NONE) { + __removeSub(REQ_SUBSCRIBE, rid); + _E("Subscription request failed: %#x", __lastErr); + return __lastErr; + } + + return rid; +} + +int ContextMonitor::unsubscribe(int ruleId, std::string subject, Json option, IContextListener* listener) +{ + int rid = __findSub(REQ_SUBSCRIBE, subject.c_str(), &option); + if (rid < 0) { + _D("Invalid unsubscribe request"); + return ERR_INVALID_PARAMETER; + } + + if (__removeListener(REQ_SUBSCRIBE, rid, listener) <= 0) { + __unsubscribe(subject.c_str(), rid); + } + _D(YELLOW("Unsubscribe event(rule%d). req%d"), ruleId, rid); + + return ERR_NONE; +} + +void ContextMonitor::__unsubscribe(const char *subject, int subscriptionId) +{ + FactRequest *req = new(std::nothrow) FactRequest(REQ_UNSUBSCRIBE, subscriptionId, subject, NULL, NULL); + IF_FAIL_VOID_TAG(req, _E, "Memory allocation failed"); + + __contextMgr->assignRequest(req); + __removeSub(REQ_SUBSCRIBE, subscriptionId); +} + +int ContextMonitor::read(std::string subject, Json option, IContextListener* listener) +{ + int reqId = __read(subject.c_str(), &option, listener); + IF_FAIL_RETURN_TAG(reqId > 0, ERR_OPERATION_FAILED, _E, "Read condition failed"); + _D(YELLOW("Read condition(%s). req%d"), subject.c_str(), reqId); + + return ERR_NONE; +} + +int ContextMonitor::__read(const char* subject, Json* option, IContextListener* listener) +{ + IF_FAIL_RETURN(subject, ERR_INVALID_PARAMETER); + + int rid = __findSub(REQ_READ, subject, option); + if (rid > 0) { + __addListener(REQ_READ, rid, listener); + _D("Duplicated request for %s", subject); + return rid; + } + + rid = __generateReqId(); + + FactRequest *req = new(std::nothrow) FactRequest(REQ_READ, + rid, subject, option ? option->str().c_str() : NULL, this); + IF_FAIL_RETURN_TAG(req, -1, _E, "Memory allocation failed"); + + __contextMgr->assignRequest(req); + __addSub(REQ_READ, rid, subject, option, listener); + + if (__lastErr != ERR_NONE) { + _E("Read request failed: %#x", __lastErr); + return -1; + } + + return rid; +} + +bool ContextMonitor::isSupported(std::string subject) +{ + return __contextMgr->isSupported(subject.c_str()); +} + +bool ContextMonitor::isAllowed(const char *client, const char *subject) +{ + //TODO: re-implement this in the proper 3.0 style + //return __contextMgr->isAllowed(client, subject); + return true; +} + +int ContextMonitor::__findSub(RequestType type, const char* subject, Json* option) +{ + // @return request id + std::map* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap; + + Json jOpt; + if (option) { + jOpt = *option; + } + + for (auto it = map->begin(); it != map->end(); ++it) { + if ((*(it->second)).subject == subject && (*(it->second)).option == jOpt) { + return it->first; + } + } + + return -1; +} + +bool ContextMonitor::__addSub(RequestType type, int sid, const char* subject, Json* option, IContextListener* listener) +{ + std::map* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap; + + SubscrInfo *info = new(std::nothrow) SubscrInfo(sid, subject, option); + IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed"); + info->listenerList.push_back(listener); + + map->insert(std::pair(sid, info)); + return true; +} + +void ContextMonitor::__removeSub(RequestType type, const char* subject, Json* option) +{ + std::map* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap; + + Json jOpt; + if (option) { + jOpt = *option; + } + + for (auto it = map->begin(); it != map->end(); ++it) { + if ((*(it->second)).subject == subject && (*(it->second)).option == jOpt) { + delete it->second; + map->erase(it); + return; + } + } +} + +void ContextMonitor::__removeSub(RequestType type, int sid) +{ + std::map* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap; + + SubscrInfo* info = map->at(sid); + info->listenerList.clear(); + + delete info; + map->erase(sid); + + return; +} + +int ContextMonitor::__addListener(RequestType type, int sid, IContextListener* listener) +{ + // @return number of listeners for the corresponding sid + std::map* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap; + + auto it = map->find(sid); + + SubscrInfo* info = it->second; + info->listenerList.push_back(listener); + + return info->listenerList.size(); +} + +int ContextMonitor::__removeListener(RequestType type, int sid, IContextListener* listener) +{ + // @return number of listeners for the corresponding sid + std::map* map = (type == REQ_SUBSCRIBE)? &__subscrMap : &__readMap; + + auto it = map->find(sid); + + SubscrInfo* info = it->second; + + for (auto it2 = info->listenerList.begin(); it2 != info->listenerList.end(); ++it2) { + if (*it2 == listener) { + info->listenerList.erase(it2); + break; + } + } + + return info->listenerList.size(); +} + +void ContextMonitor::replyResult(int reqId, int error, Json* requestResult) +{ + _D("Request result received: %d", reqId); + + __lastRid = reqId; + __lastErr = error; +} + +void ContextMonitor::replyResult(int reqId, int error, const char* subject, Json* option, Json* fact) +{ + _D(YELLOW("Condition received: subject(%s), option(%s), fact(%s)"), subject, option->str().c_str(), fact->str().c_str()); + + auto it = __readMap.find(reqId); + IF_FAIL_VOID_TAG(it != __readMap.end(), _E, "Request id not found"); + + SubscrInfo* info = it->second; + for (auto it2 = info->listenerList.begin(); it2 != info->listenerList.end(); ++it2) { + (*it2)->onConditionReceived(subject, *option, *fact); + } + + __removeSub(REQ_READ, reqId); +} + +void ContextMonitor::publishFact(int reqId, int error, const char* subject, Json* option, Json* fact) +{ + _D(YELLOW("Event received: subject(%s), option(%s), fact(%s)"), subject, option->str().c_str(), fact->str().c_str()); + + auto it = __subscrMap.find(reqId); + IF_FAIL_VOID_TAG(it != __subscrMap.end(), _E, "Request id not found"); + + SubscrInfo* info = it->second; + for (auto it2 = info->listenerList.begin(); it2 != info->listenerList.end(); ++it2) { + (*it2)->onEventReceived(subject, *option, *fact); + } +} diff --git a/src/agent/legacy/trigger/ContextMonitor.h b/src/agent/legacy/trigger/ContextMonitor.h new file mode 100644 index 0000000..473cac2 --- /dev/null +++ b/src/agent/legacy/trigger/ContextMonitor.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_CONTEXT_MONITOR_H_ +#define _CONTEXT_TRIGGER_CONTEXT_MONITOR_H_ + +#include +#include +#include +#include + +namespace ctx { + + class ContextManager; + +namespace trigger { + + class IContextListener; + class FactRequest; + + class ContextMonitor { + public: + static ContextMonitor* getInstance(); + static void setContextManager(ContextManager* ctxMgr); + static void destroy(); + + int subscribe(int ruleId, std::string subject, Json option, IContextListener* listener); + int unsubscribe(int ruleId, std::string subject, Json option, IContextListener* listener); + int read(std::string subject, Json option, IContextListener* listener); + bool isSupported(std::string subject); + bool isAllowed(const char *client, const char *subject); + + void replyResult(int reqId, int error, Json *requestResult = NULL); + void replyResult(int reqId, int error, const char *subject, Json *option, Json *fact); + void publishFact(int reqId, int error, const char *subject, Json *option, Json *fact); + + private: + ContextMonitor(); + ContextMonitor(const ContextMonitor& other); + ~ContextMonitor(); + + static ContextMonitor *__instance; + static ContextManager *__contextMgr; + + int __subscribe(const char* subject, Json* option, IContextListener* listener); + void __unsubscribe(const char *subject, int subscriptionId); + int __read(const char *subject, Json *option, IContextListener* listener); + + struct SubscrInfo { + int sid; + std::string subject; + Json option; + std::list listenerList; + + SubscrInfo(int id, const char *subj, Json *opt) : + sid(id), + subject(subj) + { + if (opt) + option = *opt; + } + }; + + std::map __subscrMap; + std::map __readMap; + + int __findSub(RequestType type, const char *subject, Json *option); + bool __addSub(RequestType type, int sid, const char *subject, Json *option, IContextListener* listener); + void __removeSub(RequestType type, const char *subject, Json *option); + void __removeSub(RequestType type, int sid); + int __addListener(RequestType type, int sid, IContextListener* listener); + int __removeListener(RequestType type, int sid, IContextListener* listener); + + }; /* class ContextMonitor */ + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_CONTEXT_MONITOR_H_ */ diff --git a/src/agent/legacy/trigger/FactRequest.cpp b/src/agent/legacy/trigger/FactRequest.cpp new file mode 100644 index 0000000..fc09d9d --- /dev/null +++ b/src/agent/legacy/trigger/FactRequest.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "FactRequest.h" + +using namespace ctx; +using namespace ctx::trigger; + +FactRequest::FactRequest(int type, int reqId, const char* subj, const char* desc, ContextMonitor* ctxMonitor) : + RequestInfo(type, reqId, subj, desc), + __ctxMonitor(ctxMonitor), + __replied(false) +{ +} + +FactRequest::~FactRequest() +{ + reply(ERR_OPERATION_FAILED); +} + +const char* FactRequest::getClient() +{ + return "TRIGGER"; +} + +bool FactRequest::reply(int error) +{ + IF_FAIL_RETURN(!__replied && __ctxMonitor, true); + __ctxMonitor->replyResult(__reqId, error); + __replied = (error != ERR_NONE); + return true; +} + +bool FactRequest::reply(int error, Json& requestResult) +{ + IF_FAIL_RETURN(!__replied && __ctxMonitor, true); + __ctxMonitor->replyResult(__reqId, error, &requestResult); + __replied = (error != ERR_NONE); + return true; +} + +bool FactRequest::reply(int error, Json& requestResult, Json& dataRead) +{ + IF_FAIL_RETURN(!__replied && __ctxMonitor, true); + __ctxMonitor->replyResult(__reqId, error, __subject.c_str(), &getDescription(), &dataRead); + return (__replied = true); +} + +bool FactRequest::publish(int error, Json& data) +{ + IF_FAIL_RETURN(__ctxMonitor, true); + __ctxMonitor->publishFact(__reqId, error, __subject.c_str(), &getDescription(), &data); + return true; +} diff --git a/src/agent/legacy/trigger/FactRequest.h b/src/agent/legacy/trigger/FactRequest.h new file mode 100644 index 0000000..8c54fe8 --- /dev/null +++ b/src/agent/legacy/trigger/FactRequest.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_FACT_REQUEST_H_ +#define _CONTEXT_TRIGGER_FACT_REQUEST_H_ + +#include "ContextMonitor.h" +#include "../Request.h" + +namespace ctx { + +namespace trigger { + + class FactRequest : public RequestInfo { + public: + FactRequest(int type, int reqId, const char* subj, const char* desc, ContextMonitor* ctxMonitor); + ~FactRequest(); + + const char* getClient(); + bool reply(int error); + bool reply(int error, ctx::Json& requestResult); + bool reply(int error, ctx::Json& requestResult, ctx::Json& dataRead); + bool publish(int error, ctx::Json& data); + + private: + ContextMonitor *__ctxMonitor; + bool __replied; + }; + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_FACT_REQUEST_H_ */ diff --git a/src/agent/legacy/trigger/FactTypes.h b/src/agent/legacy/trigger/FactTypes.h new file mode 100644 index 0000000..fe50f11 --- /dev/null +++ b/src/agent/legacy/trigger/FactTypes.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_FACT_TYPES_H_ +#define _CONTEXT_TRIGGER_FACT_TYPES_H_ + +#define FACT_KEY_EVENT "event" +#define FACT_KEY_CONDITION "condition" +#define FACT_KEY_NAME "name" +#define FACT_KEY_OPTION "option" +#define FACT_KEY_DATA "data" + +#endif /* End of _CONTEXT_TRIGGER_FACT_TYPES_H_ */ diff --git a/src/agent/legacy/trigger/IContextListener.h b/src/agent/legacy/trigger/IContextListener.h new file mode 100644 index 0000000..826ab41 --- /dev/null +++ b/src/agent/legacy/trigger/IContextListener.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_I_CONTEXT_LISTENER_H_ +#define _CONTEXT_TRIGGER_I_CONTEXT_LISTENER_H_ + +namespace ctx { + /* Forward Declaration */ + class Json; + +namespace trigger { + + class IContextListener { + public: + virtual ~IContextListener() {} + + virtual void onEventReceived(std::string name, Json option, Json data) = 0; + + virtual void onConditionReceived(std::string name, Json option, Json data) = 0; + }; + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_I_CONTEXT_LISTENER_H_ */ diff --git a/src/agent/legacy/trigger/Rule.cpp b/src/agent/legacy/trigger/Rule.cpp new file mode 100644 index 0000000..33b2ef8 --- /dev/null +++ b/src/agent/legacy/trigger/Rule.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "Rule.h" +#include "ActionManager.h" +#include "RuleEvaluator.h" +#include "ContextMonitor.h" +#include "FactTypes.h" +#include "RuleManager.h" + +using namespace ctx; +using namespace ctx::trigger; + +RuleManager *Rule::__ruleMgr = NULL; + +Rule::Rule(int i, Json& d, const char* p, RuleManager* rm) : + __result(EMPTY_JSON_OBJECT), + id(i), + pkgId(p) +{ + // Rule manager + if (!__ruleMgr) { + __ruleMgr = rm; + } + + // Statement + __statement = d.str(); + + // Event + Json e; + d.get(NULL, TRIG_RULE_KEY_EVENT, &e); + __event = new(std::nothrow) ContextItem(e); + + // Condition + int condNum = d.getSize(NULL, TRIG_RULE_KEY_CONDITION); + for (int j = 0; j < condNum; j++) { + Json c; + d.getAt(NULL, TRIG_RULE_KEY_CONDITION, j, &c); + __condition.push_back(new(std::nothrow) ContextItem(c)); + } + + // Extra + Json extra; + d.get(NULL, _TRIG_RULE_KEY_EXTRA, &extra); + __extra = extra.str(); + + // Action + Json a; + d.get(NULL, TRIG_RULE_KEY_ACTION, &a); + __action = a.str(); +} + +Rule::~Rule() +{ + // Release resources + delete __event; + for (auto it = __condition.begin(); it != __condition.end(); ++it) { + delete *it; + } +} + +int Rule::start(void) +{ + // Subscribe event + int error = ContextMonitor::getInstance()->subscribe(id, __event->name, __event->option, this); + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to start rule%d", id); + + return error; +} + +int Rule::stop(void) +{ + // Unsubscribe event + int error = ContextMonitor::getInstance()->unsubscribe(id, __event->name, __event->option, this); + if (error == ERR_NOT_SUPPORTED) { + _E("Stop rule%d (event not supported)"); + return ERR_NONE; + } + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", id); + + return error; +} + +bool Rule::__setConditionOptionBasedOnEvent(Json& option) +{ + // Set condition option if it references event data + std::list optionKeys; + option.getKeys(&optionKeys); + + for (auto it = optionKeys.begin(); it != optionKeys.end(); ++it) { + std::string optKey = (*it); + + std::string optVal; + if (option.get(NULL, optKey.c_str(), &optVal)) { + if (optVal.find("?") != 0) { + continue; + } + + std::string eventKey = optVal.substr(1, optVal.length() - 1); + + std::string newStr; + int new_val; + if (__result.get(FACT_KEY_EVENT "." FACT_KEY_DATA, eventKey.c_str(), &newStr)) { + option.set(NULL, optKey.c_str(), newStr); + } else if (__result.get(FACT_KEY_EVENT "." FACT_KEY_DATA, eventKey.c_str(), &new_val)) { + option.set(NULL, optKey.c_str(), new_val); + } else { + _W("Failed to find '%s' in event data", eventKey.c_str()); + return false; + } + } + } + + return true; +} + +void Rule::onEventReceived(std::string name, Json option, Json data) +{ + if (__result != EMPTY_JSON_OBJECT) { + __clearResult(); + } + + // Check if creator package is uninstalled + if (RuleManager::isUninstalledPackage(pkgId)) { + _D("Creator(%s) of rule%d is uninstalled.", pkgId.c_str(), id); + g_idle_add(__handleUninstalledRule, &pkgId); + return; + } + + _D("Rule%d received event data", id); + + // Set event data + __result.set(FACT_KEY_EVENT, FACT_KEY_NAME, name); + __result.set(FACT_KEY_EVENT, FACT_KEY_OPTION, option); + __result.set(FACT_KEY_EVENT, FACT_KEY_DATA, data); + + if (__condition.size() == 0) { + __onContextDataPrepared(); + return; + } + + IF_FAIL_VOID_TAG(RuleEvaluator::evaluateRule(__statement, __result), _E, "Event not matched"); + + // Request read conditions + for (auto it = __condition.begin(); it != __condition.end(); ++it) { + Json condOption = (*it)->option.str(); + if (!__setConditionOptionBasedOnEvent(condOption)) { // condOption should be copy of original option. + __clearResult(); + return; + } + + int error = ContextMonitor::getInstance()->read((*it)->name.c_str(), condOption, this); + IF_FAIL_VOID_TAG(error == ERR_NONE, _E, "Failed to read condition"); + } + + // TODO timer set +} + +void Rule::onConditionReceived(std::string name, Json option, Json data) +{ + _D("Rule%d received condition data", id); + + // Set condition data + Json item; + item.set(NULL, FACT_KEY_NAME, name); + item.set(NULL, FACT_KEY_OPTION, option); + item.set(NULL, FACT_KEY_DATA, data); + __result.append(NULL, FACT_KEY_CONDITION, item); + + if (__result.getSize(NULL, FACT_KEY_CONDITION) == (int) __condition.size()) { + __onContextDataPrepared(); + } +} + +void Rule::__clearResult() +{ + __result = EMPTY_JSON_OBJECT; + // TODO timer cancel +} + +void Rule::__onContextDataPrepared(void) +{ + if (RuleEvaluator::evaluateRule(__statement, __result)) { + action_manager::triggerAction(__action, pkgId); + } + __clearResult(); +} + +gboolean Rule::__handleUninstalledRule(gpointer data) +{ + std::string* pkgId = static_cast(data); + __ruleMgr->handleRuleOfUninstalledPackage(*pkgId); + + return FALSE; +} diff --git a/src/agent/legacy/trigger/Rule.h b/src/agent/legacy/trigger/Rule.h new file mode 100644 index 0000000..1192b6e --- /dev/null +++ b/src/agent/legacy/trigger/Rule.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_RULE_H_ +#define _CONTEXT_TRIGGER_RULE_H_ + +#include +#include +#include +#include "IContextListener.h" + +namespace ctx { + +namespace trigger { + + class RuleManager; + + class Rule : public IContextListener { + private: + struct ContextItem { + std::string name; + ctx::Json option; + ContextItem(ctx::Json item) { + std::list keyList; + item.getKeys(&keyList); + name = *keyList.begin(); + + ctx::Json o; + if (item.get(name.c_str(), TRIG_RULE_KEY_OPTION, &o)) + option = o.str(); + } + }; + + ctx::Json __statement; + ContextItem* __event; + std::list __condition; + ctx::Json __extra; + ctx::Json __action; + ctx::Json __result; + + static RuleManager* __ruleMgr; + + void __clearResult(void); + bool __setConditionOptionBasedOnEvent(ctx::Json& option); + void __onContextDataPrepared(void); + + static gboolean __handleUninstalledRule(gpointer data); + + public: + int id; + std::string pkgId; + + Rule(int i, ctx::Json& d, const char* p, RuleManager* rm); + ~Rule(); + + int start(void); + int stop(void); + + void onEventReceived(std::string name, ctx::Json option, ctx::Json data); + void onConditionReceived(std::string name, ctx::Json option, ctx::Json data); + + }; + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_RULE_H_ */ diff --git a/src/agent/legacy/trigger/RuleEvaluator.cpp b/src/agent/legacy/trigger/RuleEvaluator.cpp new file mode 100644 index 0000000..b0e5833 --- /dev/null +++ b/src/agent/legacy/trigger/RuleEvaluator.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "RuleEvaluator.h" +#include "FactTypes.h" + +#define OPERATOR_EQ "==" +#define OPERATOR_NEQ "!=" +#define OPERATOR_LEQ "<=" +#define OPERATOR_GEQ ">=" +#define OPERATOR_LT "<" +#define OPERATOR_GT ">" + +using namespace ctx; +using namespace ctx::trigger; + +RuleEvaluator::RuleEvaluator() +{ +} + +template +bool RuleEvaluator::__evaluateSingleData(T factVal, Json& comparison, std::string op) +{ + T ruleVal; + comparison.get(NULL, TRIG_RULE_KEY_VALUE, &ruleVal); + + if (op == TRIG_RULE_OP_EQUAL_TO) { + return (ruleVal == factVal); + } else if (op == TRIG_RULE_OP_NOT_EQUAL_TO) { + return (ruleVal != factVal); + } else if (op == TRIG_RULE_OP_GREATER_THAN) { + return (ruleVal > factVal); + } else if (op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO) { + return (ruleVal >= factVal); + } else if (op == TRIG_RULE_OP_LESS_THAN) { + return (ruleVal < factVal); + } else if (op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) { + return (ruleVal <= factVal); + } + + return false; +} + +template +bool RuleEvaluator::__evaluateDualData(T factVal, Json& comparison, std::string op) +{ + T ruleVal1, ruleVal2; + comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, 0, &ruleVal1); + comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, 1, &ruleVal2); + + if (op == TRIG_RULE_OP_IN) { + return (ruleVal1 <= factVal && factVal <= ruleVal2); + } else if (op == TRIG_RULE_OP_NOT_IN) { + return (factVal < ruleVal1 || ruleVal2 < factVal); + } + + return false; +} + +template +bool RuleEvaluator::__evaluateMultipleData(T factVal, Json& comparison, std::string op) +{ + T ruleVal; + for (int i = 0; comparison.getAt(NULL, TRIG_RULE_KEY_VALUE, i, &ruleVal); i++) { + if (ruleVal == factVal) { + if (op == TRIG_RULE_OP_ONE_OF) { + return true; + } else if (op == TRIG_RULE_OP_NONE_OF) { + return false; + } + } + } + + if (op == TRIG_RULE_OP_NONE_OF) { + return true; + } + + return false; +} + +template +bool RuleEvaluator::__evaluateData(T factVal, Json& comparison) +{ + std::string op; + comparison.get(NULL, TRIG_RULE_KEY_OPERATOR, &op); + + if (op == TRIG_RULE_OP_EQUAL_TO || op == TRIG_RULE_OP_NOT_EQUAL_TO || + op == TRIG_RULE_OP_GREATER_THAN || op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO || + op == TRIG_RULE_OP_LESS_THAN || op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) { + return __evaluateSingleData(factVal, comparison, op); + } else if (op == TRIG_RULE_OP_IN || op == TRIG_RULE_OP_NOT_IN) { + return __evaluateDualData(factVal, comparison, op); + } else if (op == TRIG_RULE_OP_ONE_OF || op == TRIG_RULE_OP_NONE_OF) { + return __evaluateMultipleData(factVal, comparison, op); + } + + return false; +} + +void RuleEvaluator::__replaceSingleDataReferences(Json& eventFactData, Json& ruleComp, std::string& dataKey) +{ + std::string refVal; + std::string eventRefStr; + int eventRefInt; + + if (!ruleComp.get(dataKey.c_str(), TRIG_RULE_KEY_VALUE, &refVal)) { + return; + } + + if (refVal.substr(0, 1) != TRIG_RULE_REF_KEY_PREFIX) { + return; + } + + std::string eventKey = refVal.substr(1, refVal.length() - 1); + if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) { + ruleComp.set(dataKey.c_str(), TRIG_RULE_KEY_VALUE, eventRefStr); + } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) { + ruleComp.set(dataKey.c_str(), TRIG_RULE_KEY_VALUE, eventRefInt); + } else { + _W("Attribute %s not found in event_data", eventKey.c_str()); + } +} + +void RuleEvaluator::__replaceMultipleDataReferences(Json& eventFactData, Json& ruleComp, std::string& dataKey) +{ + std::string refVal; + std::string eventRefStr; + int eventRefInt; + + for (int i = 0; ruleComp.getAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, &refVal); i++) { + if (refVal.substr(0, 1) != TRIG_RULE_REF_KEY_PREFIX) { + continue; + } + + std::string eventKey = refVal.substr(1, refVal.length() - 1); + if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) { + ruleComp.setAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, eventRefStr); + } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) { + ruleComp.setAt(dataKey.c_str(), TRIG_RULE_KEY_VALUE, i, eventRefInt); + } else { + _W("Attribute %s not found in event_data", eventKey.c_str()); + } + } +} + +void RuleEvaluator::__replaceDataReferences(Json eventFactData, Json& ruleComp) +{ + // Replace referencing data to actual value + std::list compKeys; + ruleComp.getKeys(&compKeys); + + for (auto it = compKeys.begin(); it != compKeys.end(); ++it) { + std::string dataKey = *it; + + std::string op; + ruleComp.get(dataKey.c_str(), TRIG_RULE_KEY_OPERATOR, &op); + + std::string val; + if (op == TRIG_RULE_OP_EQUAL_TO || op == TRIG_RULE_OP_NOT_EQUAL_TO || + op == TRIG_RULE_OP_GREATER_THAN || op == TRIG_RULE_OP_GREATER_THAN_OR_EQUAL_TO || + op == TRIG_RULE_OP_LESS_THAN || op == TRIG_RULE_OP_LESS_THAN_OR_EQUAL_TO) { + + __replaceSingleDataReferences(eventFactData, ruleComp, dataKey); + } else { + __replaceMultipleDataReferences(eventFactData, ruleComp, dataKey); + } + } +} + +bool RuleEvaluator::__evaluateItem(Json& factItem, Json& ruleItem, std::string logicalOp) +{ + std::string name; + factItem.get(NULL, FACT_KEY_NAME, &name); + + Json comparison; + ruleItem.get(name.c_str(), TRIG_RULE_KEY_COMPARISON, &comparison); + + std::list compKeys; + comparison.getKeys(&compKeys); + if (compKeys.size() == 0) { + return true; + } + + bool isConjunction = (TRIG_RULE_LOGICAL_CONJUNCTION == logicalOp); + + for (auto it = compKeys.begin(); it != compKeys.end(); ++it) { + std::string dataKey = *it; + + Json comp; + comparison.get(NULL, dataKey.c_str(), &comp); + + std::string factValStr; + int factValInt; + + bool result; + if (factItem.get(FACT_KEY_DATA, dataKey.c_str(), &factValStr)) { + result = __evaluateData(factValStr, comp); + } else if (factItem.get(FACT_KEY_DATA, dataKey.c_str(), &factValInt)) { + result = __evaluateData(factValInt, comp); + } else { + _W("Could not get value corresponding to data key %s", dataKey.c_str()); + result = false; + } + + if (isConjunction && !result) { + return false; + } else if (!isConjunction && result) { + return true; + } + } + return isConjunction; +} + +bool RuleEvaluator::__evaluateRuleEvent(Json& fact, Json& rule) +{ + Json factItem; + Json ruleItem; + fact.get(NULL, FACT_KEY_EVENT, &factItem); + rule.get(NULL, TRIG_RULE_KEY_EVENT, &ruleItem); + + std::string eventOp; + rule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &eventOp); + + return __evaluateItem(factItem, ruleItem, eventOp); +} + +Json RuleEvaluator::__getConditionFact(Json& fact, Json& ruleCond) +{ + std::list condKey; + ruleCond.getKeys(&condKey); + std::string ruleCondName = *(condKey.begin()); + + Json factCond; + for (int i = 0; fact.getAt(NULL, FACT_KEY_CONDITION, i, &factCond); i++) { + // Check if fact item name is matched with condition + std::string factCondName; + factCond.get(NULL, FACT_KEY_NAME, &factCondName); + if (factCondName != ruleCondName) { + continue; + } + + // Check if fact item option is mathced with condition + Json ruleCondOption; + Json factCondOption; + ruleCond.get(ruleCondName.c_str(), TRIG_RULE_KEY_OPTION, &ruleCondOption); + factCond.get(NULL, FACT_KEY_OPTION, &factCondOption); + if (factCondOption == ruleCondOption) { + return factCond; + } + } + + _W(YELLOW("find condition failed for condition")); + return EMPTY_JSON_OBJECT; +} + +bool RuleEvaluator::__evaluateRuleCondition(Json& fact, Json& rule) +{ + std::string ruleOp; + rule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &ruleOp); + bool isConjunction = (TRIG_RULE_LOGICAL_CONJUNCTION == ruleOp); + + Json ruleCond; + for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &ruleCond); i++) { + Json factCond = __getConditionFact(fact, ruleCond); + + bool result; + if (factCond == EMPTY_JSON_OBJECT) { + result = false; + } else { + std::string condOp; + rule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, i, &condOp); + result = __evaluateItem(factCond, ruleCond, condOp); + } + + if (isConjunction && !result) { + return false; + } else if (!isConjunction && result) { + return true; + } + } + + return isConjunction; +} + +bool RuleEvaluator::__replaceOptionReferences(Json eventFactData, Json& ruleOption) +{ + // Replace referencing option to actual value + std::string refVal; + std::string eventRefStr; + int eventRefInt; + + std::list keyList; + ruleOption.getKeys(&keyList); + + for (std::list::iterator it = keyList.begin(); it != keyList.end(); ++it) { + std::string optionKey = *it; + + if (!ruleOption.get(NULL, optionKey.c_str(), &refVal)) { + continue; + } + if (!(refVal.substr(0, 1) == TRIG_RULE_REF_KEY_PREFIX)) { + continue; + } + + std::string eventKey = refVal.substr(1, refVal.length() - 1); + if (eventFactData.get(NULL, eventKey.c_str(), &eventRefStr)) { + ruleOption.set(NULL, optionKey.c_str(), eventRefStr); + } else if (eventFactData.get(NULL, eventKey.c_str(), &eventRefInt)) { + ruleOption.set(NULL, optionKey.c_str(), eventRefInt); + } else { + _W("Option %s not found in event_data", eventKey.c_str()); + return false; + } + } + + return true; +} + +bool RuleEvaluator::__replaceEventReferences(Json& fact, Json& rule) +{ + // Replace referencing data/option to actual value + Json eventFactData; + if (!fact.get(FACT_KEY_EVENT, FACT_KEY_DATA, &eventFactData)) { + _E("No event data found, error"); + return false; + } + + Json ruleCond; + for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &ruleCond); i++) { + std::list condKey; + ruleCond.getKeys(&condKey); + std::string ruleCondName = *(condKey.begin()); + + Json ruleComp; + for (int j = 0; ruleCond.getAt(ruleCondName.c_str(), TRIG_RULE_KEY_COMPARISON, j, &ruleComp); j++) { + __replaceDataReferences(eventFactData, ruleComp); + } + + Json ruleOption; + if (ruleCond.get(ruleCondName.c_str(), TRIG_RULE_KEY_OPTION, &ruleOption)) { + __replaceOptionReferences(eventFactData, ruleOption); + } + } + + return true; +} + +bool RuleEvaluator::evaluateRule(Json rule, Json fact) +{ + _D("Rule is %s ", rule.str().c_str()); + _D("fact is %s ", fact.str().c_str()); + + RuleEvaluator eval; + bool ret; + Json tempJson; + if (fact.get(NULL, FACT_KEY_CONDITION, &tempJson)) { + Json ruleCopy(rule.str()); + if (!eval.__replaceEventReferences(fact, ruleCopy)) { + _W("Replace failed"); + } + ret = eval.__evaluateRuleCondition(fact, ruleCopy); + _D("Checking condition %s", ret ? "true" : "false"); + } else { + ret = eval.__evaluateRuleEvent(fact, rule); + _D("Checking event %s", ret ? "true" : "false"); + } + + return ret; +} diff --git a/src/agent/legacy/trigger/RuleEvaluator.h b/src/agent/legacy/trigger/RuleEvaluator.h new file mode 100644 index 0000000..3e79682 --- /dev/null +++ b/src/agent/legacy/trigger/RuleEvaluator.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_RULE_EVALUATOR_H_ +#define _CONTEXT_TRIGGER_RULE_EVALUATOR_H_ + +namespace ctx { + + class Json; + +namespace trigger { + + class RuleEvaluator { + private: + RuleEvaluator(); + + bool __evaluateRuleEvent(ctx::Json& fact, ctx::Json& rule); + bool __evaluateRuleCondition(ctx::Json& fact, ctx::Json& rule); + bool __evaluateItem(ctx::Json& factItem, ctx::Json& ruleItem, std::string logicalOp); + template bool __evaluateData(T factVal, Json& comparison); + template bool __evaluateSingleData(T factVal, Json& comparison, std::string op); + template bool __evaluateDualData(T factVal, Json& comparison, std::string op); + template bool __evaluateMultipleData(T factVal, Json& comparison, std::string op); + + ctx::Json __getConditionFact(ctx::Json& fact, ctx::Json& ruleCond); + + bool __replaceEventReferences(ctx::Json& fact, ctx::Json& rule); + void __replaceDataReferences(ctx::Json eventFactData, ctx::Json& ruleComp); + void __replaceSingleDataReferences(ctx::Json& eventFactData, ctx::Json& ruleComp, std::string& dataKey); + void __replaceMultipleDataReferences(ctx::Json& eventFactData, ctx::Json& ruleComp, std::string& dataKey); + bool __replaceOptionReferences(ctx::Json eventFactData, ctx::Json& ruleOption); + + public: + static bool evaluateRule(ctx::Json rule, ctx::Json data); + }; + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_RULE_EVALUATOR_H_ */ diff --git a/src/agent/legacy/trigger/RuleManager.cpp b/src/agent/legacy/trigger/RuleManager.cpp new file mode 100644 index 0000000..11a9561 --- /dev/null +++ b/src/agent/legacy/trigger/RuleManager.cpp @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "RuleManager.h" +#include "ContextMonitor.h" +#include "Rule.h" + +#define RULE_TABLE "ContextTriggerRule" +#define RULE_IDS_JSON "{ \"" TRIG_KEY_ENABLED_IDS "\" : [ ] , \"" TRIG_KEY_DISABLED_IDS "\" : [ ] }"; + +using namespace ctx; +using namespace ctx::trigger; + +static int __stringToInt(std::string str) +{ + int i; + std::istringstream convert(str); + + if (!(convert >> i)) + i = 0; + + return i; +} + +static std::string __intToString(int i) +{ + std::ostringstream convert; + convert << i; + std::string str = convert.str(); + return str; +} + +RuleManager::RuleManager() +{ +} + +RuleManager::~RuleManager() +{ + // Release rule instances + _D("Release rule instances"); + for (auto it = __ruleMap.begin(); it != __ruleMap.end(); ++it) { + Rule* rule = static_cast(it->second); + + int error = rule->stop(); + if (error != ERR_NONE) { + _E("Failed to stop rule%d", it->first); + } + + delete rule; + } + __ruleMap.clear(); +} + +bool RuleManager::init() +{ + bool ret; + int error; + + // Create tables into db (rule, template) + std::string q1 = std::string("status INTEGER DEFAULT 0 NOT NULL, creator TEXT DEFAULT '' NOT NULL,") + + "packageId TEXT DEFAULT '' NOT NULL, description TEXT DEFAULT ''," + + "details TEXT DEFAULT '' NOT NULL"; + ret = __dbManager.createTableSync(RULE_TABLE, q1.c_str(), NULL); + IF_FAIL_RETURN_TAG(ret, false, _E, "Create rule table failed"); + + // Before re-enable rules, handle uninstalled app's rules + if (__getUninstalledApp() > 0) { + error = __clearRuleOfUninstalledPackage(true); + IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Failed to remove uninstalled apps' rules while initialization"); + } + ret = __reenableRule(); + + return ret; +} + +void RuleManager::handleRuleOfUninstalledPackage(std::string pkgId) +{ + __uninstalledPackages.insert(pkgId); + __clearRuleOfUninstalledPackage(); +} + +int RuleManager::__getUninstalledApp(void) +{ + // Return number of uninstalled apps + std::string q1 = "SELECT DISTINCT packageId FROM ContextTriggerRule"; + + std::vector record; + bool ret = __dbManager.executeSync(q1.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, -1, _E, "Query package ids of registered rules failed"); + + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + std::string pkgId; + elem.get(NULL, "packageId", &pkgId); + + if (isUninstalledPackage(pkgId)) { + __uninstalledPackages.insert(pkgId); + } + } + + return __uninstalledPackages.size(); +} + +bool RuleManager::isUninstalledPackage(std::string pkgId) +{ + IF_FAIL_RETURN_TAG(!pkgId.empty(), false, _D, "Empty package id"); + + package_info_h pkgInfo; + int error = package_manager_get_package_info(pkgId.c_str(), &pkgInfo); + + if (error == PACKAGE_MANAGER_ERROR_NONE) { + package_info_destroy(pkgInfo); + } else if (error == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) { + // Uninstalled package found + _D("Uninstalled package found: %s", pkgId.c_str()); + return true; + } else { + _E("Failed to get package info(%s): %d", pkgId.c_str(), error); + } + + return false; +} + +int RuleManager::__clearRuleOfUninstalledPackage(bool isInit) +{ + if (__uninstalledPackages.size() <= 0) { + return ERR_NONE; + } + + int error; + bool ret; + + _D("Clear uninstalled packages' rule started"); + // Package list + std::string pkgList = "("; + std::set::iterator it = __uninstalledPackages.begin(); + pkgList += "packageId = '" + *it + "'"; + it++; + for (; it != __uninstalledPackages.end(); ++it) { + pkgList += " OR packageId = '" + *it + "'"; + } + pkgList += ")"; + + // After event received, disable all the enabled rules of uninstalled apps + if (!isInit) { + std::string q1 = "SELECT rowId FROM ContextTriggerRule WHERE status = 2 and ("; + q1 += pkgList; + q1 += ")"; + + std::vector record; + ret = __dbManager.executeSync(q1.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query enabled rules of uninstalled packages"); + + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + int ruleId; + elem.get(NULL, "rowId", &ruleId); + error = disableRule(ruleId); + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to disable rule"); + } + _D("Uninstalled packages' rules are disabled"); + } + + // Delete rules of uninstalled packages from DB + std::string q2 = "DELETE FROM ContextTriggerRule WHERE " + pkgList; + std::vector dummy; + ret = __dbManager.executeSync(q2.c_str(), &dummy); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to remove rules from db"); + _D("Uninstalled packages' rules are deleted from db"); + + __uninstalledPackages.clear(); + + return ERR_NONE; +} + +int RuleManager::pauseRuleWithItem(std::string& subject) +{ + std::string q = "SELECT rowId FROM ContextTriggerRule WHERE (status=2) AND (details LIKE '%\"ITEM_NAME\":\"" + subject + "\"%');"; + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query rowIds to be paused"); + IF_FAIL_RETURN(record.size() > 0, ERR_NONE); + + _D("Pause rules related to %s", subject.c_str()); + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + int rowId; + elem.get(NULL, "rowId", &rowId); + + int error = pauseRule(rowId); + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to disable rules using custom item"); + } + + return ERR_NONE; +} + +int RuleManager::resumeRuleWithItem(std::string& subject) +{ + std::string q = "SELECT rowId FROM ContextTriggerRule WHERE (status=1) AND (details LIKE '%\"ITEM_NAME\":\"" + subject + "\"%');"; + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query paused rule ids failed"); + IF_FAIL_RETURN(record.size() > 0, ERR_NONE); + + _D("Resume rules related to %s", subject.c_str()); + std::string qRowId; + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + int rowId; + elem.get(NULL, "rowId", &rowId); + + int error = enableRule(rowId); + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to resume rule"); + } + + return ERR_NONE; +} + +bool RuleManager::__reenableRule(void) +{ + int error; + std::string q = "SELECT rowId FROM ContextTriggerRule WHERE status = 2"; + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, false, _E, "Query rowIds of enabled rules failed"); + IF_FAIL_RETURN_TAG(record.size() > 0, true, _D, "No rule to re-enable"); + + _D(YELLOW("Re-enable rule started")); + + std::string qRowId; + qRowId.clear(); + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + int rowId; + elem.get(NULL, "rowId", &rowId); + + error = enableRule(rowId); + if (error == ERR_NOT_SUPPORTED) { + qRowId += "(rowId = " + __intToString(rowId) + ") OR "; + } else if (error != ERR_NONE) { + _E("Re-enable rule%d failed(%d)", rowId, error); + } + } + IF_FAIL_RETURN(!qRowId.empty(), true); + qRowId = qRowId.substr(0, qRowId.length() - 4); + + // For rules which is failed to re-enable + std::string qUpdate = "UPDATE ContextTriggerRule SET status = 1 WHERE " + qRowId; + std::vector record2; + ret = __dbManager.executeSync(qUpdate.c_str(), &record2); + IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update rules as paused"); + + return true; +} + +bool RuleManager::__ruleEquals(Json& lRule, Json& rRule) +{ + // Compare event + Json lEvent, rEvent; + lRule.get(NULL, TRIG_RULE_KEY_EVENT, &lEvent); + rRule.get(NULL, TRIG_RULE_KEY_EVENT, &rEvent); + + std::string lEOp, rEOp; + lRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &lEOp); + rRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_EVENT_LOGICAL_OP, &rEOp); + + if (lEOp != rEOp || lEvent != rEvent) + return false; + + // Compare conditions + int lCondCnt, rCondCnt; + lCondCnt = lRule.getSize(NULL, TRIG_RULE_KEY_CONDITION); + rCondCnt = rRule.getSize(NULL, TRIG_RULE_KEY_CONDITION); + if (lCondCnt != rCondCnt) + return false; + + std::string lOp, rOp; + lRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &lOp); + rRule.get(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_RULE_LOGICAL_OP, &rOp); + if (lOp != rOp) + return false; + + for (int i = 0; i < lCondCnt; i++) { + bool found = false; + Json lCond; + lRule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &lCond); + + std::string lCOp; + lRule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, i, &lCOp); + + for (int j = 0; j < lCondCnt; j++) { + Json rCond; + rRule.getAt(NULL, TRIG_RULE_KEY_CONDITION, j, &rCond); + + std::string rCOp; + rRule.getAt(_TRIG_RULE_KEY_EXTRA, _TRIG_RULE_KEY_CONDITION_LOGICAL_OP, j, &rCOp); + + if (lCOp == rCOp && lCond == rCond) { + found = true; + break; + } + } + if (!found) + return false; + } + + // Compare action + Json lAction, rAction; + lRule.get(NULL, TRIG_RULE_KEY_ACTION, &lAction); + rRule.get(NULL, TRIG_RULE_KEY_ACTION, &rAction); + if (lAction != rAction) + return false; + + return true; +} + +int64_t RuleManager::__getDuplicatedRuleId(std::string pkgId, Json& rule) +{ + std::string q = "SELECT rowId, description, details FROM ContextTriggerRule WHERE packageId = '"; + q += pkgId; + q += "'"; + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, false, _E, "Query rowId, details by package id failed"); + + std::string rDesc; + rule.get(NULL, TRIG_RULE_KEY_DESCRIPTION, &rDesc); + Json rDetails = rule.str(); + rDetails.remove(NULL, TRIG_RULE_KEY_DESCRIPTION); + + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + std::string dStr; + Json details; + + elem.get(NULL, "details", &dStr); + details = dStr; + + if (__ruleEquals(rDetails, details)) { + int64_t rowId; + elem.get(NULL, "rowId", &rowId); + + // Description comparison + std::string desc; + elem.get(NULL, "description", &desc); + if (rDesc.compare(desc)) { + // Only description is changed + std::string qUpdate = "UPDATE ContextTriggerRule SET description='" + rDesc + "' WHERE rowId = " + __intToString(rowId); + + std::vector dummy; + ret = __dbManager.executeSync(qUpdate.c_str(), &dummy); + if (ret) { + _D("Rule%lld description is updated", rowId); + } else { + _W("Failed to update description of rule%lld", rowId); + } + } + + return rowId; + } + } + + return -1; +} + +int RuleManager::__verifyRule(Json& rule, const char* creator) +{ + ContextMonitor* ctxMonitor = ContextMonitor::getInstance(); + IF_FAIL_RETURN_TAG(ctxMonitor, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed"); + + // Event + Json event; + rule.get(NULL, TRIG_RULE_KEY_EVENT, &event); + + std::list eventKey; + event.getKeys(&eventKey); + IF_FAIL_RETURN_TAG(eventKey.size() == 1, ERR_INVALID_PARAMETER, _E, "Invalid event"); + + std::string eventName = *eventKey.begin(); + IF_FAIL_RETURN_TAG(ctxMonitor->isSupported(eventName), ERR_NOT_SUPPORTED, _I, "Event(%s) is not supported", eventName.c_str()); + + if (!ctxMonitor->isAllowed(creator, eventName.c_str())) { + _W("Permission denied for '%s'", eventName.c_str()); + return ERR_PERMISSION_DENIED; + } + + // Conditions + Json cond; + for (int i = 0; rule.getAt(NULL, TRIG_RULE_KEY_CONDITION, i, &cond); i++) { + std::list condKey; + cond.getKeys(&condKey); + IF_FAIL_RETURN_TAG(condKey.size() == 1, ERR_INVALID_PARAMETER, _E, "Invalid condition"); + + std::string condName = *condKey.begin(); + IF_FAIL_RETURN_TAG(ctxMonitor->isSupported(condName), ERR_NOT_SUPPORTED, _I, "Condition(%s) is not supported", condName.c_str()); + + if (!ctxMonitor->isAllowed(creator, condName.c_str())) { + _W("Permission denied for '%s'", condName.c_str()); + return ERR_PERMISSION_DENIED; + } + } + + return ERR_NONE; +} + +int RuleManager::addRule(std::string creator, const char* pkgId, Json rule, Json* ruleId) +{ + bool ret; + int64_t rid; + + // Check if all items are supported && allowed to access + int err = __verifyRule(rule, creator.c_str()); + IF_FAIL_RETURN(err == ERR_NONE, err); + + // Check if duplicated rule exits + if ((rid = __getDuplicatedRuleId(pkgId, rule)) > 0) { + // Save rule id + ruleId->set(NULL, TRIG_KEY_RULE_ID, rid); + _D("Duplicated rule found"); + return ERR_NONE; + } + + // Insert rule to rule table, get rule id + Json record; + std::string description; + rule.get(NULL, TRIG_RULE_KEY_DESCRIPTION, &description); + + Json details = rule.str(); + details.remove(NULL, TRIG_RULE_KEY_DESCRIPTION); + record.set(NULL, "details", details.str()); + + record.set(NULL, "creator", creator); + if (pkgId) { + record.set(NULL, "packageId", pkgId); + } + record.set(NULL, "description", description); + + ret = __dbManager.insertSync(RULE_TABLE, record, &rid); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert rule to db failed"); + + // Save rule id + ruleId->set(NULL, TRIG_KEY_RULE_ID, rid); + + _D("Add rule%d succeeded", (int)rid); + return ERR_NONE; +} + + +int RuleManager::removeRule(int ruleId) +{ + bool ret; + + // Delete rule from DB + std::string query = "DELETE FROM 'ContextTriggerRule' where rowId = "; + query += __intToString(ruleId); + + std::vector record; + ret = __dbManager.executeSync(query.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed"); + + _D("Remove rule%d succeeded", ruleId); + + return ERR_NONE; +} + +int RuleManager::enableRule(int ruleId) +{ + int error; + std::string query; + std::vector record; + std::vector dummy; + std::string pkgId; + Json jRule; + std::string tmp; + std::string idStr = __intToString(ruleId); + + Rule* rule; + + // Get rule Json by rule id; + query = "SELECT details, packageId FROM ContextTriggerRule WHERE rowId = "; + query += idStr; + error = (__dbManager.executeSync(query.c_str(), &record))? ERR_NONE : ERR_OPERATION_FAILED; + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Query rule by rule id failed"); + + record[0].get(NULL, "details", &tmp); + jRule = tmp; + record[0].get(NULL, "packageId", &pkgId); + + // Create a rule instance + rule = new(std::nothrow) Rule(ruleId, jRule, pkgId.c_str(), this); + IF_FAIL_RETURN_TAG(rule, ERR_OUT_OF_MEMORY, _E, "Failed to create rule instance"); + + // Start the rule + error = rule->start(); + IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Failed to start rule%d", ruleId); + + // Update db to set 'enabled' + query = "UPDATE ContextTriggerRule SET status = 2 WHERE rowId = "; + query += idStr; + error = (__dbManager.executeSync(query.c_str(), &dummy))? ERR_NONE : ERR_OPERATION_FAILED; + IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Update db failed"); + + // Add rule instance to __ruleMap + __ruleMap[ruleId] = rule; + + _D(YELLOW("Enable Rule%d succeeded"), ruleId); + return ERR_NONE; + +CATCH: + delete rule; + rule = NULL; + + return error; +} + +int RuleManager::disableRule(int ruleId) +{ + bool ret; + int error; + + auto it = __ruleMap.find(ruleId); + bool paused = (it == __ruleMap.end()); + + // For 'enabled' rule, not 'paused' + if (!paused) { + // Stop the rule + Rule* rule = static_cast(it->second); + error = rule->stop(); + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", ruleId); + + // Remove rule instance from __ruleMap + delete rule; + __ruleMap.erase(it); + } + + // Update db to set 'disabled' // TODO skip while clear uninstalled rule + std::string query = "UPDATE ContextTriggerRule SET status = 0 WHERE rowId = "; + query += __intToString(ruleId); + std::vector record; + ret = __dbManager.executeSync(query.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed"); + + _D(YELLOW("Disable Rule%d succeeded"), ruleId); + return ERR_NONE; +} + +int RuleManager::pauseRule(int ruleId) +{ + bool ret; + int error; + + auto it = __ruleMap.find(ruleId); + IF_FAIL_RETURN_TAG(it != __ruleMap.end(), ERR_OPERATION_FAILED, _E, "Rule instance not found"); + + // Stop the rule + Rule* rule = static_cast(it->second); + error = rule->stop(); + IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to stop rule%d", ruleId); + + // Update db to set 'paused' + std::string query = "UPDATE ContextTriggerRule SET status = 1 WHERE rowId = "; + + query += __intToString(ruleId); + std::vector record; + ret = __dbManager.executeSync(query.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed"); + + // Remove rule instance from __ruleMap + delete rule; + __ruleMap.erase(it); + + _D(YELLOW("Pause Rule%d"), ruleId); + return ERR_NONE; +} + +int RuleManager::checkRule(std::string pkgId, int ruleId) +{ + // Get package id + std::string q = "SELECT packageId FROM ContextTriggerRule WHERE rowId ="; + q += __intToString(ruleId); + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, false, _E, "Query package id by rule id failed"); + + if (record.size() == 0) { + return ERR_NO_DATA; + } + + std::string p; + record[0].get(NULL, "packageId", &p); + + if (p.compare(pkgId) == 0) { + return ERR_NONE; + } + + return ERR_NO_DATA; +} + +bool RuleManager::isRuleEnabled(int ruleId) +{ + std::string q = "SELECT status FROM ContextTriggerRule WHERE rowId ="; + q += __intToString(ruleId); + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, false, _E, "Query enabled by rule id failed"); + + int status; + record[0].get(NULL, "status", &status); + + return (status != 0); +} + +int RuleManager::getRuleById(std::string pkgId, int ruleId, Json* requestResult) +{ + std::string q = "SELECT description FROM ContextTriggerRule WHERE (packageId = '"; + q += pkgId; + q += "') and (rowId = "; + q += __intToString(ruleId); + q += ")"; + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, false, _E, "Query rule by rule id failed"); + + if (record.size() == 0) { + return ERR_NO_DATA; + } else if (record.size() != 1) { + return ERR_OPERATION_FAILED; + } + + std::string description; + record[0].get(NULL, "description", &description); + + (*requestResult).set(NULL, TRIG_KEY_RULE_ID, ruleId); + (*requestResult).set(NULL, TRIG_RULE_KEY_DESCRIPTION, description); + + return ERR_NONE; +} + +int RuleManager::getRuleIds(std::string pkgId, Json* requestResult) +{ + (*requestResult) = RULE_IDS_JSON; + + std::string q = "SELECT rowId, status FROM ContextTriggerRule WHERE (packageId = '"; + q += pkgId; + q += "')"; + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rules failed"); + + std::vector::iterator vecEnd = record.end(); + for (std::vector::iterator vecPos = record.begin(); vecPos != vecEnd; ++vecPos) { + Json elem = *vecPos; + std::string id; + int status; + + elem.get(NULL, "rowId", &id); + elem.get(NULL, "status", &status); + + if (status >= 1) { + (*requestResult).append(NULL, TRIG_KEY_ENABLED_IDS, __stringToInt(id)); + } else if (status == 0) { + (*requestResult).append(NULL, TRIG_KEY_DISABLED_IDS, __stringToInt(id)); + } + } + + return ERR_NONE; +} diff --git a/src/agent/legacy/trigger/RuleManager.h b/src/agent/legacy/trigger/RuleManager.h new file mode 100644 index 0000000..cf47eee --- /dev/null +++ b/src/agent/legacy/trigger/RuleManager.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_RULE_MANAGER_H_ +#define _CONTEXT_TRIGGER_RULE_MANAGER_H_ + +#include +#include +#include + +namespace ctx { + + class Json; + +namespace trigger { + + class Trigger; + class Rule; + + class RuleManager { + public: + RuleManager(); + ~RuleManager(); + + bool init(); + int addRule(std::string creator, const char* pkgId, Json rule, Json* ruleId); + int removeRule(int ruleId); + int enableRule(int ruleId); + int disableRule(int ruleId); + int getRuleById(std::string pkgId, int ruleId, Json* requestResult); + int getRuleIds(std::string pkgId, Json* requestResult); + int checkRule(std::string pkgId, int ruleId); + bool isRuleEnabled(int ruleId); + int pauseRuleWithItem(std::string& subject); + int pauseRule(int ruleId); + int resumeRuleWithItem(std::string& subject); + void handleRuleOfUninstalledPackage(std::string pkgId); + + static bool isUninstalledPackage(std::string pkgId); + + private: + bool __reenableRule(void); + int __verifyRule(Json& rule, const char* creator); + int64_t __getDuplicatedRuleId(std::string pkgId, Json& rule); + bool __ruleEquals(Json& lRule, Json& rRule); + int __getUninstalledApp(void); + int __clearRuleOfUninstalledPackage(bool isInit = false); + void __applyTemplates(void); + + std::set __uninstalledPackages; + std::map __ruleMap; + DatabaseManager __dbManager; + }; /* class RuleManager */ + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_RULE_MANAGER_H_ */ diff --git a/src/agent/legacy/trigger/TemplateManager.cpp b/src/agent/legacy/trigger/TemplateManager.cpp new file mode 100644 index 0000000..65ddc39 --- /dev/null +++ b/src/agent/legacy/trigger/TemplateManager.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "../ContextManager.h" +#include "RuleManager.h" +#include "TemplateManager.h" + +using namespace ctx; +using namespace ctx::trigger; + +TemplateManager *TemplateManager::__instance = NULL; +ContextManager *TemplateManager::__contextMgr = NULL; +RuleManager *TemplateManager::__ruleMgr = NULL; + +static std::string __intToString(int i) +{ + std::ostringstream convert; + convert << i; + std::string str = convert.str(); + return str; +} + +TemplateManager::TemplateManager() +{ +} + +TemplateManager::~TemplateManager() +{ +} + +void TemplateManager::setManager(ContextManager* ctxMgr, RuleManager* ruleMgr) +{ + __contextMgr = ctxMgr; + __ruleMgr = ruleMgr; +} + +TemplateManager* TemplateManager::getInstance() +{ + IF_FAIL_RETURN_TAG(__contextMgr, NULL, _E, "Context manager is needed"); + IF_FAIL_RETURN_TAG(__ruleMgr, NULL, _E, "Rule manager is needed"); + + IF_FAIL_RETURN(!__instance, __instance); + + __instance = new(std::nothrow) TemplateManager(); + IF_FAIL_RETURN_TAG(__instance, NULL, _E, "Memory alllocation failed"); + + return __instance; +} + +void TemplateManager::destroy() +{ + IF_FAIL_VOID(__instance); + + __instance->applyTemplates(); + + delete __instance; + __instance = NULL; +} + +bool TemplateManager::init() +{ + std::string q = std::string("CREATE TABLE IF NOT EXISTS ContextTriggerTemplate ") + + "(name TEXT DEFAULT '' NOT NULL PRIMARY KEY, operation INTEGER DEFAULT 3 NOT NULL, " + + "attributes TEXT DEFAULT '' NOT NULL, options TEXT DEFAULT '' NOT NULL, owner TEXT DEFAULT '' NOT NULL)"; + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed"); + + // Apply templates + applyTemplates(); + + return true; +} + +void TemplateManager::applyTemplates() +{ + std::string subject; + int operation; + Json attributes; + Json options; + std::string owner; + std::string query; + query.clear(); + + while (__contextMgr->popTriggerTemplate(subject, operation, attributes, options)) { + registerTemplate(subject, operation, attributes, options, ""); + } +} + +void TemplateManager::registerTemplate(std::string subject, int operation, Json attributes, Json options, std::string owner) +{ + _D("[Add template] Subject: %s, Ops: %d, Owner: %s", subject.c_str(), operation, owner.c_str()); + _J("Attr", attributes); + _J("Opt", options); + + std::string query = "UPDATE ContextTriggerTemplate SET operation=" + __intToString(operation) + + ", attributes='" + attributes.str() + "', options='" + options.str() + "', owner='" + owner + + "' WHERE name='" + subject + "'; "; + + query += "INSERT OR IGNORE INTO ContextTriggerTemplate (name, operation, attributes, options, owner) VALUES ('" + + subject + "', " + __intToString(operation) + ", '" + attributes.str() + "', '" + options.str() + "', '" + + owner + "'); "; + + std::vector record; + bool ret = __dbManager.executeSync(query.c_str(), &record); + IF_FAIL_VOID_TAG(ret, _E, "Update template db failed"); + + if (!owner.empty()) { + __ruleMgr->resumeRuleWithItem(subject); + } +} + +void TemplateManager::unregisterTemplate(std::string subject) +{ + _D("[Remove template] Subject: %s", subject.c_str()); + std::string query = "DELETE FROM ContextTriggerTemplate WHERE name = '" + subject + "'; "; + + std::vector record; + bool ret = __dbManager.executeSync(query.c_str(), &record); + IF_FAIL_VOID_TAG(ret, _E, "Update template db failed"); + + __ruleMgr->pauseRuleWithItem(subject); +} + + +std::string TemplateManager::__addTemplate(std::string &subject, int &operation, Json &attributes, Json &options, std::string &owner) +{ + _D("[Add template] Subject: %s, Ops: %d, Owner: %s", subject.c_str(), operation, owner.c_str()); + _J("Attr", attributes); + _J("Opt", options); + + std::string query = "UPDATE ContextTriggerTemplate SET operation=" + __intToString(operation) + + ", attributes='" + attributes.str() + "', options='" + options.str() + "', owner='" + owner + + "' WHERE name='" + subject + "'; "; + + query += "INSERT OR IGNORE INTO ContextTriggerTemplate (name, operation, attributes, options, owner) VALUES ('" + + subject + "', " + __intToString(operation) + ", '" + attributes.str() + "', '" + options.str() + "', '" + + owner + "'); "; + + return query; +} + +std::string TemplateManager::__removeTemplate(std::string &subject) +{ + _D("[Remove template] Subject: %s", subject.c_str()); + std::string query = "DELETE FROM ContextTriggerTemplate WHERE name = '" + subject + "'; "; + + return query; +} + +int TemplateManager::getTemplate(std::string &subject, Json* tmpl) +{ + if (!__contextMgr->isSupported(subject.c_str())) + return ERR_NOT_SUPPORTED; + + // Update latest template information + std::string q = "SELECT * FROM ContextTriggerTemplate WHERE name = '" + subject + "'"; + + std::vector record; + bool ret = __dbManager.executeSync(q.c_str(), &record); + IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query template failed"); + IF_FAIL_RETURN_TAG(record.size() > 0, ERR_NOT_SUPPORTED, _E, "Template(%s) not found", subject.c_str()); + IF_FAIL_RETURN_TAG(record.size() == 1, ERR_OPERATION_FAILED, _E, "Tepmlate duplicated"); + + (*tmpl) = *record.begin(); + + std::string optStr; + std::string attrStr; + tmpl->get(NULL, TRIG_TMPL_KEY_OPTION, &optStr); + tmpl->get(NULL, TRIG_TMPL_KEY_ATTRIBUTE, &attrStr); + + Json opt = optStr; + Json attr = attrStr; + + tmpl->set(NULL, TRIG_TMPL_KEY_OPTION, opt); + tmpl->set(NULL, TRIG_TMPL_KEY_ATTRIBUTE, attr); + + return ERR_NONE; +} diff --git a/src/agent/legacy/trigger/TemplateManager.h b/src/agent/legacy/trigger/TemplateManager.h new file mode 100644 index 0000000..c91ef15 --- /dev/null +++ b/src/agent/legacy/trigger/TemplateManager.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_TEMPLATE_MANAGER_H_ +#define _CONTEXT_TRIGGER_TEMPLATE_MANAGER_H_ + +#include +#include + +namespace ctx { + + class ContextManager; + +namespace trigger { + + class RuleManager; + + class TemplateManager { + public: + static TemplateManager* getInstance(); + static void setManager(ContextManager* ctxMgr, RuleManager* ruleMgr); + static void destroy(); + + bool init(); + void applyTemplates(); + int getTemplate(std::string &subject, Json* tmpl); + void registerTemplate(std::string subject, int operation, Json attributes, Json options, std::string owner); + void unregisterTemplate(std::string subject); + + private: + TemplateManager(); + TemplateManager(const TemplateManager& other); + ~TemplateManager(); + + static TemplateManager *__instance; + static ContextManager *__contextMgr; + static RuleManager *__ruleMgr; + + DatabaseManager __dbManager; + + std::string __addTemplate(std::string &subject, int &operation, Json &attributes, Json &options, std::string &owner); + std::string __removeTemplate(std::string &subject); + + }; /* class TemplateManager */ + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_TEMPLATE_MANAGER_H_ */ diff --git a/src/agent/legacy/trigger/Trigger.cpp b/src/agent/legacy/trigger/Trigger.cpp new file mode 100644 index 0000000..bb3c7aa --- /dev/null +++ b/src/agent/legacy/trigger/Trigger.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "Trigger.h" +#include "ContextMonitor.h" +#include "TemplateManager.h" +#include "RuleManager.h" + +using namespace ctx; +using namespace ctx::trigger; + +Trigger::Trigger() : + __ruleMgr(NULL) +{ +} + +Trigger::~Trigger() +{ +} + +bool Trigger::init(ContextManager* ctxMgr) +{ + // Do the necessary initialization process. + // This function is called from the main thread during the service launching process. + _D("Context Trigger Init"); + __processInitialize(ctxMgr); + + return true; +} + +void Trigger::release() +{ + // Release the occupied resources. + // This function is called from the main thread during the service termination process. + + _D("Template Manager Destroy"); + TemplateManager::destroy(); + + _D("Rule Manager Release"); + delete __ruleMgr; + __ruleMgr = NULL; + + _D("Context Monitor Destroy"); + ContextMonitor::destroy(); +} + +bool Trigger::assignRequest(RequestInfo* request) +{ + std::string subject = request->getSubject(); + if (subject != SUBJ_TRIGGER_ADD && subject != SUBJ_TRIGGER_REMOVE && + subject != SUBJ_TRIGGER_ENABLE && subject != SUBJ_TRIGGER_DISABLE && + subject != SUBJ_TRIGGER_GET && subject != SUBJ_TRIGGER_GET_RULE_IDS && + subject != SUBJ_TRIGGER_GET_TEMPLATE) { + return false; + } + + __processRequest(request); + return true; +} + +void Trigger::__processRequest(RequestInfo* request) +{ + // Process the request, and reply to the client if necessary. + const char* reqSubj = request->getSubject(); + _D("Request is %s", reqSubj); + std::string subject(reqSubj); + + if (subject == SUBJ_TRIGGER_ADD) { + __addRule(request); + } else if (subject == SUBJ_TRIGGER_REMOVE) { + __removeRule(request); + } else if (subject == SUBJ_TRIGGER_ENABLE) { + __enableRule(request); + } else if (subject == SUBJ_TRIGGER_DISABLE) { + __disableRule(request); + } else if (subject == SUBJ_TRIGGER_GET) { + __getRuleById(request); + } else if (subject == SUBJ_TRIGGER_GET_RULE_IDS) { + __getRuleIds(request); + } else if (subject == SUBJ_TRIGGER_GET_TEMPLATE) { + __getTemplate(request); + } else { + _E("Invalid request"); + } + + delete request; +} + +void Trigger::__processInitialize(ContextManager* mgr) +{ + // Context Monitor + ContextMonitor::setContextManager(mgr); + + // Rule Manager + __ruleMgr = new(std::nothrow) RuleManager(); + IF_FAIL_VOID_TAG(__ruleMgr, _E, "Memory allocation failed"); + + // Template Manager + TemplateManager::setManager(mgr, __ruleMgr); + TemplateManager* tmplMgr = TemplateManager::getInstance(); + IF_FAIL_VOID_TAG(tmplMgr, _E, "Memory allocation failed"); + + // Initialization + if (!tmplMgr->init()) { + _E("Template manager initialization failed"); + raise(SIGTERM); + } + + if (!__ruleMgr->init()) { + _E("Context trigger initialization failed"); + raise(SIGTERM); + } +} + +void Trigger::__addRule(RequestInfo* request) +{ + Json ruleId; + + const char* client = request->getClient(); + if (client == NULL) { + request->reply(ERR_OPERATION_FAILED); + return; + } + + const char* pkgId = request->getPackageId(); + + int error = __ruleMgr->addRule(client, pkgId, request->getDescription(), &ruleId); + _I("'%s' adds a rule (Error: %#x)", request->getClient(), error); + + request->reply(error, ruleId); +} + +void Trigger::__removeRule(RequestInfo* request) +{ + int id; + int error; + + const char* pkgId = request->getPackageId(); + + Json ruleId = request->getDescription(); + ruleId.get(NULL, TRIG_KEY_RULE_ID, &id); + + error = __ruleMgr->checkRule((pkgId)? pkgId : "", id); + if (error != ERR_NONE) { + request->reply(error); + return; + } + + bool ret = __ruleMgr->isRuleEnabled(id); + if (ret) { + request->reply(ERR_RULE_ENABLED); + return; + } + + error = __ruleMgr->removeRule(id); + _I("'%s' removes rule%d (Error: %#x)", request->getClient(), id, error); + request->reply(error); +} + +void Trigger::__enableRule(RequestInfo* request) +{ + int id; + int error; + + const char* pkgId = request->getPackageId(); + + Json ruleId = request->getDescription(); + ruleId.get(NULL, TRIG_KEY_RULE_ID, &id); + + error = __ruleMgr->checkRule((pkgId)? pkgId : "", id); + if (error != ERR_NONE) { + request->reply(error); + return; + } + + bool ret = __ruleMgr->isRuleEnabled(id); + if (ret) { + request->reply(ERR_RULE_ENABLED); + return; + } + + error = __ruleMgr->enableRule(id); + _I("'%s' enables rule%d (Error: %#x)", request->getClient(), id, error); + request->reply(error); +} + +void Trigger::__disableRule(RequestInfo* request) +{ + int id; + int error; + + const char* pkgId = request->getPackageId(); + + Json ruleId = request->getDescription(); + ruleId.get(NULL, TRIG_KEY_RULE_ID, &id); + + error = __ruleMgr->checkRule((pkgId)? pkgId : "", id); + if (error != ERR_NONE) { + request->reply(error); + return; + } + + bool ret = __ruleMgr->isRuleEnabled(id); + if (!ret) { + request->reply(ERR_RULE_NOT_ENABLED); + return; + } + + error = __ruleMgr->disableRule(id); + _I("'%s' disables rule%d (Error: %#x)", request->getClient(), id, error); + request->reply(error); +} + +void Trigger::__getRuleById(RequestInfo* request) +{ + int error; + + Json option = request->getDescription(); + int id; + option.get(NULL, TRIG_KEY_RULE_ID, &id); + + const char* pkgId = request->getPackageId(); + + Json readData; + error = __ruleMgr->getRuleById((pkgId)? pkgId : "", id, &readData); + + Json dummy; + request->reply(error, dummy, readData); +} + +void Trigger::__getRuleIds(RequestInfo* request) +{ + int error; + + const char* pkgId = request->getPackageId(); + + Json readData; + error = __ruleMgr->getRuleIds((pkgId)? pkgId : "", &readData); + + Json dummy; + request->reply(error, dummy, readData); +} + +void Trigger::__getTemplate(RequestInfo* request) +{ + int error; + + Json option = request->getDescription(); + std::string name; + option.get(NULL, TRIG_TMPL_KEY_SUBJECT, &name); + + TemplateManager* tmplMgr = TemplateManager::getInstance(); + if (!tmplMgr) { + _E("Memory allocation failed"); + request->reply(ERR_OUT_OF_MEMORY); + return; + } + + Json tmpl; + error = tmplMgr->getTemplate(name, &tmpl); + + Json dummy; + request->reply(error, dummy, tmpl); +} diff --git a/src/agent/legacy/trigger/Trigger.h b/src/agent/legacy/trigger/Trigger.h new file mode 100644 index 0000000..161c99e --- /dev/null +++ b/src/agent/legacy/trigger/Trigger.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_TRIGGER_TRIGGER_H_ +#define _CONTEXT_TRIGGER_TRIGGER_H_ + +#include "../Request.h" + +namespace ctx { + + class client_request; + class ContextManager; + +namespace trigger { + + class RuleManager; + + class Trigger { + public: + Trigger(); + ~Trigger(); + + bool init(ContextManager* ctxMgr); + void release(); + + bool assignRequest(RequestInfo* request); + + private: + void __processRequest(RequestInfo* request); + void __processInitialize(ContextManager* mgr); + + void __addRule(RequestInfo* request); + void __removeRule(RequestInfo* request); + void __enableRule(RequestInfo* request); + void __disableRule(RequestInfo* request); + void __getRuleById(RequestInfo* request); + void __getRuleIds(RequestInfo* request); + void __getTemplate(RequestInfo* request); + + RuleManager* __ruleMgr; + }; + +} /* namespace trigger */ +} /* namespace ctx */ + +#endif /* End of _CONTEXT_TRIGGER_TRIGGER_H_ */ -- 2.7.4