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

Commit 9ab518ad authored by Irfan Sheriff's avatar Irfan Sheriff
Browse files

softAp framework changes

Remove AP persist settings
Add new netd interface
Handle errors
Handle AP config change
Bug: 2413908
Change-Id: I31a1221ef5479da8d4a2620f0f0ee0b62539bc69
parent 9c041bbd
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.os;

import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
import android.net.wifi.WifiConfiguration;

/**
 * @hide
@@ -166,7 +167,7 @@ interface INetworkManagementService
    /**
     * Start Wifi Access Point
     */
    void startAccessPoint();
    void startAccessPoint(in WifiConfiguration wifiConfig, String intf);

    /**
     * Stop Wifi Access Point
+21 −0
Original line number Diff line number Diff line
@@ -2501,6 +2501,27 @@ public final class Settings {
         */
        public static final String WIFI_AP_ON = "wifi_ap_on";

        /**
         * AP SSID
         *
         * @hide
         */
        public static final String WIFI_AP_SSID = "wifi_ap_ssid";

        /**
         * AP security
         *
         * @hide
         */
        public static final String WIFI_AP_SECURITY = "wifi_ap_security";

        /**
         * AP passphrase
         *
         * @hide
         */
        public static final String WIFI_AP_PASSWD = "wifi_ap_passwd";

        /**
         * The acceptable packet loss percentage (range 0 - 100) before trying
         * another AP on the same network.
+2 −0
Original line number Diff line number Diff line
@@ -2013,6 +2013,8 @@
        <item quantity="one">Open Wi-Fi network available</item>
        <item quantity="other">Open Wi-Fi networks available</item>
    </plurals>
    <!-- Do not translate. Default access point SSID used for tethering -->
    <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string>

    <!-- Name of the dialog that lets the user choose an accented character to insert -->
    <string name="select_character">Insert character</string>
+31 −4
Original line number Diff line number Diff line
@@ -26,10 +26,13 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.INetworkManagementService;
import android.os.Handler;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import java.util.ArrayList;
import java.util.StringTokenizer;
@@ -457,14 +460,38 @@ class NetworkManagementService extends INetworkManagementService.Stub {
        throw new IllegalStateException("Got an empty response");
    }

    public void startAccessPoint()
    public void startAccessPoint(WifiConfiguration wifiConfig, String intf)
             throws IllegalStateException {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
        mContext.enforceCallingOrSelfPermission(
            android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
        mConnector.doCommand(String.format("softap set"));
        mConnector.doCommand(String.format("softap start"));
        mConnector.doCommand(String.format("softap stop " + intf));
        mConnector.doCommand(String.format("softap fwreload " + intf + " AP"));
        mConnector.doCommand(String.format("softap start " + intf));
        if (wifiConfig == null) {
            mConnector.doCommand(String.format("softap set " + intf + " wl0.1"));
        } else {
            /**
             * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
             * argv1 - wlan interface
             * argv2 - softap interface
             * argv3 - SSID
             * argv4 - Security
             * argv5 - Key
             * argv6 - Channel
             * argv7 - Preamble
             * argv8 - Max SCB
             *
             * TODO: get a configurable softap interface from driver
             */
            String str = String.format("softap set " + intf + " wl0.1 %s %s %s", wifiConfig.SSID,
                                       wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
                                       "wpa2-psk" : "open",
                                       wifiConfig.preSharedKey);
            mConnector.doCommand(str);
        }
        mConnector.doCommand(String.format("softap startap"));
    }

    public void stopAccessPoint() throws IllegalStateException {
@@ -472,7 +499,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
        mContext.enforceCallingOrSelfPermission(
            android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
        mConnector.doCommand("softap stop");
        mConnector.doCommand("softap stopap");
    }

}
+96 −57
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.net.wifi.WifiStateTracker;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.ConnectivityManager;
import android.net.InterfaceConfiguration;
import android.net.NetworkStateTracker;
@@ -81,6 +82,7 @@ import java.net.UnknownHostException;
import com.android.internal.app.IBatteryStats;
import android.app.backup.IBackupManager;
import com.android.server.am.BatteryStatsService;
import com.android.internal.R;

