[电池]设置-电池-上次充满电时间计算

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

1. 现象

为什么第一次开机或者格式化后电池显示上次充满电是xxx天或者xxx分钟前,不管之前电池电量数值

实际操作:

  1. 充满电且拔除充电线,则显示上次充满电为0分钟前
  2. 新机器第一次开机,不论当前电量大小,拔除充电线,则显示上次充满电为0分钟前
  3. 修改系统时间未来时间,则显示上次充满电是xxx天或者xxx分钟前
  4. 修改系统时间过去时间,则显示为0分钟前

2. 原因

因为上次充满电接口getStartClockTime中 mStartClockTime = currentTime - (mClocks.elapsedRealtime()/当前自开机后,经过的时间,包括深度休眠的时间/-(mRealtimeStart/1000))决定,其中elapsedRealtime和mRealtimeStart的数值刷新逻辑BatteryStatsImpl->setBatteryStateLocked->setOnBatteryLocked->resetAllStatsLocked->initTimes改变

故这里显示上次充满电是xxx天或者xxx分钟前,是因为没有实际充电的时刻时,取的上次充满电时间为系统当前时间.故会有明明没充满电,显示上次充满电是xxx天或者xxx分钟前的逻辑显示。除非充满电且拔除充电线则为正常显示了。

Google的这个逻辑确实存在不精确

3. 源码

3.1 设置->电池

package com.android.settings.fuelgauge;

public class PowerUsageSummary extends PowerUsageBase implements OnLongClickListener,
        BatteryTipPreferenceController.BatteryTipListener {
        
    @VisibleForTesting
    void updateLastFullChargePreference() {
        if (mBatteryInfo != null && mBatteryInfo.averageTimeToDischarge
                != Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN) {
            // 电池在充满电后的预估使用时间
        } else {
            final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper,
                    System.currentTimeMillis());
            mLastFullChargePref.setTitle(R.string.battery_last_full_charge); // 上次充满电
            mLastFullChargePref.setSubtitle(
                    StringUtil.formatRelativeTime(getContext(), lastFullChargeTime,
                            false /* withSeconds */));
        }
    }

3.2 BatteryUtils.calculateLastFullChargeTime

package com.android.settings.fuelgauge;

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

    /**
     * Calculate the time since last full charge, including the device off time
     * 计算上次充电电时间,包含设备关机时间
     *
     * @param batteryStatsHelper utility class that contains the data 电池信息类
     * @param currentTimeMs      current wall time 当前时间
     * @return time in millis 返回时长
     */
    public long calculateLastFullChargeTime(BatteryStatsHelper batteryStatsHelper,
            long currentTimeMs) {
        return currentTimeMs - batteryStatsHelper.getStats().getStartClockTime();

    }

3.3 BatteryStatsHelper.getStats().getStartClockTime()

  • frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
package com.android.internal.os;

public class BatteryStatsHelper {

    private BatteryStats mStats;

    public BatteryStats getStats() {
        if (mStats == null) {
            load();
        }
        return mStats;
    }
    
    private static BatteryStatsImpl getStats(IBatteryStats service) {
        try {
            ParcelFileDescriptor pfd = service.getStatisticsStream();
            if (pfd != null) {
                try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
                    byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
                    Parcel parcel = Parcel.obtain();
                    parcel.unmarshall(data, 0, data.length);
                    parcel.setDataPosition(0);
                    BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
                            .createFromParcel(parcel);
                    return stats;
                } catch (IOException e) {
                    Log.w(TAG, "Unable to read statistics stream", e);
                }
            }
        } catch (RemoteException e) {
            Log.w(TAG, "RemoteException:", e);
        }
        return new BatteryStatsImpl();
    }
3.3.1 BatteryStats.getStartClockTime()
  • frameworks/base/core/java/android/os/BatteryStats.java
package android.os;

public abstract class BatteryStats implements Parcelable {

    /**
     * Return the wall clock time when battery stats data collection started.
     */
    public abstract long getStartClockTime()
3.3.2 BatteryStatsImpl.getStartClockTime()
  • frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
package com.android.internal.os;

public class BatteryStatsImpl extends BatteryStats {

    // 获取上次充满电时间
    @Override public long getStartClockTime() {
    final long currentTime = System.currentTimeMillis();
    if (ensureStartClockTime(currentTime)) {
            recordCurrentTimeChangeLocked(currentTime, mClocks.elapsedRealtime(),
                    mClocks.uptimeMillis());
        }
        return mStartClockTime;
    }

3.4 BatteryStatsImpl.getStartClockTime

3.4.1 BatteryStatsImpl.getStartClockTime.ensureStartClockTime
package com.android.internal.os;

public class BatteryStatsImpl extends BatteryStats {

