2 * Copyright (c) 2013-2020 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>
36 const std::string DBUS_CLIENT_NAME("tests.dbus.client");
37 const std::string DBUS_PROPERTIES_INTERFACE("org.freedesktop.DBus.Properties");
38 const std::string SYSTEMD_DESTINATION("org.freedesktop.systemd1");
39 const std::string SYSTEMD_PATH("/org/freedesktop/systemd1");
40 const std::string SYSTEMD_MANAGER_INTERFACE("org.freedesktop.systemd1.Manager");
41 const std::string SYSTEMD_SERVICE_INTERFACE("org.freedesktop.systemd1.Service");
43 const std::string MATCH_JOB_REMOVED("JobRemoved");
44 const std::string MATCH_JOB_NEW("JobNew");
45 const std::string MATCH_RELOADING("Reloading");
49 ServiceManager::ServiceManager(const std::string &serviceName,
50 const std::vector<std::string>& socketsNames)
51 : m_connection(DBUS_BUS_SYSTEM, true)
52 , m_serviceName(serviceName)
53 , m_socketsNames(socketsNames)
55 addBusMatch(MATCH_JOB_REMOVED);
56 addBusMatch(MATCH_JOB_NEW);
57 addBusMatch(MATCH_RELOADING);
59 m_connection.addFilter(messageHandler,
60 static_cast<void*>(this));
62 m_connection.requestName(DBUS_CLIENT_NAME);
66 void ServiceManager::addBusMatch(const std::string &member)
68 std::ostringstream rule;
69 rule << "type='signal',"
70 << "sender='" << SYSTEMD_DESTINATION << "',"
71 << "interface='" << SYSTEMD_MANAGER_INTERFACE << "',"
72 << "member='" << member << "',"
73 << "path='" << SYSTEMD_PATH << "'";
75 m_connection.addMatch(rule.str());
78 void ServiceManager::subscribeSignals()
80 DBus::MessageOut messageOut = newMethodCall("Subscribe");
81 m_connection.sendWithReplyAndBlock(messageOut);
84 void ServiceManager::reloadDbusManager()
86 DBus::MessageOut messageOut = newMethodCall("Reload");
87 m_connection.sendWithReplyAndBlock(messageOut);
88 m_runningJobs.insert(MATCH_RELOADING);
91 void ServiceManager::getUnitPath()
93 DBus::MessageOut messageOut = newMethodCall("GetUnit");
94 messageOut.append(m_serviceName);
95 DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
96 m_unitPath = handleObjectPathMsgReply(messageIn);
99 DBus::MessageOut ServiceManager::newMethodCall(const std::string &method)
101 return DBus::MessageOut(SYSTEMD_DESTINATION,
103 SYSTEMD_MANAGER_INTERFACE,
107 std::string ServiceManager::handleObjectPathMsgReply(DBus::MessageIn &messageIn)
109 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
110 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
111 return iterator.getArgString();
114 uint32_t ServiceManager::handleVariantUIntMsgReply(DBus::MessageIn &messageIn)
116 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
117 iterator.expectArgType(DBUS_TYPE_VARIANT);
118 DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
119 iteratorSub.expectArgType(DBUS_TYPE_UINT32);
120 return iteratorSub.getArgUint32();
123 uint64_t ServiceManager::handleVariantUInt64MsgReply(DBus::MessageIn &messageIn)
125 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
126 iterator.expectArgType(DBUS_TYPE_VARIANT);
127 DBus::MessageIn::Iterator iteratorSub = iterator.recurse();
128 iteratorSub.expectArgType(DBUS_TYPE_UINT64);
129 return iteratorSub.getArgUint64();
132 void ServiceManager::sendToService(const std::string &method, const std::string &unit)
134 DBus::MessageOut messageOut = newMethodCall(method);
135 messageOut.append(unit);
136 messageOut.append("fail");
137 DBus::MessageIn messageIn = m_connection.sendWithReplyAndBlock(messageOut);
138 m_runningJobs.insert(handleObjectPathMsgReply(messageIn));
141 void ServiceManager::sendMaskToService()
143 const std::vector<std::string> mask(1, m_serviceName);
144 DBus::MessageOut messageOut = newMethodCall("MaskUnitFiles");
145 messageOut.append(mask);
146 messageOut.append(true);
147 messageOut.append(true);
148 m_connection.sendWithReplyAndBlock(messageOut);
151 void ServiceManager::sendUnmaskToService()
153 const std::vector<std::string> mask(1, m_serviceName);
154 DBus::MessageOut messageOut = newMethodCall("UnmaskUnitFiles");
155 messageOut.append(mask);
156 messageOut.append(true);
157 m_connection.sendWithReplyAndBlock(messageOut);
160 DBus::MessageIn ServiceManager::sendPropertyGetMsg(const std::string &interface,
161 const std::string &property)
163 DBus::MessageOut messageOut(SYSTEMD_DESTINATION,
165 DBUS_PROPERTIES_INTERFACE,
167 messageOut.append(interface);
168 messageOut.append(property);
169 return m_connection.sendWithReplyAndBlock(messageOut);
172 uint32_t ServiceManager::getUIntProperty(const std::string &interface,
173 const std::string &property)
175 DBus::MessageIn messageIn = sendPropertyGetMsg(interface, property);
176 return handleVariantUIntMsgReply(messageIn);
179 uint64_t ServiceManager::getUInt64Property(const std::string &interface,
180 const std::string &property)
182 DBus::MessageIn messageIn = sendPropertyGetMsg(interface, property);
183 return handleVariantUInt64MsgReply(messageIn);
186 void ServiceManager::sendResetFailedToService()
188 DBus::MessageOut messageOut = newMethodCall("ResetFailedUnit");
189 messageOut.append(m_serviceName);
190 m_connection.sendWithReplyAndBlock(messageOut);
193 DBusHandlerResult ServiceManager::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t)
196 ServiceManager* self = static_cast<ServiceManager*>(t);
198 DBus::MessageIn messageIn(msg, true);
199 if (messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_REMOVED))
200 self->signalJobRemovedHandler(messageIn);
201 else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_JOB_NEW))
202 self->signalJobNewHandler(messageIn);
203 else if(messageIn.isSignal(SYSTEMD_MANAGER_INTERFACE, MATCH_RELOADING))
204 self->signalReloadingHandler(messageIn);
206 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
209 void ServiceManager::signalJobRemovedHandler(DBus::MessageIn &messageIn)
211 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
213 iterator.expectArgType(DBUS_TYPE_UINT32);
214 uint32_t id = iterator.getArgUint32();
215 iterator.expectNext();
217 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
218 std::string path = iterator.getArgString();
219 iterator.expectNext();
221 iterator.expectArgType(DBUS_TYPE_STRING);
222 std::string unit = iterator.getArgString();
223 iterator.expectNext();
225 iterator.expectArgType(DBUS_TYPE_STRING);
226 std::string result = iterator.getArgString();
228 if (unit == m_serviceName
229 || std::count(m_socketsNames.begin(), m_socketsNames.end(), unit) > 0) {
230 RUNNER_ASSERT_MSG(result == "done" || result == "canceled",
231 "RemoveJob signal delivered bad news. Job wasn't completed successfully: "
232 << "expected job results = {done, canceled}, "
233 << "received job result = " << result << ", "
234 << "for job with id = " << id << ", "
235 << "and path = " << path);
236 m_runningJobs.erase(path);
240 void ServiceManager::signalJobNewHandler(DBus::MessageIn &messageIn)
242 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
244 iterator.expectArgTypeValid();
245 iterator.expectNext();
247 iterator.expectArgType(DBUS_TYPE_OBJECT_PATH);
248 std::string path = iterator.getArgString();
249 iterator.expectNext();
251 iterator.expectArgType(DBUS_TYPE_STRING);
252 std::string unit = iterator.getArgString();
254 if(m_serviceName == unit)
255 m_runningJobs.insert(path);
258 void ServiceManager::signalReloadingHandler(DBus::MessageIn &messageIn)
260 DBus::MessageIn::Iterator iterator = messageIn.iterInit();
262 iterator.expectArgType(DBUS_TYPE_BOOLEAN);
263 bool active = iterator.getArgBool();
266 m_runningJobs.insert(MATCH_RELOADING);
268 m_runningJobs.erase(MATCH_RELOADING);
271 void ServiceManager::waitForRunningJobsFinish()
273 while (!m_runningJobs.empty())
274 m_connection.readWriteDispatch();
277 void ServiceManager::executeMethod(const std::string &method, const std::string &unit)
279 sendToService(method, unit);
280 waitForRunningJobsFinish();
281 sendResetFailedToService();
284 void ServiceManager::startService(bool withSockets)
287 for (const auto &socket : m_socketsNames)
288 executeMethod("StartUnit", socket);
289 executeMethod("StartUnit", m_serviceName);
292 void ServiceManager::stopService(bool withSockets)
295 for (const auto &socket : m_socketsNames)
296 executeMethod("StopUnit", socket);
297 executeMethod("StopUnit", m_serviceName);
300 void ServiceManager::restartService(bool withSockets)
303 for (const auto &socket : m_socketsNames)
304 executeMethod("StopUnit", socket);
306 executeMethod("RestartUnit", m_serviceName);
309 for (const auto &socket : m_socketsNames)
310 executeMethod("StartUnit", socket);
313 pid_t ServiceManager::getServicePid()
315 return static_cast<pid_t>(getUIntProperty(SYSTEMD_SERVICE_INTERFACE, "MainPID"));
318 timeval ServiceManager::getServiceStartTimestamp() {
319 uint64_t timestamp = getUInt64Property(SYSTEMD_SERVICE_INTERFACE,
320 "ExecMainStartTimestamp");
321 return {static_cast<long>(timestamp / 1000000), static_cast<long>(timestamp % 1000000)};
324 void ServiceManager::maskService()
328 waitForRunningJobsFinish();
329 sendResetFailedToService();
332 void ServiceManager::unmaskService()
334 sendUnmaskToService();
336 waitForRunningJobsFinish();
337 sendResetFailedToService();