最近在研究如何避免游戏在中低端手机上发热降频,需要一些指标来参考,主要是手机各个传感器的实时温度,与CPU的运行状态(是否在线、频率),实时电流等,通过这些信息可以分析哪些场景下会比较容易发生降频,以及不同手机厂商的调校策略,在此记录一下。
电流获取
电流获取主要参考了雨松的这篇博客Unity3D研究院之实时获取手机电流、电压、计算功率发热,主要是通过Android的BatteryManager,可以获取到手机的电流,再根据电压来计算功率。
但实际测试的时候发现,在充电状态下是无法获取准确的电流信息的,而且通知、消息、WiFi、蓝牙等是否开启都会对这个数值产生比较大的影响,不过还是有一定的参考价值。
CPU信息获取
相比于电流,CPU信息能更好的反映游戏运行的开销,而CPU的信息通过Android的系统日志可以读取到,首先我们需要获取系统文件的可读权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
我们可以通过Runtime.getRuntime().avaliableProcessors()来得到CPU核心的总个数,然后找到对应核心的文件即可,scaling_cur_freq是CPU当前频率,cpuinfo_min_freq是系统设定的最小频率,cpuinfo_max_freq是系统设定的最大频率,如果发生降频,cpuinfo_max_freq可能会降低。
大致代码如下:
int cpuNum = Runtime.getRuntime().availableProcessors();//CPU总核心数
String resultStr = "Cpu:" + cpuNum + ",On:";
for(int i = 0; i < cpuNum; i++){
String currentFreqPath = "/sys/devices/system/cpu/cpu"+ i + "/cpufreq/scaling_cur_freq";//当前频率
String minPath = "/sys/devices/system/cpu/cpu" + i +"/cpufreq/cpuinfo_min_freq";//最小频率
String maxPath = "/sys/devices/system/cpu/cpu"+ i + "/cpufreq/cpuinfo_max_freq";//最大频率
RandomAccessFile rf = new RandomAccessFile(currentFreqPath, "r");
RandomAccessFile minFile = new RandomAccessFile(minPath, "r");
RandomAccessFile maxFile = new RandomAccessFile(maxPath, "r");
try {
Long result = Long.parseLong(rf.readLine()) / 1000;
Long minResult = Long.parseLong(minFile.readLine()) / 1000;
Long maxResult = Long.parseLong(maxFile.readLine()) / 1000;
Log.e("tst", "Core:" + i + " " + String.valueOf(result) + " min:" + minResult + " max:" + maxResult);
}
catch (Exception e){
}
}
try {
RandomAccessFile rf = new RandomAccessFile("/sys/devices/system/cpu/online", "r");
String online = rf.readLine();
resultStr += online;
}catch (Exception e){
}
注意,这里的核心频率即使不为0,也不一定表示它没有被关掉,比较准确的方法是通过 “/sys/devices/system/cpu/online”来获取当前核心在线状态:
try {
RandomAccessFile rf = new RandomAccessFile("/sys/devices/system/cpu/online", "r");
String online = rf.readLine();
resultStr += online;
}catch (Exception e){
}
比如CPU总共8个核,这里读取到的Online信息为0-2, 4-7 就表示第4个核心(编号为3)被关掉了。
温度信息
温度信息是最复杂的,因为不同系统,不同型号的手机它们的传感器信息都不一样,这里我的方法比较暴力,把所有可能的传感器日志路径都列出来,然后遍历,从中筛选出疑似温度的值(数值在10~100之间),再根据传感器的名字进行分类,比如”cpu_temp”这可能是一个cpu温度传感器,”xxx_skin”可能是手机外壳的温度传感器,几个比较常见的关键字是:cpu、temp、tz、skin、tsens。 传感器文件列表如下:
"/sys/devices/system/cpu/cpu0/cpufreq/cpu_temp",
"/sys/devices/system/cpu/cpu0/cpufreq/FakeShmoo_cpu_temp",
"/sys/class/i2c-adapter/i2c-4/4-004c/temperature",
"/sys/devices/platform/tegra-i2c.3/i2c-4/4-004c/temperature",
"/sys/devices/platform/omap/omap_temp_sensor.0/temperature",
"/sys/devices/platform/tegra_tmon/temp1_input",
"/sys/kernel/debug/tegra_thermal/temp_tj",
"/sys/devices/platform/s5p-tmu/temperature",
"/sys/class/hwmon/hwmon0/device/temp1_input",
"/sys/devices/virtual/thermal/thermal_zone0/temp",
"/sys/class/thermal/thermal_zone0/temp",
"/sys/class/hwmon/hwmonX/temp1_input",
"/sys/devices/platform/s5p-tmu/curr_temp"
//这里的i我设定为0~100遍历
"/sys/devices/virtual/thermal/thermal_zone"+i+"/type";
"/sys/devices/virtual/thermal/thermal_zone"+i+"/temp";
我们可以对分类筛选出的结果求平均值,最后可以得到诸如机身温度、CPU温度、GPU温度这样的数据,结果存在一定的误差,不过对于分析参考已经足够了。
结果
最后我把它做成了悬浮窗,可以在游戏测试的过程中观察:
还是比较方便直观的,我们可以看到温度的变化趋势,可以看到CPU运行的瓶颈,以及何时会发生降频。而且还可以观察竞品游戏的运行状态。另外,通过ADB也可以获取这个数据,不过在连数据线的情况下,会受到一些干扰。