vip-agent: double check VIPs on booting done 78/258078/11 accepted/tizen/unified/20210528.134755 submit/tizen/20210528.010751
authorYoungjae Cho <y0.cho@samsung.com>
Mon, 10 May 2021 07:29:55 +0000 (16:29 +0900)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Wed, 12 May 2021 09:52:38 +0000 (09:52 +0000)
Change-Id: Id2596633387d44233b6df9729c0d24550bd35a68
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
src/common/dbus-handler.c
src/common/dbus-handler.h
src/vip-agent/vip-process.c

index 9331fb3..94cf16c 100644 (file)
@@ -216,6 +216,30 @@ int d_bus_call_method_sync_gvariant(const char *dest, const char *path,
        return ret;
 }
 
+int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
+               const char *interface, const char *method,
+               GVariant *gv, GVariant **out_reply)
+{
+       GVariant *reply = NULL;
+       GError *err = NULL;
+
+       reply = g_dbus_connection_call_sync(d_bus_get_connection(), dest, path,
+                       interface, method, gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+       if (err || !reply) {
+               /* The case where !err && !reply (i.e. reply type mismatch) can't currently happen
+                * because we don't specify the desired reply type, but it's good to be future-proof */
+               _E("Failed to call D-Bus name %s, objpath %s, iface %s, method %s: %s",
+                       dest, path, interface, method, err ? err->message : "reply signature mismatch");
+               if (err)
+                       g_error_free(err);
+               return -ECOMM;
+       }
+
+       *out_reply = reply;
+
+       return 0;
+}
+
 int d_bus_call_method_async(const char *dest, const char *path,
                const char *interface, const char *method,
                const char *sig, char *param[])
index c58e6d5..df66ffd 100644 (file)
@@ -100,6 +100,10 @@ int d_bus_call_method_async_gvariant(const char *dest, const char *path,
                const char *interface, const char *method,
                GVariant *gv);
 
+int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
+               const char *interface, const char *method,
+               GVariant *gv, GVariant **out_reply);
+
 int d_bus_call_method_async(const char *dest, const char *path,
                const char *interface, const char *method,
                const char *sig, char *param[]);
index a2d87b2..3782027 100644 (file)
 #include "module.h"
 #include "module-data.h"
 #include "vip-process.h"
+#include "dbus-handler.h"
 
-#define VIP_CONF_FILE          RD_CONFIG_FILE(vip-process)
+#define VIP_CONF_FILE                  RD_CONFIG_FILE(vip-process)
+
+#define SYSTEMD_DBUS_DEST              "org.freedesktop.systemd1"
+#define SYSTEMD_DBUS_UNIT_PATH         "/org/freedesktop/systemd1/unit/"
+#define SYSTEMD_DBUS_SERVICE_IFACE     SYSTEMD_DBUS_DEST".Service"
+#define DBUS_IFACE_DBUS_PROPERTIES     "org.freedesktop.DBus.Properties"
+
+#define SYSTEMD_UNIT_ESCAPE_CHAR       ".-"
 
 static char **arg_vip_proc_names = NULL;
 static char **arg_vip_systemd_services = NULL;
 
