Change subsession_id type to std::string{,_view} 67/276967/18
authorMateusz Majewski <m.majewski2@samsung.com>
Tue, 28 Jun 2022 11:30:45 +0000 (13:30 +0200)
committerArkadiusz Nowak <a.nowak3@samsung.com>
Thu, 7 Jul 2022 10:59:21 +0000 (12:59 +0200)
Co-authored-by: Adam Michalski <a.michalski2@partner.samsung.com>
Change-Id: Ie5d645b9172d7423f40b74c5b92c44ac106b8c1e

doc/sessiond-dbus-interface.md
libsessiond/include/sessiond.h
sessiond/src/fs_helpers.cpp
sessiond/src/fs_helpers.h
sessiond/src/globals.hpp
sessiond/src/main.cpp

index aba79c0..6ffed2d 100644 (file)
@@ -15,27 +15,27 @@ In case of an error, methods return a DBus error.
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: AddUser
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32> in
-            subsession_id <int32> in
+            subsession_id <string> in
 
 2. Remove a user from the subsession:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: RemoveUser
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32> in
-            subsession_id <int32> in
+            subsession_id <string> in
 
 3. Switch the subsession user:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: SwitchUser
-        parameters: (iii)
+        parameters: (is)
             session_uid <int32> in
-            next_subsession_id <int32> in
+            next_subsession_id <string> in
 
 4. Register to wait for user add operation:
 
@@ -66,18 +66,18 @@ In case of an error, methods return a DBus error.
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: AddUserDone
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32> in
-            subsession_id <int32> in
+            subsession_id <string> in
 
 8. Mark user remove callback as done:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: RemoveUserDone
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32> in
-            subsession_id <int32> in
+            subsession_id <string> in
 
 9. Mark user switch callback as done:
 
@@ -93,9 +93,9 @@ In case of an error, methods return a DBus error.
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: GetUserList
-        parameters: (i) -> (ai)
+        parameters: (i) -> (as)
             session_uid <int32> in
-            subsession_id_list <array<int32>> out
+            subsession_id_list <array<string>> out
 
 # Signals
 
@@ -104,55 +104,55 @@ In case of an error, methods return a DBus error.
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: AddUserStarted
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32>
-            subsession_id <int32>
+            subsession_id <string>
 
 2. On user removal:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: RemoveUserStarted
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32>
-            subsession_id <int32>
+            subsession_id <string>
 
 3. On user switch:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: SwitchUserStarted
-        parameters: (ixii)
+        parameters: (ixss)
             session_uid <int32>
             switch_id <int64>
-            prev_subsession_id <int32>
-            next_subsession_id <int32>
+            prev_subsession_id <string>
+            next_subsession_id <string>
 
 4. On user add completed:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: AddUserCompleted
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32>
-            subsession_id <int32>
+            subsession_id <string>
 
 5. On user removal completed:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: RemoveUserCompleted
-        parameters: (ii)
+        parameters: (is)
             session_uid <int32>
-            subsession_id <int32>
+            subsession_id <string>
 
 6. On user switch completed:
 
         objpath: /org/tizen/sessiond
         interface: org.tizen.sessiond.subsession.Manager
         member: SwitchUserCompleted
-        parameters: (ixii)
+        parameters: (ixss)
             session_uid <int32>
             switch_id <int64>
-            prev_subsession_id <int32>
-            next_subsession_id <int32>
+            prev_subsession_id <string>
+            next_subsession_id <string>
index 26fb8ec..b73ac97 100644 (file)
@@ -74,6 +74,9 @@ typedef struct subsession_event_info {
        };
 } subsession_event_info;
 
