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 uint64_t ServiceManager::handleVariantUInt64MsgReply(DBus::MessageIn &messageIn)
122 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
123 iterator.expectArgType(DBUS_TYPE_VARIANT);
124 DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
125 iteratorSub.expectArgType(DBUS_TYPE_UINT64);
126 return iteratorSub.getArgUint64();
129 void ServiceManager::sendToService(const std::string &method)
131 DBus::MessageOut messageOut = newMethodCall(method);
132 messageOut.append(m_serviceName);
133 messageOut.append("fail");
134 DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
135 m_runningJobs.insert(handleObjectPathMsgReply(messageIn));
138 void ServiceManager::sendMaskToService()
140 const std::vector<std::string> mask(1, m_serviceName);
141 DBus::MessageOut messageOut = newMethodCall("MaskUnitFiles");
142 messageOut.append(mask);
143 messageOut.append(true);
144 messageOut.append(true);
145 m_connection.sendWithReplyAndBlock(messageOut);
148 void ServiceManager::sendUnmaskToService()
150 const std::vector<std::string> mask(1, m_serviceName);
151 DBus::MessageOut messageOut = newMethodCall("UnmaskUnitFiles");
152 messageOut.append(mask);
153 messageOut.append(true);
154 m_connection.sendWithReplyAndBlock(messageOut);
157 DBus::MessageIn ServiceManager::sendPropertyGetMsg(const std::string &interface,
158 const std::string &property)
160 DBus::MessageOut messageOut(SYSTEMD_DESTINATION,
162 DBUS_PROPERTIES_INTERFACE,
164 messageOut.append(interface);
165 messageOut.append(property);
166 return m_connection.sendWithReplyAndBlock(messageOut);
169 uint32_t ServiceManager::getUIntProperty(const std::string &interface,
170 const std::string &property)
172 DBus::MessageIn messageIn = sendPropertyGetMsg(interface, property);
173 return handleVariantUIntMsgReply(messageIn);
176 uint64_t ServiceManager::getUInt64Property(const std::string &interface,
177 const std::string &property)
179 DBus::MessageIn messageIn = sendPropertyGetMsg(interface, property);
180 return handleVariantUInt64MsgReply(messageIn);
183 void ServiceManager::sendResetFailedToService()
185 DBus::MessageOut messageOut = newMethodCall("ResetFailedUnit");
186 messageOut.append(m_serviceName);
187 m_connection.sendWithReplyAndBlock(messageOut);
190 DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t)
193 ServiceManager* self = reinterpret_cast<ServiceManager*>(t);
195 DBus::MessageIn messageIn(msg, true);
196 if (messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_REMOVED))
197 self->signalJobRemovedHandler(messageIn);
198 else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_NEW))
199 self->signalJobNewHandler(messageIn);
200 else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_RELOADING))
201 self->signalReloadingHandler(messageIn);
203 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
206 void ServiceManager::signalJobRemovedHandler(DBus::MessageIn &messageIn)
208 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
210 iterator.expectArgType(DBUS_TYPE_UINT32);
211 uint32_t id = iterator.getArgUint32();
212 iterator.expectNext();
214 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
215 std::string path = iterator.getArgString();
216 iterator.expectNext();
218 iterator.expectArgType(DBUS_TYPE_STRING);
219 std::string unit = iterator.getArgString();
220 iterator.expectNext();
222 iterator.expectArgType(DBUS_TYPE_STRING);
223 std::string result = iterator.getArgString();
225 if(m_serviceName == unit) {
226 RUNNER_ASSERT_MSG(result == "done" || result == "canceled",
227 "RemoveJob signal delivered bad news. Job wasn't completed successfully: "
228 << "expected job results = {done, canceled}, "
229 << "received job result = " << result << ", "
230 << "for job with id = " << id << ", "
231 << "and path = " << path);
232 m_runningJobs.erase(path);
236 void ServiceManager::signalJobNewHandler(DBus::MessageIn &messageIn)
238 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
240 iterator.expectArgTypeValid();
241 iterator.expectNext();
243 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
244 std::string path = iterator.getArgString();
245 iterator.expectNext();
247 iterator.expectArgType(DBUS_TYPE_STRING);
248 std::string unit = iterator.getArgString();
250 if(m_serviceName == unit)
251 m_runningJobs.insert(path);
254 void ServiceManager::signalReloadingHandler(DBus::MessageIn &messageIn)
256 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
258 iterator.expectArgType(DBUS_TYPE_BOOLEAN);
259 bool active = iterator.getArgBool();
262 m_runningJobs.insert(MATCH_RELOADING);
264 m_runningJobs.erase(MATCH_RELOADING);
267 void ServiceManager::waitForRunningJobsFinish()
269 while (!m_runningJobs.empty())
270 m_connection.readWriteDispatch();
273 void ServiceManager::startService()
275 sendToService("StartUnit");
276 waitForRunningJobsFinish();
277 sendResetFailedToService();
280 void ServiceManager::stopService()
282 sendToService("StopUnit");
283 waitForRunningJobsFinish();
284 sendResetFailedToService();
287 void ServiceManager::restartService()
289 sendToService("RestartUnit");
290 waitForRunningJobsFinish();
291 sendResetFailedToService();
294 pid_t ServiceManager::getServicePid()
296 return static_cast<pid_t>(getUIntProperty(SYSTEMD_SERVICE_INTERFACE, "MainPID"));
299 timeval ServiceManager::getServiceStartTimestamp() {
300 uint64_t timestamp = getUInt64Property(SYSTEMD_SERVICE_INTERFACE,
301 "ExecMainStartTimestamp");
302 return {static_cast<long>(timestamp / 1000000), static_cast<long>(timestamp % 1000000)};
305 void ServiceManager::maskService()
309 waitForRunningJobsFinish();
310 sendResetFailedToService();
313 void ServiceManager::unmaskService()
315 sendUnmaskToService();
317 waitForRunningJobsFinish();
318 sendResetFailedToService();