/**
 * WifiService handles remote WiFi operation requests by implementing
@@ -105,6 +107,8 @@ public class WifiService extends IWifiManager.Stub {
    private boolean mDeviceIdle;
    private int mPluggedType;

    private enum DriverAction {DRIVER_UNLOAD, NO_DRIVER_UNLOAD};

    // true if the user enabled Wifi while in airplane mode
    private boolean mAirplaneModeOverwridden;

@@ -271,11 +275,9 @@ public class WifiService extends IWifiManager.Stub {
     */
    public void startWifi() {
        boolean wifiEnabled = getPersistedWifiEnabled();
        boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled();
        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                (wifiEnabled ? "enabled" : "disabled"));
        setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
        setWifiApEnabledBlocking(wifiAPEnabled, true, Process.myUid(), null);
    }

    private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
@@ -297,28 +299,22 @@ public class WifiService extends IWifiManager.Stub {
                    try {
                        ifcg = service.getInterfaceConfig(intf);
                        if (ifcg != null) {
                            /* IP/netmask: 169.254.2.1/255.255.255.0 */
                            ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1;
                            /* IP/netmask: 169.254.2.2/255.255.255.0 */
                            ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 2;
                            ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
                            ifcg.interfaceFlags = "up";

                            service.setInterfaceConfig(intf, ifcg);
                        }
                    } catch (Exception e) {
                        /**
                         * TODO: Add broadcast to indicate tether failed
                         */
                        Slog.e(TAG, "Error configuring interface " + intf + ", :" + e);
                        setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD);
                        return;
                    }

                    /**
                     * TODO: Add broadcast to indicate tether failed
                     */
                    if(mCm.tether(intf) == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
                        Slog.d(TAG, "Tethered "+intf);
                    } else {
                    if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
                        Slog.e(TAG, "Error tethering "+intf);
                        setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD);
                    }
                    break;
                }
@@ -434,7 +430,7 @@ public class WifiService extends IWifiManager.Stub {
        setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);

        if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
            setWifiApEnabledBlocking(false, true, Process.myUid(), null);
            setWifiApEnabledBlocking(false, Process.myUid(), null);
        }

        if (enable) {
@@ -581,21 +577,6 @@ public class WifiService extends IWifiManager.Stub {
        return mWifiStateTracker.reassociate();
    }

    private boolean getPersistedWifiApEnabled() {
        final ContentResolver cr = mContext.getContentResolver();
        try {
            return Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_ON) == 1;
        } catch (Settings.SettingNotFoundException e) {
            Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_ON, 0);
            return false;
        }
    }

    private void persistWifiApEnabled(boolean enabled) {
      final ContentResolver cr = mContext.getContentResolver();
      Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_ON, enabled ? 1 : 0);
    }

    /**
     * see {@link android.net.wifi.WifiManager#startAccessPoint(WifiConfiguration)}
     * @param wifiConfig SSID, security and channel details as
@@ -621,46 +602,101 @@ public class WifiService extends IWifiManager.Stub {
        return true;
    }

    public WifiConfiguration getWifiApConfiguration() {
        final ContentResolver cr = mContext.getContentResolver();
        WifiConfiguration wifiConfig = new WifiConfiguration();
        int authType;
        try {
            wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID);
            if (wifiConfig.SSID == null)
                return null;
            authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY);
            wifiConfig.allowedKeyManagement.set(authType);
            wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD);
            return wifiConfig;
        } catch (Settings.SettingNotFoundException e) {
            Slog.e(TAG,"AP settings not found, returning");
            return null;
        }
    }

    private void persistApConfiguration(WifiConfiguration wifiConfig) {
        final ContentResolver cr = mContext.getContentResolver();
        boolean isWpa;
        if (wifiConfig == null)
            return;
        Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID);
        isWpa = wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK);
        Settings.Secure.putInt(cr,
                               Settings.Secure.WIFI_AP_SECURITY,
                               isWpa ? KeyMgmt.WPA_PSK : KeyMgmt.NONE);
        if (isWpa)
            Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey);
    }

    /**
     * Enables/disables Wi-Fi AP synchronously. The driver is loaded
     * and soft access point configured as a single operation.
     * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
     * @param persist {@code true} if the setting should be persisted.
     * @param uid The UID of the process making the request.
     * @param config The WifiConfiguration for AP
     * @param wifiConfig The WifiConfiguration for AP
     * @return {@code true} if the operation succeeds (or if the existing state
     *         is the same as the requested state)
     */
    /**
     * TODO: persist needs to go away in WifiService
     * This will affect all persist related functions
     * for Access Point
     */
    private boolean setWifiApEnabledBlocking(boolean enable,
                        boolean persist, int uid, WifiConfiguration wifiConfig) {
                                int uid, WifiConfiguration wifiConfig) {
        final int eventualWifiApState = enable ? WIFI_AP_STATE_ENABLED : WIFI_AP_STATE_DISABLED;

        if (mWifiApState == eventualWifiApState) {
            /* Configuration changed on a running access point */
            if(enable && (wifiConfig != null)) {
                try {
                    persistApConfiguration(wifiConfig);
                    nwService.stopAccessPoint();
                    nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName());
                    return true;
                } catch(Exception e) {
                    Slog.e(TAG, "Exception in nwService during AP restart");
                    setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
                    return false;
                }
            } else {
                return true;
            }
        }

        setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING : WIFI_AP_STATE_DISABLING, uid);
        setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING :
                                       WIFI_AP_STATE_DISABLING, uid, DriverAction.NO_DRIVER_UNLOAD);

        if (enable && (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED)) {
        if (enable) {

            /**
             * Disable client mode for starting AP
             */
            if (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) {
                setWifiEnabledBlocking(false, true, Process.myUid());
            }

        if (enable) {
            /* Use default config if there is no existing config */
            if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
                wifiConfig = new WifiConfiguration();
                wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
                wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE);
            }
            persistApConfiguration(wifiConfig);

            if (!mWifiStateTracker.loadDriver()) {
                Slog.e(TAG, "Failed to load Wi-Fi driver for AP mode");
                setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid);
                setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
                return false;
            }

            try {
                nwService.startAccessPoint();
                nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName());
            } catch(Exception e) {
                Slog.e(TAG, "Exception in startAccessPoint()");
                setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
                return false;
            }

        } else {
@@ -669,20 +705,18 @@ public class WifiService extends IWifiManager.Stub {
                nwService.stopAccessPoint();
            } catch(Exception e) {
                Slog.e(TAG, "Exception in stopAccessPoint()");
                setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
                return false;
            }

            if (!mWifiStateTracker.unloadDriver()) {
                Slog.e(TAG, "Failed to unload Wi-Fi driver for AP mode");
                setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid);
                setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
                return false;
            }
        }

        // Success!
        if (persist) {
            persistWifiApEnabled(enable);
        }
        setWifiApEnabledState(eventualWifiApState, uid);
        setWifiApEnabledState(eventualWifiApState, uid, DriverAction.NO_DRIVER_UNLOAD);
        return true;
    }

