CpuMonitorService
- 背景:Android 14 新增了一个系统服务,名字叫CpuMonitorService,主要用于监控CPU相关的使用情况,我们近今天介绍下它的用途
启动
- CpuMonitorService在Systemserver初始化函数startCoreServices中启动,目前只有在debug相关版本上使能
if (Build.IS_DEBUGGABLE || Build.IS_ENG) {
t.traceBegin("CpuMonitorService");
mSystemServiceManager.startService(CpuMonitorService.class);
t.traceEnd();
}
运行时许图
- CpuMonitorService 运行起来之后,会轮训读取CPU信息,下面时许图中的13~17 步会周期性执行,执行周期为1分钟。
private static final long DEBUG_MONITORING_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(1);

监控内容
CpuMonitorService 关注的系统目录有下面这些:
private static final String CPUFREQ_DIR_PATH = "/sys/devices/system/cpu/cpufreq"
private static final String POLICY_DIR_PREFIX = "policy"
private static final String RELATED_CPUS_FILE = "related_cpus"
private static final String AFFECTED_CPUS_FILE = "affected_cpus"
private static final String CUR_SCALING_FREQ_FILE = "scaling_cur_freq"
private static final String MAX_SCALING_FREQ_FILE = "scaling_max_freq"
private static final String TIME_IN_STATE_FILE = "stats/time_in_state"
private static final String CPUSET_DIR_PATH = "/dev/cpuset"
private static final String CPUSET_TOP_APP_DIR = "top-app"
private static final String CPUSET_BACKGROUND_DIR = "background"
private static final String CPUS_FILE = "cpus"
private static final String PROC_STAT_FILE_PATH = "/proc/stat"
CpuMonitorService可以提供哪些信息
- 每个CPU是什么categories,这里categories指的是top-app还是background
writer.printf("Cpuset categories by CPU core:\n")
writer.increaseIndent()
for (int i = 0
writer.printf("CPU core id = %d, %s\n", mCpusetCategoriesByCpus.keyAt(i),
toCpusetCategoriesStr(mCpusetCategoriesByCpus.valueAt(i)));
}
- 每个CPU在什么policy下面,按照policy分类CPU
writer.println("Cpu frequency policy directories by policy id:")
writer.increaseIndent()
for (int i = 0
writer.printf("Policy id = %d, Dir = %s\n", mCpuFreqPolicyDirsById.keyAt(i),
mCpuFreqPolicyDirsById.valueAt(i));
}
- 每个policy下面的最大频率,下面代码中的static代表的就是最大频率(静态的意思)
writer.println("Static cpu frequency policy infos by policy id:")
writer.increaseIndent()
for (int i = 0
writer.printf("Policy id = %d, %s\n", mStaticPolicyInfoById.keyAt(i),
mStaticPolicyInfoById.valueAt(i));
}
writer.println("Cpu time in frequency state by policy id:");
writer.increaseIndent();
for (int i = 0; i < mTimeInStateByPolicyId.size(); i++) {
writer.printf("Policy id = %d, Time(millis) in state by CPU frequency(KHz) = %s\n",
mTimeInStateByPolicyId.keyAt(i), mTimeInStateByPolicyId.valueAt(i));
}
writer.println("Last read CPU infos:")
writer.increaseIndent()
for (int i = 0
writer.printf("%s\n", mLastReadCpuInfos.valueAt(i))
}
CpuInfo(relatedCpuCore, cpusetCategories, /* isOnline= */true,
dynamicPolicyInfo.curCpuFreqKHz, staticPolicyInfo.maxCpuFreqKHz,
dynamicPolicyInfo.avgTimeInStateCpuFreqKHz, usageStats)
// usageStats 指的是/proc/stat下面的CPU信息
writer.println("Latest cumulative CPU usage stats by CPU core:")
writer.increaseIndent()
for (int i = 0
writer.printf("CPU core id = %d, %s\n", mCumulativeCpuUsageStats.keyAt(i),
mCumulativeCpuUsageStats.valueAt(i));
}
上面这些信息都可以通过dump 服务获得
重点变量和函数介绍
- CpuMonitorService 中存在各种代表CPU信息的变量和读取CPU信息的各种函数,看代码时容易迷糊,我们列举一下为了方便查询,下面是变量名
| 参数 | 含义 |
|---|
| mCumulativeCpuUsageStats | 保存当前的cpu累计信息的cpuUsageStats结构体 |
| mCpuFreqPolicyDirsById | 保存policy后面的整数,比如下面保存 0 4 7 sys/devices/system/cpu/cpufreq/policy0 |
| mTimeInStateByPolicyId | mTimeInStateByPolicyId.put(policyId, latestTimeInState);保存的是id 和time_in_state 对应关系 |
| dynamicPolicyInfoById | DynamicPolicyInfo dynamicPolicyInfo = new DynamicPolicyInfo(curCpuFreqKHz,avgTimeInStateCpuFreqKHz, affectedCpuCores);dynamicPolicyInfoById.append(policyId, dynamicPolicyInfo);affectedCpuCores 代表“/sys/devices/system/cpu/cpufreq/policy0 # cat affected_cpus” |
| mStaticPolicyInfoById | 保存同一policy下面所有related CPU的最大频率 |
| mCpusetCategoriesByCpus | 键值对,CPU id和对应的类别,这里的类别指的是FLAG_CPUSET_CATEGORY_TOP_APPFLAG_CPUSET_CATEGORY_BACKGROUND |
| 函数 | 含义 |
|---|
| readCumulativeCpuUsageStats | 读取/proc/stat 并把结果保存到cpuUsageStats结构体 |
| readDynamicPolicyInfo | 读取cpu当前频率,affectcpus ,平均频率并保存 |
| populateCpuFreqPolicyDirsById | 读取"/sys/devices/system/cpu/cpufreq"目录下面policy后面的整数值,保存在mCpuFreqPolicyDirsById 中 |
| readAvgTimeInStateCpuFrequency | 计算来两次差值之前的平均频率,调用的是calculateAvgCpuFreq |
| readTimeInState | 读取/sys/devices/system/cpu/cpufreq/policy0/stats/time_in_state的内容,并返回 |
| calculateDeltaTimeInState | 算两次time in state的差值 |
| calculateAvgCpuFreq | for (int i = 0; i < timeInState.size(); i++) {avgFreqKHz += (timeInState.keyAt(i) * timeInState.valueAt(i)) / totalTimeInState;}计算平均频率 |
| readStaticPolicyInfo | 读取同一policy下面所有related CPU的最大频率,保存到mStaticPolicyInfoByIdStaticPolicyInfo staticPolicyInfo = new StaticPolicyInfo(maxCpuFreqKHz,relatedCpuCores); |
| readCpuInfos | 读取CPU 信息,返回cpuinfoCpuInfo cpuInfo = new CpuInfo(relatedCpuCore, cpusetCategories, /* isOnline= */true,dynamicPolicyInfo.curCpuFreqKHz, staticPolicyInfo.maxCpuFreqKHz,dynamicPolicyInfo.avgTimeInStateCpuFreqKHz, usageStats);cpuInfoByCpus.append(relatedCpuCore, cpuInfo); |