Android 8.0— 02 电池的耗电详情-模拟耗电数据 getFakeStats

本文介绍了一种在Android系统中模拟电池耗电数据的方法。通过使用PowerUsageSummary类中的getFakeStats()函数,开发者可以在无需等待真实耗电数据的情况下进行UI和算法的调试。文章详细解释了如何设置调试开关、制造模拟耗电数据,并展示了如何计算耗电百分比。

1.PowerUsageSummary.getFakeStats()

Google的函数调试,实际用途不大,但是适合修改UI和算法,毕竟总不能静静等耗电数据产生吧。

故这里提供了非常好的模拟数据和方法,进行调试耗电详情列表

模拟数据

1.1 开启调试开关

Z:\8.1\vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\fuelgauge\PowerUsageSummary.java

/**
 * Displays a list of apps and subsystems that consume power, ordered by how much power was
 * consumed since the last time it was unplugged.
 */
public class PowerUsageSummary extends PowerUsageBase implements
        AnomalyDialogListener, OnLongClickListener, OnClickListener {

    private static final boolean USE_FAKE_DATA = true;
    private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
1.2 耗电详情类型
// frameworks/base/core/java/com/android/internal/os/BatterySipper.java
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatterySipper.DrainType;

    public enum DrainType {
        IDLE,
        CELL,
        PHONE,
        WIFI,
        BLUETOOTH,
        FLASHLIGHT,
        SCREEN,
        APP,
        USER,
        UNACCOUNTED,
        OVERCOUNTED,
        CAMERA,
        MEMORY
    }
1.3 制造模拟耗电数据

PowerUsageSummary->getFakeStats() 主要进行 DrainType 中的所有类型的模拟数据填充

    private static List<BatterySipper> getFakeStats() {
        ArrayList<BatterySipper> stats = new ArrayList<>();
        // 耗电量 单位是 mA
        float use = 5;
        // 遍历耗电类型,除了APP类型,其他类型数据填充模拟数据 use
        for (DrainType type : DrainType.values()) {
            // 应用类型的耗电数据
            if (type == DrainType.APP) {
                // 过滤掉
                continue;
            }
            // 接口名称 BatterySipper(DrainType drainType, Uid uid, double value)
            /**
                05-30 12:27:56.464  1295  1295 D fadi: type = IDLE, use = 5.0 mA
                05-30 12:27:56.464  1295  1295 D fadi: type = CELL, use = 10.0 mA
                05-30 12:27:56.464  1295  1295 D fadi: type = PHONE, use = 15.0 mA
                05-30 12:27:56.464  1295  1295 D fadi: type = WIFI, use = 20.0 mA
                05-30 12:27:56.464  1295  1295 D fadi: type = BLUETOOTH, use = 25.0 mA
                05-30 12:27:56.464  1295  1295 D fadi: type = FLASHLIGHT, use = 30.0 mA
                05-30 12:27:56.465  1295  1295 D fadi: type = SCREEN, use = 35.0 mA
                05-30 12:27:56.465  1295  1295 D fadi: type = USER, use = 40.0 mA
                05-30 12:27:56.465  1295  1295 D fadi: type = UNACCOUNTED, use = 45.0 mA
                05-30 12:27:56.465  1295  1295 D fadi: type = OVERCOUNTED, use = 50.0 mA
                05-30 12:27:56.465  1295  1295 D fadi: type = CAMERA, use = 55.0 mA
                05-30 12:27:56.465  1295  1295 D fadi: type = MEMORY, use = 60.0 mA
             */
            stats.add(new BatterySipper(type, null, use));
            use += 5;
        }

        // 将 UID为 10000 ~ 10099 的应用,填写上模拟耗电数据数据
        for (int i = 0; i < 100; i++) {
            // 具体UID 对应的应用可以使用命令导出查看 adb pull /data/system/packages.xml D://
            /**
             *  05-30 12:48:54.623  1297  1297 D fadi    : DrainType.APP UID = 10000, use = 65.0 mA
                05-30 12:48:54.624  1297  1297 D fadi    : DrainType.APP UID = 10001, use = 65.0 mA
                05-30 12:48:54.625  1297  1297 D fadi    : DrainType.APP UID = 10002, use = 65.0 mA
                ... ...
                05-30 12:48:54.649  1297  1297 D fadi    : DrainType.APP UID = 10097, use = 65.0 mA
                05-30 12:48:54.649  1297  1297 D fadi    : DrainType.APP UID = 10098, use = 65.0 mA
                05-30 12:48:54.649  1297  1297 D fadi    : DrainType.APP UID = 10099, use = 65.0 mA
             */
            stats.add(new BatterySipper(DrainType.APP, new FakeUid(Process.FIRST_APPLICATION_UID + i), use));
        }

        // 事实上没有 uid 为 0 的进程,可作为防错检测
        // stats.add(new BatterySipper(DrainType.APP,new FakeUid(0), use));

        // 模拟odex进程的耗电数据 Simulate dex2oat process.
        // // 模拟UID 10000 的耗电数据
        // android.auto_generated_rro__ 10000 0 /data/user/0/android.auto_generated_rro__ platform:targetSdkVersion=27 none
        BatterySipper sipper = new BatterySipper(DrainType.APP,
                new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID)), 10.0f);
        sipper.packageWithHighestDrain = "dex2oat";
        stats.add(sipper);

        // 模拟UID 10001 的耗电数据
        // com.android.systemui.theme.dark 10001 1 /data/user/0/com.android.systemui.theme.dark platform:targetSdkVersion=27 none
        sipper = new BatterySipper(DrainType.APP,
                new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f);
        sipper.packageWithHighestDrain = "dex2oat";
        stats.add(sipper);

        // 模拟日志进程的耗电数据
        sipper = new BatterySipper(DrainType.APP,
                new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f);
        stats.add(sipper);

        return stats;
    }
