All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.internal.os.WakelockPowerCalculator Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.os;

import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;

import java.util.List;

public class WakelockPowerCalculator extends PowerCalculator {
    private static final String TAG = "WakelockPowerCalculator";
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private final UsageBasedPowerEstimator mPowerEstimator;

    private static class PowerAndDuration {
        public long durationMs;
        public double powerMah;
    }

    public WakelockPowerCalculator(PowerProfile profile) {
        mPowerEstimator = new UsageBasedPowerEstimator(
                profile.getAveragePower(PowerProfile.POWER_CPU_IDLE));
    }

    @Override
    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
        final PowerAndDuration result = new PowerAndDuration();
        UidBatteryConsumer.Builder osBatteryConsumer = null;
        double osPowerMah = 0;
        long osDurationMs = 0;
        long totalAppDurationMs = 0;
        double appPowerMah = 0;
        final SparseArray uidBatteryConsumerBuilders =
                builder.getUidBatteryConsumerBuilders();
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
            calculateApp(result, app.getBatteryStatsUid(), rawRealtimeUs,
                    BatteryStats.STATS_SINCE_CHARGED);
            app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs)
                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
            totalAppDurationMs += result.durationMs;
            appPowerMah += result.powerMah;

            if (app.getUid() == Process.ROOT_UID) {
                osBatteryConsumer = app;
                osDurationMs = result.durationMs;
                osPowerMah = result.powerMah;
            }
        }

        // The device has probably been awake for longer than the screen on
        // time and application wake lock time would account for.  Assign
        // this remainder to the OS, if possible.
        calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs,
                BatteryStats.STATS_SINCE_CHARGED, osPowerMah, osDurationMs, totalAppDurationMs);
        final double remainingPowerMah = result.powerMah;
        if (osBatteryConsumer != null) {
            osBatteryConsumer.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
                    result.durationMs)
                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, remainingPowerMah);
        }

        long wakeTimeMs = calculateWakeTimeMillis(batteryStats, rawRealtimeUs, rawUptimeUs);
        if (wakeTimeMs < 0) {
            wakeTimeMs = 0;
        }
        builder.getAggregateBatteryConsumerBuilder(
                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
                        wakeTimeMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
                        appPowerMah + remainingPowerMah);
        builder.getAggregateBatteryConsumerBuilder(
                BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
                        totalAppDurationMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK,
                        appPowerMah);
    }

    @Override
    public void calculate(List sippers, BatteryStats batteryStats,
            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray asUsers) {
        final PowerAndDuration result = new PowerAndDuration();
        BatterySipper osSipper = null;
        double osPowerMah = 0;
        long osDurationMs = 0;
        long totalAppDurationMs = 0;
        for (int i = sippers.size() - 1; i >= 0; i--) {
            final BatterySipper app = sippers.get(i);
            if (app.drainType == BatterySipper.DrainType.APP) {
                calculateApp(result, app.uidObj, rawRealtimeUs, statsType);
                app.wakeLockTimeMs = result.durationMs;
                app.wakeLockPowerMah = result.powerMah;
                totalAppDurationMs += result.durationMs;

                if (app.getUid() == Process.ROOT_UID) {
                    osSipper = app;
                    osPowerMah = result.powerMah;
                    osDurationMs = result.durationMs;
                }
            }
        }

        // The device has probably been awake for longer than the screen on
        // time and application wake lock time would account for.  Assign
        // this remainder to the OS, if possible.
        if (osSipper != null) {
            calculateRemaining(result, batteryStats, rawRealtimeUs, rawUptimeUs, statsType,
                    osPowerMah, osDurationMs, totalAppDurationMs);
            osSipper.wakeLockTimeMs = result.durationMs;
            osSipper.wakeLockPowerMah = result.powerMah;
            osSipper.sumPower();
        }
    }

    private void calculateApp(PowerAndDuration result, BatteryStats.Uid u, long rawRealtimeUs,
            int statsType) {
        long wakeLockTimeUs = 0;
        final ArrayMap wakelockStats =
                u.getWakelockStats();
        final int wakelockStatsCount = wakelockStats.size();
        for (int i = 0; i < wakelockStatsCount; i++) {
            final BatteryStats.Uid.Wakelock wakelock = wakelockStats.valueAt(i);

            // Only care about partial wake locks since full wake locks
            // are canceled when the user turns the screen off.
            BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
            if (timer != null) {
                wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType);
            }
        }
        result.durationMs = wakeLockTimeUs / 1000; // convert to millis

        // Add cost of holding a wake lock.
        result.powerMah = mPowerEstimator.calculatePower(result.durationMs);
        if (DEBUG && result.powerMah != 0) {
            Log.d(TAG, "UID " + u.getUid() + ": wake " + result.durationMs
                    + " power=" + formatCharge(result.powerMah));
        }
    }

    private void calculateRemaining(PowerAndDuration result, BatteryStats stats, long rawRealtimeUs,
            long rawUptimeUs, int statsType, double osPowerMah, long osDurationMs,
            long totalAppDurationMs) {
        final long wakeTimeMillis = calculateWakeTimeMillis(stats, rawRealtimeUs, rawUptimeUs)
                - totalAppDurationMs;
        if (wakeTimeMillis > 0) {
            final double power = mPowerEstimator.calculatePower(wakeTimeMillis);
            if (DEBUG) {
                Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power " + formatCharge(power));
            }
            result.durationMs = osDurationMs + wakeTimeMillis;
            result.powerMah = osPowerMah + power;
        } else {
            result.durationMs = 0;
            result.powerMah = 0;
        }
    }

    /**
     * Return on-battery/screen-off time.  May be negative if the screen-on time exceeds
     * the on-battery time.
     */
    private long calculateWakeTimeMillis(BatteryStats batteryStats, long rawRealtimeUs,
            long rawUptimeUs) {
        final long batteryUptimeUs = batteryStats.getBatteryUptime(rawUptimeUs);
        final long screenOnTimeUs =
                batteryStats.getScreenOnTime(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
        return (batteryUptimeUs - screenOnTimeUs) / 1000;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy