diff options
author | Eric Schwarzenbach <easchwar@google.com> | 2018-02-06 11:28:50 -0800 |
---|---|---|
committer | Eric Schwarzenbach <easchwar@google.com> | 2018-03-21 15:31:40 -0700 |
commit | 12d31e7fea8e5c17dddc0ab433c26c31a3bf2550 (patch) | |
tree | c0b45c623a27af03fa6a08b04bbd8b356af66e88 | |
parent | 563e1b048d0edd4a1ea95c555951f31b16b77f50 (diff) |
Add metrics for Wifi Wake
Test: runtest, manual
Bug: 72762459
Change-Id: I0bb64c9a6bff0fde8c1203de4445698247bb781a
6 files changed, 632 insertions, 10 deletions
diff --git a/service/java/com/android/server/wifi/WakeupController.java b/service/java/com/android/server/wifi/WakeupController.java index 4adee42c5..6fe51570e 100644 --- a/service/java/com/android/server/wifi/WakeupController.java +++ b/service/java/com/android/server/wifi/WakeupController.java @@ -61,6 +61,7 @@ public class WakeupController { private final WifiConfigManager mWifiConfigManager; private final WifiInjector mWifiInjector; private final WakeupConfigStoreData mWakeupConfigStoreData; + private final WifiWakeMetrics mWifiWakeMetrics; private final WifiScanner.ScanListener mScanListener = new WifiScanner.ScanListener() { @Override @@ -97,6 +98,9 @@ public class WakeupController { /** Whether the WakeupController is currently active. */ private boolean mIsActive = false; + /** The number of scans that have been handled by the controller since last {@link #reset()}. */ + private int mNumScansHandled = 0; + public WakeupController( Context context, Looper looper, @@ -105,6 +109,7 @@ public class WakeupController { WakeupOnboarding wakeupOnboarding, WifiConfigManager wifiConfigManager, WifiConfigStore wifiConfigStore, + WifiWakeMetrics wifiWakeMetrics, WifiInjector wifiInjector, FrameworkFacade frameworkFacade) { mContext = context; @@ -113,6 +118,7 @@ public class WakeupController { mWakeupEvaluator = wakeupEvaluator; mWakeupOnboarding = wakeupOnboarding; mWifiConfigManager = wifiConfigManager; + mWifiWakeMetrics = wifiWakeMetrics; mFrameworkFacade = frameworkFacade; mWifiInjector = wifiInjector; mContentObserver = new ContentObserver(mHandler) { @@ -156,6 +162,7 @@ public class WakeupController { // If already active, we don't want to re-initialize the lock, so return early. if (mIsActive) { + // TODO record metric for calls to start() when already active return; } setActive(true); @@ -163,7 +170,10 @@ public class WakeupController { // ensure feature is enabled and store data has been read before performing work if (isEnabled()) { mWakeupOnboarding.maybeShowNotification(); - mWakeupLock.initialize(getMostRecentSavedScanResults()); + + Set<ScanResultMatchInfo> mostRecentSavedScanResults = getMostRecentSavedScanResults(); + mWifiWakeMetrics.recordStartEvent(mostRecentSavedScanResults.size()); + mWakeupLock.initialize(mostRecentSavedScanResults); } } @@ -182,6 +192,8 @@ public class WakeupController { /** Resets the WakeupController, setting {@link #mIsActive} to false. */ public void reset() { Log.d(TAG, "reset()"); + mWifiWakeMetrics.recordResetEvent(mNumScansHandled); + mNumScansHandled = 0; setActive(false); } @@ -214,7 +226,6 @@ public class WakeupController { goodSavedNetworks.add(ScanResultMatchInfo.fromWifiConfiguration(config)); } - Log.d(TAG, "getGoodSavedNetworks: " + goodSavedNetworks.size()); return goodSavedNetworks; } @@ -240,6 +251,9 @@ public class WakeupController { return; } + // only count scan as handled if isEnabled + mNumScansHandled++; + // need to show notification here in case user enables Wifi Wake when Wifi is off mWakeupOnboarding.maybeShowNotification(); if (!mWakeupOnboarding.isOnboarded()) { @@ -260,6 +274,7 @@ public class WakeupController { } Log.d(TAG, "WakeupLock emptied"); + mWifiWakeMetrics.recordUnlockEvent(mNumScansHandled); } ScanResult network = @@ -288,6 +303,7 @@ public class WakeupController { // TODO(b/72180295): ensure that there is no race condition with WifiServiceImpl here if (mWifiInjector.getWifiSettingsStore().handleWifiToggled(true /* wifiEnabled */)) { mWifiInjector.getWifiController().sendMessage(CMD_WIFI_TOGGLED); + mWifiWakeMetrics.recordWakeupEvent(mNumScansHandled); } } @@ -305,9 +321,13 @@ public class WakeupController { /** Dumps wakeup controller state. */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Dump of WakeupController"); - pw.println("mWifiWakeupEnabled: " + mWifiWakeupEnabled); pw.println("USE_PLATFORM_WIFI_WAKE: " + USE_PLATFORM_WIFI_WAKE); + pw.println("mWifiWakeupEnabled: " + mWifiWakeupEnabled); + pw.println("isOnboarded: " + mWakeupOnboarding.isOnboarded()); + pw.println("configStore hasBeenRead: " + mWakeupConfigStoreData.hasBeenRead()); pw.println("mIsActive: " + mIsActive); + pw.println("mNumScansHandled: " + mNumScansHandled); + mWakeupLock.dump(fd, pw, args); } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 28e36169b..eb4cb496f 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -266,7 +266,7 @@ public class WifiInjector { mWakeupController = new WakeupController(mContext, mWifiStateMachineHandlerThread.getLooper(), new WakeupLock(mWifiConfigManager), WakeupEvaluator.fromContext(mContext), wakeupOnboarding, mWifiConfigManager, - mWifiConfigStore, this, mFrameworkFacade); + mWifiConfigStore, mWifiMetrics.getWakeupMetrics(), this, mFrameworkFacade); mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService()); mWifiController = new WifiController(mContext, mWifiStateMachine, wifiStateMachineLooper, mSettingsStore, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade, diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 992182686..f076f8f62 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -190,6 +190,9 @@ public class WifiMetrics { /** Wifi power metrics*/ private WifiPowerMetrics mWifiPowerMetrics = new WifiPowerMetrics(); + /** Wifi Wake metrics */ + private final WifiWakeMetrics mWifiWakeMetrics = new WifiWakeMetrics(); + class RouterFingerPrint { private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto; RouterFingerPrint() { @@ -1877,6 +1880,7 @@ public class WifiMetrics { + mWpsMetrics.numWpsCancellation); mWifiPowerMetrics.dump(pw); + mWifiWakeMetrics.dump(pw); } } } @@ -2163,6 +2167,7 @@ public class WifiMetrics { mWifiLogProto.wpsMetrics = mWpsMetrics; mWifiLogProto.wifiPowerStats = mWifiPowerMetrics.buildProto(); + mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto(); } } @@ -2226,6 +2231,7 @@ public class WifiMetrics { mSoftApEventListTethered.clear(); mSoftApEventListLocalOnly.clear(); mWpsMetrics.clear(); + mWifiWakeMetrics.clear(); } } @@ -2410,6 +2416,10 @@ public class WifiMetrics { return mWifiAwareMetrics; } + public WifiWakeMetrics getWakeupMetrics() { + return mWifiWakeMetrics; + } + // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask // and attach it to the next event which is generated. private int mSupplicantStateChangeBitmask = 0; diff --git a/service/java/com/android/server/wifi/WifiWakeMetrics.java b/service/java/com/android/server/wifi/WifiWakeMetrics.java new file mode 100644 index 000000000..fba72369f --- /dev/null +++ b/service/java/com/android/server/wifi/WifiWakeMetrics.java @@ -0,0 +1,294 @@ +/* + * 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.server.wifi; + +import android.annotation.Nullable; +import android.os.SystemClock; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.wifi.nano.WifiMetricsProto.WifiWakeStats; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +/** + * Holds WifiWake metrics and converts them to a protobuf included in WifiLog. + */ +public class WifiWakeMetrics { + + /** Maximum number of sessions to store in WifiWakeStats proto. */ + @VisibleForTesting + static final int MAX_RECORDED_SESSIONS = 10; + + @GuardedBy("mLock") + private final List<Session> mSessions = new ArrayList<>(); + @GuardedBy("mLock") + private Session mCurrentSession; + + private boolean mIsInSession = false; + private int mTotalSessions = 0; + + private final Object mLock = new Object(); + + /** + * Records the beginning of a Wifi Wake session. + * + * <p>Starts the session. + * + * @param numNetworks The total number of networks stored in the WakeupLock at initialization. + */ + public void recordStartEvent(int numNetworks) { + synchronized (mLock) { + mCurrentSession = new Session(numNetworks, SystemClock.elapsedRealtime()); + mIsInSession = true; + } + } + + /** + * Records the unlock event of the current Wifi Wake session. + * + * <p>The unlock event occurs when the WakeupLock has all of its networks removed. This event + * will not be recorded if the start event recorded 0 locked networks. + * + * <p>Note: The start event must be recorded before this event, otherwise this call will be + * ignored. + * + * @param numScans The total number of elapsed scans since start. + */ + public void recordUnlockEvent(int numScans) { + synchronized (mLock) { + if (!mIsInSession) { + return; + } + mCurrentSession.recordUnlockEvent(numScans, SystemClock.elapsedRealtime()); + } + } + + /** + * Records the wakeup event of the current Wifi Wake session. + * + * <p>The wakeup event occurs when Wifi is re-enabled by the WakeupController. + * + * <p>Note: The start event must be recorded before this event, otherwise this call will be + * ignored. + * + * @param numScans The total number of elapsed scans since start. + */ + public void recordWakeupEvent(int numScans) { + synchronized (mLock) { + if (!mIsInSession) { + return; + } + mCurrentSession.recordWakeupEvent(numScans, SystemClock.elapsedRealtime()); + } + } + + /** + * Records the reset event of the current Wifi Wake session. + * + * <p>The reset event occurs when Wifi enters client mode. Stores the first + * {@link #MAX_RECORDED_SESSIONS} in the session list. + * + * <p>Note: The start event must be recorded before this event, otherwise this call will be + * ignored. This event ends the current session. + * + * @param numScans The total number of elapsed scans since start. + */ + public void recordResetEvent(int numScans) { + synchronized (mLock) { + if (!mIsInSession) { + return; + } + mCurrentSession.recordResetEvent(numScans, SystemClock.elapsedRealtime()); + + mTotalSessions++; + if (mSessions.size() < MAX_RECORDED_SESSIONS) { + mSessions.add(mCurrentSession); + } + mIsInSession = false; + } + } + + /** + * Returns the consolidated WifiWakeStats proto for WifiMetrics. + */ + public WifiWakeStats buildProto() { + WifiWakeStats proto = new WifiWakeStats(); + + proto.numSessions = mTotalSessions; + proto.sessions = new WifiWakeStats.Session[mSessions.size()]; + + for (int i = 0; i < mSessions.size(); i++) { + proto.sessions[i] = mSessions.get(i).buildProto(); + } + + return proto; + } + + /** + * Dump all WifiWake stats to console (pw) + * @param pw + */ + public void dump(PrintWriter pw) { + synchronized (mLock) { + pw.println("-------WifiWake metrics-------"); + pw.println("mTotalSessions: " + mTotalSessions); + pw.println("mIsInSession: " + mIsInSession); + pw.println("Stored Sessions: " + mSessions.size()); + for (Session session : mSessions) { + session.dump(pw); + } + if (mCurrentSession != null) { + pw.println("Current Session: "); + mCurrentSession.dump(pw); + } + pw.println("----end of WifiWake metrics----"); + } + } + + /** + * Clears WifiWakeMetrics. + * + * <p>Keeps the current WifiWake session. + */ + public void clear() { + mSessions.clear(); + mTotalSessions = 0; + } + + /** A single WifiWake session. */ + public static class Session { + + private final long mStartTimestamp; + private final int mNumNetworks; + + @VisibleForTesting + @Nullable + Event mUnlockEvent; + @VisibleForTesting + @Nullable + Event mWakeupEvent; + @VisibleForTesting + @Nullable + Event mResetEvent; + + /** Creates a new WifiWake session. */ + public Session(int numNetworks, long timestamp) { + mNumNetworks = numNetworks; + mStartTimestamp = timestamp; + } + + /** + * Records an unlock event. + * + * <p>Ignores subsequent calls. + * + * @param numScans Total number of scans at the time of this event. + * @param timestamp The timestamp of the event. + */ + public void recordUnlockEvent(int numScans, long timestamp) { + if (mUnlockEvent == null) { + mUnlockEvent = new Event(numScans, timestamp - mStartTimestamp); + } + } + + /** + * Records a wakeup event. + * + * <p>Ignores subsequent calls. + * + * @param numScans Total number of scans at the time of this event. + * @param timestamp The timestamp of the event. + */ + public void recordWakeupEvent(int numScans, long timestamp) { + if (mWakeupEvent == null) { + mWakeupEvent = new Event(numScans, timestamp - mStartTimestamp); + } + } + + /** + * Records a reset event. + * + * <p>Ignores subsequent calls. + * + * @param numScans Total number of scans at the time of this event. + * @param timestamp The timestamp of the event. + */ + public void recordResetEvent(int numScans, long timestamp) { + if (mResetEvent == null) { + mResetEvent = new Event(numScans, timestamp - mStartTimestamp); + } + } + + /** Returns the proto representation of this session. */ + public WifiWakeStats.Session buildProto() { + WifiWakeStats.Session sessionProto = new WifiWakeStats.Session(); + sessionProto.startTimeMillis = mStartTimestamp; + sessionProto.lockedNetworksAtStart = mNumNetworks; + + if (mUnlockEvent != null) { + sessionProto.unlockEvent = mUnlockEvent.buildProto(); + } + if (mWakeupEvent != null) { + sessionProto.wakeupEvent = mWakeupEvent.buildProto(); + } + if (mResetEvent != null) { + sessionProto.resetEvent = mResetEvent.buildProto(); + } + + return sessionProto; + } + + /** Dumps the current state of the session. */ + public void dump(PrintWriter pw) { + pw.println("WifiWakeMetrics.Session:"); + pw.println("mStartTimestamp: " + mStartTimestamp); + pw.println("mNumNetworks: " + mNumNetworks); + pw.println("mUnlockEvent: " + (mUnlockEvent == null ? "{}" : mUnlockEvent.toString())); + pw.println("mWakeupEvent: " + (mWakeupEvent == null ? "{}" : mWakeupEvent.toString())); + pw.println("mResetEvent: " + (mResetEvent == null ? "{}" : mResetEvent.toString())); + } + } + + /** An event in a WifiWake session. */ + public static class Event { + + /** Total number of scans that have elapsed prior to this event. */ + public final int mNumScans; + /** Total elapsed time in milliseconds at the instant of this event. */ + public final long mElapsedTime; + + public Event(int numScans, long elapsedTime) { + mNumScans = numScans; + mElapsedTime = elapsedTime; + } + + /** Returns the proto representation of this event. */ + public WifiWakeStats.Session.Event buildProto() { + WifiWakeStats.Session.Event eventProto = new WifiWakeStats.Session.Event(); + eventProto.elapsedScans = mNumScans; + eventProto.elapsedTimeMillis = mElapsedTime; + return eventProto; + } + + @Override + public String toString() { + return "{ mNumScans: " + mNumScans + ", elapsedTime: " + mElapsedTime + " }"; + } + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java index 79d1a1c29..f246c4884 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java @@ -19,8 +19,11 @@ package com.android.server.wifi; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -64,6 +67,8 @@ public class WakeupControllerTest { @Mock private WifiConfigManager mWifiConfigManager; @Mock private FrameworkFacade mFrameworkFacade; @Mock private WifiSettingsStore mWifiSettingsStore; + @Mock private WifiWakeMetrics mWifiWakeMetrics; + @Mock private WifiController mWifiController; private TestLooper mLooper; private WakeupController mWakeupController; @@ -78,6 +83,8 @@ public class WakeupControllerTest { when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner); when(mWifiInjector.getWifiSettingsStore()).thenReturn(mWifiSettingsStore); + when(mWifiInjector.getWifiController()).thenReturn(mWifiController); + when(mWifiSettingsStore.handleWifiToggled(anyBoolean())).thenReturn(true); mLooper = new TestLooper(); @@ -109,6 +116,7 @@ public class WakeupControllerTest { mWakeupOnboarding, mWifiConfigManager, mWifiConfigStore, + mWifiWakeMetrics, mWifiInjector, mFrameworkFacade); @@ -190,6 +198,7 @@ public class WakeupControllerTest { initializeWakeupController(true /* enabled */); mWakeupController.start(); verify(mWakeupLock).initialize(any()); + verify(mWifiWakeMetrics).recordStartEvent(anyInt()); } /** @@ -200,6 +209,7 @@ public class WakeupControllerTest { initializeWakeupController(false /* enabled */); mWakeupController.start(); verify(mWakeupLock, never()).initialize(any()); + verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt()); } /** @@ -208,14 +218,17 @@ public class WakeupControllerTest { @Test public void startDoesNotInitializeWakeupLockIfAlreadyActive() { initializeWakeupController(true /* enabled */); - InOrder inOrder = Mockito.inOrder(mWakeupLock); + InOrder lockInOrder = Mockito.inOrder(mWakeupLock); + InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics); mWakeupController.start(); - inOrder.verify(mWakeupLock).initialize(any()); + lockInOrder.verify(mWakeupLock).initialize(any()); + metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt()); mWakeupController.stop(); mWakeupController.start(); - inOrder.verify(mWakeupLock, never()).initialize(any()); + lockInOrder.verify(mWakeupLock, never()).initialize(any()); + metricsInOrder.verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt()); } /** @@ -248,15 +261,20 @@ public class WakeupControllerTest { @Test public void resetSetsActiveToFalse() { initializeWakeupController(true /* enabled */); - InOrder inOrder = Mockito.inOrder(mWakeupLock); + InOrder lockInOrder = Mockito.inOrder(mWakeupLock); + InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics); mWakeupController.start(); - inOrder.verify(mWakeupLock).initialize(any()); + lockInOrder.verify(mWakeupLock).initialize(any()); + metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt()); mWakeupController.stop(); mWakeupController.reset(); + metricsInOrder.verify(mWifiWakeMetrics).recordResetEvent(0 /* numScans */); + mWakeupController.start(); - inOrder.verify(mWakeupLock).initialize(any()); + lockInOrder.verify(mWakeupLock).initialize(any()); + metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt()); } /** @@ -290,6 +308,7 @@ public class WakeupControllerTest { initializeWakeupController(true /* enabled */); mWakeupController.start(); verify(mWakeupLock).initialize(eq(expectedMatchInfos)); + verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size()); } /** @@ -314,6 +333,30 @@ public class WakeupControllerTest { } /** + * Verify that WifiWakeMetrics logs the unlock event when the WakeupLock is emptied. + */ + @Test + public void recordMetricsWhenWakeupLockIsEmptied() { + initializeWakeupController(true /* enabled */); + mWakeupController.start(); + + // Simulates emptying the lock: first returns false then returns true + when(mWakeupLock.isEmpty()).thenReturn(false).thenReturn(true); + + ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = + ArgumentCaptor.forClass(WifiScanner.ScanListener.class); + + verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); + WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); + + // incoming scan results + scanListener.onResults(mTestScanDatas); + + verify(mWakeupLock, times(2)).isEmpty(); + verify(mWifiWakeMetrics).recordUnlockEvent(1 /* numScans */); + } + + /** * Verify that the controller searches for viable networks during onResults when WakeupLock is * empty. */ @@ -388,6 +431,7 @@ public class WakeupControllerTest { verify(mWakeupEvaluator).findViableNetwork(any(), any()); verify(mWifiSettingsStore).handleWifiToggled(true /* wifiEnabled */); + verify(mWifiWakeMetrics).recordWakeupEvent(1 /* numScans */); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WifiWakeMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiWakeMetricsTest.java new file mode 100644 index 000000000..37a658976 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/WifiWakeMetricsTest.java @@ -0,0 +1,254 @@ +/* + * Copyright 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.server.wifi; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; + +import com.android.server.wifi.nano.WifiMetricsProto.WifiWakeStats; + +import org.junit.Before; +import org.junit.Test; + + +public class WifiWakeMetricsTest { + + private WifiWakeMetrics mWifiWakeMetrics; + + @Before + public void setUp() { + mWifiWakeMetrics = new WifiWakeMetrics(); + } + + @Test + public void buildsEmptyProto() { + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 0); + assertEquals(wifiWakeStats.sessions.length, 0); + } + + @Test + public void buildsMultiSessionProto_fewerThanMax() { + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + mWifiWakeMetrics.recordStartEvent(1 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + mWifiWakeMetrics.recordStartEvent(2 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 3); + assertEquals(wifiWakeStats.sessions.length, 3); + } + + @Test + public void buildsMultiSessionProto_greaterThanMax() { + int numSessions = WifiWakeMetrics.MAX_RECORDED_SESSIONS + 1; + for (int i = 0; i < numSessions; i++) { + mWifiWakeMetrics.recordStartEvent(i); + mWifiWakeMetrics.recordResetEvent(i); + } + + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, numSessions); + assertEquals(wifiWakeStats.sessions.length, WifiWakeMetrics.MAX_RECORDED_SESSIONS); + + // ensure that the first (not last) MAX_RECORDED_SESSIONS are recorded + for (int i = 0; i < WifiWakeMetrics.MAX_RECORDED_SESSIONS; i++) { + WifiWakeStats.Session session = wifiWakeStats.sessions[i]; + assertNotNull(session); + assertEquals(session.lockedNetworksAtStart, i); + } + } + + @Test + public void buildProtoDoesNotIncludeCurrentSession() { + mWifiWakeMetrics.recordStartEvent(1 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + mWifiWakeMetrics.recordStartEvent(2 /* numNetworks */); + + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 1); + assertEquals(wifiWakeStats.sessions.length, 1); + assertEquals(wifiWakeStats.sessions[0].lockedNetworksAtStart, 1); + } + + @Test + public void ignoresEventsIfStartNotCalled() { + mWifiWakeMetrics.recordUnlockEvent(1 /* numScans */); + mWifiWakeMetrics.recordWakeupEvent(1 /* numScans */); + mWifiWakeMetrics.recordResetEvent(1 /* numScans */); + + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 0); + assertEquals(wifiWakeStats.sessions.length, 0); + } + + @Test + public void ignoresEventsAfterResetAndBeforeStartCalled() { + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordWakeupEvent(1 /* numScans */); + mWifiWakeMetrics.recordResetEvent(1 /* numScans */); + + mWifiWakeMetrics.recordWakeupEvent(10 /* numScans */); + + // verify only 1 session + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 1); + assertEquals(wifiWakeStats.sessions.length, 1); + + // verify it didn't overwrite session + WifiWakeStats.Session session = wifiWakeStats.sessions[0]; + assertNotNull(session.wakeupEvent); + assertEquals(session.wakeupEvent.elapsedScans, 1); + } + + @Test + public void clearRemovesSessions() { + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + // verify sessions + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 3); + assertEquals(wifiWakeStats.sessions.length, 3); + + mWifiWakeMetrics.clear(); + wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 0); + assertEquals(wifiWakeStats.sessions.length, 0); + } + + @Test + public void clearDoesNotInterruptCurrentSession() { + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + mWifiWakeMetrics.recordStartEvent(0 /* numNetworks */); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + mWifiWakeMetrics.recordStartEvent(1 /* numNetworks */); + mWifiWakeMetrics.clear(); + mWifiWakeMetrics.recordResetEvent(0 /* numScans */); + + // keeps the current session + WifiWakeStats wifiWakeStats = mWifiWakeMetrics.buildProto(); + assertNotNull(wifiWakeStats); + assertEquals(wifiWakeStats.numSessions, 1); + assertEquals(wifiWakeStats.sessions.length, 1); + } + + @Test + public void session_buildsEmptyProto() { + WifiWakeMetrics.Session session = + new WifiWakeMetrics.Session(1 /* numNetworks */, 1000 /* timestamp */); + + WifiWakeStats.Session sessionProto = session.buildProto(); + assertNotNull(sessionProto); + assertEquals(sessionProto.lockedNetworksAtStart, 1); + assertEquals(sessionProto.startTimeMillis, 1000); + assertNull(sessionProto.unlockEvent); + assertNull(sessionProto.wakeupEvent); + assertNull(sessionProto.resetEvent); + } + + @Test + public void session_recordsEvents() { + WifiWakeMetrics.Session session = + new WifiWakeMetrics.Session(1 /* numNetworks */, 1000 /* timestamp */); + + session.recordUnlockEvent(1 /* numScans */, 1100 /* timestamp */); + assertNotNull(session.mUnlockEvent); + assertEquals(session.mUnlockEvent.mNumScans, 1); + assertEquals(session.mUnlockEvent.mElapsedTime, 100); + + session.recordWakeupEvent(2 /* numScans */, 1200 /* timestamp */); + assertNotNull(session.mWakeupEvent); + assertEquals(session.mWakeupEvent.mNumScans, 2); + assertEquals(session.mWakeupEvent.mElapsedTime, 200); + + session.recordResetEvent(3 /* numScans */, 1300 /* timestamp */); + assertNotNull(session.mResetEvent); + assertEquals(session.mResetEvent.mNumScans, 3); + assertEquals(session.mResetEvent.mElapsedTime, 300); + } + + @Test + public void session_buildProto() { + WifiWakeMetrics.Session session = + new WifiWakeMetrics.Session(1 /* numNetworks */, 1000 /* timestamp */); + + session.recordUnlockEvent(1 /* numScans */, 1100 /* timestamp */); + session.recordWakeupEvent(2 /* numScans */, 1200 /* timestamp */); + session.recordResetEvent(3 /* numScans */, 1300 /* timestamp */); + + WifiWakeStats.Session sessionProto = session.buildProto(); + assertNotNull(sessionProto); + assertEquals(sessionProto.lockedNetworksAtStart, 1); + assertEquals(sessionProto.startTimeMillis, 1000); + + verifyEventProto(sessionProto.unlockEvent, 1, 100); + verifyEventProto(sessionProto.wakeupEvent, 2, 200); + verifyEventProto(sessionProto.resetEvent, 3, 300); + } + + @Test + public void session_ignoresRepeatedEvents() { + WifiWakeMetrics.Session session = + new WifiWakeMetrics.Session(1 /* numNetworks */, 1000 /* timestamp */); + + session.recordResetEvent(1 /* numScans */, 1100 /* timestamp */); + assertNotNull(session.mResetEvent); + assertEquals(session.mResetEvent.mNumScans, 1); + assertEquals(session.mResetEvent.mElapsedTime, 100); + + session.recordResetEvent(2 /* numScans */, 1200 /* timestamp */); + assertEquals(session.mResetEvent.mNumScans, 1); + assertEquals(session.mResetEvent.mElapsedTime, 100); + } + + @Test + public void event_buildsProto() { + WifiWakeMetrics.Event event = + new WifiWakeMetrics.Event(1 /* numScans */, 1000 /* elapsedTime */); + + verifyEventProto(event.buildProto(), 1, 1000); + } + + private void verifyEventProto(WifiWakeStats.Session.Event event, int scans, int elapsedTime) { + assertNotNull(event); + assertEquals(event.elapsedScans, scans); + assertEquals(event.elapsedTimeMillis, elapsedTime); + } +} |