Android开发之获取手机硬件状态信息(CPU信息/频率/使用率、DDR频率/使用率、电池瞬时电流/电压/库伦counter)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzk594512323/article/details/85098354

有时候我们想要知道当前手机的一些状态信息,可以使用app(root 或者系统签名 )来显示获取。

OK,接下来看一下一些关键的代码。

我这里使用的是高通的手机,不同硬件平台的机型,其获取信息的节点可能不一样。


        /**
         * 获取当前瞬时电流
         * @return 返回获取的电流
         */
        public String getCurrent() {
            String[] cmds = {"cat /sys/class/power_supply/battery/current_now"};
            ShellUtils.CommandResult rs = ShellUtils.execCommand(cmds, false, true);
            if (!TextUtils.isEmpty(rs.successMsg)) {
                return "当前电流:"+rs.successMsg;
            } else {
                return "当前电流:" + "unknown";
            }
        }


        /**
         * 获取当前Counter
         * @return 获取的counter
         */
        public String getCounter() {
            String[] cmds = new String[]{"cat /sys/class/power_supply/battery/charge_counter"};
            ShellUtils.CommandResult rs = ShellUtils.execCommand(cmds, false, true);
            if (!TextUtils.isEmpty(rs.successMsg)) {
                return "库伦值:" + rs.successMsg;
            } else {
                return "库伦值:" + "unknown";
            }
            //Log.e("debug","库伦值:"+rs.successMsg);
        }

        /**
         * 获取GPU的频率
         * @return 返回GPU频率
         */
        public String getGPU() {
            String[] cmds = new String[]{"cat /sys/class/kgsl/kgsl-3d0/gpuclk"};
            ShellUtils.CommandResult rs = ShellUtils.execCommand(cmds, false, true);
            if (!TextUtils.isEmpty(rs.successMsg)) {
                return "GPU:" + rs.successMsg+"("+gpuBusy()+")";
            } else {
                return "GPU:" + "unknown"+"("+gpuBusy()+")";
            }
        }


        /**
         * DDR的频率和使用率
         * @return
         */
        public String clkMeasure() {
            String[] cmds = new String[]{"cd /d/clk/bimc_clk/","cat clk_measure"};
            ShellUtils.CommandResult rs = ShellUtils.execCommand( cmds, false, true);
//            Log.e("xxxxx",rs.errorMsg);
            if (!TextUtils.isEmpty(rs.successMsg)) {
                return "DDR:" + rs.successMsg+"("+meminfo()+")";
            } else {
                return "DDR:" + "unknown"+"("+meminfo()+")";
            }
        }

        /**
         * 获取当前DDR使用率
         * @return 返回内存使用率%
         */
        public String meminfo() {
            String[] cmds = new String[]{"cat proc/meminfo"};
            ShellUtils.CommandResult rs = ShellUtils.execCommand(cmds, false, true);
            if (!TextUtils.isEmpty(rs.successMsg)) {
                String[] tmpList = rs.successMsg.split("kB");
                Double total = null, free = null, available = null, cached = null;
                for (String line : tmpList) {
                    if (line.contains("MemTotal:")) {
                        total = Double.valueOf(Pattern.compile("[^0-9]").matcher(line).replaceAll(""));
                    }
                    if (line.contains("MemFree:")) {
                        free = Double.valueOf(Pattern.compile("[^0-9]").matcher(line).replaceAll(""));
                    }

                    if (line.contains("MemAvailable:")) {
                        available = Double.valueOf(Pattern.compile("[^0-9]").matcher(line).replaceAll(""));
                    }

                    if (line.contains("Cached:")) {
                        cached = Double.valueOf(Pattern.compile("[^0-9]").matcher(line).replaceAll(""));
                        if (total != null && total > 0 && free != null && free > 0) {
                            break;
                        }
                    }
                }
                available = 0.00;
                return String.valueOf(100-mathRound((free + cached) / total * 100)) + "%";
                //Log.e("debug","DDR使用率:"+String.valueOf((total-free-available)/total*100)+"%");
            } else {
                return "unknown";
            }
        }

        
        /**
         * CPU使用率、状态、频率
         * @return
         */
        private String getCPUStatus() {
            String cpuStatusString = "";
            String cpuOnlineStatus = "";
            String cpuFreqStatus = "";

            ArrayList<OneCpuInfo> currentInfo = takeCpuUsageSnapshot();
            int[] cpuUsages = calcCpuUsages(currentInfo, mLastInfo);

            if (cpuUsages != null && cpuUsages.length > 0) {
                cpuStatusString = "CPU状态:"+cpuUsages[0] + "%\n";
//                Log.d(TAG, "cpuUsages length=" + cpuUsages.length);
            } else {
                cpuStatusString = "CPU状态:"+"unknown\n";
                //Log.d(TAG, "cpuUsages is null");
            }

            int cpuNum = getCpuNum();
            int onlineCPUCount = 1;
            for (int i=0; i<cpuNum; i++) {
                ShellUtils.CommandResult rs = ShellUtils.execCommand( new String[]{"cat /sys/devices/system/cpu/cpu" + i + "/online"}, false, true);
                cpuOnlineStatus = rs.successMsg;
                if (cpuOnlineStatus.contains("1")) {
                    rs = ShellUtils.execCommand( new String[]{"cat sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_freq"}, false, true);
                    cpuFreqStatus = rs.successMsg;
                    if (cpuFreqStatus == null || cpuFreqStatus.length() == 1) {
                        cpuStatusString += "cpu" + i + "0 MHz";
                    } else {
                        cpuFreqStatus = cpuFreqStatus.substring(0, cpuFreqStatus.length() - 3);
                        if (cpuUsages != null && onlineCPUCount < cpuUsages.length) {
                            cpuStatusString += "cpu" + i + " " + cpuFreqStatus + " MHz ("+ cpuUsages[onlineCPUCount] + "%)";
                        } else {
                            if (cpuUsages != null)
                                Log.d(TAG, "onlineCPUCount=" + onlineCPUCount + " cpuUsages.length=" + cpuUsages.length);
                            cpuStatusString += "cpu" + i + " " + cpuFreqStatus + " MHz (0%)";
                        }
                    }
                    onlineCPUCount++;
                } else {
                    cpuStatusString += "cpu" + i + " offline";
                }
                if (i<cpuNum-1) {
                    cpuStatusString = cpuStatusString + "\n";
                }
            }

            mLastInfo = currentInfo;
            return cpuStatusString;
        }

