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

Commit 154cc823 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Have BatteryStats track and report the running wakelocks." into nyc-mr1-dev

parents 5a3e33a8 adbee556
Loading
Loading
Loading
Loading
+79 −6
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.MutableBoolean;
import android.util.Pair;
import android.util.Printer;
@@ -47,6 +49,7 @@ import com.android.internal.os.BatteryStatsHelper;
 * @hide
 */
public abstract class BatteryStats implements Parcelable {
    private static final String TAG = "BatteryStats";

    private static final boolean LOCAL_LOGV = false;

@@ -175,8 +178,11 @@ public abstract class BatteryStats implements Parcelable {

    /**
     * Current version of checkin data format.
     *
     * New in version 19:
     *   - Wakelock data (wl) gets current and max times.
     */
    static final String CHECKIN_VERSION = "18";
    static final String CHECKIN_VERSION = "19";

    /**
     * Old version, we hit 9 and ran out of room, need to remove.
@@ -351,6 +357,32 @@ public abstract class BatteryStats implements Parcelable {
         */
        public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs);

        /**
         * Returns the max duration if it is being tracked.
         * Not all Timer subclasses track the max duration and the current duration.

         */
        public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
            return -1;
        }

        /**
         * Returns the current time the timer has been active, if it is being tracked.
         * Not all Timer subclasses track the max duration and the current duration.
         */
        public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
            return -1;
        }

        /**
         * Returns whether the timer is currently running.  Some types of timers
         * (e.g. BatchTimers) don't know whether the event is currently active,
         * and report false.
         */
        public boolean isRunningLocked() {
            return false;
        }

        /**
         * Temporary for debugging.
         */
@@ -2558,6 +2590,22 @@ public abstract class BatteryStats implements Parcelable {
                sb.append('(');
                sb.append(count);
                sb.append(" times)");
                final long maxDurationMs = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
                if (maxDurationMs >= 0) {
                    sb.append(" max=");
                    sb.append(maxDurationMs);
                }
                if (timer.isRunningLocked()) {
                    final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
                    if (currentMs >= 0) {
                        sb.append(" (running for ");
                        sb.append(currentMs);
                        sb.append("ms)");
                    } else {
                        sb.append(" (running)");
                    }
                }

                return ", ";
            }
        }
