2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <runtime_info.h>
26 #include <runtime_info_private.h>
31 #define RESOURCED_BUS_NAME "org.tizen.resourced"
32 #define RESOURCED_USAGE_OBJECT_NAME "/Org/Tizen/ResourceD/Process"
33 #define RESOURCED_USAGE_INTERFACE_NAME "org.tizen.resourced.process"
34 #define DBUS_REPLY_TIMEOUT (120 * 1000)
37 USAGE_TYPE_PROCESS_MEMORY,
38 USAGE_TYPE_PROCESS_CPU,
39 USAGE_TYPE_APP_MEMORY,
41 } runtime_info_usage_type_e;
44 const char *method_name;
46 } runtime_info_dbus_info_s;
48 /* The index of this array must be matched with runtime_info_usage_type_e */
49 static const runtime_info_dbus_info_s dbus_info[] = {
50 { "ProcMemoryUsage", "process memory" },
51 { "ProcCpuUsage", "process cpu" },
52 { "GetMemoryList", "all apps memory" },
53 { "GetCpuList", "all apps cpu" },
56 #define ULONGtoINT(ulong) (int)(MIN((ulong), INT_MAX))
58 /* ((val << 12) >> 10) = (val << 2) */
59 #define pagetoKiB(val) ((val) <= 0) ? 0 : (int)MIN(((long long)(val) << 2), INT_MAX)
61 /* Convert int array to GVariant("ai") */
62 static GVariant *runtime_info_append_args(int *args, int size)
64 GVariantBuilder builder, *sub_builder;
67 g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
68 sub_builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
70 for (i = 0; i < size; i++)
71 g_variant_builder_add(sub_builder, "i", args[i]);
73 g_variant_builder_add_value(&builder, g_variant_new("ai", sub_builder));
74 g_variant_builder_unref(sub_builder);
76 return g_variant_builder_end(&builder);
79 /* Handler function which handles dbus related instructions
80 * Creates the method call to resourced and receives the reply (if successful)
81 * Return the received usage information (if received) else NULL to signify failed call to resourced
83 static GVariant *runtime_info_dbus_request_usage_info(runtime_info_usage_type_e type,
84 int *pid, int size, int *error)
86 static GDBusConnection *conn;
88 GVariant *args_in = NULL;
89 GVariant *args_out = NULL;
94 case USAGE_TYPE_PROCESS_MEMORY:
95 case USAGE_TYPE_PROCESS_CPU:
96 if (!pid || size <= 0) {
97 //LCOV_EXCL_START : system error
98 _E("INVALID_PARAMETER(0x%08x): pid list cannot be null",
99 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
101 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
106 case USAGE_TYPE_APP_MEMORY:
107 case USAGE_TYPE_APP_CPU:
109 //LCOV_EXCL_START : system error
110 _E("INVALID_PARAMETER(0x%08x): error parameter cannot be null",
111 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
117 //LCOV_EXCL_START : system error
118 _E("INVALID_PARAMETER(0x%08x): invalid type parameter",
119 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
120 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
125 /* Make argument for requesting */
127 case USAGE_TYPE_PROCESS_MEMORY:
128 case USAGE_TYPE_PROCESS_CPU:
129 _D("Process %d: received query to get %s usage of %d processes",
130 getpid(), dbus_info[type].caption, size);
131 args_in = runtime_info_append_args(pid, size);
133 //LCOV_EXCL_START : system error
134 _E("DBUS_METHOD_CALL: not able to append pid array to message");
135 *error = RUNTIME_INFO_ERROR_IO_ERROR;
140 case USAGE_TYPE_APP_MEMORY:
141 case USAGE_TYPE_APP_CPU:
142 _D("Process %d: received query to get %s usage of all apps",
143 getpid(), dbus_info[type].caption);
148 /* Send message to resourced and receive reply */
150 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
152 //LCOV_EXCL_START : system error
153 _E("Failed to get dbus connection : %s",
154 err && err->message ? err->message : NULL);
156 g_variant_unref(args_in);
162 _D("Process %d: Sending dbus message to resourced for %s info",
163 getpid(), dbus_info[type].caption);
165 args_out = g_dbus_connection_call_sync(conn,
167 RESOURCED_USAGE_OBJECT_NAME,
168 RESOURCED_USAGE_INTERFACE_NAME,
169 dbus_info[type].method_name,
170 args_in, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, NULL, &err);
172 //LCOV_EXCL_START : system error
173 _E("DBUS_METHOD_CALL: not able to send message : %s",
174 err && err->message ? err->message : NULL);
175 if (err && (err->code == G_FILE_ERROR_TXTBSY))
176 *error = RUNTIME_INFO_ERROR_PERMISSION_DENIED;
178 *error = RUNTIME_INFO_ERROR_REMOTE_IO;
180 g_variant_unref(args_in);
185 usage = g_variant_get_child_value(args_out, 0);
186 g_variant_unref(args_out);
191 static int runtime_info_get_all_apps_usage(runtime_info_usage_type_e type,
197 struct app_usages_s *usages;
202 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
203 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
204 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
207 reply = runtime_info_dbus_request_usage_info(type, NULL, 0, &error);
209 //LCOV_EXCL_START : system error
210 _E("DBUS_METHOD_CALL: call to resourced not successful");
215 /* Check whether the received usage has expected format or not */
216 if (g_strcmp0(g_variant_get_type_string(reply), "a(su)")) {
217 //LCOV_EXCL_START : system error
218 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
219 g_variant_unref(reply);
220 return RUNTIME_INFO_ERROR_REMOTE_IO;
224 /* Populate the entries of info array using the data received from resourced */
225 len = g_variant_n_children(reply);
227 _E("NO_DATA(0x%08x) : there is no registered app", RUNTIME_INFO_ERROR_NO_DATA);
228 g_variant_unref(reply);
229 return RUNTIME_INFO_ERROR_NO_DATA;
232 usages = calloc(1, sizeof(struct app_usages_s));
234 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
235 g_variant_unref(reply);
236 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
239 usages->len = (int)len;
241 usages->list = calloc(len, sizeof(struct app_usage_s));
243 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
245 g_variant_unref(reply);
246 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
249 g_variant_iter_init(&iter, reply);
250 for (i = 0; i < len; i++)
251 g_variant_iter_next(&iter, "(su)",
252 &(usages->list[i].appid), &(usages->list[i].usage));
253 g_variant_unref(reply);
257 return RUNTIME_INFO_ERROR_NONE;
260 API int runtime_info_get_system_memory_info(runtime_memory_info_s *info)
265 unsigned long mem_total = 0;
266 unsigned long mem_free = 0;
267 unsigned long cached = 0;
268 unsigned long mem_available = 0;
269 unsigned long swap_total = 0;
270 unsigned long swap_free = 0;
273 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
274 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
275 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
278 swap_total = swap_free = mem_available = 0;
280 fp = fopen("/proc/meminfo", "r");
282 _E("IO_ERROR(0x%08x) : failed to open file to read memory usage",
283 RUNTIME_INFO_ERROR_IO_ERROR);
284 return RUNTIME_INFO_ERROR_IO_ERROR;
287 info->total = info->free = info->cache = 0;
288 while (fgets(buf, sizeof(buf), fp) != NULL) {
289 if (sscanf(buf, "MemTotal: %lu", &mem_total) == 1)
290 info->total = ULONGtoINT(mem_total);
291 else if (sscanf(buf, "MemFree: %lu", &mem_free) == 1)
292 info->free = ULONGtoINT(mem_free);
293 else if (sscanf(buf, "Cached: %lu", &cached) == 1)
294 info->cache = ULONGtoINT(cached);
295 else if (sscanf(buf, "MemAvailable: %lu", &value) == 1)
296 mem_available = value;
297 else if (sscanf(buf, "SwapTotal: %lu", &value) == 1)
299 else if (sscanf(buf, "SwapFree: %lu", &value) == 1)
304 if (mem_available > 0) {
305 if (mem_total > mem_available)
306 info->used = ULONGtoINT(mem_total - mem_available);
310 if (mem_total > mem_free && mem_total - mem_free > cached)
311 info->used = ULONGtoINT(mem_total - mem_free - cached);
316 info->swap = (swap_total > swap_free) ? ULONGtoINT(swap_total - swap_free) : 0;
318 return RUNTIME_INFO_ERROR_NONE;
321 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
328 if (!pid || size <= 0) {
329 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
330 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
331 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
335 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
336 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
337 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
342 /* Get the needed information from resourced daemon using dbus */
343 usages = runtime_info_dbus_request_usage_info(USAGE_TYPE_PROCESS_MEMORY, pid, size, &error);
345 //LCOV_EXCL_START : system error
346 _E("DBUS_METHOD_CALL: call to resourced not successful");
351 /* Check whether the received usage has expected format or not */
352 if (g_strcmp0(g_variant_get_type_string(usages), "a(iiiiiii)") ||
353 g_variant_n_children(usages) != size) {
354 //LCOV_EXCL_START : system error
355 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
356 g_variant_unref(usages);
357 return RUNTIME_INFO_ERROR_REMOTE_IO;
361 /* Populate the entries of info array using the data received from resourced */
362 *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s));
364 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
365 g_variant_unref(usages);
366 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
369 g_variant_iter_init(&iter, usages);
370 for (i = 0; i < size; i++)
371 g_variant_iter_next(&iter, "(iiiiiii)",
375 &((*info)[i].shared_clean),
376 &((*info)[i].shared_dirty),
377 &((*info)[i].private_clean),
378 &((*info)[i].private_dirty));
380 g_variant_unref(usages);
382 return RUNTIME_INFO_ERROR_NONE;
385 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
389 unsigned long long user = 0;
390 unsigned long long nice = 0;
391 unsigned long long system = 0;
392 unsigned long long idle = 0;
393 unsigned long long iowait = 0;
394 unsigned long long irq = 0;
395 unsigned long long softirq = 0;
396 unsigned long long total_uptime = 0;
399 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
400 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
401 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
404 cpuinfo_fp = fopen("/proc/stat", "r");
405 if (cpuinfo_fp == NULL) {
406 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
407 RUNTIME_INFO_ERROR_IO_ERROR);
408 return RUNTIME_INFO_ERROR_IO_ERROR;
411 while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
412 if (!strncmp(buf, "cpu ", 4) &&
413 sscanf(buf + 4, "%llu %llu %llu %llu %llu %llu %llu",
414 &user, &nice, &system, &idle,
415 &iowait, &irq, &softirq) == 7)
420 total_uptime = user + nice + system + idle + iowait + irq + softirq;
422 if (total_uptime > 0) {
423 usage->user = (double)user * 100 / total_uptime;
424 usage->nice = (double)nice * 100 / total_uptime;
425 usage->system = (double)system * 100 / total_uptime;
426 usage->iowait = (double)iowait * 100 / total_uptime;
434 return RUNTIME_INFO_ERROR_NONE;
437 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
444 if (!pid || size <= 0) {
445 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
446 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
447 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
451 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
452 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
453 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
458 /* Get the needed information from resourced daemon using dbus */
459 usages = runtime_info_dbus_request_usage_info(USAGE_TYPE_PROCESS_CPU, pid, size, &error);
461 //LCOV_EXCL_START : system error
462 _E("DBUS_METHOD_CALL: call to resourced not successful");
467 /* Check whether the received usage has expected format or not */
468 if (g_strcmp0(g_variant_get_type_string(usages), "a(ii)") ||
469 g_variant_n_children(usages) != size) {
470 //LCOV_EXCL_START : system error
471 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
472 g_variant_unref(usages);
473 return RUNTIME_INFO_ERROR_REMOTE_IO;
477 /* Populate the entries of info array using the data received from resourced */
478 *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
480 //LCOV_EXCL_START : system error
481 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
482 g_variant_unref(usages);
483 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
487 g_variant_iter_init(&iter, usages);
488 for (i = 0; i < size; i++)
489 g_variant_iter_next(&iter, "(ii)", &((*usage)[i].utime), &((*usage)[i].stime));
491 g_variant_unref(usages);
493 return RUNTIME_INFO_ERROR_NONE;
496 API int runtime_info_get_processor_count(int *num_core)
503 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
504 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
505 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
508 cpuinfo_fp = fopen("/sys/devices/system/cpu/possible", "r");
509 if (cpuinfo_fp == NULL) {
510 //LCOV_EXCL_START : system error
511 _E("IO_ERROR(0x%08x) : failed to open file to read cpu information",
512 RUNTIME_INFO_ERROR_IO_ERROR);
513 return RUNTIME_INFO_ERROR_IO_ERROR;
517 if (!fscanf(cpuinfo_fp, "%d-%d", &buf, &result)) {
518 //LCOV_EXCL_START : system error
519 _E("IO_ERROR(0x%08x) : there is no information in the system file",
520 RUNTIME_INFO_ERROR_IO_ERROR);
522 return RUNTIME_INFO_ERROR_IO_ERROR;
526 *num_core = result + 1;
529 return RUNTIME_INFO_ERROR_NONE;
532 API int runtime_info_get_processor_current_frequency(int core_idx, int *cpu_freq)
536 if (runtime_info_get_processor_count(&num_core)
537 != RUNTIME_INFO_ERROR_NONE) {
538 _E("runtime_info_get_processor_count is failed");
539 return RUNTIME_INFO_ERROR_IO_ERROR;
542 if (core_idx < 0 || core_idx >= num_core) {
543 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
544 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
545 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
549 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
550 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
551 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
554 if (runtime_info_get_frequency_cpufreq(core_idx, "cur", cpu_freq)
555 != RUNTIME_INFO_ERROR_NONE) {
556 //LCOV_EXCL_START : system error
557 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
559 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
560 case RUNTIME_INFO_ERROR_NONE:
561 _I("Notice : it is max CPU frequency");
563 case RUNTIME_INFO_ERROR_NO_DATA:
564 _E("This system doesn't support MHz information in the cpuinfo");
565 return RUNTIME_INFO_ERROR_NO_DATA;
567 _E("Fail to get current CPU frequency");
568 return RUNTIME_INFO_ERROR_IO_ERROR;
573 return RUNTIME_INFO_ERROR_NONE;
576 API int runtime_info_get_processor_max_frequency(int core_idx, int *cpu_freq)
580 if (runtime_info_get_processor_count(&num_core)
581 != RUNTIME_INFO_ERROR_NONE) {
582 _E("runtime_info_get_processor_count is failed");
583 return RUNTIME_INFO_ERROR_IO_ERROR;
586 if (core_idx < 0 || core_idx >= num_core) {
587 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
588 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
589 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
593 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
594 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
595 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
598 if (runtime_info_get_frequency_cpufreq(core_idx, "max", cpu_freq)
599 != RUNTIME_INFO_ERROR_NONE) {
600 //LCOV_EXCL_START : system error
601 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
603 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
604 case RUNTIME_INFO_ERROR_NONE:
606 case RUNTIME_INFO_ERROR_NO_DATA:
607 _E("This system doesn't support MHz information in the cpuinfo");
608 return RUNTIME_INFO_ERROR_NO_DATA;
610 _E("Fail to get current CPU frequency");
611 return RUNTIME_INFO_ERROR_IO_ERROR;
616 return RUNTIME_INFO_ERROR_NONE;
619 API int runtime_info_get_physical_memory_size(int *size)
624 FILE *fp = fopen("/proc/zoneinfo", "r");
626 _E("IO_ERROR(0x%08x) : failed to open file to read memory size",
627 RUNTIME_INFO_ERROR_IO_ERROR);
628 return RUNTIME_INFO_ERROR_IO_ERROR;
632 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
633 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
635 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
639 while (fgets(buf, sizeof(buf), fp) != NULL)
640 if (sscanf(buf, " spanned %lu", &value) == 1)
642 *size = pagetoKiB(sum);
646 return RUNTIME_INFO_ERROR_NONE;
649 API int runtime_info_app_usage_destroy(app_usage_h handle)
652 struct app_usage_s *list;
653 struct app_usages_s *usages = handle;
656 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
657 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
658 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
663 for (i = 0; i < usages->len; i++)
671 return RUNTIME_INFO_ERROR_NONE;
674 API int runtime_info_app_usage_get_count(app_usage_h handle, int *count)
676 struct app_usages_s *usages = handle;
679 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
680 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
681 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
685 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
686 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
687 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
690 *count = usages->len;
692 return RUNTIME_INFO_ERROR_NONE;
695 API int runtime_info_app_usage_get_appid(app_usage_h handle, int index, char **appid)
697 struct app_usages_s *usages = handle;
699 if (!usages || index < 0 || index >= usages->len) {
700 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
701 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
702 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
706 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
707 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
708 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
711 *appid = strndup(usages->list[index].appid, strlen(usages->list[index].appid));
713 return RUNTIME_INFO_ERROR_NONE;
716 API int runtime_info_app_usage_get_usage(app_usage_h handle, int index, unsigned int *usage)
718 struct app_usages_s *usages = handle;
720 if (!usages || index < 0 || index >= usages->len) {
721 _E("INVALID PARAMETER(0x%08x) : invalid input parameter",
722 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
723 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
727 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
728 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
729 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
732 *usage = usages->list[index].usage;
734 return RUNTIME_INFO_ERROR_NONE;
737 API int runtime_info_get_all_apps_memory_usage(app_usage_h *usage)
739 return runtime_info_get_all_apps_usage(USAGE_TYPE_APP_MEMORY, usage);
742 API int runtime_info_get_all_apps_cpu_rate(app_usage_h *rate)
744 return runtime_info_get_all_apps_usage(USAGE_TYPE_APP_CPU, rate);