tizen 2.3 release
[kernel/api/system-resource.git] / src / proc-stat / proc-stat.c
1 /*
2  * resourced
3  *
4  * Library for getting process statistics
5  *
6  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28 #include <linux/limits.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <fcntl.h>
34 #include <dirent.h>
35 #include <ctype.h>
36 #include <unistd.h>
37
38 #include "macro.h"
39 #include "proc_stat.h"
40 #include "trace.h"
41 #include "proc-noti.h"
42 #include "const.h"
43
44 #define PROC_STAT_PATH "/proc/%d/stat"
45 #define PROC_STATM_PATH "/proc/%d/statm"
46 #define PROC_CMDLINE_PATH "/proc/%d/cmdline"
47
48 #ifndef TEST_IN_X86
49 #include <assert.h>
50 #else
51 #define assert(x) \
52 do { \
53         if (!(x)) { \
54                 printf("assertion %s %d\n", __FILE__ , __LINE__); \
55                 exit(-1); \
56         } \
57 } while (0)
58 #endif
59
60 API bool proc_stat_get_cpu_time_by_pid(pid_t pid, unsigned long *utime,
61                                        unsigned long *stime)
62 {
63         char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
64         FILE *fp;
65
66         assert(utime != NULL);
67         assert(stime != NULL);
68
69         sprintf(proc_path, PROC_STAT_PATH, pid);
70         fp = fopen(proc_path, "r");
71         if (fp == NULL)
72                 return false;
73
74         if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
75                 fclose(fp);
76                 return false;
77         }
78
79         if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
80                 fclose(fp);
81                 return false;
82         }
83
84         fclose(fp);
85
86         return true;
87 }
88
89
90 API bool proc_stat_get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
91 {
92         FILE *fp;
93         char proc_path[sizeof(PROC_STATM_PATH) + MAX_DEC_SIZE(int)] = {0};
94
95         sprintf(proc_path, PROC_STATM_PATH, pid);
96         fp = fopen(proc_path, "r");
97         if (fp == NULL)
98                 return false;
99
100         if (fscanf(fp, "%*s %d", rss) < 1) {
101                 fclose(fp);
102                 return false;
103         }
104
105         fclose(fp);
106
107         /* convert page to Kb */
108         *rss *= 4;
109         return true;
110 }
111
112
113 static int get_mem_size(char *buffer, const char *const items[], const int items_len[], const int items_cnt, unsigned int mem_size[])
114 {
115         char *p = buffer;
116         int num_found = 0;
117
118         while (*p && num_found < items_cnt) {
119                 int i = 0;
120                 while (i < items_cnt) {
121                         if (strncmp(p, items[i], items_len[i] - 1) == 0) {
122                                 /* the format of line is like this "MemTotal:             745696 kB" */
123                                 /* when it finds a item, skip the name of item */
124                                 p += items_len[i];
125
126                                 /* skip white space */
127                                 while (*p == ' ')
128                                         ++p;
129
130                                 char *num = p;
131
132                                 /* go to the immediate next of numerical value */
133                                 while (*p >= '0' && *p <= '9')
134                                         ++p;
135
136                                 /* at this time, [num,p) is the value of item */
137
138                                 /* insert null to p to parse [num,p] by atoi() */
139                                 if (*p != 0) {
140                                         *p = 0;
141                                         ++p;
142
143                                         /* when it is the end of buffer, to avoid out of buffer */
144                                         if (*p == 0)
145                                                 --p;
146                                 }
147                                 mem_size[i] = atoi(num);
148                                 num_found++;
149                                 break;
150                         }
151                         ++i;
152                 }
153                 ++p;
154         }
155
156         return num_found;
157 }
158
159
160 API bool proc_stat_get_total_mem_size(unsigned int *total_mem)
161 {
162         int fd = 0;
163         int len = 0;
164         char *buffer = NULL;
165         const int buffer_size = 4096;
166         static const char *const items[] = { "MemTotal:" };
167         static const int items_len[] = {sizeof("MemTotal:") };
168         unsigned int mem_size[1];
169         int num_found;
170
171         assert(total_mem != NULL);
172
173         fd = open("/proc/meminfo", O_RDONLY);
174         if (fd < 0)
175                 return false;
176
177         buffer = malloc(buffer_size);
178         assert(buffer != NULL);
179
180         len = read(fd, buffer, buffer_size - 1);
181         close(fd);
182
183         if (len < 0) {
184                 free(buffer);
185                 return false;
186         }
187
188         buffer[len] = 0;
189
190         /* to get the best search performance, the order of items should refelect the order of /proc/meminfo */
191         num_found = get_mem_size(buffer, items, items_len, 1 , mem_size);
192
193         free(buffer);
194
195         if (num_found < 1)
196                 return false;
197
198         /* total_mem = "MemTotal" */
199         *total_mem = mem_size[0] / 1024;
200
201         return true;
202 }
203
204
205 API bool proc_stat_get_free_mem_size(unsigned int *free_mem)
206 {
207         int fd = 0;
208         char *buffer = NULL;
209         const int buffer_size = 4096;
210         int len = 0;
211         static const char *const items[] = { "MemFree:", "Buffers:", "Cached:", "SwapCached:", "Shmem:" };
212         static const int items_len[] = { sizeof("MemFree:"), sizeof("Buffers:"), sizeof("Cached:"),
213                                                           sizeof("SwapCached:"), sizeof("Shmem:") };
214         static const int items_cnt = ARRAY_SIZE(items);
215         unsigned int mem_size[items_cnt];
216         int num_found;
217
218         assert(free_mem != NULL);
219
220         fd = open("/proc/meminfo", O_RDONLY);
221
222         if (fd < 0)
223                 return false;
224
225         buffer = malloc(buffer_size);
226         assert(buffer != NULL);
227
228         len = read(fd, buffer, buffer_size - 1);
229         close(fd);
230         buffer[len] = 0;
231
232
233         /* to get the best search performance, the order of items should refelect the order of /proc/meminfo */
234         num_found = get_mem_size(buffer, items, items_len, items_cnt, mem_size);
235
236         free(buffer);
237
238         if (num_found < items_cnt)
239                 return false;
240
241         /* free_mem = "MemFree" + "Buffers" + "Cached" + "SwapCache" - "Shmem" */
242         *free_mem = (mem_size[0] + mem_size[1] + mem_size[2] + mem_size[3] - mem_size[4]) / 1024;
243
244         return true;
245 }
246
247 static bool get_proc_cmdline(pid_t pid, char *cmdline)
248 {
249         assert(cmdline != NULL);
250
251         char buf[PATH_MAX];
252         char cmdline_path[sizeof(PROC_CMDLINE_PATH) + MAX_DEC_SIZE(int)] = {0};
253         char *filename;
254         FILE *fp;
255
256         sprintf(cmdline_path, PROC_CMDLINE_PATH, pid);
257         fp = fopen(cmdline_path, "r");
258         if (fp == NULL)
259                 return false;
260
261         if (fscanf(fp, "%s", buf) < 1) {
262                 fclose(fp);
263                 return false;
264         }
265         fclose(fp);
266
267
268         filename = strrchr(buf, '/');
269         if (filename == NULL)
270                 filename = buf;
271         else
272                 filename = filename + 1;
273
274         strncpy(cmdline, filename, NAME_MAX-1);
275
276         return true;
277 }
278
279 static bool get_proc_filename(pid_t pid, char *process_name)
280 {
281         FILE *fp;
282         char buf[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
283         char filename[PATH_MAX];
284
285         assert(process_name != NULL);
286
287         sprintf(buf, PROC_STAT_PATH, pid);
288         fp = fopen(buf, "r");
289
290         if (fp == NULL)
291                 return false;
292
293         if (fscanf(fp, "%*s (%[^)]", filename) < 1) {
294                 fclose(fp);
295                 return false;
296         }
297
298         strncpy(process_name, filename, NAME_MAX-1);
299         fclose(fp);
300
301         return true;
302 }
303
304 API bool proc_stat_get_name_by_pid(pid_t pid, char *name)
305 {
306
307         assert(name != NULL);
308
309         if (get_proc_cmdline(pid, name))
310                 return true;
311         else if (get_proc_filename(pid, name))
312                 return true;
313
314         return false;
315 }
316
317
318 static void diff_system_time(proc_stat_system_time *st_diff, proc_stat_system_time *st_a, proc_stat_system_time *st_b)
319 {
320         assert(st_diff != NULL);
321         assert(st_a != NULL);
322         assert(st_b != NULL);
323
324         st_diff->total_time = st_a->total_time - st_b->total_time;
325         st_diff->user_time = st_a->user_time - st_b->user_time;
326         st_diff->nice_time = st_a->nice_time - st_b->nice_time;
327         st_diff->system_time = st_a->system_time - st_b->system_time;
328         st_diff->idle_time = st_a->idle_time - st_b->idle_time;
329         st_diff->iowait_time = st_a->iowait_time - st_b->iowait_time;
330         st_diff->irq_time = st_a->irq_time - st_b->irq_time;
331         st_diff->softirq_time = st_a->softirq_time - st_b->softirq_time;
332 }
333
334 static bool get_system_time(proc_stat_system_time *st)
335 {
336         FILE *fp;
337
338         assert(st != NULL);
339
340         fp = fopen("/proc/stat", "r");
341         if (fp == NULL)
342                 return false;
343
344         if (fscanf(fp, "%*s %lld %lld %lld %lld %lld %lld %lld",
345                 &st->user_time, &st->nice_time, &st->system_time, &st->idle_time,
346                 &st->iowait_time, &st->irq_time, &st->softirq_time) < 1) {
347                 fclose(fp);
348                 return false;
349         }
350
351         fclose(fp);
352
353         st->total_time = st->user_time + st->nice_time + st->system_time + st->idle_time
354                                 + st->iowait_time + st->irq_time + st->softirq_time;
355
356         return true;
357 }
358
359
360
361 API bool proc_stat_get_system_time_diff(proc_stat_system_time *st_diff)
362 {
363         static proc_stat_system_time prev_st;
364         proc_stat_system_time cur_st;
365
366         assert(st_diff != NULL);
367
368         get_system_time(&cur_st);
369
370         if (prev_st.total_time == 0) {
371                 memset(st_diff, 0, sizeof(proc_stat_system_time));
372                 prev_st = cur_st;
373                 return false;
374         }
375
376         diff_system_time(st_diff, &cur_st, &prev_st);
377         prev_st = cur_st;
378
379         return (bool) (st_diff->total_time);
380 }
381
382
383 static int comapre_pid(const pid_t *pid_a, const pid_t *pid_b)
384 {
385         assert(pid_a != NULL);
386         assert(pid_b != NULL);
387
388         /* the process which has smaller number of pid is ordered ahead */
389         return (*pid_a - *pid_b);
390 }
391
392 /**
393  * @brief Get pids under /proc file system
394  *
395  * @param pids the pointer of GArray to store pids
396  * @return  true on success, false on failure.
397  *
398  * This function fills Garray instance with pids under /proc file system.
399  */
400
401 static bool get_pids(GArray *pids)
402 {
403         DIR *dirp;
404         struct dirent *entry;
405
406         assert(pids != NULL);
407
408         dirp = opendir("/proc");
409
410         if (dirp == NULL)
411                 return false;
412
413         while ((entry = readdir(dirp)) != NULL) {
414                 const char *p = entry->d_name;
415                 char *end;
416                 pid_t pid;
417
418                 while (*p) {
419                         if (*p < '0' || *p > '9')
420                                 break;
421                         p++;
422                 }
423
424                 if (*p != 0)
425                         continue;
426
427                 pid = strtol(entry->d_name, &end, 10);
428
429                 g_array_append_val(pids, pid);
430         }
431
432         closedir(dirp);
433         g_array_sort(pids, (GCompareFunc)comapre_pid);
434
435         return true;
436 }
437
438 API bool proc_stat_get_pids(pid_t **pids, int *cnt)
439 {
440         unsigned int i;
441         GArray *garray = NULL;
442
443         assert(pids != NULL);
444         assert(cnt != NULL);
445
446         garray = g_array_new(false, false, sizeof(pid_t));
447         g_return_val_if_fail(garray, false);
448
449         if (get_pids(garray) == false) {
450                 /* g_array_free is resistant to input NULL */
451                 g_array_free(garray, true);
452                 return false;
453         }
454
455         *pids = malloc(sizeof(pid_t) * garray->len);
456         assert(*pids != NULL);
457
458         *cnt = garray->len;
459
460         for (i = 0 ; i < garray->len; ++i)
461                 (*pids)[i] = g_array_index(garray, pid_t, i);
462
463         g_array_free(garray, true);
464
465         return true;
466 }
467
468
469 /**
470  * @brief Fill proc_infos with proc_stat_process_info instances which have process statistics , specially time difference each process spent in user mode and system mode between two consecutive its calls
471  *
472  * @param pids GArray instance which have current pids under /proc file system
473  * @param proc_infos the pointer of GArray instance to be filled with proc_stat_process_info instances which are matched with each pid in pids.
474  * @param terminated_proc_infos the pointer of GArray instance to be filled with proc_stat_process_info instances which were terminated between two consecutive its calls
475                   ,pass NULL if if this information is not necessary
476  * @return nothing
477  *
478  * This function fills proc_infos with proc_stat_process_info instances which have process statistics , specially time difference each process spent in user mode and system mode between two consecutive its calls
479  *
480  */
481
482 static void update_proc_infos(GArray *pids, GArray *proc_infos,
483                                                 GArray *terminated_proc_infos)
484 {
485         /* when this function is called first, we don't have basis
486         *  for time interval, so it is not valid.
487         */
488         static bool first = true;
489
490         unsigned int pids_cnt = 0;
491         unsigned int cur_pi_idx = 0;
492         proc_stat_process_info *pi = NULL;
493
494         unsigned int i;
495
496         assert(pids != NULL);
497         assert(proc_infos != NULL);
498
499         pids_cnt = pids->len;
500
501         /* with current pids, update proc_infos */
502         for (i = 0 ; i < pids_cnt; ++i) {
503                 unsigned long utime, stime;
504
505                 if (cur_pi_idx < proc_infos->len)
506                         pi = &g_array_index(proc_infos, proc_stat_process_info, cur_pi_idx);
507                 else
508                 /* current pid is out of proc_infos, so it is new pid. */
509                         pi = NULL;
510
511                 assert(i < pids->len);
512                 pid_t pid = g_array_index(pids, pid_t, i);
513
514                 if ((pi != NULL) && (pi->pid == pid)) {
515                         /* current pid is matched with proc_infos[curPsIdex],
516                         *  so update proc_infos[curPsIdex]
517                         */
518                         ++cur_pi_idx;
519
520                         pi->fresh = false; /* it is not new process */
521                         /* by now, we don't know whether it is valid or not,
522                         *  so mark it as invalid by default.
523                         */
524                         pi->valid = false;
525
526                         if (!(proc_stat_get_cpu_time_by_pid(pid, &utime, &stime) && proc_stat_get_mem_usage_by_pid(pid, &(pi->rss))))
527                                 continue;
528
529                         if ((pi->utime_prev == utime) && (pi->stime_prev == stime)) {
530                                 /* There is no diff in execution time, mark it as inactive. */
531                                 pi->utime_diff = 0;
532                                 pi->stime_diff = 0;
533                                 pi->active = false;
534                                 continue;
535                         } else {
536                                 pi->active = true; /* mark it as active */
537                         }
538                         /* update time related fields */
539                         pi->utime_diff = (utime - pi->utime_prev);
540                         pi->stime_diff = (stime - pi->stime_prev);
541                         pi->utime_prev = utime;
542                         pi->stime_prev = stime;
543
544                         pi->valid = true; /* mark it as valid */
545                 } else if ((pi == NULL) || (pi->pid > pid)) {
546                         /* in case of new process */
547                         proc_stat_process_info new_pi;
548
549                         new_pi.pid = pid;
550
551                         if (!(proc_stat_get_name_by_pid(pid, new_pi.name) && proc_stat_get_cpu_time_by_pid(pid, &utime, &stime) && proc_stat_get_mem_usage_by_pid(pid, &new_pi.rss)))
552                                 continue; /* in case of not getting information of current pid, skip it */
553
554                         new_pi.fresh = true; /* mark it as new (process) */
555                         new_pi.utime_prev = utime;
556                         new_pi.stime_prev = stime;
557                         new_pi.utime_diff = utime;
558                         new_pi.stime_diff = stime;
559
560                         if (first == false)
561                                 /* This process is created after the first call of update_proc_infos, so we know execution time of it.
562                                 *  Mark it as valid.
563                                 */
564                                 new_pi.valid = true;
565                         else
566                                 new_pi.valid = false;
567
568                         /* add it to proc_infos */
569                         g_array_insert_val(proc_infos, cur_pi_idx , new_pi);
570                         ++cur_pi_idx;
571                 } else {
572                         if (terminated_proc_infos != NULL) {
573                                 proc_stat_process_info terminated_pi;
574                                 terminated_pi = *pi;
575                                 g_array_append_val(terminated_proc_infos, terminated_pi);
576                         }
577
578                         /* in case of the process terminated, remove it from proc_infos */
579                         assert(cur_pi_idx < proc_infos->len);
580                         g_array_remove_index(proc_infos, cur_pi_idx);
581                         /* current pid should be compared again, so decrease loop count */
582                         --i;
583                 }
584
585         }
586
587         /* in case of the process terminated, remove it from proc_infos */
588         while (cur_pi_idx < proc_infos->len) {
589                 if (terminated_proc_infos != NULL) {
590                         proc_stat_process_info terminated_pi;
591
592                         assert(cur_pi_idx < proc_infos->len);
593                         terminated_pi = g_array_index(proc_infos, proc_stat_process_info, cur_pi_idx);
594                         g_array_append_val(terminated_proc_infos, terminated_pi);
595                 }
596
597                 assert(cur_pi_idx < proc_infos->len);
598                 g_array_remove_index(proc_infos, cur_pi_idx);
599         }
600
601         first = false;
602 }
603
604
605
606 static int compare_proc_info(const proc_stat_process_info *proc_info_a, const proc_stat_process_info *proc_info_b)
607 {
608         /*
609         * Firstly, long execution time process is ordered  ahead
610         * Secondly, newly created process is ordered ahead
611         */
612         unsigned long exec_time_a, exec_time_b;
613
614         assert(proc_info_a != NULL);
615         assert(proc_info_b != NULL);
616
617         exec_time_a = proc_info_a->utime_diff + proc_info_a->stime_diff;
618         exec_time_b = proc_info_b->utime_diff + proc_info_b->stime_diff;
619
620         if (exec_time_a != exec_time_b)
621                 return (exec_time_b - exec_time_a);
622
623         if (proc_info_a->fresh != proc_info_b->fresh)
624                 return ((int)(proc_info_b->fresh) - (int)(proc_info_a->fresh));
625
626         return 0;
627
628 }
629
630
631 /**
632  * @brief Extract valid proc_stat_process_info instances from proc_infos and fill valid_proc_infos with these instances
633  *
634  * @param proc_infos from which source to extract valid proc_stat_process_info instances
635  * @param valid_proc_infos GArray instance to be filled with valid proc_stat_process_info instances
636  * @param total_valid_proc_time to get the sum of the time spent by all valid proc_stat_process_info instance, pass NULL if if this information is not necessary
637  * @return  nothing
638  *
639  * This function extracts valid proc_stat_process_info instances from proc_infos and fills valid_proc_infos with these instances
640  */
641 static void pick_valid_proc_infos(GArray *proc_infos, GArray *valid_proc_infos, unsigned long *total_valid_proc_time)
642 {
643         unsigned int i;
644         proc_stat_process_info pi;
645
646         assert(valid_proc_infos != NULL);
647
648         if (total_valid_proc_time != NULL)
649                 *total_valid_proc_time = 0;
650
651         for (i = 0; i < proc_infos->len ; ++i) {
652                 assert(i < proc_infos->len);
653                 pi = g_array_index(proc_infos, proc_stat_process_info, i);
654
655                 if (pi.valid) {
656                         g_array_append_val(valid_proc_infos, pi);
657
658                         if (total_valid_proc_time != NULL)
659                                 *total_valid_proc_time += (pi.utime_diff+pi.stime_diff);
660                 }
661         }
662
663         g_array_sort(valid_proc_infos, (GCompareFunc)compare_proc_info);
664 }
665
666
667 static GArray *g_pids = NULL;
668 static GArray *proc_infos = NULL;
669
670 API void proc_stat_init(void)
671 {
672         g_pids = g_array_new(false, false, sizeof(pid_t));
673         proc_infos = g_array_new(false, false, sizeof(proc_stat_process_info));
674 }
675
676 API bool proc_stat_get_process_info(GArray *valid_proc_infos,
677                                     GArray *terminated_proc_infos,
678                                     unsigned long *total_valid_proc_time)
679 {
680         assert(valid_proc_infos != NULL);
681
682         g_array_set_size(g_pids, 0);
683
684         if (!get_pids(g_pids))
685                 return false;
686
687         update_proc_infos(g_pids, proc_infos, terminated_proc_infos);
688         pick_valid_proc_infos(proc_infos, valid_proc_infos, total_valid_proc_time);
689
690         return true;
691
692 }
693
694 API void proc_stat_finalize(void)
695 {
696         if (g_pids) {
697                 g_array_free(g_pids, true);
698                 g_pids = NULL;
699         }
700
701         if (proc_infos) {
702                 g_array_free(proc_infos, true);
703                 proc_infos = NULL;
704         }
705 }
706
707
708 API unsigned int proc_stat_get_gpu_clock(void)
709 {
710         FILE *fp;
711         unsigned int clock;
712
713         fp = fopen("/sys/module/mali/parameters/mali_gpu_clk", "r");
714         if (fp == NULL)
715                 return -1;
716
717         if (fscanf(fp, "%d", &clock) < 1) {
718                 fclose(fp);
719                 return -1;
720         }
721
722         fclose(fp);
723
724         return clock;
725 }
726
727 bool proc_stat_is_gpu_on(void)
728 {
729         if (proc_stat_get_gpu_clock() <= 0)
730                 return false;
731
732         return true;
733 }
734
735
736
737 static inline int send_int(int fd, int val)
738 {
739         return write(fd, &val, sizeof(int));
740 }
741
742 static inline int send_str(int fd, char *str)
743 {
744         int len;
745         int ret;
746         if (str == NULL) {
747                 len = 0;
748                 ret = write(fd, &len, sizeof(int));
749         } else {
750                 len = strlen(str);
751                 if (len > NOTI_MAXARGLEN)
752                         len = NOTI_MAXARGLEN;
753                 ret = write(fd, &len, sizeof(int));
754                 if (ret < 0) {
755                         _E("%s: write failed\n", __FUNCTION__);
756                         return ret;
757                 }
758                 ret = write(fd, str, len);
759         }
760         return ret;
761 }
762
763 static int send_socket(struct resourced_noti *msg, bool sync)
764 {
765         int client_len;
766         int client_sockfd;
767         int result = 0;
768         struct sockaddr_un clientaddr;
769         int i;
770         int ret;
771
772         client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
773         if (client_sockfd == -1) {
774                 _E("%s: socket create failed\n", __FUNCTION__);
775                 return -1;
776         }
777
778         bzero(&clientaddr, sizeof(clientaddr));
779         clientaddr.sun_family = AF_UNIX;
780         strncpy(clientaddr.sun_path, RESOURCED_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
781         client_len = sizeof(clientaddr);
782
783         if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) <
784             0) {
785                 _E("%s: connect failed\n", __FUNCTION__);
786                 close(client_sockfd);
787                 return RESOURCED_ERROR_FAIL;
788         }
789
790         send_int(client_sockfd, msg->pid);
791         send_int(client_sockfd, msg->type);
792         send_str(client_sockfd, msg->path);
793         send_int(client_sockfd, msg->argc);
794         for (i = 0; i < msg->argc; i++)
795                 send_str(client_sockfd, msg->argv[i]);
796
797         if (sync) {
798                 ret = read(client_sockfd, &result, sizeof(int));
799                 if (ret < 0) {
800                         _E("%s: read failed\n", __FUNCTION__);
801                         close(client_sockfd);
802                         return RESOURCED_ERROR_FAIL;
803                 }
804         }
805
806         close(client_sockfd);
807         return result;
808 }
809
810 static resourced_ret_c proc_cgroup_send_status(const int type, int num, ...)
811 {
812         struct resourced_noti *msg;
813         resourced_ret_c ret = RESOURCED_ERROR_NONE;
814         va_list argptr;
815
816         int i;
817         char *args = NULL;
818         bool sync = SYNC_OPERATION(type);
819
820         msg = malloc(sizeof(struct resourced_noti));
821
822         if (msg == NULL)
823                 return RESOURCED_ERROR_OUT_OF_MEMORY;
824
825         msg->pid = getpid();
826         msg->type = type;
827         msg->path = NULL;
828
829         msg->argc = num;
830         va_start(argptr, num);
831         /* it's just for debug purpose to test error reporting */
832         for (i = 0; i < num; i++) {
833                 args = va_arg(argptr, char *);
834                 msg->argv[i] = args;
835         }
836         va_end(argptr);
837
838         ret = send_socket(msg, sync);
839         if (ret < 0)
840                 ret = RESOURCED_ERROR_FAIL;
841
842         free(msg);
843
844         return ret;
845 }
846
847 API resourced_ret_c proc_cgroup_foregrd(void)
848 {
849         char buf[MAX_DEC_SIZE(int)];
850         snprintf(buf, sizeof(buf), "%d", getpid());
851         return proc_cgroup_send_status(PROC_CGROUP_SET_FOREGRD, 1, buf);
852 }
853
854 API resourced_ret_c proc_cgroup_backgrd(void)
855 {
856         char buf[MAX_DEC_SIZE(int)];
857         snprintf(buf, sizeof(buf), "%d", getpid());
858         return proc_cgroup_send_status(PROC_CGROUP_SET_BACKGRD, 1, buf);
859 }
860
861 API resourced_ret_c proc_cgroup_active(pid_t pid)
862 {
863         char buf[MAX_DEC_SIZE(int)];
864         snprintf(buf, sizeof(buf), "%d", pid);
865         return proc_cgroup_send_status(PROC_CGROUP_SET_ACTIVE, 1, buf);
866 }
867
868 API resourced_ret_c proc_cgroup_inactive(pid_t pid)
869 {
870         char buf[MAX_DEC_SIZE(int)];
871         snprintf(buf, sizeof(buf), "%d", pid);
872         return proc_cgroup_send_status(PROC_CGROUP_SET_INACTIVE, 1, buf);
873 }
874
875 API resourced_ret_c proc_group_change_status(int type, pid_t pid, char* app_id)
876 {
877         char pid_buf[MAX_DEC_SIZE(int)];
878         char appid_buf[NOTI_MAXARGLEN];
879         snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
880         snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
881         return proc_cgroup_send_status(type, 2, pid_buf, appid_buf);
882 }
883
884 API resourced_ret_c proc_cgroup_sweep_memory(void)
885 {
886         char buf[MAX_DEC_SIZE(int)];
887         snprintf(buf, sizeof(buf), "%d", getpid());
888         return proc_cgroup_send_status(PROC_CGROUP_GET_MEMSWEEP, 1, buf);
889 }
890
891 API resourced_ret_c proc_cgroup_launch(int type, pid_t pid, char* app_id, char* pkg_id)
892 {
893         char pid_buf[MAX_DEC_SIZE(int)];
894         char appid_buf[NOTI_MAXARGLEN];
895         char pkgid_buf[NOTI_MAXARGLEN];
896         snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
897         snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
898         snprintf(pkgid_buf, sizeof(pkgid_buf)-1, "%s", pkg_id);
899         return proc_cgroup_send_status(type, 3, pid_buf, appid_buf, pkgid_buf);
900 }
901