2 * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd All Rights Reserved
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
17 * @file service_manager.cpp
18 * @author Zbigniew Jasinski <z.jasinski@samsung.com>
19 * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
20 * @author Marcin Niesluchowski <m.niesluchow@samsung.com>
22 * @brief Definition of service control class using dbus interface to communicate with systemd
25 #include <service_manager.h>
27 #include <dpl/test/test_runner.h>
35 const std::string DBUS_CLIENT_NAME("tests.dbus.client");
36 const std::string DBUS_PROPERTIES_INTERFACE("org.freedesktop.DBus.Properties");
37 const std::string SYSTEMD_DESTINATION("org.freedesktop.systemd1");
38 const std::string SYSTEMD_PATH("/org/freedesktop/systemd1");
39 const std::string SYSTEMD_MANAGER_INTERFACE("org.freedesktop.systemd1.Manager");
40 const std::string SYSTEMD_SERVICE_INTERFACE("org.freedesktop.systemd1.Service");
42 const std::string MATCH_JOB_REMOVED("JobRemoved");
43 const std::string MATCH_JOB_NEW("JobNew");
44 const std::string MATCH_RELOADING("Reloading");
48 ServiceManager::ServiceManager(const std::string &serviceName)
49 : m_connection(DBUS_BUS_SYSTEM, true)
50 , m_serviceName(serviceName)
52 addBusMatch(MATCH_JOB_REMOVED);
53 addBusMatch(MATCH_JOB_NEW);
54 addBusMatch(MATCH_RELOADING);
56 m_connection.addFilter(messageHandler,
57 reinterpret_cast<void*>(this));
59 m_connection.requestName(DBUS_CLIENT_NAME);
63 void ServiceManager::addBusMatch(const std::string &member)
65 std::ostringstream rule;
66 rule << "type='signal',"
67 << "sender='" << SYSTEMD_DESTINATION << "',"
68 << "interface='" << SYSTEMD_MANAGER_INTERFACE << "',"
69 << "member='" << member << "',"
70 << "path='" << SYSTEMD_PATH << "'";
72 m_connection.addMatch(rule.str());
75 void ServiceManager::subscribeSignals()
77 DBus::MessageOut messageOut = newMethodCall("Subscribe");
78 m_connection.sendWithReplyAndBlock(messageOut);
81 void ServiceManager::reloadDbusManager()
83 DBus::MessageOut messageOut = newMethodCall("Reload");
84 m_connection.sendWithReplyAndBlock(messageOut);
85 m_runningJobs.insert(MATCH_RELOADING);
88 void ServiceManager::getUnitPath()
90 DBus::MessageOut messageOut = newMethodCall("GetUnit");
91 messageOut.append(m_serviceName);
92 DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
93 m_unitPath = handleObjectPathMsgReply(messageIn);
96 DBus::MessageOut ServiceManager::newMethodCall(const std::string &method)
98 return DBus::MessageOut(SYSTEMD_DESTINATION.c_str(),
100 SYSTEMD_MANAGER_INTERFACE.c_str(),
104 std::string ServiceManager::handleObjectPathMsgReply(DBus::MessageIn &messageIn)
106 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
107 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
108 return iterator.getArgString();
111 uint32_t ServiceManager::handleVariantUIntMsgReply(DBus::MessageIn &messageIn)
113 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
114 iterator.expectArgType(DBUS_TYPE_VARIANT);
115 DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
116 iteratorSub.expectArgType(DBUS_TYPE_UINT32);
117 return iteratorSub.getArgUint32();
120 void ServiceManager::sendToService(const std::string &method)
122 DBus::MessageOut messageOut = newMethodCall(method);
123 messageOut.append(m_serviceName);
124 messageOut.append("fail");
125 DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
126 m_runningJobs.insert(handleObjectPathMsgReply(messageIn));
129 void ServiceManager::sendMaskToService()
131 const std::vector<std::string> mask(1, m_serviceName);
132 DBus::MessageOut messageOut = newMethodCall("MaskUnitFiles");
133 messageOut.append(mask);
134 messageOut.append(true);
135 messageOut.append(true);
136 m_connection.sendWithReplyAndBlock(messageOut);
139 void ServiceManager::sendUnmaskToService()
141 const std::vector<std::string> mask(1, m_serviceName);
142 DBus::MessageOut messageOut = newMethodCall("UnmaskUnitFiles");
143 messageOut.append(mask);
144 messageOut.append(true);
145 m_connection.sendWithReplyAndBlock(messageOut);
148 uint32_t ServiceManager::getUIntProperty(const std::string &interface, const std::string &property)
150 DBus::MessageOut messageOut(SYSTEMD_DESTINATION.c_str(),
151 SYSTEMD_PATH.c_str(),
152 DBUS_PROPERTIES_INTERFACE.c_str(),
154 messageOut.append(interface);
155 messageOut.append(property);
156 DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
157 return handleVariantUIntMsgReply(messageIn);
160 void ServiceManager::sendResetFailedToService()
162 DBus::MessageOut messageOut = newMethodCall("ResetFailedUnit");
163 messageOut.append(m_serviceName);
164 m_connection.sendWithReplyAndBlock(messageOut);
167 DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t)
170 ServiceManager* self = reinterpret_cast<ServiceManager*>(t);
172 DBus::MessageIn messageIn(msg, true);
173 if (messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_REMOVED))
174 self->signalJobRemovedHandler(messageIn);
175 else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_NEW))
176 self->signalJobNewHandler(messageIn);
177 else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_RELOADING))
178 self->signalReloadingHandler(messageIn);
180 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
183 void ServiceManager::signalJobRemovedHandler(DBus::MessageIn &messageIn)
185 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
187 iterator.expectArgType(DBUS_TYPE_UINT32);
188 uint32_t id = iterator.getArgUint32();
189 iterator.expectNext();
191 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
192 std::string path = iterator.getArgString();
193 iterator.expectNext();
195 iterator.expectArgType(DBUS_TYPE_STRING);
196 std::string unit = iterator.getArgString();
197 iterator.expectNext();
199 iterator.expectArgType(DBUS_TYPE_STRING);
200 std::string result = iterator.getArgString();
202 if(m_serviceName == unit) {
203 RUNNER_ASSERT_MSG(result == "done" || result == "canceled",
204 "RemoveJob signal delivered bad news. Job wasn't completed successfully: "
205 << "expected job results = {done, canceled}, "
206 << "received job result = " << result << ", "
207 << "for job with id = " << id << ", "
208 << "and path = " << path);
209 m_runningJobs.erase(path);
213 void ServiceManager::signalJobNewHandler(DBus::MessageIn &messageIn)
215 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
217 iterator.expectArgTypeValid();
218 iterator.expectNext();
220 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
221 std::string path = iterator.getArgString();
222 iterator.expectNext();
224 iterator.expectArgType(DBUS_TYPE_STRING);
225 std::string unit = iterator.getArgString();
227 if(m_serviceName == unit)
228 m_runningJobs.insert(path);
231 void ServiceManager::signalReloadingHandler(DBus::MessageIn &messageIn)
233 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
235 iterator.expectArgType(DBUS_TYPE_BOOLEAN);
236 bool active = iterator.getArgBool();
239 m_runningJobs.insert(MATCH_RELOADING);
241 m_runningJobs.erase(MATCH_RELOADING);
244 void ServiceManager::waitForRunningJobsFinish()
246 while (!m_runningJobs.empty())
247 m_connection.readWriteDispatch();
250 void ServiceManager::startService()
252 sendToService("StartUnit");
253 waitForRunningJobsFinish();
254 sendResetFailedToService();
257 void ServiceManager::stopService()
259 sendToService("StopUnit");
260 waitForRunningJobsFinish();
261 sendResetFailedToService();
264 void ServiceManager::restartService()
266 sendToService("RestartUnit");
267 waitForRunningJobsFinish();
268 sendResetFailedToService();
271 pid_t ServiceManager::getServicePid()
273 return static_cast<pid_t>(getUIntProperty(SYSTEMD_SERVICE_INTERFACE, "MainPID"));
276 void ServiceManager::maskService()
280 waitForRunningJobsFinish();
281 sendResetFailedToService();
284 void ServiceManager::unmaskService()
286 sendUnmaskToService();
288 waitForRunningJobsFinish();
289 sendResetFailedToService();