Merge changes I8d835c08,I4620691a

* changes:
  Add dump commmand for Wifi Wake.
  Connect WakeupLock and WakeupController to the config store data.
diff --git a/service/java/com/android/server/wifi/WakeupConfigStoreData.java b/service/java/com/android/server/wifi/WakeupConfigStoreData.java
index f839ac8..5775117 100644
--- a/service/java/com/android/server/wifi/WakeupConfigStoreData.java
+++ b/service/java/com/android/server/wifi/WakeupConfigStoreData.java
@@ -45,8 +45,10 @@
 
     /**
      * Interface defining a data source for the store data.
+     *
+     * @param <T> Type of data source
      */
-    interface DataSource<T> {
+    public interface DataSource<T> {
         /**
          * Returns the data from the data source.
          */
diff --git a/service/java/com/android/server/wifi/WakeupController.java b/service/java/com/android/server/wifi/WakeupController.java
index a3c095a..8787bfd 100644
--- a/service/java/com/android/server/wifi/WakeupController.java
+++ b/service/java/com/android/server/wifi/WakeupController.java
@@ -24,6 +24,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * WakeupController is responsible managing Auto Wifi.
  *
@@ -38,16 +41,26 @@
     private final Handler mHandler;
     private final FrameworkFacade mFrameworkFacade;
     private final ContentObserver mContentObserver;
+    private final WakeupLock mWakeupLock;
+    private final WifiConfigManager mWifiConfigManager;
 
     /** Whether this feature is enabled in Settings. */
     private boolean mWifiWakeupEnabled;
 
+    /** Whether the WakeupController is currently active. */
+    private boolean mIsActive = false;
+
     public WakeupController(
             Context context,
             Looper looper,
+            WakeupLock wakeupLock,
+            WifiConfigManager wifiConfigManager,
+            WifiConfigStore wifiConfigStore,
             FrameworkFacade frameworkFacade) {
         mContext = context;
         mHandler = new Handler(looper);
+        mWakeupLock = wakeupLock;
+        mWifiConfigManager = wifiConfigManager;
         mFrameworkFacade = frameworkFacade;
         mContentObserver = new ContentObserver(mHandler) {
             @Override
@@ -59,6 +72,19 @@
         mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
                 Settings.Global.WIFI_WAKEUP_ENABLED), true, mContentObserver);
         mContentObserver.onChange(false /* selfChange */);
+
+        // registering the store data here has the effect of reading the persisted value of the
+        // data sources after system boot finishes
+        WakeupConfigStoreData wakeupConfigStoreData =
+                new WakeupConfigStoreData(new IsActiveDataSource(), mWakeupLock.getDataSource());
+        wifiConfigStore.registerStoreData(wakeupConfigStoreData);
+    }
+
+    private void setActive(boolean isActive) {
+        if (mIsActive != isActive) {
+            mIsActive = isActive;
+            mWifiConfigManager.saveToStore(false /* forceWrite */);
+        }
     }
 
     /**
@@ -71,4 +97,26 @@
     boolean isEnabled() {
         return mWifiWakeupEnabled;
     }
+
+    /** 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("mIsActive: " + mIsActive);
+        mWakeupLock.dump(fd, pw, args);
+    }
+
+    private class IsActiveDataSource implements WakeupConfigStoreData.DataSource<Boolean> {
+
+        @Override
+        public Boolean getData() {
+            return mIsActive;
+        }
+
+        @Override
+        public void setData(Boolean data) {
+            mIsActive = data;
+        }
+    }
 }
diff --git a/service/java/com/android/server/wifi/WakeupLock.java b/service/java/com/android/server/wifi/WakeupLock.java
index 73cda91..1fcd9f8 100644
--- a/service/java/com/android/server/wifi/WakeupLock.java
+++ b/service/java/com/android/server/wifi/WakeupLock.java
@@ -17,12 +17,16 @@
 package com.android.server.wifi;
 
 import android.util.ArrayMap;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * A lock to determine whether Auto Wifi can re-enable Wifi.
@@ -31,18 +35,24 @@
  */
 public class WakeupLock {
 
+    private static final String TAG = WakeupLock.class.getSimpleName();
+
     @VisibleForTesting
     static final int CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 3;
 
-    private Map<ScanResultMatchInfo, Integer> mLockedNetworks = new ArrayMap<>();
 
-    // TODO(easchwar) read initial value of mLockedNetworks from file
-    public WakeupLock() {
+    private final WifiConfigManager mWifiConfigManager;
+    private final Map<ScanResultMatchInfo, Integer> mLockedNetworks = new ArrayMap<>();
+
+    public WakeupLock(WifiConfigManager wifiConfigManager) {
+        mWifiConfigManager = wifiConfigManager;
     }
 
     /**
      * Initializes the WakeupLock with the given {@link ScanResultMatchInfo} list.
      *
+     * <p>This saves the wakeup lock to the store.
+     *
      * @param scanResultList list of ScanResultMatchInfos to start the lock with
      */
     public void initialize(Collection<ScanResultMatchInfo> scanResultList) {
@@ -50,17 +60,23 @@
         for (ScanResultMatchInfo scanResultMatchInfo : scanResultList) {
             mLockedNetworks.put(scanResultMatchInfo, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
         }
+
+        Log.d(TAG, "Lock initialized. Number of networks: " + mLockedNetworks.size());
+
+        mWifiConfigManager.saveToStore(false /* forceWrite */);
     }
 
     /**
      * Updates the lock with the given {@link ScanResultMatchInfo} list.
      *
      * <p>If a network in the lock is not present in the list, reduce the number of scans
-     * required to evict by one. Remove any entries in the list with 0 scans required to evict.
+     * required to evict by one. Remove any entries in the list with 0 scans required to evict. If
+     * any entries in the lock are removed, the store is updated.
      *
      * @param scanResultList list of present ScanResultMatchInfos to update the lock with
      */
     public void update(Collection<ScanResultMatchInfo> scanResultList) {
+        boolean hasChanged = false;
         Iterator<Map.Entry<ScanResultMatchInfo, Integer>> it =
                 mLockedNetworks.entrySet().iterator();
         while (it.hasNext()) {
@@ -76,9 +92,13 @@
             entry.setValue(entry.getValue() - 1);
             if (entry.getValue() <= 0) {
                 it.remove();
+                hasChanged = true;
             }
         }
-        // TODO(easchwar) write the updated list to file
+
+        if (hasChanged) {
+            mWifiConfigManager.saveToStore(false /* forceWrite */);
+        }
     }
 
     /**
@@ -87,4 +107,36 @@
     public boolean isEmpty() {
         return mLockedNetworks.isEmpty();
     }
+
+    /** Returns the data source for the WakeupLock config store data. */
+    public WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> getDataSource() {
+        return new WakeupLockDataSource();
+    }
+
+    /** Dumps wakeup lock contents. */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("WakeupLock: ");
+        pw.println("Locked networks: " + mLockedNetworks.size());
+        for (Map.Entry<ScanResultMatchInfo, Integer> entry : mLockedNetworks.entrySet()) {
+            pw.println(entry.getKey() + ", scans to evict: " + entry.getValue());
+        }
+    }
+
+    private class WakeupLockDataSource
+            implements WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> {
+
+        @Override
+        public Set<ScanResultMatchInfo> getData() {
+            return mLockedNetworks.keySet();
+        }
+
+        @Override
+        public void setData(Set<ScanResultMatchInfo> data) {
+            mLockedNetworks.clear();
+            for (ScanResultMatchInfo network : data) {
+                mLockedNetworks.put(network, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
+            }
+
+        }
+    }
 }
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 11fb682..dc48163 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -230,7 +230,8 @@
                 new OpenNetworkRecommender(),
                 new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade));
         mWakeupController = new WakeupController(mContext,
-                mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade);
+                mWifiStateMachineHandlerThread.getLooper(), new WakeupLock(mWifiConfigManager),
+                mWifiConfigManager, mWifiConfigStore, mFrameworkFacade);
         mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
         mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
                 mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 910e90d..1521bb9 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -2281,6 +2281,7 @@
         } else {
             pw.println("mWifiConnectivityManager is not initialized");
         }
