2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
22 * @brief Implementation of class for managing one container
27 #include "container.hpp"
28 #include "base-exception.hpp"
30 #include "logger/logger.hpp"
31 #include "utils/paths.hpp"
32 #include "config/manager.hpp"
34 #include <boost/filesystem.hpp>
40 namespace security_containers {
42 namespace fs = boost::filesystem;
46 typedef std::lock_guard<std::recursive_mutex> Lock;
48 // TODO: move constants to the config file when default values are implemented there
49 const int RECONNECT_RETRIES = 15;
50 const int RECONNECT_DELAY = 1 * 1000;
54 Container::Container(const std::string& containerConfigPath,
55 const std::string& baseRunMountPointPath)
57 config::loadFromFile(containerConfigPath, mConfig);
59 for (std::string r: mConfig.permittedToSend) {
60 mPermittedToSend.push_back(boost::regex(r));
62 for (std::string r: mConfig.permittedToRecv) {
63 mPermittedToRecv.push_back(boost::regex(r));
66 const std::string baseConfigPath = utils::dirName(containerConfigPath);
67 mConfig.config = fs::absolute(mConfig.config, baseConfigPath).string();
68 mConfig.networkConfig = fs::absolute(mConfig.networkConfig, baseConfigPath).string();
69 mConfig.networkFilterConfig = fs::absolute(mConfig.networkFilterConfig,
70 baseConfigPath).string();
71 if (!mConfig.runMountPoint.empty()) {
72 mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string();
75 LOGT("Creating Network Admin " << mConfig.networkConfig);
76 mNetworkAdmin.reset(new NetworkAdmin(mConfig));
77 LOGT("Creating Container Admin " << mConfig.config);
78 mAdmin.reset(new ContainerAdmin(mConfig));
81 Container::~Container()
83 // Make sure all OnNameLostCallbacks get finished and no new will
84 // get called before proceeding further. This guarantees no race
85 // condition on the mReconnectThread.
87 Lock lock(mReconnectMutex);
91 if (mReconnectThread.joinable()) {
92 mReconnectThread.join();
96 const std::vector<boost::regex>& Container::getPermittedToSend() const
98 return mPermittedToSend;
101 const std::vector<boost::regex>& Container::getPermittedToRecv() const
103 return mPermittedToRecv;
106 const std::string& Container::getId() const
108 Lock lock(mReconnectMutex);
109 return mAdmin->getId();
112 int Container::getPrivilege() const
114 return mConfig.privilege;
117 void Container::start()
119 Lock lock(mReconnectMutex);
120 if (mConfig.enableDbusIntegration) {
121 mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint));
123 mNetworkAdmin->start();
125 if (mConfig.enableDbusIntegration) {
129 // Send to the background only after we're connected, otherwise it'd take ages.
130 LOGD(getId() << ": sending to the background");
134 void Container::stop()
136 Lock lock(mReconnectMutex);
139 mNetworkAdmin->stop();
140 mConnectionTransport.reset();
143 void Container::connect()
145 // assume called under reconnect lock
146 mDbusAddress = mConnectionTransport->acquireAddress();
147 mConnection.reset(new ContainerConnection(mDbusAddress,
148 std::bind(&Container::onNameLostCallback, this)));
149 if (mNotifyCallback) {
150 mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
152 if (mDisplayOffCallback) {
153 mConnection->setDisplayOffCallback(mDisplayOffCallback);
155 if (mFileMoveCallback) {
156 mConnection->setFileMoveRequestCallback(mFileMoveCallback);
158 if (mProxyCallCallback) {
159 mConnection->setProxyCallCallback(mProxyCallCallback);
161 if (mDbusStateChangedCallback) {
162 mDbusStateChangedCallback(mDbusAddress);
166 void Container::disconnect()
168 // assume called under reconnect lock
171 mDbusAddress.clear();
172 if (mDbusStateChangedCallback) {
173 // notify about invalid dbusAddress for this container
174 mDbusStateChangedCallback(std::string());
179 std::string Container::getDbusAddress()
181 Lock lock(mReconnectMutex);
185 void Container::goForeground()
187 Lock lock(mReconnectMutex);
188 mAdmin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
191 void Container::goBackground()
193 Lock lock(mReconnectMutex);
194 mAdmin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
197 void Container::setDetachOnExit()
199 Lock lock(mReconnectMutex);
200 mNetworkAdmin->setDetachOnExit();
201 mAdmin->setDetachOnExit();
202 if (mConnectionTransport) {
203 mConnectionTransport->setDetachOnExit();
207 bool Container::isRunning()
209 Lock lock(mReconnectMutex);
210 return mAdmin->isRunning();
213 bool Container::isStopped()
215 Lock lock(mReconnectMutex);
216 return mAdmin->isStopped();
219 bool Container::isPaused()
221 Lock lock(mReconnectMutex);
222 return mAdmin->isPaused();
225 bool Container::isSwitchToDefaultAfterTimeoutAllowed() const
227 return mConfig.switchToDefaultAfterTimeout;
230 void Container::onNameLostCallback()
232 LOGI(getId() << ": A connection to the DBUS server has been lost, reconnecting...");
234 if (mReconnectThread.joinable()) {
235 mReconnectThread.join();
237 mReconnectThread = std::thread(std::bind(&Container::reconnectHandler, this));
240 void Container::reconnectHandler()
243 Lock lock(mReconnectMutex);
247 for (int i = 0; i < RECONNECT_RETRIES; ++i) {
248 // This sleeps even before the first try to give DBUS some time to come back up
249 std::this_thread::sleep_for(std::chrono::milliseconds(RECONNECT_DELAY));
251 Lock lock(mReconnectMutex);
253 LOGI(getId() << ": Has stopped, nothing to reconnect to, bailing out");
258 LOGT(getId() << ": Reconnect try " << i + 1);
260 LOGI(getId() << ": Reconnected");
262 } catch (SecurityContainersException&) {
263 LOGT(getId() << ": Reconnect try " << i + 1 << " has been unsuccessful");
267 LOGE(getId() << ": Reconnecting to the DBUS has failed, stopping the container");
271 void Container::setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback)
273 Lock lock(mReconnectMutex);
274 mNotifyCallback = callback;
276 mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
280 void Container::sendNotification(const std::string& container,
281 const std::string& application,
282 const std::string& message)
284 Lock lock(mReconnectMutex);
286 mConnection->sendNotification(container, application, message);
288 LOGE(getId() << ": Can't send notification, no connection to DBUS");
292 void Container::setDisplayOffCallback(const DisplayOffCallback& callback)
294 Lock lock(mReconnectMutex);
296 mDisplayOffCallback = callback;
298 mConnection->setDisplayOffCallback(callback);
302 void Container::setFileMoveRequestCallback(const FileMoveRequestCallback& callback)
304 Lock lock(mReconnectMutex);
306 mFileMoveCallback = callback;
308 mConnection->setFileMoveRequestCallback(callback);
312 void Container::setProxyCallCallback(const ProxyCallCallback& callback)
314 Lock lock(mReconnectMutex);
316 mProxyCallCallback = callback;
318 mConnection->setProxyCallCallback(callback);
322 void Container::setDbusStateChangedCallback(const DbusStateChangedCallback& callback)
324 mDbusStateChangedCallback = callback;
327 void Container::proxyCallAsync(const std::string& busName,
328 const std::string& objectPath,
329 const std::string& interface,
330 const std::string& method,
331 GVariant* parameters,
332 const dbus::DbusConnection::AsyncMethodCallCallback& callback)
334 Lock lock(mReconnectMutex);
336 mConnection->proxyCallAsync(busName,
343 LOGE(getId() << ": Can't do a proxy call, no connection to DBUS");
348 } // namespace security_containers