removed log messages from process usage info APIs
[platform/core/api/runtime-info.git] / src / runtime_info_usage.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <dlog.h>
22
23 #include <runtime_info.h>
24 #include <runtime_info_private.h>
25
26 #include <E_DBus.h>
27
28 #ifdef LOG_TAG
29 #undef LOG_TAG
30 #endif
31 #define LOG_TAG "CAPI_RUNTIME_INFO_USAGE"
32
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)
36
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
44 #define CPU_USAGE 2
45
46 #define kBtoKiB(val) (int)(((long long)val * 1024)/1000)
47
48 static int runtime_info_get_dbus_error(const char *err_name)
49 {
50         int size;
51
52         if (!err_name)
53                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
54
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;
62         else
63                 return RUNTIME_INFO_ERROR_REMOTE_IO;
64 }
65
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
70  */
71 static DBusMessage *runtime_info_dbus_process_usage_info(int *pid, int size, int info, int *error)
72 {
73         DBusConnection *conn;
74         DBusMessage *msg;
75         DBusMessage *reply;
76         DBusError err;
77         int ret;
78
79         if (!pid || !error) {
80                 _E("INVALID_PARAMETER(0x%08x): pid list and error params cannot be null");
81
82                 if (error)
83                         *error = RUNTIME_INFO_ERROR_INVALID_PARAMETER;
84                 return NULL;
85         }
86
87         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
88         if (!conn) {
89                 _E("DBUS_CONNECTION_ERROR");
90                 *error = RUNTIME_INFO_ERROR_REMOTE_IO;
91                 return NULL;
92         }
93
94         if (info == MEMORY_USAGE) {
95                 _D("Process %d: received query to get process memory info of %d processes",
96                                 getpid(), size);
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",
103                                 getpid(), size);
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);
108         } else {
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;
112                 return NULL;
113         }
114
115         if (!msg) {
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;
120                 return NULL;
121         }
122
123         ret = dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &pid,
124                         size, DBUS_TYPE_INVALID);
125         if (!ret) {
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);
129                 return NULL;
130         }
131
132         dbus_error_init(&err);
133         *error = 0;
134
135         if (info == MEMORY_USAGE)
136                 _D("Process %d: Sending dbus message to resourced for process memory usage info",
137                                 getpid());
138         else
139                 _D("Process %d: Sending dbus message to resourced for process cpu usage info",
140                                 getpid());
141         reply = dbus_connection_send_with_reply_and_block(conn, msg,
142                         DBUS_REPLY_TIMEOUT, &err);
143         if (!reply)
144                 _E("DBUS_METHOD_CALL: not able to send message");
145
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);
150                 reply = NULL;
151         }
152
153         dbus_message_unref(msg);
154         return reply;
155 }
156
157 API int runtime_info_get_system_memory_info(runtime_memory_info_s *info)
158 {
159         FILE *meminfo_fp;
160         char buf[256];
161         unsigned long swap_total, swap_free, value;
162
163         if (info == NULL) {
164                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
165                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
166                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
167         }
168
169         swap_total = swap_free = 0;
170
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;
176         }
177
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)
186                         swap_total = value;
187                 else if (sscanf(buf, "SwapFree: %lu", &value) == 1)
188                         swap_free = value;
189         }
190         fclose(meminfo_fp);
191
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));
194
195         return RUNTIME_INFO_ERROR_NONE;
196 }
197
198 API int runtime_info_get_process_memory_info(int *pid, int size, process_memory_info_s **info)
199 {
200         DBusMessageIter iter, iter_array, iter_struct;
201         int index, value;
202         int error;
203         process_memory_info_s *proc_info;
204         DBusMessage *replymsg;
205
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;
210         }
211
212         if (!info) {
213                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
214                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
215                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
216         }
217
218         *info = NULL;
219
220         /* Get the needed information from resourced daemon using dbus */
221         replymsg = runtime_info_dbus_process_usage_info(pid, size, MEMORY_USAGE, &error);
222         if (!replymsg) {
223                 _E("DBUS_METHOD_CALL: call to resourced not successful");
224                 return error;
225         }
226
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);
234                 return error;
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;
239         }
240
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));
243         if (!info) {
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;
247         }
248
249         dbus_message_iter_recurse(&iter, &iter_array);
250         for (index = 0; index < size; ++index) {
251                 proc_info = &(*info)[index];
252
253                 dbus_message_iter_recurse(&iter_array, &iter_struct);
254
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;
275
276                 dbus_message_iter_next(&iter_array);
277         }
278
279         dbus_message_unref(replymsg);
280         return RUNTIME_INFO_ERROR_NONE;
281 }
282
283 API int runtime_info_get_cpu_usage(runtime_cpu_usage_s *usage)
284 {
285         FILE *cpuinfo_fp;
286         char buf[256];
287         unsigned long long user, nice, system, idle, iowait, irq, softirq, total_uptime;
288
289         if (usage == NULL) {
290                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
291                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
292                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
293         }
294
295         cpuinfo_fp = fopen("/proc/stat", "r");
296         if (cpuinfo_fp == NULL) {
297                 _E("IO_ERROR(0x%08x) : failed to open file to read cpu usage",
298                                 RUNTIME_INFO_ERROR_IO_ERROR);
299                 return RUNTIME_INFO_ERROR_IO_ERROR;
300         }
301
302         while (fgets(buf, sizeof(buf), cpuinfo_fp) != NULL) {
303                 if (!strncmp(buf, "cpu ", 4) &&
304                     sscanf(buf+4, "%llu %llu %llu %llu %llu %llu %llu",
305                                 &user, &nice, &system, &idle,
306                                 &iowait, &irq, &softirq) == 7)
307                         break;
308         }
309         fclose(cpuinfo_fp);
310
311         total_uptime = user+nice+system+idle+iowait+irq+softirq;
312
313         usage->user = (double)user*100/total_uptime;
314         usage->nice = (double)nice*100/total_uptime;
315         usage->system = (double)system*100/total_uptime;
316         usage->iowait = (double)iowait*100/total_uptime;
317
318         return RUNTIME_INFO_ERROR_NONE;
319 }
320
321 API int runtime_info_get_process_cpu_usage(int *pid, int size, process_cpu_usage_s **usage)
322 {
323         DBusMessageIter iter, iter_array, iter_struct;
324         int index, value;
325         int error;
326         process_cpu_usage_s *proc_usage;
327         DBusMessage *replymsg;
328
329         if (!pid || size <= 0) {
330                 _E("INVALID_PARAMETER(0x%08x) : invalid input param",
331                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
332                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
333         }
334
335         if (!usage) {
336                 _E("INVALID_PARAMETER(0x%08x) : invalid output param",
337                                 RUNTIME_INFO_ERROR_INVALID_PARAMETER);
338                 return RUNTIME_INFO_ERROR_INVALID_PARAMETER;
339         }
340
341         *usage = NULL;
342
343         /* Get the needed information from resourced daemon using dbus */
344         replymsg = runtime_info_dbus_process_usage_info(pid, size, CPU_USAGE, &error);
345         if (!replymsg) {
346                 _E("DBUS_METHOD_CALL: call to resourced not successful");
347                 return error;
348         }
349
350         /* Check if the message is an error message or not in expected format
351          * and return error value */
352         dbus_message_iter_init(replymsg, &iter);
353         if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32) {
354                 dbus_message_iter_get_basic(&iter, &error);
355                 _E("DBUS_METHOD_CALL: call to resourced returned error message");
356                 dbus_message_unref(replymsg);
357                 return error;
358         } else if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
359                 _E("DBUS_METHOD_CALL: received dbus message is not in expected format");
360                 dbus_message_unref(replymsg);
361                 return RUNTIME_INFO_ERROR_REMOTE_IO;
362         }
363
364         /* Populate the entries of info array using the data received from resourced */
365         *usage = (process_cpu_usage_s *)malloc(size * sizeof(process_cpu_usage_s));
366         if (!(*usage)) {
367                 _E("OUT_OF_MEMORY(0x%08x)", RUNTIME_INFO_ERROR_OUT_OF_MEMORY);
368                 dbus_message_unref(replymsg);
369                 return RUNTIME_INFO_ERROR_OUT_OF_MEMORY;
370         }
371
372         dbus_message_iter_recurse(&iter, &iter_array);
373         for (index = 0; index < size; ++index) {
374                 proc_usage = &(*usage)[index];
375
376                 dbus_message_iter_recurse(&iter_array, &iter_struct);
377
378                 dbus_message_iter_get_basic(&iter_struct, &value);
379                 proc_usage->utime = value;
380                 dbus_message_iter_next(&iter_struct);
381                 dbus_message_iter_get_basic(&iter_struct, &value);
382                 proc_usage->stime = value;
383
384                 dbus_message_iter_next(&iter_array);
385         }
386
387         dbus_message_unref(replymsg);
388         return RUNTIME_INFO_ERROR_NONE;
389 }