工具类ShellUtils :

package com.meitutest.getstat;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public class ShellUtils {

    public static final String COMMAND_SU = "su";
    public static final String COMMAND_SH = "sh";
    public static final String COMMAND_EXIT = "exit\n";
    public static final String COMMAND_LINE_END = "\n";


    /**
     * execute shell commands, default return result msg
     *
     * @param commands command list
     * @param isRoot   whether need to run with root
     * @return
     * @see ShellUtils#execCommand(String[], boolean, boolean)
     */
    public static CommandResult execCommand(List<String> commands, boolean isRoot) {
        return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
    }


    /**
     * execute shell commands
     *
     * @param commands        command array
     * @param isRoot          whether need to run with root
     * @param isNeedResultMsg whether need result msg
     * @return <ul>
     * <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and {@link CommandResult#errorMsg} is
     * null.</li>
     * <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li>
     * </ul>
     */
    public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, null, null);
        }

        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;
        DataOutputStream os = null;
        try {

            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) {
                    continue;
                }
                if (command.contains("uiautomator")) {// 只有执行脚本的时候需要清除缓存
                    StreamGobbler ssgError = new StreamGobbler(process.getErrorStream(), "Error");
                    StreamGobbler ssgOutput = new StreamGobbler(process.getInputStream(), "Output");
                    ssgError.start();
                    ssgOutput.start();
                }
                os.write(command.getBytes());
                os.writeBytes(COMMAND_LINE_END);
                os.flush();

            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();
            result = process.waitFor();
            if (isNeedResultMsg) {
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream()), 1024);
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String s;
                while ((s = successResult.readLine()) != null) {
                    successMsg.append(s);
                }

                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (process != null) {
                process.destroy();

            }
        }

        return new CommandResult(result, successMsg == null ? null
                : successMsg.toString(), errorMsg == null ? null
                : errorMsg.toString());
    }

    /**
     * execute shell commands
     *
     * @param commands        command array
     * @param isRoot          whether need to run with root
     * @param isNeedResultMsg whether need result msg
     * @return <ul>
     * <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and {@link CommandResult#errorMsg} is
     * null.</li>
     * <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li>
     * </ul>
     */
    public static CommandResult execCommandWithNewLine(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, null, null);
        }

        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;
        DataOutputStream os = null;
        try {

            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) {
                    continue;
                }
                if (command.contains("uiautomator")) {// 只有执行脚本的时候需要清除缓存
                    StreamGobbler ssgError = new StreamGobbler(process.getErrorStream(), "Error");
                    StreamGobbler ssgOutput = new StreamGobbler(process.getInputStream(), "Output");
                    ssgError.start();
                    ssgOutput.start();
                }
                os.write(command.getBytes());
                os.writeBytes(COMMAND_LINE_END);
                os.flush();

            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();
            result = process.waitFor();
            if (isNeedResultMsg) {
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream()), 1024);
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String s;
                while ((s = successResult.readLine()) != null) {
                    successMsg.append(s+"\n");
                }

                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s+"\n");
                }

            }
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (process != null) {
                process.destroy();

            }
        }

        return new CommandResult(result, successMsg == null ? null
                : successMsg.toString(), errorMsg == null ? null
                : errorMsg.toString());
    }




    /**
     * result of command
     * <ul>
     * <li>{@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in
     * linux shell</li>
     * <li>{@link CommandResult#successMsg} means success message of command result</li>
     * <li>{@link CommandResult#errorMsg} means error message of command result</li>
     * </ul>
     *
     * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16
     */
    public static class CommandResult {

        /**
         * result of command
         **/
        public int result;
        /**
         * success message of command result
         **/
        public String successMsg;
        /**
         * error message of command result
         **/
        public String errorMsg;


        public CommandResult(int result, String successMsg, String errorMsg) {
            this.result = result;
            this.successMsg = successMsg;
            this.errorMsg = errorMsg;
        }
    }


}

