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)
39 static int runtime_info_get_dbus_error(const char *err_name)
44 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
46 size = strlen(err_name);
47 if (!strncmp(err_name, DBUS_ERROR_IO_ERROR, size))
48 return RUNTIME_INFO_ERROR_IO_ERROR;
49 else if (!strncmp(err_name, DBUS_ERROR_NO_MEMORY, size))
50 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
51 else if (!strncmp(err_name, DBUS_ERROR_ACCESS_DENIED, size))
52 return RUNTIME_INFO_ERROR_PERMISSION_DENIED;
54 return RUNTIME_INFO_ERROR_REMOTE_IO;
57 /* Handler function which handles dbus related instructions
58 * for both per process memory and cpu requests.
59 * Creates the method call to resourced and receives the reply (if successful)
60 * Return the received reply (if received) else NULL to signify failed call to resourced
62 static DBusMessage *runtime_info_dbus_process_usage_info(int *pid, int size, int info, int *error)
71 _E("INVALID_PARAMETER(0x%08x): pid list and error params cannot be null");
74 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
78 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
80 _E("DBUS_CONNECTION_ERROR");
81 *error = RUNTIME_INFO_ERROR_REMOTE_IO;
85 if (info == MEMORY_USAGE) {
86 _D("Process %d: received query to get process memory info of %d processes",
88 msg = dbus_message_new_method_call(RESOURCED_BUS_NAME,
89 RESOURCED_USAGE_OBJECT_NAME,
90 RESOURCED_USAGE_INTERFACE_NAME,
91 RESOURCED_MEMORY_USAGE_METHOD);
92 } else if (info == CPU_USAGE) {
93 _D("Process %d: received query to get process cpu usage 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_CPU_USAGE_METHOD);
100 _E("INVALID_PARAMETER(0x%08x): info parameter should be %d or %d",
101 MEMORY_USAGE, CPU_USAGE, RUNTIME_INFO_ERROR_INVALID_PARAMETER);
102 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
107 _E("DBUS_METHOD_CALL: not able to create method call (%s:%s-%s)",
108 RESOURCED_USAGE_OBJECT_NAME, RESOURCED_USAGE_INTERFACE_NAME,
109 RESOURCED_MEMORY_USAGE_METHOD);
110 *error = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
114 ret = dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &pid,
115 size, DBUS_TYPE_INVALID);
117 _E("DBUS_METHOD_CALL: not able to append pid array to message");
118 *error = RUNTIME_INFO_ERROR_IO_ERROR;
119 dbus_message_unref(msg);
123 dbus_error_init(&err);
126 if (info == MEMORY_USAGE)
127 _D("Process %d: Sending dbus message to resourced for process memory usage info",
130 _D("Process %d: Sending dbus message to resourced for process cpu usage info",
132 reply = dbus_connection_send_with_reply_and_block(conn, msg,
133 DBUS_REPLY_TIMEOUT, &err);
135 _E("DBUS_METHOD_CALL: not able to send message");
137 if (dbus_error_is_set(&err)) {
138 _E("DBUS_METHOD_CALL: dbus_connection_send error(%s:%s)", err.name, err.message);
139 *error = runtime_info_get_dbus_error(err.name);
140 dbus_error_free(&err);
144 dbus_message_unref(msg);
148 API int runtime_info_get_system_memory_info(runtime_memory_info_s *info)
152 unsigned long swap_total, swap_free, value;
155 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
156 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
157 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
160 swap_total = swap_free = 0;
162 meminfo_fp = fopen("/proc/meminfo", "r");
163 if (meminfo_fp == NULL) {
164 _E("IO_ERROR(0x%08x) : failed to open file to read memory usage",
165 RUNTIME_INFO_ERROR_IO_ERROR);
166 return RUNTIME_INFO_ERROR_IO_ERROR;
169 while (fgets(buf, sizeof(buf), meminfo_fp) != NULL) {
170 if (sscanf(buf, "MemTotal: %lu", &value) == 1)
171 info->total = kBtoKiB(value);
172 else if (sscanf(buf, "MemFree: %lu", &value) == 1)
173 info->free = kBtoKiB(value);
174 else if (sscanf(buf, "Cached: %lu", &value) == 1)
175 info->cache = kBtoKiB(value);
176 else if (sscanf(buf, "SwapTotal: %lu", &value) == 1)
178 else if (sscanf(buf, "SwapFree: %lu", &value) == 1)
183 info->used = (info->total > info->free) ? (info->total - info->free) : 0;
184 info->swap = kBtoKiB(((swap_total > swap_free) ? (int)(swap_total - swap_free) : 0));
186 return RUNTIME_INFO_ERROR_NONE;
189 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
191 DBusMessageIter iter, iter_array, iter_struct;
194 process_memory_info_s *proc_info;
195 DBusMessage *replymsg;
197 if (!pid || size <= 0) {
198 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
199 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
200 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
204 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
205 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
206 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
211 /* Get the needed information from resourced daemon using dbus */
212 replymsg = runtime_info_dbus_process_usage_info(pid, size, MEMORY_USAGE, &error);
214 _E("DBUS_METHOD_CALL: call to resourced not successful");
218 /* Check if the message is an error message or not in expected
219 * format and return error value */
220 dbus_message_iter_init(replymsg, &iter);
221 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
222 dbus_message_iter_get_basic(&iter, &error);
223 _E("DBUS_METHOD_CALL: call to resourced returned error message");
224 dbus_message_unref(replymsg);
226 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
227 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
228 dbus_message_unref(replymsg);
229 return RUNTIME_INFO_ERROR_REMOTE_IO;
232 /* Populate the entries of info array using the data received from resourced */
233 *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s));
235 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
236 dbus_message_unref(replymsg);
237 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
240 dbus_message_iter_recurse(&iter, &iter_array);
241 for (index = 0; index < size; ++index) {
242 proc_info = &(*info)[index];
244 dbus_message_iter_recurse(&iter_array, &iter_struct);
246 dbus_message_iter_get_basic(&iter_struct, &value);
247 proc_info->vsz = value;
248 dbus_message_iter_next(&iter_struct);
249 dbus_message_iter_get_basic(&iter_struct, &value);
250 proc_info->rss = value;
251 dbus_message_iter_next(&iter_struct);
252 dbus_message_iter_get_basic(&iter_struct, &value);
253 proc_info->pss = value;
254 dbus_message_iter_next(&iter_struct);
255 dbus_message_iter_get_basic(&iter_struct, &value);
256 proc_info->shared_clean = value;
257 dbus_message_iter_next(&iter_struct);
258 dbus_message_iter_get_basic(&iter_struct, &value);
259 proc_info->shared_dirty = value;
260 dbus_message_iter_next(&iter_struct);
261 dbus_message_iter_get_basic(&iter_struct, &value);
262 proc_info->private_clean = value;
263 dbus_message_iter_next(&iter_struct);
264 dbus_message_iter_get_basic(&iter_struct, &value);
265 proc_info->private_dirty = value;
267 dbus_message_iter_next(&iter_array);
270 dbus_message_unref(replymsg);
271 return RUNTIME_INFO_ERROR_NONE;
274 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
278 unsigned long long user, nice, system, idle, iowait, irq, softirq, total_uptime;
281 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
282 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
283 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
286 cpuinfo_fp = fopen("/proc/stat", "r");
287 if (cpuinfo_fp == NULL) {
288 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
289 RUNTIME_INFO_ERROR_IO_ERROR);
290 return RUNTIME_INFO_ERROR_IO_ERROR;
293 while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
294 if (!strncmp(buf, "cpu ", 4) &&
295 sscanf(buf+4, "%llu %llu %llu %llu %llu %llu %llu",
296 &user, &nice, &system, &idle,
297 &iowait, &irq, &softirq) == 7)
302 total_uptime = user+nice+system+idle+iowait+irq+softirq;
304 usage->user = (double)user*100/total_uptime;
305 usage->nice = (double)nice*100/total_uptime;
306 usage->system = (double)system*100/total_uptime;
307 usage->iowait = (double)iowait*100/total_uptime;
309 return RUNTIME_INFO_ERROR_NONE;
312 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
314 DBusMessageIter iter, iter_array, iter_struct;
317 process_cpu_usage_s *proc_usage;
318 DBusMessage *replymsg;
320 if (!pid || size <= 0) {
321 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
322 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
323 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
327 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
328 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
329 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
334 /* Get the needed information from resourced daemon using dbus */
335 replymsg = runtime_info_dbus_process_usage_info(pid, size, CPU_USAGE, &error);
337 _E("DBUS_METHOD_CALL: call to resourced not successful");
341 /* Check if the message is an error message or not in expected format
342 * and return error value */
343 dbus_message_iter_init(replymsg, &iter);
344 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
345 dbus_message_iter_get_basic(&iter, &error);
346 _E("DBUS_METHOD_CALL: call to resourced returned error message");
347 dbus_message_unref(replymsg);
349 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
350 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
351 dbus_message_unref(replymsg);
352 return RUNTIME_INFO_ERROR_REMOTE_IO;
355 /* Populate the entries of info array using the data received from resourced */
356 *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
358 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
359 dbus_message_unref(replymsg);
360 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
363 dbus_message_iter_recurse(&iter, &iter_array);
364 for (index = 0; index < size; ++index) {
365 proc_usage = &(*usage)[index];
367 dbus_message_iter_recurse(&iter_array, &iter_struct);
369 dbus_message_iter_get_basic(&iter_struct, &value);
370 proc_usage->utime = value;
371 dbus_message_iter_next(&iter_struct);
372 dbus_message_iter_get_basic(&iter_struct, &value);
373 proc_usage->stime = value;
375 dbus_message_iter_next(&iter_array);
378 dbus_message_unref(replymsg);
379 return RUNTIME_INFO_ERROR_NONE;
382 API int runtime_info_get_processor_count(int *num_core)
389 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
390 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
391 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
394 cpuinfo_fp = fopen("/sys/devices/system/cpu/possible", "r");
395 if (cpuinfo_fp == NULL) {
396 _E("IO_ERROR(0x%08x) : failed to open file to read cpu information",
397 RUNTIME_INFO_ERROR_IO_ERROR);
398 return RUNTIME_INFO_ERROR_IO_ERROR;
401 if (!fscanf(cpuinfo_fp, "%d-%d", &buf, &result)) {
402 _E("IO_ERROR(0x%08x) : there is no information in the system file",
403 RUNTIME_INFO_ERROR_IO_ERROR);
405 return RUNTIME_INFO_ERROR_IO_ERROR;
408 *num_core = result + 1;
411 return RUNTIME_INFO_ERROR_NONE;
414 API int runtime_info_get_processor_current_frequency(int core_idx, int *cpu_freq)
418 if (runtime_info_get_processor_count(&num_core)
419 != RUNTIME_INFO_ERROR_NONE) {
420 _E("runtime_info_get_processor_count is failed");
421 return RUNTIME_INFO_ERROR_IO_ERROR;
424 if (core_idx < 0 || core_idx >= num_core) {
425 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
426 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
427 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
431 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
432 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
433 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
436 if (runtime_info_get_frequency_cpufreq(core_idx, "cur", cpu_freq)
437 != RUNTIME_INFO_ERROR_NONE) {
438 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
440 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
441 case RUNTIME_INFO_ERROR_NONE:
442 _I("Notice : it is max CPU frequency");
444 case RUNTIME_INFO_ERROR_NOT_SUPPORTED:
445 _E("This system doesn't support MHz information in the cpuinfo");
446 return RUNTIME_INFO_ERROR_NOT_SUPPORTED;
448 _E("Fail to get current CPU frequency");
449 return RUNTIME_INFO_ERROR_IO_ERROR;
453 return RUNTIME_INFO_ERROR_NONE;
456 API int runtime_info_get_processor_max_frequency(int core_idx, int *cpu_freq)
460 if (runtime_info_get_processor_count(&num_core)
461 != RUNTIME_INFO_ERROR_NONE) {
462 _E("runtime_info_get_processor_count is failed");
463 return RUNTIME_INFO_ERROR_IO_ERROR;
466 if (core_idx < 0 || core_idx >= num_core) {
467 _E("INVALID_PARAMETER(0x%08x) : invalid input parameter",
468 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
469 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
473 _E("INVALID_PARAMETER(0x%08x) : invalid output parameter",
474 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
475 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
478 if (runtime_info_get_frequency_cpufreq(core_idx, "max", cpu_freq)
479 != RUNTIME_INFO_ERROR_NONE) {
480 _I("This system doesn't support cpufreq. Use cpuinfo instead.");
482 switch (runtime_info_get_frequency_cpuinfo(core_idx, cpu_freq)) {
483 case RUNTIME_INFO_ERROR_NONE:
485 case RUNTIME_INFO_ERROR_NOT_SUPPORTED:
486 _E("This system doesn't support MHz information in the cpuinfo");
487 return RUNTIME_INFO_ERROR_NOT_SUPPORTED;
489 _E("Fail to get current CPU frequency");
490 return RUNTIME_INFO_ERROR_IO_ERROR;
494 return RUNTIME_INFO_ERROR_NONE;