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;
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)