2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <ScopeMutex.h>
19 #include <ClientBase.h>
20 #include <MethodCall.h>
21 #include <ServiceBase.h>
25 static std::atomic_uint __activeUid;
27 bool ServiceBase::__singleThreading = false;
29 ServiceBase::ServiceBase(GDBusConnection* conn, const char* serviceName, const char* methodSpecs) :
31 __serviceName(serviceName),
36 __methodSpecs(methodSpecs),
37 __objPath(CTX_DBUS_PATH),
38 __interface(CTX_DBUS_IFACE),
42 __objPath += serviceName;
43 __interface += serviceName;
46 ServiceBase::~ServiceBase()
50 GDBusConnection* ServiceBase::getConnection()
55 bool ServiceBase::start()
57 IF_FAIL_RETURN(!__running, true);
60 _I("Preparing '%s'", __serviceName);
62 if (__singleThreading) {
63 _I(CYAN("'%s' runs on the global main loop"), __serviceName);
64 IF_FAIL_RETURN(__init(), false);
66 __gthread = g_thread_new(__serviceName, __threadFunc, this);
67 IF_FAIL_RETURN_TAG(__gthread, false, _E, "Thread creation failed");
73 void ServiceBase::stop()
75 IF_FAIL_VOID(__running);
78 if (__singleThreading) {
81 if (__mainLoop && g_main_loop_is_running(__mainLoop)) {
82 GSource *gSrc = g_idle_source_new();
84 // Tries to stop the main loop within its thread.
85 // In this way, already scheduled idle tasks are not discarded.
86 g_source_set_callback(gSrc, __stopMainLoop, this, NULL);
87 g_source_attach(gSrc, __mainContext);
94 _I("Joining the thread of '%s'", __serviceName);
95 g_thread_join(__gthread);
100 gboolean ServiceBase::__stopMainLoop(gpointer data)
102 ServiceBase* svc = static_cast<ServiceBase*>(data);
103 _I(PURPLE("Stopping '%s'"), svc->__serviceName);
104 g_main_loop_quit(svc->__mainLoop);
105 return G_SOURCE_REMOVE;
108 void ServiceBase::publish(const std::string& busName, const std::string& signalName, GVariant* param)
111 g_dbus_connection_emit_signal(__connection,
112 busName.c_str(), __objPath.c_str(), __interface.c_str(),
113 signalName.c_str(), param, &gerr);
117 uid_t ServiceBase::getActiveUser()
119 return __activeUid.load();
122 void ServiceBase::setActiveUser(uid_t uid)
124 __activeUid.store(uid);
127 void ServiceBase::onUserActivated()
131 void ServiceBase::onUserDeactivated()
135 void ServiceBase::notifyUserNew()
137 GSource* gSrc = g_idle_source_new();
138 IF_FAIL_VOID_TAG(gSrc, _E, "Memory allocation failed");
140 g_source_set_callback(gSrc, __onUserActivated, this, NULL);
141 g_source_attach(gSrc, __mainContext);
144 void ServiceBase::notifyUserRemoved()
146 GSource* gSrc = g_idle_source_new();
147 IF_FAIL_VOID_TAG(gSrc, _E, "Memory allocation failed");
149 g_source_set_callback(gSrc, __onUserDeactivated, this, NULL);
150 g_source_attach(gSrc, __mainContext);
153 gboolean ServiceBase::__onUserActivated(gpointer data)
155 ServiceBase* svc = static_cast<ServiceBase*>(data);
156 svc->onUserActivated();
157 return G_SOURCE_REMOVE;
160 gboolean ServiceBase::__onUserDeactivated(gpointer data)
162 ServiceBase* svc = static_cast<ServiceBase*>(data);
163 svc->onUserDeactivated();
164 return G_SOURCE_REMOVE;
167 gpointer ServiceBase::__threadFunc(gpointer data)
169 ServiceBase* service = static_cast<ServiceBase*>(data);
174 void ServiceBase::__run()
177 _E("Starting failed");
182 _I(CYAN("Starting '%s'"), __serviceName);
183 g_main_loop_run(__mainLoop);
188 bool ServiceBase::__init()
191 GDBusInterfaceVTable vtable;
193 vtable.method_call = __onMethodCalled;
194 vtable.get_property = NULL;
195 vtable.set_property = NULL;
197 if (!__singleThreading) {
198 __mainContext = g_main_context_new();
199 IF_FAIL_RETURN_TAG(__mainContext, false, _E, "MainContext creation failed");
201 g_main_context_push_thread_default(__mainContext);
203 __mainLoop = g_main_loop_new(__mainContext, FALSE);
204 IF_FAIL_RETURN_TAG(__mainLoop, false, _E, "MainLoop creation failed");
207 std::string introspection("<node><interface name='");
208 introspection += __interface + "'>" + __methodSpecs + "</interface></node>";
210 __nodeInfo = g_dbus_node_info_new_for_xml(introspection.c_str(), NULL);
211 IF_FAIL_RETURN_TAG(__nodeInfo, false, _E, "NodeInfo creation failed");
213 __registrationId = g_dbus_connection_register_object(__connection,
214 __objPath.c_str(), __nodeInfo->interfaces[0], &vtable, this, NULL, &gerr);
216 IF_FAIL_RETURN_TAG(__registrationId > 0, false, _E, "Object registration failed");
221 void ServiceBase::__release()
223 _D("Releasing '%s'", __serviceName);
225 for (auto iter = __clients.begin(); iter != __clients.end(); ++iter) {
226 iter->second.client->onDisconnected();
227 delete iter->second.client;
234 if (__registrationId > 0)
235 g_dbus_connection_unregister_object(__connection, __registrationId);
238 g_dbus_node_info_unref(__nodeInfo);
241 g_main_loop_unref(__mainLoop);
244 g_main_context_unref(__mainContext);
247 void ServiceBase::__onMethodCalled(GDBusConnection* conn, const gchar* sender,
248 const gchar* path, const gchar* iface, const gchar* name,
249 GVariant* param, GDBusMethodInvocation* invocation, gpointer userData)
251 ServiceBase* service = static_cast<ServiceBase*>(userData);
252 service->__onMethodCalled(sender, name, param, invocation);
255 void ServiceBase::__onMethodCalled(const std::string& sender,
256 const std::string& name, GVariant* param, GDBusMethodInvocation* invocation)
258 _I("'%s' called '%s.%s'", sender.c_str(), __serviceName, name.c_str());
260 ClientBase* client = __getClient(sender);
261 IF_FAIL_VOID(client);
263 MethodCall* methodCall = new(std::nothrow) MethodCall(client, name, param, invocation);
264 IF_FAIL_VOID_TAG(methodCall, _E, "Memory allocation failed");
266 client->onMethodCalled(methodCall);
269 ClientBase* ServiceBase::__getClient(const std::string& busName)
271 auto iter = __clients.find(busName);
273 if (iter != __clients.end())
274 return iter->second.client;
276 ClientBase* client = createClient(busName);
277 IF_FAIL_RETURN_TAG(client, NULL, _E, "Memory allocation failed");
279 if (!client->isVerified()) {
284 ClientInfo info = {client, __watch(busName, client)};
285 __clients[busName] = info;
290 void ServiceBase::__onNameOwnerChanged(GDBusConnection* conn, const gchar* sender,
291 const gchar* path, const gchar* iface, const gchar* name,
292 GVariant* param, gpointer userData)
294 ClientBase* client = static_cast<ClientBase*>(userData);
295 client->getHostService().__removeClient(client->getBusName());
298 void ServiceBase::__removeClient(const std::string& busName)
300 _I("'%s' lost '%s'", __serviceName, busName.c_str());
302 auto iter = __clients.find(busName);
303 IF_FAIL_VOID(iter != __clients.end());
305 ClientInfo info = iter->second;
306 __clients.erase(iter);
308 __unwatch(info.watchId);
309 info.client->onDisconnected();
313 unsigned int ServiceBase::__watch(const std::string& busName, ClientBase* client)
315 return g_dbus_connection_signal_subscribe(__connection,
316 "org.freedesktop.DBus", "org.freedesktop.DBus", "NameOwnerChanged", "/org/freedesktop/DBus",
317 busName.c_str(), G_DBUS_SIGNAL_FLAGS_NONE, __onNameOwnerChanged, client, NULL);
320 void ServiceBase::__unwatch(unsigned int watchId)
322 g_dbus_connection_signal_unsubscribe(__connection, watchId);
325 void ServiceBase::setSingleThreading()
327 __singleThreading = true;