#include <systemd/sd-login.h>
#include <ServerUtil.h>
+#include "ServiceLoader.h"
#include "ActiveUserMonitor.h"
#define ROOT_UID 0
using namespace ctx;
-ActiveUserMonitor::ActiveUserMonitor() :
+ActiveUserMonitor::ActiveUserMonitor(ServiceLoader* svcLoader) :
+ __serviceLoader(svcLoader),
__connection(NULL),
- __activateUser(NULL),
- __deactivateUser(NULL),
- __activeUid(ROOT_UID),
__userNewSignalId(0),
__userRemovedSignalId(0),
__newClientSignalId(0)
{
}
-void ActiveUserMonitor::start(GDBusConnection* conn, uid_cb_t activateUser, uid_cb_t deactivateUser)
+void ActiveUserMonitor::start(GDBusConnection* conn)
{
__connection = conn;
- __activateUser = activateUser;
- __deactivateUser = deactivateUser;
__userNewSignalId = g_dbus_connection_signal_subscribe(__connection,
NULL, "org.freedesktop.systemd1.Manager", "UserSessionStartupFinished", NULL,
const gchar* path, const gchar* iface, const gchar* name,
GVariant* param, gpointer userData)
{
- uint32_t uid = 0;
- guint64 uid64 = 0;
-
- g_variant_get_child(param, 0, "t", &uid64);
- uid = static_cast<uint32_t>(uid64);
+ guint64 uid = 0;
+ g_variant_get_child(param, 0, "t", &uid);
+ IF_FAIL_VOID_TAG(uid != 0, _W, "UID == 0");
- IF_FAIL_VOID_TAG(uid > 0, _W, "UID == 0");
-
- _D("UID: %u", uid);
+ _D("UID: %llu", uid);
- ActiveUserMonitor* monitor = static_cast<ActiveUserMonitor*>(userData);
-
- if (monitor->__activeUid == uid)
- return;
-
- if (monitor->__activeUid > ROOT_UID) {
- _W("Over-activation of the user %u", uid);
- monitor->__deactivateUser(monitor->__activeUid);
- }
-
- monitor->__activateUser(uid);
- monitor->__activeUid = uid;
+ static_cast<ActiveUserMonitor*>(userData)->__add(static_cast<uid_t>(uid));
}
void ActiveUserMonitor::__onUserRemoved(GDBusConnection* conn, const gchar* sender,
{
uint32_t uid = 0;
g_variant_get_child(param, 0, "u", &uid);
- IF_FAIL_VOID_TAG(uid > 0, _W, "UID == 0");
+ IF_FAIL_VOID_TAG(uid != 0, _W, "UID == 0");
_D("UID: %u", uid);
- ActiveUserMonitor* monitor = static_cast<ActiveUserMonitor*>(userData);
-
- if (monitor->__activeUid == ROOT_UID) {
- _W("No active user");
- return;
- }
-
- if (monitor->__activeUid != uid) {
- _W("Mismatched uid");
- }
-
- monitor->__deactivateUser(uid);
- monitor->__activeUid = ROOT_UID;
+ static_cast<ActiveUserMonitor*>(userData)->__remove(static_cast<uid_t>(uid));
}
void ActiveUserMonitor::__onNewClient(GDBusConnection* conn, const gchar* sender,
const gchar* path, const gchar* iface, const gchar* name,
GVariant* param, gpointer userData)
{
- _D(GREEN("A new ServiceProxy signaled"));
+ _D(GREEN("A new ServiceProxy(%s) has been created."), sender);
ActiveUserMonitor* monitor = static_cast<ActiveUserMonitor*>(userData);
- IF_FAIL_VOID(monitor->__activeUid == ROOT_UID);
+ IF_FAIL_VOID(monitor->__uids.empty());
uid_t* users = NULL;
- int numUsers = sd_get_active_uids(&users);
- IF_FAIL_VOID(numUsers > 0);
+ int numUsers = sd_get_uids(&users);
+
+ for (int i = 0; i < numUsers; ++i) {
+ monitor->__add(users[i]);
+ }
- uid_t activeUid = users[0];
g_free(users);
+}
- IF_FAIL_VOID(activeUid != ROOT_UID);
+void ActiveUserMonitor::__add(uid_t uid)
+{
+ if (__uids.find(uid) != __uids.end())
+ return;
+
+ __serviceLoader->startUser(uid);
+ __serviceLoader->notifyUserNew(uid);
+ __uids.insert(uid);
+}
- _D("UID: %u", monitor->__activeUid);
+void ActiveUserMonitor::__remove(uid_t uid)
+{
+ if (__uids.find(uid) == __uids.end())
+ return;
- monitor->__activeUid = activeUid;
- monitor->__activateUser(activeUid);
+ __serviceLoader->stopUser(uid);
+ __serviceLoader->notifyUserRemoved(uid);
+ __uids.erase(uid);
}
#ifndef __CONTEXT_ACTIVE_USER_MONITOR_H__
#define __CONTEXT_ACTIVE_USER_MONITOR_H__
+#include <set>
#include <ContextTypes.h>
namespace ctx {
- class ActiveUserMonitor {
-
- typedef void (*uid_cb_t)(uid_t);
+ class ServiceLoader;
+ class ActiveUserMonitor {
public:
- ActiveUserMonitor();
+ ActiveUserMonitor(ServiceLoader* svcLoader);
~ActiveUserMonitor();
- void start(GDBusConnection* conn, uid_cb_t activateUser, uid_cb_t deactivateUser);
+ void start(GDBusConnection* conn);
void stop();
private:
const gchar* path, const gchar* iface, const gchar* name,
GVariant* param, gpointer userData);
+ void __add(uid_t uid);
+ void __remove(uid_t uid);
+
+ ServiceLoader* __serviceLoader;
GDBusConnection* __connection;
- uid_cb_t __activateUser;
- uid_cb_t __deactivateUser;
- uid_t __activeUid;
+
guint __userNewSignalId;
guint __userRemovedSignalId;
guint __newClientSignalId;
+
+ std::set<uid_t> __uids;
};
}
bool Credential::isSystem() const
{
- return util::isSystemUid(__uid);
+ return util::isSystem(__uid);
}
}
static ServiceLoader __serviceLoader;
-static ActiveUserMonitor __activeUserMonitor;
+static ActiveUserMonitor __activeUserMonitor(&__serviceLoader);
static AlarmInitializer __alarmInit;
-static void __activateUser(uid_t uid)
-{
- __serviceLoader.startUser(uid);
-}
-
-static void __deactivateUser(uid_t uid)
-{
- __serviceLoader.stopUser();
-}
-
static void __startService(GDBusConnection* conn)
{
- __activeUserMonitor.start(conn, __activateUser, __deactivateUser);
+ __activeUserMonitor.start(conn);
_I("Loading services");
if (!__serviceLoader.load(conn)) {
__activeUserMonitor.stop();
_I("Unloading services");
- __serviceLoader.stopUser();
- __serviceLoader.stopSystem();
+ __serviceLoader.stopAll();
MainLoop::stop();
return G_SOURCE_REMOVE;
#include "ServiceLoader.h"
-#define ROOT_UID 0
-
using namespace ctx;
-ServiceLoader::ServiceLoader() :
- __activeUser(ROOT_UID)
+ServiceLoader::ServiceLoader()
{
}
}
}
+template<typename ServiceType>
+void ServiceLoader::__create(GDBusConnection* conn)
+{
+ IService* svc = NULL;
+
+ try {
+ svc = new ServiceType();
+ } catch (const std::runtime_error& e) {
+ _I(YELLOW("%s"), e.what());
+ return;
+ }
+
+ ServiceRunner* runner = NULL;
+
+ if (dynamic_cast<IUserService*>(svc)) {
+ runner = new UserServiceRunner(conn, svc);
+ __userServices.push_back(runner);
+ } else {
+ runner = new SystemServiceRunner(conn, svc);
+ __systemServices.push_back(runner);
+ }
+
+ svc->setServiceRunner(runner);
+}
+
bool ServiceLoader::load(GDBusConnection* conn)
{
__create<ContextStoreService>(conn);
void ServiceLoader::startUser(uid_t uid)
{
- IF_FAIL_VOID(__activeUser != uid);
- _I("Starting services for %u", static_cast<unsigned int>(uid));
-
- util::setActiveUid(uid);
-
- for (auto& runner : __userServices) {
- runner->start();
+ if (util::isNormalUser(uid)) {
+ for (auto& runner : __userServices) {
+ runner->stop();
+ runner->start(uid);
+ }
}
+}
- for (auto& runner : __systemServices) {
- runner->notifyUserNew();
+void ServiceLoader::stopUser(uid_t uid)
+{
+ if (util::isNormalUser(uid)) {
+ for (auto& runner : __userServices) {
+ runner->stop();
+ }
}
- __activeUser = uid;
}
-void ServiceLoader::stopUser()
+void ServiceLoader::stopAll()
{
- IF_FAIL_VOID(__activeUser != ROOT_UID);
- _I("Stopping services for %u", static_cast<unsigned int>(__activeUser));
-
for (auto& runner : __userServices) {
runner->stop();
}
- util::setActiveUid(ROOT_UID);
+ for (auto& runner : __systemServices) {
+ runner->stop();
+ }
+}
+void ServiceLoader::notifyUserNew(uid_t uid)
+{
for (auto& runner : __systemServices) {
- runner->notifyUserRemoved();
+ runner->notifyUserNew(uid);
}
+}
- __activeUser = ROOT_UID;
+void ServiceLoader::notifyUserRemoved(uid_t uid)
+{
+ for (auto& runner : __systemServices) {
+ runner->notifyUserRemoved(uid);
+ }
}
#include <vector>
#include <ContextTypes.h>
#include <IService.h>
+#include <IUserService.h>
#include "ServiceRunner.h"
#include "ServiceClient.h"
bool load(GDBusConnection* conn);
- void startUser(uid_t uid);
- void stopUser();
void startSystem();
void stopSystem();
- private:
- uid_t __activeUser;
- std::vector<ServiceRunner*> __userServices;
- std::vector<ServiceRunner*> __systemServices;
+ void startUser(uid_t uid);
+ void stopUser(uid_t uid);
- template<typename ServiceType> void __create(GDBusConnection* conn)
- {
- IService* svc = NULL;
+ void stopAll();
- try {
- svc = new ServiceType();
- } catch (const std::runtime_error& e) {
- _I(YELLOW("%s"), e.what());
- return;
- }
+ void notifyUserNew(uid_t uid);
+ void notifyUserRemoved(uid_t uid);
- ServiceRunner* runner = new ServiceRunner(conn, svc);
- svc->setServiceRunner(runner);
+ private:
+ std::vector<ServiceRunner*> __userServices;
+ std::vector<ServiceRunner*> __systemServices;
- if (svc->isUserService()) {
- __userServices.push_back(runner);
- } else {
- __systemServices.push_back(runner);
- }
- }
+ template<typename ServiceType> void __create(GDBusConnection* conn);
};
}
* limitations under the License.
*/
-#include <ScopeMutex.h>
+#include <ServerUtil.h>
+#include <SharedUtil.h>
+#include <ISystemService.h>
+#include <IUserService.h>
#include "MethodCall.h"
#include "ServiceClient.h"
#include "ServiceRunner.h"
using namespace ctx;
ServiceRunner::ServiceRunner(GDBusConnection* conn, IService* service) :
- __service(service),
- __started(false),
+ serviceInstance(service),
+ started(false),
+ __uid(0),
__connection(conn),
__objPath(CTX_DBUS_PATH "/"),
__interface(CTX_DBUS_IFACE "."),
__nodeInfo(NULL),
__registrationId(0)
{
- __objPath += __service->getServiceName();
- __interface += __service->getServiceName();
+ __objPath += serviceInstance->getServiceName();
+ __interface += serviceInstance->getServiceName();
}
ServiceRunner::~ServiceRunner()
IService* ServiceRunner::getService()
{
- return __service;
+ return serviceInstance;
}
-bool ServiceRunner::start()
+bool ServiceRunner::start(uid_t uid)
{
- IF_FAIL_RETURN(!__started, true);
+ IF_FAIL_RETURN(!started, true);
- _I(CYAN("Starting '%s'"), __service->getServiceName());
+ _I(CYAN("Starting '%s'"), serviceInstance->getServiceName());
- if (!__init()) {
+ if (!__init(uid)) {
_E("Starting failed");
- __release();
+ __release(uid);
return false;
}
- __started = true;
+ started = true;
+ __uid = uid;
return true;
}
void ServiceRunner::stop()
{
- IF_FAIL_VOID(__started);
- __started = false;
+ IF_FAIL_VOID(started);
+ started = false;
- _I(PURPLE("Stopping '%s'"), __service->getServiceName());
+ _I(PURPLE("Stopping '%s'"), serviceInstance->getServiceName());
- __release();
+ __release(__uid);
}
void ServiceRunner::publish(const std::string& busName, const std::string& signalName, GVariant* param)
HANDLE_GERROR(gerr);
}
-void ServiceRunner::notifyUserNew()
-{
- if (__started)
- __service->onUserActivated();
-}
-
-void ServiceRunner::notifyUserRemoved()
-{
- if (__started)
- __service->onUserDeactivated();
-}
-
-bool ServiceRunner::__init()
+bool ServiceRunner::__init(uid_t uid)
{
GError* gerr = NULL;
GDBusInterfaceVTable vtable;
vtable.set_property = NULL;
std::string introspection("<node><interface name='");
- introspection += __interface + "'>" + __service->getMethodSpecs() + "</interface></node>";
+ introspection += __interface + "'>" + serviceInstance->getMethodSpecs() + "</interface></node>";
__nodeInfo = g_dbus_node_info_new_for_xml(introspection.c_str(), NULL);
IF_FAIL_RETURN_TAG(__nodeInfo, false, _E, "NodeInfo creation failed");
HANDLE_GERROR(gerr);
IF_FAIL_RETURN_TAG(__registrationId > 0, false, _E, "Object registration failed");
- return __service->prepare();
+ return __prepare(uid);
}
-void ServiceRunner::__release()
+void ServiceRunner::__release(uid_t uid)
{
for (auto iter = __clients.begin(); iter != __clients.end(); ++iter) {
iter->second.client->onDisconnected();
__clients.clear();
- __service->cleanup();
+ __cleanup(uid);
if (__registrationId > 0)
g_dbus_connection_unregister_object(__connection, __registrationId);
GVariant* param, GDBusMethodInvocation* invocation, gpointer userData)
{
ServiceRunner* runner = static_cast<ServiceRunner*>(userData);
- runner->__onMethodCalled(sender, name, param, invocation);
-}
-void ServiceRunner::__onMethodCalled(const std::string& sender,
- const std::string& name, GVariant* param, GDBusMethodInvocation* invocation)
-{
- _I("'%s' called '%s.%s'", sender.c_str(), __service->getServiceName(), name.c_str());
+ _I("'%s' called '%s.%s'", sender, iface, name);
- ServiceClient* client = __getClient(sender);
- IF_FAIL_VOID(client);
+ ServiceClient* client = runner->__getClient(sender);
+ if (!client) {
+ g_dbus_method_invocation_return_error_literal(invocation, CTX_ERROR_DOMAIN, E_SUPPORT, "");
+ return;
+ }
client->onMethodCalled(new MethodCall(client, name, param, invocation));
}
if (iter != __clients.end())
return iter->second.client;
- ServiceClient* client = new ServiceClient(this, busName);
- if (!client->isVerified()) {
- delete client;
- return NULL;
- }
+ ServiceClient* client = __createClient(busName);
+ IF_FAIL_RETURN(client, NULL);
- IMethodCallHandler* callHandler = __service->createMethodCallHandler(client);
+ IMethodCallHandler* callHandler = serviceInstance->createMethodCallHandler(client);
if (!callHandler) {
- _E("This cannot be NULL.");
+ _E("%s's method call handler cannot be NULL.", serviceInstance->getServiceName());
delete client;
return NULL;
}
void ServiceRunner::__removeClient(const std::string& busName)
{
- _I("'%s' lost '%s'", __service->getServiceName(), busName.c_str());
+ _I("'%s' lost '%s'", serviceInstance->getServiceName(), busName.c_str());
auto iter = __clients.find(busName);
IF_FAIL_VOID(iter != __clients.end());
{
g_dbus_connection_signal_unsubscribe(__connection, watchId);
}
+
+
+SystemServiceRunner::SystemServiceRunner(GDBusConnection* conn, IService* service) :
+ ServiceRunner(conn, service)
+{
+}
+
+void SystemServiceRunner::notifyUserNew(uid_t uid)
+{
+ if (started)
+ static_cast<ISystemService*>(serviceInstance)->onUserActivated(uid);
+}
+
+void SystemServiceRunner::notifyUserRemoved(uid_t uid)
+{
+ if (started)
+ static_cast<ISystemService*>(serviceInstance)->onUserDeactivated(uid);
+}
+
+bool SystemServiceRunner::__prepare(uid_t uid)
+{
+ return static_cast<ISystemService*>(serviceInstance)->prepare();
+}
+
+void SystemServiceRunner::__cleanup(uid_t uid)
+{
+ static_cast<ISystemService*>(serviceInstance)->cleanup();
+}
+
+ServiceClient* SystemServiceRunner::__createClient(const std::string& busName)
+{
+ ServiceClient* client = new ServiceClient(this, busName);
+
+ if (!client->isVerified()) {
+ delete client;
+ return NULL;
+ }
+
+ return client;
+}
+
+UserServiceRunner::UserServiceRunner(GDBusConnection* conn, IService* service) :
+ ServiceRunner(conn, service)
+{
+}
+
+void UserServiceRunner::notifyUserNew(uid_t uid)
+{
+}
+
+void UserServiceRunner::notifyUserRemoved(uid_t uid)
+{
+}
+
+bool UserServiceRunner::__prepare(uid_t uid)
+{
+ return static_cast<IUserService*>(serviceInstance)->prepare(uid);
+}
+
+void UserServiceRunner::__cleanup(uid_t uid)
+{
+ static_cast<IUserService*>(serviceInstance)->cleanup(uid);
+}
+
+ServiceClient* UserServiceRunner::__createClient(const std::string& busName)
+{
+ ServiceClient* client = new ServiceClient(this, busName);
+
+ if (!client->isVerified()) {
+ delete client;
+ return NULL;
+ }
+
+ if (!util::isNormalUser(client->getUid())) {
+ _W("%s does not support container users.", serviceInstance->getServiceName());
+ delete client;
+ return NULL;
+ }
+
+ return client;
+}
class ServiceRunner : public IServiceRunner {
public:
- ServiceRunner(GDBusConnection* conn, IService* service);
- ~ServiceRunner();
+ virtual ~ServiceRunner();
- bool start();
- void stop();
+ virtual void notifyUserNew(uid_t uid) = 0;
+ virtual void notifyUserRemoved(uid_t uid) = 0;
- void notifyUserNew();
- void notifyUserRemoved();
+ bool start(uid_t uid = 0);
+ void stop();
void publish(const std::string& busName, const std::string& signalName, GVariant* param);
GDBusConnection* getConnection();
IService* getService();
+ protected:
+ ServiceRunner(GDBusConnection* conn, IService* service);
+
+ IService* serviceInstance;
+ bool started;
+
private:
static void __onMethodCalled(GDBusConnection* conn, const gchar* sender,
const gchar* path, const gchar* iface, const gchar* name,
const gchar* path, const gchar* iface, const gchar* name,
GVariant* param, gpointer userData);
- void __onMethodCalled(const std::string& sender,
- const std::string& name, GVariant* param, GDBusMethodInvocation* invocation);
+ virtual bool __prepare(uid_t uid) = 0;
+ virtual void __cleanup(uid_t uid) = 0;
- bool __init();
- void __release();
+ virtual ServiceClient* __createClient(const std::string& busName) = 0;
+
+ bool __init(uid_t uid);
+ void __release(uid_t uid);
ServiceClient* __getClient(const std::string& busName);
void __removeClient(const std::string& busName);
unsigned int __watch(const std::string& busName, ServiceClient* client);
void __unwatch(unsigned int watchId);
- IService* __service;
- bool __started;
+ uid_t __uid;
GDBusConnection* __connection;
std::string __objPath;
std::map<std::string, __ClientInfo> __clients;
};
+
+ class SystemServiceRunner : public ServiceRunner {
+ public:
+ SystemServiceRunner(GDBusConnection* conn, IService* service);
+
+ void notifyUserNew(uid_t uid);
+ void notifyUserRemoved(uid_t uid);
+
+ private:
+ bool __prepare(uid_t uid);
+ void __cleanup(uid_t uid);
+
+ ServiceClient* __createClient(const std::string& busName);
+ };
+
+
+ class UserServiceRunner : public ServiceRunner {
+ public:
+ UserServiceRunner(GDBusConnection* conn, IService* service);
+
+ void notifyUserNew(uid_t uid);
+ void notifyUserRemoved(uid_t uid);
+
+ private:
+ bool __prepare(uid_t uid);
+ void __cleanup(uid_t uid);
+
+ ServiceClient* __createClient(const std::string& busName);
+ };
+
}
#endif /* __CONTEXT_SERVICE_RUNNER_H__ */