1.4 显示耗电数据

PowerUsageSummary->refreshAppListGroup()

具体如下

    private void refreshAppListGroup() {
        final Context context = getContext();
        // 获取电量校准文件
        final PowerProfile powerProfile = mStatsHelper.getPowerProfile();
        // 电量相关数据,我们也可以使用 adb shell dumpsys batterystats > batterystats.txt 导出
        final BatteryStats stats = mStatsHelper.getStats();
        // 屏幕最高亮度平均电流
        final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
        boolean addedSome = false;

        // frameworks/base/core/res/res/values/attrs.xml:1095:        <attr name="colorControlNormal" format="color" />
        // TypedArray是存储资源数组的容器
        TypedArray array = context.obtainStyledAttributes(
                new int[]{android.R.attr.colorControlNormal});
        final int colorControl = array.getColor(0, 0);

        Log.d("fadi", "colorControl = " + colorControl);
        // 使用完后释放
        array.recycle();

        // dichargeaAmount 相当于 usb 拔掉后这段时间的电量
        final int dischargeAmount = USE_FAKE_DATA ? 5000
                : stats != null ? stats.getDischargeAmount(mStatsType) : 0;

        cacheRemoveAllPrefs(mAppListGroup);
        // 被add进来的时候是否排序
        mAppListGroup.setOrderingAsAdded(false);

        Log.d("fadi", "averagePower = " + averagePower);
        if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) {
            final List<BatterySipper> usageList = getCoalescedUsageList(
                    USE_FAKE_DATA ? getFakeStats() : mStatsHelper.getUsageList());
            double hiddenPowerMah = mShowAllApps ? 0 /**完整设备用电量*/:
                    mBatteryUtils.removeHiddenBatterySippers(usageList)/**显示应用使用情况*/;
            // 排序,耗电量从高到低
            mBatteryUtils.sortUsageList(usageList);

            final int numSippers = usageList.size();
            for (int i = 0; i < numSippers; i++) {
                final BatterySipper sipper = usageList.get(i);
                double totalPower = USE_FAKE_DATA ? 4000 : mStatsHelper.getTotalPower();


                // 耗电量百分比换算
                final double percentOfTotal = mBatteryUtils.calculateBatteryPercent(
                        sipper.totalPowerMah/**该类型耗电量大小*/, totalPower/**总负载耗电量*/, hiddenPowerMah, dischargeAmount/**usb 拔掉后这段时间的电量*/);

                ...
                主要是应用信息获取形成 list
1.5 耗电百分百换算
package com.android.settings.fuelgauge;

/**
 * Utils for battery operation
 */
public class BatteryUtils {

    /**
     * Calculate the power usage percentage for an app
     *
     * @param powerUsageMah   power used by the app
     * @param totalPowerMah   total power used in the system
     * @param hiddenPowerMah  power used by no-actionable app that we want to hide, i.e. Screen,
     *                        Android OS.
     * @param dischargeAmount The discharge amount calculated by {@link BatteryStats}
     * @return A percentage value scaled by {@paramref dischargeAmount}
     * @see BatteryStats#getDischargeAmount(int)
     */
    public double calculateBatteryPercent(double powerUsageMah, double totalPowerMah,
            double hiddenPowerMah, int dischargeAmount) {
        if (totalPowerMah == 0) {
            return 0;
        }
        // 
        return (powerUsageMah / (totalPowerMah - hiddenPowerMah)) * dischargeAmount;
    }
1.6 结语

我们可以通过 getFakeStats() 函数进行模拟数据的修改和调试,快速看到功耗结果。
其中模拟数据 BatterySipper(DrainType drainType, Uid uid, double value),的三个参数,耗电类型,耗电应用UID,和耗电量构成了耗电列表的主要参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

法迪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值