工具类Testreport:

package com.meitutest.getstat;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Calendar;
import java.util.TimeZone;

public class TestReport {
    public static final int OPEN = 0;

    public static final int INFO = 2;
    public static final int ERROR = 3;
    public static final int FAIL = 4;
    public static final int SUCCESS = 5;
    private static final int SELF_DEFINE_ONLY_TXT = 1;
    private static final int SELF_DEFINE = 6;
    public static final int CRASH = 1000;

    public static int logfile_switch = OPEN;
    public static int logcat_switch = OPEN;

    public static int errors, failures, success;

    private static String log_path = "/sdcard/GetSystemStat/";// Environment.getExternalStorageDirectory().getPath();
    private static String log_default_tag = "autotest";



    public static int i(String msg) {
        return i(log_default_tag, msg);
    }

    public static int i(String tag, String msg) {
        return println(INFO, tag, msg);
    }

    public static int e(String msg) {
        return e(log_default_tag, msg);
    }

    public static int e(String tag, String msg) {
        errors++;
        return println(ERROR, tag, msg);
    }



    public static String getLogPath() {
        return log_path;
    }

    public static boolean checkLogPath(String newPath) {
        if (newPath == null) {
            return false;
        }
        boolean ret = false;
        try {
            File logPath = new File(newPath);
            if (!logPath.exists()) {
                logPath.mkdirs();
            }
            if (logPath.isDirectory()) {
                ret = true;
            } else {
                ret = false;
            }
        } catch (Throwable tr) {
            ret = false;
        }
        return ret;
    }



    private static int printToFile(int priority, String tag, String type,
                                   byte[] buffer, int offset, int count) {
        int ret = 0;
        String logpath = getLogPath();
        if (priority == CRASH) {
            type = "crash";
        }
        if (priority < logfile_switch || !checkLogPath(logpath)) {
            if (priority == CRASH) {
                logpath = "/sdcard/";
                type = "crash";
                if (!checkLogPath(logpath)) {
                    return ret;
                }
            } else {
                return ret;
            }
        }
        Thread thread = Thread.currentThread();
        // String threadInfo = "id:"+thread.getId()+";name:"+thread.getName();
        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00"));
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        int millisecond = cal.get(Calendar.MILLISECOND);

        String timeString = String.format("%d-%02d-%02d %02d:%02d:%02d.%d",
                year, month, day, hour, minute, second, millisecond);
        String headString = String.format("\r\n%s\t(%d)\ttag:%s\tdata:",
                timeString, priority, tag);
        byte[] headBuffer = headString.getBytes();

        String fileName;
        switch (priority) {
            case INFO:
                fileName = "%s/AnLog_Info%d%02d%02d.%s";
                break;
            case ERROR:
                fileName = "%s/AnLog_Error%d%02d%02d.%s";
                break;
            case FAIL:
                fileName = "%s/AnLog_Fail%d%02d%02d.%s";
                break;
            case SUCCESS:
                fileName = "%s/AnLog_Success%d%02d%02d.%s";
                break;
            case SELF_DEFINE_ONLY_TXT:
                fileName = "%s/" + tag +".txt";
                break;
            case SELF_DEFINE:
                fileName = "%s/" + tag +".txt";
                break;
            default:
                fileName = "%s/%d%02d%02d.%s";
        }
        fileName = String.format(fileName, logpath, year, month, day, type);
        FileOutputStream fo = null;
        try {
            File file = new File(fileName);
            fo = new FileOutputStream(file, true);
            fo.write(headBuffer);
            fo.write(buffer, offset, count);
            ret = headBuffer.length + count;
        } catch (Throwable tr) {
            ret = 0;
        } finally {
            if (fo != null) {
                try {
                    fo.close();
                } catch (Throwable tr) {
                }
            }
        }
        return ret;
    }

