前语

记载寻找替换方案的进程

top 指令现已不可行

首要检验运用 top 指令去获取 cpu 信息,在电脑上履行

adb shell top -n 1

获取到的信息如下

C:\Users\Admin>adb shell top -n 1
[uTasks: 769 total,   3 running, 766 sleeping,   0 stopped,   0 zombie
Mem:      5.4G total,      5.4G used,       71M free,      239M buffers
Swap:      2.5G total,      610M used,      1.9G free,      2.2G cached
800%cpu  45%user   0%nice 100%sys 634%idle   0%iow  17%irq   3%sirq   0%host

看到可以获取 cpu 信息了,但是没快乐多久,当放到 Android App 中去履行时,就 G 了,在我 Android 13 的手机上一向获取到 cpu 信息都是 0 ,不甘心换了台 Android 10 检验也是相同成果

成果如下

line : 800%cpu   0%user   0%nice   0%sys 800%idle   0%iow   0%irq   0%sirq   0%host

看来 top 指令的办法现已不再可用了,去滴滴 Dokit 上看到也有人反馈 Dokit 获取不到 cpu 信息,只能另找方案了 github.com/didi/DoKit/…

HardwarePropertiesManager

检验通过系统服务来直接获取 cpu 运用率,最终仍是不可,相同也是需求系统运用才能访问到

cpufreq 途径

作为一个 sys 目录下的一个途径,看到有博客说这种办法可用

这种方案有两种办法获取

  1. 通过逐个获取每个 cpu 的运转时间,比方我的小米是 8 核 cpu,那我去获取 cpu[0-7] 共 8 份文件中的总和
  • 通过 cpu 战略,比方 8 核有 3 份战略,这种方案的确可以少读取几个文件,但有个疑问,怎么去获取战略数量,会不会有些 cpu 战略并不是 3 份,这种又怎么处理呢

先来看下第一种办法获取,获取 cpu7 的参数,前面是 cpu 频率,后边对应频率下的履行时间

C:\Users\Admin>adb shell cat /sys/devices/system/cpu/cpu7/cpufreq/stats/time_in_state
825600 55901351
902400 86570
979200 74804
1056000 213817
1209600 129256
1286400 52766
1363200 79177
1459200 43535
1536000 24624
1612800 87744
1689600 55199
1766400 18301
1843200 16066
1920000 13120
1996800 14409
2092800 59493
2169600 13362
2246400 21327
2323200 80973
2400000 8857
2476800 8298
2553600 10331
2649600 55135
2803200 543609

再看第二种办法获取,他俩其实仍是有不同,比方 “2803200 ” 这个频率下,我就没在 policy0/4/7 这三个战略中找到对应的

C:\Users\Admin>adb shell cat  /sys/devices/system/cpu/cpufreq/policy7/stats/time_in_state
806400 13732109
940800 60388
1056000 804627
1171200 189701
1286400 290102
1401600 158627
1497600 36420
1612800 79639
1728000 207300
1843200 24322
1958400 80042
2054400 691783
2169600 803
2284800 53212
2400000 94008
2515200 339
2630400 258
2726400 258
2822400 311
2841600 14242
2995200 1950

sys 中记载了全部战略下 CPU 运用时间,只需一个个累加起来就是 CPU 的总运用时长

然后找到 CPU 空闲,就可以核算出 CPU 的运用率了

具体流程

  1. 查找有几份战略
  2. 然后读取不同战略下的总时长

读取文件的办法

     private void getCpuTime(String fileName) {
           try {
                BufferedReader cpuReader = new BufferedReader(new InputStreamReader(
                            new FileInputStream(fileName)), 1000);
                String line = cpuReader.readLine();
                while (line != null) {
                    String[] cpuInfoArray = line.split(" ");
                    Log.e(TAG, " cpuRate"+ cpuInfoArray[1]);
                    cpuTime += Long.parseLong(cpuInfoArray[1]);
                    line = cpuReader.readLine();
                 }
              } catch (Throwable throwable) {
                  Log.e(TAG, "doSample: ", throwable);
              } finally {
                    try {
                        if (cpuReader != null) {
                            cpuReader.close();
                        }
                    } catch (IOException exception) {
                        Log.e(TAG, "doSample: ", exception);
                    }
                }
            }

获取空闲时间

获取 Cpu 空闲时间费事一点点,大概流程:

// 获取其时 cpuidle state
C:\Users\Admin>adb shell ls /sys/devices/system/cpu/cpu0/cpuidle
driver
state0
state1
state2
// state 对应的时长 (微秒)
C:\Users\Admin>adb shell cat /sys/devices/system/cpu/cpu0/cpuidle/state0/time
160453296988
  1. 先获取 cpu0 的 idleSate,一般由一两个,然后通过 state 获取其时空闲时间
  2. 然后获取其时 state 的进入次数
  3. 第一二步的值相乘,就获取到 cpu0 的空闲时间了(微秒)
  4. 重复 1-3 步,直到获取全部 cpu 的空闲时间

看作者的博文中说到,这样还会呈现空闲时间核算禁绝的情况,原因是有些 state 的改写延时大于我们一般的采样时间(比方 BlockCanary 默认为 200ms),在核算空闲时长的差值很小,接近 0 ,导致核算出来的 CPU 运用率很高,跟真实的偏差大

作者也给出了方案,具体可以看 Android 高版别搜集系统CPU运用率的办法

小结

一通检验下来,验证了的确有替换方案,来获取 cpu 运用率,接下来 fork BlockCanary 代码准备着手改造了

相关链接

  • Android 高版别搜集系统CPU运用率的办法

  • AnotherMonitor 监测库,库作者也在寻找替换方案

  • 浅显易懂CPUFreq|极客笔记 (deepinout.com)

  • adb shell top 指令详解

  • sysfs CPUFreq Stats的一般阐明