@@ -2565,6 +2613,7 @@ public abstract class BatteryStats implements Parcelable {
    }

    /**
     * Prints details about a timer, if its total time was greater than 0.
     *
     * @param pw a PrintWriter object to print to.
     * @param sb a StringBuilder object.
@@ -2573,24 +2622,40 @@ public abstract class BatteryStats implements Parcelable {
     * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
     * @param prefix a String to be prepended to each line of output.
     * @param type the name of the timer.
     * @return true if anything was printed.
     */
    private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer,
            long rawRealtime, int which, String prefix, String type) {
            long rawRealtimeUs, int which, String prefix, String type) {
        if (timer != null) {
            // Convert from microseconds to milliseconds with rounding
            final long totalTime = (timer.getTotalTimeLocked(
                    rawRealtime, which) + 500) / 1000;
            final long totalTimeMs = (timer.getTotalTimeLocked(
                    rawRealtimeUs, which) + 500) / 1000;
            final int count = timer.getCountLocked(which);
            if (totalTime != 0) {
            if (totalTimeMs != 0) {
                sb.setLength(0);
                sb.append(prefix);
                sb.append("    ");
                sb.append(type);
                sb.append(": ");
                formatTimeMs(sb, totalTime);
                formatTimeMs(sb, totalTimeMs);
                sb.append("realtime (");
                sb.append(count);
                sb.append(" times)");
                final long maxDurationMs = timer.getMaxDurationMsLocked(rawRealtimeUs/1000);
                if (maxDurationMs >= 0) {
                    sb.append(" max=");
                    sb.append(maxDurationMs);
                }
                if (timer.isRunningLocked()) {
                    final long currentMs = timer.getCurrentDurationMsLocked(rawRealtimeUs/1000);
                    if (currentMs >= 0) {
                        sb.append(" (running for ");
                        sb.append(currentMs);
                        sb.append("ms)");
                    } else {
                        sb.append(" (running)");
                    }
                }
                pw.println(sb.toString());
                return true;
            }
@@ -2613,15 +2678,23 @@ public abstract class BatteryStats implements Parcelable {
            long elapsedRealtimeUs, String name, int which, String linePrefix) {
        long totalTimeMicros = 0;
        int count = 0;
        long max = -1;
        long current = -1;
        if (timer != null) {
            totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
            count = timer.getCountLocked(which); 
            current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
            max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
        }
        sb.append(linePrefix);
        sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
        sb.append(',');
        sb.append(name != null ? name + "," : "");
        sb.append(count);
        sb.append(',');
        sb.append(current);
        sb.append(',');
        sb.append(max);
        return ",";
    }
    
+220 −18
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS'

    // Current on-disk Parcel version
    private static final int VERSION = 148 + (USE_OLD_HISTORY ? 1000 : 0);
    private static final int VERSION = 149 + (USE_OLD_HISTORY ? 1000 : 0);

    // Maximum number of items we will record in the history.
    private static final int MAX_HISTORY_ITEMS = 2000;
@@ -1566,6 +1566,186 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }


    /**
     * A StopwatchTimer that also tracks the total and max individual
     * time spent active according to the given timebase.  Whereas
     * StopwatchTimer apportions the time amongst all in the pool,
     * the total and max durations are not apportioned.
     */
    public static class DurationTimer extends StopwatchTimer {
        /**
         * The time (in ms) that the timer was last acquired or the time base
         * last (re-)started. Increasing the nesting depth does not reset this time.
         *
         * -1 if the timer is currently not running or the time base is not running.
         *
         * If written to a parcel, the start time is reset, as is mNesting in the base class
         * StopwatchTimer.
         */
        long mStartTimeMs = -1;

        /**
         * The longest time period (in ms) that the timer has been active.
         */
        long mMaxDurationMs;

        /**
         * The total time (in ms) that that the timer has been active since reset().
         */
        long mCurrentDurationMs;

        public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
                TimeBase timeBase, Parcel in) {
            super(clocks, uid, type, timerPool, timeBase, in);
            mMaxDurationMs = in.readLong();
        }

        public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
                TimeBase timeBase) {
            super(clocks, uid, type, timerPool, timeBase);
        }

        @Override
        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
            super.writeToParcel(out, elapsedRealtimeUs);
            out.writeLong(mMaxDurationMs);
        }

        /**
         * Write the summary to the parcel.
         *
         * Since the time base is probably meaningless after we come back, reading
         * from this will have the effect of stopping the timer. So here all we write
         * is the max duration.
         */
        @Override
        public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
            super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
            out.writeLong(mMaxDurationMs);
        }

        /**
         * Read the summary parcel.
         *
         * Has the side effect of stopping the timer.
         */
        @Override
        public void readSummaryFromParcelLocked(Parcel in) {
            super.readSummaryFromParcelLocked(in);
            mMaxDurationMs = in.readLong();
            mStartTimeMs = -1;
            mCurrentDurationMs = 0;
        }

        /**
         * The TimeBase time started (again).
         *
         * If the timer is also running, store the start time.
         */
        public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
            super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime);
            if (mNesting > 0) {
                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
            }
        }

        /**
         * The TimeBase stopped running.
         *
         * If the timer is running, add the duration into mCurrentDurationMs.
         */
        @Override
        public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
            super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtime);
            if (mNesting > 0) {
                mCurrentDurationMs += (elapsedRealtimeUs / 1000) - mStartTimeMs;
            }
            mStartTimeMs = -1;
        }

        @Override
        public void logState(Printer pw, String prefix) {
            super.logState(pw, prefix);
        }

        @Override
        public void startRunningLocked(long elapsedRealtimeMs) {
            super.startRunningLocked(elapsedRealtimeMs);
            if (mNesting == 1 && mTimeBase.isRunning()) {
                // Just started
                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
            }
        }

        /**
         * Decrements the mNesting ref-count on this timer.
         *
         * If it actually stopped (mNesting went to 0), then possibly update
         * mMaxDuration if the current duration was the longest ever.
         */
        @Override
        public void stopRunningLocked(long elapsedRealtimeMs) {
            super.stopRunningLocked(elapsedRealtimeMs);
            if (mNesting == 0) {
                final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
                if (durationMs > mMaxDurationMs) {
                    mMaxDurationMs = durationMs;
                }
                mStartTimeMs = -1;
                mCurrentDurationMs = 0;
            }
        }

        @Override
        public boolean reset(boolean detachIfReset) {
            boolean result = super.reset(detachIfReset);
            mMaxDurationMs = 0;
            mCurrentDurationMs = 0;
            if (mNesting > 0) {
                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
            } else {
                mStartTimeMs = -1;
            }
            return result;
        }

        /**
         * Returns the max duration that this timer has ever seen.
         *
         * Note that this time is NOT split between the timers in the timer group that
         * this timer is attached to.  It is the TOTAL time.
         */
        @Override
        public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
            if (mNesting > 0) {
                final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
                if (durationMs > mMaxDurationMs) {
                    return durationMs;
                }
            }
            return mMaxDurationMs;
        }

        /**
         * Returns the time since the timer was started.
         *
         * Note that this time is NOT split between the timers in the timer group that
         * this timer is attached to.  It is the TOTAL time.
         */
        @Override
        public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
            long durationMs = mCurrentDurationMs;
            if (mNesting > 0) {
                if (mTimeBase.isRunning()) {
                    durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
                            - mStartTimeMs;
                }
            }
            return durationMs;
        }
    }

    /**
     * State for keeping track of timing information.
     */
