Merge "Use wificond to configure and start hostapd"
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 266234b..46ef28f 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -23,8 +23,8 @@
 import android.net.wifi.IApInterface;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.os.IBinder.DeathRecipient;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -34,6 +34,7 @@
 import com.android.internal.util.StateMachine;
 import com.android.server.wifi.util.ApConfigUtil;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -44,18 +45,17 @@
 public class SoftApManager {
     private static final String TAG = "SoftApManager";
 
-    private final INetworkManagementService mNmService;
     private final WifiNative mWifiNative;
     private final ArrayList<Integer> mAllowed2GChannels;
 
     private final String mCountryCode;
 
-    private final String mInterfaceName;
-
     private final SoftApStateMachine mStateMachine;
 
     private final Listener mListener;
 
+    private final IApInterface mApInterface;
+
     /**
      * Listener for soft AP state changes.
      */
@@ -70,20 +70,17 @@
 
     public SoftApManager(Looper looper,
                          WifiNative wifiNative,
-                         INetworkManagementService nmService,
                          String countryCode,
                          ArrayList<Integer> allowed2GChannels,
                          Listener listener,
                          IApInterface apInterface) {
-        mStateMachine = new SoftApStateMachine(looper, apInterface);
+        mStateMachine = new SoftApStateMachine(looper);
 
-        mNmService = nmService;
         mWifiNative = wifiNative;
         mCountryCode = countryCode;
         mAllowed2GChannels = allowed2GChannels;
         mListener = listener;
-
-        mInterfaceName = mWifiNative.getInterfaceName();
+        mApInterface = apInterface;
     }
 
     /**
@@ -118,8 +115,8 @@
      * @return integer result code
      */
     private int startSoftAp(WifiConfiguration config) {
-        if (config == null) {
-            Log.e(TAG, "Unable to start soft AP without configuration");
+        if (config == null || config.SSID == null) {
+            Log.e(TAG, "Unable to start soft AP without valid configuration");
             return ERROR_GENERIC;
         }
 
@@ -147,11 +144,30 @@
             }
         }
 
+        int encryptionType = getIApInterfaceEncryptionType(localConfig);
+
         try {
-            mNmService.startAccessPoint(localConfig, mInterfaceName);
-        } catch (Exception e) {
+            // Note that localConfig.SSID is intended to be either a hex string or "double quoted".
+            // However, it seems that whatever is handing us these configurations does not obey
+            // this convention.
+            boolean success = mApInterface.writeHostapdConfig(
+                    localConfig.SSID.getBytes(StandardCharsets.UTF_8), false,
+                    localConfig.apChannel, encryptionType,
+                    (localConfig.preSharedKey != null)
+                            ? localConfig.preSharedKey.getBytes(StandardCharsets.UTF_8)
+                            : new byte[0]);
+            if (!success) {
+                Log.e(TAG, "Failed to write hostapd configuration");
+                return ERROR_GENERIC;
+            }
+
+            success = mApInterface.startHostapd();
+            if (!success) {
+                Log.e(TAG, "Failed to start hostapd.");
+                return ERROR_GENERIC;
+            }
+        } catch (RemoteException e) {
             Log.e(TAG, "Exception in starting soft AP: " + e);
-            return ERROR_GENERIC;
         }
 
         Log.d(TAG, "Soft AP is started");
@@ -159,13 +175,34 @@
         return SUCCESS;
     }
 
+    private static int getIApInterfaceEncryptionType(WifiConfiguration localConfig) {
+        int encryptionType;
+        switch (localConfig.getAuthType()) {
+            case KeyMgmt.NONE:
+                encryptionType = IApInterface.ENCRYPTION_TYPE_NONE;
+                break;
+            case KeyMgmt.WPA_PSK:
+                encryptionType = IApInterface.ENCRYPTION_TYPE_WPA;
+                break;
+            case KeyMgmt.WPA2_PSK:
+                encryptionType = IApInterface.ENCRYPTION_TYPE_WPA2;
+                break;
+            default:
+                // We really shouldn't default to None, but this was how NetworkManagementService
+                // used to do this.
+                encryptionType = IApInterface.ENCRYPTION_TYPE_NONE;
+                break;
+        }
+        return encryptionType;
+    }
+
     /**
      * Teardown soft AP.
      */
     private void stopSoftAp() {
         try {
-            mNmService.stopAccessPoint(mInterfaceName);
-        } catch (Exception e) {
+            mApInterface.stopHostapd();
+        } catch (RemoteException e) {
             Log.e(TAG, "Exception in stopping soft AP: " + e);
             return;
         }
@@ -178,8 +215,6 @@
         public static final int CMD_STOP = 1;
         public static final int CMD_AP_INTERFACE_BINDER_DEATH = 2;
 
-        private final IApInterface mApInterface;
-
         private final State mIdleState = new IdleState();
         private final State mStartedState = new StartedState();
 
@@ -193,9 +228,8 @@
         }
 
 
