proc-monitor: Identify windows to save in app info
[platform/core/system/resourced.git] / src / process / proc-monitor.c
1 /*
2
3  * resourced
4  *
5  * Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 /*
22  * @file proc-monitor.c
23  *
24  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
25  *
26  */
27
28 #include <string.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <sys/mount.h>
32 #include <sys/time.h>
33 #include <sys/resource.h>
34
35 #include "proc-main.h"
36 #include "proc-monitor.h"
37 #include "resourced.h"
38 #include "macro.h"
39 #include "trace.h"
40 #include "safe-kill.h"
41 #include "dbus-handler.h"
42 #include "proc-process.h"
43 #include "proc-usage-stats.h"
44 #include "proc-usage-stats-helper.h"
45 #include "procfs.h"
46 #include "notifier.h"
47 #include "module.h"
48 #include "util.h"
49 #include "file-helper.h"
50 #include "watchdog-cgroup.h"
51
52 #include <libsyscommon/libsystemd.h>
53
54 #define WATCHDOG_LAUNCHING_PARAM "PopupLaunch"
55 #define WATCHDOG_KEY1                   "_SYSPOPUP_CONTENT_"
56 #define WATCHDOG_KEY2                   "_APP_NAME_"
57 #define WATCHDOG_VALUE_1                        "watchdog"
58
59 #define TIZEN_DEBUG_MODE_FILE   RD_SYS_ETC"/.debugmode"
60 #define DEFAULT_APPID   "NULL"
61 #define DEFAULT_RAMSIZE 512
62
63 #define INIT_PID        1
64 #define POWER_OFF_DIRECT  2
65
66 static int current_lcd_state;
67
68 static GSource *app_watchdog_check_timer;
69 #define APP_WATCHDOG_TIMER_INTERVAL             10
70
71 static struct app_watchdog_info {
72         pid_t pid;
73         int signum;
74 } app_watchdog = { -1, -1 };
75
76 #define INIT_PROCESS_PID 1
77
78 static bool is_valid_window(const char *window_name, const char *app_state,
79                 const struct proc_app_window_info *window)
80 {
81         if (!window_name) {
82                 _E("Window name cannot be NULL");
83                 return false;
84         }
85
86         if (window->pid < INIT_PROCESS_PID) {
87                 _E("window = %s, pid = %d", window_name, window->pid);
88                 return false;
89         }
90
91         /* Focused app should be visible */
92         if (window->is_focused) {
93                 if (window->visibility != 0 && window->visibility != 1) {
94                         _I("Focused app should be visible."
95                                         "window = %s, is_focused = %d, visibility = %d",
96                                         window_name, window->is_focused,
97                                         window->visibility);
98                         return false;
99                 }
100         }
101
102         if (app_state == NULL)
103                 return true;
104
105         if (!strncmp(app_state, "fg", 3)) {
106                 /**
107                  * Foreground app should be visible,
108                  * but sometimes it does not guaranteed because of timing issue
109                  */
110                 if (window->visibility != 0 && window->visibility != 1) {
111                         _I("Fg app (window = %s) must be visible.",
112                                         window_name);
113                         return false;
114                 }
115         } else if (!strncmp(app_state, "bg", 3)) {
116                 /**
117                  * Background app should not be focused,
118                  * but sometimes it does not guaranteed because of timing issue
119                  */
120                 if (window->is_focused) {
121                         _I("Bg app (window = %s) must not be focused.",
122                                         window_name);
123                         return false;
124                 }
125
126                 /**
127                  * Background app should not be visible,
128                  * but sometimes it does not guaranteed because of timing issue
129                  */
130                 if (window->visibility == 0 || window->visibility == 1) {
131                         _I("Bg app (window = %s) must not be visible.",
132                                         window_name);
133                         return false;
134                 }
135         } else {
136                 _I("Unknown app state = %s, window = %s",
137                                 app_state, window_name);
138                 return false;
139         }
140
141         return true;
142 }
143
144 static int insert_window_in_window_table(GHashTable *window_table,
145                 const struct proc_app_window_info *window)
146 {
147         struct proc_app_window_info *new_window;
148         struct proc_app_window_info *existing_window;
149
150         if (!window_table || !window) {
151                 _E("window table and window cannot be NULL");
152                 return RESOURCED_ERROR_INVALID_PARAMETER;
153         }
154
155         /**
156          * A process (app) can have more than 1 window.
157          * In this case, resourced stores the most important window information
158          * into proc_app_info structure.
159          *
160          * Criterion for judging which window is the most important:
161          *
162          * If one of window has is_focused = 1, then it is the most important.
163          * Otherwise, the higher in the window stack, the more important window.
164          */
165         existing_window = g_hash_table_lookup(window_table, (gconstpointer) &window->pid);
166         if (existing_window && !window->is_focused)
167                 return RESOURCED_ERROR_NONE;
168
169         new_window = calloc(1, sizeof(struct proc_app_window_info));
170         if (new_window == NULL) {
171                 _E("Failed to alloc memory for new window");
172                 return RESOURCED_ERROR_OUT_OF_MEMORY;
173         }
174
175         memcpy(new_window, window, sizeof(struct proc_app_window_info));
176         g_hash_table_insert(window_table, (gpointer) &new_window->pid,
177                         (gpointer)new_window);
178
179         return RESOURCED_ERROR_NONE;
180 }
181
182 static int insert_window_info_in_proc_app_info(GHashTable *window_table)
183 {
184         struct proc_app_window_info *window;
185         struct proc_app_info *pai;
186         GHashTableIter iter;
187         gpointer value;
188         gpointer pid;
189
190         if (!window_table) {
191                 _E("window table can not be NULL");
192                 return RESOURCED_ERROR_INVALID_PARAMETER;
193         }
194
195         g_hash_table_iter_init(&iter, window_table);
196         while (g_hash_table_iter_next(&iter, &pid, &value)) {
197                 window = (struct proc_app_window_info *)value;
198                 if (!window) {
199                         _E("Window strucutre can not be null (SIGABRT)");
200                         assert(0);
201                 }
202
203                 pai = find_app_info(window->pid);
204                 if (pai == NULL)
205                         continue;
206
207                 memcpy(&pai->window, window, sizeof(struct proc_app_window_info));
208                 _D("app = %s, pid = %d, is_focused = %d, "
209                                 "visibility = %d, x = %d, y = %d, z = %d",
210                                 pai->appid, pai->window.pid,
211                                 pai->window.is_focused, pai->window.visibility,
212                                 pai->window.x, pai->window.y, pai->window.z);
213         }
214
215         return RESOURCED_ERROR_NONE;
216 }
217
218 static void free_window_stack(GVariantIter *iter, GVariant *reply,
219                 GHashTable *window_table)
220 {
221         if (iter)
222                 g_variant_iter_free(iter);
223
224         if (reply)
225                 g_variant_unref(reply);
226
227         if (window_table)
228                 g_hash_table_remove_all(window_table);
229 }
230
231 static int dbus_update_window_stack(pid_t *pid, const char *app_state)
232 {
233         static GHashTable *window_table = NULL;
234         struct proc_app_window_info window;
235         GVariantIter *iter = NULL;
236         GVariant *reply = NULL;
237         gchar *name;
238         int z = 0;
239         int ret;
240
241         if (!pid || !app_state) {
242                 _E("It is impossible to parse pid or app status");
243                 return RESOURCED_ERROR_INVALID_PARAMETER;
244         }
245
246         ret = d_bus_call_method_sync_gvariant_with_reply(WINDOW_SYSTEM_BUS_NAME,
247                         WINDOW_SYSTEM_OBJECT_PATH, WINDOW_SYSTEM_INTERFACE_NAME,
248                         GET_VISIBLE_WINDOW_INFO_V2, NULL, &reply);
249         if (ret < 0) {
250                 _E("d_bus call fail");
251                 return RESOURCED_ERROR_FAIL;
252         }
253
254         if (!g_variant_get_safe (reply, "(a("VISIBLE_WINDOW_INFO_V2_ARRAY_VALUE_TYPE"))",
255                                 &iter)) {
256                 _E("reply type is wrong");
257                 goto error_to_parse_window_stack;
258         }
259
260         if (window_table == NULL) {
261                 window_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free);
262                 g_assert(window_table);
263         }
264
265         while (g_variant_iter_loop(iter, "("VISIBLE_WINDOW_INFO_V2_VALUE_TYPE")",
266                                 &window.pid, &window.x, &window.y, &window.w, &window.h,
267                                 &window.is_transformed, &window.alpha, &window.opaque,
268                                 &window.visibility, &window.is_focused,
269                                 &window.is_mapped, &window.layer, &name)) {
270                 bool is_same_pid;
271
272                 ++z;
273                 window.z = z;
274
275                 is_same_pid = (*pid == window.pid);
276                 if (!is_valid_window(name, is_same_pid ? app_state : NULL, &window))
277                         goto error_to_parse_window_stack;
278
279                 ret = insert_window_in_window_table(window_table, &window);
280                 if (ret < 0)
281                         goto error_to_parse_window_stack;
282         }
283
284         /**
285          * Validity of all windows in window stack is checked,
286          * so update proc_app_info structure of corresponding windows
287          */
288         ret = insert_window_info_in_proc_app_info(window_table);
289         if (ret < 0)
290                 goto error_to_parse_window_stack;
291         free_window_stack(iter, reply, window_table);
292
293         return RESOURCED_ERROR_NONE;
294
295 error_to_parse_window_stack:
296         free_window_stack(iter, reply, window_table);
297
298         return RESOURCED_ERROR_FAIL;
299 }
300
301 static void dbus_get_meminfo(GDBusMethodInvocation *invocation, GVariant *params)
302 {
303         unsigned int mem_total, mem_free, mem_available, cached, used;
304         unsigned int swap_total, swap_free, swap;
305         struct meminfo mi;
306         int r;
307
308         r = proc_get_meminfo(&mi,
309                              MEMINFO_MASK_MEM_TOTAL |
310                              MEMINFO_MASK_MEM_FREE |
311                              MEMINFO_MASK_MEM_AVAILABLE |
312                              MEMINFO_MASK_CACHED |
313                              MEMINFO_MASK_SWAP_TOTAL |
314                              MEMINFO_MASK_SWAP_FREE);
315         if (r < 0) {
316                 _E("Failed to get meminfo: %m");
317                 D_BUS_REPLY_ERR(invocation);
318                 return;
319         }
320
321         mem_total = mi.value[MEMINFO_ID_MEM_TOTAL];
322         mem_free = mi.value[MEMINFO_ID_MEM_FREE];
323         mem_available = mi.value[MEMINFO_ID_MEM_AVAILABLE];
324         cached = mi.value[MEMINFO_ID_CACHED];
325         swap_total = mi.value[MEMINFO_ID_SWAP_TOTAL];
326         swap_free = mi.value[MEMINFO_ID_SWAP_FREE];
327
328         used = mem_total - mem_available;
329         swap = swap_total - swap_free;
330
331         _D("memory info total = %u, free = %u, cache = %u, used = %u, swap = %u",
332                 mem_total, mem_free, cached, used, swap);
333
334         g_dbus_method_invocation_return_value(invocation, g_variant_new("(uuuuu)",
335                                 mem_total, mem_free, cached, used, swap));
336 }
337
338 static void dbus_reclaim_memory(GDBusMethodInvocation *invocation, GVariant *params)
339 {
340         _D("reclaiming memory!");
341
342         bool ok = true;
343         ok &= (RESOURCED_ERROR_NONE == proc_sys_node_trigger(SYS_VM_SHRINK_MEMORY));
344         ok &= (RESOURCED_ERROR_NONE == proc_sys_node_trigger(SYS_VM_COMPACT_MEMORY));
345
346         g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ok ? RESOURCED_ERROR_NONE : RESOURCED_ERROR_FAIL));
347 }
348
349 static void turn_off_proc_watchdog_handler()
350 {
351         /* Set the agent to something harmless. This destroys the previous
352          * state by losing information about the previous agent, though it's
353          * fine because the system is shutting down anyway and the "proper"
354          * way of doing this (iterate over all subdirectories and set their
355          * `notify_on_release` to 0) is bound to be slower than this. */
356         static const char AGENT_REPLACEMENT_PATH[] = "/bin/true";
357         if (fwrite_str(PROC_WATCHDOGCG_PATH "/" RELEASE_AGENT, AGENT_REPLACEMENT_PATH) == RESOURCED_ERROR_NONE) {
358                 _I("disabled release agent by setting to %s", AGENT_REPLACEMENT_PATH);
359                 return;
360         }
361
362         /* Fallback: subvert the agent itself. This is somewhat dangerous
363          * as now the program does something else than expected but the
364          * system is shutting down and nobody else should use the agent
365          * anyway so there isn't much opportunity to cause any surprises. */
366         if (!mount(AGENT_REPLACEMENT_PATH, PROC_WATCHDOG_HANDLER_PATH, NULL, MS_BIND | MS_RDONLY, NULL)) {
367                 _I("disabled release agent by bind mounting %s to %s", AGENT_REPLACEMENT_PATH, PROC_WATCHDOG_HANDLER_PATH);
368                 return;
369         }
370
371         _E("disabling release agent by bind mounting %s to %s failed; release agent is potentially still alive", AGENT_REPLACEMENT_PATH, PROC_WATCHDOG_HANDLER_PATH);
372 }
373
374 static void turn_off_proc_watchdog()
375 {
376         /* Turn off the "reboot on death" behaviour.
377          * It is normal for processes to die throughout a poweroff, while it
378          * is undesirable for the poweroff to be replaced by a reboot. */
379         turn_off_proc_watchdog_handler();
380
381         /* Unmounting the release cgroup does not make the above redundant because
382          * the unmounting can be done lazily and is not guaranteed to take place
383          * immediately. */
384         umount2(PROC_WATCHDOGCG_PATH, MNT_FORCE | MNT_DETACH);
385         _I("disabled process by unmounting release cgroup");
386 }
387
388 static void proc_poweroff()
389 {
390         _D("pre power off: unmounting cgroup fs");
391
392         proc_sweep_memory(PROC_SWEEP_EXCLUDE_ACTIVE, INIT_PID);
393         resourced_notify(RESOURCED_NOTIFIER_POWER_OFF, NULL);
394         turn_off_proc_watchdog();
395 }
396
397 static void dbus_pre_poweroff(GDBusMethodInvocation *invocation, GVariant *params)
398 {
399         proc_poweroff();
400         g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", -1));
401 }
402
403 static void dbus_get_checkappstatus(GDBusMethodInvocation *invocation, GVariant *params)
404 {
405         int len;
406         int detect = 0;
407         struct proc_app_info *pai;
408         char *appid = DEFAULT_APPID;
409         char *type = NULL;
410         pid_t pid = -1;
411
412         do_expr_unless_g_variant_get_typechecked(goto null_reply, params, "(i&s)", &pid, &type);
413         if (pid < 0 || type == NULL) {
414                 _D("there is no message");
415                 goto null_reply;
416         }
417
418         pai = find_app_info(pid);
419         if (!pai) {
420                 _D("There is no appid %d", pid);
421                 goto response;
422         }
423
424         /*
425          * allowed strings: normal, lcddim, lcdoff
426          * normal & lcddim : allow only UI application
427          * lcdoff : allow if it sends the excluding dbus signal
428          */
429         len = strlen(type);
430
431         if (len != 6) {
432                 _D("wrong lock type : %s", type);
433                 goto response;
434         }
435
436         appid = pai->appid;
437         if (pai->app_watchdog_exclude || pai->runtime_exclude) {
438                 _E("application (%d, %s) used %s lock longly but it is excluded", pid, appid, type);
439                 goto response;
440         }
441
442         if (!strncmp(type, "norm", 4) || !strncmp(type, "lcdd", 4)) {
443                 if (pai->type == PROC_TYPE_SERVICE || pai->type == PROC_TYPE_READY ||
444                     pai->type == PROC_TYPE_NONE)
445                         detect = 1;
446         } else if (!strncmp(type, "lcdo", 4)) {
447                 detect = 1;
448         }
449
450         if (detect)
451                 _E("detect application locking %s lock longly : %d, %s", type, pid, appid);
452         else
453                 _D("application locking %s lock longly but it seems normal : %d, %s", type, pid, appid);
454
455 response:
456         g_dbus_method_invocation_return_value(invocation, g_variant_new("(iis)",
457                                 pid, detect, appid));
458         return;
459
460 null_reply:
461         D_BUS_REPLY_ERR(invocation);
462 }
463
464 EXPORT_TEST void proc_dbus_active_signal_handler(GVariant *params)
465 {
466         int type;
467         char *str = NULL;
468         pid_t pid = 0;
469
470         do_expr_unless_g_variant_get_typechecked(return, params, "(&si)", &str, &pid);
471         if (!str || pid == 0) {
472                 _D("there is no message");
473                 return;
474         }
475
476         if (!strncmp(str, "active", strlen("active")+1))
477                 type = PROC_CGROUP_SET_ACTIVE;
478         else if (!strncmp(str, "inactive", strlen("inactive")+1))
479                 type = PROC_CGROUP_SET_INACTIVE;
480         else
481                 return;
482
483         _D("received %s signal for pid %d", str, pid);
484         resourced_proc_status_change(type, pid, NULL, NULL, PROC_TYPE_NONE);
485 }
486
487 EXPORT_TEST void dbus_get_app_cpu(GDBusMethodInvocation *invocation, GVariant *params)
488 {
489         char *appid = NULL;
490         unsigned long total, utime, stime, starttime;
491         struct proc_app_info *pai = NULL;
492
493         do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&s)", &appid);
494         if (!appid) {
495                 _E("Wrong message arguments!");
496                 goto failure;
497         }
498
499         pai = find_app_info_by_appid(appid);
500         if (!pai) {
501                 _E("There is no appid %s", appid);
502                 goto failure;
503         }
504
505         if (proc_get_cpu_time(pai->main_pid, &utime, &stime, &starttime) != RESOURCED_ERROR_NONE) {
506                 _E("proc_get_cpu_time = %s (%d)", appid, pai->main_pid);
507                 goto failure;
508         }
509
510         _D("cpu usage of %s (%d), utime = %lu, stime = %lu", appid, pai->main_pid, utime, stime);
511         total = utime + stime;
512
513         g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", total));
514         return;
515
516 failure:
517         D_BUS_REPLY_ERR(invocation);
518 }
519
520 EXPORT_TEST void dbus_get_app_memory(GDBusMethodInvocation *invocation, GVariant *params)
521 {
522         char *appid = NULL;
523         unsigned int usage = 0;
524         struct proc_app_info *pai = NULL;
525
526         do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&s)", &appid);
527         if (!appid) {
528                 _E("Wrong message arguments!");
529                 goto failure;
530         }
531
532         pai = find_app_info_by_appid(appid);
533         if (!pai || !pai->main_pid) {
534                 _E("There is no appid %s", appid);
535                 goto failure;
536         }
537
538         if (proc_get_mem_usage(pai->main_pid, &usage) < 0) {
539                 _E("lowmem_get_proc_mem_usage failed for appid = %s (%d)",
540                         appid, pai->main_pid);
541                 goto failure;
542         }
543
544         _D("memory usage of %s (%d), rss = %u", appid, pai->main_pid, usage);
545
546         g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", usage));
547         return;
548
549 failure:
550         D_BUS_REPLY_ERR(invocation);
551 }
552
553 EXPORT_TEST void dbus_get_memory_list(GDBusMethodInvocation *invocation, GVariant *params)
554 {
555         _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
556         GSList *giter;
557         char *appid;
558         struct proc_app_info *pai;
559         unsigned int usage = 0;
560         GVariantBuilder builder, *sub_builder;
561
562         g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
563         sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
564
565         proc_app_list = proc_app_list_open();
566         gslist_for_each_item(giter, proc_app_list) {
567                 pai = (struct proc_app_info *)giter->data;
568                 if (!pai || !pai->main_pid)
569                         continue;
570                 if (proc_get_mem_usage(pai->main_pid, &usage) < 0)
571                         continue;
572
573                 appid = pai->appid;
574
575                 g_variant_builder_add(sub_builder, "(su)", appid, usage);
576         }
577         g_variant_builder_add_value(&builder, g_variant_new("a(su)", sub_builder));
578         g_variant_builder_unref(sub_builder);
579
580         g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
581 }
582
583 EXPORT_TEST void dbus_get_cpu_list(GDBusMethodInvocation *invocation, GVariant *params)
584 {
585         _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
586         GSList *giter;
587         char *appid;
588         struct proc_app_info *pai;
589         unsigned long uptime, utime, stime, deltatime, starttime;
590         int ret;
591         GVariantBuilder builder, *sub_builder;
592
593         proc_app_list = proc_app_list_open();
594
595         ret = proc_get_uptime(&uptime);
596         if (ret) {
597                 _E("Failed to get uptime");
598                 D_BUS_REPLY_ERR(invocation);
599                 return;
600         }
601
602         g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
603         sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
604
605         gslist_for_each_item(giter, proc_app_list) {
606                 unsigned long percent;
607                 pai = (struct proc_app_info *)giter->data;
608                 if (!pai->main_pid)
609                         continue;
610                 if (proc_get_cpu_time(pai->main_pid, &utime, &stime, &starttime) != RESOURCED_ERROR_NONE)
611                         continue;
612                 appid = pai->appid;
613
614                 deltatime = uptime - pai->starttime;
615                 if (deltatime == 0)
616                         percent = 0;
617                 else
618                         percent = (utime + stime) / deltatime;
619
620                 g_variant_builder_add(sub_builder, "(su)", appid, percent);
621         }
622         g_variant_builder_add_value(&builder, g_variant_new("a(su)", sub_builder));
623         g_variant_builder_unref(sub_builder);
624
625         g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
626 }
627
628 EXPORT_TEST void dbus_get_memory_lists(GDBusMethodInvocation *invocation, GVariant *params)
629 {
630         GSList *proc_app_list = PAL_INIT_VALUE;
631         GSList *giter;
632         char *appid;
633         int type;
634         struct proc_app_info *pai;
635         unsigned int usage = 0;
636         GVariantBuilder builder, *sub_builder;
637
638         do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &type);
639         if (type < 0 || type >= PROC_TYPE_MAX) {
640                 _E("Wrong message arguments!");
641                 goto failure;
642         }
643
644         g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
645         sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
646
647         proc_app_list = proc_app_list_open();
648         gslist_for_each_item(giter, proc_app_list) {
649                 pai = (struct proc_app_info *)giter->data;
650                 if (!pai || !pai->main_pid)
651                         continue;
652                 if (type != PROC_TYPE_MAX && pai->type != type)
653                         continue;
654                 if (proc_get_mem_usage(pai->main_pid, &usage) < 0)
655                         continue;
656
657                 appid = pai->appid;
658
659                 g_variant_builder_add(sub_builder, "(su)", appid, usage);
660         }
661         g_variant_builder_add_value(&builder, g_variant_new("a(su)", sub_builder));
662         g_variant_builder_unref(sub_builder);
663
664         g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
665         proc_app_list_close();
666         return;
667
668 failure:
669         D_BUS_REPLY_ERR(invocation);
670 }
671
672 EXPORT_TEST void dbus_get_cpu_lists(GDBusMethodInvocation *invocation, GVariant *params)
673 {
674         GSList *proc_app_list = PAL_INIT_VALUE;
675         GSList *giter;
676         int ret, type;
677         char *appid;
678         struct proc_app_info *pai;
679         unsigned long uptime, utime, stime, deltatime, starttime;
680         GVariantBuilder builder, *sub_builder;
681
682         do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &type);
683         if (type < 0 || type >= PROC_TYPE_MAX) {
684                 _E("Wrong message arguments!");
685                 goto failure;
686         }
687
688         ret = proc_get_uptime(&uptime);
689         if (ret) {
690                 _E("Failed to get uptime");
691                 goto failure;
692         }
693
694         g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
695         sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
696
697         proc_app_list = proc_app_list_open();
698         gslist_for_each_item(giter, proc_app_list) {
699                 unsigned long percent;
700                 pai = (struct proc_app_info *)giter->data;
701                 if (!pai->main_pid)
702                         continue;
703                 if (type != PROC_TYPE_MAX && pai->type != type)
704                         continue;
705                 if (proc_get_cpu_time(pai->main_pid, &utime, &stime, &starttime) != RESOURCED_ERROR_NONE)
706                         continue;
707                 appid = pai->appid;
708
709                 /*
710                  * cpu usage can be calculated using total usage of stime and utime out of delta time.
711                  * cpu usage = (utime + stime ticks) / (current uptime - process start time) * 100 percentage
712                  *           = (utime + stime seconds) / (current uptime - process start time)
713                  *
714                  * Meanwhile, delta time between uptime and starttime should be checked
715                  * whether it is zero or not.
716                  * If delta time is zero, it can cause "divided by zero" fatal error.
717                  */
718                 deltatime = uptime - pai->starttime;
719                 if (deltatime == 0)
720                         percent = 0;
721                 else
722                         percent = (utime + stime) / deltatime;
723
724                 g_variant_builder_add(sub_builder, "(su)", appid, percent);
725         }
726         g_variant_builder_add_value(&builder, g_variant_new("a(su)", sub_builder));
727         g_variant_builder_unref(sub_builder);
728
729         g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
730         proc_app_list_close();
731         return;
732
733 failure:
734         D_BUS_REPLY_ERR(invocation);
735 }
736
737 static void dbus_get_get_ram_size(GDBusMethodInvocation *invocation, GVariant *params)
738 {
739         unsigned int total = MBYTE_TO_KBYTE(DEFAULT_RAMSIZE);
740         int ret;
741
742         ret = proc_get_ram_total(&total);
743         if (ret)
744                 _E("can't get ram total size. use default size");
745
746         g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", total));
747 }
748
749 EXPORT_TEST void proc_dbus_exclude_signal_handler(GVariant *params)
750 {
751         const char *str = NULL;
752         pid_t pid = 0;
753         struct proc_exclude pe;
754         int len;
755
756         do_expr_unless_g_variant_get_typechecked(return, params, "(&si)", &str, &pid);
757         if (!str || pid == 0) {
758                 _D("there is no message");
759                 return;
760         }
761
762         /*
763          * allowed strings: wakeup, exclude, include
764          */
765         len = strlen(str);
766
767         _D("%s signal on pid = %d", str, pid);
768         if (len == 6 && !strncmp(str, "wa", 2)) {
769                 struct proc_status ps = {0};
770
771                 ps.pai = find_app_info(pid);
772                 ps.pid = pid;
773                 resourced_notify(RESOURCED_NOTIFIER_APP_WAKEUP, &ps);
774         } else if (len == 7) {
775                 if (!strncmp(str, "ex", 2)) {
776                         pe.pid = pid;
777                         pe.type = PROC_EXCLUDE;
778                         resourced_notify(RESOURCED_NOTIFIER_CONTROL_EXCLUDE, &pe);
779                         proc_set_runtime_exclude_list(pe.pid, pe.type, find_app_info(pe.pid));
780                 } else if (!strncmp(str, "in", 2)) {
781                         pe.pid = pid;
782                         pe.type = PROC_INCLUDE;
783                         resourced_notify(RESOURCED_NOTIFIER_CONTROL_EXCLUDE, &pe);
784                         proc_set_runtime_exclude_list(pe.pid, pe.type, find_app_info(pe.pid));
785                 }
786         } else
787                 return;
788 }
789
790 EXPORT_TEST void proc_dbus_exclude_method_handler(GDBusMethodInvocation *invocation, GVariant *params)
791 {
792         const char *str = NULL;
793         pid_t pid = 0;
794
795         do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&si)", &str, &pid);
796         if (!str || pid == 0) {
797                 _E("invalid parameters");
798                 goto failure;
799         }
800         proc_dbus_exclude_signal_handler(params);
801         g_dbus_method_invocation_return_value(invocation, NULL);
802         return;
803
804 failure:
805         g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
806                 G_DBUS_ERROR_INVALID_ARGS, "invalid arguments");
807 }
808
809 EXPORT_TEST void proc_dbus_exclude_appid_signal_handler(GVariant *params)
810 {
811         char *str = NULL;
812         char *appid = NULL;
813         struct proc_exclude pe;
814         int len;
815         struct proc_status ps = {0};
816
817         do_expr_unless_g_variant_get_typechecked(return, params, "(&s&s)", &str, &appid);
818         if (!str || !appid) {
819                 _D("there is no message");
820                 return;
821         }
822
823         ps.pai = find_app_info_by_appid(appid);
824         if (!ps.pai) {
825                 _E("no entry of %s in app list", appid);
826                 return;
827         }
828         ps.pid = ps.pai->main_pid;
829
830         /*
831          * allowed strings: wakeup, exclude, include
832          */
833         len = strlen(str);
834
835         _D("%s signal on app = %s", str, appid);
836         if (len == 6 && !strncmp(str, "wa", 2)) {
837                 resourced_notify(RESOURCED_NOTIFIER_APP_WAKEUP, &ps);
838         } else if (len == 7) {
839                 if (!strncmp(str, "ex", 2)) {
840                         pe.pid = ps.pid;
841                         pe.type = PROC_EXCLUDE;
842                         resourced_notify(RESOURCED_NOTIFIER_CONTROL_EXCLUDE, &pe);
843                         proc_set_runtime_exclude_list(pe.pid, pe.type, ps.pai);
844                 } else if (!strncmp(str, "in", 2)) {
845                         pe.pid = ps.pid;
846                         pe.type = PROC_INCLUDE;
847                         resourced_notify(RESOURCED_NOTIFIER_CONTROL_EXCLUDE, &pe);
848                         proc_set_runtime_exclude_list(pe.pid, pe.type, ps.pai);
849                 }
850         } else
851                 return;
852 }
853
854 static void proc_dbus_set_priority_signal_handler(GVariant *params)
855 {
856         char *str = NULL;
857         pid_t pid = -1;
858         struct proc_app_info *pai;
859
860         do_expr_unless_g_variant_get_typechecked(return, params, "(&si)", &str, &pid);
861         if (!str || pid < 0) {
862                 _D("there is no message");
863                 return;
864         }
865
866         pai = find_app_info(pid);
867         if (pai && pai->app_cpu_nice_update_exclude)
868                 return;
869
870         _D("pid (%d) requested to change priority (%s)", pid, str);
871         if (!strncmp(str, "high", sizeof "high"))
872                 setpriority(PRIO_PGRP, pid, -5);
873         else if (!strncmp(str, "default", sizeof "default"))
874                 setpriority(PRIO_PGRP, pid, 0);
875         else if (!strncmp(str, "low", sizeof "low"))
876                 setpriority(PRIO_PGRP, pid, 1);
877         else
878                 _W("Warning: invalid set priority request (%s)!", str);
879 }
880
881 EXPORT_TEST void proc_dbus_prelaunch_signal_handler(GVariant *params)
882 {
883         char *appid = NULL;
884         char *pkgid = NULL;
885         int flags = -1;
886         int categories = -1;
887         struct proc_status ps;
888         struct proc_app_info *pai;
889
890         do_expr_unless_g_variant_get_typechecked(return, params, "(&s&sii)", &appid, &pkgid, &flags, &categories);
891         if (!appid || !pkgid || flags < 0 || categories < 0) {
892                 _D("there is no message");
893                 return;
894         }
895
896         _D("call proc_dbus_prelaunch_handler: appid = %s, pkgid = %s, flags = %d,"
897                 " categories = %X\n", appid, pkgid, flags, categories);
898
899         pai = proc_add_app_info(appid, pkgid, 0, flags, categories, PROC_TYPE_READY, PROC_STATE_DEFAULT);
900         ps.pai = pai;
901         resourced_notify(RESOURCED_NOTIFIER_APP_PRELAUNCH, &ps);
902 }
903
904 static void proc_dbus_sweep_signal_handler(GVariant *params)
905 {
906         proc_sweep_memory(PROC_SWEEP_INCLUDE_ACTIVE, INIT_PID);
907 }
908
909 static gboolean check_app_watchdog_cb(gpointer data)
910 {
911         int oom_score_adj = 0, ret;
912         pid_t pid = app_watchdog.pid;
913
914         ret = proc_get_oom_score_adj(pid, &oom_score_adj);
915         if (!ret) {
916                 _E("app watchdog pid %d not terminated, kill again\n", pid);
917                 safe_kill(pid, SIGKILL);
918         }
919         app_watchdog_check_timer = NULL;
920         app_watchdog.pid = -1;
921         app_watchdog.signum = -1;
922
923         return false;
924 }
925
926 static int proc_dbus_show_popup(const char *value)
927 {
928         char str_val[32];       // The original max size of represented string is 32
929         memcpy(str_val, value, sizeof str_val - 1);
930         str_val[sizeof str_val - 1] = '\0';
931
932         GVariantBuilder *const gv_builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
933         g_variant_builder_add(gv_builder, "{ss}", WATCHDOG_KEY1, WATCHDOG_VALUE_1);
934         g_variant_builder_add(gv_builder, "{ss}", WATCHDOG_KEY2, str_val);
935
936         GVariant *const params = g_variant_new("(a{ss})", gv_builder);
937         g_variant_builder_unref(gv_builder);
938
939         int ret_val = d_bus_call_method_sync_gvariant(SYSTEM_POPUP_BUS_NAME, SYSTEM_POPUP_PATH_SYSTEM,
940                 SYSTEM_POPUP_IFACE_SYSTEM, WATCHDOG_LAUNCHING_PARAM, params);
941
942         g_variant_unref(params);
943
944         return ret_val;
945 }
946
947 static void proc_dbus_app_watchdog_handler(GVariant *params)
948 {
949         int result;
950         int pid = -1;
951         int command = -1;
952         char appname[PROC_NAME_MAX];
953         struct proc_status ps;
954
955         do_expr_unless_g_variant_get_typechecked(return, params, "(ii)", &pid, &command);
956         if (pid < 0 || command < 0) {
957                 _D("[WATCHDOG] there is no message");
958                 return;
959         }
960
961         result = proc_get_cmdline(pid, appname, sizeof appname);
962         if (result != RESOURCED_ERROR_NONE) {
963                 _E("[WATCHDOG] ERROR : invalid pid(%d)", pid);
964                 return;
965         }
966
967         result = fixed_app_and_service_watchdog_action(appname, APP_TYPE);
968         if (result == PROC_ACTION_IGNORE) {
969                 _I("[WATCHDOG] appname (%s), pid (%d) is watchdog excluded app", appname, pid);
970                 return;
971         }
972
973         if (current_lcd_state == LCD_STATE_OFF) {
974                 _E("[WATCHDOG] Receive watchdog signal to pid: %d(%s) but don't show ANR popup in LCD off state\n", pid, appname);
975                 return;
976         }
977
978         _E("[WATCHDOG] Receive watchdog signal to app %s, pid %d\n", appname, pid);
979         ps.pai = find_app_info(pid);
980         ps.pid = pid;
981         resourced_notify(RESOURCED_NOTIFIER_APP_ANR, &ps);
982
983         if (proc_dbus_show_popup(appname) < 0)
984                 _E("[WATCHDOG] Failed to show ANR popup");
985
986         if (app_watchdog_check_timer) {
987                 if (app_watchdog.pid == pid) {
988                         _E("[WATCHDOG] app %s, pid %d has already received watchdog siganl but not terminated", appname, pid);
989                         safe_kill(pid, SIGKILL);
990                         app_watchdog.pid = -1;
991                         app_watchdog.signum = -1;
992                         return;
993                 }
994         }
995
996         resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
997                     pid, NULL, NULL, PROC_TYPE_NONE);
998         safe_kill(pid, SIGABRT);
999         if (!app_watchdog_check_timer) {
1000                 app_watchdog_check_timer = g_timeout_source_new_seconds(APP_WATCHDOG_TIMER_INTERVAL);
1001                 g_source_set_callback(app_watchdog_check_timer, check_app_watchdog_cb, NULL, NULL);
1002                 g_source_attach(app_watchdog_check_timer, NULL);
1003
1004                 app_watchdog.pid = pid;
1005                 app_watchdog.signum = command;
1006         }
1007 }
1008
1009 static void send_dump_signal(char *signal)
1010 {
1011         pid_t pid = getpid();
1012
1013         d_bus_broadcast_signal_gvariant(DUMP_SERVICE_OBJECT_PATH,
1014                         DUMP_SERVICE_INTERFACE_NAME, signal,
1015                         g_variant_new("(i)", pid));
1016 }
1017
1018 static void proc_dbus_dump_handler(GVariant *params)
1019 {
1020         char *path = NULL;
1021         int mode = -1;
1022
1023         do_expr_unless_g_variant_get_typechecked(return, params, "(i&s)", &mode, &path);
1024         if (mode < 0 || !path) {
1025                 _D("there is no message");
1026                 return;
1027         }
1028
1029         _D("received dump request: path %s", path);
1030         send_dump_signal(SIGNAL_DUMP_START);
1031         resourced_proc_dump(mode, path);
1032         send_dump_signal(SIGNAL_DUMP_FINISH);
1033 }
1034
1035 static void proc_dbus_systemservice_handler(GVariant *params)
1036 {
1037         pid_t pid = 0;
1038
1039         do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &pid);
1040         if (pid == 0) {
1041                 _D("there is no message");
1042                 return;
1043         }
1044
1045         resourced_proc_status_change(PROC_CGROUP_SET_SYSTEM_SERVICE, pid,
1046                     NULL, NULL, PROC_TYPE_NONE);
1047 }
1048
1049 EXPORT_TEST void proc_dbus_lcd_on(GVariant *params)
1050 {
1051         current_lcd_state = LCD_STATE_ON;
1052         /* nothing */
1053 }
1054
1055 EXPORT_TEST void proc_dbus_lcd_off(GVariant *params)
1056 {
1057         current_lcd_state = LCD_STATE_OFF;
1058 }
1059
1060 EXPORT_TEST void booting_done_signal_handler(GVariant *params)
1061 {
1062         _I("booting done");
1063         modules_init_late(NULL);
1064         resourced_notify(RESOURCED_NOTIFIER_BOOTING_DONE, NULL);
1065 }
1066
1067 EXPORT_TEST void low_battery_signal_handler(GVariant *params)
1068 {
1069         resourced_notify(RESOURCED_NOTIFIER_LOW_BATTERY, NULL);
1070 }
1071
1072 static void poweroff_signal_handler(GVariant *params)
1073 {
1074         int response;
1075
1076         do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &response);
1077
1078         /* This code does not check for values which could be too high.
1079          * This is for legacy reasons (we inherited the code without such
1080          * checks so potentially somebody might be using it that way). */
1081         if (response < POWER_OFF_DIRECT) {
1082                 _D("Invalid power off status: %d", response);
1083                 return;
1084         }
1085
1086         proc_poweroff();
1087 }
1088
1089 static void systemtime_changed_signal_handler(GVariant *params)
1090 {
1091         resourced_notify(RESOURCED_NOTIFIER_SYSTEMTIME_CHANGED, NULL);
1092 }
1093
1094 EXPORT_TEST void proc_dbus_aul_launch(GVariant *params)
1095 {
1096         pid_t pid = 0;
1097         int status, apptype;
1098         char *appid = NULL;
1099         char *pkgid = NULL;
1100         char *pkgtype = NULL;
1101
1102         do_expr_unless_g_variant_get_typechecked(return, params, "(i&s&s&s)", &pid, &appid, &pkgid, &pkgtype);
1103         if (pid == 0 || !appid || !pkgid || !pkgtype) {
1104                 _D("there is no message");
1105                 return;
1106         }
1107
1108 #ifdef PROC_DEBUG
1109         _D("aul_launch: app %s, pkgd %s, pid %d, pkgtype %s",
1110                         appid, pkgid, pid, pkgtype);
1111 #endif
1112
1113         if (!strncmp(pkgtype, "svc", 3)) {
1114                 apptype = PROC_TYPE_SERVICE;
1115                 status = PROC_CGROUP_SET_SERVICE_REQUEST;
1116         } else if (!strncmp(pkgtype, "ui", 2)) {
1117                 apptype = PROC_TYPE_GUI;
1118                 status = PROC_CGROUP_SET_LAUNCH_REQUEST;
1119         } else if (!strncmp(pkgtype, "widget", 6)) {
1120                 apptype = PROC_TYPE_WIDGET;
1121                 status = PROC_CGROUP_SET_LAUNCH_REQUEST;
1122         } else if (!strncmp(pkgtype, "watch", 5)) {
1123                 apptype = PROC_TYPE_WATCH;
1124                 status = PROC_CGROUP_SET_LAUNCH_REQUEST;
1125         } else
1126                 return;
1127
1128         resourced_proc_status_change(status, pid, appid, pkgid, apptype);
1129 }
1130
1131 EXPORT_TEST void proc_dbus_aul_resume(GVariant *params)
1132 {
1133         pid_t pid = 0;
1134         int status = PROC_CGROUP_SET_RESUME_REQUEST, apptype;
1135         char *appid = NULL;
1136         char *pkgid = NULL;
1137         char *pkgtype = NULL;
1138
1139         do_expr_unless_g_variant_get_typechecked(return, params, "(i&s&s&s)", &pid, &appid, &pkgid, &pkgtype);
1140         if (pid == 0 || !appid || !pkgid || !pkgtype) {
1141                 _D("there is no message");
1142                 return;
1143         }
1144
1145         if (!strncmp(pkgtype, "svc", 3))
1146                 apptype = PROC_TYPE_SERVICE;
1147         else if (!strncmp(pkgtype, "widget", 6))
1148                 apptype = PROC_TYPE_WIDGET;
1149         else if (!strncmp(pkgtype, "watch", 5))
1150                 apptype = PROC_TYPE_WATCH;
1151         else
1152                 apptype = PROC_TYPE_GUI;
1153
1154         resourced_proc_status_change(status, pid, appid, pkgid, apptype);
1155 }
1156
1157 EXPORT_TEST void proc_dbus_aul_terminate(GVariant *params)
1158 {
1159         pid_t pid = 0;
1160         int status = PROC_CGROUP_SET_TERMINATE_REQUEST;
1161         char *appid = NULL;
1162         char *pkgid = NULL;
1163         char *pkgtype = NULL;
1164
1165         do_expr_unless_g_variant_get_typechecked(return, params, "(i&s&s&s)", &pid, &appid, &pkgid, &pkgtype);
1166         if (pid == 0 || !appid || !pkgid || !pkgtype) {
1167                 _D("there is no message");
1168                 return;
1169         }
1170
1171         resourced_proc_status_change(status, pid, appid, pkgid, PROC_TYPE_NONE);
1172 }
1173
1174 EXPORT_TEST void proc_dbus_aul_changestate(GVariant *params)
1175 {
1176         pid_t pid = 0;
1177         int status, apptype;
1178         char *appid = NULL;
1179         char *pkgid = NULL;
1180         char *statstr = NULL;
1181         char *pkgtype = NULL;
1182
1183         do_expr_unless_g_variant_get_typechecked(return, params, "(i&s&s&s&s)", &pid, &appid, &pkgid, &statstr, &pkgtype);
1184         if (pid == 0 || !appid || !pkgid || !statstr || !pkgtype) {
1185                 _D("there is no message");
1186                 return;
1187         }
1188
1189         if (!strncmp(statstr, "fg", 2))
1190                 status = PROC_CGROUP_SET_FOREGRD;
1191         else if (!strncmp(statstr, "bg", 2))
1192                 status = PROC_CGROUP_SET_BACKGRD;
1193         else
1194                 return;
1195
1196         if (!strncmp(pkgtype, "svc", 3))
1197                 apptype = PROC_TYPE_SERVICE;
1198         else if (!strncmp(pkgtype, "widget", 6))
1199                 apptype = PROC_TYPE_WIDGET;
1200         else if (!strncmp(pkgtype, "watch", 5))
1201                 apptype = PROC_TYPE_WATCH;
1202         else
1203                 apptype = PROC_TYPE_GUI;
1204
1205         resourced_proc_status_change(status, pid, appid, pkgid, apptype);
1206         dbus_update_window_stack(&pid, statstr);
1207 }
1208
1209 EXPORT_TEST void proc_dbus_aul_group(GVariant *params)
1210 {
1211         pid_t ownerpid = 0;
1212         pid_t childpid = 0;
1213         char *appid = NULL;
1214
1215         do_expr_unless_g_variant_get_typechecked(return, params, "(ii&s)", &ownerpid, &childpid, &appid);
1216         if (ownerpid == 0 || childpid == 0 || !appid) {
1217                 _D("there is no message");
1218                 return;
1219         }
1220
1221         if (ownerpid == childpid) {
1222                 _I("specific case, one application %d makes multiple window. skip to merge", ownerpid);
1223                 return;
1224         }
1225
1226         _D("received process grouping : owner %d, child %d, previous appid %s",
1227                     ownerpid, childpid, appid);
1228         proc_set_group(ownerpid, childpid, appid);
1229 }
1230
1231 EXPORT_TEST void proc_dbus_aul_terminated(GVariant *params)
1232 {
1233         pid_t pid = 0;
1234         int status = PROC_CGROUP_SET_TERMINATED;
1235
1236         do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &pid);
1237         if (pid == 0) {
1238                 _D("there is no message");
1239                 return;
1240         }
1241
1242         resourced_proc_status_change(status, pid, NULL, NULL, PROC_TYPE_NONE);
1243 }
1244
1245 EXPORT_TEST void proc_dbus_suspend_hint(GVariant *params)
1246 {
1247         pid_t pid = 0;
1248         struct proc_app_info *pai = NULL;
1249         struct proc_status ps = {0};
1250         enum proc_state state;
1251
1252         do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &pid);
1253         if (pid == 0) {
1254                 _D("there is no message");
1255                 return;
1256         }
1257
1258         pai = find_app_info(pid);
1259         if (!pai)
1260                 return;
1261
1262         if (pai->appid)
1263                 _D("received suspend hint : app %s, pid %d",
1264                                 pai->appid, pid);
1265         else
1266                 _D("received suspend hint : pid %d", pid);
1267
1268         state = proc_check_suspend_state(pai);
1269         if (state == PROC_STATE_SUSPEND) {
1270                 ps.pid = pid;
1271                 ps.pai = pai;
1272                 resourced_notify(RESOURCED_NOTIFIER_APP_SUSPEND,
1273                             &ps);
1274         }
1275 }
1276
1277 static const char dbus_methods_xml[] =
1278 "<node>"
1279 "       <interface name='"RESOURCED_INTERFACE_PROCESS"'>"
1280 "               <method name='GetAppCpu'>"
1281 "                       <arg type='s' name='Appid' direction='in'/>"
1282 "                       <arg type='u' name='CpuUsage' direction='out'/>"
1283 "               </method>"
1284 "               <method name='GetCpuList'>"
1285 "                       <arg type='a(su)' name='PidWithCpuUsagePercent' direction='out'/>"
1286 "               </method>"
1287 "               <method name='GetCpuLists'>"
1288 "                       <arg type='i' name='AppType' direction='in'/>"
1289 "                       <arg type='a(su)' name='UsagePercent' direction='out'/>"
1290 "               </method>"
1291 "               <method name='GetAppMemory'>"
1292 "                       <arg type='s' name='Appid' direction='in'/>"
1293 "                       <arg type='u' name='MemoryUsage' direction='out'/>"
1294 "               </method>"
1295 "               <method name='GetMemoryList'>"
1296 "                       <arg type='a(su)' name='PidWithMemoryUsage' direction='out'/>"
1297 "               </method>"
1298 "               <method name='GetMemoryLists'>"
1299 "                       <arg type='i' name='AppType' direction='in'/>"
1300 "                       <arg type='a(su)' name='PidWithMemoryUsage' direction='out'/>"
1301 "               </method>"
1302 "               <method name='GetMemInfo'>"
1303 "                       <arg type='u' name='MemTotal' direction='out'/>"
1304 "                       <arg type='u' name='MemFree' direction='out'/>"
1305 "                       <arg type='u' name='MemCached' direction='out'/>"
1306 "                       <arg type='u' name='MemUsed' direction='out'/>"
1307 "                       <arg type='u' name='MemSwap' direction='out'/>"
1308 "               </method>"
1309 "               <method name='ReclaimMemory'>"
1310 "                       <arg type='i' name='ZeroOnSuccess' direction='out'/>"
1311 "               </method>"
1312 "               <method name='PrePoweroff'>"
1313 "                       <arg type='i' name='MinusOne' direction='out'/>"
1314 "               </method>"
1315 "               <method name='ProcExclude'>"
1316 "                       <arg type='s' name='Action' direction='in'/>"
1317 "                       <arg type='i' name='PID' direction='in'/>"
1318 "               </method>"
1319 /* Following functions are defined in proc-usage-stats.c */
1320 "               <method name='ProcMemoryUsage'>"
1321 "                       <arg type='ai' name='ProcList' direction='in'/>"
1322 "                       <arg type='a(iiiiiii)' name='MemoryUsage' direction='out'/>"
1323 "               </method>"
1324 "               <method name='ProcCpuUsage'>"
1325 "                       <arg type='ai' name='ProcList' direction='in'/>"
1326 "                       <arg type='a(ii)' name='CpuUsage' direction='out'/>"
1327 "               </method>"
1328 "               <method name='ProcSwapUsage'>"
1329 "                       <arg type='ai' name='ProcList' direction='in'/>"
1330 "                       <arg type='a(i)' name='SwapUsage' direction='out'/>"
1331 "               </method>"
1332 "               <method name='CheckAppStatus'>"
1333 "                       <arg type='i' name='Pid' direction='in'/>"
1334 "                       <arg type='s' name='Type' direction='in'/>"
1335 "                       <arg type='i' name='Pid' direction='out'/>"
1336 "                       <arg type='i' name='Detect' direction='out'/>"
1337 "                       <arg type='s' name='Appid' direction='out'/>"
1338 "               </method>"
1339 "               <method name='GetRamSize'>"
1340 "                       <arg type='u' name='TotalSizeKB' direction='out'/>"
1341 "               </method>"
1342 "       </interface>"
1343 "</node>";
1344
1345 static struct d_bus_method dbus_methods[] = {
1346         { "GetAppCpu", dbus_get_app_cpu },
1347         { "GetCpuList", dbus_get_cpu_list },
1348         { "GetCpuLists", dbus_get_cpu_lists },
1349         { "GetAppMemory", dbus_get_app_memory },
1350         { "GetMemoryList", dbus_get_memory_list },
1351         { "GetMemoryLists", dbus_get_memory_lists },
1352         { "GetMemInfo", dbus_get_meminfo },
1353         { "ReclaimMemory", dbus_reclaim_memory },
1354         { "PrePoweroff", dbus_pre_poweroff },
1355         { "ProcExclude", proc_dbus_exclude_method_handler},
1356 /* Following functions are defined in proc-usage-stats.c */
1357         { "ProcMemoryUsage", dbus_proc_memory_usage },
1358         { "ProcCpuUsage", dbus_proc_cpu_usage },
1359         { "CheckAppStatus", dbus_get_checkappstatus },
1360         { "GetRamSize", dbus_get_get_ram_size },
1361         { "ProcSwapUsage", dbus_proc_swap_usage },
1362         /* Add methods here */
1363 };
1364
1365 static const struct d_bus_signal dbus_signals[] = {
1366         /* RESOURCED DBUS */
1367         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1368             SIGNAL_PROC_ACTIVE, proc_dbus_active_signal_handler, NULL},
1369         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1370             SIGNAL_PROC_EXCLUDE, proc_dbus_exclude_signal_handler, NULL},
1371         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1372             SIGNAL_PROC_PRELAUNCH, proc_dbus_prelaunch_signal_handler, NULL},
1373         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1374             SIGNAL_PROC_SWEEP, proc_dbus_sweep_signal_handler, NULL},
1375         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1376             SIGNAL_PROC_WATCHDOG, proc_dbus_app_watchdog_handler, NULL},
1377         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1378             SIGNAL_PROC_SYSTEMSERVICE, proc_dbus_systemservice_handler, NULL},
1379         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1380             SIGNAL_PROC_EXCLUDEAPPID, proc_dbus_exclude_appid_signal_handler, NULL},
1381         {RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
1382             SIGNAL_PROC_SET_PRIORITY, proc_dbus_set_priority_signal_handler, NULL},
1383
1384         /* DEVICED DBUS */
1385         {DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
1386             SIGNAL_DEVICED_LCDON, proc_dbus_lcd_on, NULL},
1387         {DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
1388             SIGNAL_DEVICED_LCDOFF, proc_dbus_lcd_off, NULL},
1389         /* DEVICED_INTERFACE_POWEROFF / SIGNAL_DEVICED_CHANGESTATE left unhandled
1390            on purpose - DeviceD sends the signal earlier than supposed to. Nothing
1391            is lost though because at some point DeviceD also sends a SIGTERM,
1392            which is handled the same way (i.e. quits the main loop). */
1393         {DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF,
1394             SIGNAL_DEVICED_POWEROFF_STATE, poweroff_signal_handler, NULL},
1395         {DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
1396             SIGNAL_DEVICED_LOW_BATTERY, low_battery_signal_handler, NULL},
1397         {DUMP_SERVICE_OBJECT_PATH, DUMP_SERVICE_INTERFACE_NAME,
1398             SIGNAL_DUMP, proc_dbus_dump_handler, NULL},
1399         {DEVICED_PATH_TIME, DEVICED_INTERFACE_TIME,
1400             SIGNAL_DEVICED_SYSTEMTIME_CHANGED,
1401             systemtime_changed_signal_handler, NULL},
1402
1403         /* AMD DBUS */
1404         {AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME,
1405             SIGNAL_AMD_LAUNCH, proc_dbus_aul_launch, NULL},
1406         {AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME,
1407             SIGNAL_AMD_RESUME, proc_dbus_aul_resume, NULL},
1408         {AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME,
1409             SIGNAL_AMD_TERMINATE, proc_dbus_aul_terminate, NULL},
1410         {AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME,
1411             SIGNAL_AMD_STATE, proc_dbus_aul_changestate, NULL},
1412         {AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME,
1413             SIGNAL_AMD_GROUP, proc_dbus_aul_group, NULL},
1414         {AUL_APPSTATUS_OBJECT_PATH, AUL_APPSTATUS_INTERFACE_NAME,
1415             SIGNAL_AMD_TERMINATED, proc_dbus_aul_terminated, NULL},
1416         {AUL_SUSPEND_OBJECT_PATH, AUL_SUSPEND_INTERFACE_NAME,
1417             SIGNAL_AMD_SUSPNED, proc_dbus_suspend_hint, NULL},
1418
1419         /* BOOTING DBUS */
1420         {BOOTING_DONE_PATH, BOOTING_DONE_INTERFACE,
1421             SIGNAL_BOOTING_DONE, booting_done_signal_handler, NULL},
1422 };
1423
1424 static int proc_dbus_init(void *data)
1425 {
1426         resourced_ret_c ret;
1427
1428         /* start watchdog check timer for preveting ANR during booting */
1429         app_watchdog_check_timer = g_timeout_source_new_seconds(APP_WATCHDOG_TIMER_INTERVAL);
1430         g_source_set_callback(app_watchdog_check_timer, check_app_watchdog_cb, NULL, NULL);
1431         g_source_attach(app_watchdog_check_timer, NULL);
1432
1433         ret = d_bus_register_signals(dbus_signals, ARRAY_SIZE(dbus_signals));
1434         if (ret != RESOURCED_ERROR_NONE)
1435                 goto out;
1436
1437         ret = d_bus_register_methods(RESOURCED_PATH_PROCESS, dbus_methods_xml,
1438                         dbus_methods, ARRAY_SIZE(dbus_methods));
1439 out:
1440         return ret;
1441 }
1442
1443 static int proc_dbus_exit(void *data)
1444 {
1445         if (app_watchdog_check_timer)
1446                 g_source_destroy(app_watchdog_check_timer);
1447         return RESOURCED_ERROR_NONE;
1448 }
1449
1450 static const struct proc_module_ops proc_dbus_ops = {
1451         .name           = "PROC_DBUS",
1452         .init           = proc_dbus_init,
1453         .exit           = proc_dbus_exit,
1454 };
1455 PROC_MODULE_REGISTER(&proc_dbus_ops)