@@ -6535,7 +6715,7 @@ public class BatteryStatsImpl extends BatteryStats {
            /**
             * How long (in ms) this uid has been keeping the device partially awake.
             */
            StopwatchTimer mTimerPartial;
            DurationTimer mTimerPartial;

            /**
             * How long (in ms) this uid has been keeping the device fully awake.
@@ -6564,8 +6744,8 @@ public class BatteryStatsImpl extends BatteryStats {
             * @param in the Parcel to be read from.
             * return a new Timer, or null.
             */
            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
                    TimeBase timeBase, Parcel in) {
            private StopwatchTimer readStopwatchTimerFromParcel(int type,
                    ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) {
                if (in.readInt() == 0) {
                    return null;
                }
@@ -6573,6 +6753,22 @@ public class BatteryStatsImpl extends BatteryStats {
                return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
            }

            /**
             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
             * proper timer pool from the given BatteryStatsImpl object.
             *
             * @param in the Parcel to be read from.
             * return a new Timer, or null.
             */
            private DurationTimer readDurationTimerFromParcel(int type,
                    ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) {
                if (in.readInt() == 0) {
                    return null;
                }

                return new DurationTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
            }

            boolean reset() {
                boolean wlactive = false;
                if (mTimerFull != null) {
@@ -6609,11 +6805,14 @@ public class BatteryStatsImpl extends BatteryStats {
            }

            void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
                mTimerPartial = readDurationTimerFromParcel(WAKE_TYPE_PARTIAL,
                        mBsi.mPartialTimers, screenOffTimeBase, in);
                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
                mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
                mTimerFull = readStopwatchTimerFromParcel(WAKE_TYPE_FULL,
                        mBsi.mFullTimers, timeBase, in);
                mTimerWindow = readStopwatchTimerFromParcel(WAKE_TYPE_WINDOW,
                        mBsi.mWindowTimers, timeBase, in);
                mTimerDraw = readStopwatchTimerFromParcel(WAKE_TYPE_DRAW,
                        mBsi.mDrawTimers, timeBase, in);
            }

            void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
@@ -6635,40 +6834,43 @@ public class BatteryStatsImpl extends BatteryStats {
            }

            public StopwatchTimer getStopwatchTimer(int type) {
                StopwatchTimer t;
                switch (type) {
                    case WAKE_TYPE_PARTIAL:
                        t = mTimerPartial;
                    case WAKE_TYPE_PARTIAL: {
                        DurationTimer t = mTimerPartial;
                        if (t == null) {
                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
                            t = new DurationTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
                                    mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
                            mTimerPartial = t;
                        }
                        return t;
                    case WAKE_TYPE_FULL:
                        t = mTimerFull;
                    }
                    case WAKE_TYPE_FULL: {
                        StopwatchTimer t = mTimerFull;
                        if (t == null) {
                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
                                    mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
                            mTimerFull = t;
                        }
                        return t;
                    case WAKE_TYPE_WINDOW:
                        t = mTimerWindow;
                    }
                    case WAKE_TYPE_WINDOW: {
                        StopwatchTimer t = mTimerWindow;
                        if (t == null) {
                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
                                    mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
                            mTimerWindow = t;
                        }
                        return t;
                    case WAKE_TYPE_DRAW:
                        t = mTimerDraw;
                    }
                    case WAKE_TYPE_DRAW: {
                        StopwatchTimer t = mTimerDraw;
                        if (t == null) {
                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
                                    mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
                            mTimerDraw = t;
                        }
                        return t;
                    }
                    default:
                        throw new IllegalArgumentException("type=" + type);
                }
+151 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.BatteryStats;
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.util.Log;

import junit.framework.TestCase;

import org.mockito.Mockito;

/**
 * Test BatteryStatsImpl.DurationTimer.
 *
 * In these tests, unless otherwise commented, the time increments by
 * 2x + 100, to make the subtraction unlikely to alias to another time.
 */
public class BatteryStatsDurationTimerTest extends TestCase {

    @SmallTest
    public void testStartStop() throws Exception {
        final MockClocks clocks = new MockClocks();

        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());

        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, 
                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);

        // TimeBase running, timer not running: current and max are 0
        timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100*1000);
        assertFalse(timer.isRunningLocked());
        assertEquals(0, timer.getCurrentDurationMsLocked(300));
        assertEquals(0, timer.getMaxDurationMsLocked(301));

        // Start timer: current and max advance
        timer.startRunningLocked(700);
        assertTrue(timer.isRunningLocked());
        assertEquals(800, timer.getCurrentDurationMsLocked(1500));
        assertEquals(801, timer.getMaxDurationMsLocked(1501));

        // Stop timer: current resets to 0, max remains
        timer.stopRunningLocked(3100);
        assertFalse(timer.isRunningLocked());
        assertEquals(0, timer.getCurrentDurationMsLocked(6300));
        assertEquals(2400, timer.getMaxDurationMsLocked(6301));

        // Start time again, but check with a short time, and make sure max doesn't
        // increment.
        timer.startRunningLocked(12700);
        assertTrue(timer.isRunningLocked());
        assertEquals(100, timer.getCurrentDurationMsLocked(12800));
        assertEquals(2400, timer.getMaxDurationMsLocked(12801));

        // And stop it again, but with a short time, and make sure it doesn't increment.
        timer.stopRunningLocked(12900);
        assertFalse(timer.isRunningLocked());
        assertEquals(0, timer.getCurrentDurationMsLocked(13000));
        assertEquals(2400, timer.getMaxDurationMsLocked(13001));

        // Now start and check that the time doesn't increase if the two times are the same.
        timer.startRunningLocked(27000);
        assertTrue(timer.isRunningLocked());
        assertEquals(0, timer.getCurrentDurationMsLocked(27000));
        assertEquals(2400, timer.getMaxDurationMsLocked(27000));

        // Stop the TimeBase. The values should be frozen.
        timeBase.setRunning(false, /* uptimeUs */ 10, /* realtimeUs */ 55000*1000);
        assertTrue(timer.isRunningLocked());
        assertEquals(28100, timer.getCurrentDurationMsLocked(110100)); // Why 28100 and not 28000?
        assertEquals(28100, timer.getMaxDurationMsLocked(110101));

        // Start the TimeBase. The values should be the old value plus the delta
        // between when the timer restarted and the current time
        timeBase.setRunning(true, /* uptimeUs */ 10, /* realtimeUs */ 220100*1000);
        assertTrue(timer.isRunningLocked());
        assertEquals(28300, timer.getCurrentDurationMsLocked(220300)); // extra 100 from above??
        assertEquals(28301, timer.getMaxDurationMsLocked(220301));
    }

    @SmallTest
    public void testReset() throws Exception {
    }

    @SmallTest
    public void testParceling() throws Exception {
        final MockClocks clocks = new MockClocks();

        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());

        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, 
                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);

        // Start running on battery.
        clocks.realtime = 100;
        clocks.uptime = 10;
        timeBase.setRunning(true, clocks.uptimeMillis()*1000, clocks.elapsedRealtime()*1000);

        timer.startRunningLocked(300);

        // Check that it did start running
        assertEquals(400, timer.getMaxDurationMsLocked(700));
        assertEquals(401, timer.getCurrentDurationMsLocked(701));

        // Write summary
        final Parcel summaryParcel = Parcel.obtain();
        timer.writeSummaryFromParcelLocked(summaryParcel, 1500*1000);
        summaryParcel.setDataPosition(0);

        // Read summary
        final BatteryStatsImpl.DurationTimer summary = new BatteryStatsImpl.DurationTimer(clocks, 
                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
        summary.startRunningLocked(3100);
        summary.readSummaryFromParcelLocked(summaryParcel);
        // The new one shouldn't be running, and therefore 0 for current time
        assertFalse(summary.isRunningLocked());
        assertEquals(0, summary.getCurrentDurationMsLocked(6300));
        // The new one should have the max duration that we had when we wrote it
        assertEquals(1200, summary.getMaxDurationMsLocked(6301));

        // Write full
        final Parcel fullParcel = Parcel.obtain();
        timer.writeToParcel(fullParcel, 1500*1000);
        fullParcel.setDataPosition(0);
 
        // Read full - Should be the same as the summary as far as DurationTimer is concerned.
        final BatteryStatsImpl.DurationTimer full = new BatteryStatsImpl.DurationTimer(clocks, 
                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase, fullParcel);
        // The new one shouldn't be running, and therefore 0 for current time
        assertFalse(full.isRunningLocked());
        assertEquals(0, full.getCurrentDurationMsLocked(6300));
        // The new one should have the max duration that we had when we wrote it
        assertEquals(1200, full.getMaxDurationMsLocked(6301));
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({
        BatteryStatsDurationTimerTest.class,
        BatteryStatsSamplingTimerTest.class,
        BatteryStatsServTest.class,
        BatteryStatsTimeBaseTest.class,