/*
* Copyright (C) 2015-present, Ant Financial Services Group
*
* 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.
*/
//
// Created by Cathor on 17/8/29.
//
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
#include
#include
#include
#include
#define TAG "CPU_JNI" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGI类型
typedef struct PidData{
struct PidData* next;
int pid;
long long previousAppUsage;
} PidData;
static PidData root = {
.next = NULL,
.pid = -1,
.previousAppUsage = 0
};
static long long previousTotalUsage = 0;
static long long previousIdle = 0;
/*
* 获取总CPU占用率
* Class: com_alipay_hulu_shared_display_items_CPUTools
* Method: getTotalUsage
* Signature: ()F
*/
jfloat Java_com_alipay_hulu_shared_display_items_CPUTools_getTotalUsage(JNIEnv* env, jclass clz) {
FILE * pFile;
char* filename = "/proc/stat";
pFile = fopen(filename, "r");
if (pFile == NULL) {
return 0;
}
char* line = (char*) malloc(1024);
char* tmp;
fgets(line, 1024, pFile);
char* pch = strtok_r(line," \n", &tmp);
int count = 0;
long long currentTotalUsage = 0;
long long currentIdle = 0;
while (pch != NULL) {
if (count > 7) {
break;
}
if (count == 4) {
currentIdle = atoll(pch);
}
if (count > 0) {
currentTotalUsage += atoll(pch);
}
pch = strtok_r(NULL, " \n", &tmp);
count++;
}
free(line);
fclose(pFile);
if (previousTotalUsage == 0L) {
previousTotalUsage = currentTotalUsage;
previousIdle = currentIdle;
return 0;
}
// 计算时间段内cpu运行时间与idle时间
long cpuTotalTime = currentTotalUsage - previousTotalUsage;
long cpuIdleTime = currentIdle - previousIdle;
// 转化为double计算结果
double result = 100 * (cpuTotalTime - cpuIdleTime) / (double) cpuTotalTime;
// 同步到上一次结果
previousTotalUsage = currentTotalUsage;
previousIdle = currentIdle;
return (float)result;
}
static int count = 0;
/*
* 获取应用CPU占用率与CPU总占用率
* Class: com_alipay_hulu_shared_display_items_CPUTools
* Method: getAppTotalUsage
* Signature: (I)[F
*/
jfloatArray
Java_com_alipay_hulu_shared_display_items_CPUTools_getAppTotalUsage(JNIEnv *env, jclass clz, jintArray pids) {
jboolean b;
jint *realPids = (*env)->GetIntArrayElements(env, pids, &b);
int length = (*env)->GetArrayLength(env, pids);
FILE *cpuFile;
FILE **appFiles = (FILE**) malloc(sizeof(FILE*) * length);
float *data = (float *) malloc(sizeof(float) * (1 + length));
// 尽量保证同时打开文件,同时获取文件数据
cpuFile = fopen("/proc/stat", "r");
if (cpuFile == NULL) {
free(appFiles);
LOGI("Open CPU file failed");
jfloatArray result = (*env)->NewFloatArray(env, 0);
free(data);
(*env)->ReleaseIntArrayElements(env, pids, realPids, 0);
return result;
}
// 逐项格式化文件名
for (int i = 0; i < length; ++i) {
char filename[20];
sprintf(filename, "/proc/%d/stat", realPids[i]);
appFiles[i] = fopen(filename, "r");
}
// // 存在文件不能打开的情况,Android 7.0以上无法直接打开/proc/pid/stat
// if (appFile == NULL) {
// fclose(cpuFile);
// jfloat cpuUsage = Java_com_alipay_hulu_display_CPUTools_getTotalUsage(env, clz);
// LOGI("Open app file failed");
// jfloatArray result = (*env)->NewFloatArray(env, cpuUsage);
// free(data);
// return result;
// }
// 获取第一行数据
char *cpuLine = (char *) malloc(256);
fgets(cpuLine, 256, cpuFile);
char **appLines = (char **) malloc(sizeof(char *) * length);
for (int i = 0; i < length; ++i) {
if (appFiles[i] != NULL) {
char *appLine = (char *) malloc(256);
fgets(appLine, 256, appFiles[i]);
appLines[i] = appLine;
} else {
appLines[i] = NULL;
}
}
// 文件读取完毕,关闭文件
fclose(cpuFile);
for (int i = 0; i < length; ++i) {
if (appFiles[i] != NULL) {
fclose(appFiles[i]);
}
}
free(appFiles);
// 解析CPU数据
char* tmp;
char *pch = strtok_r(cpuLine, " \n", &tmp);
int count = 0;
long long currentTotalUsage = 0;
long long currentIdle = 0;
// 第2-8位为CPU各项运行时间,第5位为CPU空闲时间
while (pch != NULL) {
if (!pch || *pch == '\0') {
continue;
}
if (count > 7) {
break;
}
if (count == 4) {
currentIdle = atoll(pch);
}
if (count > 0) {
currentTotalUsage += atoll(pch);
}
pch = strtok_r(NULL, " \n", &tmp);
count++;
}
// 清理CPU行内存
free(cpuLine);
if (previousTotalUsage == 0L) {
previousTotalUsage = currentTotalUsage;
previousIdle = currentIdle;
jfloatArray result = (*env)->NewFloatArray(env, 0);
free(data);
(*env)->ReleaseIntArrayElements(env, pids, realPids, 0);
return result;
}
// 计算时间段内cpu运行时间与idle时间
long cpuTotalTime = currentTotalUsage - previousTotalUsage;
long cpuIdleTime = currentIdle - previousIdle;
double cpuUsage = 100 * (cpuTotalTime - cpuIdleTime) / (double) cpuTotalTime;
// 替换前一次数据
previousTotalUsage = currentTotalUsage;
previousIdle = currentIdle;
// 存入结果
data[length] = (float) cpuUsage;
for (int i = 0; i < length; ++i) {
// 对于空数据,直接跳过
if (appLines[i] == NULL) {
data[i] = 0;
continue;
}
char* save_tmp;
pch = strtok_r(appLines[i], " \n", &save_tmp);
count = 0;
long long currentAppUsage = 0;
// 计算应用占用总时间,从13到16位分别为用户态运行,核心态运行时间,已死线程用户态运行时间,已死线程核心态运行时间
while (pch != NULL) {
// 空字符,忽略
if (!pch || *pch == '\0') {
continue;
}
if (count > 16) {
break;
}
if (count > 12) {
currentAppUsage += atoll(pch);
}
pch = strtok_r(NULL, " \n", &save_tmp);
count++;
}
// 清理应用行内存
free(appLines[i]);
PidData *currentPidData = &root;
while (currentPidData->pid != realPids[i] && currentPidData->next != NULL) {
currentPidData = currentPidData->next;
}
LOGD("Pid: %d with data: %lld", realPids[i], currentAppUsage);
// 当pid不为目标pid,说明未找到,在末尾添加新的PidData
if (currentPidData->pid != realPids[i]) {
PidData *newItem = (PidData *) malloc(sizeof(PidData));
newItem->next = NULL;
newItem->previousAppUsage = 0;
newItem->pid = realPids[i];
currentPidData->next = newItem;
currentPidData = newItem;
}
// 未初始化,清理
if (currentPidData->previousAppUsage == 0) {
currentPidData->previousAppUsage = currentAppUsage;
data[i] = 0;
continue;
}
long appTime = currentAppUsage - currentPidData->previousAppUsage;
double appUsage = 100 * appTime / (double) cpuTotalTime;
data[i] = (float) appUsage;
// 替换前一次数据
currentPidData->previousAppUsage = currentAppUsage;
}
// 拷贝结果数据
jfloatArray result = (*env)->NewFloatArray(env, length + 1);
(*env)->SetFloatArrayRegion(env, result, 0, length + 1, data);
free(data);
(*env)->ReleaseIntArrayElements(env, pids, realPids, 0);
return result;
}