/* Copyright (2017) Baidu Inc. All rights reserved. * * File: duerapp_system_info.c * Auth: Zhong Shuai(zhongshuai@baidu.com) * Desc: Provide the information about the system */ #include "lightduer_statistics.h" #include #include #include #include #include #include #include "lightduer_system_info.h" #include "lightduer_mutex.h" #include "lightduer_types.h" #include "lightduer_timers.h" #include "lightduer_log.h" #include "lightduer_memory.h" #include "lightduer_lib.h" #ifdef ANDROID // ensure android app has permission to read and write sdcard #define TEMP_FILE "/sdcard/temp_log" #else #define TEMP_FILE "/tmp/temp_log" #endif // ANDROID #define DELAY_TIEM (5 * 1000) extern int duer_system_info_init(void); volatile static uint32_t s_peak = 0; volatile static uint32_t s_trough = (~0x0); volatile static uint32_t s_sum = 0; volatile static uint32_t s_counts = 0; volatile static duer_mutex_t s_lock_sys_info = NULL; extern duer_system_static_info_t g_system_static_info; static void calculate_system_info(void *arg) { int fd = 0; int ret = DUER_OK; static int count = 1; const int BUF_LEN = 300; char buf[BUF_LEN + 1]; char used_memory_str[10]; uint64_t used_memory = 0; memset(used_memory_str, 0, sizeof(used_memory_str)); ret = system("free > "TEMP_FILE); if (ret < 0) { DUER_LOGE("Get Memory info failed ret: %d", ret); return; } fd = open(TEMP_FILE, O_RDONLY); if (fd < 0) { DUER_LOGE("Open "TEMP_FILE" failed, ret = %d", ret); return; } do { count = read(fd, buf, BUF_LEN); if (count < 0) { DUER_LOGE("Read "TEMP_FILE" failed ret: %d", count); break; } buf[BUF_LEN] = '\0'; sscanf(buf, "%*[^:]:%*s %s %*s %*s %*s", used_memory_str); used_memory = atoll(used_memory_str); ret = duer_mutex_lock(s_lock_sys_info); if (ret != DUER_OK) { DUER_LOGE("Lock sys info failed"); break; } if (used_memory > s_peak) { s_peak = used_memory; } if (used_memory < s_trough) { s_trough = used_memory; } s_sum += used_memory; s_counts++; ret = duer_mutex_unlock(s_lock_sys_info); if (ret != DUER_OK) { DUER_LOGE("Unlock sys info failed"); } } while (0); close(fd); return; } static int duer_init_system_info_module(void) { int ret = 0; duer_timer_handler timer; if (s_lock_sys_info == NULL) { s_lock_sys_info = duer_mutex_create(); if (s_lock_sys_info == NULL) { DUER_LOGE("Create lock failed"); return DUER_ERR_FAILED; } } #ifndef ANDROID timer = duer_timer_acquire(calculate_system_info, NULL, DUER_TIMER_PERIODIC); ret = duer_timer_start(timer, DELAY_TIEM); if (ret != DUER_OK) { DUER_LOGE("Start timer failed"); ret = DUER_ERR_FAILED; } #endif return DUER_OK; } static int duer_get_system_static_info(duer_system_static_info_t *info) { if (info == NULL) { DUER_LOGE("Sys Info: Argument Error"); return DUER_ERR_INVALID_PARAMETER; } memcpy(info, &g_system_static_info, sizeof(*info)); return DUER_OK; } static int get_sys_time(uint64_t *time) { int i = 0; int fd = 0; int num = 0; int count = 0; int ret = DUER_OK; const int BUF_LEN = 15; char buf[BUF_LEN]; char sys_time[BUF_LEN]; memset(buf, 0, sizeof(buf)); do { fd = open("/proc/uptime", O_RDONLY); if (fd < 0) { DUER_LOGE("Open /proc/uptime failed"); ret = DUER_ERR_FAILED; break; } count = read(fd, sys_time, BUF_LEN - 1); if (count < 0) { DUER_LOGE("Read /proc/uptime failed ret: %d", count); ret = DUER_ERR_FAILED; break; } sys_time[BUF_LEN - 1] = '\0'; for (i = 0; i < BUF_LEN; i++) { if (sys_time[i] != '.') { buf[i] = sys_time[i]; } else { break; } } *time = atoll(buf); } while (0); if (fd > 0) { close(fd); } return ret; } static int duer_get_system_dynamic_info(duer_system_dynamic_info_t *info) { int j = 0; int i = 0; int k = 0; int fd = 0; int count = 0; int progress[2]; int ret = DUER_OK; const int BUF_LEN = 50; char buf[BUF_LEN]; char num[BUF_LEN]; memset(buf, 0, BUF_LEN); memset(num, 0, BUF_LEN); do { ret = get_sys_time(&info->system_up_time); if (ret < 0) { DUER_LOGE("Get system up time failed"); ret = DUER_ERR_FAILED; break; } fd = open("/proc/loadavg", O_RDONLY); if (fd < 0) { DUER_LOGE("Open /proc/loadavg failed"); ret = DUER_ERR_FAILED; break; } count = read(fd, buf, BUF_LEN); if (count <= 0) { DUER_LOGE("Read /proc/loadavg failed ret: %d", count); ret = DUER_ERR_FAILED; break; } info->system_load = (char *)DUER_MALLOC(count); if (info->system_load == NULL) { DUER_LOGE("Malloc failed"); break; } memcpy(info->system_load, buf, count - 1); info->system_load_len = count - 1; for (i = 0; i < BUF_LEN; i++) { if (buf[i] == ' ') { j++; if (j >= 3) { break; } } } j = 0; i++; while (i < BUF_LEN) { if (buf[i] != '/' && buf[i] != ' ') { num[k++] = buf[i++]; } else { progress[j++] = atoi(num); memset(num, 0, BUF_LEN); i++; k = 0; if (j >= 2) { break; } } } info->running_task = progress[0]; info->total_task = progress[1]; } while (0); if (fd > 0) { close(fd); } return ret; } static int duer_free_system_dynamic_info(duer_system_dynamic_info_t *info) { DUER_FREE(info->system_load); info->system_load = NULL; return DUER_OK; } static int duer_get_memory_info(duer_memory_info_t *mem_info) { int fd = 0; int count = 0; int ret = DUER_OK; const int BUF_LEN = 300; char buf[BUF_LEN + 1]; char *swap_info = NULL; char swap_size_str[10]; char total_memory_str[10]; char shared_memory_str[10]; char buffer_memory_str[10]; char free_swap_size_str[10]; char available_memory_str[10]; memset(total_memory_str, 0, sizeof(total_memory_str)); memset(available_memory_str, 0, sizeof(available_memory_str)); memset(shared_memory_str, 0, sizeof(shared_memory_str)); memset(buffer_memory_str, 0, sizeof(buffer_memory_str)); memset(swap_size_str, 0, sizeof(swap_size_str)); memset(free_swap_size_str, 0, sizeof(free_swap_size_str)); ret = system("free > "TEMP_FILE); if (ret < 0) { DUER_LOGE("Get Memory info failed ret: %d", ret); return DUER_ERR_FAILED; } fd = open(TEMP_FILE, O_RDONLY); if (fd < 0) { DUER_LOGE("Open "TEMP_FILE" failed"); return DUER_ERR_FAILED; } count = read(fd, buf, BUF_LEN); close(fd); if (count < 0) { DUER_LOGE("Read "TEMP_FILE" failed ret: %d", count); return DUER_ERR_FAILED; } buf[BUF_LEN] = '\0'; sscanf(buf, "%*[^:]:%s %*s %s %s %s", total_memory_str, available_memory_str, shared_memory_str, buffer_memory_str); mem_info->memory_type = RAM; mem_info->total_memory_size = atoll(total_memory_str); mem_info->available_memory_size = atoll(available_memory_str); mem_info->shared_memory_size = atoll(shared_memory_str); mem_info->buffer_memory_size = atoll(buffer_memory_str); calculate_system_info(NULL); ret = duer_mutex_lock(s_lock_sys_info); if (ret != DUER_OK) { DUER_LOGE("Lock sys info failed"); return ret; } mem_info->peak = s_peak; mem_info->trough = s_trough; if (s_counts > 0) { mem_info->average = 1.0f * s_sum / s_counts; } else { DUER_LOGE("No memory info was measured!!!"); } s_peak = 0; s_trough = ~0; s_sum = 0; s_counts = 0; ret = duer_mutex_unlock(s_lock_sys_info); if (ret != DUER_OK) { DUER_LOGE("Unlock sys info failed"); } swap_info = strstr(buf, "Swap"); if (swap_info == NULL) { DUER_LOGE("Can not find swap info"); return DUER_ERR_FAILED; } sscanf(swap_info, "%*[^:]:%s %*s %s", swap_size_str, free_swap_size_str); mem_info->swap_size = atoll(swap_size_str); mem_info->free_swap_size = atoll(free_swap_size_str); return DUER_OK; } static int duer_get_disk_info(duer_disk_info_t **disk_info) { int i = 0; int j = 0; int k = 0; int fd = 0; int num = 0; int count = 0; int skip_line = 0; int ret = DUER_OK; const int BUF_LEN = 2000; const int LINE_LEN = 201; char *buf = NULL; char line_str[LINE_LEN]; char used_size_str[10]; char total_size_str[10]; char unilization_str[10]; char available_size_str[10]; char mount_info_str[MOUNT_INFO_LEN + 1]; char partition_name[100]; duer_disk_info_t *item = NULL; duer_disk_info_t *next = NULL; duer_disk_info_t *head = NULL; duer_disk_info_t *previous = NULL; duer_disk_info_t *partition = NULL; memset(line_str, 0, sizeof(line_str)); memset(partition_name, 0, sizeof(partition_name)); memset(total_size_str, 0, sizeof(total_size_str)); memset(used_size_str, 0, sizeof(used_size_str)); memset(available_size_str, 0, sizeof(available_size_str)); memset(unilization_str, 0, sizeof(unilization_str)); memset(mount_info_str, 0, MOUNT_INFO_LEN + 1); ret = system("df > "TEMP_FILE); if (ret < 0) { DUER_LOGE("Get disk info failed ret: %d", ret); return DUER_ERR_FAILED; } buf = DUER_MALLOC(BUF_LEN + 1); if (buf == NULL) { DUER_LOGE("Malloc buf failed"); return DUER_ERR_FAILED; } memset(buf, 0, BUF_LEN + 1); ret = DUER_OK; do { fd = open(TEMP_FILE, O_RDONLY); if (fd < 0) { DUER_LOGE("Open "TEMP_FILE" failed ret: %d", ret); ret = DUER_ERR_FAILED; break; } count = read(fd, buf, BUF_LEN); close(fd); if (count < 0) { DUER_LOGE("Read "TEMP_FILE" failed ret: %d", ret); ret = DUER_ERR_FAILED; break; } for (i = 0, j = 0, k = 0; buf[i] != '\0'; i++) { if (buf[i] != '\n') { if (j < LINE_LEN) { line_str[j++] = buf[i]; } else { skip_line = 1; DUER_LOGW("line %d is too long", k); } } else { j = 0; if (k++ < 1 || skip_line) { skip_line = 0; continue; } partition = DUER_MALLOC(sizeof(*partition)); if (partition == NULL) { DUER_LOGE("Malloc disk fialed"); item = head; while (item) { next = item->next; DUER_FREE(item); item = next; } ret = DUER_ERR_FAILED; break; } memset(partition, 0, sizeof(*partition)); if (k == 2) { head = partition; previous = partition; } else { previous->next = partition; previous = partition; } sscanf(line_str, "%s %s %s %s %s%% %s", partition_name, total_size_str, used_size_str, available_size_str, unilization_str, mount_info_str); DUER_LOGI("partition_name = %s", partition_name); memcpy(partition->partition_name, partition_name, PARTITION_NAME_LEN); memcpy(partition->mount_info, mount_info_str, MOUNT_INFO_LEN); partition->unilization = atoi(unilization_str); partition->total_size = atoll(total_size_str); partition->used_size = atoll(used_size_str); partition->available_size = atoll(available_size_str); partition->next = NULL; memset(line_str, 0, sizeof(line_str)); memset(partition_name, 0, PARTITION_NAME_LEN + 1); memset(total_size_str, 0, sizeof(total_size_str)); memset(used_size_str, 0, sizeof(used_size_str)); memset(available_size_str, 0, sizeof(available_size_str)); memset(unilization_str, 0, sizeof(unilization_str)); memset(mount_info_str, 0, MOUNT_INFO_LEN + 1); } } *disk_info = head; } while (0); if (buf != NULL) { DUER_FREE(buf); buf = NULL; } return DUER_OK; } static int duer_free_disk_info(duer_disk_info_t *disk_info) { duer_disk_info_t *temp = NULL; while (disk_info != NULL) { temp = disk_info; disk_info = temp->next; DUER_FREE(temp); } return DUER_OK; } static int get_str_num(char const *str, char const *needle, uint64_t *num) { char num_str[20]; char *search_ret = NULL; memset(num_str, 0, sizeof(num_str)); search_ret = strstr(str, needle); if (search_ret == NULL) { return DUER_ERR_FAILED; } sscanf(search_ret + strlen(needle), "%s", num_str); *num = atoll(num_str); return DUER_OK; } static int get_network_info(duer_network_info_t *network_info) { int i = 0; int j = 0; int fd_net_info = 0; int fd_wireless_info = 0; int count = 0; int ret = DUER_OK; int skip = -1; int len = 0; char num_str[20]; char link_str[10]; char line_str[121]; char level_str[10]; char noise_str[10]; char w_netdev_buf[301]; const int BUF_LEN = 2000; char *buf = NULL; char *search_ret = NULL; memset(line_str, 0, sizeof(line_str)); memset(network_info, 0, sizeof(*network_info)); ret = system("ifconfig > "TEMP_FILE); if (ret < 0) { DUER_LOGE("Get network info failed ret: %d", ret); return DUER_ERR_FAILED; } buf = DUER_MALLOC(BUF_LEN + 1); if (buf == NULL) { DUER_LOGE("Malloc buf failed"); return DUER_ERR_FAILED; } memset(buf, 0, BUF_LEN + 1); do { fd_net_info = open(TEMP_FILE, O_RDONLY); if (fd_net_info < 0) { DUER_LOGE("Open "TEMP_FILE" failed ret: %d", ret); ret = DUER_ERR_FAILED; break; } count = read(fd_net_info, buf, BUF_LEN); if (count < 0) { DUER_LOGE("Read "TEMP_FILE" failed ret: %d", count); ret = DUER_ERR_FAILED; break; } for (i = 0, j = 0; buf[i] != '\0'; i++) { if (buf[i] != '\n') { line_str[j++] = buf[i]; } else { j = 0; search_ret = strstr(line_str, "Link encap"); if (search_ret != NULL) { if (skip == 0) { // if skip == 0, one networkinfo has been parsed break; } search_ret = strstr(line_str, "lo"); if (search_ret != NULL) { skip = 1; memset(line_str, 0, 121); continue; } else { skip = 0; } search_ret = strstr(line_str, "wlan"); if (search_ret != NULL) { network_info->network_type = WIFI_TYPE; fd_wireless_info = open("/proc/net/wireless", O_RDONLY); if (fd_wireless_info < 0) { DUER_LOGE("Open /proc/net/wireless failed"); ret = DUER_ERR_FAILED; break; } memset(w_netdev_buf, 0, sizeof(w_netdev_buf)); count = read(fd_wireless_info, w_netdev_buf, sizeof(w_netdev_buf) - 1); close(fd_wireless_info); if (count < 0) { DUER_LOGE("Read /proc/net/wireless failed"); ret = DUER_ERR_FAILED; break; } search_ret = strstr(w_netdev_buf, "wlan"); if (search_ret != NULL) { memset(link_str, 0, sizeof(link_str)); memset(level_str, 0, sizeof(level_str)); memset(noise_str, 0, sizeof(noise_str)); sscanf(search_ret, "%*[^:]:%*s %s %s %s", link_str, level_str, noise_str); len = strlen(link_str); if (len > 0 && link_str[len - 1] == '.') { link_str[len - 1] = 0; } len = strlen(level_str); if (len > 0 && level_str[len - 1] == '.') { level_str[len - 1] = 0; } len = strlen(noise_str); if (len > 0 && noise_str[len - 1] == '.') { noise_str[len - 1] = 0; } network_info->wireless.link = atoi(link_str); network_info->wireless.level = atoi(level_str); network_info->wireless.noise = atoi(noise_str); } } else { // TODO: maybe other type network_info->network_type = ETHERNET_TYPE; } search_ret = strstr(line_str, "HWaddr"); if (search_ret != NULL) { sscanf(search_ret, "%*s %[a-zA-Z0-9:]", network_info->hw_address); } } if (skip) { memset(line_str, 0, 121); continue; } search_ret = strstr(line_str, "inet addr"); if (search_ret != NULL) { search_ret = strstr(line_str, ":"); if (search_ret != NULL) { sscanf(search_ret + 1, "%s", network_info->ipv4_address); } } search_ret = strstr(line_str, "inet6 addr"); if (search_ret != NULL) { sscanf(search_ret + 12, "%s", network_info->ipv6_address); } search_ret = strstr(line_str, "MTU"); if (search_ret != NULL) { memset(num_str, 0, 20); sscanf(search_ret + 4, "%s", num_str); network_info->mtu = atoi(num_str); } search_ret = strstr(line_str, "RX packets:"); if (search_ret != NULL) { get_str_num(line_str, "RX packets:", &network_info->received_packets); // get_str_num(line_str, "errors:", &network_info->rx_error_packet); // get_str_num(line_str, "dropped:", &network_info->rx_dropped_packet); // get_str_num(line_str, "overruns:", &network_info->rx_overruns); // get_str_num(line_str, "frame:", &network_info->rx_frame); } search_ret = strstr(line_str, "TX packets:"); if (search_ret != NULL) { get_str_num(line_str, "TX packets:", &network_info->transmitted_packets); // get_str_num(line_str, "errors:", &network_info->tx_error_packet); // get_str_num(line_str, "dropped:", &network_info->tx_dropped_packet); // get_str_num(line_str, "overruns:", &network_info->tx_overruns); } memset(line_str, 0, sizeof(line_str)); } } } while (0); if (buf != NULL) { DUER_FREE(buf); buf = NULL; } if (fd_net_info > 0) { close(fd_net_info); } return ret; } static int duer_free_network_info(duer_network_info_t *network_info) { return DUER_OK; } static duer_system_info_ops_t s_system_info_ops = { .init = duer_init_system_info_module, .get_system_static_info = duer_get_system_static_info, .get_system_dynamic_info = duer_get_system_dynamic_info, .free_system_dynamic_info = duer_free_system_dynamic_info, .get_memory_info = duer_get_memory_info, .get_disk_info = duer_get_disk_info, .free_disk_info = duer_free_disk_info, .get_network_info = get_network_info, .free_network_info = duer_free_network_info, }; int duer_statistics_initialize(void) { int ret = DUER_OK; ret = duer_system_info_register_system_info_ops(&s_system_info_ops); if (ret != DUER_OK) { DUER_LOGE("Sys Info: Register system info ops failed ret: %d", ret); return ret; } ret = duer_init_system_info(); if (ret != DUER_OK) { DUER_LOGE("Sys Info: Init system info failed ret: %d", ret); } return ret; }