+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
-*/
-
-/*
- * @file proc_info.c
- * @desc It's main thread to get system & process information
- * to provide runtime api
-*/
-
-#include <stdio.h>
-#include <limits.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/stat.h>
-#include <sys/xattr.h>
-#include <pthread.h>
-
-#include <Ecore.h>
-
-#include "macro.h"
-#include "proc-main.h"
-#include "proc-info.h"
-#include "proc-process.h"
-#include "proc-noti.h"
-#include "resourced.h"
-#include "module.h"
-#include "trace.h"
-
-#define MAX_CONNECTION 5
-
-static pthread_t proc_info_thread;
-
-static void *resourced_proc_info_func(void *data)
-{
- struct sockaddr_un client_address;
- struct resourced_noti *msg;
- char *send_buffer = NULL;
- int ret, send_len = 0;
- long server_fd, client_fd, client_len;
- pid_t pid;
- struct timeval tv = { 1, 0 }; /* 1 sec */
-
- if (!data) {
- _E("data is NULL");
- return NULL;
- }
-
- server_fd = (long)data;
-
- client_len = sizeof(client_address);
-
- if (listen(server_fd, MAX_CONNECTION) < 0) {
- _E("Failed to listen socket");
- close(server_fd);
- return NULL;
- }
-
- while (1) {
- client_fd =
- accept(server_fd, (struct sockaddr *)&client_address,
- (socklen_t *)&client_len);
- if (client_fd < 0) {
- _E("Failed to accept");
- continue;
- }
- msg = calloc(1, sizeof(struct resourced_noti));
- if (msg == NULL) {
- _E("proc_noti_cb : Not enough memory");
- goto end;
- }
- ret = setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- if (ret)
- _E("failed to set socket option");
- ret = read_message(client_fd, msg);
- if (ret)
- goto end;
- if (msg->argc > NOTI_MAXARG || msg->type < PROC_CGROUP_GET_CMDLINE) {
- _E("%s : error argument", __func__);
- goto end;
- }
-
- pid = atoi(msg->argv[0]);
- send_len = atoi(msg->argv[1]);
- if (pid < 0 || send_len < 0) {
- _E("invalid parameters");
- goto end;
- }
- send_buffer = calloc(1, send_len);
- if (send_buffer == NULL) {
- _E("Not enough memory");
- goto end;
- }
- ret = proc_get_state(msg->type, pid, send_buffer, send_len);
-end:
- write_response(&ret, client_fd, send_buffer, send_len);
- free_message(msg);
- close(client_fd);
- if (send_buffer) {
- free(send_buffer);
- send_buffer = NULL;
- }
- ret = 0;
- send_len = 0;
- }
-
- return NULL;
-}
-
-static int proc_info_socket_init(void)
-{
- int fd;
- struct sockaddr_un serveraddr;
-
- if (access(RESOURCED_PROC_INFO_SOCKET_PATH, F_OK) == 0)
- unlink(RESOURCED_PROC_INFO_SOCKET_PATH);
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- _E("Failed to create socket");
- return -1;
- }
-
- if ((fsetxattr(fd, "security.SMACK64IPOUT", "@", 2, 0)) < 0) {
- _E("Failed to set Socket SMACK label");
- if (errno != EOPNOTSUPP) {
- close(fd);
- return -1;
- }
- }
-
- if ((fsetxattr(fd, "security.SMACK64IPIN", "*", 2, 0)) < 0) {
- _E("Failed to set Socket SMACK label");
- if (errno != EOPNOTSUPP) {
- close(fd);
- return -1;
- }
- }
-
- bzero(&serveraddr, sizeof(struct sockaddr_un));
- serveraddr.sun_family = AF_UNIX;
- strncpy(serveraddr.sun_path, RESOURCED_PROC_INFO_SOCKET_PATH,
- sizeof(serveraddr.sun_path));
-
- if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) < 0) {
- _E("Failed to bind socket");
- close(fd);
- return -1;
- }
-
- if (chmod(RESOURCED_PROC_INFO_SOCKET_PATH, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
- _E("Failed to change the socket permission");
- _D("socket create ok");
- return fd;
-}
-
-static int proc_info_init(void *data)
-{
- int ret;
- long fd;
-
- fd = proc_info_socket_init();
- if (fd < 0) {
- _E("Failed to init socket");
- return -1;
- }
- /* start thread */
- ret = pthread_create(&proc_info_thread, NULL, resourced_proc_info_func,
- (void *)fd);
- if (ret != 0) {
- _E("Failed to create thread");
- return RESOURCED_ERROR_FAIL;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int proc_info_exit(void *data)
-{
- _D("proc info exit!");
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct proc_module_ops proc_info_ops = {
- .name = "PROC_INFO",
- .init = proc_info_init,
- .exit = proc_info_exit,
-};
-PROC_MODULE_REGISTER(&proc_info_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
-*/
-
-/*
- * @file proc_noti.c
- * @desc It's main entry point for handling proc events
- * @see proc_cgroup_cmd_type
-*/
-
-#include <stdio.h>
-#include <limits.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/stat.h>
-#include <sys/xattr.h>
-
-#include <Ecore.h>
-#include <systemd/sd-daemon.h>
-
-#include "macro.h"
-#include "util.h"
-#include "proc-main.h"
-#include "proc-noti.h"
-#include "proc-process.h"
-#include "resourced.h"
-#include "trace.h"
-
-static int noti_fd;
-/*
- * @desc function receives uint
- * negative value for error reporting
- */
-static inline int recv_int(int fd)
-{
- int val = 0, r = -1;
- while (1) {
- r = read(fd, &val, sizeof(int));
- if (r == sizeof(int))
- return val;
-
- if (errno == EINTR) {
- _E("Re-read for error(EINTR)");
- continue;
- } else {
- _E("Read fail for int");
- return -errno;
- }
- }
-}
-
-static inline char *recv_str(int fd)
-{
- int len, r = -1;
- char *str;
-
- while (1) {
- r = read(fd, &len, sizeof(int));
- if (r < 0) {
- if (errno == EINTR) {
- _E("Re-read for error(EINTR)");
- continue;
- } else {
- _E("Read fail for str length");
- return NULL;
- }
- } else
- break;
- }
-
- if (len <= 0)
- return NULL;
-
- if (len >= INT_MAX - 1) {
- _E("size is over INT_MAX");
- return NULL;
- }
-
- str = (char *)malloc(len + 1);
- if (str == NULL) {
- _E("Not enough memory");
- return NULL;
- }
-
- while (1) {
- r = read(fd, str, len);
- if (r < 0) {
- if (errno == EINTR) {
- _E("Re-read for error(EINTR)");
- continue;
- } else {
- _E("Read fail for str");
- free(str);
- return NULL;
- }
- } else
- break;
- }
- str[len] = 0;
-
- return str;
-}
-
-/*
- * @desc This function read from fd to msg,
- * it supports multiple argument list given from client
- * of string type
- * @return 0 on success errno constants in error case
-*/
-int read_message(int fd, struct resourced_noti *msg)
-{
- int i;
-
- ret_value_if(fd < 0, RESOURCED_ERROR_FAIL);
- msg->pid = recv_int(fd);
- ret_value_if(msg->pid <= 0, errno);
- msg->type = recv_int(fd);
- ret_value_if(msg->type <= 0, errno);
- msg->argc = recv_int(fd);
- ret_value_if(msg->argc <= 0, errno);
- ret_value_if(msg->argc > NOTI_MAXARG, RESOURCED_ERROR_FAIL);
-
- for (i = 0; i < msg->argc; ++i) {
- msg->argv[i] = recv_str(fd);
- ret_value_if(msg->argv[i] <= 0, errno);
- }
-
- return 0;
-}
-
-static bool _fatal_read_message_error(const int error_code)
-{
- return error_code == EBADF || error_code == EISDIR;
-}
-
-static inline void internal_free(char *str)
-{
- if (str)
- free(str);
-}
-
-void free_message(struct resourced_noti *msg)
-{
- int i;
-
- if (!msg)
- return;
-
- for (i = 0; i < msg->argc; i++)
- internal_free(msg->argv[i]);
- free(msg);
-}
-
-static int process_message(struct resourced_noti *msg)
-{
- _D("process message caller pid %d\n", msg->pid);
- return resourced_proc_action(msg->type, msg->argc, msg->argv);
-}
-
-static void safe_write_int(int fd, int type, int *value)
-{
- bool sync = SYNC_OPERATION(type);
- int ret;
- if (!sync) {
- _D("Response is not needed");
- return;
- }
-
- ret = write(fd, value, sizeof(int));
- if (ret < 0)
- ETRACE_ERRNO_MSG("Failed to response to client, %d", *value);
-}
-
-int write_response(int *retval, int fd, char *buf, int len)
-{
- int ret;
- ret = send(fd, retval, sizeof(int), 0);
- if (ret < 0)
- _E("Failed to send");
- if (!buf)
- return ret;
- ret = send(fd, buf, len, 0);
- if (ret < 0)
- _E("Failed to write");
- return ret;
-}
-
-static Eina_Bool proc_noti_cb(void *data, Ecore_Fd_Handler *fd_handler)
-{
- int fd;
- struct resourced_noti *msg;
- int ret = -1;
- struct sockaddr_un client_address;
- int client_sockfd;
- int client_len;
- int error_code;
- _cleanup_free_ char *send_buffer = NULL;
- int send_len;
- pid_t pid;
- struct timeval tv = { 1, 0 }; /* 1 sec */
-
- if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
- _E("ecore_main_fd_handler_active_get error , return");
- return ECORE_CALLBACK_CANCEL;
- }
-
- fd = ecore_main_fd_handler_fd_get(fd_handler);
- if (fd < 0) {
- _E("ecore_main_fd_handler_fd_get failed");
- return ECORE_CALLBACK_CANCEL;
- }
-
- msg = calloc(1, sizeof(struct resourced_noti));
- if (msg == NULL) {
- _E("proc_noti_cb : Not enough memory");
- return ECORE_CALLBACK_RENEW;
- }
-
- client_len = sizeof(client_address);
- client_sockfd =
- accept(fd, (struct sockaddr *)&client_address,
- (socklen_t *)&client_len);
- if (client_sockfd == -1) {
- _E("socket accept error");
- free(msg);
- return ECORE_CALLBACK_RENEW;
- }
-
- ret = setsockopt(client_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- if (ret)
- _E("failed to set socket option");
- error_code = read_message(client_sockfd, msg);
-
- if (error_code && _fatal_read_message_error(error_code)) {
- free_message(msg);
- close(client_sockfd);
- return ECORE_CALLBACK_CANCEL;
- } else if (error_code) { /* It's not fatal */
- _E("%s : recv error msg, %d", __func__, error_code);
- safe_write_int(client_sockfd, msg->type, &ret);
- goto proc_noti_renew;
- }
-
- if (msg->argc > NOTI_MAXARG) {
- _E("%s : error argument", __func__);
- safe_write_int(client_sockfd, msg->type, &ret);
- goto proc_noti_renew;
- }
-
- if (msg->type >= PROC_CGROUP_GET_CMDLINE) {
- pid = atoi(msg->argv[0]);
- send_len = atoi(msg->argv[1]);
- if (pid <= 0 || send_len <= 0) {
- _E("invalid parameters");
- ret = -EINVAL;
- safe_write_int(client_sockfd, msg->type, &ret);
- goto proc_noti_renew;
- }
- send_buffer = calloc(1, send_len);
- if (!send_buffer) {
- _E("not enough memory for calloc");
- ret = -ENOMEM;
- safe_write_int(client_sockfd, msg->type, &ret);
- goto proc_noti_renew;
- }
- ret = proc_get_state(msg->type, pid, send_buffer, send_len);
- write_response(&ret, client_sockfd, send_buffer, send_len);
- } else {
- ret = process_message(msg);
- safe_write_int(client_sockfd, msg->type, &ret);
- }
-
-proc_noti_renew:
-
- close(client_sockfd);
- free_message(msg);
-
- return ECORE_CALLBACK_RENEW;
-}
-
-static int proc_noti_socket_init(void)
-{
- int fd, n = 0;
- struct sockaddr_un serveraddr;
-
- n = sd_listen_fds(0);
- if (n > 1) {
- _E("Error: Too many file descriptors received: %d", n);
- return -1;
- } else if (n == 1) {
- fd = SD_LISTEN_FDS_START + 0;
- } else {
- if (access(RESOURCED_SOCKET_PATH, F_OK) == 0)
- unlink(RESOURCED_SOCKET_PATH);
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- _E("%s: socket create failed\n", __func__);
- return -1;
- }
-
- if ((fsetxattr(fd, "security.SMACK64IPOUT", "@", 2, 0)) < 0) {
- _E("%s: Socket SMACK labeling failed\n", __func__);
- if (errno != EOPNOTSUPP) {
- close(fd);
- return -1;
- }
- }
-
- if ((fsetxattr(fd, "security.SMACK64IPIN", "*", 2, 0)) < 0) {
- _E("%s: Socket SMACK labeling failed\n", __func__);
- if (errno != EOPNOTSUPP) {
- close(fd);
- return -1;
- }
- }
-
- bzero(&serveraddr, sizeof(struct sockaddr_un));
- serveraddr.sun_family = AF_UNIX;
- strncpy(serveraddr.sun_path, RESOURCED_SOCKET_PATH,
- sizeof(serveraddr.sun_path)-1);
- serveraddr.sun_path[sizeof(serveraddr.sun_path)-1] = 0;
-
- if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) <
- 0) {
- _E("%s: socket bind failed\n", __func__);
- close(fd);
- return -1;
- }
-
- if (chmod(RESOURCED_SOCKET_PATH, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
- _E("failed to change the socket permission");
-
- if (listen(fd, 5) < 0) {
- _E("%s: socket listen failed\n", __func__);
- close(fd);
- return -1;
- }
- }
- _D("socket create & listen ok\n");
-
- return fd;
-}
-
-static int proc_noti_init(void *data)
-{
- noti_fd = proc_noti_socket_init();
- ecore_main_fd_handler_add(noti_fd, ECORE_FD_READ, (Ecore_Fd_Cb)proc_noti_cb,
- NULL, NULL, NULL);
- return RESOURCED_ERROR_NONE;
-}
-
-static int proc_noti_exit(void *data)
-{
- close(noti_fd);
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct proc_module_ops proc_noti_ops = {
- .name = "PROC_NOTI",
- .init = proc_noti_init,
- .exit = proc_noti_exit,
-};
-PROC_MODULE_REGISTER(&proc_noti_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Library for getting process statistics
- *
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <linux/limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <unistd.h>
-
-#include "macro.h"
-#include "util.h"
-#include "proc_stat.h"
-#include "procfs.h"
-#include "trace.h"
-#include "proc-noti.h"
-#include "proc-info.h"
-#include "const.h"
-
-#define PROC_STAT_PATH "/proc/%d/stat"
-#define PROC_STATM_PATH "/proc/%d/statm"
-#define PROC_CMDLINE_PATH "/proc/%d/cmdline"
-#define PROC_MEMINFO_BUF_SIZE 1024
-
-#ifndef TEST_IN_X86
-#include <assert.h>
-#else
-#define assert(x) \
-do { \
- if (!(x)) { \
- printf("assertion %s %d\n", __FILE__ , __LINE__); \
- exit(-1); \
- } \
-} while (0)
-#endif
-
-API bool proc_stat_get_cpu_time_by_pid(pid_t pid, unsigned long *utime,
- unsigned long *stime)
-{
- char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
- FILE *fp;
-
- assert(utime != NULL);
- assert(stime != NULL);
-
- snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
- fp = fopen(proc_path, "r");
- if (fp == NULL)
- return false;
-
- if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
- fclose(fp);
- return false;
- }
-
- if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
-
- return true;
-}
-
-
-API bool proc_stat_get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
-{
- FILE *fp;
- char proc_path[sizeof(PROC_STATM_PATH) + MAX_DEC_SIZE(int)] = {0};
-
- snprintf(proc_path, sizeof(proc_path), PROC_STATM_PATH, pid);
- fp = fopen(proc_path, "r");
- if (fp == NULL)
- return false;
-
- if (fscanf(fp, "%*s %d", rss) < 1) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
-
- /* convert page to Kb */
- *rss *= 4;
- return true;
-}
-
-API bool proc_stat_get_total_mem_size(unsigned int *total_mem)
-{
- static unsigned int total_mem_cached = 0;
- struct meminfo mi;
-
- assert(total_mem != NULL);
-
- if (total_mem_cached)
- goto finish;
-
- if (proc_get_meminfo(&mi, MEMINFO_MASK_MEM_TOTAL) < 0)
- return false;
-
- total_mem_cached = KBYTE_TO_MBYTE(mi.value[MEMINFO_ID_MEM_TOTAL]);
-
-finish:
- *total_mem = total_mem_cached;
-
- return true;
-}
-
-
-API bool proc_stat_get_free_mem_size(unsigned int *free_mem)
-{
- *free_mem = proc_get_mem_available();
- return !!(*free_mem);
-}
-
-static bool get_proc_cmdline(pid_t pid, char *cmdline)
-{
- assert(cmdline != NULL);
-
- char buf[PATH_MAX];
- char cmdline_path[sizeof(PROC_CMDLINE_PATH) + MAX_DEC_SIZE(int)] = {0};
- char *filename;
- FILE *fp;
- char format[10];
-
- snprintf(cmdline_path, sizeof(cmdline_path), PROC_CMDLINE_PATH, pid);
- fp = fopen(cmdline_path, "r");
- if (fp == NULL)
- return false;
-
- snprintf(format, 10, "%%%ds", PATH_MAX);
- if (fscanf(fp, format, buf) < 1) {
- fclose(fp);
- return false;
- }
- buf[sizeof(buf)-1] = 0;
-
- fclose(fp);
-
-
- filename = strrchr(buf, '/');
- if (filename == NULL)
- filename = buf;
- else
- filename = filename + 1;
-
- strncpy(cmdline, filename, NAME_MAX-1);
- cmdline[NAME_MAX-1] = 0;
-
- return true;
-}
-
-static bool get_proc_filename(pid_t pid, char *process_name)
-{
- FILE *fp;
- char buf[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
- char filename[PATH_MAX];
-
- assert(process_name != NULL);
-
- snprintf(buf, sizeof(buf), PROC_STAT_PATH, pid);
- fp = fopen(buf, "r");
-
- if (fp == NULL)
- return false;
-
- if (fscanf(fp, "%*s (%[^)]", filename) < 1) {
- fclose(fp);
- return false;
- }
-
- strncpy(process_name, filename, NAME_MAX-1);
- process_name[NAME_MAX-1] = 0;
- fclose(fp);
-
- return true;
-}
-
-API bool proc_stat_get_name_by_pid(pid_t pid, char *name)
-{
-
- assert(name != NULL);
-
- if (get_proc_cmdline(pid, name))
- return true;
- else if (get_proc_filename(pid, name))
- return true;
-
- return false;
-}
-
-
-static void diff_system_time(proc_stat_system_time *st_diff, proc_stat_system_time *st_a, proc_stat_system_time *st_b)
-{
- assert(st_diff != NULL);
- assert(st_a != NULL);
- assert(st_b != NULL);
-
- st_diff->total_time = st_a->total_time - st_b->total_time;
- st_diff->user_time = st_a->user_time - st_b->user_time;
- st_diff->nice_time = st_a->nice_time - st_b->nice_time;
- st_diff->system_time = st_a->system_time - st_b->system_time;
- st_diff->idle_time = st_a->idle_time - st_b->idle_time;
- st_diff->iowait_time = st_a->iowait_time - st_b->iowait_time;
- st_diff->irq_time = st_a->irq_time - st_b->irq_time;
- st_diff->softirq_time = st_a->softirq_time - st_b->softirq_time;
-}
-
-static bool get_system_time(proc_stat_system_time *st)
-{
- FILE *fp;
-
- assert(st != NULL);
-
- fp = fopen("/proc/stat", "r");
- if (fp == NULL)
- return false;
-
- if (fscanf(fp, "%*s %lld %lld %lld %lld %lld %lld %lld",
- &st->user_time, &st->nice_time, &st->system_time, &st->idle_time,
- &st->iowait_time, &st->irq_time, &st->softirq_time) < 1) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
-
- st->total_time = st->user_time + st->nice_time + st->system_time + st->idle_time
- + st->iowait_time + st->irq_time + st->softirq_time;
-
- return true;
-}
-
-
-
-API bool proc_stat_get_system_time_diff(proc_stat_system_time *st_diff)
-{
- static proc_stat_system_time prev_st;
- proc_stat_system_time cur_st;
-
- assert(st_diff != NULL);
-
- get_system_time(&cur_st);
-
- if (prev_st.total_time == 0) {
- memset(st_diff, 0, sizeof(proc_stat_system_time));
- prev_st = cur_st;
- return false;
- }
-
- diff_system_time(st_diff, &cur_st, &prev_st);
- prev_st = cur_st;
-
- return (bool) (st_diff->total_time);
-}
-
-
-static int comapre_pid(const pid_t *pid_a, const pid_t *pid_b)
-{
- assert(pid_a != NULL);
- assert(pid_b != NULL);
-
- /* the process which has smaller number of pid is ordered ahead */
- return *pid_a - *pid_b;
-}
-
-/**
- * @brief Get pids under /proc file system
- *
- * @param pids the pointer of GArray to store pids
- * @return true on success, false on failure.
- *
- * This function fills Garray instance with pids under /proc file system.
- */
-
-static bool get_pids(GArray *pids)
-{
- DIR *dirp;
- struct dirent entry;
- struct dirent *result;
- int ret;
-
- assert(pids != NULL);
-
- dirp = opendir("/proc");
-
- if (dirp == NULL)
- return false;
-
- while (!(ret = readdir_r(dirp, &entry, &result)) && result != NULL) {
- const char *p = entry.d_name;
- char *end;
- pid_t pid;
-
- while (*p) {
- if (*p < '0' || *p > '9')
- break;
- p++;
- }
-
- if (*p != 0)
- continue;
-
- pid = strtol(entry.d_name, &end, 10);
-
- g_array_append_val(pids, pid);
- }
- closedir(dirp);
-
- if (ret)
- return false;
-
- g_array_sort(pids, (GCompareFunc)comapre_pid);
-
- return true;
-}
-
-API bool proc_stat_get_pids(pid_t **pids, int *cnt)
-{
- unsigned int i;
- GArray *garray = NULL;
-
- assert(pids != NULL);
- assert(cnt != NULL);
-
- garray = g_array_new(false, false, sizeof(pid_t));
- g_return_val_if_fail(garray, false);
-
- if (get_pids(garray) == false) {
- /* g_array_free is resistant to input NULL */
- g_array_free(garray, true);
- return false;
- }
-
- *pids = malloc(sizeof(pid_t) * garray->len);
- assert(*pids != NULL);
-
- *cnt = garray->len;
-
- for (i = 0; i < garray->len; ++i)
- (*pids)[i] = g_array_index(garray, pid_t, i);
-
- g_array_free(garray, true);
-
- return true;
-}
-
-
-/**
- * @brief Fill proc_infos with proc_stat_process_info instances which have process statistics , specially time difference each process spent in user mode and system mode between two consecutive its calls
- *
- * @param pids GArray instance which have current pids under /proc file system
- * @param proc_infos the pointer of GArray instance to be filled with proc_stat_process_info instances which are matched with each pid in pids.
- * @param terminated_proc_infos the pointer of GArray instance to be filled with proc_stat_process_info instances which were terminated between two consecutive its calls
- ,pass NULL if if this information is not necessary
- * @return nothing
- *
- * This function fills proc_infos with proc_stat_process_info instances which have process statistics , specially time difference each process spent in user mode and system mode between two consecutive its calls
- *
- */
-
-static void update_proc_infos(GArray *pids, GArray *proc_infos,
- GArray *terminated_proc_infos)
-{
- /* when this function is called first, we don't have basis
- * for time interval, so it is not valid.
- */
- static bool first = true;
-
- unsigned int pids_cnt = 0;
- unsigned int cur_pi_idx = 0;
- proc_stat_process_info *pi = NULL;
-
- unsigned int i;
-
- assert(pids != NULL);
- assert(proc_infos != NULL);
-
- pids_cnt = pids->len;
-
- /* with current pids, update proc_infos */
- for (i = 0; i < pids_cnt; ++i) {
- unsigned long utime, stime;
-
- if (cur_pi_idx < proc_infos->len)
- pi = &g_array_index(proc_infos, proc_stat_process_info, cur_pi_idx);
- else
- /* current pid is out of proc_infos, so it is new pid. */
- pi = NULL;
-
- assert(i < pids->len);
- pid_t pid = g_array_index(pids, pid_t, i);
-
- if ((pi != NULL) && (pi->pid == pid)) {
- /* current pid is matched with proc_infos[curPsIdex],
- * so update proc_infos[curPsIdex]
- */
- ++cur_pi_idx;
-
- pi->fresh = false; /* it is not new process */
- /* by now, we don't know whether it is valid or not,
- * so mark it as invalid by default.
- */
- pi->valid = false;
-
- if (!(proc_stat_get_cpu_time_by_pid(pid, &utime, &stime) && proc_stat_get_mem_usage_by_pid(pid, &(pi->rss))))
- continue;
-
- if ((pi->utime_prev == utime) && (pi->stime_prev == stime)) {
- /* There is no diff in execution time, mark it as inactive. */
- pi->utime_diff = 0;
- pi->stime_diff = 0;
- pi->active = false;
- continue;
- } else {
- pi->active = true; /* mark it as active */
- }
- /* update time related fields */
- pi->utime_diff = (utime - pi->utime_prev);
- pi->stime_diff = (stime - pi->stime_prev);
- pi->utime_prev = utime;
- pi->stime_prev = stime;
-
- pi->valid = true; /* mark it as valid */
- } else if ((pi == NULL) || (pi->pid > pid)) {
- /* in case of new process */
- proc_stat_process_info new_pi;
-
- new_pi.pid = pid;
-
- if (!(proc_stat_get_name_by_pid(pid, new_pi.name) && proc_stat_get_cpu_time_by_pid(pid, &utime, &stime) && proc_stat_get_mem_usage_by_pid(pid, &new_pi.rss)))
- continue; /* in case of not getting information of current pid, skip it */
-
- new_pi.fresh = true; /* mark it as new (process) */
- new_pi.utime_prev = utime;
- new_pi.stime_prev = stime;
- new_pi.utime_diff = utime;
- new_pi.stime_diff = stime;
-
- if (first == false)
- /* This process is created after the first call of update_proc_infos, so we know execution time of it.
- * Mark it as valid.
- */
- new_pi.valid = true;
- else
- new_pi.valid = false;
-
- /* add it to proc_infos */
- g_array_insert_val(proc_infos, cur_pi_idx , new_pi);
- ++cur_pi_idx;
- } else {
- if (terminated_proc_infos != NULL) {
- proc_stat_process_info terminated_pi;
- terminated_pi = *pi;
- g_array_append_val(terminated_proc_infos, terminated_pi);
- }
-
- /* in case of the process terminated, remove it from proc_infos */
- assert(cur_pi_idx < proc_infos->len);
- g_array_remove_index(proc_infos, cur_pi_idx);
- /* current pid should be compared again, so decrease loop count */
- --i;
- }
-
- }
-
- /* in case of the process terminated, remove it from proc_infos */
- while (cur_pi_idx < proc_infos->len) {
- if (terminated_proc_infos != NULL) {
- proc_stat_process_info terminated_pi;
-
- assert(cur_pi_idx < proc_infos->len);
- terminated_pi = g_array_index(proc_infos, proc_stat_process_info, cur_pi_idx);
- g_array_append_val(terminated_proc_infos, terminated_pi);
- }
-
- assert(cur_pi_idx < proc_infos->len);
- g_array_remove_index(proc_infos, cur_pi_idx);
- }
-
- first = false;
-}
-
-
-
-static int compare_proc_info(const proc_stat_process_info *proc_info_a, const proc_stat_process_info *proc_info_b)
-{
- /*
- * Firstly, long execution time process is ordered ahead
- * Secondly, newly created process is ordered ahead
- */
- unsigned long exec_time_a, exec_time_b;
-
- assert(proc_info_a != NULL);
- assert(proc_info_b != NULL);
-
- exec_time_a = proc_info_a->utime_diff + proc_info_a->stime_diff;
- exec_time_b = proc_info_b->utime_diff + proc_info_b->stime_diff;
-
- if (exec_time_a != exec_time_b)
- return exec_time_b - exec_time_a;
-
- if (proc_info_a->fresh != proc_info_b->fresh)
- return (int)(proc_info_b->fresh) - (int)(proc_info_a->fresh);
-
- return 0;
-
-}
-
-
-/**
- * @brief Extract valid proc_stat_process_info instances from proc_infos and fill valid_proc_infos with these instances
- *
- * @param proc_infos from which source to extract valid proc_stat_process_info instances
- * @param valid_proc_infos GArray instance to be filled with valid proc_stat_process_info instances
- * @param total_valid_proc_time to get the sum of the time spent by all valid proc_stat_process_info instance, pass NULL if if this information is not necessary
- * @return nothing
- *
- * This function extracts valid proc_stat_process_info instances from proc_infos and fills valid_proc_infos with these instances
- */
-static void pick_valid_proc_infos(GArray *proc_infos, GArray *valid_proc_infos, unsigned long *total_valid_proc_time)
-{
- unsigned int i;
- proc_stat_process_info pi;
-
- assert(valid_proc_infos != NULL);
-
- if (total_valid_proc_time != NULL)
- *total_valid_proc_time = 0;
-
- for (i = 0; i < proc_infos->len; ++i) {
- assert(i < proc_infos->len);
- pi = g_array_index(proc_infos, proc_stat_process_info, i);
-
- if (pi.valid) {
- g_array_append_val(valid_proc_infos, pi);
-
- if (total_valid_proc_time != NULL)
- *total_valid_proc_time += (pi.utime_diff+pi.stime_diff);
- }
- }
-
- g_array_sort(valid_proc_infos, (GCompareFunc)compare_proc_info);
-}
-
-static GArray *g_pids;
-static GArray *proc_infos;
-
-API void proc_stat_init(void)
-{
- g_pids = g_array_new(false, false, sizeof(pid_t));
- proc_infos = g_array_new(false, false, sizeof(proc_stat_process_info));
-}
-
-API bool proc_stat_get_process_info(GArray *valid_proc_infos,
- GArray *terminated_proc_infos,
- unsigned long *total_valid_proc_time)
-{
- assert(valid_proc_infos != NULL);
-
- g_array_set_size(g_pids, 0);
-
- if (!get_pids(g_pids))
- return false;
-
- update_proc_infos(g_pids, proc_infos, terminated_proc_infos);
- pick_valid_proc_infos(proc_infos, valid_proc_infos, total_valid_proc_time);
-
- return true;
-
-}
-
-API void proc_stat_finalize(void)
-{
- if (g_pids) {
- g_array_free(g_pids, true);
- g_pids = NULL;
- }
-
- if (proc_infos) {
- g_array_free(proc_infos, true);
- proc_infos = NULL;
- }
-}
-
-
-API unsigned int proc_stat_get_gpu_clock(void)
-{
- FILE *fp;
- unsigned int clock;
-
- fp = fopen("/sys/module/mali/parameters/mali_gpu_clk", "r");
- if (fp == NULL)
- return -1;
-
- if (fscanf(fp, "%d", &clock) < 1) {
- fclose(fp);
- return -1;
- }
-
- fclose(fp);
-
- return clock;
-}
-
-bool proc_stat_is_gpu_on(void)
-{
- if (proc_stat_get_gpu_clock() <= 0)
- return false;
-
- return true;
-}
-
-
-
-static inline int send_int(int fd, int val)
-{
- return write(fd, &val, sizeof(int));
-}
-
-static inline int send_str(int fd, char *str)
-{
- int len;
- int ret;
- if (str == NULL) {
- len = 0;
- ret = write(fd, &len, sizeof(int));
- } else {
- len = strlen(str);
- if (len > NOTI_MAXARGLEN)
- len = NOTI_MAXARGLEN;
- ret = write(fd, &len, sizeof(int));
- if (ret < 0) {
- _E("%s: write failed\n", __func__);
- return ret;
- }
- ret = write(fd, str, len);
- }
- return ret;
-}
-
-static int send_socket(struct resourced_noti *msg, bool sync)
-{
- int client_len;
- int client_sockfd;
- int result = 0;
- struct sockaddr_un clientaddr;
- int i;
- int ret = 0;
- struct timeval tv = { 1, 0 }; /* 1sec */
-
- client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (client_sockfd == -1) {
- _E("%s: socket create failed\n", __func__);
- return -1;
- }
-
- bzero(&clientaddr, sizeof(clientaddr));
- clientaddr.sun_family = AF_UNIX;
- strncpy(clientaddr.sun_path, RESOURCED_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
- clientaddr.sun_path[sizeof(clientaddr.sun_path)-1] = 0;
- client_len = sizeof(clientaddr);
-
- if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) <
- 0) {
- _E("%s: connect failed\n", __func__);
- goto error;
- }
-
- ret = setsockopt(client_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- if (ret)
- _E("failed to set socket option");
- ret = send_int(client_sockfd, msg->pid);
- if (ret < 0) {
- _E("send failed (%d)\n", ret);
- goto error;
- }
- ret = send_int(client_sockfd, msg->type);
- if (ret < 0) {
- _E("send failed (%d)\n", ret);
- goto error;
- }
- ret = send_int(client_sockfd, msg->argc);
- if (ret < 0) {
- _E("send failed (%d)\n", ret);
- goto error;
- }
- for (i = 0; i < msg->argc; i++) {
- ret = send_str(client_sockfd, msg->argv[i]);
- if (ret < 0) {
- _E("send failed (%d)\n", ret);
- goto error;
- }
- }
-
- if (sync) {
- ret = read(client_sockfd, &result, sizeof(int));
- if (ret < 0) {
- _E("%s: read failed\n", __func__);
- goto error;
- }
- }
-
- close(client_sockfd);
- return result;
-error:
- close(client_sockfd);
- return ret;
-}
-
-static int send_socket_with_repy(struct resourced_noti *msg,
- char *buf, char *len_buf)
-{
- int client_len;
- int client_sockfd;
- int result = 0;
- struct sockaddr_un clientaddr;
- int i, ret;
- int size = atoi(len_buf);
- char errbuf[256];
- struct timeval tv = { 1, 0 }; /* 1sec */
-
- client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (client_sockfd == -1) {
- _E("socket create failed, errno: %d, %s\n", errno, strerror_r(errno, errbuf, sizeof(errbuf)));
- return -errno;
- }
-
- bzero(&clientaddr, sizeof(clientaddr));
- clientaddr.sun_family = AF_UNIX;
- strncpy(clientaddr.sun_path, RESOURCED_PROC_INFO_SOCKET_PATH,
- sizeof(clientaddr.sun_path) - 1);
- client_len = sizeof(clientaddr);
-
- ret = connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len);
- if (ret < 0) {
- _E("%s: connect failed\n", __func__);
- close(client_sockfd);
- return RESOURCED_ERROR_FAIL;
- }
- ret = setsockopt(client_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- if (ret)
- _E("failed to set socket option");
- send_int(client_sockfd, msg->pid);
- send_int(client_sockfd, msg->type);
- send_int(client_sockfd, msg->argc);
- for (i = 0; i < msg->argc; i++)
- send_str(client_sockfd, msg->argv[i]);
-
- ret = recv(client_sockfd, &result, sizeof(int), 0);
- if (ret < 0 || result < 0) {
- _E("%s: read failed\n", __func__);
- close(client_sockfd);
- return RESOURCED_ERROR_FAIL;
- }
- ret = recv(client_sockfd, buf, size, 0);
- if (ret < 0) {
- _E("%s: read failed\n", __func__);
- close(client_sockfd);
- return RESOURCED_ERROR_FAIL;
- }
-
- close(client_sockfd);
- return result;
-}
-
-static resourced_ret_c proc_cgroup_send_status(const int type, int num, ...)
-{
- struct resourced_noti *msg;
- resourced_ret_c ret = RESOURCED_ERROR_NONE;
- va_list argptr;
-
- int i;
- char *args = NULL;
- bool sync = SYNC_OPERATION(type);
-
- msg = malloc(sizeof(struct resourced_noti));
-
- if (msg == NULL)
- return RESOURCED_ERROR_OUT_OF_MEMORY;
-
- msg->pid = getpid();
- msg->type = type;
- msg->argc = num;
- va_start(argptr, num);
- /* it's just for debug purpose to test error reporting */
- for (i = 0; i < num; i++) {
- args = va_arg(argptr, char *);
- msg->argv[i] = args;
- }
- va_end(argptr);
-
- ret = send_socket(msg, sync);
- if (ret < 0)
- ret = RESOURCED_ERROR_FAIL;
-
- free(msg);
-
- return ret;
-}
-
-static resourced_ret_c proc_send_get_status(const int type, char* pid_buf,
- char *buf, char *len_buf)
-{
- struct resourced_noti *msg;
- resourced_ret_c ret = RESOURCED_ERROR_NONE;
-
- msg = malloc(sizeof(struct resourced_noti));
-
- if (msg == NULL)
- return RESOURCED_ERROR_OUT_OF_MEMORY;
-
- msg->pid = getpid();
- msg->type = type;
- msg->argc = 2;
- msg->argv[0] = pid_buf;
- msg->argv[1] = len_buf;
-
- ret = send_socket_with_repy(msg, buf, len_buf);
- if (ret < 0)
- ret = RESOURCED_ERROR_FAIL;
-
- free(msg);
- return ret;
-}
-
-
-API resourced_ret_c proc_cgroup_foregrd(void)
-{
- char buf[MAX_DEC_SIZE(int)];
- snprintf(buf, sizeof(buf), "%d", getpid());
- return proc_cgroup_send_status(PROC_CGROUP_SET_FOREGRD, 1, buf);
-}
-
-API resourced_ret_c proc_cgroup_backgrd(void)
-{
- char buf[MAX_DEC_SIZE(int)];
- snprintf(buf, sizeof(buf), "%d", getpid());
- return proc_cgroup_send_status(PROC_CGROUP_SET_BACKGRD, 1, buf);
-}
-
-API resourced_ret_c proc_cgroup_active(pid_t pid)
-{
- char buf[MAX_DEC_SIZE(int)];
- snprintf(buf, sizeof(buf), "%d", pid);
- return proc_cgroup_send_status(PROC_CGROUP_SET_ACTIVE, 1, buf);
-}
-
-API resourced_ret_c proc_cgroup_inactive(pid_t pid)
-{
- char buf[MAX_DEC_SIZE(int)];
- snprintf(buf, sizeof(buf), "%d", pid);
- return proc_cgroup_send_status(PROC_CGROUP_SET_INACTIVE, 1, buf);
-}
-
-API resourced_ret_c proc_group_change_status(int type, pid_t pid, char *app_id)
-{
- char pid_buf[MAX_DEC_SIZE(int)];
- char appid_buf[NOTI_MAXARGLEN];
- snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
- snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
- return proc_cgroup_send_status(type, 2, pid_buf, appid_buf);
-}
-
-API resourced_ret_c proc_cgroup_sweep_memory(void)
-{
- char buf[MAX_DEC_SIZE(int)];
- snprintf(buf, sizeof(buf), "%d", getpid());
- return proc_cgroup_send_status(PROC_CGROUP_GET_MEMSWEEP, 1, buf);
-}
-
-API resourced_ret_c proc_cgroup_launch(int type, pid_t pid, char *app_id, char *pkg_id)
-{
- char pid_buf[MAX_DEC_SIZE(int)];
- char appid_buf[NOTI_MAXARGLEN];
- char pkgid_buf[NOTI_MAXARGLEN];
- snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
- snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
- snprintf(pkgid_buf, sizeof(pkgid_buf)-1, "%s", pkg_id);
- return proc_cgroup_send_status(type, 3, pid_buf, appid_buf, pkgid_buf);
-}
-
-API resourced_ret_c proc_stat_get_pid_entry(int type, pid_t pid,
- char *buf, int len)
-{
- char pid_buf[MAX_DEC_SIZE(int)];
- char len_buf[MAX_DEC_SIZE(int)];
- snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
- snprintf(len_buf, sizeof(len_buf), "%d", len);
- return proc_send_get_status(type, pid_buf, buf, len_buf);
-}
-