From 8665d7290a71c379de0a17d3c1f68ff4e3ca7126 Mon Sep 17 00:00:00 2001 From: Prajwal A N Date: Wed, 27 May 2015 21:16:14 +0900 Subject: [PATCH] runtime-info: added process Memory and CPU usage APIs * added call to dbus methods in resourced * added code to parse the reply dbus message and populate the right structs Change-Id: I94514adf12fea4257c759c977a473f5dc658c0a6 Signed-off-by: Prajwal A N --- CMakeLists.txt | 2 +- include/runtime_info.h | 10 +- packaging/capi-system-runtime-info.spec | 1 + src/runtime_info_usage.c | 291 +++++++++++++++++++++++++++++++- 4 files changed, 295 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70ed8d7..d596761 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(requires "dlog vconf capi-base-common") +SET(requires "dlog vconf capi-base-common edbus") SET(pc_requires "capi-base-common") INCLUDE(FindPkgConfig) diff --git a/include/runtime_info.h b/include/runtime_info.h index 53cc112..6ce30da 100644 --- a/include/runtime_info.h +++ b/include/runtime_info.h @@ -316,7 +316,10 @@ typedef struct { * * @retval #RUNTIME_INFO_ERROR_NONE Successful * @retval #RUNTIME_INFO_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #RUNTIME_INFO_ERROR_PERMISSION_DENIED Permission denied + * @retval #RUNTIME_INFO_ERROR_OUT_OF_MEMORY Not able to allocate memory (for output param/other operations) + * @retval #RUNTIME_INFO_ERROR_REMOTE_IO Call to resource daemon failed (dbus errors/resource daemon errors) + * @retval #RUNTIME_INFO_ERROR_IO_ERROR An I/O error during dbus message operations + * @retval #RUNTIME_INFO_PERMISSION_DENIED Process not authorized to request process usage info * * @see runtime_info_get_system_memory_info() */ @@ -377,7 +380,10 @@ typedef struct { * * @retval #RUNTIME_INFO_ERROR_NONE Successful * @retval #RUNTIME_INFO_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #RUNTIME_INFO_ERROR_PERMISSION_DENIED Permission denied + * @retval #RUNTIME_INFO_ERROR_OUT_OF_MEMORY Not able to allocate memory (for output param/other operations) + * @retval #RUNTIME_INFO_ERROR_REMOTE_IO Call to resource daemon failed (dbus errors/resource daemon errors) + * @retval #RUNTIME_INFO_ERROR_IO_ERROR An I/O error occured (during dbus message operations/other IO operations) + * @retval #RUNTIME_INFO_PERMISSION_DENIED Process not authorized to request process usage info * * @see runtime_info_get_cpu_usage() */ diff --git a/packaging/capi-system-runtime-info.spec b/packaging/capi-system-runtime-info.spec index 7805681..6d8c32d 100644 --- a/packaging/capi-system-runtime-info.spec +++ b/packaging/capi-system-runtime-info.spec @@ -11,6 +11,7 @@ BuildRequires: cmake BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(vconf) BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(edbus) Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig diff --git a/src/runtime_info_usage.c b/src/runtime_info_usage.c index 517f852..78496eb 100644 --- a/src/runtime_info_usage.c +++ b/src/runtime_info_usage.c @@ -16,19 +16,143 @@ #include #include +#include #include #include #include +#include + #ifdef LOG_TAG #undef LOG_TAG #endif +#define LOG_TAG "CAPI_RUNTIME_INFO_USAGE" + +#define _E(fmt, arg...) LOGE("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg) +#define _D(fmt, arg...) LOGD("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg) +#define _I(fmt, arg...) LOGI("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg) + +#define RESOURCED_BUS_NAME "org.tizen.resourced" +#define RESOURCED_USAGE_OBJECT_NAME "/Org/Tizen/ResourceD/Process" +#define RESOURCED_USAGE_INTERFACE_NAME "org.tizen.resourced.process" +#define RESOURCED_MEMORY_USAGE_METHOD "ProcMemoryUsage" +#define RESOURCED_CPU_USAGE_METHOD "ProcCpuUsage" +#define DBUS_REPLY_TIMEOUT (120 * 1000) +#define MEMORY_USAGE 1 +#define CPU_USAGE 2 + +#define kBtoKiB(val) (int)(((long long)val * 1024)/1000) + +static int runtime_info_get_dbus_error(const char *err_name) +{ + int size; + + if (!err_name) + return RUNTIME_INFO_ERROR_INVALID_PARAMETER; + + size = strlen(err_name); + if (!strncmp(err_name, DBUS_ERROR_IO_ERROR, size)) + return RUNTIME_INFO_ERROR_IO_ERROR; + else if (!strncmp(err_name, DBUS_ERROR_NO_MEMORY, size)) + return RUNTIME_INFO_ERROR_OUT_OF_MEMORY; + else if (!strncmp(err_name, DBUS_ERROR_ACCESS_DENIED, size)) + return RUNTIME_INFO_ERROR_PERMISSION_DENIED; + else + return RUNTIME_INFO_ERROR_REMOTE_IO; +} + +/* Handler function which handles dbus related instructions + * for both per process memory and cpu requests. + * Creates the method call to resourced and receives the reply (if successful) + * Return the received reply (if received) else NULL to signify failed call to resourced + */ +static DBusMessage *runtime_info_dbus_process_usage_info(int *pid, int size, int info, int *error) +{ + DBusConnection *conn; + DBusMessage *msg; + DBusMessage *reply; + DBusError err; + int ret; + + if (!pid || !error) { + _E("INVALID_PARAMETER(0x%08x): pid list and error params cannot be null"); + + if (error) + *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER; + return NULL; + } -#define LOG_TAG "CAPI_SYSTEM_RUNTIME_INFO" + conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (!conn) { + _E("DBUS_CONNECTION_ERROR"); + *error = RUNTIME_INFO_ERROR_REMOTE_IO; + return NULL; + } -#define kBtoKiB(val) (int)(((long long)val*1024)/1000) + if (info == MEMORY_USAGE) { + _D("Process %d: received query to get process memory info of %d processes", + getpid(), size); + msg = dbus_message_new_method_call(RESOURCED_BUS_NAME, + RESOURCED_USAGE_OBJECT_NAME, + RESOURCED_USAGE_INTERFACE_NAME, + RESOURCED_MEMORY_USAGE_METHOD); + } else if (info == CPU_USAGE) { + _D("Process %d: received query to get process cpu usage of %d processes", + getpid(), size); + msg = dbus_message_new_method_call(RESOURCED_BUS_NAME, + RESOURCED_USAGE_OBJECT_NAME, + RESOURCED_USAGE_INTERFACE_NAME, + RESOURCED_CPU_USAGE_METHOD); + } else { + _E("INVALID_PARAMETER(0x%08x): info parameter should be %d or %d", + MEMORY_USAGE, CPU_USAGE, RUNTIME_INFO_ERROR_INVALID_PARAMETER); + *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (!msg) { + _E("DBUS_METHOD_CALL: not able to create method call (%s:%s-%s)", + RESOURCED_USAGE_OBJECT_NAME, RESOURCED_USAGE_INTERFACE_NAME, + RESOURCED_MEMORY_USAGE_METHOD); + *error = RUNTIME_INFO_ERROR_OUT_OF_MEMORY; + return NULL; + } + + ret = dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &pid, + size, DBUS_TYPE_INVALID); + if (!ret) { + _E("DBUS_METHOD_CALL: not able to append pid array to message"); + *error = RUNTIME_INFO_ERROR_IO_ERROR; + dbus_message_unref(msg); + return NULL; + } + + dbus_error_init(&err); + *error = 0; + + if (info == MEMORY_USAGE) + _D("Process %d: Sending dbus message to resourced for process memory usage info", + getpid()); + else + _D("Process %d: Sending dbus message to resourced for process cpu usage info", + getpid()); + reply = dbus_connection_send_with_reply_and_block(conn, msg, + DBUS_REPLY_TIMEOUT, &err); + if (!reply) + _E("DBUS_METHOD_CALL: not able to send message"); + + if (dbus_error_is_set(&err)) { + _E("DBUS_METHOD_CALL: dbus_connection_send error(%s:%s)", err.name, err.message); + *error = runtime_info_get_dbus_error(err.name); + dbus_error_free(&err); + reply = NULL; + } + + dbus_message_unref(msg); + return reply; +} API int runtime_info_get_system_memory_info(runtime_memory_info_s *info) { @@ -37,7 +161,8 @@ API int runtime_info_get_system_memory_info(runtime_memory_info_s *info) unsigned long swap_total, swap_free, value; if (info == NULL) { - LOGE("INVALID_PARAMETER(0x%08x) : invalid output param", RUNTIME_INFO_ERROR_INVALID_PARAMETER); + _E("INVALID_PARAMETER(0x%08x) : invalid output param", + RUNTIME_INFO_ERROR_INVALID_PARAMETER); return RUNTIME_INFO_ERROR_INVALID_PARAMETER; } @@ -45,7 +170,8 @@ API int runtime_info_get_system_memory_info(runtime_memory_info_s *info) meminfo_fp = fopen("/proc/meminfo", "r"); if (meminfo_fp == NULL) { - LOGE("IO_ERROR(0x%08x) : failed to open file to read memory usage", RUNTIME_INFO_ERROR_IO_ERROR); + _E("IO_ERROR(0x%08x) : failed to open file to read memory usage", + RUNTIME_INFO_ERROR_IO_ERROR); return RUNTIME_INFO_ERROR_IO_ERROR; } @@ -71,6 +197,90 @@ API int runtime_info_get_system_memory_info(runtime_memory_info_s *info) API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info) { + DBusMessageIter iter, iter_array, iter_struct; + int index, value; + int error; + process_memory_info_s *proc_info; + DBusMessage *replymsg; + + if (!pid || size <= 0) { + _E("INVALID_PARAMETER(0x%08x) : invalid input param", + RUNTIME_INFO_ERROR_INVALID_PARAMETER); + return RUNTIME_INFO_ERROR_INVALID_PARAMETER; + } + + if (!info) { + _E("INVALID_PARAMETER(0x%08x) : invalid output param", + RUNTIME_INFO_ERROR_INVALID_PARAMETER); + return RUNTIME_INFO_ERROR_INVALID_PARAMETER; + } + + *info = NULL; + + /* Get the needed information from resourced daemon using dbus */ + replymsg = runtime_info_dbus_process_usage_info(pid, size, MEMORY_USAGE, &error); + if (!replymsg) { + _E("DBUS_METHOD_CALL: call to resourced not successful"); + return error; + } + + /* Check if the message is an error message or not in expected + * format and return error value */ + dbus_message_iter_init(replymsg, &iter); + if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) { + dbus_message_iter_get_basic(&iter, &error); + _E("DBUS_METHOD_CALL: call to resourced returned error message"); + dbus_message_unref(replymsg); + return error; + } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { + _E("DBUS_METHOD_CALL: received dbus message is not in expected format"); + dbus_message_unref(replymsg); + return RUNTIME_INFO_ERROR_REMOTE_IO; + } + + /* Populate the entries of info array using the data received from resourced */ + *info = (process_memory_info_s *)malloc(size * sizeof(process_memory_info_s)); + if (!info) { + _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY); + dbus_message_unref(replymsg); + return RUNTIME_INFO_ERROR_OUT_OF_MEMORY; + } + + dbus_message_iter_recurse(&iter, &iter_array); + for (index = 0; index < size; ++index) { + proc_info = &(*info)[index]; + + dbus_message_iter_recurse(&iter_array, &iter_struct); + + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->vsz = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->rss = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->pss = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->shared_clean = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->shared_dirty = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->private_clean = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_info->private_dirty = value; + + _D("Index %d: Process %d, vsz %d, rss %d, pss %d, sh_clean %d, sh_dirty %d, pr_clean %d, pr_dirty %d", + index, pid[index], proc_info->vsz, proc_info->rss, proc_info->pss, + proc_info->shared_clean, proc_info->shared_dirty, + proc_info->private_clean, proc_info->private_dirty); + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(replymsg); return RUNTIME_INFO_ERROR_NONE; } @@ -81,13 +291,15 @@ API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage) unsigned long long user, nice, system, idle, iowait, irq, softirq, total_uptime; if (usage == NULL) { - LOGE("INVALID_PARAMETER(0x%08x) : invalid output param", RUNTIME_INFO_ERROR_INVALID_PARAMETER); + _E("INVALID_PARAMETER(0x%08x) : invalid output param", + RUNTIME_INFO_ERROR_INVALID_PARAMETER); return RUNTIME_INFO_ERROR_INVALID_PARAMETER; } cpuinfo_fp = fopen("/proc/stat", "r"); if (cpuinfo_fp == NULL) { - LOGE("IO_ERROR(0x%08x) : failed to open file to read cpu usage", RUNTIME_INFO_ERROR_IO_ERROR); + _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage", + RUNTIME_INFO_ERROR_IO_ERROR); return RUNTIME_INFO_ERROR_IO_ERROR; } @@ -112,5 +324,72 @@ API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage) API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage) { + DBusMessageIter iter, iter_array, iter_struct; + int index, value; + int error; + process_cpu_usage_s *proc_usage; + DBusMessage *replymsg; + + if (!pid || size <= 0) { + _E("INVALID_PARAMETER(0x%08x) : invalid input param", + RUNTIME_INFO_ERROR_INVALID_PARAMETER); + return RUNTIME_INFO_ERROR_INVALID_PARAMETER; + } + + if (!usage) { + _E("INVALID_PARAMETER(0x%08x) : invalid output param", + RUNTIME_INFO_ERROR_INVALID_PARAMETER); + return RUNTIME_INFO_ERROR_INVALID_PARAMETER; + } + + *usage = NULL; + + /* Get the needed information from resourced daemon using dbus */ + replymsg = runtime_info_dbus_process_usage_info(pid, size, CPU_USAGE, &error); + if (!replymsg) { + _E("DBUS_METHOD_CALL: call to resourced not successful"); + return error; + } + + /* Check if the message is an error message or not in expected format + * and return error value */ + dbus_message_iter_init(replymsg, &iter); + if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) { + dbus_message_iter_get_basic(&iter, &error); + _E("DBUS_METHOD_CALL: call to resourced returned error message"); + dbus_message_unref(replymsg); + return error; + } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { + _E("DBUS_METHOD_CALL: received dbus message is not in expected format"); + dbus_message_unref(replymsg); + return RUNTIME_INFO_ERROR_REMOTE_IO; + } + + /* Populate the entries of info array using the data received from resourced */ + *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s)); + if (!(*usage)) { + _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY); + dbus_message_unref(replymsg); + return RUNTIME_INFO_ERROR_OUT_OF_MEMORY; + } + + dbus_message_iter_recurse(&iter, &iter_array); + for (index = 0; index < size; ++index) { + proc_usage = &(*usage)[index]; + + dbus_message_iter_recurse(&iter_array, &iter_struct); + + dbus_message_iter_get_basic(&iter_struct, &value); + proc_usage->utime = value; + dbus_message_iter_next(&iter_struct); + dbus_message_iter_get_basic(&iter_struct, &value); + proc_usage->stime = value; + + _D("Index %d: Process %d, utime %d, stime %d", index, pid[index], + proc_usage->utime, proc_usage->stime); + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(replymsg); return RUNTIME_INFO_ERROR_NONE; } -- 2.7.4