These classes were originally implemented in context-common.
Change-Id: Id26d5dd7321de8062ae7126607b66bf0a5119666
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
Name: context-service
Summary: Tizen Contextual Service Framework
-Version: 1.0.1
+Version: 1.0.2
Release: 1
Group: Service/Context
License: Apache-2.0
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(capi-base-common)
BuildRequires: pkgconfig(alarm-service)
+BuildRequires: pkgconfig(cynara-creds-gdbus)
+BuildRequires: pkgconfig(cynara-client)
+BuildRequires: pkgconfig(cynara-session)
BuildRequires: pkgconfig(context-common-server)
BuildRequires: pkgconfig(context-app-history-server)
BuildRequires: pkgconfig(capi-appfw-app-manager)
BuildRequires: pkgconfig(capi-appfw-package-manager)
BuildRequires: pkgconfig(notification)
-BuildRequires: pkgconfig(cynara-creds-gdbus)
-BuildRequires: pkgconfig(cynara-client)
-BuildRequires: pkgconfig(cynara-session)
BuildRequires: pkgconfig(context-common-legacy)
# ---
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(DEPS
+ libsystemd-login
+ glib-2.0
+ gio-2.0
+ dlog
+ capi-base-common
+ alarm-service
+ cynara-creds-gdbus
+ cynara-client
+ cynara-session
+ context-common-server
+ context-app-history-server
+ context-sensor-recorder-server
+ context-store-server
+ context-job-scheduler-server
+)
SET(INCDIR "${CMAKE_INSTALL_INCLUDEDIR}/context-service")
--- /dev/null
+/*
+ * 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 <cynara-creds-gdbus.h>
+#include <cynara-session.h>
+#include <cynara-client.h>
+#include <ScopeMutex.h>
+#include <ServerUtil.h>
+#include "Credential.h"
+
+#define CACHE_SIZE 100
+
+using namespace ctx;
+
+namespace {
+
+ GMutex __cynaraMutex;
+
+ class PrivilegeChecker {
+ private:
+ cynara* __cynara;
+
+ public:
+ PrivilegeChecker() :
+ __cynara(NULL)
+ {
+ ScopeMutex sm(&__cynaraMutex);
+
+ int err;
+ cynara_configuration* conf = NULL;
+
+ 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");
+ }
+
+ ~PrivilegeChecker()
+ {
+ ScopeMutex sm(&__cynaraMutex);
+
+ if (__cynara)
+ cynara_finish(__cynara);
+
+ _I("Cynara deinitialized");
+ }
+
+ bool hasPrivilege(const char* client, const char* session, const char* user, const char* privil)
+ {
+ ScopeMutex sm(&__cynaraMutex);
+
+ IF_FAIL_RETURN_TAG(__cynara, false, _E, "Cynara not initialized");
+ int ret = cynara_check(__cynara, client, session, user, privil);
+ return (ret == CYNARA_API_ACCESS_ALLOWED);
+ }
+ };
+}
+
+Credential::Credential(GDBusConnection* conn, const std::string& busName) :
+ __pid(0),
+ __uid(ROOT_UID),
+ __session(NULL),
+ __user(NULL),
+ __valid(true)
+{
+ ScopeMutex sm(&__cynaraMutex);
+
+ if (cynara_creds_gdbus_get_pid(conn, busName.c_str(), &__pid) == CYNARA_API_SUCCESS)
+ __session = cynara_session_from_pid(__pid);
+
+ char* cid = NULL;
+ cynara_creds_gdbus_get_client(conn, busName.c_str(), CLIENT_METHOD_DEFAULT, &cid);
+ cynara_creds_gdbus_get_user(conn, busName.c_str(), USER_METHOD_DEFAULT, &__user);
+
+ _SD("%d, %s, %s, %s", __pid, cid, __session, __user);
+
+ if (!cid || !__session || !__user) {
+ _E("Peer credentialing failed");
+ __valid = false;
+ }
+
+ if (cid) {
+ __clientId = cid;
+ g_free(cid);
+ }
+
+ if (__user)
+ __uid = static_cast<uid_t>(std::atoll(__user));
+}
+
+Credential::~Credential()
+{
+ g_free(__session);
+ g_free(__user);
+}
+
+bool Credential::valid() const
+{
+ return __valid;
+}
+
+bool Credential::hasPrivilege(const char* privil) const
+{
+ IF_FAIL_RETURN(privil, true);
+ IF_FAIL_RETURN_TAG(valid(), false, _W, "Unidentified peer");
+
+ static PrivilegeChecker privilegeChecker;
+
+ _D("Checking '%s' for '%s'", privil, __clientId.c_str());
+ if (!privilegeChecker.hasPrivilege(__clientId.c_str(), __session, __user, privil)) {
+ _W("Privilege denied");
+ return false;
+ }
+ return true;
+}
+
+uid_t Credential::getUid() const
+{
+ return __uid;
+}
+
+const std::string& Credential::getClientId() const
+{
+ return __clientId;
+}
+
+bool Credential::isSystem() const
+{
+ return util::isSystemUid(__uid);
+}
--- /dev/null
+/*
+ * 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_CREDENTIAL_H__
+#define __CONTEXT_CREDENTIAL_H__
+
+#include <string>
+#include <ContextTypes.h>
+
+#define ROOT_UID 0
+
+namespace ctx {
+
+ class Credential {
+ public:
+ Credential(GDBusConnection* conn, const std::string& busName);
+ ~Credential();
+
+ bool valid() const;
+ bool hasPrivilege(const char* privil) const;
+
+ uid_t getUid() const;
+ const std::string& getClientId() const;
+ bool isSystem() const;
+
+ static bool isSystemUid(uid_t uid);
+
+ private:
+ pid_t __pid;
+ uid_t __uid;
+ std::string __clientId; /* Tizen-Default: Smack label */
+ char* __session;
+ char* __user; /* Tizen-Default: UID */
+ bool __valid;
+ };
+
+}
+
+#endif
--- /dev/null
+/*
+ * 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 <SharedUtil.h>
+#include "MethodCall.h"
+
+using namespace ctx;
+
+MethodCall::MethodCall(IClient* caller, const std::string& methodName, GVariant* param, GDBusMethodInvocation* invocation) :
+ __caller(caller),
+ __methodName(methodName),
+ __param(param),
+ __invocation(invocation)
+{
+ g_variant_ref(__param);
+}
+
+MethodCall::~MethodCall()
+{
+ g_variant_unref(__param);
+
+ if (!__invocation)
+ return;
+
+ _E("Method call '%s' from '%s' is not handled yet", __methodName.c_str(), __caller->getBusName().c_str());
+
+ g_dbus_method_invocation_return_error_literal(__invocation, CTX_ERROR_DOMAIN, E_FAILED, "");
+}
+
+const std::string& MethodCall::getMethodName()
+{
+ return __methodName;
+}
+
+GVariant* MethodCall::getParam()
+{
+ return __param;
+}
+
+bool MethodCall::reply(GVariant* param)
+{
+ IF_FAIL_RETURN_TAG(__invocation, false, _E, "Replied already");
+
+ g_dbus_method_invocation_return_value(__invocation, param);
+ __invocation = NULL;
+
+ return true;
+}
+
+bool MethodCall::reply(int error)
+{
+ IF_FAIL_RETURN_TAG(__invocation, false, _D, "Replied already");
+
+ if (error == E_NONE)
+ return reply(static_cast<GVariant*>(NULL));
+
+ g_dbus_method_invocation_return_error_literal(__invocation, CTX_ERROR_DOMAIN, error, "");
+ __invocation = NULL;
+
+ return true;
+}
+
+void MethodCall::publish(const std::string& signalName, GVariant* param)
+{
+ getCaller().publish(signalName, param);
+}
+
+bool MethodCall::hasPrivilege(const char* privil)
+{
+ return getCaller().hasPrivilege(privil);
+}
+
+uid_t MethodCall::getUid()
+{
+ return getCaller().getUid();
+}
+
+const std::string& MethodCall::getCallerId()
+{
+ return getCaller().getId();
+}
+
+bool MethodCall::isSystem()
+{
+ return getCaller().isSystem();
+}
+
+IClient& MethodCall::getCaller()
+{
+ return *__caller;
+}
--- /dev/null
+/*
+ * 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_METHOD_CALL_H__
+#define __CONTEXT_METHOD_CALL_H__
+
+#include <string>
+#include <ContextTypes.h>
+#include <IMethodCall.h>
+#include <IClient.h>
+
+namespace ctx {
+
+ class MethodCall : public IMethodCall {
+ public:
+ MethodCall(IClient* caller, const std::string& methodName, GVariant* param, GDBusMethodInvocation* invocation);
+ ~MethodCall();
+
+ const std::string& getMethodName();
+
+ GVariant* getParam();
+
+ bool reply(GVariant* param);
+ bool reply(int error);
+
+ void publish(const std::string& signalName, GVariant* param);
+
+ bool hasPrivilege(const char* privil);
+
+ uid_t getUid();
+
+ const std::string& getCallerId();
+
+ bool isSystem();
+
+ IClient& getCaller();
+
+ private:
+ IClient* __caller;
+ std::string __methodName;
+ GVariant* __param;
+ GDBusMethodInvocation* __invocation;
+ };
+
+}
+
+#endif /* __CONTEXT_METHOD_CALL_H__ */
--- /dev/null
+/*
+ * 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 "Credential.h"
+#include "ServiceRunner.h"
+#include "ServiceClient.h"
+
+using namespace ctx;
+
+ServiceClient::ServiceClient(ServiceRunner* runner, IMethodCallHandler* handler, const std::string& busName) :
+ __serviceRunner(runner),
+ __methodCallHandler(handler),
+ __busName(busName),
+ __credential(NULL)
+{
+}
+
+ServiceClient::~ServiceClient()
+{
+ delete __credential;
+ delete __methodCallHandler;
+}
+
+const std::string& ServiceClient::getBusName()
+{
+ return __busName;
+}
+
+const std::string& ServiceClient::getId()
+{
+ return __credential->getClientId();
+}
+
+uid_t ServiceClient::getUid()
+{
+ return __credential->getUid();
+}
+
+bool ServiceClient::isSystem()
+{
+ return __credential->isSystem();
+}
+
+bool ServiceClient::isVerified()
+{
+ IF_FAIL_RETURN(__getCredential(), false);
+ return __credential->valid();
+}
+
+bool ServiceClient::hasPrivilege(const char* privil)
+{
+ return __credential->hasPrivilege(privil);
+}
+
+bool ServiceClient::hasPrivileges(const std::vector<std::string>& privil)
+{
+ for (auto& item : privil) {
+ if (!hasPrivilege(item.c_str()))
+ return false;
+ }
+ return true;
+}
+
+void ServiceClient::publish(const std::string& signalName, GVariant* param)
+{
+ __serviceRunner->publish(__busName, signalName, param);
+}
+
+IService* ServiceClient::getHostService()
+{
+ return __serviceRunner->getService();
+}
+
+ServiceRunner* ServiceClient::getHostServiceRunner()
+{
+ return __serviceRunner;
+}
+
+void ServiceClient::onMethodCalled(IMethodCall* methodCall)
+{
+ __methodCallHandler->onMethodCalled(methodCall);
+}
+
+void ServiceClient::onDisconnected()
+{
+ __methodCallHandler->onDisconnected();
+}
+
+bool ServiceClient::__getCredential()
+{
+ if (__credential)
+ return true;
+
+ __credential = new Credential(__serviceRunner->getConnection(), __busName);
+
+ return true;
+}
--- /dev/null
+/*
+ * 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_SERVICE_CLIENT_H__
+#define __CONTEXT_SERVICE_CLIENT_H__
+
+#include <vector>
+#include <string>
+#include <ContextTypes.h>
+#include <IClient.h>
+#include <IMethodCall.h>
+#include <IMethodCallHandler.h>
+
+namespace ctx {
+
+ class ServiceRunner;
+ class Credential;
+
+ class ServiceClient : public IClient {
+ public:
+ ServiceClient(ServiceRunner* runner, IMethodCallHandler* callHandler, const std::string& busName);
+ ~ServiceClient();
+
+ const std::string& getBusName();
+ const std::string& getId();
+
+ uid_t getUid();
+ bool isSystem();
+
+ bool isVerified();
+
+ bool hasPrivilege(const char* privil);
+ bool hasPrivileges(const std::vector<std::string>& privil);
+
+ void publish(const std::string& signalName, GVariant* param);
+
+ IService* getHostService();
+ ServiceRunner* getHostServiceRunner();
+
+ void onMethodCalled(IMethodCall* methodCall);
+ void onDisconnected();
+
+ private:
+ bool __getCredential();
+
+ ServiceRunner* __serviceRunner;
+ IMethodCallHandler* __methodCallHandler;
+ std::string __busName;
+ Credential* __credential;
+ };
+
+}
+
+#endif /* __CONTEXT_SERVICE_CLIENT_H__ */
* limitations under the License.
*/
+#include <ServerUtil.h>
#include <AppHistoryService.h>
#include <SensorRecorderService.h>
#include <ContextStoreService.h>
ServiceLoader::~ServiceLoader()
{
- for (auto& svc : __userServices) {
- delete svc;
+ for (auto& runner : __userServices) {
+ delete runner;
}
- for (auto& svc : __systemServices) {
- delete svc;
+ for (auto& runner : __systemServices) {
+ delete runner;
}
}
void ServiceLoader::startSystem()
{
- for (auto& svc : __systemServices) {
- svc->start();
+ for (auto& runner : __systemServices) {
+ runner->start();
}
}
void ServiceLoader::stopSystem()
{
- for (auto& svc : __systemServices) {
- svc->stop();
+ for (auto& runner : __systemServices) {
+ runner->stop();
}
}
IF_FAIL_VOID(__activeUser != uid);
_I("Starting services for %u", static_cast<unsigned int>(uid));
- ServiceBase::setActiveUser(uid);
+ util::setActiveUid(uid);
- for (auto& svc : __userServices) {
- svc->start();
+ for (auto& runner : __userServices) {
+ runner->start();
}
- for (auto& svc : __systemServices) {
- svc->notifyUserNew();
+ for (auto& runner : __systemServices) {
+ runner->notifyUserNew();
}
__activeUser = uid;
IF_FAIL_VOID(__activeUser != ROOT_UID);
_I("Stopping services for %u", static_cast<unsigned int>(__activeUser));
- for (auto& svc : __userServices) {
- svc->stop();
+ for (auto& runner : __userServices) {
+ runner->stop();
}
- ServiceBase::setActiveUser(ROOT_UID);
+ util::setActiveUid(ROOT_UID);
- for (auto& svc : __systemServices) {
- svc->notifyUserRemoved();
+ for (auto& runner : __systemServices) {
+ runner->notifyUserRemoved();
}
__activeUser = ROOT_UID;
#include <vector>
#include <ContextTypes.h>
-#include <ServiceBase.h>
+#include <IService.h>
+#include "ServiceRunner.h"
+#include "ServiceClient.h"
namespace ctx {
private:
uid_t __activeUser;
- std::vector<ServiceBase*> __userServices;
- std::vector<ServiceBase*> __systemServices;
+ std::vector<ServiceRunner*> __userServices;
+ std::vector<ServiceRunner*> __systemServices;
template<typename ServiceType> void __create(GDBusConnection* conn)
{
- ServiceBase *svc = NULL;
+ IService* svc = NULL;
+
try {
- svc = new ServiceType(conn);
+ svc = new ServiceType();
} catch (const std::runtime_error& e) {
_I(YELLOW("%s"), e.what());
return;
}
+
+ ServiceRunner* runner = new ServiceRunner(conn, svc);
+ svc->setServiceRunner(runner);
+
if (svc->isUserService()) {
- __userServices.push_back(svc);
+ __userServices.push_back(runner);
} else {
- __systemServices.push_back(svc);
+ __systemServices.push_back(runner);
}
}
};
--- /dev/null
+/*
+ * 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 <ScopeMutex.h>
+#include "MethodCall.h"
+#include "ServiceClient.h"
+#include "ServiceRunner.h"
+
+using namespace ctx;
+
+ServiceRunner::ServiceRunner(GDBusConnection* conn, IService* service) :
+ __service(service),
+ __started(false),
+ __threadRunning(false),
+ __mainContext(NULL),
+ __mainLoop(NULL),
+ __gthread(NULL),
+ __connection(conn),
+ __objPath(CTX_DBUS_PATH),
+ __interface(CTX_DBUS_IFACE),
+ __nodeInfo(NULL),
+ __registrationId(0)
+{
+ __objPath += __service->getServiceName();
+ __interface += __service->getServiceName();
+}
+
+ServiceRunner::~ServiceRunner()
+{
+}
+
+GMainContext* ServiceRunner::getMainContext()
+{
+ return __mainContext;
+}
+
+GDBusConnection* ServiceRunner::getConnection()
+{
+ return __connection;
+}
+
+IService* ServiceRunner::getService()
+{
+ return __service;
+}
+
+bool ServiceRunner::start()
+{
+ IF_FAIL_RETURN(!__started, true);
+
+ _I("Preparing '%s'", __service->getServiceName());
+
+ __gthread = g_thread_new(__service->getServiceName(), __threadFunc, this);
+ IF_FAIL_RETURN_TAG(__gthread, false, _E, "Thread creation failed");
+
+ __started = true;
+ return true;
+}
+
+void ServiceRunner::stop()
+{
+ IF_FAIL_VOID(__started);
+ __started = false;
+
+ IF_FAIL_VOID(__threadRunning.load());
+
+ GSource *gSrc = g_idle_source_new();
+ if (gSrc) {
+ // Tries to stop the main loop within its thread.
+ // In this way, already scheduled idle tasks are not discarded.
+ g_source_set_callback(gSrc, __stopMainLoop, this, NULL);
+ g_source_attach(gSrc, __mainContext);
+ g_source_unref(gSrc);
+ } else {
+ __stopMainLoop(this);
+ }
+
+ _I("Joining the thread of '%s'", __service->getServiceName());
+ g_thread_join(__gthread);
+ __gthread = NULL;
+}
+
+gboolean ServiceRunner::__stopMainLoop(gpointer data)
+{
+ ServiceRunner* runner = static_cast<ServiceRunner*>(data);
+ _I(PURPLE("Stopping '%s'"), runner->__service->getServiceName());
+ g_main_loop_quit(runner->__mainLoop);
+ return G_SOURCE_REMOVE;
+}
+
+void ServiceRunner::publish(const std::string& busName, const std::string& signalName, GVariant* param)
+{
+ GError* gerr = NULL;
+ g_dbus_connection_emit_signal(__connection,
+ busName.c_str(), __objPath.c_str(), __interface.c_str(),
+ signalName.c_str(), param, &gerr);
+ HANDLE_GERROR(gerr);
+}
+
+void ServiceRunner::notifyUserNew()
+{
+ IF_FAIL_VOID(__started);
+ IF_FAIL_VOID(__threadRunning.load());
+
+ GSource* gSrc = g_idle_source_new();
+ IF_FAIL_VOID_TAG(gSrc, _E, E_STR_ALLOC);
+
+ g_source_set_callback(gSrc, __onUserActivated, __service, NULL);
+ g_source_attach(gSrc, __mainContext);
+ g_source_unref(gSrc);
+}
+
+void ServiceRunner::notifyUserRemoved()
+{
+ IF_FAIL_VOID(__started);
+ IF_FAIL_VOID(__threadRunning.load());
+
+ GSource* gSrc = g_idle_source_new();
+ IF_FAIL_VOID_TAG(gSrc, _E, E_STR_ALLOC);
+
+ g_source_set_callback(gSrc, __onUserDeactivated, __service, NULL);
+ g_source_attach(gSrc, __mainContext);
+ g_source_unref(gSrc);
+}
+
+gboolean ServiceRunner::__onUserActivated(gpointer data)
+{
+ IService* svc = static_cast<IService*>(data);
+ svc->onUserActivated();
+ return G_SOURCE_REMOVE;
+}
+
+gboolean ServiceRunner::__onUserDeactivated(gpointer data)
+{
+ IService* svc = static_cast<IService*>(data);
+ svc->onUserDeactivated();
+ return G_SOURCE_REMOVE;
+}
+
+gpointer ServiceRunner::__threadFunc(gpointer data)
+{
+ ServiceRunner* runner = static_cast<ServiceRunner*>(data);
+ runner->__run();
+ return NULL;
+}
+
+void ServiceRunner::__run()
+{
+ if (!__init()) {
+ _E("Starting '%s' failed", __service->getServiceName());
+ __release();
+ return;
+ }
+
+ __threadRunning.store(true);
+
+ _I(CYAN("Starting '%s'"), __service->getServiceName());
+ g_main_loop_run(__mainLoop);
+
+ __threadRunning.store(false);
+
+ __release();
+}
+
+bool ServiceRunner::__init()
+{
+ GError* gerr = NULL;
+ GDBusInterfaceVTable vtable;
+
+ vtable.method_call = __onMethodCalled;
+ vtable.get_property = NULL;
+ vtable.set_property = NULL;
+
+ __mainContext = g_main_context_new();
+ IF_FAIL_RETURN_TAG(__mainContext, false, _E, "MainContext creation failed");
+
+ g_main_context_push_thread_default(__mainContext);
+
+ __mainLoop = g_main_loop_new(__mainContext, FALSE);
+ IF_FAIL_RETURN_TAG(__mainLoop, false, _E, "MainLoop creation failed");
+
+ std::string introspection("<node><interface name='");
+ introspection += __interface + "'>" + __service->getMethodSpecs() + "</interface></node>";
+
+ __nodeInfo = g_dbus_node_info_new_for_xml(introspection.c_str(), NULL);
+ IF_FAIL_RETURN_TAG(__nodeInfo, false, _E, "NodeInfo creation failed");
+
+ __registrationId = g_dbus_connection_register_object(__connection,
+ __objPath.c_str(), __nodeInfo->interfaces[0], &vtable, this, NULL, &gerr);
+ HANDLE_GERROR(gerr);
+ IF_FAIL_RETURN_TAG(__registrationId > 0, false, _E, "Object registration failed");
+
+ return __service->prepare();
+}
+
+void ServiceRunner::__release()
+{
+ _D("Releasing '%s'", __service->getServiceName());
+
+ for (auto iter = __clients.begin(); iter != __clients.end(); ++iter) {
+ iter->second.client->onDisconnected();
+ delete iter->second.client;
+ }
+
+ __clients.clear();
+
+ __service->cleanup();
+
+ if (__registrationId > 0)
+ g_dbus_connection_unregister_object(__connection, __registrationId);
+
+ if (__nodeInfo)
+ g_dbus_node_info_unref(__nodeInfo);
+
+ if (__mainLoop)
+ g_main_loop_unref(__mainLoop);
+
+ if (__mainContext)
+ g_main_context_unref(__mainContext);
+}
+
+void ServiceRunner::__onMethodCalled(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, GDBusMethodInvocation* invocation, gpointer userData)
+{
+ ServiceRunner* runner = static_cast<ServiceRunner*>(userData);
+ runner->__onMethodCalled(sender, name, param, invocation);
+}
+
+void ServiceRunner::__onMethodCalled(const std::string& sender,
+ const std::string& name, GVariant* param, GDBusMethodInvocation* invocation)
+{
+ _I("'%s' called '%s.%s'", sender.c_str(), __service->getServiceName(), name.c_str());
+
+ ServiceClient* client = __getClient(sender);
+ IF_FAIL_VOID(client);
+
+ client->onMethodCalled(new MethodCall(client, name, param, invocation));
+}
+
+ServiceClient* ServiceRunner::__getClient(const std::string& busName)
+{
+ auto iter = __clients.find(busName);
+
+ if (iter != __clients.end())
+ return iter->second.client;
+
+ IMethodCallHandler* callHandler = __service->createMethodCallHandler();
+ IF_FAIL_RETURN(callHandler, NULL);
+
+ ServiceClient* client = new ServiceClient(this, callHandler, busName);
+ if (!client->isVerified()) {
+ delete client;
+ return NULL;
+ }
+
+ callHandler->setCaller(client);
+
+ __ClientInfo info = {client, __watch(busName, client)};
+ __clients[busName] = info;
+
+ return client;
+}
+
+void ServiceRunner::__onNameOwnerChanged(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, gpointer userData)
+{
+ ServiceClient* client = static_cast<ServiceClient*>(userData);
+ client->getHostServiceRunner()->__removeClient(client->getBusName());
+}
+
+void ServiceRunner::__removeClient(const std::string& busName)
+{
+ _I("'%s' lost '%s'", __service->getServiceName(), busName.c_str());
+
+ auto iter = __clients.find(busName);
+ IF_FAIL_VOID(iter != __clients.end());
+
+ __ClientInfo info = iter->second;
+ __clients.erase(iter);
+
+ __unwatch(info.watchId);
+ info.client->onDisconnected();
+ delete info.client;
+}
+
+unsigned int ServiceRunner::__watch(const std::string& busName, ServiceClient* client)
+{
+ return g_dbus_connection_signal_subscribe(__connection,
+ "org.freedesktop.DBus", "org.freedesktop.DBus", "NameOwnerChanged", "/org/freedesktop/DBus",
+ busName.c_str(), G_DBUS_SIGNAL_FLAGS_NONE, __onNameOwnerChanged, client, NULL);
+}
+
+void ServiceRunner::__unwatch(unsigned int watchId)
+{
+ g_dbus_connection_signal_unsubscribe(__connection, watchId);
+}
--- /dev/null
+/*
+ * 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_SERVICE_RUNNER_H__
+#define __CONTEXT_SERVICE_RUNNER_H__
+
+#include <atomic>
+#include <string>
+#include <map>
+#include <ContextTypes.h>
+#include <IService.h>
+#include <IServiceRunner.h>
+
+namespace ctx {
+
+ class ServiceClient;
+
+ class ServiceRunner : public IServiceRunner {
+ public:
+ ServiceRunner(GDBusConnection* conn, IService* service);
+ ~ServiceRunner();
+
+ void setService(IService* service);
+
+ bool start();
+ void stop();
+
+ void notifyUserNew();
+ void notifyUserRemoved();
+
+ void publish(const std::string& busName, const std::string& signalName, GVariant* param);
+
+ GMainContext* getMainContext();
+ GDBusConnection* getConnection();
+ IService* getService();
+
+ private:
+ static gpointer __threadFunc(gpointer data);
+
+ static void __onMethodCalled(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, GDBusMethodInvocation* invocation, gpointer userData);
+
+ static void __onNameOwnerChanged(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, gpointer userData);
+
+ static gboolean __onUserActivated(gpointer data);
+
+ static gboolean __onUserDeactivated(gpointer data);
+
+ static gboolean __stopMainLoop(gpointer data);
+
+ void __onMethodCalled(const std::string& sender,
+ const std::string& name, GVariant* param, GDBusMethodInvocation* invocation);
+
+ void __run();
+ bool __init();
+ void __release();
+
+ ServiceClient* __getClient(const std::string& busName);
+ void __removeClient(const std::string& busName);
+ unsigned int __watch(const std::string& busName, ServiceClient* client);
+ void __unwatch(unsigned int watchId);
+
+ IService* __service;
+ bool __started;
+ std::atomic_bool __threadRunning;
+
+ GMainContext* __mainContext;
+ GMainLoop* __mainLoop;
+ GThread* __gthread;
+
+ GDBusConnection* __connection;
+ std::string __objPath;
+ std::string __interface;
+
+ GDBusNodeInfo* __nodeInfo;
+ guint __registrationId;
+
+ struct __ClientInfo {
+ ServiceClient* client;
+ unsigned int watchId;
+ };
+
+ std::map<std::string, __ClientInfo> __clients;
+ };
+
+}
+
+#endif /* __CONTEXT_SERVICE_RUNNER_H__ */