    long mStartClockTime;

    void initTimes(long uptime, long realtime) {
        ...
        mStartClockTime = System.currentTimeMillis();
        ...
    }

    // 从电池详情数据库中 batterystats.bin 更新StartClockTime
    public void readSummaryFromParcel(Parcel in) throws ParcelFormatException {
        ...
        // 从 batterystats.bin 获取上次充满电时间
        mStartClockTime = in.readLong();
        mRealtimeStart = in.readLong();
        ...
    }


    public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
        ...
        // Pull the clock time.  This may update the time and make a new history entry
        // if we had originally pulled a time before the RTC was set.
        long startClockTime = getStartClockTime();
        out.writeLong(startClockTime);
        out.writeLong(mRealtimeStart);
        ...
    }

    // 是否需要重新校准上次充满电时间
    boolean ensureStartClockTime(final long currentTime) {
        final long ABOUT_ONE_YEAR = 365*24*60*60*1000L; // 1 年时间 31536000000
        // 是否满足以下条件
        // 1. 当前时间毫秒值 大于 1年,例如这里是100%满足,2018-12-22 10:41:46,即当前时间毫秒值 1545446651000
        // 2. 上次充满电时间StartClockTime 小于 当前时间毫秒值与1年的差, 即这里即记录最长上次充满电1年内,即我手动调整时间,最长只能记录上次充满电365天内

        // 或者满足下面条件
        // 1. 上次充满电时间StartClockTime 大于 当前时间毫秒值,这个条件可以将系统时间调整为过去的时间
        if ((currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR))
                || (mStartClockTime > currentTime)) {
            // If the start clock time has changed by more than a year, then presumably
            // the previous time was completely bogus.  So we are going to figure out a
            // new time based on how much time has elapsed since we started counting.
            mStartClockTime = currentTime - (mClocks.elapsedRealtime()/*获取从设备boot后经历的时间值*/-(mRealtimeStart/1000));
            return true;
        }
        return false;
    }
    
    
3.4.2 查看 mStartClockTime 的赋值情况
  1. BatteryStatsImpl 初始化时间
    private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
            PlatformIdleStateCallback cb,
            UserInfoProvider userInfoProvider) {
        ...
        long uptime = mClocks.uptimeMillis() * 1000;
        long realtime = mClocks.elapsedRealtime() * 1000;
        initTimes(uptime, realtime)
  1. resetAllStatsLocked 初始化时间
    private void resetAllStatsLocked() {
        final long uptimeMillis = mClocks.uptimeMillis();
        final long elapsedRealtimeMillis = mClocks.elapsedRealtime();
        initTimes(uptimeMillis * 1000, elapsedRealtimeMillis * 1000);
        
  1. initTimes 函数
    public interface Clocks {
        public long elapsedRealtime();
        public long uptimeMillis();
    }

    public static class SystemClocks implements Clocks {
        public long elapsedRealtime() {
            return SystemClock.elapsedRealtime(); // 自开机后,经过的时间,包括深度休眠的时间
        }

        public long uptimeMillis() {
            return SystemClock.uptimeMillis(); // 自开机后,经过的时间,不包括深度休眠的时间
        }
    }
    
    void initTimes(long uptime, long realtime) {
        mStartClockTime = System.currentTimeMillis(); // 系统当前时间,即日期时间,可以被系统设置修改,如果设置系统时间,时间值会发生跳变。
        mOnBatteryTimeBase.init(uptime, realtime);
        mOnBatteryScreenOffTimeBase.init(uptime, realtime);
        mRealtimeStart = realtime;
    }

3.5 BatteryStatsImpl.setBatteryStateLocked.setOnBatteryLocked.resetAllStatsLocked

    @GuardedBy("this")
    public void setBatteryStateLocked(final int status, final int health, final int plugType,
            final int level, /* not final */ int temp, final int volt, final int chargeUAh,
            final int chargeFullUAh) {
            if (onBattery != mOnBattery) {
                ...
                setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level, chargeUAh);


    @GuardedBy("this")
    protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
            final boolean onBattery, final int oldStatus, final int level, final int chargeUAh) {
            
        if (onBattery) {
            // We will reset our status if we are unplugging after the
            // battery was last full, or the level is at 100, or
            // we have gone through a significant charge (from a very low
            // level to a now very high level).
            boolean reset = false;
            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                    || level >= 90
                    || (mDischargeCurrentLevel < 20 && level >= 80)
                    || (getHighDischargeAmountSinceCharge() >= 200
                            && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) {
                ...
                resetAllStatsLocked();

猜你喜欢

转载自blog.csdn.net/su749520/article/details/85202294