-        SoftApStateMachine(Looper looper, IApInterface apInterface) {
+        SoftApStateMachine(Looper looper) {
             super(TAG, looper);
-            mApInterface = apInterface;
 
             addState(mIdleState);
             addState(mStartedState);
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index cc117da..c354407 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -232,7 +232,7 @@
             SoftApManager.Listener listener, IApInterface apInterface) {
         return new SoftApManager(
                 mWifiServiceHandlerThread.getLooper(),
-                wifiNative, nmService, countryCode,
+                wifiNative, countryCode,
                 allowed2GChannels, listener, apInterface);
     }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index 5919156..2cf2398 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.wifi;
 
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.inOrder;
@@ -30,7 +31,6 @@
 import android.net.wifi.WifiManager;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
-import android.os.INetworkManagementService;
 import android.os.test.TestLooper;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -51,20 +51,19 @@
 
     private static final String TAG = "SoftApManagerTest";
 
-    private static final String TEST_INTERFACE_NAME = "TestInterface";
+    private static final String TEST_SSID = "TestSSID";
     private static final String TEST_COUNTRY_CODE = "TestCountry";
     private static final Integer[] ALLOWED_2G_CHANNELS = {1, 2, 3, 4};
 
     private final ArrayList<Integer> mAllowed2GChannels =
-            new ArrayList<Integer>(Arrays.asList(ALLOWED_2G_CHANNELS));
+            new ArrayList<>(Arrays.asList(ALLOWED_2G_CHANNELS));
 
     TestLooper mLooper;
     @Mock WifiNative mWifiNative;
-    @Mock INetworkManagementService mNmService;
     @Mock SoftApManager.Listener mListener;
     @Mock InterfaceConfiguration mInterfaceConfiguration;
-    @Mock IApInterface mApInterface;
     @Mock IBinder mApInterfaceBinder;
+    @Mock IApInterface mApInterface;
     final ArgumentCaptor<DeathRecipient> mDeathListenerCaptor =
             ArgumentCaptor.forClass(DeathRecipient.class);
 
@@ -76,14 +75,14 @@
         MockitoAnnotations.initMocks(this);
         mLooper = new TestLooper();
 
-        when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
-        when(mNmService.getInterfaceConfig(TEST_INTERFACE_NAME))
-                .thenReturn(mInterfaceConfiguration);
         when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
+        when(mApInterface.startHostapd()).thenReturn(true);
+        when(mApInterface.stopHostapd()).thenReturn(true);
+        when(mApInterface.writeHostapdConfig(
+                any(), anyBoolean(), anyInt(), anyInt(), any())).thenReturn(true);
 
         mSoftApManager = new SoftApManager(mLooper.getLooper(),
                                            mWifiNative,
-                                           mNmService,
                                            TEST_COUNTRY_CODE,
                                            mAllowed2GChannels,
                                            mListener,
@@ -124,7 +123,7 @@
         mSoftApManager.stop();
         mLooper.dispatchAll();
 
-        verify(mNmService).stopAccessPoint(TEST_INTERFACE_NAME);
+        verify(mApInterface).stopHostapd();
         order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0);
         order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
     }
@@ -143,7 +142,7 @@
 
     /** Starts soft AP and verifies that it is enabled successfully. */
     protected void startSoftApAndVerifyEnabled() throws Exception {
-        InOrder order = inOrder(mListener, mApInterfaceBinder);
+        InOrder order = inOrder(mListener, mApInterfaceBinder, mApInterface);
 
         /**
          *  Only test the default configuration. Testing for different configurations
@@ -151,15 +150,17 @@
          */
         WifiConfiguration config = new WifiConfiguration();
         config.apBand = WifiConfiguration.AP_BAND_2GHZ;
+        config.SSID = TEST_SSID;
         when(mWifiNative.isHalStarted()).thenReturn(false);
         when(mWifiNative.setCountryCodeHal(TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)))
                 .thenReturn(true);
         mSoftApManager.start(config);
         mLooper.dispatchAll();
-        verify(mNmService).startAccessPoint(
-                any(WifiConfiguration.class), eq(TEST_INTERFACE_NAME));
         order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0);
         order.verify(mApInterfaceBinder).linkToDeath(mDeathListenerCaptor.capture(), eq(0));
+        order.verify(mApInterface).writeHostapdConfig(
+                any(), anyBoolean(), anyInt(), anyInt(), any());
+        order.verify(mApInterface).startHostapd();
         order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
     }