SET(target "contextd")
-SET(DEPS "glib-2.0 gio-2.0 dlog capi-base-common alarm-service")
+SET(DEPS "libsystemd-login glib-2.0 gio-2.0 dlog capi-base-common alarm-service")
SET(DEPS "${DEPS} context-common-server")
SET(DEPS "${DEPS} sensor-recorder-server")
SET(DEPS "${DEPS} context-store-server")
Source2: org.tizen.context.conf
BuildRequires: cmake
+BuildRequires: pkgconfig(libsystemd-login)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(dlog)
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <systemd/sd-login.h>
+#include "ActiveUserMonitor.h"
+
+#define ROOT_UID 0
+
+using namespace ctx;
+
+ActiveUserMonitor::ActiveUserMonitor() :
+ __connection(NULL),
+ __activateUser(NULL),
+ __deactivateUser(NULL),
+ __activeUid(ROOT_UID),
+ __userNewSignalId(0),
+ __userRemovedSignalId(0)
+{
+}
+
+ActiveUserMonitor::~ActiveUserMonitor()
+{
+}
+
+void ActiveUserMonitor::start(GDBusConnection* conn, uid_cb_t activateUser, uid_cb_t deactivateUser)
+{
+ __connection = conn;
+ __activateUser = activateUser;
+ __deactivateUser = deactivateUser;
+
+ __userNewSignalId = g_dbus_connection_signal_subscribe(__connection,
+ NULL, "org.freedesktop.login1.Manager", "UserNew", NULL,
+ NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserNew, this, NULL);
+
+ __userRemovedSignalId = g_dbus_connection_signal_subscribe(__connection,
+ NULL, "org.freedesktop.login1.Manager", "UserRemoved", NULL,
+ NULL, G_DBUS_SIGNAL_FLAGS_NONE, __onUserRemoved, this, NULL);
+
+ g_idle_add(__checkCurrentUser, this);
+}
+
+void ActiveUserMonitor::stop()
+{
+ g_dbus_connection_signal_unsubscribe(__connection, __userNewSignalId);
+ g_dbus_connection_signal_unsubscribe(__connection, __userRemovedSignalId);
+}
+
+void ActiveUserMonitor::__onUserNew(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, gpointer userData)
+{
+ uint32_t uid = 0;
+ g_variant_get_child(param, 0, "u", &uid);
+ IF_FAIL_VOID_TAG(uid > 0, _W, "UID == 0");
+
+ _D("UID: %u", 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;
+}
+
+void ActiveUserMonitor::__onUserRemoved(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, gpointer userData)
+{
+ uint32_t uid = 0;
+ g_variant_get_child(param, 0, "u", &uid);
+ 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;
+}
+
+gboolean ActiveUserMonitor::__checkCurrentUser(gpointer userData)
+{
+ ActiveUserMonitor* monitor = static_cast<ActiveUserMonitor*>(userData);
+ IF_FAIL_RETURN(monitor->__activeUid == ROOT_UID, G_SOURCE_REMOVE);
+
+ uid_t* users = NULL;
+ int numUsers = sd_get_active_uids(&users);
+
+ if (numUsers > 0)
+ monitor->__activeUid = users[0];
+
+ g_free(users);
+
+ if (monitor->__activeUid != ROOT_UID) {
+ _D("UID: %u", monitor->__activeUid);
+ monitor->__activateUser(monitor->__activeUid);
+ }
+
+ return G_SOURCE_REMOVE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_ACTIVE_USER_MONITOR_H__
+#define __CONTEXT_ACTIVE_USER_MONITOR_H__
+
+#include <ContextTypes.h>
+
+namespace ctx {
+
+ class ActiveUserMonitor {
+
+ typedef void (*uid_cb_t)(uid_t);
+
+ public:
+ ActiveUserMonitor();
+ ~ActiveUserMonitor();
+
+ void start(GDBusConnection* conn, uid_cb_t activateUser, uid_cb_t deactivateUser);
+ void stop();
+
+ private:
+ static void __onUserNew(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, gpointer userData);
+
+ static void __onUserRemoved(GDBusConnection* conn, const gchar* sender,
+ const gchar* path, const gchar* iface, const gchar* name,
+ GVariant* param, gpointer userData);
+
+ static gboolean __checkCurrentUser(gpointer userData);
+
+ GDBusConnection* __connection;
+ uid_cb_t __activateUser;
+ uid_cb_t __deactivateUser;
+ uid_t __activeUid;
+ guint __userNewSignalId;
+ guint __userRemovedSignalId;
+ };
+
+}
+
+#endif
#include <Timer.h>
#include "DBusConnector.h"
#include "ServiceLoader.h"
+#include "ActiveUserMonitor.h"
#include "AlarmInitializer.h"
using namespace ctx;
namespace {
- class Server {
+ class MainLoop {
public:
static bool start();
static void stop();
private:
- Server() {}
+ MainLoop() {}
static GMainLoop* __mainLoop;
};
}
-static gboolean __stopService(gpointer data)
-{
- _I("Unloading services");
- ServiceLoader::unload();
- ::Server::stop();
- return G_SOURCE_REMOVE;
-}
+GMainLoop* MainLoop::__mainLoop = NULL;
-GMainLoop* ::Server::__mainLoop = NULL;
-
-bool ::Server::start()
+bool MainLoop::start()
{
__mainLoop = g_main_loop_new(NULL, FALSE);
IF_FAIL_RETURN_TAG(__mainLoop, false, _E, "Memory allocation failed");
return true;
}
-void ::Server::stop()
+void MainLoop::stop()
{
_I(PURPLE("Terminating..."));
g_main_loop_quit(__mainLoop);
}
+static ServiceLoader __serviceLoader;
+static ActiveUserMonitor __activeUserMonitor;
static AlarmInitializer __alarmInit;
-static void __signalHandler(int signum)
+static void __activateUser(uid_t uid)
{
- _I(YELLOW("SIGNAL-%d: '%s'"), signum, strsignal(signum));
- static bool terminated = false;
- if (!terminated) {
- g_idle_add(__stopService, NULL);
- terminated = true;
- }
+ __serviceLoader.startUser(uid);
}
-static void __busAcquired(GDBusConnection* conn)
+static void __deactivateUser(uid_t uid)
+{
+ __serviceLoader.stopUser();
+}
+
+static void __startService(GDBusConnection* conn)
{
Timer::setDBusConnection(conn);
+ __activeUserMonitor.start(conn, __activateUser, __deactivateUser);
_I("Loading services");
- if (ServiceLoader::load(conn)) {
- _I("Service loading successful");
+ if (!__serviceLoader.load(conn)) {
+ _E(RED("No service loaded"));
return;
}
- _E(RED("No service loaded."));
+ _I("Service loading successful");
+ __serviceLoader.startSystem();
+}
+
+static gboolean __stopService(gpointer data)
+{
+ __activeUserMonitor.stop();
+
+ _I("Unloading services");
+ __serviceLoader.stopUser();
+ __serviceLoader.stopSystem();
+
+ MainLoop::stop();
+ return G_SOURCE_REMOVE;
+}
+
+static void __busAcquired(GDBusConnection* conn)
+{
+ __startService(conn);
}
static void __busLost(GDBusConnection* conn)
__stopService(NULL);
}
+static void __signalHandler(int signum)
+{
+ _I(YELLOW("SIGNAL-%d: '%s'"), signum, strsignal(signum));
+ static bool terminated = false;
+ if (!terminated) {
+ g_idle_add(__stopService, NULL);
+ terminated = true;
+ }
+}
+
int main(int argc, char* argv[])
{
static struct sigaction signalAction;
DBusConnector dbusConnector(__busAcquired, __busLost);
- ::Server::start();
+ MainLoop::start();
return EXIT_SUCCESS;
}
#include "ServiceLoader.h"
+#define ROOT_UID 0
+
using namespace ctx;
-std::vector<ServiceBase*> ServiceLoader::__services;
+ServiceLoader::ServiceLoader() :
+ __activeUser(ROOT_UID)
+{
+}
-ServiceLoader::ServiceLoader()
+ServiceLoader::~ServiceLoader()
{
+ for (auto& svc : __userServices) {
+ delete svc;
+ }
+ for (auto& svc : __systemServices) {
+ delete svc;
+ }
}
bool ServiceLoader::load(GDBusConnection* conn)
__create<ContextStoreService>(conn);
//__create<JobSchedulerService>(conn);
- if (__services.size() == 1) {
+ if ((__userServices.size() + __systemServices.size()) == 1) {
_I("Switch to single-threading");
ServiceBase::setSingleThreading();
}
- for (auto& svc : __services) {
- if (!svc->start())
- return false;
+ return (!__systemServices.empty() || !__userServices.empty());
+}
+
+void ServiceLoader::startSystem()
+{
+ for (auto& svc : __systemServices) {
+ svc->start();
}
+}
- return !__services.empty();
+void ServiceLoader::stopSystem()
+{
+ for (auto& svc : __systemServices) {
+ svc->stop();
+ }
}
-void ServiceLoader::unload()
+void ServiceLoader::startUser(uid_t uid)
{
- for (auto& svc : __services) {
+ IF_FAIL_VOID(__activeUser != uid);
+ _I("Starting services for %u", static_cast<unsigned int>(uid));
+
+ ServiceBase::setActiveUser(uid);
+
+ for (auto& svc : __userServices) {
+ svc->start();
+ }
+
+ for (auto& svc : __systemServices) {
+ svc->notifyUserNew();
+ }
+
+ __activeUser = uid;
+}
+
+void ServiceLoader::stopUser()
+{
+ IF_FAIL_VOID(__activeUser != ROOT_UID);
+ _I("Stopping services for %u", static_cast<unsigned int>(__activeUser));
+
+ for (auto& svc : __userServices) {
svc->stop();
- delete svc;
}
- __services.clear();
+
+ ServiceBase::setActiveUser(ROOT_UID);
+
+ for (auto& svc : __systemServices) {
+ svc->notifyUserRemoved();
+ }
+
+ __activeUser = ROOT_UID;
}
class ServiceLoader {
public:
- static bool load(GDBusConnection* conn);
- static void unload();
-
- private:
ServiceLoader();
+ ~ServiceLoader();
+
+ bool load(GDBusConnection* conn);
- static std::vector<ServiceBase*> __services;
+ void startUser(uid_t uid);
+ void stopUser();
+ void startSystem();
+ void stopSystem();
- template<typename ServiceType> static void __create(GDBusConnection* conn)
+ private:
+ uid_t __activeUser;
+ std::vector<ServiceBase*> __userServices;
+ std::vector<ServiceBase*> __systemServices;
+
+ template<typename ServiceType> void __create(GDBusConnection* conn)
{
ServiceBase *svc = NULL;
try {
_W("Service creation failed (%s)", e.what());
return;
}
- __services.push_back(svc);
+ if (svc->isUserService()) {
+ __userServices.push_back(svc);
+ } else {
+ __systemServices.push_back(svc);
+ }
}
};