    public static int printMsgToFile(int priority, String tag, String msg) {
        if (msg == null) {
            msg = "[null]";
        }
        byte[] buffer = msg.getBytes();
//		if (tag != null && tag.startsWith("autotest")) {
//			printToFile(priority, tag, "autotest", buffer, 0, buffer.length);
//		}
        return printToFile(priority, tag, "txt", buffer, 0, buffer.length);
    }

    private static int println(int priority, String tag, String msg) {
        int ret = 0;
        if (priority >= logcat_switch) {
            ret += android.util.Log.println(priority, tag, msg);
        }
        if (priority >= logfile_switch) {
            ret += printMsgToFile(priority, tag, msg);
        }
        return ret;
    }

    public static int selfDefine(String tag, String msg, boolean showOnLog) {
        if (!showOnLog) {
            return println(SELF_DEFINE_ONLY_TXT, tag, msg);
        } else {
            return println(SELF_DEFINE, tag, msg);
        }
    }

    public static int selfDefine(String tag, String msg) {
        return selfDefine(tag, msg, false);
    }
}

工具类StreamGobbler:

package com.meitutest.getstat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;

public class StreamGobbler extends Thread {
    InputStream is;
    String type;
    OutputStream os;

    StreamGobbler(InputStream is, String type) {
        this(is, type, null);
    }
    StreamGobbler(InputStream is, String type, OutputStream redirect) {
        this.is = is;
        this.type = type;
        this.os = redirect;
    }

    public void run() {
        try {
            PrintWriter pw = null;
            if (os != null)
                pw = new PrintWriter(os);

            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null) {
                if (pw != null)
                    pw.println(line);
                System.out.println(type + ">" + line);
            }
            if (pw != null)
                pw.flush();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

新建一个线程,再添加使用一个TimerTask的子类,外加一个输出窗口,让这些方法间隔一段时间执行一次,便可以获取实时获取了。

我这里还添加了一个持久化到本地的txt文件中,便于后续查询。

    @Override
    public void run() {
        isRun = true;
//        TestReport.selfDefine(TAG, getCurrent());
        for (int i = 0; i < 9; i++) {
            //当前电流
           TestReport.selfDefine(TAG, getCurrent());
           sleep(1000);
           if (i == 8||i<100) {
//            if (i < 9) {
                String result="=======================\n";
                //当前电流
                result = result+getCurrent()+"uA\n";
                //电流库伦值
                result = result+getCounter()+"uA\n";
                //GPU频率、使用率
                result = result+getGPU()+"\n";
                //DDR频率、使用率
                result = result+clkMeasure()+"\n";
                //CPU信息
                result = result+getCPUStatus()+"\n";
                Log.e("GetSystemState",result);
                TestReport.selfDefine(TAG, result);
            }
        }
    }
    private static int println(int priority, String tag, String msg) {
        int ret = 0;
        if (priority >= logcat_switch) {
            ret += android.util.Log.println(priority, tag, msg);
        }
        if (priority >= logfile_switch) {
            ret += printMsgToFile(priority, tag, msg);
        }
        return ret;
    }

    public static int selfDefine(String tag, String msg, boolean showOnLog) {
        if (!showOnLog) {
            return println(SELF_DEFINE_ONLY_TXT, tag, msg);
        } else {
            return println(SELF_DEFINE, tag, msg);
        }
    }

    public static int selfDefine(String tag, String msg) {
        return selfDefine(tag, msg, false);
    }

成果图:

需要注意的是: 通过APP获取并且做了一些数据上的处理,以及持久化到sdcard上。这些操作都会使用到CPU的处理、IO的读写等,可能会对获取的数据非常轻微的影响。这个,大家可以自主权衡。我亲测过电流和CPU的一些变化,几乎可以忽略不计。如果对数据结果精度要求较高的话,不建议使用这种方式来获取。大家自行斟酌。

猜你喜欢

转载自blog.csdn.net/hzk594512323/article/details/85098354