proc-monitor: Save window info obtained from window system in app info 52/294552/39
authorUnsung Lee <unsung.lee@samsung.com>
Mon, 19 Jun 2023 08:49:25 +0000 (17:49 +0900)
committerUnsung Lee <unsung.lee@samsung.com>
Mon, 31 Jul 2023 02:35:06 +0000 (11:35 +0900)
Send dbus method call to window system to get window stack
and store window information into app information after checking validity

The window system manages information of windows called window stack, and
window stack includes information such as visibility and whether a window has
focus. This information is added to app information after validation process.

New dbus method call added from resourced to window system.
  - A bus name (org.enlightenment.wm), a path (/org/enlightenment/wm),
  and an interface (org.enlightenment.wm.proc) of window system
  - A method (GetVisibleWinInfo_v2)

Change-Id: I03984bbfedc7f861063c824ecd7541cc0bc8794f
Signed-off-by: Unsung Lee <unsung.lee@samsung.com>
src/common/ipc/dbus-names-external.h
src/common/proc-common.h
src/process/proc-monitor.c

index 91d932d..dc2ef9d 100644 (file)
 #define BOOTING_DONE_INTERFACE "org.tizen.system.Booting"
 #define SIGNAL_BOOTING_DONE    "BootingDone"
 
+/*
+ * Window System (UIFW)
+ */
+#define WINDOW_SYSTEM_BUS_NAME         "org.enlightenment.wm"
+#define WINDOW_SYSTEM_OBJECT_PATH      "/org/enlightenment/wm"
+#define WINDOW_SYSTEM_INTERFACE_NAME   "org.enlightenment.wm.proc"
+#define GET_VISIBLE_WINDOW_INFO_V2     "GetVisibleWinInfo_v2"
+
+#define VISIBLE_WINDOW_INFO_V2_VALUE_TYPE      "iiiiibbiibbi&s"
+#define VISIBLE_WINDOW_INFO_V2_ARRAY_VALUE_TYPE        "iiiiibbiibbis"
+
 #endif
index c635a47..ba10365 100644 (file)
@@ -207,6 +207,22 @@ struct proc_memory_state {
        bool memlimit_update_exclude;
 };
 
