Android获取温度与CPU频率

Posted by LioMiss on June 22, 2023 阅读()

最近在研究如何避免游戏在中低端手机上发热降频,需要一些指标来参考,主要是手机各个传感器的实时温度,与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温度这样的数据,结果存在一定的误差,不过对于分析参考已经足够了。

结果

最后我把它做成了悬浮窗,可以在游戏测试的过程中观察: pPHWj2Q.png
还是比较方便直观的,我们可以看到温度的变化趋势,可以看到CPU运行的瓶颈,以及何时会发生降频。而且还可以观察竞品游戏的运行状态。另外,通过ADB也可以获取这个数据,不过在连数据线的情况下,会受到一些干扰。