+#define SUBSESSION_INITIAL_SID ""
+#define SUBSESSION_USER_MAXLEN 20
+
 /**
  * @brief Callback fired when requested operation completes.
  * @since_tizen 7.0
@@ -118,9 +121,10 @@ int subsession_add_user(int session_uid, int user, subsession_reply_callback cb,
  * @retval #SUBSESSION_ERROR_NONE Success
  * @retval #SUBSESSION_ERROR_INVALID_PARAMETER Provided parameter is invalid
  * @retval #SUBSESSION_ERROR_OUT_OF_MEMORY Out of memory
- * @remarks Only inactive session ID can be removed. \n
- * In order remove currently used session ID first switch to special session ID 0, and \n
- * only after switch completes remove previously active session ID.
+ * @remarks Subsession ID must not start with a dot or have slashes.
+ * Only inactive session ID can be removed. \n
+ * In order remove currently used session ID first switch to special session ID "" (empty string),
+ * and only after switch completes, remove previously active session ID.
  */
 int subsession_remove_user(int session_uid, int user, subsession_reply_callback cb, void *cb_data);
 
@@ -137,8 +141,9 @@ int subsession_remove_user(int session_uid, int user, subsession_reply_callback
  * @retval #SUBSESSION_ERROR_NONE Success
  * @retval #SUBSESSION_ERROR_INVALID_PARAMETER Provided parameter is invalid
  * @retval #SUBSESSION_ERROR_OUT_OF_MEMORY Out of memory
- * @remarks Special subsession ID 0 can be switched to, when it's required to deactivate current subsession \n
- * (this step is needed when current session is to be removed).
+ * @remarks Subsession ID must not start with a dot or have slashes.
+ * Special subsession ID "" (empty string) can be switched to, when it's required to deactivate
+ * current subsession (this step is needed when current session is to be removed).
  */
 int subsession_switch_user(int session_uid, int next_user, subsession_reply_callback cb, void *cb_data);
 
index 4cd9597..d890de3 100644 (file)
@@ -165,10 +165,10 @@ void fs_helpers::create_main_subdirectory(const int session_uid, std::string_vie
                        + "` subdirectory");
 }
 
