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>
31 #define LOG_TAG "CAPI_RUNTIME_INFO_USAGE"
33 #define _E(fmt, arg...) LOGE("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg)
34 #define _D(fmt, arg...) LOGD("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg)
35 #define _I(fmt, arg...) LOGI("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg)
37 #define RESOURCED_BUS_NAME "org.tizen.resourced"
38 #define RESOURCED_USAGE_OBJECT_NAME "/Org/Tizen/ResourceD/Process"
39 #define RESOURCED_USAGE_INTERFACE_NAME "org.tizen.resourced.process"
40 #define RESOURCED_MEMORY_USAGE_METHOD "ProcMemoryUsage"
41 #define RESOURCED_CPU_USAGE_METHOD "ProcCpuUsage"
42 #define DBUS_REPLY_TIMEOUT (120 * 1000)
43 #define MEMORY_USAGE 1
46 #define kBtoKiB(val) (int)(((long long)val * 1024)/1000)
48 static int runtime_info_get_dbus_error(const char *err_name)
53 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
55 size = strlen(err_name);
56 if (!strncmp(err_name, DBUS_ERROR_IO_ERROR, size))
57 return RUNTIME_INFO_ERROR_IO_ERROR;
58 else if (!strncmp(err_name, DBUS_ERROR_NO_MEMORY, size))
59 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
60 else if (!strncmp(err_name, DBUS_ERROR_ACCESS_DENIED, size))
61 return RUNTIME_INFO_ERROR_PERMISSION_DENIED;
63 return RUNTIME_INFO_ERROR_REMOTE_IO;
66 /* Handler function which handles dbus related instructions
67 * for both per process memory and cpu requests.
68 * Creates the method call to resourced and receives the reply (if successful)
69 * Return the received reply (if received) else NULL to signify failed call to resourced
71 static DBusMessage *runtime_info_dbus_process_usage_info(int *pid, int size, int info, int *error)
80 _E("INVALID_PARAMETER(0x%08x): pid list and error params cannot be null");
83 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
87 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
89 _E("DBUS_CONNECTION_ERROR");
90 *error = RUNTIME_INFO_ERROR_REMOTE_IO;
94 if (info == MEMORY_USAGE) {
95 _D("Process %d: received query to get process memory info of %d processes",
97 msg = dbus_message_new_method_call(RESOURCED_BUS_NAME,
98 RESOURCED_USAGE_OBJECT_NAME,
99 RESOURCED_USAGE_INTERFACE_NAME,
100 RESOURCED_MEMORY_USAGE_METHOD);
101 } else if (info == CPU_USAGE) {
102 _D("Process %d: received query to get process cpu usage of %d processes",
104 msg = dbus_message_new_method_call(RESOURCED_BUS_NAME,
105 RESOURCED_USAGE_OBJECT_NAME,
106 RESOURCED_USAGE_INTERFACE_NAME,
107 RESOURCED_CPU_USAGE_METHOD);
109 _E("INVALID_PARAMETER(0x%08x): info parameter should be %d or %d",
110 MEMORY_USAGE, CPU_USAGE, RUNTIME_INFO_ERROR_INVALID_PARAMETER);
111 *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
116 _E("DBUS_METHOD_CALL: not able to create method call (%s:%s-%s)",
117 RESOURCED_USAGE_OBJECT_NAME, RESOURCED_USAGE_INTERFACE_NAME,
118 RESOURCED_MEMORY_USAGE_METHOD);
119 *error = RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
123 ret = dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &pid,
124 size, DBUS_TYPE_INVALID);
126 _E("DBUS_METHOD_CALL: not able to append pid array to message");
127 *error = RUNTIME_INFO_ERROR_IO_ERROR;
128 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");
146 if (dbus_error_is_set(&err)) {
147 _E("DBUS_METHOD_CALL: dbus_connection_send error(%s:%s)", err.name, err.message);
148 *error = runtime_info_get_dbus_error(err.name);
149 dbus_error_free(&err);
153 dbus_message_unref(msg);
157 API int runtime_info_get_system_memory_info(runtime_memory_info_s *info)
161 unsigned long swap_total, swap_free, value;
164 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
165 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
166 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
169 swap_total = swap_free = 0;
171 meminfo_fp = fopen("/proc/meminfo", "r");
172 if (meminfo_fp == NULL) {
173 _E("IO_ERROR(0x%08x) : failed to open file to read memory usage",
174 RUNTIME_INFO_ERROR_IO_ERROR);
175 return RUNTIME_INFO_ERROR_IO_ERROR;
178 while (fgets(buf, sizeof(buf), meminfo_fp) != NULL) {
179 if (sscanf(buf, "MemTotal: %lu", &value) == 1)
180 info->total = kBtoKiB(value);
181 else if (sscanf(buf, "MemFree: %lu", &value) == 1)
182 info->free = kBtoKiB(value);
183 else if (sscanf(buf, "Cached: %lu", &value) == 1)
184 info->cache = kBtoKiB(value);
185 else if (sscanf(buf, "SwapTotal: %lu", &value) == 1)
187 else if (sscanf(buf, "SwapFree: %lu", &value) == 1)
192 info->used = (info->total > info->free) ? (info->total - info->free) : 0;
193 info->swap = kBtoKiB(((swap_total > swap_free) ? (int)(swap_total - swap_free) : 0));
195 return RUNTIME_INFO_ERROR_NONE;
198 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
200 DBusMessageIter iter, iter_array, iter_struct;
203 process_memory_info_s *proc_info;
204 DBusMessage *replymsg;
206 if (!pid || size <= 0) {
207 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
208 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
209 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
213 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
214 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
215 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
220 /* Get the needed information from resourced daemon using dbus */
221 replymsg = runtime_info_dbus_process_usage_info(pid, size, MEMORY_USAGE, &error);
223 _E("DBUS_METHOD_CALL: call to resourced not successful");
227 /* Check if the message is an error message or not in expected
228 * format and return error value */
229 dbus_message_iter_init(replymsg, &iter);
230 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
231 dbus_message_iter_get_basic(&iter, &error);
232 _E("DBUS_METHOD_CALL: call to resourced returned error message");
233 dbus_message_unref(replymsg);
235 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
236 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
237 dbus_message_unref(replymsg);
238 return RUNTIME_INFO_ERROR_REMOTE_IO;
241 /* Populate the entries of info array using the data received from resourced */
242 *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s));
244 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
245 dbus_message_unref(replymsg);
246 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
249 dbus_message_iter_recurse(&iter, &iter_array);
250 for (index = 0; index < size; ++index) {
251 proc_info = &(*info)[index];
253 dbus_message_iter_recurse(&iter_array, &iter_struct);
255 dbus_message_iter_get_basic(&iter_struct, &value);
256 proc_info->vsz = value;
257 dbus_message_iter_next(&iter_struct);
258 dbus_message_iter_get_basic(&iter_struct, &value);
259 proc_info->rss = value;
260 dbus_message_iter_next(&iter_struct);
261 dbus_message_iter_get_basic(&iter_struct, &value);
262 proc_info->pss = value;
263 dbus_message_iter_next(&iter_struct);
264 dbus_message_iter_get_basic(&iter_struct, &value);
265 proc_info->shared_clean = value;
266 dbus_message_iter_next(&iter_struct);
267 dbus_message_iter_get_basic(&iter_struct, &value);
268 proc_info->shared_dirty = value;
269 dbus_message_iter_next(&iter_struct);
270 dbus_message_iter_get_basic(&iter_struct, &value);
271 proc_info->private_clean = value;
272 dbus_message_iter_next(&iter_struct);
273 dbus_message_iter_get_basic(&iter_struct, &value);
274 proc_info->private_dirty = value;
276 _D("Index %d: Process %d, vsz %d, rss %d, pss %d, sh_clean %d, sh_dirty %d, pr_clean %d, pr_dirty %d",
277 index, pid[index], proc_info->vsz, proc_info->rss, proc_info->pss,
278 proc_info->shared_clean, proc_info->shared_dirty,
279 proc_info->private_clean, proc_info->private_dirty);
280 dbus_message_iter_next(&iter_array);
283 dbus_message_unref(replymsg);
284 return RUNTIME_INFO_ERROR_NONE;
287 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
291 unsigned long long user, nice, system, idle, iowait, irq, softirq, total_uptime;
294 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
295 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
296 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
299 cpuinfo_fp = fopen("/proc/stat", "r");
300 if (cpuinfo_fp == NULL) {
301 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
302 RUNTIME_INFO_ERROR_IO_ERROR);
303 return RUNTIME_INFO_ERROR_IO_ERROR;
306 while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
307 if (!strncmp(buf, "cpu ", 4) &&
308 sscanf(buf+4, "%llu %llu %llu %llu %llu %llu %llu",
309 &user, &nice, &system, &idle,
310 &iowait, &irq, &softirq) == 7)
315 total_uptime = user+nice+system+idle+iowait+irq+softirq;
317 usage->user = (double)user*100/total_uptime;
318 usage->nice = (double)nice*100/total_uptime;
319 usage->system = (double)system*100/total_uptime;
320 usage->iowait = (double)iowait*100/total_uptime;
322 return RUNTIME_INFO_ERROR_NONE;
325 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
327 DBusMessageIter iter, iter_array, iter_struct;
330 process_cpu_usage_s *proc_usage;
331 DBusMessage *replymsg;
333 if (!pid || size <= 0) {
334 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
335 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
336 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
340 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
341 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
342 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
347 /* Get the needed information from resourced daemon using dbus */
348 replymsg = runtime_info_dbus_process_usage_info(pid, size, CPU_USAGE, &error);
350 _E("DBUS_METHOD_CALL: call to resourced not successful");
354 /* Check if the message is an error message or not in expected format
355 * and return error value */
356 dbus_message_iter_init(replymsg, &iter);
357 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
358 dbus_message_iter_get_basic(&iter, &error);
359 _E("DBUS_METHOD_CALL: call to resourced returned error message");
360 dbus_message_unref(replymsg);
362 } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
363 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
364 dbus_message_unref(replymsg);
365 return RUNTIME_INFO_ERROR_REMOTE_IO;
368 /* Populate the entries of info array using the data received from resourced */
369 *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
371 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
372 dbus_message_unref(replymsg);
373 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
376 dbus_message_iter_recurse(&iter, &iter_array);
377 for (index = 0; index < size; ++index) {
378 proc_usage = &(*usage)[index];
380 dbus_message_iter_recurse(&iter_array, &iter_struct);
382 dbus_message_iter_get_basic(&iter_struct, &value);
383 proc_usage->utime = value;
384 dbus_message_iter_next(&iter_struct);
385 dbus_message_iter_get_basic(&iter_struct, &value);
386 proc_usage->stime = value;
388 _D("Index %d: Process %d, utime %d, stime %d", index, pid[index],
389 proc_usage->utime, proc_usage->stime);
390 dbus_message_iter_next(&iter_array);
393 dbus_message_unref(replymsg);
394 return RUNTIME_INFO_ERROR_NONE;