Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f866742 authored by Mike Ma's avatar Mike Ma Committed by android-build-merger
Browse files

Merge "Record Bluetooth Cumulative Stats Properly" into pi-dev

am: 827a06d4

Change-Id: I9086e4560f676693329a42ac71194ff1e64e8222
parents 1daf6456 827a06d4
Loading
Loading
Loading
Loading
+100 −75
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ public class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
    // Current on-disk Parcel version
    private static final int VERSION = 176 + (USE_OLD_HISTORY ? 1000 : 0);
    private static final int VERSION = 177 + (USE_OLD_HISTORY ? 1000 : 0);
    // Maximum number of items we will record in the history.
    private static final int MAX_HISTORY_ITEMS;
@@ -1551,27 +1551,31 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    @VisibleForTesting
    public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
        final TimeBase mTimeBase;
        long mCount;
        long mLoadedCount;
        long mUnpluggedCount;
        public long mCount;
        public long mCurrentCount;
        public long mLoadedCount;
        public long mUnpluggedCount;
        LongSamplingCounter(TimeBase timeBase, Parcel in) {
        public LongSamplingCounter(TimeBase timeBase, Parcel in) {
            mTimeBase = timeBase;
            mCount = in.readLong();
            mCurrentCount = in.readLong();
            mLoadedCount = in.readLong();
            mUnpluggedCount = in.readLong();
            timeBase.add(this);
        }
        LongSamplingCounter(TimeBase timeBase) {
        public LongSamplingCounter(TimeBase timeBase) {
            mTimeBase = timeBase;
            timeBase.add(this);
        }
        public void writeToParcel(Parcel out) {
            out.writeLong(mCount);
            out.writeLong(mCurrentCount);
            out.writeLong(mLoadedCount);
            out.writeLong(mUnpluggedCount);
        }
@@ -1598,24 +1602,37 @@ public class BatteryStatsImpl extends BatteryStats {
        @Override
        public void logState(Printer pw, String prefix) {
            pw.println(prefix + "mCount=" + mCount
                    + " mCurrentCount=" + mCurrentCount
                    + " mLoadedCount=" + mLoadedCount
                    + " mUnpluggedCount=" + mUnpluggedCount);
        }
        void addCountLocked(long count) {
            addCountLocked(count, mTimeBase.isRunning());
        public void addCountLocked(long count) {
            update(mCurrentCount + count, mTimeBase.isRunning());
        }
        public void addCountLocked(long count, boolean isRunning) {
            update(mCurrentCount + count, isRunning);
        }
        public void update(long count) {
            update(count, mTimeBase.isRunning());
        }
        void addCountLocked(long count, boolean isRunning) {
        public void update(long count, boolean isRunning) {
            if (count < mCurrentCount) {
                mCurrentCount = 0;
            }
            if (isRunning) {
                mCount += count;
                mCount += count - mCurrentCount;
            }
            mCurrentCount = count;
        }
        /**
         * Clear state of this counter.
         */
        void reset(boolean detachIfReset) {
        public void reset(boolean detachIfReset) {
            mCount = 0;
            mLoadedCount = mUnpluggedCount = 0;
            if (detachIfReset) {
@@ -1623,18 +1640,16 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        void detach() {
        public void detach() {
            mTimeBase.remove(this);
        }
        void writeSummaryFromParcelLocked(Parcel out) {
        public void writeSummaryFromParcelLocked(Parcel out) {
            out.writeLong(mCount);
        }
        void readSummaryFromParcelLocked(Parcel in) {
            mLoadedCount = in.readLong();
            mCount = mLoadedCount;
            mUnpluggedCount = mLoadedCount;
        public void readSummaryFromParcelLocked(Parcel in) {
            mCount = mUnpluggedCount= mLoadedCount = in.readLong();
        }
    }
@@ -11603,10 +11618,6 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    // Cache last value for comparison.
    private BluetoothActivityEnergyInfo mLastBluetoothActivityEnergyInfo =
            new BluetoothActivityEnergyInfo(0, 0, 0, 0, 0, 0);
    /**
     * Add modem tx power to history
     * Device is said to be in high cellular transmit power when it has spent most of the transmit
@@ -11645,8 +11656,35 @@ public class BatteryStatsImpl extends BatteryStats {
        return;
    }
    private final class BluetoothActivityInfoCache {
        long idleTimeMs;
        long rxTimeMs;
        long txTimeMs;
        long energy;
        SparseLongArray uidRxBytes = new SparseLongArray();
        SparseLongArray uidTxBytes = new SparseLongArray();
        void set(BluetoothActivityEnergyInfo info) {
            idleTimeMs = info.getControllerIdleTimeMillis();
            rxTimeMs = info.getControllerRxTimeMillis();
            txTimeMs = info.getControllerTxTimeMillis();
            energy = info.getControllerEnergyUsed();
            if (info.getUidTraffic() != null) {
                for (UidTraffic traffic : info.getUidTraffic()) {
                    uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
                    uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
                }
            }
        }
    }
    private final BluetoothActivityInfoCache mLastBluetoothActivityInfo
            = new BluetoothActivityInfoCache();
    /**
     * Distribute Bluetooth energy info and network traffic to apps.
     *
     * @param info The energy information from the bluetooth controller.
     */
    public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
@@ -11661,12 +11699,13 @@ public class BatteryStatsImpl extends BatteryStats {
        mHasBluetoothReporting = true;
        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
        final long rxTimeMs = info.getControllerRxTimeMillis() -
                mLastBluetoothActivityEnergyInfo.getControllerRxTimeMillis();
        final long txTimeMs = info.getControllerTxTimeMillis() -
                mLastBluetoothActivityEnergyInfo.getControllerTxTimeMillis();
        final long idleTimeMs = info.getControllerIdleTimeMillis() -
                mLastBluetoothActivityEnergyInfo.getControllerIdleTimeMillis();
        final long rxTimeMs =
                info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs;
        final long txTimeMs =
                info.getControllerTxTimeMillis() - mLastBluetoothActivityInfo.txTimeMs;
        final long idleTimeMs =
                info.getControllerIdleTimeMillis() - mLastBluetoothActivityInfo.idleTimeMs;
        if (DEBUG_ENERGY) {
            Slog.d(TAG, "------ BEGIN BLE power blaming ------");
            Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
@@ -11738,8 +11777,8 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        if (DEBUG_ENERGY) {
            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs
                    + " TX=" + leftOverTxTimeMs);
            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs + " TX="
                    + leftOverTxTimeMs);
        }
        //
@@ -11750,70 +11789,56 @@ public class BatteryStatsImpl extends BatteryStats {
        long totalRxBytes = 0;
        final UidTraffic[] uidTraffic = info.getUidTraffic();
        final UidTraffic[] lastUidTraffic = mLastBluetoothActivityEnergyInfo.getUidTraffic();
        final ArrayList<UidTraffic> deltaTraffic = new ArrayList<>();
        int m = 0, n = 0;
        for (; m < uidTraffic.length && n < lastUidTraffic.length; m++) {
            final UidTraffic traffic = uidTraffic[m];
            final UidTraffic lastTraffic = lastUidTraffic[n];
            if (traffic.getUid() == lastTraffic.getUid()) {
                deltaTraffic.add(new UidTraffic(traffic.getUid(),
                        traffic.getRxBytes() - lastTraffic.getRxBytes(),
                        traffic.getTxBytes() - lastTraffic.getTxBytes()));
                n++;
            }
        }
        for (; m < uidTraffic.length; m ++) {
            deltaTraffic.add(uidTraffic[m]);
        }
        for (int i = 0, j = 0; i < deltaTraffic.size(); i++) {
            final UidTraffic traffic = deltaTraffic.get(i);
        final int numUids = uidTraffic != null ? uidTraffic.length : 0;
        for (int i = 0; i < numUids; i++) {
            final UidTraffic traffic = uidTraffic[i];
            final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(
                    traffic.getUid());
            final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(
                    traffic.getUid());
            // Add to the global counters.
            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
                    traffic.getRxBytes());
            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
                    traffic.getTxBytes());
            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(rxBytes);
            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(txBytes);
            // Add to the UID counters.
            final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, rxBytes, 0);
            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, txBytes, 0);
            // Calculate the total traffic.
            totalTxBytes += traffic.getTxBytes();
            totalRxBytes += traffic.getRxBytes();
            totalRxBytes += rxBytes;
            totalTxBytes += txBytes;
        }
        if ((totalTxBytes != 0 || totalRxBytes != 0) &&
                (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) {
            for (int i = 0; i < deltaTraffic.size(); i++) {
                final UidTraffic traffic = deltaTraffic.get(i);
                final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
        if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0
                || leftOverTxTimeMs != 0)) {
            for (int i = 0; i < numUids; i++) {
                final UidTraffic traffic = uidTraffic[i];
                final int uid = traffic.getUid();
                final long rxBytes =
                        traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid);
                final long txBytes =
                        traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(uid);
                final Uid u = getUidStatsLocked(mapUid(uid));
                final ControllerActivityCounterImpl counter =
                        u.getOrCreateBluetoothControllerActivityLocked();
                if (totalRxBytes > 0 && traffic.getRxBytes() > 0) {
                    final long timeRxMs = (leftOverRxTimeMs * traffic.getRxBytes()) / totalRxBytes;
                if (totalRxBytes > 0 && rxBytes > 0) {
                    final long timeRxMs = (leftOverRxTimeMs * rxBytes) / totalRxBytes;
                    if (DEBUG_ENERGY) {
                        Slog.d(TAG, "UID=" + traffic.getUid() + " rx_bytes=" + traffic.getRxBytes()
                                + " rx_time=" + timeRxMs);
                        Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs);
                    }
                    counter.getRxTimeCounter().addCountLocked(timeRxMs);
                    leftOverRxTimeMs -= timeRxMs;
                }
                if (totalTxBytes > 0 && traffic.getTxBytes() > 0) {
                    final long timeTxMs = (leftOverTxTimeMs * traffic.getTxBytes()) / totalTxBytes;
                if (totalTxBytes > 0 && txBytes > 0) {
                    final long timeTxMs = (leftOverTxTimeMs * txBytes) / totalTxBytes;
                    if (DEBUG_ENERGY) {
                        Slog.d(TAG, "UID=" + traffic.getUid() + " tx_bytes=" + traffic.getTxBytes()
                                + " tx_time=" + timeTxMs);
                        Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs);
                    }
                    counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
                    leftOverTxTimeMs -= timeTxMs;
                }
@@ -11830,10 +11855,10 @@ public class BatteryStatsImpl extends BatteryStats {
        if (opVolt != 0) {
            // We store the power drain as mAms.
            mBluetoothActivity.getPowerCounter().addCountLocked(
                    (long) ((info.getControllerEnergyUsed() -
                            mLastBluetoothActivityEnergyInfo.getControllerEnergyUsed() )/ opVolt));
                    (long) ((info.getControllerEnergyUsed() - mLastBluetoothActivityInfo.energy)
                            / opVolt));
        }
        mLastBluetoothActivityEnergyInfo = info;
        mLastBluetoothActivityInfo.set(info);
    }
    /**
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import org.junit.runners.Suite;
        KernelUidCpuActiveTimeReaderTest.class,
        KernelUidCpuClusterTimeReaderTest.class,
        KernelWakelockReaderTest.class,
        LongSamplingCounterTest.class,
        LongSamplingCounterArrayTest.class,
        PowerCalculatorTest.class,
        PowerProfileTest.class
+194 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 static android.os.BatteryStats.STATS_SINCE_CHARGED;

import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounter;
import static com.android.internal.os.BatteryStatsImpl.TimeBase;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

/**
 * Test class for {@link LongSamplingCounter}.
 *
 * To run the tests, use
 *
 * bit FrameworksCoreTests:com.android.internal.os.LongSamplingCounterTest
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class LongSamplingCounterTest {

    private static final long COUNT = 1111;
    private static final long CURRENT_COUNT = 5555;

    @Mock
    private TimeBase mTimeBase;
    private LongSamplingCounter mCounter;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mCounter = new LongSamplingCounter(mTimeBase);
        Mockito.reset(mTimeBase);
    }

    @Test
    public void testReadWriteParcel() {
        final Parcel parcel = Parcel.obtain();
        updateCounts(COUNT, CURRENT_COUNT);
        mCounter.writeToParcel(parcel);
        parcel.setDataPosition(0);

        // Now clear counterArray and verify values are read from parcel correctly.
        updateCounts(0, 0);

        mCounter = new LongSamplingCounter(mTimeBase, parcel);
        assertEquals(COUNT, mCounter.mCount);
        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
        parcel.recycle();
    }

    @Test
    public void testReadWriteSummaryParcel() {
        final Parcel parcel = Parcel.obtain();
        updateCounts(COUNT, CURRENT_COUNT);
        mCounter.writeSummaryFromParcelLocked(parcel);
        parcel.setDataPosition(0);

        // Now clear counterArray and verify values are read from parcel correctly.
        updateCounts(0, 0);

        mCounter.readSummaryFromParcelLocked(parcel);
        assertEquals(COUNT, mCounter.mCount);
        parcel.recycle();
    }

    @Test
    public void testOnTimeStarted() {
        updateCounts(COUNT, CURRENT_COUNT);
        mCounter.onTimeStarted(0, 0, 0);
        assertEquals(COUNT, mCounter.mCount);
        assertEquals(COUNT, mCounter.mUnpluggedCount);
    }

    @Test
    public void testOnTimeStopped() {
        updateCounts(COUNT, CURRENT_COUNT);
        mCounter.onTimeStopped(0, 0, 0);
        assertEquals(COUNT, mCounter.mCount);
    }

    @Test
    public void testAddCountLocked() {
        updateCounts(0, 0);
        assertEquals(0, mCounter.getCountLocked(0));
        when(mTimeBase.isRunning()).thenReturn(true);
        mCounter.addCountLocked(111);
        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(111, mCounter.mCurrentCount);
        mCounter.addCountLocked(222);
        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(333, mCounter.mCurrentCount);

        when(mTimeBase.isRunning()).thenReturn(false);
        mCounter.addCountLocked(456);
        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(789, mCounter.mCurrentCount);

        mCounter.addCountLocked(444, true);
        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(1233, mCounter.mCurrentCount);
        mCounter.addCountLocked(567, false);
        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(1800, mCounter.mCurrentCount);
    }

    @Test
    public void testUpdate() {
        updateCounts(0, 0);
        assertEquals(0, mCounter.getCountLocked(0));
        when(mTimeBase.isRunning()).thenReturn(true);
        mCounter.update(111);
        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(111, mCounter.mCurrentCount);
        mCounter.update(333);
        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(333, mCounter.mCurrentCount);

        when(mTimeBase.isRunning()).thenReturn(false);
        mCounter.update(789);
        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(789, mCounter.mCurrentCount);
        mCounter.update(100);
        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(100, mCounter.mCurrentCount);

        mCounter.update(544, true);
        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(544, mCounter.mCurrentCount);
        mCounter.update(1544, false);
        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
        assertEquals(1544, mCounter.mCurrentCount);
    }

    @Test
    public void testReset() {
        updateCounts(COUNT, CURRENT_COUNT);
        // Test with detachIfReset=false
        mCounter.reset(false /* detachIfReset */);
        assertEquals(0, mCounter.mCount);
        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
        verifyZeroInteractions(mTimeBase);

        updateCounts(COUNT, CURRENT_COUNT);
        // Test with detachIfReset=true
        mCounter.reset(true /* detachIfReset */);
        assertEquals(0, mCounter.mCount);
        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
        verify(mTimeBase).remove(mCounter);
        verifyNoMoreInteractions(mTimeBase);
    }

    @Test
    public void testDetach() {
        mCounter.detach();
        verify(mTimeBase).remove(mCounter);
        verifyNoMoreInteractions(mTimeBase);
    }

    private void updateCounts(long total, long current) {
        mCounter.mCount = total;
        mCounter.mCurrentCount = current;
    }
}
+25 −21
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
                mUseLatestStates = true;
            }

            try {
                synchronized (mWorkerLock) {
                    if (DEBUG) {
                        Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
@@ -308,6 +309,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
                    }
                    mStats.clearPendingRemovedUids();
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Error updating external stats: ", e);
            }
        }
    };

@@ -398,7 +402,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
                if (bluetoothInfo.isValid()) {
                    mStats.updateBluetoothStateLocked(bluetoothInfo);
                } else {
                    Slog.e(TAG, "bluetooth info is invalid: " + bluetoothInfo);
                    Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
                }
            }
        }
@@ -410,7 +414,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
            if (wifiInfo.isValid()) {
                mStats.updateWifiState(extractDeltaLocked(wifiInfo));
            } else {
                Slog.e(TAG, "wifi info is invalid: " + wifiInfo);
                Slog.w(TAG, "wifi info is invalid: " + wifiInfo);
            }
        }

@@ -418,7 +422,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
            if (modemInfo.isValid()) {
                mStats.updateMobileRadioState(modemInfo);
            } else {
                Slog.e(TAG, "modem info is invalid: " + modemInfo);
                Slog.w(TAG, "modem info is invalid: " + modemInfo);
            }
        }
    }