adb shell dumpsys battery源码解析

56 篇文章 0 订阅
8 篇文章 0 订阅

首先执行 adb shell dumpsys battery 看看

~/projects/MTK_R_6580_2/alps/frameworks$ adb shell dumpsys battery
Current Battery Service state:
  AC powered: false
  USB powered: true
  Wireless powered: false
  Max charging current: 500000
  Max charging voltage: 5000000
  Charge counter: 4980000
  status: 5
  health: 2
  present: true
  level: 100
  scale: 100
  voltage: 4377
  temperature: 250
  technology: Li-ion

Current Battery Service state 这个字符串为出发点查找文件

~/projects/MTK_R_6580_2/alps/frameworks$ grep "Current Battery Service state" ./ -r
frameworks/base/services/core/java/com/android/server/BatteryService.java:                pw.println("Current Battery Service state:");

找到在frameworks/base/services/core/java/com/android/server/BatteryService.java文件
相关代码如下

private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
    synchronized (mLock) {
        if (args == null || args.length == 0 || "-a".equals(args[0])) {
            pw.println("Current Battery Service state:");
            if (mUpdatesStopped) {
                pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");
            }
            pw.println("  AC powered: " + mHealthInfo.chargerAcOnline);
            pw.println("  USB powered: " + mHealthInfo.chargerUsbOnline);
            pw.println("  Wireless powered: " + mHealthInfo.chargerWirelessOnline);
            pw.println("  Max charging current: " + mHealthInfo.maxChargingCurrent);
            pw.println("  Max charging voltage: " + mHealthInfo.maxChargingVoltage);
            pw.println("  Charge counter: " + mHealthInfo.batteryChargeCounter);
            pw.println("  status: " + mHealthInfo.batteryStatus);
            pw.println("  health: " + mHealthInfo.batteryHealth);
            pw.println("  present: " + mHealthInfo.batteryPresent);
            pw.println("  level: " + mHealthInfo.batteryLevel);
            pw.println("  scale: " + BATTERY_SCALE);
            pw.println("  voltage: " + mHealthInfo.batteryVoltage);
            pw.println("  temperature: " + mHealthInfo.batteryTemperature);
            pw.println("  technology: " + mHealthInfo.batteryTechnology);
        } else {
            Shell shell = new Shell();
            shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
        }
    }
}

从上面这段代码中可以看出 args 为空或 args 的第一个参数为 -a 的时候会打印电池相关信息,然后我们再看 else 部分代码

Shell shell = new Shell();
shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));

Shell的代码如下

class Shell extends ShellCommand {
    @Override
    public int onCommand(String cmd) {
        return onShellCommand(this, cmd);
    }

    @Override
    public void onHelp() {
        PrintWriter pw = getOutPrintWriter();
        dumpHelp(pw);
    }
}

想必在shell执行exec方法的时候会回调到 onCommand()方法,为了验证我们的猜想,看一下 Shell 的父类 ShellCommand

frameworks/base/core/java/android/os/ShellCommand.java

public abstract class ShellCommand extends BasicShellCommandHandler {
    private ShellCallback mShellCallback;
    private ResultReceiver mResultReceiver;

    public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
        mShellCallback = callback;
        mResultReceiver = resultReceiver;
        final int result = super.exec(target, in, out, err, args);

        if (mResultReceiver != null) {
            mResultReceiver.send(result, null);
        }

        return result;
    }

ShellCommand中没有找到 onCommand 的回调,但找到 super.exec() ,继续往父类中看
frameworks/base/core/java/android/os/BasicShellCommandHandler.java

public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
        String[] args) {
    String cmd;
    int start;
    if (args != null && args.length > 0) {
        cmd = args[0];
        start = 1;
    } else {
        cmd = null;
        start = 0;
    }
    init(target, in, out, err, args, start);
    mCmd = cmd;

    if (DEBUG) {
        RuntimeException here = new RuntimeException("here");
        here.fillInStackTrace();
        Log.d(TAG, "Starting command " + mCmd + " on " + mTarget, here);
        Log.d(TAG, "Calling uid=" + Binder.getCallingUid()
                + " pid=" + Binder.getCallingPid());
    }
    int res = -1;
    try {
        res = onCommand(mCmd);					// 果然在这里找到了 onCommand() 方法的回调
        if (DEBUG) Log.d(TAG, "Executed command " + mCmd + " on " + mTarget);
    } catch (Throwable e) {
        // Unlike usual calls, in this case if an exception gets thrown
        // back to us we want to print it back in to the dump data, since
        // that is where the caller expects all interesting information to
        // go.
        PrintWriter eout = getErrPrintWriter();
        eout.println();
        eout.println("Exception occurred while executing '" + mCmd + "':");
        e.printStackTrace(eout);
    } finally {
        if (DEBUG) Log.d(TAG, "Flushing output streams on " + mTarget);
        if (mOutPrintWriter != null) {
            mOutPrintWriter.flush();
        }
        if (mErrPrintWriter != null) {
            mErrPrintWriter.flush();
        }
        if (DEBUG) Log.d(TAG, "Sending command result on " + mTarget);
    }
    if (DEBUG) Log.d(TAG, "Finished command " + mCmd + " on " + mTarget);
    return res;
}

