Use libsyscommon for dbus
[platform/core/api/runtime-info.git] / src / runtime_info_usage.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <limits.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <stdarg.h>
23
24 #include <libsyscommon/dbus-system.h>
25 #include <dlog.h>
26
27 #include <runtime_info.h>
28 #include <runtime_info_private.h>
29 #include <runtime_info-internal.h>
30
31 #include <glib.h>
32
33 #include <hal/device/hal-memory.h>
34
35 #define RESOURCED_BUS_NAME "org.tizen.resourced"
36 #define RESOURCED_USAGE_OBJECT_NAME "/Org/Tizen/ResourceD/Process"
37 #define RESOURCED_USAGE_INTERFACE_NAME "org.tizen.resourced.process"
38 #define DBUS_REPLY_TIMEOUT (120 * 1000)
39
40 typedef enum {
41         USAGE_TYPE_PROCESS_MEMORY,
42         USAGE_TYPE_PROCESS_CPU,
43         USAGE_TYPE_APP_MEMORY,
44         USAGE_TYPE_APP_CPU,
45         USAGE_TYPE_PROCESS_SWAP,
46 } runtime_info_usage_type_e;
47
48 typedef struct {
49         const char *method_name;
50         const char *caption;
51 } runtime_info_dbus_info_s;
52
53 /* The index of this array must be matched with runtime_info_usage_type_e */
54 static const runtime_info_dbus_info_s dbus_info[] = {
55         { "ProcMemoryUsage", "process memory" },
56         { "ProcCpuUsage", "process cpu" },
57         { "GetMemoryList", "all apps memory" },
58         { "GetCpuList", "all apps cpu" },
59         { "ProcSwapUsage", "process swap" },
60 };
61
62 #define ULONGtoINT(ulong)       (int)(MIN((ulong), INT_MAX))
63
64 /* ((val << 12) >> 10) = (val << 2) */
65 #define pagetoKiB(val) ((val) <= 0) ? 0 : (int)MIN(((long long)(val) << 2), INT_MAX)
66
67 /* Convert int array to GVariant("ai") */
68 static GVariant *runtime_info_append_args(int *args, int size)
69 {
70         GVariantBuilder builder, *sub_builder;
71         int i;
72
73         g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
74         sub_builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
75
76         for (i = 0; i < size; i++)
77                 g_variant_builder_add(sub_builder, "i", args[i]);
78
79         g_variant_builder_add_value(&builder, g_variant_new("ai", sub_builder));
80         g_variant_builder_unref(sub_builder);
81
82         return g_variant_builder_end(&builder);
83 }
84
85 /* Handler function which handles dbus related instructions
86  * Creates the method call to resourced and receives the reply (if successful)
87  * Return the received usage information (if received) else NULL to signify failed call to resourced
88  */
89 static GVariant *runtime_info_dbus_request_usage_info(runtime_info_usage_type_e type,
90                 int *pid, int size, int *error)
91 {
92         GVariant *args_in = NULL;
93         GVariant *args_out = NULL;
94         GVariant *usage;
95
96         /* Check parameter */
97         switch (type) {
98         case USAGE_TYPE_PROCESS_MEMORY:
99         case USAGE_TYPE_PROCESS_CPU:
100         case USAGE_TYPE_PROCESS_SWAP:
101                 if (!pid || size <= 0) {
102                         //LCOV_EXCL_START : system error
103                         _E("INVALID_PARAMETER(0x%08x): pid list cannot be null",
104                                         RUNTIME_INFO_ERROR_INVALID_PARAMETER);
105                         if (error)
106                                 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
107                         return NULL;
108                         //LCOV_EXCL_STOP
109                 }
110                 /* Fall through */
111         case USAGE_TYPE_APP_MEMORY:
112         case USAGE_TYPE_APP_CPU:
113                 if (!error) {
114                         //LCOV_EXCL_START : system error
115                         _E("INVALID_PARAMETER(0x%08x): error parameter cannot be null",
116                                         RUNTIME_INFO_ERROR_INVALID_PARAMETER);
117                         return NULL;
118                         //LCOV_EXCL_STOP
119                 }
120                 break;
121         default:
122                 //LCOV_EXCL_START : system error
123                 _E("INVALID_PARAMETER(0x%08x): invalid type parameter",
124                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
125                 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
126                 return NULL;
127                 //LCOV_EXCL_STOP
128         }
129
130         /* Make argument for requesting */
131         switch (type) {
132         case USAGE_TYPE_PROCESS_MEMORY:
133         case USAGE_TYPE_PROCESS_CPU:
134         case USAGE_TYPE_PROCESS_SWAP:
135                 _D("Process %d: received query to get %s usage of %d processes",
136                                 getpid(), dbus_info[type].caption, size);
137                 args_in = runtime_info_append_args(pid, size);
138                 if (!args_in) {
139                         //LCOV_EXCL_START : system error
140                         _E("DBUS_METHOD_CALL: not able to append pid array to message");
141                         *error = RUNTIME_INFO_ERROR_IO_ERROR;
142                         return NULL;
143                         //LCOV_EXCL_STOP
144                 }
145                 break;
146         case USAGE_TYPE_APP_MEMORY:
147         case USAGE_TYPE_APP_CPU:
148                 _D("Process %d: received query to get %s usage of all apps",
149                                 getpid(), dbus_info[type].caption);
150                 args_in = NULL;
151                 break;
152         }
153
154         _D("Process %d: Sending dbus message to resourced for %s info",
155                         getpid(), dbus_info[type].caption);
156         args_out = dbus_handle_method_sync_with_reply_var(RESOURCED_BUS_NAME,
157                                 RESOURCED_USAGE_OBJECT_NAME,
158                                 RESOURCED_USAGE_INTERFACE_NAME,
159                                 dbus_info[type].method_name,
160                                 args_in);
161
162         if (!args_out) {
163                 //LCOV_EXCL_START : system error
164                 _E("DBUS_METHOD_CALL: not able to send message");
165
166                 return NULL;
167                 //LCOV_EXCL_STOP
168         }
169
170         usage = g_variant_get_child_value(args_out, 0);
171         g_variant_unref(args_out);
172
173         return usage;
174 }
175
176 static int runtime_info_get_all_apps_usage(runtime_info_usage_type_e type,
177                                                                                 app_usage_h *handle)
178 {
179         int i;
180         int error;
181         unsigned int len;
182         struct app_usages_s *usages;
183         GVariant *reply;
184         GVariantIter iter;
185
186         if (!handle) {
187                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
188                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
189                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
190         }
191
192         reply = runtime_info_dbus_request_usage_info(type, NULL, 0, &error);
193         if (!reply) {
194                 //LCOV_EXCL_START : system error
195                 _E("DBUS_METHOD_CALL: call to resourced not successful");
196                 return error;
197                 //LCOV_EXCL_STOP
198         }
199
200         /* Check whether the received usage has expected format or not */
201         if (g_strcmp0(g_variant_get_type_string(reply), "a(su)")) {
202                 //LCOV_EXCL_START : system error
203                 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
204                 g_variant_unref(reply);
205                 return RUNTIME_INFO_ERROR_REMOTE_IO;
206                 //LCOV_EXCL_STOP
207         }
208
209         /* Populate the entries of info array using the data received from resourced */
210         len = g_variant_n_children(reply);
211         if (len <= 0) {
212                 _E("NO_DATA(0x%08x) : there is no registered app", RUNTIME_INFO_ERROR_NO_DATA);
213                 g_variant_unref(reply);
214                 return RUNTIME_INFO_ERROR_NO_DATA;
215         }
216
217         usages = calloc(1, sizeof(struct app_usages_s));
218         if (!usages) {
219                 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
220                 g_variant_unref(reply);
221                 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
222         }
223
224         usages->len = (int)len;
225
226         usages->list = calloc(len, sizeof(struct app_usage_s));
227         if (!usages->list) {
228                 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
229                 free(usages);
230                 g_variant_unref(reply);
231                 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
232         }
233
234         g_variant_iter_init(&iter, reply);
235         for (i = 0; i < len; i++)
236                 g_variant_iter_next(&iter, "(su)",
237                                 &(usages->list[i].appid), &(usages->list[i].usage));
238         g_variant_unref(reply);
239
240         *handle = usages;
241
242         return RUNTIME_INFO_ERROR_NONE;
243 }
244
245 API int runtime_info_get_system_memory_info(runtime_memory_info_s *info)
246 {
247         FILE *fp;
248         char buf[256];
249         unsigned long value;
250         unsigned long mem_total = 0;
251         unsigned long mem_free = 0;
252         unsigned long cached = 0;
253         unsigned long mem_available = 0;
254         unsigned long swap_total = 0;
255         unsigned long swap_free = 0;
256
257         if (info == NULL) {
258                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
259                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
260                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
261         }
262
263         swap_total = swap_free = mem_available = 0;
264
265         fp = fopen("/proc/meminfo", "r");
266         if (fp == NULL) {
267                 _E("IO_ERROR(0x%08x) : failed to open file to read memory usage",
268                                 RUNTIME_INFO_ERROR_IO_ERROR);
269                 return RUNTIME_INFO_ERROR_IO_ERROR;
270         }
271
272         info->total = info->free = info->cache = 0;
273         while (fgets(buf, sizeof(buf), fp) != NULL) {
274                 if (sscanf(buf, "MemTotal: %lu", &mem_total) == 1)
275                         info->total = ULONGtoINT(mem_total);
276                 else if (sscanf(buf, "MemFree: %lu", &mem_free) == 1)
277                         info->free = ULONGtoINT(mem_free);
278                 else if (sscanf(buf, "Cached: %lu", &cached) == 1)
279                         info->cache = ULONGtoINT(cached);
280                 else if (sscanf(buf, "MemAvailable: %lu", &value) == 1)
281                         mem_available = value;
282                 else if (sscanf(buf, "SwapTotal: %lu", &value) == 1)
283                         swap_total = value;
284                 else if (sscanf(buf, "SwapFree: %lu", &value) == 1)
285                         swap_free = value;
286         }
287         fclose(fp);
288
289         if (mem_available > 0) {
290                 if (mem_total > mem_available)
291                         info->used = ULONGtoINT(mem_total - mem_available);
292                 else
293                         info->used = 0;
294         } else {
295                 if (mem_total > mem_free && mem_total - mem_free > cached)
296                         info->used = ULONGtoINT(mem_total - mem_free - cached);
297                 else
298                         info->used = 0;
299         }
300
301         info->swap = (swap_total > swap_free) ? ULONGtoINT(swap_total - swap_free) : 0;
302
303         return RUNTIME_INFO_ERROR_NONE;
304 }
305
306 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
307 {
308         int i;
309         int error;
310         GVariant *usages;
311         GVariantIter iter;
312
313         if (!pid || size <= 0) {
314                 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
315                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
316                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
317         }
318
319         if (!info) {
320                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
321                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
322                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
323         }
324
325         *info = NULL;
326
327         /* Get the needed information from resourced daemon using dbus */
328         usages = runtime_info_dbus_request_usage_info(USAGE_TYPE_PROCESS_MEMORY, pid, size, &error);
329         if (!usages) {
330                 //LCOV_EXCL_START : system error
331                 _E("DBUS_METHOD_CALL: call to resourced not successful");
332                 return error;
333                 //LCOV_EXCL_STOP
334         }
335
336         /* Check whether the received usage has expected format or not */
337         if (g_strcmp0(g_variant_get_type_string(usages), "a(iiiiiii)") ||
338                         g_variant_n_children(usages) != size) {
339                 //LCOV_EXCL_START : system error
340                 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
341                 g_variant_unref(usages);
342                 return RUNTIME_INFO_ERROR_REMOTE_IO;
343                 //LCOV_EXCL_STOP
344         }
345
346         /* Populate the entries of info array using the data received from resourced */
347         *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s));
348         if (!(*info)) {
349                 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
350                 g_variant_unref(usages);
351                 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
352         }
353
354         g_variant_iter_init(&iter, usages);
355         for (i = 0; i < size; i++)
356                 g_variant_iter_next(&iter, "(iiiiiii)",
357                                 &((*info)[i].vsz),
358                                 &((*info)[i].rss),
359                                 &((*info)[i].pss),
360                                 &((*info)[i].shared_clean),
361                                 &((*info)[i].shared_dirty),
362                                 &((*info)[i].private_clean),
363                                 &((*info)[i].private_dirty));
364
365         g_variant_unref(usages);
366
367         return RUNTIME_INFO_ERROR_NONE;
368 }
369
370 static runtime_info_error_e hal_error_to_runtime_info_error(int err)
371 {
372         switch (err) {
373         case 0:
374                 return RUNTIME_INFO_ERROR_NONE;
375         case -EINVAL:
376                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
377         case -ENOMEM:
378                 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
379         case -EIO:
380         case -ENOENT:
381                 return RUNTIME_INFO_ERROR_IO_ERROR;
382         case -EPERM:
383         case -EACCES:
384                 return RUNTIME_INFO_ERROR_PERMISSION_DENIED;
385         case -ENOTSUP:
386                 return RUNTIME_INFO_ERROR_NOT_SUPPORTED;
387         default:
388                 // TODO: what is the runtime-info error for this default case?
389                 return RUNTIME_INFO_ERROR_NO_DATA;
390         }
391 }
392
393 static int get_process_memory_info_direct(int *pid, int size, process_memory_info_key_e key, int **info)
394 {
395         int ret, i;
396         struct gpu_info gpu_info;
397         struct gem_info gem_info;
398         int *result;
399         int err = RUNTIME_INFO_ERROR_NONE;
400
401         result = (int *)calloc(size, sizeof(int));
402         if (!result) {
403                 err = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
404                 goto out;
405         }
406
407         switch (key) {
408         case RUNTIME_INFO_PROC_MEMORY_GPU:
409                 for (i = 0; i < size; ++i) {
410                         ret = hal_device_memory_get_gpu_info(pid[i], &gpu_info);
411                         if (ret != 0) {
412                                 err = hal_error_to_runtime_info_error(ret);
413                                 goto out;
414                         }
415                         result[i] = gpu_info.used_pages;
416                 }
417                 *info = result;
418                 break;
419         case RUNTIME_INFO_PROC_MEMORY_GEM_RSS:
420                 for (i = 0; i < size; ++i) {
421                         ret = hal_device_memory_get_gem_info(pid[i], &gem_info);
422                         if (ret != 0) {
423                                 err = hal_error_to_runtime_info_error(ret);
424                                 goto out;
425                         }
426                         result[i] = gem_info.rss;
427                 }
428                 *info = result;
429                 break;
430         default:
431                 err = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
432                 break;
433         }
434
435 out:
436         if (err != RUNTIME_INFO_ERROR_NONE)
437                 free(result);
438
439         return err;
440 }
441
442 static int get_process_memory_swap_info(int *pid, int size, int **info)
443 {
444     int i, temp;
445     int error;
446     GVariant *usages;
447     GVariantIter iter;
448
449     if (!pid || size <= 0) {
450         _E("INVALID_PARAMETER(0x%08x) : invalid input param",
451                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
452         return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
453     }
454
455     if (!info) {
456         _E("INVALID_PARAMETER(0x%08x) : invalid output param",
457                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
458         return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
459     }
460
461     *info = NULL;
462
463     /* Get the needed information from resourced daemon using dbus */
464     usages = runtime_info_dbus_request_usage_info(USAGE_TYPE_PROCESS_SWAP, pid, size, &error);
465     if (!usages) {
466         //LCOV_EXCL_START : system error
467         _E("DBUS_METHOD_CALL: call to resourced not successful");
468         return error;
469         //LCOV_EXCL_STOP
470     }
471
472     /* Check whether the received usage has expected format or not */
473     if (g_strcmp0(g_variant_get_type_string(usages), "a(i)") ||
474             g_variant_n_children(usages) != size) {
475         //LCOV_EXCL_START : system error
476         _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
477         g_variant_unref(usages);
478         return RUNTIME_INFO_ERROR_REMOTE_IO;
479         //LCOV_EXCL_STOP
480     }
481
482     /* Populate the entries of info array using the data received from resourced */
483         *info = (int *)malloc(size * sizeof(int));
484     if (!(*info)) {
485         _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
486         g_variant_unref(usages);
487         return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
488     }
489
490     g_variant_iter_init(&iter, usages);
491     for (i = 0; i < size; i++) {
492         g_variant_iter_next(&iter, "(i)", &temp);
493                 (*info)[i] = temp;
494         }
495
496     g_variant_unref(usages);
497
498     return RUNTIME_INFO_ERROR_NONE;
499 }
500
501 static int get_process_memory_info(int *pid, int size, process_memory_info_key_e key, int **info)
502 {
503         int i;
504         int ret;
505         int *result;
506         process_memory_info_s *base = NULL;
507
508         ret = RUNTIME_INFO_ERROR_NONE;
509
510         result = (int *)calloc(size, sizeof(int));
511         if (!result) {
512                 ret = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
513                 goto out;
514         }
515
516         ret = runtime_info_get_process_memory_info(pid, size, &base);
517         if (ret != RUNTIME_INFO_ERROR_NONE)
518                 goto out;
519
520         switch (key) {
521         case RUNTIME_INFO_PROC_MEMORY_VSZ:
522                 for (i = 0; i < size; ++i)
523                         result[i] = base[i].vsz;
524                 break;
525         case RUNTIME_INFO_PROC_MEMORY_RSS:
526                 for (i = 0; i < size; ++i)
527                         result[i] = base[i].rss;
528                 break;
529         case RUNTIME_INFO_PROC_MEMORY_PSS:
530                 for (i = 0; i < size; ++i)
531                         result[i] = base[i].pss;
532                 break;
533         case RUNTIME_INFO_PROC_MEMORY_SHARED_CLEAN:
534                 for (i = 0; i < size; ++i)
535                         result[i] = base[i].shared_clean;
536                 break;
537         case RUNTIME_INFO_PROC_MEMORY_SHARED_DIRTY:
538                 for (i = 0; i < size; ++i)
539                         result[i] = base[i].shared_dirty;
540                 break;
541         case RUNTIME_INFO_PROC_MEMORY_PRIVATE_CLEAN:
542                 for (i = 0; i < size; ++i)
543                         result[i] = base[i].private_clean;
544                 break;
545         case RUNTIME_INFO_PROC_MEMORY_PRIVATE_DIRTY:
546                 for (i = 0; i < size; ++i)
547                         result[i] = base[i].private_dirty;
548                 break;
549         default:
550                 ret = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
551                 goto out;
552         }
553
554         *info = result;
555
556 out:
557         if (ret != RUNTIME_INFO_ERROR_NONE)
558                 free(result);
559         free(base);
560
561         return ret;
562 }
563
564 API int runtime_info_get_process_memory_value_int(int *pid, int size, process_memory_info_key_e key, int **info)
565 {
566         switch (key) {
567         case RUNTIME_INFO_PROC_MEMORY_GPU:
568         case RUNTIME_INFO_PROC_MEMORY_GEM_RSS:
569                 return get_process_memory_info_direct(pid, size, key, info);
570         case RUNTIME_INFO_PROC_MEMORY_SWAP:
571                 return get_process_memory_swap_info(pid, size, info);
572         case RUNTIME_INFO_PROC_MEMORY_VSZ:
573         case RUNTIME_INFO_PROC_MEMORY_RSS:
574         case RUNTIME_INFO_PROC_MEMORY_PSS:
575         case RUNTIME_INFO_PROC_MEMORY_SHARED_CLEAN:
576         case RUNTIME_INFO_PROC_MEMORY_SHARED_DIRTY:
577         case RUNTIME_INFO_PROC_MEMORY_PRIVATE_CLEAN:
578         case RUNTIME_INFO_PROC_MEMORY_PRIVATE_DIRTY:
579                 return get_process_memory_info(pid, size, key, info);
580         default:
581                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
582         }
583 }
584
585 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
586 {
587         FILE *cpuinfo_fp;
588         char buf[256];
589         unsigned long long user = 0;
590         unsigned long long nice = 0;
591         unsigned long long system = 0;
592         unsigned long long idle = 0;
593         unsigned long long iowait = 0;
594         unsigned long long irq = 0;
595         unsigned long long softirq = 0;
596         unsigned long long total_uptime = 0;
597
598         if (usage == NULL) {
599                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
600                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
601                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
602         }
603
604         cpuinfo_fp = fopen("/proc/stat", "r");
605         if (cpuinfo_fp == NULL) {
606                 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
607                                 RUNTIME_INFO_ERROR_IO_ERROR);
608                 return RUNTIME_INFO_ERROR_IO_ERROR;
609         }
610
611         while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
612                 if (!strncmp(buf, "cpu ", 4) &&
613                     sscanf(buf + 4, "%llu %llu %llu %llu %llu %llu %llu",
614                                 &user, &nice, &system, &idle,
615                                 &iowait, &irq, &softirq) == 7)
616                         break;
617         }
618         fclose(cpuinfo_fp);
619
620         total_uptime = user + nice + system + idle + iowait + irq + softirq;
621
622         if (total_uptime > 0) {
623                 usage->user = (double)user * 100 / total_uptime;
624                 usage->nice = (double)nice * 100 / total_uptime;
625                 usage->system = (double)system * 100 / total_uptime;
626                 usage->iowait = (double)iowait * 100 / total_uptime;
627         } else {
628                 usage->user = 0;
629                 usage->nice = 0;
630                 usage->system = 0;
631                 usage->iowait = 0;
632         }
633
634         return RUNTIME_INFO_ERROR_NONE;
635 }
636
637 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
638 {
639         int i;
640         int error;
641         GVariant *usages;
642         GVariantIter iter;
643
644         if (!pid || size <= 0) {
645                 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
646                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
647                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
648         }
649
650         if (!usage) {
651                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
652                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
653                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
654         }
655
656         *usage = NULL;
657
658         /* Get the needed information from resourced daemon using dbus */
659         usages = runtime_info_dbus_request_usage_info(USAGE_TYPE_PROCESS_CPU, pid, size, &error);
660         if (!usages) {
661                 //LCOV_EXCL_START : system error
662                 _E("DBUS_METHOD_CALL: call to resourced not successful");
663                 return error;
664                 //LCOV_EXCL_STOP
665         }
666
667         /* Check whether the received usage has expected format or not */
668         if (g_strcmp0(g_variant_get_type_string(usages), "a(ii)") ||
669                         g_variant_n_children(usages) != size) {
670                 //LCOV_EXCL_START : system error
671                 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
672                 g_variant_unref(usages);
673                 return RUNTIME_INFO_ERROR_REMOTE_IO;
674                 //LCOV_EXCL_STOP
675         }
676
677         /* Populate the entries of info array using the data received from resourced */
678         *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
679         if (!(*usage)) {
680                 //LCOV_EXCL_START : system error
681                 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
682                 g_variant_unref(usages);
683                 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
684                 //LCOV_EXCL_STOP
685         }
686
687         g_variant_iter_init(&iter, usages);
688         for (i = 0; i < size; i++)
689                 g_variant_iter_next(&iter, "(ii)", &((*usage)[i].utime), &((*usage)[i].stime));
690
691         g_variant_unref(usages);
692
693         return RUNTIME_INFO_ERROR_NONE;
694 }
695
696 API int runtime_info_get_processor_count(int *num_core)
697 {
698         FILE *cpuinfo_fp;
699         int buf;
700         int result;
701
702         if (!num_core) {
703                 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
704                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
705                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
706         }
707
708         cpuinfo_fp = fopen("/sys/devices/system/cpu/possible", "r");
709         if (cpuinfo_fp == NULL) {
710                 //LCOV_EXCL_START : system error
711                 _E("IO_ERROR(0x%08x) : failed to open file to read cpu information",
712                                 RUNTIME_INFO_ERROR_IO_ERROR);
713                 return RUNTIME_INFO_ERROR_IO_ERROR;
714                 //LCOV_EXCL_STOP
715         }
716
717         if (!fscanf(cpuinfo_fp, "%d-%d", &buf, &result)) {
718                 //LCOV_EXCL_START : system error
719                 _E("IO_ERROR(0x%08x) : there is no information in the system file",
720                                 RUNTIME_INFO_ERROR_IO_ERROR);
721                 fclose(cpuinfo_fp);
722                 return RUNTIME_INFO_ERROR_IO_ERROR;
723                 //LCOV_EXCL_STOP
724         }
725
726         *num_core = result + 1;
727
728         fclose(cpuinfo_fp);
729         return RUNTIME_INFO_ERROR_NONE;
730 }
731
732 API int runtime_info_get_processor_current_frequency(int core_idx, int *cpu_freq)
733 {
734         int num_core;
735
736         if (runtime_info_get_processor_count(&num_core)
737                         != RUNTIME_INFO_ERROR_NONE) {
738                 _E("runtime_info_get_processor_count is failed");
739                 return RUNTIME_INFO_ERROR_IO_ERROR;
740         }
741
742         if (core_idx < 0 || core_idx >= num_core) {
743                 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
744                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
745                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
746         }
747
748         if (!cpu_freq) {
749                 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
750                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
751                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
752         }
753
754         if (runtime_info_get_frequency_cpufreq(core_idx, "cur", cpu_freq)
755                         != RUNTIME_INFO_ERROR_NONE) {
756                 //LCOV_EXCL_START : system error
757                 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
758
759                 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
760                 case RUNTIME_INFO_ERROR_NONE:
761                         _I("Notice : it is max CPU frequency");
762                         break;
763                 case RUNTIME_INFO_ERROR_NO_DATA:
764                         _E("This system doesn't support MHz information in the cpuinfo");
765                         return RUNTIME_INFO_ERROR_NO_DATA;
766                 default:
767                         _E("Fail to get current CPU frequency");
768                         return RUNTIME_INFO_ERROR_IO_ERROR;
769                 };
770                 //LCOV_EXCL_STOP
771         }
772
773         return RUNTIME_INFO_ERROR_NONE;
774 }
775
776 API int runtime_info_get_processor_max_frequency(int core_idx, int *cpu_freq)
777 {
778         int num_core;
779
780         if (runtime_info_get_processor_count(&num_core)
781                         != RUNTIME_INFO_ERROR_NONE) {
782                 _E("runtime_info_get_processor_count is failed");
783                 return RUNTIME_INFO_ERROR_IO_ERROR;
784         }
785
786         if (core_idx < 0 || core_idx >= num_core) {
787                 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
788                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
789                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
790         }
791
792         if (!cpu_freq) {
793                 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
794                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
795                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
796         }
797
798         if (runtime_info_get_frequency_cpufreq(core_idx, "max", cpu_freq)
799                         != RUNTIME_INFO_ERROR_NONE) {
800                 //LCOV_EXCL_START : system error
801                 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
802
803                 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
804                 case RUNTIME_INFO_ERROR_NONE:
805                         break;
806                 case RUNTIME_INFO_ERROR_NO_DATA:
807                         _E("This system doesn't support MHz information in the cpuinfo");
808                         return RUNTIME_INFO_ERROR_NO_DATA;
809                 default:
810                         _E("Fail to get current CPU frequency");
811                         return RUNTIME_INFO_ERROR_IO_ERROR;
812                 };
813                 //LCOV_EXCL_STOP
814         }
815
816         return RUNTIME_INFO_ERROR_NONE;
817 }
818
819 API int runtime_info_get_physical_memory_size(int *size)
820 {
821         char buf[256];
822         unsigned long value;
823         int sum;
824         FILE *fp = fopen("/proc/zoneinfo", "r");
825         if (!fp) {
826                 _E("IO_ERROR(0x%08x) : failed to open file to read memory size",
827                                 RUNTIME_INFO_ERROR_IO_ERROR);
828                 return RUNTIME_INFO_ERROR_IO_ERROR;
829         }
830
831         if (!size) {
832                 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
833                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
834                 fclose(fp);
835                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
836         }
837
838         sum = 0;
839         while (fgets(buf, sizeof(buf), fp) != NULL)
840                 if (sscanf(buf, " spanned %lu", &value) == 1)
841                         sum += value;
842         *size = pagetoKiB(sum);
843
844         fclose(fp);
845
846         return RUNTIME_INFO_ERROR_NONE;
847 }
848
849 API int runtime_info_app_usage_destroy(app_usage_h handle)
850 {
851         int i;
852         struct app_usage_s *list;
853         struct app_usages_s *usages = handle;
854
855         if (!usages) {
856                 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
857                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
858                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
859         }
860
861         list = usages->list;
862         if (list) {
863                 for (i = 0; i < usages->len; i++)
864                         if (list[i].appid)
865                                 free(list[i].appid);
866         }
867
868         free(list);
869         free(usages);
870
871         return RUNTIME_INFO_ERROR_NONE;
872 }
873
874 API int runtime_info_app_usage_get_count(app_usage_h handle, int *count)
875 {
876         struct app_usages_s *usages = handle;
877
878         if (!usages) {
879                 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
880                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
881                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
882         }
883
884         if (!count) {
885                 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
886                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
887                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
888         }
889
890         *count = usages->len;
891
892         return RUNTIME_INFO_ERROR_NONE;
893 }
894
895 API int runtime_info_app_usage_get_appid(app_usage_h handle, int index, char **appid)
896 {
897         struct app_usages_s *usages = handle;
898
899         if (!usages || index < 0 || index >= usages->len) {
900                 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
901                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
902                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
903         }
904
905         if (!appid) {
906                 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
907                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
908                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
909         }
910
911         *appid = strndup(usages->list[index].appid, strlen(usages->list[index].appid));
912
913         return RUNTIME_INFO_ERROR_NONE;
914 }
915
916 API int runtime_info_app_usage_get_usage(app_usage_h handle, int index, unsigned int *usage)
917 {
918         struct app_usages_s *usages = handle;
919
920         if (!usages || index < 0 || index >= usages->len) {
921                 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
922                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
923                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
924         }
925
926         if (!usage) {
927                 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
928                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
929                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
930         }
931
932         *usage = usages->list[index].usage;
933
934         return RUNTIME_INFO_ERROR_NONE;
935 }
936
937 API int runtime_info_get_all_apps_memory_usage(app_usage_h *usage)
938 {
939         return runtime_info_get_all_apps_usage(USAGE_TYPE_APP_MEMORY, usage);
940 }
941
942 API int runtime_info_get_all_apps_cpu_rate(app_usage_h *rate)
943 {
944         return runtime_info_get_all_apps_usage(USAGE_TYPE_APP_CPU, rate);
945 }