+        mWifiInjector.getWakeupController().dump(fd, pw, args);
     }
 
     public void handleUserSwitch(int userId) {
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
index 742c520..5e45570 100644
--- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
@@ -18,6 +18,8 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -29,12 +31,18 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+
 /**
  * Unit tests for {@link WakeupController}.
  */
 public class WakeupControllerTest {
 
     @Mock private Context mContext;
+    @Mock private WakeupLock mWakeupLock;
+    @Mock private WifiConfigManager mWifiConfigManager;
+    @Mock private WifiConfigStore mWifiConfigStore;
     @Mock private FrameworkFacade mFrameworkFacade;
 
     private TestLooper mLooper;
@@ -47,6 +55,11 @@
         mLooper = new TestLooper();
     }
 
+    private WakeupController newWakeupController() {
+        return new WakeupController(mContext, mLooper.getLooper(), mWakeupLock, mWifiConfigManager,
+                mWifiConfigStore, mFrameworkFacade);
+    }
+
     /**
      * Verify WakeupController is enabled when the settings toggle is true.
      */
@@ -54,8 +67,7 @@
     public void verifyEnabledWhenToggledOn() {
         when(mFrameworkFacade.getIntegerSetting(mContext,
                 Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(1);
-        mWakeupController = new WakeupController(mContext, mLooper.getLooper(),
-                mFrameworkFacade);
+        mWakeupController = newWakeupController();
 
         assertTrue(mWakeupController.isEnabled());
     }
@@ -67,9 +79,30 @@
     public void verifyDisabledWhenToggledOff() {
         when(mFrameworkFacade.getIntegerSetting(mContext,
                 Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(0);
-        mWakeupController = new WakeupController(mContext, mLooper.getLooper(),
-                mFrameworkFacade);
+        mWakeupController = newWakeupController();
 
         assertFalse(mWakeupController.isEnabled());
     }
+
+    /**
+     * Verify WakeupController registers its store data with the WifiConfigStore on construction.
+     */
+    @Test
+    public void registersWakeupConfigStoreData() {
+        mWakeupController = newWakeupController();
+        verify(mWifiConfigStore).registerStoreData(any(WakeupConfigStoreData.class));
+    }
+
+    /**
+     * Verify that dump calls also dump the state of the WakeupLock.
+     */
+    @Test
+    public void dumpIncludesWakeupLock() {
+        mWakeupController = newWakeupController();
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        PrintWriter writer = new PrintWriter(stream);
+        mWakeupController.dump(null, writer, null);
+
+        verify(mWakeupLock).dump(null, writer, null);
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
index bad9e3a..7144ecf 100644
--- a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
@@ -18,9 +18,13 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -35,6 +39,8 @@
     private static final String SSID_1 = "ssid1";
     private static final String SSID_2 = "ssid2";
 
+    @Mock private WifiConfigManager mWifiConfigManager;
+
     private ScanResultMatchInfo mNetwork1;
     private ScanResultMatchInfo mNetwork2;
     private WakeupLock mWakeupLock;
@@ -44,6 +50,8 @@
      */
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
         mNetwork1 = new ScanResultMatchInfo();
         mNetwork1.networkSsid = SSID_1;
         mNetwork1.networkType = ScanResultMatchInfo.NETWORK_TYPE_OPEN;
@@ -52,7 +60,7 @@
         mNetwork2.networkSsid = SSID_2;
         mNetwork2.networkType = ScanResultMatchInfo.NETWORK_TYPE_EAP;
 
-        mWakeupLock = new WakeupLock();
+        mWakeupLock = new WakeupLock(mWifiConfigManager);
     }
 
     /**
@@ -69,6 +77,18 @@
     }
 
     /**
+     * Updates the lock enough times to evict any networks not passed in.
+     *
+     * <p>It calls update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} times with
+     * the given network list. It does not make any assertions about the state of the lock.
+     */
+    private void updateEnoughTimesToEvictWithoutAsserts(Collection<ScanResultMatchInfo> networks) {
+        for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) {
+            mWakeupLock.update(networks);
+        }
+    }
+
+    /**
      * Verify that the WakeupLock is not empty immediately after being initialized with networks.
      */
     @Test
@@ -161,4 +181,34 @@
         updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2));
         assertTrue(mWakeupLock.isEmpty());
     }
+
+    /**
+     * Verify that initializing the lock persists the SSID list to the config store.
+     */
+    @Test
+    public void initializeShouldSaveSsidsToStore() {
+        mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+        verify(mWifiConfigManager).saveToStore(eq(false));
+    }
+
+    /**
+     * Verify that update saves to store if the lock changes.
+     */
+    @Test
+    public void updateShouldOnlySaveIfLockChanges() {
+        mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+        updateEnoughTimesToEvictWithoutAsserts(Collections.emptyList());
+
+        // need exactly 2 invocations: 1 for initialize, 1 for successful update
+        verify(mWifiConfigManager, times(2)).saveToStore(eq(false));
+    }
+
+    /**
+     * Verify that update does not save to store if the lock does not change.
+     */
+    @Test
+    public void updateShouldNotSaveIfLockDoesNotChange() {
+        mWakeupLock.update(Collections.singletonList(mNetwork1));
+        verify(mWifiConfigManager, never()).saveToStore(anyBoolean());
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 80536aa..e6972ea 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -376,6 +376,7 @@
     @Mock IProvisioningCallback mProvisioningCallback;
     @Mock HandlerThread mWifiServiceHandlerThread;
     @Mock WifiPermissionsWrapper mWifiPermissionsWrapper;
+    @Mock WakeupController mWakeupController;
 
     public WifiStateMachineTest() throws Exception {
     }
@@ -422,6 +423,7 @@
         when(mWifiServiceHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
         when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(mWifiServiceHandlerThread);
         when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
+        when(mWifiInjector.getWakeupController()).thenReturn(mWakeupController);
 
         when(mWifiNative.setupForClientMode(WIFI_IFACE_NAME))
                 .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mClientInterface));
@@ -2829,4 +2831,15 @@
         currentConfig.networkId = lastSelectedNetworkId - 1;
         assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
     }
+
+    /**
+     * Verify that WSM dump includes WakeupController.
+     */
+    @Test
+    public void testDumpShouldDumpWakeupController() {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        PrintWriter writer = new PrintWriter(stream);
+        mWsm.dump(null, writer, null);
+        verify(mWakeupController).dump(null, writer, null);
+    }
 }