现在回到 Shell 类中看一下 onShellCommand(this, cmd); 方法中做了什么

int onShellCommand(Shell shell, String cmd) {
    if (cmd == null) {
        return shell.handleDefaultCommands(cmd);
    }
    PrintWriter pw = shell.getOutPrintWriter();
    switch (cmd) {
        case "unplug": {
            int opts = parseOptions(shell);
            getContext().enforceCallingOrSelfPermission(
                    android.Manifest.permission.DEVICE_POWER, null);
            if (!mUpdatesStopped) {
                copy(mLastHealthInfo, mHealthInfo);
            }
            mHealthInfo.chargerAcOnline = false;
            mHealthInfo.chargerUsbOnline = false;
            mHealthInfo.chargerWirelessOnline = false;
            long ident = Binder.clearCallingIdentity();
            try {
                mUpdatesStopped = true;
                processValuesFromShellLocked(pw, opts);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        } break;
        case "set": {
            int opts = parseOptions(shell);
            getContext().enforceCallingOrSelfPermission(
                    android.Manifest.permission.DEVICE_POWER, null);
            final String key = shell.getNextArg();
            if (key == null) {
                pw.println("No property specified");
                return -1;

            }
            final String value = shell.getNextArg();
            if (value == null) {
                pw.println("No value specified");
                return -1;

            }
            try {
                if (!mUpdatesStopped) {
                    copy(mLastHealthInfo, mHealthInfo);
                }
                boolean update = true;
                switch (key) {
                    case "present":
                        mHealthInfo.batteryPresent = Integer.parseInt(value) != 0;
                        break;
                    case "ac":
                        mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0;
                        break;
                    case "usb":
                        mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0;
                        break;
                    case "wireless":
                        mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0;
                        break;
                    case "status":
                        mHealthInfo.batteryStatus = Integer.parseInt(value);
                        break;
                    case "level":
                        mHealthInfo.batteryLevel = Integer.parseInt(value);
                        break;
                    case "counter":
                        mHealthInfo.batteryChargeCounter = Integer.parseInt(value);
                        break;
                    case "temp":
                        mHealthInfo.batteryTemperature = Integer.parseInt(value);
                        break;
                    case "invalid":
                        mInvalidCharger = Integer.parseInt(value);
                        break;
                    default:
                        pw.println("Unknown set option: " + key);
                        update = false;
                        break;
                }
                if (update) {
                    long ident = Binder.clearCallingIdentity();
                    try {
                        mUpdatesStopped = true;
                        processValuesFromShellLocked(pw, opts);
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                }
            } catch (NumberFormatException ex) {
                pw.println("Bad value: " + value);
                return -1;
            }
        } break;
        case "reset": {
            int opts = parseOptions(shell);
            getContext().enforceCallingOrSelfPermission(
                    android.Manifest.permission.DEVICE_POWER, null);
            long ident = Binder.clearCallingIdentity();
            try {
                if (mUpdatesStopped) {
                    mUpdatesStopped = false;
                    copy(mHealthInfo, mLastHealthInfo);
                    processValuesFromShellLocked(pw, opts);
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        } break;
        default:
            return shell.handleDefaultCommands(cmd);
    }
    return 0;
}

看到这段代码应该就豁然开朗了,看到有3个方法 unplug、set、reset
set 方法后面有可以跟present、ac、usb、wireless、status、level、counter、temp、invalid

我们再回到最开始的地方看一下是哪里调用 dumpInternal() 方法的?

private final class BinderService extends Binder {
    @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;

        if (args.length > 0 && "--proto".equals(args[0])) {
            dumpProto(fd);
        } else {
            dumpInternal(fd, pw, args);
        }
    }

    @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
            FileDescriptor err, String[] args, ShellCallback callback,
            ResultReceiver resultReceiver) {
        (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
    }
}

哦,原来是 binder,那是不是其它的binder(或者自己加的binder)也可以通过这种方法做一些功能方便我们调试呢?小伙伴们可以自己尝试一下哦!~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值