android耗电量大解决方案

0. 介绍 主要介绍UI位置和基本函数入口,其中耗电详情与power_profile.xml息息相关 1. UI 界面 2. 源码 2.1 设置界面入口 PowerUsageSummary->getPreferenceScreenResId() package com.android.settings.fuelgauge; /** * Displays a

0. 介绍

主要介绍UI位置和基本函数入口,其中耗电详情与power_profile.xml息息相关

1. UI 界面

应用电量

2. 源码

2.1 设置界面入口

PowerUsageSummary->getPreferenceScreenResId()

package com.android.settings.fuelgauge;

/**
 * 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 {

    @Override
    protected int getPreferenceScreenResId() {
        return R.xml.power_usage_summary;
    }
2.2 UI 布局

R.xml.power_usage_summary

<string name="power_usage_list_summary" msgid="6775339745194635000">"充满电(<xliff:g id="TIME">^1</xliff:g>前)后的应用用电量"</string>

    <PreferenceCategory
        android:key="app_list"
        android:title="@string/power_usage_list_summary"/>

上述即 key 为 app_list 为耗电详情列表

2.3 耗电详情 app_list

PowerUsageSummary.java

    private static final String KEY_APP_LIST = "app_list";

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        ...
        mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
2.4 耗电数据填充
  • PowerUsageSummary->refreshAppListGroup, 显示耗电详情
  • PowerUsageSummary->addNotAvailableMessage, 显示没有电池使用数据
    private void refreshAppListGroup() {
        ...
        mAppListGroup.addPreference(notAvailable);
        ...
    }


    private void addNotAvailableMessage() {
        final String NOT_AVAILABLE = "not_available";
        Preference notAvailable = getCachedPreference(NOT_AVAILABLE);
        if (notAvailable == null) {
            notAvailable = new Preference(getPrefContext());
            notAvailable.setKey(NOT_AVAILABLE);
            // <string name="power_usage_not_available" msgid="3109326074656512387">"没有电池使用数据。"</string>
            notAvailable.setTitle(R.string.power_usage_not_available);
            mAppListGroup.addPreference(notAvailable);
        }
    }
2.5 refreshAppListGroup 数据处理
2.5.1 条件判断-功耗参考文件

PowerUsageSummary->refreshAppListGroup

    // 是否使用假数据
    private static final boolean USE_FAKE_DATA = false;

    // 背光电流的最小值
    private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;


    private void refreshAppListGroup() {

        // 获取背光亮度功率
        final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);

        if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) {
            // 这里要求平均电流需要大于 10, 要求我们需要配置 power_profile.xml 文件的电流数据
            // frameworks\base\core\res\res\xml\power_profile.xml 厂商根据功耗电流进行配置,否则该项数据始终为无

            final List<BatterySipper> usageList = getCoalescedUsageList(
                    USE_FAKE_DATA ? getFakeStats() : mStatsHelper.getUsageList());
        }

小知识

文件路径在于:frameworks\base\core\java\com\android\internal\os\PowerProfile.java
文件路径:frameworks\base\core\res\res\xml\power_profile.xml

    /**
     * Power consumption at full backlight brightness. If the backlight is at
     * 50% brightness, then this should be multiplied by 0.5
     */
    public static final String POWER_SCREEN_FULL = "screen.full";

    <item name="screen.full">0.1</item>  <!-- ~300mA -->
2.5.2 功耗文件,获取假数据

PowerUsageSummary-> getFakeStats()

    private static List<BatterySipper> getFakeStats() {
        ArrayList<BatterySipper> stats = new ArrayList<>();
        float use = 5;
        for (DrainType type : DrainType.values()) {
            if (type == DrainType.APP) {
                continue;
            }
            stats.add(new BatterySipper(type, null, use));
            use += 5;
        }
        for (int i = 0; i < 100; i++) {
            stats.add(new BatterySipper(DrainType.APP,
                    new FakeUid(Process.FIRST_APPLICATION_UID + i), use));
        }
        stats.add(new BatterySipper(DrainType.APP,
                new FakeUid(0), use));

        // Simulate dex2oat process.
        BatterySipper sipper = new BatterySipper(DrainType.APP,
                new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID)), 10.0f);
        sipper.packageWithHighestDrain = "dex2oat";
        stats.add(sipper);

        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;
    }
2.5.3 功耗文件,获取功耗数据

frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java

BatteryStatsHelper->getUsageList()

    /**
     * List of apps using power.
     */
    private final List<BatterySipper> mUsageList = new ArrayList<>();

    public List<BatterySipper> getUsageList() {
        return mUsageList;
    }

    public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs, long rawUptimeUs) {
        ...
        mUsageList.add(index, bs);
        ...
    }
知秋君
上一篇 2024-08-23 16:36
下一篇 2024-08-23 16:02

相关推荐