-bool fs_helpers::subsession_exists(const int session_uid, const int subsession_id) try {
+bool fs_helpers::subsession_exists(const int session_uid, const std::string_view subsession_id) try {
        std::string home_dir = fs_helpers::get_home_dir_by_user_id(session_uid);
        std::string main_dir = std::move(home_dir) + "/" + main_dir_name.data();
-       std::string subsession_dir = std::move(main_dir) + "/" + std::to_string(subsession_id);
+       std::string subsession_dir = std::move(main_dir) + "/" + subsession_id.data();
        fs::path subsession_path { subsession_dir };
        return fs::exists(subsession_path);
 }
@@ -179,7 +179,7 @@ catch (std::exception const &ex) {
        return false;
 }
 
-void fs_helpers::add_user_subsession(const int session_uid, const int subsession_id)
+void fs_helpers::add_user_subsession(const int session_uid, const std::string_view subsession_id)
 {
        try {
                std::string home_dir = get_home_dir_by_user_id(session_uid);
@@ -187,25 +187,26 @@ void fs_helpers::add_user_subsession(const int session_uid, const int subsession
 
                create_main_subdirectory(session_uid, main_dir);
 
-               std::string subsession_dir = std::move(main_dir) + "/" + std::to_string(subsession_id);
+               std::string subsession_dir = main_dir + "/" + subsession_id.data();
                fs::path subsession_path { subsession_dir };
 
                if (fs::exists(subsession_path))
                        throw std::system_error(EEXIST, std::generic_category(),
                                "Subsession directory already exists");
 
-               fs::create_directory(subsession_dir);
+               std::string tmp_subsession_dir = std::move(main_dir) + "/" + ".tmpnew" + subsession_id.data();
+               fs::path tmp_subsession_path { tmp_subsession_dir };
 
-               std::string apps_rw_dir = subsession_dir + "/apps_rw";
+               fs::create_directory(tmp_subsession_dir);
+
+               std::string apps_rw_dir = tmp_subsession_dir + "/apps_rw";
                fs::path apps_rw_path { apps_rw_dir };
-               std::string apps_rw_tmp_dir = apps_rw_dir + ".tmpnew";
-               fs::path apps_rw_tmp_path { apps_rw_tmp_dir };
                std::string source_dir = "/etc/skel/apps_rw";
                auto const source_dir_len = source_dir.length();
 
                fs::copy
                        ( fs::path{ source_dir }
-                       , apps_rw_tmp_path
+                       , apps_rw_path
                        , fs::copy_options::recursive
                        | fs::copy_options::copy_symlinks
                );
@@ -216,17 +217,17 @@ void fs_helpers::add_user_subsession(const int session_uid, const int subsession
 
                        std::string tmp_path = s_path;
                        tmp_path.erase(0, source_dir_len);
-                       std::string d_path = apps_rw_tmp_dir + std::move(tmp_path);
+                       std::string d_path = apps_rw_dir + std::move(tmp_path);
 
                        copy_ownership(s_path, d_path);
                        copy_smack_attributes(s_path, d_path);
                }
                // Last but not least - the `apps_rw` directory itself
-               copy_ownership(source_dir, apps_rw_tmp_dir);
-               copy_smack_attributes(source_dir, apps_rw_tmp_dir);
+               copy_ownership(source_dir, apps_rw_dir);
+               copy_smack_attributes(source_dir, apps_rw_dir);
 
                // Copy + rename so that the replacement is atomic
-               fs::rename(apps_rw_tmp_path, apps_rw_path);
+               fs::rename(tmp_subsession_path, subsession_path);
 
        }
        catch (std::system_error const &ex) {
@@ -243,12 +244,12 @@ void fs_helpers::add_user_subsession(const int session_uid, const int subsession
        }
 }
 
-void fs_helpers::remove_user_subsession(const int session_uid, const int subsession_id)
+void fs_helpers::remove_user_subsession(const int session_uid, const std::string_view subsession_id)
 {
        try {
                std::string home_dir = get_home_dir_by_user_id(session_uid);
                fs::path subsession_path {
-                       std::move(home_dir) + "/" + main_dir_name.data() + "/" + std::to_string(subsession_id)
+                       std::move(home_dir) + "/" + main_dir_name.data() + "/" + subsession_id.data()
                };
 
                if (!fs::exists(subsession_path))
@@ -280,10 +281,10 @@ fs::path fs_helpers::get_subsession_dir_by_uid(const int session_uid)
        };
 }
 
-std::vector<int> fs_helpers::get_user_list(const int session_uid) try
+std::vector<std::string> fs_helpers::get_user_list(const int session_uid) try
 {
        auto const subsession_path = get_subsession_dir_by_uid(session_uid);
-       std::vector<int> subsessions;
+       std::vector<std::string> subsessions;
 
        /* NB: the `subsession` folder may not exist if no
         * subsessions have been created before. */
@@ -294,21 +295,10 @@ std::vector<int> fs_helpers::get_user_list(const int session_uid) try
                if (!fs::is_directory(entry.status()))
                        continue;
 
-               std::string_view s_path = entry.path().filename().native();
-
-               /* NB: the std::stoi check below is insufficient,
-                * since you can create folders named +123 or 0x123. */
-               if (s_path.find_first_not_of("0123456789") != std::string::npos)
-                       continue;
+               const auto s_path = entry.path().filename();
 
-               try {
-                       const int subsession_id { std::stoi(s_path.data()) };
-                       if (subsession_id > 0)
-                               subsessions.emplace_back(subsession_id);
-               }
-               catch (std::exception const &ex) {
-                       continue;
-               }
+               if (check_subsession_id_valid(s_path.native()))
+                       subsessions.emplace_back(s_path);
        }
 
        return subsessions;
index 333740c..d0772cb 100644 (file)
@@ -18,10 +18,10 @@ namespace fs_helpers
        void copy_ownership(std::string_view src_path, std::string_view dest_path);
        std::string get_smack_label(std::string_view src_path, smack_label_type type);
        void copy_smack_attributes(std::string_view src_path, std::string_view dest_path);
-       bool subsession_exists(const int session_uid, const int subsession_id);
-       void add_user_subsession(const int session_uid, const int subsession_id);
-       void remove_user_subsession(const int session_uid, const int subsession_id);
-       std::vector<int> get_user_list(const int session_uid);
+       bool subsession_exists(const int session_uid, const std::string_view subsession_id);
+       void add_user_subsession(const int session_uid, const std::string_view subsession_id);
+       void remove_user_subsession(const int session_uid, const std::string_view subsession_id);
+       std::vector<std::string> get_user_list(const int session_uid);
 
        constexpr static std::string_view main_dir_name  = "subsession";
        constexpr static std::string_view main_dir_group = "system_share";
index 4ab3e61..e532a77 100644 (file)
 #include <exception>
 #include <stdexcept>
 #include <string>
+#include <string_view>
 
 #include <gio/gio.h>
 
+#include "sessiond-internal.h"
+
 using namespace std::chrono_literals;
 
 constexpr inline std::string_view bus_name   = "org.tizen.sessiond";
@@ -43,3 +46,15 @@ constexpr std::chrono::seconds timeout = 10s;
        throw std::runtime_error(std::move(message));
 }
 
+inline bool check_subsession_id_valid(const std::string_view subsession_id)
+{
+       if (subsession_id.length() < 1
+        || subsession_id.length() >= SUBSESSION_USER_MAXLEN
+        || subsession_id.find_first_of("/") != std::string::npos)
+               return false;
+
+       if (subsession_id[0] == '.')
+               return false;
+
+       return true;
+}
index 5f30d62..d044e99 100644 (file)
@@ -32,8 +32,6 @@
 #include "tuple_hash.hpp"
 #include "wait_manager.hpp"
 
-#include "sessiond-internal.h"
-
 static constexpr const char * get_dbus_error_mapping (subsession_error_e subsession_error)
 {
        /* I want this function to be evaluated at compile time
@@ -114,10 +112,6 @@ struct main_loop {
 };
 
 struct sessiond_context {
-       /* A special value representing the state
-        * before any sub session is switched to. */
-       static constexpr int INITIAL_SUB_SESSION_ID = 0;
-
        sessiond_context() : data(xml), id(), loop()
        {
                connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
@@ -147,16 +141,18 @@ struct sessiond_context {
                throw std::runtime_error("Bus name lost");
        }
 
-       bool check_parameters_invalid(GDBusMethodInvocation *invocation, const int session_uid, const int subsession_id)
+       bool check_parameters_invalid(GDBusMethodInvocation *invocation,
+               const int session_uid, const std::string_view subsession_id)
        {
                if (session_uid <= 0) {
                        g_dbus_method_invocation_return_dbus_error(invocation,
                                get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
                        return true;
                }
-               if (subsession_id <= 0) {
+
+               if (!check_subsession_id_valid(subsession_id)) {
                        g_dbus_method_invocation_return_dbus_error(invocation,
-                               get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative subsession_id passed");
+                               get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Incorrect subsession_id passed");
                        return true;
                }
 
@@ -165,7 +161,7 @@ struct sessiond_context {
 
        void on_add_user(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
        {
-               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, int>(parameters);
+               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, std::string>(parameters);
 
                if (check_parameters_invalid(invocation, session_uid, subsession_id))
                        return;
@@ -185,12 +181,12 @@ struct sessiond_context {
 
        void on_remove_user(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
        {
-               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, int>(parameters);
+               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, std::string>(parameters);
 
                if (check_parameters_invalid(invocation, session_uid, subsession_id))
                        return;
 
-               int current_subsession_id = INITIAL_SUB_SESSION_ID;
+               std::string_view current_subsession_id = SUBSESSION_INITIAL_SID;
                if (last_subsession_per_session.contains(session_uid))
                        current_subsession_id = last_subsession_per_session.at(session_uid);
                if (subsession_id == current_subsession_id) {
@@ -214,21 +210,21 @@ struct sessiond_context {
 
        void on_switch_user(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
        {
-               auto [ session_uid, next_subsession_id ] = tuple_from_g_variant<int, int>(parameters);
+               auto [ session_uid, next_subsession_id ] = tuple_from_g_variant<int, std::string>(parameters);
 
                if (session_uid <= 0) {
                        g_dbus_method_invocation_return_dbus_error(invocation,
                                get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative UID passed");
                        return;
                }
-               // N.B. Switch to user '0' is possible and it means no subsession is currently active
-               if (next_subsession_id < 0) {
+
+               // N.B. Switch to user "" (empty string) is possible and it means no subsession is currently active
+               if (next_subsession_id != SUBSESSION_INITIAL_SID && !check_subsession_id_valid(next_subsession_id)) {
                        g_dbus_method_invocation_return_dbus_error(invocation,
-                               get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Negative subsession_id passed");
+                               get_dbus_error_mapping(SUBSESSION_ERROR_INVALID_PARAMETER), "Incorrect subsession_id passed");
                        return;
                }
-
-               if (next_subsession_id > 0 && !fs_helpers::subsession_exists(session_uid, next_subsession_id)) {
+               if (next_subsession_id != SUBSESSION_INITIAL_SID && !fs_helpers::subsession_exists(session_uid, next_subsession_id)) {
                        g_dbus_method_invocation_return_dbus_error(invocation,
                                get_dbus_error_mapping(SUBSESSION_ERROR_NOT_AVAILABLE), "Subsession does not exist");
                        return;
@@ -236,7 +232,7 @@ struct sessiond_context {
 
                switch_id += 1;
 
-               int prev_subsession_id = INITIAL_SUB_SESSION_ID;
+               std::string_view prev_subsession_id = SUBSESSION_INITIAL_SID;
                if (last_subsession_per_session.contains(session_uid))
                        prev_subsession_id = last_subsession_per_session.at(session_uid);
 
@@ -248,7 +244,7 @@ struct sessiond_context {
                last_subsession_per_session[session_uid] = next_subsession_id;
 
                wait_switch.try_emplace(session_uid, session_uid, connection, "SwitchUserCompleted");
-               wait_switch.at(session_uid).on_start(switch_id, { prev_subsession_id, next_subsession_id });
+               wait_switch.at(session_uid).on_start(switch_id, { std::string(prev_subsession_id), next_subsession_id });
 
                g_dbus_method_invocation_return_value(invocation, nullptr);
        }
@@ -303,7 +299,7 @@ struct sessiond_context {
 
        void on_add_user_done(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
        {
-               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, int>(parameters);
+               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, std::string>(parameters);
 
                if (check_parameters_invalid(invocation, session_uid, subsession_id))
                        return;
@@ -316,7 +312,7 @@ struct sessiond_context {
 
        void on_remove_user_done(GDBusMethodInvocation *invocation, std::string_view sender, GVariant *parameters)
        {
-               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, int>(parameters);
+               auto [ session_uid, subsession_id ] = tuple_from_g_variant<int, std::string>(parameters);
 
                if (check_parameters_invalid(invocation, session_uid, subsession_id))
                        return;
@@ -356,10 +352,10 @@ struct sessiond_context {
                auto users = fs_helpers::get_user_list(session_uid);
 
                // TODO: It would be cool to be able to use vals_to_g_variant here.
-               g_autoptr(GVariantBuilder) builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
-               for (auto user : users)
-                       g_variant_builder_add(builder, "i", user);
-               auto ret = g_variant_new("(ai)", builder);
+               g_autoptr(GVariantBuilder) builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+               for (const auto &user : users)
+                       g_variant_builder_add(builder, "s", user.c_str());
+               auto ret = g_variant_new("(as)", builder);
 
                g_dbus_method_invocation_return_value(invocation, ret);
        }
@@ -374,7 +370,7 @@ struct sessiond_context {
                        return;
                }
 
-               int subsession_id = INITIAL_SUB_SESSION_ID;
+               std::string subsession_id = SUBSESSION_INITIAL_SID;
                if (last_subsession_per_session.contains(session_uid))
                        subsession_id = last_subsession_per_session.at(session_uid);
 
@@ -452,15 +448,15 @@ struct sessiond_context {
                        "<interface name=\"org.tizen.sessiond.subsession.Manager\">"
                                "<method name=\"AddUser\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"in\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"in\"/>"
                                "</method>"
                                "<method name=\"RemoveUser\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"in\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"in\"/>"
                                "</method>"
                                "<method name=\"SwitchUser\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"next_subsession_id\" type=\"i\" direction=\"in\"/>"
+                                       "<arg name=\"next_subsession_id\" type=\"s\" direction=\"in\"/>"
                                "</method>"
                                "<method name=\"AddUserWait\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
@@ -473,11 +469,11 @@ struct sessiond_context {
                                "</method>"
                                "<method name=\"AddUserDone\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"in\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"in\"/>"
                                "</method>"
                                "<method name=\"RemoveUserDone\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"in\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"in\"/>"
                                "</method>"
                                "<method name=\"SwitchUserDone\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
@@ -485,39 +481,39 @@ struct sessiond_context {
                                "</method>"
                                "<method name=\"GetUserList\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"subsession_id_list\" type=\"ai\" direction=\"out\"/>"
+                                       "<arg name=\"subsession_id_list\" type=\"as\" direction=\"out\"/>"
                                "</method>"
                                "<method name=\"GetCurrentUser\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"in\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"out\"/>"
                                "</method>"
                                "<signal name=\"AddUserStarted\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"out\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"out\"/>"
                                "</signal>"
                                "<signal name=\"RemoveUserStarted\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"out\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"out\"/>"
                                "</signal>"
                                "<signal name=\"SwitchUserStarted\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"out\"/>"
                                        "<arg name=\"switch_id\"          type=\"x\" direction=\"out\"/>"
-                                       "<arg name=\"prev_subsession_id\" type=\"i\" direction=\"out\"/>"
-                                       "<arg name=\"next_subsession_id\" type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"prev_subsession_id\" type=\"s\" direction=\"out\"/>"
+                                       "<arg name=\"next_subsession_id\" type=\"s\" direction=\"out\"/>"
                                "</signal>"
                                "<signal name=\"AddUserCompleted\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"out\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"out\"/>"
                                "</signal>"
                                "<signal name=\"RemoveUserCompleted\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"out\"/>"
-                                       "<arg name=\"subsession_id\"      type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"subsession_id\"      type=\"s\" direction=\"out\"/>"
                                "</signal>"
                                "<signal name=\"SwitchUserCompleted\">"
                                        "<arg name=\"session_uid\"        type=\"i\" direction=\"out\"/>"
                                        "<arg name=\"switch_id\"          type=\"x\" direction=\"out\"/>"
-                                       "<arg name=\"prev_subsession_id\" type=\"i\" direction=\"out\"/>"
-                                       "<arg name=\"next_subsession_id\" type=\"i\" direction=\"out\"/>"
+                                       "<arg name=\"prev_subsession_id\" type=\"s\" direction=\"out\"/>"
+                                       "<arg name=\"next_subsession_id\" type=\"s\" direction=\"out\"/>"
                                "</signal>"
                        "</interface>"
                "</node>";
@@ -540,12 +536,12 @@ struct sessiond_context {
        // Consider simplifying wait_manager.
        // N.B. Although GLib is multi-threaded, the following data structures do not need
        // to be protected by mutexes as all of them are accessed from DBus handlers only.
-       std::unordered_map<int, wait_manager<std::tuple<int>, std::tuple<>>> wait_add;
-       std::unordered_map<int, wait_manager<std::tuple<int>, std::tuple<>>> wait_remove;
-       std::unordered_map<int, wait_manager<std::tuple<uint64_t>, std::tuple<int, int>>> wait_switch;
+       std::unordered_map<int, wait_manager<std::tuple<std::string>, std::tuple<>>> wait_add;
+       std::unordered_map<int, wait_manager<std::tuple<std::string>, std::tuple<>>> wait_remove;
+       std::unordered_map<int, wait_manager<std::tuple<uint64_t>, std::tuple<std::string, std::string>>> wait_switch;
 
        // used for tracking subsession switches for each `session_uid`
-       std::unordered_map<int, int> last_subsession_per_session;
+       std::unordered_map<int, std::string> last_subsession_per_session;
 
        uint64_t switch_id = 0;