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

Commit 0d019146 authored by Santos Cordon's avatar Santos Cordon Committed by Android (Google) Code Review
Browse files

Merge "Improvements to wakelock log" into main

parents f7fcf9dc a050bbd6
Loading
Loading
Loading
Loading
+39 −13
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.power;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
@@ -36,8 +37,8 @@ import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.IWakeLockCallback;
import android.os.IScreenTimeoutPolicyListener;
import android.os.IWakeLockCallback;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -67,6 +68,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.input.InputManagerInternal;
@@ -147,7 +149,8 @@ public class Notifier {
    @Nullable private final StatusBarManagerInternal mStatusBarManagerInternal;
    private final TrustManager mTrustManager;
    private final Vibrator mVibrator;
    private final WakeLockLog mWakeLockLog;
    @NonNull private final WakeLockLog mPartialWakeLockLog;
    @NonNull private final WakeLockLog mFullWakeLockLog;
    private final DisplayManagerInternal mDisplayManagerInternal;

    private final NotifierHandler mHandler;
@@ -250,7 +253,9 @@ public class Notifier {
        mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
                com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);

        mWakeLockLog = mInjector.getWakeLockLog(context);
        mFullWakeLockLog = mInjector.getWakeLockLog(context);
        mPartialWakeLockLog = mInjector.getWakeLockLog(context);

        // Initialize interactive state for battery stats.
        try {
            mBatteryStats.noteInteractive(true);
@@ -324,7 +329,8 @@ public class Notifier {
                    // Ignore
                }
            }
            mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1);
            getWakeLockLog(flags).onWakeLockAcquired(tag,
                    getUidForWakeLockLog(ownerUid, workSource), flags, /*eventTime=*/ -1);
        }
        mWakefulnessSessionObserver.onWakeLockAcquired(flags);
    }
@@ -473,7 +479,8 @@ public class Notifier {
                    // Ignore
                }
            }
            mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1);
            getWakeLockLog(flags).onWakeLockReleased(tag,
                    getUidForWakeLockLog(ownerUid, workSource), /*eventTime=*/ -1);
        }
        mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason);
    }
@@ -960,11 +967,18 @@ public class Notifier {
     * @param pw The stream to print to.
     */
    public void dump(PrintWriter pw) {
        if (mWakeLockLog != null) {
            mWakeLockLog.dump(pw);
        }
        pw.println("Notifier:");

        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
        ipw.println("Partial Wakelock Log:");
        mPartialWakeLockLog.dump(ipw);

        ipw.println("");
        ipw.println("Full Wakelock Log:");
        mFullWakeLockLog.dump(ipw);

        mWakefulnessSessionObserver.dump(pw);
        ipw.println("");
        mWakefulnessSessionObserver.dump(ipw);
    }

    private void updatePendingBroadcastLocked() {
@@ -1232,7 +1246,9 @@ public class Notifier {
                // Do Nothing
            }
        }
        mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);

        getWakeLockLog(flags).onWakeLockAcquired(tag, getUidForWakeLockLog(ownerUid, workSource),
                flags, currentTime);
    }

    @SuppressLint("AndroidFrameworkRequiresPermission")
@@ -1253,7 +1269,8 @@ public class Notifier {
                // Ignore
            }
        }
        mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
        getWakeLockLog(flags).onWakeLockReleased(tag, getUidForWakeLockLog(ownerUid, workSource),
                currentTime);
    }

    @SuppressLint("AndroidFrameworkRequiresPermission")