+struct proc_app_window_info {
+       int pid;
+       int x;
+       int y;
+       int z;
+       int w;
+       int h;
+       int layer;
+       int opaque;
+       int visibility;
+       bool is_transformed;
+       bool alpha;
+       bool is_focused;
+       bool is_mapped;
+};
+
 struct proc_app_info {
        char *appid;
        pid_t main_pid;
@@ -226,6 +242,8 @@ struct proc_app_info {
 
        unsigned long last_thaw_time; // in seconds since boot
        bool dont_freeze;
+
+       struct proc_app_window_info window;
 };
 
 //int proc_priority_set_fixed(void *data);
index 6248585..222397d 100644 (file)
@@ -73,6 +73,234 @@ static struct app_watchdog_info {
        int signum;
 } app_watchdog = { -1, -1 };
 
+#define INIT_PROCESS_PID 1
+
+static bool is_valid_window(const char *window_name, const char *app_state,
+               const struct proc_app_window_info *window)
+{
+       if (!window_name) {
+               _E("Window name cannot be NULL");
+               return false;
+       }
+
+       if (window->pid < INIT_PROCESS_PID) {
+               _E("window = %s, pid = %d", window_name, window->pid);
+               return false;
+       }
+
+       /* Focused app should be visible */
+       if (window->is_focused) {
+               if (window->visibility != 0 && window->visibility != 1) {
+                       _I("Focused app should be visible."
+                                       "window = %s, is_focused = %d, visibility = %d",
+                                       window_name, window->is_focused,
+                                       window->visibility);
+                       return false;
+               }
+       }
+
+       if (app_state == NULL)
+               return true;
+
+       if (!strncmp(app_state, "fg", 3)) {
+               /**
+                * Foreground app should be visible,
+                * but sometimes it does not guaranteed because of timing issue
+                */
+               if (window->visibility != 0 && window->visibility != 1) {
+                       _I("Fg app (window = %s) must be visible.",
+                                       window_name);
+                       return false;
+               }
+       } else if (!strncmp(app_state, "bg", 3)) {
+               /**
+                * Background app should not be focused,
+                * but sometimes it does not guaranteed because of timing issue
+                */
+               if (window->is_focused) {
+                       _I("Bg app (window = %s) must not be focused.",
+                                       window_name);
+                       return false;
+               }
+
+               /**
+                * Background app should not be visible,
+                * but sometimes it does not guaranteed because of timing issue
+                */
+               if (window->visibility == 0 || window->visibility == 1) {
+                       _I("Bg app (window = %s) must not be visible.",
+                                       window_name);
+                       return false;
+               }
+       } else {
+               _I("Unknown app state = %s, window = %s",
+                               app_state, window_name);
+               return false;
+       }
+
+       return true;
+}
+
+static int insert_window_in_window_table(GHashTable *window_table,
+               const struct proc_app_window_info *window)
+{
+       struct proc_app_window_info *new_window;
+       struct proc_app_window_info *existing_window;
+
+       if (!window_table || !window) {
+               _E("window table and window cannot be NULL");
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+       }
+
+       /**
+        * A process (app) can have more than 1 window.
+        * In this case, resourced stores the most important window information
+        * into proc_app_info structure.
+        *
+        * Criterion for judging which window is the most important:
+        *
+        * If one of window has is_focused = 1, then it is the most important.
+        * Otherwise, the higher in the window stack, the more important window.
+        */
+       if (!window->is_focused)
+               return RESOURCED_ERROR_NONE;
+
+       existing_window = g_hash_table_lookup(window_table, (gconstpointer) &window->pid);
+       if (existing_window)
+               return RESOURCED_ERROR_NONE;
+
+       new_window = calloc(1, sizeof(struct proc_app_window_info));
+       if (new_window == NULL) {
+               _E("Failed to alloc memory for new window");
+               return RESOURCED_ERROR_OUT_OF_MEMORY;
+       }
+
+       memcpy(new_window, window, sizeof(struct proc_app_window_info));
+       g_hash_table_insert(window_table, (gpointer) &new_window->pid,
+                       (gpointer)new_window);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int insert_window_info_in_proc_app_info(GHashTable *window_table)
+{
+       struct proc_app_window_info *window;
+       struct proc_app_info *pai;
+       GHashTableIter iter;
+       gpointer value;
+       gpointer pid;
+
+       if (!window_table) {
+               _E("window table can not be NULL");
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+       }
+
+       g_hash_table_iter_init(&iter, window_table);
+       while (g_hash_table_iter_next(&iter, &pid, &value)) {
+               window = (struct proc_app_window_info *)value;
+               if (!window) {
+                       _E("Window strucutre can not be null (SIGABRT)");
+                       assert(0);
+               }
+
+               pai = find_app_info(window->pid);
+               if (pai == NULL)
+                       continue;
+
+               memcpy(&pai->window, window, sizeof(struct proc_app_window_info));
+               _D("app = %s, pid = %d, is_focused = %d, "
+                               "visibility = %d, x = %d, y = %d, z = %d",
+                               pai->appid, pai->window.pid,
+                               pai->window.is_focused, pai->window.visibility,
+                               pai->window.x, pai->window.y, pai->window.z);
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void free_window_stack(GVariantIter *iter, GVariant *reply,
+               GHashTable *window_table)
+{
+       if (iter)
+               g_variant_iter_free(iter);
+
+       if (reply)
+               g_variant_unref(reply);
+
+       if (window_table)
+               g_hash_table_remove_all(window_table);
+}
+
+static int dbus_update_window_stack(pid_t *pid, const char *app_state)
+{
+       static GHashTable *window_table = NULL;
+       struct proc_app_window_info window;
+       GVariantIter *iter = NULL;
+       GVariant *reply = NULL;
+       gchar *name;
+       int z = 0;
+       int ret;
+
+       if (!pid || !app_state) {
+               _E("It is impossible to parse pid or app status");
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = d_bus_call_method_sync_gvariant_with_reply(WINDOW_SYSTEM_BUS_NAME,
+                       WINDOW_SYSTEM_OBJECT_PATH, WINDOW_SYSTEM_INTERFACE_NAME,
+                       GET_VISIBLE_WINDOW_INFO_V2, NULL, &reply);
+       if (ret < 0) {
+               _E("d_bus call fail");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       if (!g_variant_get_safe (reply, "(a("VISIBLE_WINDOW_INFO_V2_ARRAY_VALUE_TYPE"))",
+                               &iter)) {
+               _E("reply type is wrong");
+               goto error_to_parse_window_stack;
+       }
+
+       if (window_table == NULL) {
+               window_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free);
+               g_assert(window_table);
+       }
+
+       while (g_variant_iter_loop(iter, "("VISIBLE_WINDOW_INFO_V2_VALUE_TYPE")",
+                               &window.pid, &window.x, &window.y, &window.w, &window.h,
+                               &window.is_transformed, &window.alpha, &window.opaque,
+                               &window.visibility, &window.is_focused,
+                               &window.is_mapped, &window.layer, &name)) {
+               bool is_same_pid;
+
+               ++z;
+               window.z = z;
+
+               is_same_pid = (*pid == window.pid);
+               if (!is_valid_window(name, is_same_pid ? app_state : NULL, &window))
+                       goto error_to_parse_window_stack;
+
+               ret = insert_window_in_window_table(window_table, &window);
+               if (ret < 0)
+                       goto error_to_parse_window_stack;
+       }
+
+       /**
+        * Validity of all windows in window stack is checked,
+        * so update proc_app_info structure of corresponding windows
+        */
+       ret = insert_window_info_in_proc_app_info(window_table);
+       if (ret < 0)
+               goto error_to_parse_window_stack;
+       free_window_stack(iter, reply, window_table);
+
+       return RESOURCED_ERROR_NONE;
+
+error_to_parse_window_stack:
+       free_window_stack(iter, reply, window_table);
+
+       return RESOURCED_ERROR_FAIL;
+}
+
 static void dbus_get_meminfo(GDBusMethodInvocation *invocation, GVariant *params)
 {
        unsigned int mem_total, mem_free, mem_available, cached, used;
@@ -978,6 +1206,7 @@ EXPORT_TEST void proc_dbus_aul_changestate(GVariant *params)
                apptype = PROC_TYPE_GUI;
 
        resourced_proc_status_change(status, pid, appid, pkgid, apptype);
+       dbus_update_window_stack(&pid, statstr);
 }
 
 EXPORT_TEST void proc_dbus_aul_group(GVariant *params)