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.
23 #include <runtime_info.h>
24 #include <runtime_info_private.h>
28 #define RESOURCED_BUS_NAME "org.tizen.resourced"
29 #define RESOURCED_USAGE_OBJECT_NAME "/Org/Tizen/ResourceD/Process"
30 #define RESOURCED_USAGE_INTERFACE_NAME "org.tizen.resourced.process"
31 #define RESOURCED_MEMORY_USAGE_METHOD "ProcMemoryUsage"
32 #define RESOURCED_CPU_USAGE_METHOD "ProcCpuUsage"
33 #define DBUS_REPLY_TIMEOUT (120 * 1000)
34 #define MEMORY_USAGE 1
37 #define kBtoKiB(val) (int)(((long long)val * 1024)/1000)
38 #define pagetoKiB(val) (int)((long long)val * 4096 / 1000)
40 //LCOV_EXCL_START : system error
41 static int runtime_info_get_dbus_error(const char *err_name)
46 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
48 size = strlen(err_name);
49 if (!strncmp(err_name, DBUS_ERROR_IO_ERROR, size))
50 return RUNTIME_INFO_ERROR_IO_ERROR;
51 else if (!strncmp(err_name, DBUS_ERROR_NO_MEMORY, size))
52 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
53 else if (!strncmp(err_name, DBUS_ERROR_ACCESS_DENIED, size))
54 return RUNTIME_INFO_ERROR_PERMISSION_DENIED;
56 return RUNTIME_INFO_ERROR_REMOTE_IO;
60 /* Handler function which handles dbus related instructions
61 * for both per process memory and cpu requests.
62 * Creates the method call to resourced and receives the reply (if successful)
63 * Return the received reply (if received) else NULL to signify failed call to resourced
65 static DBusMessage *runtime_info_dbus_process_usage_info(int *pid, int size, int info, int *error)
74 //LCOV_EXCL_START : system error
75 _E("INVALID_PARAMETER(0x%08x): pid list and error params cannot be null");
78 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
83 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
85 //LCOV_EXCL_START : system error
86 _E("DBUS_CONNECTION_ERROR");
87 *error = RUNTIME_INFO_ERROR_REMOTE_IO;
92 if (info == MEMORY_USAGE) {
93 _D("Process %d: received query to get process memory info of %d processes",
95 msg = dbus_message_new_method_call(RESOURCED_BUS_NAME,
96 RESOURCED_USAGE_OBJECT_NAME,
97 RESOURCED_USAGE_INTERFACE_NAME,
98 RESOURCED_MEMORY_USAGE_METHOD);
99 } else if (info == CPU_USAGE) {
100 _D("Process %d: received query to get process cpu usage of %d processes",
102 msg = dbus_message_new_method_call(RESOURCED_BUS_NAME,
103 RESOURCED_USAGE_OBJECT_NAME,
104 RESOURCED_USAGE_INTERFACE_NAME,
105 RESOURCED_CPU_USAGE_METHOD);
107 _E("INVALID_PARAMETER(0x%08x): info parameter should be %d or %d",
108 MEMORY_USAGE, CPU_USAGE, RUNTIME_INFO_ERROR_INVALID_PARAMETER);
109 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
114 _E("DBUS_METHOD_CALL: not able to create method call (%s:%s-%s)",
115 RESOURCED_USAGE_OBJECT_NAME, RESOURCED_USAGE_INTERFACE_NAME,
116 RESOURCED_MEMORY_USAGE_METHOD);
117 *error = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
121 ret = dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &pid,
122 size, DBUS_TYPE_INVALID);
124 //LCOV_EXCL_START : system error
125 _E("DBUS_METHOD_CALL: not able to append pid array to message");
126 *error = RUNTIME_INFO_ERROR_IO_ERROR;
127 dbus_message_unref(msg);
132 dbus_error_init(&err);
135 if (info == MEMORY_USAGE)
136 _D("Process %d: Sending dbus message to resourced for process memory usage info",
139 _D("Process %d: Sending dbus message to resourced for process cpu usage info",
141 reply = dbus_connection_send_with_reply_and_block(conn, msg,
142 DBUS_REPLY_TIMEOUT, &err);
144 _E("DBUS_METHOD_CALL: not able to send message"); //LCOV_EXCL_LINE : system error
146 if (dbus_error_is_set(&err)) {
147 //LCOV_EXCL_START : system error
148 _E("DBUS_METHOD_CALL: dbus_connection_send error(%s:%s)", err.name, err.message);
149 *error = runtime_info_get_dbus_error(err.name);
150 dbus_error_free(&err);
155 dbus_message_unref(msg);
159 API int runtime_info_get_system_memory_info(runtime_memory_info_s *info)
163 unsigned long swap_total, swap_free, value, mem_available;
166 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
167 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
168 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
171 swap_total = swap_free = mem_available = 0;
173 fp = fopen("/proc/meminfo", "r");
175 _E("IO_ERROR(0x%08x) : failed to open file to read memory usage",
176 RUNTIME_INFO_ERROR_IO_ERROR);
177 return RUNTIME_INFO_ERROR_IO_ERROR;
180 while (fgets(buf, sizeof(buf), fp) != NULL) {
181 if (sscanf(buf, "MemTotal: %lu", &value) == 1)
182 info->total = kBtoKiB(value);
183 else if (sscanf(buf, "MemFree: %lu", &value) == 1)
184 info->free = kBtoKiB(value);
185 else if (sscanf(buf, "Cached: %lu", &value) == 1)
186 info->cache = kBtoKiB(value);
187 else if (sscanf(buf, "MemAvailable: %lu", &value) == 1)
188 mem_available = kBtoKiB(value);
189 else if (sscanf(buf, "SwapTotal: %lu", &value) == 1)
191 else if (sscanf(buf, "SwapFree: %lu", &value) == 1)
196 info->used = mem_available ? (info->total - mem_available) : (info->total - info->free - info->cache);
197 info->swap = kBtoKiB(((swap_total > swap_free) ? (int)(swap_total - swap_free) : 0));
200 * Get total memory size from zoneinfo
202 * meminfo show the total memory size
203 * except kernel reserved memory
205 * Therefore, we will use (the number of page * page size)
207 fp = fopen("/proc/zoneinfo", "r");
209 _E("IO_ERROR(0x%08x) : failed to open file to read memory size",
210 RUNTIME_INFO_ERROR_IO_ERROR);
211 return RUNTIME_INFO_ERROR_IO_ERROR;
215 while (fgets(buf, sizeof(buf), fp) != NULL)
216 if (sscanf(buf, " spanned %lu", &value) == 1)
217 info->total += value;
218 info->total = pagetoKiB(info->total);
222 return RUNTIME_INFO_ERROR_NONE;
225 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
227 DBusMessageIter iter, iter_array, iter_struct;
230 process_memory_info_s *proc_info;
231 DBusMessage *replymsg;
233 if (!pid || size <= 0) {
234 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
235 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
236 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
240 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
241 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
242 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
247 /* Get the needed information from resourced daemon using dbus */
248 replymsg = runtime_info_dbus_process_usage_info(pid, size, MEMORY_USAGE, &error);
250 //LCOV_EXCL_START : system error
251 _E("DBUS_METHOD_CALL: call to resourced not successful");
256 /* Check if the message is an error message or not in expected
257 * format and return error value */
258 dbus_message_iter_init(replymsg, &iter);
259 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
260 //LCOV_EXCL_START : system error
261 dbus_message_iter_get_basic(&iter, &error);
262 _E("DBUS_METHOD_CALL: call to resourced returned error message");
263 dbus_message_unref(replymsg);
266 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
267 //LCOV_EXCL_START : system error
268 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
269 dbus_message_unref(replymsg);
270 return RUNTIME_INFO_ERROR_REMOTE_IO;
274 /* Populate the entries of info array using the data received from resourced */
275 *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s));
277 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
278 dbus_message_unref(replymsg);
279 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
282 dbus_message_iter_recurse(&iter, &iter_array);
283 for (index = 0; index < size; ++index) {
284 proc_info = &(*info)[index];
286 dbus_message_iter_recurse(&iter_array, &iter_struct);
288 dbus_message_iter_get_basic(&iter_struct, &value);
289 proc_info->vsz = value;
290 dbus_message_iter_next(&iter_struct);
291 dbus_message_iter_get_basic(&iter_struct, &value);
292 proc_info->rss = value;
293 dbus_message_iter_next(&iter_struct);
294 dbus_message_iter_get_basic(&iter_struct, &value);
295 proc_info->pss = value;
296 dbus_message_iter_next(&iter_struct);
297 dbus_message_iter_get_basic(&iter_struct, &value);
298 proc_info->shared_clean = value;
299 dbus_message_iter_next(&iter_struct);
300 dbus_message_iter_get_basic(&iter_struct, &value);
301 proc_info->shared_dirty = value;
302 dbus_message_iter_next(&iter_struct);
303 dbus_message_iter_get_basic(&iter_struct, &value);
304 proc_info->private_clean = value;
305 dbus_message_iter_next(&iter_struct);
306 dbus_message_iter_get_basic(&iter_struct, &value);
307 proc_info->private_dirty = value;
309 dbus_message_iter_next(&iter_array);
312 dbus_message_unref(replymsg);
313 return RUNTIME_INFO_ERROR_NONE;
316 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
320 unsigned long long user, nice, system, idle, iowait, irq, softirq, total_uptime;
323 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
324 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
325 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
328 cpuinfo_fp = fopen("/proc/stat", "r");
329 if (cpuinfo_fp == NULL) {
330 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
331 RUNTIME_INFO_ERROR_IO_ERROR);
332 return RUNTIME_INFO_ERROR_IO_ERROR;
335 while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
336 if (!strncmp(buf, "cpu ", 4) &&
337 sscanf(buf+4, "%llu %llu %llu %llu %llu %llu %llu",
338 &user, &nice, &system, &idle,
339 &iowait, &irq, &softirq) == 7)
344 total_uptime = user+nice+system+idle+iowait+irq+softirq;
346 usage->user = (double)user*100/total_uptime;
347 usage->nice = (double)nice*100/total_uptime;
348 usage->system = (double)system*100/total_uptime;
349 usage->iowait = (double)iowait*100/total_uptime;
351 return RUNTIME_INFO_ERROR_NONE;
354 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
356 DBusMessageIter iter, iter_array, iter_struct;
359 process_cpu_usage_s *proc_usage;
360 DBusMessage *replymsg;
362 if (!pid || size <= 0) {
363 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
364 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
365 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
369 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
370 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
371 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
376 /* Get the needed information from resourced daemon using dbus */
377 replymsg = runtime_info_dbus_process_usage_info(pid, size, CPU_USAGE, &error);
380 //LCOV_EXCL_START : system error
381 _E("DBUS_METHOD_CALL: call to resourced not successful");
386 /* Check if the message is an error message or not in expected format
387 * and return error value */
388 dbus_message_iter_init(replymsg, &iter);
389 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
390 //LCOV_EXCL_START : system error
391 dbus_message_iter_get_basic(&iter, &error);
392 _E("DBUS_METHOD_CALL: call to resourced returned error message");
393 dbus_message_unref(replymsg);
396 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
397 //LCOV_EXCL_START : system error
398 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
399 dbus_message_unref(replymsg);
400 return RUNTIME_INFO_ERROR_REMOTE_IO;
404 /* Populate the entries of info array using the data received from resourced */
405 *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
407 //LCOV_EXCL_START : system error
408 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
409 dbus_message_unref(replymsg);
410 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
414 dbus_message_iter_recurse(&iter, &iter_array);
415 for (index = 0; index < size; ++index) {
416 proc_usage = &(*usage)[index];
418 dbus_message_iter_recurse(&iter_array, &iter_struct);
420 dbus_message_iter_get_basic(&iter_struct, &value);
421 proc_usage->utime = value;
422 dbus_message_iter_next(&iter_struct);
423 dbus_message_iter_get_basic(&iter_struct, &value);
424 proc_usage->stime = value;
426 dbus_message_iter_next(&iter_array);
429 dbus_message_unref(replymsg);
430 return RUNTIME_INFO_ERROR_NONE;
433 API int runtime_info_get_processor_count(int *num_core)
440 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
441 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
442 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
445 cpuinfo_fp = fopen("/sys/devices/system/cpu/possible", "r");
446 if (cpuinfo_fp == NULL) {
447 //LCOV_EXCL_START : system error
448 _E("IO_ERROR(0x%08x) : failed to open file to read cpu information",
449 RUNTIME_INFO_ERROR_IO_ERROR);
450 return RUNTIME_INFO_ERROR_IO_ERROR;
454 if (!fscanf(cpuinfo_fp, "%d-%d", &buf, &result)) {
455 //LCOV_EXCL_START : system error
456 _E("IO_ERROR(0x%08x) : there is no information in the system file",
457 RUNTIME_INFO_ERROR_IO_ERROR);
459 return RUNTIME_INFO_ERROR_IO_ERROR;
463 *num_core = result + 1;
466 return RUNTIME_INFO_ERROR_NONE;
469 API int runtime_info_get_processor_current_frequency(int core_idx, int *cpu_freq)
473 if (runtime_info_get_processor_count(&num_core)
474 != RUNTIME_INFO_ERROR_NONE) {
475 _E("runtime_info_get_processor_count is failed");
476 return RUNTIME_INFO_ERROR_IO_ERROR;
479 if (core_idx < 0 || core_idx >= num_core) {
480 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
481 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
482 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
486 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
487 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
488 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
491 if (runtime_info_get_frequency_cpufreq(core_idx, "cur", cpu_freq)
492 != RUNTIME_INFO_ERROR_NONE) {
493 //LCOV_EXCL_START : system error
494 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
496 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
497 case RUNTIME_INFO_ERROR_NONE:
498 _I("Notice : it is max CPU frequency");
500 case RUNTIME_INFO_ERROR_NO_DATA:
501 _E("This system doesn't support MHz information in the cpuinfo");
502 return RUNTIME_INFO_ERROR_NO_DATA;
504 _E("Fail to get current CPU frequency");
505 return RUNTIME_INFO_ERROR_IO_ERROR;
510 return RUNTIME_INFO_ERROR_NONE;
513 API int runtime_info_get_processor_max_frequency(int core_idx, int *cpu_freq)
517 if (runtime_info_get_processor_count(&num_core)
518 != RUNTIME_INFO_ERROR_NONE) {
519 _E("runtime_info_get_processor_count is failed");
520 return RUNTIME_INFO_ERROR_IO_ERROR;
523 if (core_idx < 0 || core_idx >= num_core) {
524 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
525 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
526 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
530 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
531 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
532 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
535 if (runtime_info_get_frequency_cpufreq(core_idx, "max", cpu_freq)
536 != RUNTIME_INFO_ERROR_NONE) {
537 //LCOV_EXCL_START : system error
538 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
540 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
541 case RUNTIME_INFO_ERROR_NONE:
543 case RUNTIME_INFO_ERROR_NO_DATA:
544 _E("This system doesn't support MHz information in the cpuinfo");
545 return RUNTIME_INFO_ERROR_NO_DATA;
547 _E("Fail to get current CPU frequency");
548 return RUNTIME_INFO_ERROR_IO_ERROR;
553 return RUNTIME_INFO_ERROR_NONE;