+/* copy of libsyscommon/libsystemd.c: systemd_get_unit_dbus_path() */
+static int vip_get_escaped_name(const char *unit, char **escaped)
+{
+       char *path = NULL;
+       int i;
+       size_t p, k, prefix_len, unit_len;
+       size_t path_len, len, escape;
+
+       if (!unit) {
+               _E("Invalid parameter.");
+               return -EINVAL;
+       }
+       unit_len = strlen(unit);
+
+       for (escape = 0, p = 0; p < unit_len; escape++) {
+               k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+               if (p + k >= unit_len)
+                       break;
+               p += k+1;
+       }
+
+       prefix_len = strlen(SYSTEMD_DBUS_UNIT_PATH);
+       /* assume we try to get object path of foo-bar.service then
+       * the object path will be
+       * "/org/freedesktop/systemd1/unit/foo_2dbar_2eservice\n". In
+       * this case we can find two escape characters, one of escape
+       * char('-') is changed to three of char("_2d"). So the total
+       * length will be: */
+       /* (PREFIX) + (unit - escape + 3*escape) + NULL */
+       path_len = prefix_len + (unit_len - escape)
+               + (escape * 3 * sizeof(char)) + 1;
+       path = (char *)calloc(path_len, sizeof(char));
+       if (!path) {
+               _E("Not enough memory.");
+               return -ENOMEM;
+       }
+
+       *escaped = path;
+
+       strncpy(path, SYSTEMD_DBUS_UNIT_PATH, prefix_len + 1);
+       for (i = 0, p = 0; i <= escape; i++) {
+               k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+               strncpy(path + prefix_len, unit + p, k);
+               if (k < strlen(unit + p)) {
+                       len = path_len - (prefix_len + k);
+                       snprintf(path + prefix_len + k, len,
+                                       "_%x", *(unit + p + k) & 0xff);
+                       prefix_len += k + 3;
+                       p += k+1;
+               }
+       }
+
+       return 0;
+}
+
+/* get MainPID of a service. */
+static int vip_get_service_mainpid(const char *service, int *pid)
+{
+       char *escaped;
+       int ret = 0;
+       GVariant *reply = NULL;
+       GVariant *inner_reply = NULL;
+
+       if (!service)
+               return -EINVAL;
+
+       ret = vip_get_escaped_name(service, &escaped);
+       if (ret < 0) {
+               _E("Failed to makeup escaped service name.");
+               return ret;
+       }
+
+       ret = d_bus_call_method_sync_gvariant_with_reply(SYSTEMD_DBUS_DEST,
+                       escaped,
+                       DBUS_IFACE_DBUS_PROPERTIES,
+                       "Get",
+                       g_variant_new("(ss)", SYSTEMD_DBUS_SERVICE_IFACE, "ExecMainPID"),
+                       &reply);
+
+       free(escaped);
+
+       if (!reply || ret < 0) {
+               _E("Failed to get pid of service=%s", service);
+               if (reply)
+                       g_variant_unref(reply);
+               return -ECOMM;
+       }
+
+       do_expr_unless_g_variant_consume_typechecked(return -EINVAL, reply, "(v)", &inner_reply);
+       do_expr_unless_g_variant_consume_typechecked(return -EINVAL, inner_reply, "u", pid);
+
+       return 0;
+}
+
+static bool vip_check_all(void)
+{
+       int pid;
+       int ret_val;
+       bool ret = true;
+       char **pname = NULL;
+
+       FOREACH_STRV(pname, arg_vip_proc_names) {
+               pid = find_pid_from_cmdline(*pname);
+               if (pid < 0) {
+                       _E("VIP %s not found", *pname);
+                       ret = false;
+               }
+       }
+
+       FOREACH_STRV(pname, arg_vip_systemd_services) {
+               ret_val = vip_get_service_mainpid(*pname, &pid);
+               if (ret_val < 0) {
+                       _E("Failed to get MainPID of service=%s", *pname);
+                       continue;
+               }
+
+               /* The property MainPID can return a positive MainPID
+                * as a pid of inactive(dead) service if the service had once
+                * been active before. Therefore, it is necessary to check
+                * whether it is still alive. */
+               if (pid == 0 || kill(pid, 0) != 0) {
+                       _E("VIP %s not found", *pname);
+                       ret = false;
+               }
+       }
+
+       return ret;
+}
+
+static void vip_force_reboot(void)
+{
+       _E("VIP force reboot.");
+       execl("/usr/bin/vip-release-agent", "/usr/bin/vip-release-agent", NULL);
+
+       _E("Failed to execute vip-release-agent");
+}
+
 static int vip_load_config(struct parse_result *result, void *user_data)
 {
        char ***strv;
@@ -155,37 +300,19 @@ static void vip_create_systemd_service_groups(void)
                return;
 
        FOREACH_STRV(pname, arg_vip_systemd_services) {
-               _cleanup_free_ char *err_msg = NULL;
-               int r;
-               char path[128];
-               FILE *fp;
+               int ret_val;
                pid_t pid;
 
-               if (snprintf(path, sizeof(path), "%s/systemd/system.slice/%s/tasks",
-                                       DEFAULT_CGROUP, *pname) < 0) {
-                       _E("Fail to make task path");
-                       continue;
-               }
-
-               fp = fopen(path, "r");
-               if (!fp) {
-                       _E("%s is user level service or not running", *pname);
+               ret_val = vip_get_service_mainpid(*pname, &pid);
+               if (ret_val == -ECOMM)
                        continue;
-               }
 
-               if (fscanf(fp, "%d", &pid) < 0) {
-                       _E("Fail to get pid of %s", *pname);
-                       fclose(fp);
-                       continue;
-               }
                if (pid > 0) {
-                       r = vip_create_sub_cgroup(*pname, pid);
-                       if (r < 0)
+                       ret_val = vip_create_sub_cgroup(*pname, pid);
+                       if (ret_val < 0)
                                _E("failed to create "
                                   "sub cgroup of '%s', ignoring", *pname);
                }
-
-               fclose(fp);
        }
 }
 
@@ -194,6 +321,9 @@ static int vip_booting_done(void *data)
        vip_create_proc_name_groups();
        vip_create_systemd_service_groups();
 
+       if (vip_check_all() == false)
+               vip_force_reboot();
+
        return 0;
 }