runtime-info: added process Memory and CPU usage APIs 21/40721/1 accepted/tizen_3.0.2015.q2_common tizen_3.0.2015.q2_common accepted/tizen/3.0.2015.q2/common/20150615.091801 accepted/tizen/common/20150610.144403 accepted/tizen/mobile/20150611.004436 accepted/tizen/tv/20150611.004445 accepted/tizen/wearable/20150611.004459 submit/tizen/20150609.090156 submit/tizen_3.0.2015.q2_common/20150615.075539
authorPrajwal A N <an.prajwal@samsung.com>
Wed, 27 May 2015 12:16:14 +0000 (21:16 +0900)
committerTaeyoung Kim <ty317.kim@samsung.com>
Mon, 8 Jun 2015 09:55:59 +0000 (18:55 +0900)
* 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 <an.prajwal@samsung.com>
CMakeLists.txt
include/runtime_info.h
packaging/capi-system-runtime-info.spec
src/runtime_info_usage.c

index 70ed8d7..d596761 100755 (executable)
@@ -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)
index 53cc112..6ce30da 100644 (file)
@@ -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()
  */
index 7805681..6d8c32d 100644 (file)
@@ -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
 
index 517f852..78496eb 100644 (file)
 
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <dlog.h>
 
 #include <runtime_info.h>
 #include <runtime_info_private.h>
 
+#include <E_DBus.h>
+
 #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;
 }