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