@@ -699,9 +733,16 @@ public class WifiService extends IWifiManager.Stub {
        return mWifiApState;
    }

    private void setWifiApEnabledState(int wifiAPState, int uid) {
    private void setWifiApEnabledState(int wifiAPState, int uid, DriverAction flag) {
        final int previousWifiApState = mWifiApState;

        /**
         * Unload the driver if going to a failed state
         */
        if ((mWifiApState == WIFI_AP_STATE_FAILED) && (flag == DriverAction.DRIVER_UNLOAD)) {
            mWifiStateTracker.unloadDriver();
        }

        long ident = Binder.clearCallingIdentity();
        try {
            if (wifiAPState == WIFI_AP_STATE_ENABLED) {
@@ -1694,7 +1735,7 @@ public class WifiService extends IWifiManager.Stub {
    private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) {
        Message.obtain(mWifiHandler,
                (enable ? MESSAGE_START_ACCESS_POINT : MESSAGE_STOP_ACCESS_POINT),
                0, uid, wifiConfig).sendToTarget();
                uid, 0, wifiConfig).sendToTarget();
    }

    private void updateWifiState() {
@@ -1841,15 +1882,13 @@ public class WifiService extends IWifiManager.Stub {

                case MESSAGE_START_ACCESS_POINT:
                    setWifiApEnabledBlocking(true,
                                             msg.arg1 == 1,
                                             msg.arg2,
                                             msg.arg1,
                                             (WifiConfiguration) msg.obj);
                    break;

                case MESSAGE_STOP_ACCESS_POINT:
                    setWifiApEnabledBlocking(false,
                                             msg.arg1 == 1,
                                             msg.arg2,
                                             msg.arg1,
                                             (WifiConfiguration) msg.obj);
                    sWakeLock.release();
                    break;
Loading