@@ -1419,6 +1436,15 @@ public class Notifier {
        }
    }

    private @NonNull WakeLockLog getWakeLockLog(int flags) {
        return PowerManagerService.isScreenLock(flags) ? mFullWakeLockLog : mPartialWakeLockLog;
    }

    private int getUidForWakeLockLog(int ownerUid, WorkSource workSource) {
        int attributionUid = workSource != null ? workSource.getAttributionUid() : -1;
        return attributionUid != -1 ? attributionUid : ownerUid;
    }

    private final class NotifierHandler extends Handler {

        public NotifierHandler(Looper looper) {
@@ -1501,7 +1527,7 @@ public class Notifier {
        /**
         * Gets the WakeLockLog object
         */
        WakeLockLog getWakeLockLog(Context context);
        @NonNull WakeLockLog getWakeLockLog(Context context);

        /**
         * Gets the AppOpsManager system service
@@ -1522,7 +1548,7 @@ public class Notifier {
        }

        @Override
        public WakeLockLog getWakeLockLog(Context context) {
        public @NonNull WakeLockLog getWakeLockLog(Context context) {
            return new WakeLockLog(context);
        }

+9 −2
Original line number Diff line number Diff line
@@ -1723,9 +1723,16 @@ public final class PowerManagerService extends SystemService
        }
    }

    @SuppressWarnings("deprecation")
    private static boolean isScreenLock(final WakeLock wakeLock) {
        switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
        return isScreenLock(wakeLock.mFlags);
    }

    /**
     * Returns if a wakelock flag corresponds to a screen wake lock.
     */
    @SuppressWarnings("deprecation")
    public static boolean isScreenLock(int flags) {
        switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
            case PowerManager.FULL_WAKE_LOCK:
            case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
            case PowerManager.SCREEN_DIM_WAKE_LOCK:
+31 −11
Original line number Diff line number Diff line
@@ -81,11 +81,12 @@ final class WakeLockLog {
    private static final int TYPE_ACQUIRE = 0x1;
    private static final int TYPE_RELEASE = 0x2;
    private static final int MAX_LOG_ENTRY_BYTE_SIZE = 9;
    private static final int LOG_SIZE = 1024 * 10;
    private static final int LOG_SIZE = 1024 * 3;
    private static final int LOG_SIZE_MIN = MAX_LOG_ENTRY_BYTE_SIZE + 1;

    private static final int TAG_DATABASE_SIZE = 128;
    private static final int TAG_DATABASE_SIZE = 64;
    private static final int TAG_DATABASE_SIZE_MAX = 128;
    private static final int TAG_DATABASE_STARTING_SIZE = 16;

    private static final int LEVEL_SCREEN_TIMEOUT_OVERRIDE_WAKE_LOCK = 0;
    private static final int LEVEL_PARTIAL_WAKE_LOCK = 1;
@@ -182,7 +183,7 @@ final class WakeLockLog {
     * @param pw The {@code PrintWriter} to write to.
     */
    public void dump(PrintWriter pw) {
        dump(pw, false);
        dump(pw, /* includeTagDb= */ true);
    }

    @VisibleForTesting
@@ -1161,15 +1162,16 @@ final class WakeLockLog {
     */
    static class TagDatabase {
        private final int mInvalidIndex;
        private final TagData[] mArray;
        private final int mMaxArraySize;
        private TagData[] mArray;
        private Callback mCallback;

        TagDatabase(Injector injector) {
            int size = Math.min(injector.getTagDatabaseSize(), TAG_DATABASE_SIZE_MAX);

            // Largest possible index used as "INVALID", hence the (size - 1) sizing.
            mArray = new TagData[size - 1];
            mInvalidIndex = size - 1;
            // Largest possible index used as "INVALID", hence the (size - 1) sizing
            mMaxArraySize = Math.min(injector.getTagDatabaseSize(), TAG_DATABASE_SIZE_MAX - 1);
            int startingSize = Math.min(mMaxArraySize, injector.getTagDatabaseStartingSize());
            mArray = new TagData[startingSize];
            mInvalidIndex = mMaxArraySize;
        }

        @Override
@@ -1195,8 +1197,10 @@ final class WakeLockLog {
            sb.append(", entries: ").append(entries);
            sb.append(", Bytes used: ").append(byteEstimate);
            if (DEBUG) {
                sb.append(", Avg tag size: ").append(tagSize / tags);
                sb.append("\n    ").append(Arrays.toString(mArray));
                sb.append(", Avg tag size: ").append(tags == 0 ? 0 : (tagSize / tags));
                for (int i = 0; i < mArray.length; i++) {
                    sb.append("\n  [").append(i).append("] ").append(mArray[i]);
                }
            }
            return sb.toString();
        }
@@ -1284,6 +1288,18 @@ final class WakeLockLog {
                return null;
            }

            // We don't have a spot available, see if we can still increase the array size
            if (firstAvailable == -1) {
                if (mArray.length < mMaxArraySize) {
                    int oldSize = mArray.length;
                    int newSize = Math.min(oldSize * 2, mMaxArraySize);
                    TagData[] newArray = new TagData[newSize];
                    System.arraycopy(mArray, 0, newArray, 0, oldSize);
                    mArray = newArray;
                    firstAvailable = oldSize;
                }
            }

            // If we need to remove an index, report to listeners that we are removing an index.
            boolean useOldest = firstAvailable == -1;
            if (useOldest && mCallback != null) {
@@ -1402,6 +1418,10 @@ final class WakeLockLog {
            return TAG_DATABASE_SIZE;
        }

        public int getTagDatabaseStartingSize() {
            return TAG_DATABASE_STARTING_SIZE;
        }

        public int getLogSize() {
            return LOG_SIZE;
        }
+64 −5
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.annotation.NonNull;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.content.Context;
@@ -52,8 +53,8 @@ import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Handler;
import android.os.IBinder;
import android.os.IWakeLockCallback;
import android.os.IScreenTimeoutPolicyListener;
import android.os.IWakeLockCallback;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -724,6 +725,7 @@ public class NotifierTest {

        final int uid = 1234;
        final int pid = 5678;

        mNotifier.onWakeLockReleased(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
                "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
                exceptingCallback);
@@ -788,6 +790,55 @@ public class NotifierTest {
        verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
    }

    @Test
    public void test_wakeLockLogUsesWorkSource() {
        createNotifier();
        clearInvocations(mWakeLockLog);
        IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
            @Override public void onStateChanged(boolean enabled) throws RemoteException {
                throw new RemoteException("Just testing");
            }
        };

        final int uid = 1234;
        final int pid = 5678;
        WorkSource worksource = new WorkSource(1212);
        WorkSource worksource2 = new WorkSource(3131);

        mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
                "my.package.name", uid, pid, worksource, /* historyTag= */ null,
                exceptingCallback);
        verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", 1212,
                PowerManager.PARTIAL_WAKE_LOCK, -1);

        // Release the wakelock
        mNotifier.onWakeLockReleased(PowerManager.FULL_WAKE_LOCK, "wakelockTag2",
                "my.package.name", uid, pid, worksource2, /* historyTag= */ null,
                exceptingCallback);
        verify(mWakeLockLog).onWakeLockReleased("wakelockTag2", 3131, -1);

        // clear the handler
        mTestLooper.dispatchAll();

        // Now test with improveWakelockLatency flag true
        clearInvocations(mWakeLockLog);
        when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);

        mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
                "my.package.name", uid, pid, worksource, /* historyTag= */ null,
                exceptingCallback);
        mTestLooper.dispatchAll();
        verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", 1212,
                PowerManager.PARTIAL_WAKE_LOCK, 1);

        // Release the wakelock
        mNotifier.onWakeLockReleased(PowerManager.FULL_WAKE_LOCK, "wakelockTag2",
                "my.package.name", uid, pid, worksource2, /* historyTag= */ null,
                exceptingCallback);
        mTestLooper.dispatchAll();
        verify(mWakeLockLog).onWakeLockReleased("wakelockTag2", 3131, 1);
    }

    @Test
    public void
            test_notifierProcessesWorkSourceDeepCopy_OnWakelockChanging() throws RemoteException {
@@ -942,16 +993,24 @@ public class NotifierTest {
                PowerManager.DRAW_WAKE_LOCK);
        assertEquals(mNotifier.getWakelockMonitorTypeForLogging(PowerManager.PARTIAL_WAKE_LOCK),
                PowerManager.PARTIAL_WAKE_LOCK);
        assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
                        PowerManager.DOZE_WAKE_LOCK), -1);
    }

    @Test
    public void getWakelockMonitorTypeForLogging_evaluateProximityLevel() {
        // How proximity wakelock is evaluated depends on boolean configuration. Test both.
        when(mResourcesSpy.getBoolean(
                com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity))
                .thenReturn(false);
        createNotifier();
        assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
                        PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK),
                PowerManager.PARTIAL_WAKE_LOCK);
        assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
                        PowerManager.DOZE_WAKE_LOCK), -1);

        when(mResourcesSpy.getBoolean(
                com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity))
                .thenReturn(true);

        createNotifier();
        assertEquals(mNotifier.getWakelockMonitorTypeForLogging(
                        PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK), -1);
