obsidian/笔记文件/2.笔记/安卓cpu占用率.md
2025-04-11 21:47:05 +08:00

7.7 KiB
Raw Permalink Blame History

#python #安卓

如果要通过python的形式检测安卓的cpu占用率是需要通过adb调试的形式一般是连线安卓实体机 在执行上述操作之前需要确认的是安卓的adb调试是已经配置完成和可用的参考设置adb环境变量还有python 3的环境变量也是需要的可参考python设置环境变量,配置完成:

!Pasted image 20250411151801.png

其中安卓的bundleid包名com.DefaultCompany.LGCollecter

!Pasted image 20250411152113.png

这是考虑了cpu多核情况的python脚本1秒的时间间隔采集cpu时间可以直接执行

cpu.py

import subprocess
import time

PACKAGE = "com.DefaultCompany.LGCollecter"
INTERVAL = 1.0

def get_cpu_cores():
    """获取CPU核心数"""
    try:
        output = subprocess.check_output(
            "adb shell grep -c processor /proc/cpuinfo",
            stderr=subprocess.STDOUT,
            shell=True
        )
        return int(output.strip())
    except:
        return 1

def get_pid():
    """持续获取进程ID"""
    while True:
        try:
            output = subprocess.check_output(
                f"adb shell pidof {PACKAGE}",
                stderr=subprocess.STDOUT,
                shell=True
            )
            pid = output.decode().strip()
            if pid:
                return int(pid)
        except subprocess.CalledProcessError:
            pass
        print("等待应用启动...")
        time.sleep(2)

def read_proc_stat():
    """读取系统CPU总时间"""
    output = subprocess.check_output(
        "adb shell head -n1 /proc/stat",
        stderr=subprocess.STDOUT,
        shell=True
    ).decode()
    parts = output.strip().split()[1:8]
    return sum(map(int, parts))

def read_process_cpu(pid):
    """读取进程CPU时间"""
    output = subprocess.check_output(
        f"adb shell cat /proc/{pid}/stat",
        stderr=subprocess.STDOUT,
        shell=True
    ).decode()
    parts = output.strip().split()
    utime = int(parts[13])
    stime = int(parts[14])
    return utime + stime

def main():
    cores = get_cpu_cores()
    pid = get_pid()
    print(f"监控开始 (PID: {pid}, CPU核心: {cores})")

    prev_proc_time = read_process_cpu(pid)
    prev_total_time = read_proc_stat()

    while True:
        time.sleep(INTERVAL)
        
        curr_proc_time = read_process_cpu(pid)
        curr_total_time = read_proc_stat()

        proc_diff = curr_proc_time - prev_proc_time
        total_diff = curr_total_time - prev_total_time

        if total_diff == 0:
            usage = 0.0
        else:
            # 计算实际CPU使用率考虑多核
            usage = 100.0 * proc_diff / total_diff
            # 转换为多核百分比(可选)
            # usage = usage * 100.0 / cores

        print(f"{time.strftime('%H:%M:%S')}  CPU使用率: {usage:.1f}%")

        prev_proc_time = curr_proc_time
        prev_total_time = curr_total_time

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n监控已停止")
    except Exception as e:
        print(f"发生错误: {str(e)}")

安卓相关的java逻辑也可以实现cpu占用率的测算但是这个不是非常准确另外安卓相关的如果要获取系统总的cpu频率等数据相关也就是/proc/stat系统级别的信息一般是不开放这个接口权限的所以不够adb方式的python脚本获取的数据准确

需先申请权限,参考一下,权限申请:

AndroidManifest.xml

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_PROC_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application>
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:theme="@style/UnityThemeSelector">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
</manifest>

Sys.java

    public static float getProcessCPUUsageOnce() {
        try {
            // 第一次采样
            BufferedReader br1 = new BufferedReader(new FileReader("/proc/self/stat"));
            String line1 = br1.readLine();
            String[] parts1 = line1.split("\\s+");
            long utime1 = Long.parseLong(parts1[13]);
            long stime1 = Long.parseLong(parts1[14]);
            long cpuTime1 = utime1 + stime1;

            // 等待1秒
            Thread.sleep(1000);

            // 第二次采样
            BufferedReader br2 = new BufferedReader(new FileReader("/proc/self/stat"));
            String line2 = br2.readLine();
            String[] parts2 = line2.split("\\s+");
            long utime2 = Long.parseLong(parts2[13]);
            long stime2 = Long.parseLong(parts2[14]);
            long cpuTime2 = utime2 + stime2;

            // 计算使用率
            int hz = getSystemClockTicks();
            float usage = ((cpuTime2 - cpuTime1) / (float) hz) * 100f;
            // 新增日志输出
            Log.d("CPUUsage", "系统CPU使用率: " + String.format("%.2f", usage) + "%");
            return Math.max(0, Math.min(usage, 100));

        } catch (Exception e) {
            Log.e("CPUUsage", "获取CPU使用率失败", e);
            e.printStackTrace();
        }
        return -1f;
    }

    // 新增帮助方法 获取CPU时钟频率Hz
    private static int getSystemClockTicks() {
        try {
            // 方法1通过系统属性获取需要API 21+
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                int hz = (int) android.system.Os.sysconf(android.system.OsConstants._SC_CLK_TCK);
                if (hz > 0) {
                    return hz;
                }
            }

            // 方法2通过/proc文件系统动态计算
            // 读取进程启动时间和系统运行时间
            BufferedReader statBr = new BufferedReader(new FileReader("/proc/self/stat"));
            String[] stat = statBr.readLine().split("\\s+");
            long startTime = Long.parseLong(stat[21]); // 启动时间jiffies
            long utime = Long.parseLong(stat[13]);     // 用户态时间
            
            BufferedReader uptimeBr = new BufferedReader(new FileReader("/proc/uptime"));
            String uptimeStr = uptimeBr.readLine().split("\\s+")[0];
            float uptime = Float.parseFloat(uptimeStr); // 系统运行时间(秒)
            
            // 计算HZstartTime的单位是jiffiesuptime的单位是秒
            // HZ = startTime / (uptime - (process_start_time_seconds))
            long processStartSeconds = startTime / 100; // 假设初始HZ=100进行估算
            float actualHz = startTime / (uptime - processStartSeconds);
            
            // 取整并限制合理范围
            int hz = Math.max(100, Math.min(1000, (int)actualHz));
            Log.d("ClockTicks", "Calculated HZ: " + hz);
            return hz;

        } catch (Exception e) {
            Log.e("ClockTicks", "Error calculating HZ, using default 100", e);
            return 100; // 保底返回值
        }
    }