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));
199 return RUNTIME_INFO_ERROR_NONE;
202 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
204 DBusMessageIter iter, iter_array, iter_struct;
207 process_memory_info_s *proc_info;
208 DBusMessage *replymsg;
210 if (!pid || size <= 0) {
211 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
212 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
213 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
217 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
218 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
219 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
224 /* Get the needed information from resourced daemon using dbus */
225 replymsg = runtime_info_dbus_process_usage_info(pid, size, MEMORY_USAGE, &error);
227 //LCOV_EXCL_START : system error
228 _E("DBUS_METHOD_CALL: call to resourced not successful");
233 /* Check if the message is an error message or not in expected
234 * format and return error value */
235 dbus_message_iter_init(replymsg, &iter);
236 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
237 //LCOV_EXCL_START : system error
238 dbus_message_iter_get_basic(&iter, &error);
239 _E("DBUS_METHOD_CALL: call to resourced returned error message");
240 dbus_message_unref(replymsg);
243 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
244 //LCOV_EXCL_START : system error
245 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
246 dbus_message_unref(replymsg);
247 return RUNTIME_INFO_ERROR_REMOTE_IO;
251 /* Populate the entries of info array using the data received from resourced */
252 *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s));
254 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
255 dbus_message_unref(replymsg);
256 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
259 dbus_message_iter_recurse(&iter, &iter_array);
260 for (index = 0; index < size; ++index) {
261 proc_info = &(*info)[index];
263 dbus_message_iter_recurse(&iter_array, &iter_struct);
265 dbus_message_iter_get_basic(&iter_struct, &value);
266 proc_info->vsz = value;
267 dbus_message_iter_next(&iter_struct);
268 dbus_message_iter_get_basic(&iter_struct, &value);
269 proc_info->rss = value;
270 dbus_message_iter_next(&iter_struct);
271 dbus_message_iter_get_basic(&iter_struct, &value);
272 proc_info->pss = value;
273 dbus_message_iter_next(&iter_struct);
274 dbus_message_iter_get_basic(&iter_struct, &value);
275 proc_info->shared_clean = value;
276 dbus_message_iter_next(&iter_struct);
277 dbus_message_iter_get_basic(&iter_struct, &value);
278 proc_info->shared_dirty = value;
279 dbus_message_iter_next(&iter_struct);
280 dbus_message_iter_get_basic(&iter_struct, &value);
281 proc_info->private_clean = value;
282 dbus_message_iter_next(&iter_struct);
283 dbus_message_iter_get_basic(&iter_struct, &value);
284 proc_info->private_dirty = value;
286 dbus_message_iter_next(&iter_array);
289 dbus_message_unref(replymsg);
290 return RUNTIME_INFO_ERROR_NONE;
293 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
297 unsigned long long user, nice, system, idle, iowait, irq, softirq, total_uptime;
300 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
301 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
302 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
305 cpuinfo_fp = fopen("/proc/stat", "r");
306 if (cpuinfo_fp == NULL) {
307 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
308 RUNTIME_INFO_ERROR_IO_ERROR);
309 return RUNTIME_INFO_ERROR_IO_ERROR;
312 while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
313 if (!strncmp(buf, "cpu ", 4) &&
314 sscanf(buf+4, "%llu %llu %llu %llu %llu %llu %llu",
315 &user, &nice, &system, &idle,
316 &iowait, &irq, &softirq) == 7)
321 total_uptime = user+nice+system+idle+iowait+irq+softirq;
323 usage->user = (double)user*100/total_uptime;
324 usage->nice = (double)nice*100/total_uptime;
325 usage->system = (double)system*100/total_uptime;
326 usage->iowait = (double)iowait*100/total_uptime;
328 return RUNTIME_INFO_ERROR_NONE;
331 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
333 DBusMessageIter iter, iter_array, iter_struct;
336 process_cpu_usage_s *proc_usage;
337 DBusMessage *replymsg;
339 if (!pid || size <= 0) {
340 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
341 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
342 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
346 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
347 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
348 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
353 /* Get the needed information from resourced daemon using dbus */
354 replymsg = runtime_info_dbus_process_usage_info(pid, size, CPU_USAGE, &error);
357 //LCOV_EXCL_START : system error
358 _E("DBUS_METHOD_CALL: call to resourced not successful");
363 /* Check if the message is an error message or not in expected format
364 * and return error value */
365 dbus_message_iter_init(replymsg, &iter);
366 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
367 //LCOV_EXCL_START : system error
368 dbus_message_iter_get_basic(&iter, &error);
369 _E("DBUS_METHOD_CALL: call to resourced returned error message");
370 dbus_message_unref(replymsg);
373 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
374 //LCOV_EXCL_START : system error
375 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
376 dbus_message_unref(replymsg);
377 return RUNTIME_INFO_ERROR_REMOTE_IO;
381 /* Populate the entries of info array using the data received from resourced */
382 *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
384 //LCOV_EXCL_START : system error
385 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
386 dbus_message_unref(replymsg);
387 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
391 dbus_message_iter_recurse(&iter, &iter_array);
392 for (index = 0; index < size; ++index) {
393 proc_usage = &(*usage)[index];
395 dbus_message_iter_recurse(&iter_array, &iter_struct);
397 dbus_message_iter_get_basic(&iter_struct, &value);
398 proc_usage->utime = value;
399 dbus_message_iter_next(&iter_struct);
400 dbus_message_iter_get_basic(&iter_struct, &value);
401 proc_usage->stime = value;
403 dbus_message_iter_next(&iter_array);
406 dbus_message_unref(replymsg);
407 return RUNTIME_INFO_ERROR_NONE;
410 API int runtime_info_get_processor_count(int *num_core)
417 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
418 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
419 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
422 cpuinfo_fp = fopen("/sys/devices/system/cpu/possible", "r");
423 if (cpuinfo_fp == NULL) {
424 //LCOV_EXCL_START : system error
425 _E("IO_ERROR(0x%08x) : failed to open file to read cpu information",
426 RUNTIME_INFO_ERROR_IO_ERROR);
427 return RUNTIME_INFO_ERROR_IO_ERROR;
431 if (!fscanf(cpuinfo_fp, "%d-%d", &buf, &result)) {
432 //LCOV_EXCL_START : system error
433 _E("IO_ERROR(0x%08x) : there is no information in the system file",
434 RUNTIME_INFO_ERROR_IO_ERROR);
436 return RUNTIME_INFO_ERROR_IO_ERROR;
440 *num_core = result + 1;
443 return RUNTIME_INFO_ERROR_NONE;
446 API int runtime_info_get_processor_current_frequency(int core_idx, int *cpu_freq)
450 if (runtime_info_get_processor_count(&num_core)
451 != RUNTIME_INFO_ERROR_NONE) {
452 _E("runtime_info_get_processor_count is failed");
453 return RUNTIME_INFO_ERROR_IO_ERROR;
456 if (core_idx < 0 || core_idx >= num_core) {
457 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
458 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
459 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
463 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
464 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
465 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
468 if (runtime_info_get_frequency_cpufreq(core_idx, "cur", cpu_freq)
469 != RUNTIME_INFO_ERROR_NONE) {
470 //LCOV_EXCL_START : system error
471 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
473 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
474 case RUNTIME_INFO_ERROR_NONE:
475 _I("Notice : it is max CPU frequency");
477 case RUNTIME_INFO_ERROR_NO_DATA:
478 _E("This system doesn't support MHz information in the cpuinfo");
479 return RUNTIME_INFO_ERROR_NO_DATA;
481 _E("Fail to get current CPU frequency");
482 return RUNTIME_INFO_ERROR_IO_ERROR;
487 return RUNTIME_INFO_ERROR_NONE;
490 API int runtime_info_get_processor_max_frequency(int core_idx, int *cpu_freq)
494 if (runtime_info_get_processor_count(&num_core)
495 != RUNTIME_INFO_ERROR_NONE) {
496 _E("runtime_info_get_processor_count is failed");
497 return RUNTIME_INFO_ERROR_IO_ERROR;
500 if (core_idx < 0 || core_idx >= num_core) {
501 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
502 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
503 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
507 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
508 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
509 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
512 if (runtime_info_get_frequency_cpufreq(core_idx, "max", cpu_freq)
513 != RUNTIME_INFO_ERROR_NONE) {
514 //LCOV_EXCL_START : system error
515 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
517 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
518 case RUNTIME_INFO_ERROR_NONE:
520 case RUNTIME_INFO_ERROR_NO_DATA:
521 _E("This system doesn't support MHz information in the cpuinfo");
522 return RUNTIME_INFO_ERROR_NO_DATA;
524 _E("Fail to get current CPU frequency");
525 return RUNTIME_INFO_ERROR_IO_ERROR;
530 return RUNTIME_INFO_ERROR_NONE;
533 API int runtime_info_get_physical_memory_size(int *size)
538 FILE *fp = fopen("/proc/zoneinfo", "r");
540 _E("IO_ERROR(0x%08x) : failed to open file to read memory size",
541 RUNTIME_INFO_ERROR_IO_ERROR);
542 return RUNTIME_INFO_ERROR_IO_ERROR;
546 _E("INVALID PARAMETER(0x%08x) : invalid output parameter",
547 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
549 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
553 while (fgets(buf, sizeof(buf), fp) != NULL)
554 if (sscanf(buf, " spanned %lu", &value) == 1)
556 *size = pagetoKiB(sum);
560 return RUNTIME_INFO_ERROR_NONE;