@@ -1238,7 +1297,7 @@ public class NotifierTest {
                    }

                    @Override
                    public WakeLockLog getWakeLockLog(Context context) {
                    public @NonNull WakeLockLog getWakeLockLog(Context context) {
                        return mWakeLockLog;
                    }

+68 −17
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.content.pm.PackageManager;
import android.os.PowerManager;
import android.os.Process;

import com.android.server.power.WakeLockLog.TagData;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -62,8 +64,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddTwoItems_withNoEventTimeSupplied() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
        log.onWakeLockAcquired("TagPartial", 101,
@@ -93,8 +96,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddTwoItems() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("TagPartial", 101,
@@ -117,8 +121,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddTwoItemsWithTimeReset() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
@@ -136,9 +141,10 @@ public class WakeLockLogTest {

    @Test
    public void testAddTwoItemsWithTagOverwrite() {
        final int tagDatabaseSize = 2;
        final int tagDatabaseSize = 1;
        final int tagStartingSize = 1;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
@@ -157,8 +163,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddFourItemsWithRingBufferOverflow() {
        final int tagDatabaseSize = 6;
        final int tagStartingSize = 2;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        // Wake lock 1 acquired - log size = 3
@@ -206,8 +213,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddItemWithBadTag() {
        final int tagDatabaseSize = 6;
        final int tagStartingSize = 2;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        // Bad tag means it wont get written
@@ -224,8 +232,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddItemWithReducedTagName() {
        final int tagDatabaseSize = 6;
        final int tagStartingSize = 2;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("*job*/com.one.two.3hree/.one..Last", 101,
@@ -242,9 +251,10 @@ public class WakeLockLogTest {

    @Test
    public void testAddAcquireAndReleaseWithRepeatTagName() {
        final int tagDatabaseSize = 6;
        final int tagDatabaseSize = 5;
        final int tagStartingSize = 5;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
@@ -263,8 +273,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddAcquireAndReleaseWithTimeTravel() {
        final int tagDatabaseSize = 6;
        final int tagStartingSize = 2;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK, 1100L);
@@ -283,8 +294,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddSystemWakelock() {
        final int tagDatabaseSize = 6;
        final int tagStartingSize = 2;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("TagPartial", 101,
@@ -302,8 +314,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddItemWithNoPackageName() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        when(mPackageManager.getPackagesForUid(101)).thenReturn(null);
@@ -322,8 +335,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddItemWithMultiplePackageNames() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        when(mPackageManager.getPackagesForUid(101)).thenReturn(
@@ -344,8 +358,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddItemsWithRepeatOwnerUid_UsesCache() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 20;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("TagPartial", 101,
@@ -375,8 +390,9 @@ public class WakeLockLogTest {
    @Test
    public void testAddItemsWithRepeatOwnerUid_SavedAcquisitions_UsesCache() {
        final int tagDatabaseSize = 128;
        final int tagStartingSize = 16;
        final int logSize = 10;
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, tagStartingSize, logSize));
        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);

        log.onWakeLockAcquired("TagPartial", 101,
@@ -420,6 +436,34 @@ public class WakeLockLogTest {
        verify(mPackageManager, times(1)).getPackagesForUid(101);
    }

    @Test
    public void testTagDatabaseGrowsBeyondStartingSize() {
        final int tagDatabaseSize = 3;
        final int tagStartingSize = 1;
        final int logSize = 10;
        // start with size = 1 and max size
        TestInjector injector = new TestInjector(tagDatabaseSize, tagStartingSize, logSize);
        WakeLockLog.TagDatabase td = new WakeLockLog.TagDatabase(injector);

        // Add one
        TagData data1 = td.findOrCreateTag("Tagname1", 1001, /* shouldCreate= */ true);
        assertEquals(0, td.getTagIndex(data1));

        // Check that it grows by adding 1 more
        TagData data2 = td.findOrCreateTag("Tagname2", 1001, /* shouldCreate= */ true);
        assertEquals(1, td.getTagIndex(data2));

        // Lets add the last one to fill up the DB to maxSize
        TagData data3 = td.findOrCreateTag("Tagname3", 1001, /* shouldCreate= */ true);
        assertEquals(2, td.getTagIndex(data3));

        // Adding a fourth one should replace the oldest one (Tagname1)
        TagData data4 = td.findOrCreateTag("Tagname4", 1001, /* shouldCreate= */ true);
        assertEquals(0, td.getTagIndex(data4));
        assertEquals(tagDatabaseSize, td.getTagIndex(data1));

    }

    private String dumpLog(WakeLockLog log, boolean includeTagDb) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
@@ -429,10 +473,12 @@ public class WakeLockLogTest {

    public static class TestInjector extends WakeLockLog.Injector {
        private final int mTagDatabaseSize;
        private final int mTagStartingSize;
        private final int mLogSize;

        public TestInjector(int tagDatabaseSize, int logSize) {
        public TestInjector(int tagDatabaseSize, int tagStartingSize, int logSize) {
            mTagDatabaseSize = tagDatabaseSize;
            mTagStartingSize = tagStartingSize;
            mLogSize = logSize;
        }

@@ -441,6 +487,11 @@ public class WakeLockLogTest {
            return mTagDatabaseSize;
        }

        @Override
        public int getTagDatabaseStartingSize() {
            return mTagStartingSize;
        }

        @Override
        public int getLogSize() {
            return mLogSize;