Merge "Allow connecting with no requests if we're already connected." into oc-mr1-dev
diff --git a/libwifi_system/hostapd_manager.cpp b/libwifi_system/hostapd_manager.cpp
index 68184e9..658eecd 100644
--- a/libwifi_system/hostapd_manager.cpp
+++ b/libwifi_system/hostapd_manager.cpp
@@ -34,6 +34,7 @@
 
 using android::base::ParseInt;
 using android::base::ReadFileToString;
+using android::base::RemoveFileIfExists;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 using std::string;
@@ -103,6 +104,9 @@
 }
 
 bool HostapdManager::WriteHostapdConfig(const string& config) {
+  // Remove hostapd.conf because its file owner might be system
+  // in previous OS and chmod fails in that case.
+  RemoveFileIfExists(kHostapdConfigFilePath);
   if (!WriteStringToFile(config, kHostapdConfigFilePath,
                          S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
                          AID_WIFI, AID_WIFI)) {
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 06b53be..02f8302 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -2572,10 +2572,12 @@
      * @param userId The identifier of the user that stopped.
      */
     public void handleUserStop(int userId) {
+        if (mVerboseLoggingEnabled) {
+            Log.v(TAG, "Handling user stop for " + userId);
+        }
         if (userId == mCurrentUserId && mUserManager.isUserUnlockingOrUnlocked(mCurrentUserId)) {
             saveToStore(true);
-            clearInternalData();
-            mCurrentUserId = UserHandle.USER_SYSTEM;
+            clearInternalUserData(mCurrentUserId);
         }
     }
 
@@ -2587,6 +2589,7 @@
      *  - List of deleted ephemeral networks.
      */
     private void clearInternalData() {
+        localLog("clearInternalData: Clearing all internal data");
         mConfiguredNetworks.clear();
         mDeletedEphemeralSSIDs.clear();
         mScanDetailCaches.clear();
@@ -2605,12 +2608,16 @@
      * removed from memory.
      */
     private Set<Integer> clearInternalUserData(int userId) {
+        localLog("clearInternalUserData: Clearing user internal data for " + userId);
         Set<Integer> removedNetworkIds = new HashSet<>();
         // Remove any private networks of the old user before switching the userId.
         for (WifiConfiguration config : getInternalConfiguredNetworks()) {
             if (!config.shared && WifiConfigurationUtil.doesUidBelongToAnyProfile(
                     config.creatorUid, mUserManager.getProfiles(userId))) {
                 removedNetworkIds.add(config.networkId);
+                localLog("clearInternalUserData: removed config."
+                        + " netId=" + config.networkId
+                        + " configKey=" + config.configKey());
                 mConfiguredNetworks.remove(config.networkId);
             }
         }
diff --git a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
index 12a0bde..ed25e0f 100644
--- a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@@ -422,11 +422,22 @@
                 mPendingSingleScanEventHandler = null;
             }
 
-            if ((newScanSettings.backgroundScanActive || newScanSettings.singleScanActive)
-                    && !allFreqs.isEmpty()) {
-                pauseHwPnoScan();
-                Set<Integer> freqs = allFreqs.getScanFreqs();
-                boolean success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
+            if (newScanSettings.backgroundScanActive || newScanSettings.singleScanActive) {
+                boolean success = false;
+                Set<Integer> freqs;
+                if (!allFreqs.isEmpty()) {
+                    pauseHwPnoScan();
+                    freqs = allFreqs.getScanFreqs();
+                    success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
+                    if (!success) {
+                        Log.e(TAG, "Failed to start scan, freqs=" + freqs);
+                    }
+                } else {
+                    // There is a scan request but no available channels could be scanned for.
+                    // We regard it as a scan failure in this case.
+                    Log.e(TAG, "Failed to start scan because there is "
+                            + "no available channel to scan for");
+                }
                 if (success) {
                     // TODO handle scan timeout
                     if (DBG) {
@@ -439,7 +450,6 @@
                             mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
                             TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
                 } else {
-                    Log.e(TAG, "Failed to start scan, freqs=" + freqs);
                     // indicate scan failure async
                     mEventHandler.post(new Runnable() {
                             public void run() {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 7ce5362..0fa6600 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -2406,7 +2406,7 @@
     }
 
     /**
-     * Verifies that the foreground user stop using {@link WifiConfigManager#handleUserStop(int)}
+     * Verifies that the user stop handling using {@link WifiConfigManager#handleUserStop(int)}
      * and ensures that the store is written only when the foreground user is stopped.
      */
     @Test
@@ -2429,6 +2429,49 @@
     }
 
     /**
+     * Verifies that the user stop handling using {@link WifiConfigManager#handleUserStop(int)}
+     * and ensures that the shared data is not lost when the foreground user is stopped.
+     */
+    @Test
+    public void testHandleUserStopDoesNotClearSharedData() throws Exception {
+        int user1 = TEST_DEFAULT_USER;
+
+        //
+        // Setup the database for the user before initiating stop.
+        //
+        int appId = 674;
+        // Create 2 networks. 1 for user1, and 1 shared.
+        final WifiConfiguration user1Network = WifiConfigurationTestUtil.createPskNetwork();
+        user1Network.shared = false;
+        user1Network.creatorUid = UserHandle.getUid(user1, appId);
+        final WifiConfiguration sharedNetwork = WifiConfigurationTestUtil.createPskNetwork();
+
+        // Set up the store data that is loaded initially.
+        List<WifiConfiguration> sharedNetworks = new ArrayList<WifiConfiguration>() {
+            {
+                add(sharedNetwork);
+            }
+        };
+        List<WifiConfiguration> user1Networks = new ArrayList<WifiConfiguration>() {
+            {
+                add(user1Network);
+            }
+        };
+        setupStoreDataForRead(sharedNetworks, user1Networks, new HashSet<String>());
+        assertTrue(mWifiConfigManager.loadFromStore());
+        verify(mWifiConfigStore).read();
+
+        // Ensure that we have 2 networks in the database before the stop.
+        assertEquals(2, mWifiConfigManager.getConfiguredNetworks().size());
+
+        mWifiConfigManager.handleUserStop(user1);
+
+        // Ensure that we only have 1 shared network in the database after the stop.
+        assertEquals(1, mWifiConfigManager.getConfiguredNetworks().size());
+        assertEquals(sharedNetwork.SSID, mWifiConfigManager.getConfiguredNetworks().get(0).SSID);
+    }
+
+    /**
      * Verifies the foreground user unlock via {@link WifiConfigManager#handleUserUnlock(int)}
      * results in a store read after bootup.
      */
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
index ed7c582..d337cf1 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
@@ -32,6 +32,7 @@
 import com.android.server.wifi.ScanResults;
 import com.android.server.wifi.WifiMonitor;
 import com.android.server.wifi.WifiNative;
+import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -56,6 +57,39 @@
                 mLooper.getLooper(), mClock);
     }
 
+    /**
+     * Test that WificondScannerImpl will not issue a scan and report scan failure
+     * when there is no channel to scan for.
+     */
+    @Test
+    public void singleScanNotIssuedIfNoAvailableChannels() {
+        // Use mocked ChannelHelper and ChannelCollection to simulate the scenario
+        // that no channel is available for this request.
+        ChannelHelper channelHelper = mock(ChannelHelper.class);
+        ChannelCollection channelCollection = mock(ChannelCollection.class);
+        when(channelHelper.createChannelCollection()).thenReturn(channelCollection);
+        when(channelCollection.isEmpty()).thenReturn(true);
+
+        mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
+                channelHelper, mLooper.getLooper(), mClock);
+
+        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
+                .withBasePeriod(10000) // ms
+                .withMaxApPerScan(10)
+                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
+                        WifiScanner.WIFI_BAND_5_GHZ)
+                .build();
+        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
+        mScanner.startSingleScan(settings, eventHandler);
+
+        mLooper.dispatchAll();
+
+        // No scan is issued to WifiNative.
+        verify(mWifiNative, never()).scan(any(), any(Set.class));
+        // A scan failed event must be reported.
+        verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
+    }
+
     @Test
     public void backgroundScanSuccessSingleBucket() {
         WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()