summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--service/Android.mk5
-rw-r--r--service/java/com/android/server/wifi/SoftApManager.java36
-rw-r--r--service/java/com/android/server/wifi/SoftApStateMachine.java454
-rw-r--r--service/java/com/android/server/wifi/WifiApConfigStore.java37
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java32
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java16
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java41
-rw-r--r--service/java/com/android/server/wifi/WifiController.java193
-rw-r--r--service/java/com/android/server/wifi/WifiCountryCode.java5
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java5
-rw-r--r--service/java/com/android/server/wifi/WifiMonitor.java95
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java13
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkHistory.java25
-rw-r--r--service/java/com/android/server/wifi/WifiNotificationController.java3
-rw-r--r--service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java11
-rwxr-xr-x[-rw-r--r--]service/java/com/android/server/wifi/WifiServiceImpl.java252
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java360
-rw-r--r--service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java8
-rw-r--r--service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java169
-rw-r--r--service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java9
-rwxr-xr-xservice/jni/COPYING22
-rw-r--r--service/jni/README56
-rw-r--r--service/jni/com_android_server_wifi_Gbk2Utf.cpp601
-rw-r--r--service/jni/com_android_server_wifi_Gbk2Utf.h56
-rw-r--r--service/jni/com_android_server_wifi_WifiNative.cpp78
25 files changed, 2446 insertions, 136 deletions
diff --git a/service/Android.mk b/service/Android.mk
index 8201acff9..cdee104a4 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -89,6 +89,8 @@ LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
+ external/icu/icu4c/source/common \
+ external/icu/icu4c/source/i18n \
libcore/include
LOCAL_SHARED_LIBRARIES += \
@@ -98,6 +100,8 @@ LOCAL_SHARED_LIBRARIES += \
libhardware \
libhardware_legacy \
libnl \
+ libicuuc \
+ libicui18n \
libdl
LOCAL_STATIC_LIBRARIES += libwifi-hal-stub
@@ -105,6 +109,7 @@ LOCAL_STATIC_LIBRARIES += $(LIB_WIFI_HAL)
LOCAL_SRC_FILES := \
jni/com_android_server_wifi_WifiNative.cpp \
+ jni/com_android_server_wifi_Gbk2Utf.cpp \
jni/jni_helper.cpp
ifdef INCLUDE_NAN_FEATURE
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 2dfb75447..98dad2bec 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -35,6 +35,7 @@ import com.android.server.wifi.util.ApConfigUtil;
import java.util.ArrayList;
import java.util.Locale;
+import android.os.UserHandle;
/**
* Manage WiFi in AP mode.
@@ -49,7 +50,10 @@ public class SoftApManager {
private final String mCountryCode;
- private final String mInterfaceName;
+ private String mInterfaceName;
+ private boolean mCreateNewInterface = false;
+ private int mSoftApChannel = 0;
+ private String mTetherInterfaceName;
private final SoftApStateMachine mStateMachine;
@@ -111,6 +115,23 @@ public class SoftApManager {
}
/**
+ * Set SoftAp channel
+ * @param channel is channel number
+ */
+ public void setSapChannel(int channel) {
+ mSoftApChannel = channel;
+ }
+
+ /**
+ * Set SoftAp interfcae name
+ * @param name name of the interface
+ */
+ public void setSapInterfaceName(String name) {
+ mInterfaceName = name;
+ mCreateNewInterface = true;
+ }
+
+ /**
* Start a soft AP instance with the given configuration.
* @param config AP configuration
* @return integer result code
@@ -132,7 +153,7 @@ public class SoftApManager {
}
/* Setup country code if it is provide. */
- if (mCountryCode != null) {
+ if (mCountryCode != null && (mCountryCode.length() != 0)) {
/**
* Country code is mandatory for 5GHz band, return an error if failed to set
* country code when AP is configured for 5GHz band.
@@ -146,6 +167,14 @@ public class SoftApManager {
}
try {
+ if (mCreateNewInterface) {
+ mNmService.createSoftApInterface(mInterfaceName);
+ if ((localConfig.apBand != WifiConfiguration.AP_BAND_5GHZ)
+ && (mSoftApChannel != 0)) {
+ localConfig.apBand = WifiConfiguration.AP_BAND_2GHZ;
+ localConfig.apChannel = mSoftApChannel;
+ }
+ }
mNmService.startAccessPoint(localConfig, mInterfaceName);
} catch (Exception e) {
Log.e(TAG, "Exception in starting soft AP: " + e);
@@ -163,6 +192,9 @@ public class SoftApManager {
private void stopSoftAp() {
try {
mNmService.stopAccessPoint(mInterfaceName);
+ if (mCreateNewInterface) {
+ mNmService.deleteSoftApInterface(mInterfaceName);
+ }
} catch (Exception e) {
Log.e(TAG, "Exception in stopping soft AP: " + e);
return;
diff --git a/service/java/com/android/server/wifi/SoftApStateMachine.java b/service/java/com/android/server/wifi/SoftApStateMachine.java
new file mode 100644
index 000000000..1b21bb60c
--- /dev/null
+++ b/service/java/com/android/server/wifi/SoftApStateMachine.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2010 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 android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+import static android.system.OsConstants.ARPHRD_ETHER;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.dhcp.DhcpClient;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConnectionStatistics;
+import android.net.wifi.WifiManager;
+import android.os.BatteryStats;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Track the state of Wifi connectivity. All event handling is done here,
+ * and all changes in connectivity state are initiated here.
+ *
+ * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
+ * In the current implementation, we support concurrent wifi p2p and wifi operation.
+ * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
+ * handles p2p operation.
+ *
+ * @hide
+ */
+public class SoftApStateMachine extends StateMachine {
+
+ private static boolean DBG = false;
+ private static final String TAG = "SoftApStateMachine";
+
+ private WifiMonitor mWifiMonitor;
+ private WifiNative mWifiNative;
+ private WifiConfigManager mWifiConfigManager;
+ private INetworkManagementService mNwService;
+ private ConnectivityManager mCm;
+ private BaseWifiLogger mWifiLogger;
+ private WifiApConfigStore mWifiApConfigStore;
+ private final Clock mClock = new Clock();
+ private final WifiCountryCode mCountryCode;
+
+ private String mInterfaceName = "softap0";
+ private int mSoftApChannel = 0;
+ /* Tethering interface could be separate from wlan interface */
+ private String mTetherInterfaceName;
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ private WifiStateMachine mWifiStateMachine = null;
+
+ /**
+ * Tether state change notification time out
+ */
+ private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000;
+
+ /* Tracks sequence number on a tether notification time out */
+ private int mTetherToken = 0;
+
+ /*Wakelock held during wifi start/stop and driver load/unload */
+ private PowerManager.WakeLock mWakeLock;
+
+ private Context mContext;
+ /* The base for wifi message types */
+ static final int BASE = Protocol.BASE_WIFI;
+ /* Start the soft ap */
+ static final int CMD_START_AP = BASE + 21;
+ /* Indicates soft ap start failed */
+ static final int CMD_START_AP_FAILURE = BASE + 22;
+ /* Stop the soft ap */
+ static final int CMD_STOP_AP = BASE + 23;
+ /* Soft access point teardown is completed. */
+ static final int CMD_AP_STOPPED = BASE + 24;
+
+ public static final int CMD_BOOT_COMPLETED = BASE + 134;
+
+
+ /**
+ * One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
+ * {@link WifiManager#WIFI_AP_STATE_DISABLING},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLED},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLING},
+ * {@link WifiManager#WIFI_AP_STATE_FAILED}
+ */
+ private final AtomicInteger mWifiApState
+ = new AtomicInteger(WIFI_AP_STATE_DISABLED);
+ private final IBatteryStats mBatteryStats;
+
+ /* Temporary initial state */
+ private State mInitialState = new InitialState();
+ /* Soft ap state */
+ private State mSoftApState = new SoftApState();
+
+ private FrameworkFacade mFacade;
+ private final BackupManagerProxy mBackupManagerProxy;
+
+
+ public SoftApStateMachine(Context context, WifiStateMachine wifiStateMachine,
+ FrameworkFacade facade,String intf,
+ WifiConfigManager configManager,
+ WifiMonitor wifiMonitor,
+ BackupManagerProxy backupManagerProxy,
+ INetworkManagementService NwService,
+ IBatteryStats BatteryStats,
+ WifiCountryCode countryCode) {
+ super("SoftApStateMachine");
+
+ mContext = context;
+ mWifiStateMachine = wifiStateMachine;
+ mFacade = facade;
+ mWifiNative = WifiNative.getWlanNativeInterface();
+ mWifiNative.initContext(mContext);
+ mInterfaceName = intf;
+ mBackupManagerProxy = backupManagerProxy;
+ mNwService = NwService;
+ mBatteryStats = BatteryStats;
+ mWifiConfigManager = configManager;
+ mWifiMonitor = wifiMonitor;
+ mCountryCode = countryCode;
+
+ addState(mInitialState);
+ addState(mSoftApState, mInitialState);
+ setInitialState(mInitialState);
+ start();
+
+ }
+
+ void enableVerboseLogging(int verbose) {
+ if (verbose > 0) {
+ DBG = true;
+ } else {
+ DBG = false;
+ }
+ }
+
+ public void setSoftApInterfaceName(String iface) {
+ mInterfaceName = iface;
+ }
+
+ public void setSoftApChannel(int channel) {
+ mSoftApChannel = channel;
+ }
+
+
+ /* Leverage from WiFiStateMachine */
+ public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
+ if (enable) {
+ sendMessage(CMD_START_AP, wifiConfig);
+ } else {
+ sendMessage(CMD_STOP_AP);
+ }
+ }
+
+ public void setWifiApConfiguration(WifiConfiguration config) {
+ mWifiApConfigStore.setApConfiguration(config);
+ }
+
+ /* Leverage from WiFiStateMachine */
+ public WifiConfiguration syncGetWifiApConfiguration() {
+ return mWifiApConfigStore.getApConfiguration();
+ }
+
+ /* Leverage from WiFiStateMachine */
+ public int syncGetWifiApState() {
+ return mWifiApState.get();
+ }
+
+ /* Leverage from WiFiStateMachine */
+ public String syncGetWifiApStateByName() {
+ switch (mWifiApState.get()) {
+ case WIFI_AP_STATE_DISABLING:
+ return "disabling";
+ case WIFI_AP_STATE_DISABLED:
+ return "disabled";
+ case WIFI_AP_STATE_ENABLING:
+ return "enabling";
+ case WIFI_AP_STATE_ENABLED:
+ return "enabled";
+ case WIFI_AP_STATE_FAILED:
+ return "failed";
+ default:
+ return "[invalid state]";
+ }
+ }
+
+ /* Leverage from WiFiStateMachine */
+ private void setWifiApState(int wifiApState, int reason) {
+ final int previousWifiApState = mWifiApState.get();
+
+ try {
+ if (wifiApState == WIFI_AP_STATE_ENABLED) {
+ mBatteryStats.noteWifiOn();
+ } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
+ mBatteryStats.noteWifiOff();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to note battery stats in wifi");
+ }
+
+ // Update state
+ mWifiApState.set(wifiApState);
+
+ if (DBG) Log.d(TAG,"setWifiApState: " + syncGetWifiApStateByName());
+
+ final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
+ if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
+ //only set reason number when softAP start failed
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
+ }
+
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ /* Leverage from WiFiStateMachine */
+ private boolean setupDriverForSoftAp() {
+ if (!mWifiNative.loadDriver()) {
+ Log.e(TAG, "Failed to load driver for softap");
+ return false;
+ }
+ if (mWifiStateMachine != null) {
+ int wifiState = mWifiStateMachine.syncGetWifiState();
+ if ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
+ (wifiState == WifiManager.WIFI_STATE_ENABLED)) {
+ Log.d(TAG,"Wifi is in enabled state skip firmware reload");
+ return true;
+ }
+ }
+
+ try {
+ mNwService.wifiFirmwareReload(mInterfaceName, "AP");
+ if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to reload AP firmware " + e);
+ }
+ if (!mWifiNative.startHal()) {
+ Log.e(TAG, "Failed to start HAL");
+ }
+ return true;
+ }
+
+ /* Leverage from WiFiStateMachine */
+ private void checkAndSetConnectivityInstance() {
+ if (mCm == null) {
+ mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+ }
+
+ /*
+ * SoftApStateMAchine states
+ * (InitialState)
+ * |
+ * |
+ * V
+ * (SoftApState)
+ *
+ * InitialState : By default control sits in this state after
+ * SoftApStateMachine is getting initialized.
+ * It unload wlan driver if it is loaded.
+ * On request turn on softap, it movies to
+ * SoftApState.
+ * SoftApState : Once driver and firmware successfully loaded
+ * it control sits in this state.
+ * On request to stop softap, it movies back to
+ * InitialState.
+ *
+ */
+
+ /* Leverage from WiFiStateMachine */
+ class InitialState extends State {
+ @Override
+ public void enter() {
+ boolean skipUnload = false;
+ if (mWifiStateMachine != null) {
+ int wifiState = mWifiStateMachine.syncGetWifiState();
+ if ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
+ (wifiState == WifiManager.WIFI_STATE_ENABLED)) {
+ Log.d(TAG, "Avoid unload driver, WIFI_STATE is enabled/enabling");
+ skipUnload = true;
+ }
+ }
+ if (!skipUnload) {
+ mWifiNative.stopHal();
+ mWifiNative.unloadDriver();
+ }
+ if (mWifiApConfigStore == null) {
+ mWifiApConfigStore =
+ mFacade.makeApConfigStore(mContext, mBackupManagerProxy);
+ }
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_START_AP:
+ if (setupDriverForSoftAp()) {
+ transitionTo(mSoftApState);
+ } else {
+ setWifiApState(WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ /**
+ * Transition to InitialState (current state) to reset the
+ * driver/HAL back to the initial state.
+ */
+ transitionTo(mInitialState);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ /* Leverage from WiFiStateMachine */
+ class SoftApState extends State {
+ private SoftApManager mSoftApManager;
+
+ private class SoftApListener implements SoftApManager.Listener {
+ @Override
+ public void onStateChanged(int state, int reason) {
+ if (state == WIFI_AP_STATE_DISABLED) {
+ sendMessage(CMD_AP_STOPPED);
+ } else if (state == WIFI_AP_STATE_FAILED) {
+ sendMessage(CMD_START_AP_FAILURE);
+ }
+
+ setWifiApState(state, reason);
+ }
+ }
+
+ @Override
+ public void enter() {
+ final Message message = getCurrentMessage();
+ if (message.what == CMD_START_AP) {
+ WifiConfiguration config = (WifiConfiguration) message.obj;
+
+ if (config == null) {
+ /**
+ * Configuration not provided in the command, fallback to use the current
+ * configuration.
+ */
+ config = mWifiApConfigStore.getApConfiguration();
+ } else {
+ /* Update AP configuration. */
+ mWifiApConfigStore.setApConfiguration(config);
+ }
+
+ checkAndSetConnectivityInstance();
+ mSoftApManager = mFacade.makeSoftApManager(
+ mContext, getHandler().getLooper(), mWifiNative, mNwService,
+ mCm, mCountryCode.getCurrentCountryCode(),
+ mWifiApConfigStore.getAllowed2GChannel(),
+ new SoftApListener());
+ if (mSoftApChannel != 0) {
+ mSoftApManager.setSapChannel(mSoftApChannel);
+ }
+ mSoftApManager.setSapInterfaceName(mInterfaceName);
+ mSoftApManager.start(config);
+ } else {
+ throw new RuntimeException("Illegal transition to SoftApState: " + message);
+ }
+ }
+
+ @Override
+ public void exit() {
+ mSoftApManager = null;
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+
+ switch(message.what) {
+ case CMD_START_AP:
+ /* Ignore start command when it is starting/started. */
+ break;
+ case CMD_STOP_AP:
+ mSoftApManager.stop();
+ break;
+ case CMD_START_AP_FAILURE:
+ transitionTo(mInitialState);
+ break;
+ case CMD_AP_STOPPED:
+ transitionTo(mInitialState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ /**
+ * arg2 on the source message has a unique id that needs to be retained in replies
+ * to match the request
+ * <p>see WifiManager for details
+ */
+ private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg2 = srcMsg.arg2;
+ return msg;
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index bcd8d03e9..2f49586d5 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -20,6 +20,10 @@ import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
@@ -54,6 +58,8 @@ public class WifiApConfigStore {
private final String mApConfigFile;
private final BackupManagerProxy mBackupManagerProxy;
+ private static boolean mEnableRegionalHotspotCheckbox = false;
+
WifiApConfigStore(Context context, BackupManagerProxy backupManagerProxy) {
this(context, backupManagerProxy, DEFAULT_AP_CONFIG_FILE);
}
@@ -87,6 +93,11 @@ public class WifiApConfigStore {
/* Save the default configuration to persistent storage. */
writeApConfiguration(mApConfigFile, mWifiApConfig);
}
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_regional_hotspot_show_broadcast_ssid_checkbox
+ )) {
+ mEnableRegionalHotspotCheckbox = true;
+ }
}
/**
@@ -135,6 +146,9 @@ public class WifiApConfigStore {
return null;
}
config.SSID = in.readUTF();
+ if (mEnableRegionalHotspotCheckbox) {
+ config.hiddenSSID = (in.readInt() != 0);
+ }
if (version >= 2) {
config.apBand = in.readInt();
@@ -146,6 +160,10 @@ public class WifiApConfigStore {
if (authType != KeyMgmt.NONE) {
config.preSharedKey = in.readUTF();
}
+ // read in wifiApInactivityTimeout if bytes are available from in
+ if (in.available() != 0) {
+ config.wifiApInactivityTimeout = in.readLong();
+ }
} catch (IOException e) {
Log.e(TAG, "Error reading hotspot configuration " + e);
config = null;
@@ -170,6 +188,9 @@ public class WifiApConfigStore {
new FileOutputStream(filename)))) {
out.writeInt(AP_CONFIG_FILE_VERSION);
out.writeUTF(config.SSID);
+ if (mEnableRegionalHotspotCheckbox) {
+ out.writeInt(config.hiddenSSID ? 1 : 0);
+ }
out.writeInt(config.apBand);
out.writeInt(config.apChannel);
int authType = config.getAuthType();
@@ -177,6 +198,7 @@ public class WifiApConfigStore {
if (authType != KeyMgmt.NONE) {
out.writeUTF(config.preSharedKey);
}
+ out.writeLong(config.wifiApInactivityTimeout);
} catch (IOException e) {
Log.e(TAG, "Error writing hotspot configuration" + e);
}
@@ -192,10 +214,17 @@ public class WifiApConfigStore {
WifiConfiguration config = new WifiConfiguration();
config.SSID = mContext.getResources().getString(
R.string.wifi_tether_configure_ssid_default);
- config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
- String randomUUID = UUID.randomUUID().toString();
- //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
- config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
+ int wifiApSecurityType = mContext.getResources().getInteger(
+ R.integer.wifi_hotspot_security_type);
+ config.allowedKeyManagement.set(wifiApSecurityType);
+ config.preSharedKey = mContext.getResources().getString(
+ R.string.def_wifi_wifihotspot_pass);
+ if (TextUtils.isEmpty(config.preSharedKey)) {
+ String randomUUID = UUID.randomUUID().toString();
+ //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+ config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
+ }
+ config.wifiApInactivityTimeout = 0;
return config;
}
}
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 5eff02ee6..9129fe612 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -392,10 +392,20 @@ public class WifiConfigManager {
R.bool.config_wifi_fast_bss_transition_enabled);
boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled);
- Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled"));
+ boolean hs2onSet = (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_HOTSPOT2_ENABLED, 0) == 1);
+ Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " +
+ (hs2on ? "enabled" : "disabled") + ", " + hs2onSet);
mConfiguredNetworks = new ConfigurationMap(userManager);
- mMOManager = new PasspointManagementObjectManager(new File(PPS_FILE), hs2on);
+
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_passpoint_setting_on)) {
+ mMOManager = new PasspointManagementObjectManager(new File(PPS_FILE), hs2onSet);
+ } else {
+ mMOManager = new PasspointManagementObjectManager(new File(PPS_FILE), hs2on);
+ }
+
mEnableOsuQueries = true;
mAnqpCache = new AnqpCache(mClock);
mSupplicantBridgeCallbacks = new SupplicantBridgeCallbacks();
@@ -413,6 +423,23 @@ public class WifiConfigManager {
mAnqpCache.clear(all, DBG);
}
+ public HashSet<Integer> getConfiguredChannelList() {
+ /* Hashset will avoid any duplicate frequency to be added in hashmap */
+ HashSet<Integer> freqs = new HashSet<Integer>();
+ for(WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
+ if (getScanDetailCache(config) != null) {
+ for(ScanDetail scanDetail : getScanDetailCache(config).values()) {
+ ScanResult result = scanDetail.getScanResult();
+ freqs.add(result.frequency);
+ }
+ }
+ }
+ if (freqs.isEmpty())
+ return null;
+ else
+ return freqs;
+ }
+
void enableVerboseLogging(int verbose) {
mEnableVerboseLogging.set(verbose);
if (verbose > 0) {
@@ -1683,6 +1710,7 @@ public class WifiConfigManager {
final Map<String, WifiConfiguration> configs = new HashMap<>();
final SparseArray<Map<String, String>> networkExtras = new SparseArray<>();
+ mScanDetailCaches.clear();
mLastPriority = mWifiConfigStore.loadNetworks(configs, networkExtras);
readNetworkHistory(configs);
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index e4aef24c6..fc4c122fa 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -283,6 +283,15 @@ public class WifiConfigStore {
config.getNetworkSelectionStatus().setNetworkSelectionBSSID(null);
}
+ value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.SIMNumVarName);
+ if (!TextUtils.isEmpty(value)) {
+ try {
+ config.SIMNum = Integer.parseInt(value);
+ } catch (NumberFormatException ignore) {
+ Log.e(TAG,"error in parsing Selected Sim number " + config.SIMNum);
+ }
+ }
+
value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName);
config.priority = -1;
if (!TextUtils.isEmpty(value)) {
@@ -737,6 +746,13 @@ public class WifiConfigStore {
return false;
}
}
+ if (config.SIMNum != 0 && !mWifiNative.setNetworkVariable(
+ netId,
+ WifiConfiguration.SIMNumVarName,
+ Integer.toString(config.SIMNum))) {
+ loge(config.SIMNum + ": failed to set sim no: " + config.SIMNum);
+ return false;
+ }
if (!mWifiNative.setNetworkVariable(
netId,
WifiConfiguration.priorityVarName,
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 49a2842d6..1ca2608cb 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -164,6 +164,9 @@ public class WifiConnectivityManager {
// A helper to log debugging information in the local log buffer, which can
// be retrieved in bugreport.
private void localLog(String log) {
+ if (mDbg) {
+ Log.d(TAG, log);
+ }
mLocalLog.log(log);
}
@@ -179,7 +182,7 @@ public class WifiConnectivityManager {
// A single scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
// if the start scan command failed. An timer is used here to make it a deferred retry.
private class RestartSingleScanListener implements AlarmManager.OnAlarmListener {
- private final boolean mIsFullBandScan;
+ private boolean mIsFullBandScan;
RestartSingleScanListener(boolean isFullBandScan) {
mIsFullBandScan = isFullBandScan;
@@ -187,6 +190,9 @@ public class WifiConnectivityManager {
@Override
public void onAlarm() {
+ if (mStateMachine.getScanCount() < mStateMachine.getMaxConfiguredScanCount()) {
+ mIsFullBandScan = false;
+ }
startSingleScan(mIsFullBandScan);
}
}
@@ -392,6 +398,17 @@ public class WifiConnectivityManager {
@Override
public void onSuccess() {
localLog("SingleScanListener onSuccess");
+ /* As part of optimizing time for initial scans for
+ * saved profiles, increment the scan trigger count
+ * upon receiving a success.
+ */
+ int mScanCount = 0;
+ mScanCount = mStateMachine.getScanCount();
+ if (mScanCount < mStateMachine.getMaxConfiguredScanCount()) {
+ mStateMachine.setScanCount(++mScanCount);
+ }
+ // reset the count
+ mSingleScanRestartCount = 0;
}
@Override
@@ -681,6 +698,19 @@ public class WifiConnectivityManager {
}
}
+ private boolean populateFreqList(ScanSettings settings) {
+ Set<Integer> freqs = mConfigManager.getConfiguredChannelList();
+ if (freqs != null && freqs.size() != 0) {
+ int index = 0;
+ settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
+ for (Integer freq : freqs) {
+ settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
+ }
+ return true;
+ }
+ return false;
+ }
+
// Helper for setting the channels for connectivity scan when band is unspecified. Returns
// false if we can't retrieve the info.
private boolean setScanChannels(ScanSettings settings) {
@@ -749,6 +779,9 @@ public class WifiConnectivityManager {
}
mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
+ if (mStateMachine.getScanCount() < mStateMachine.getMaxConfiguredScanCount()) {
+ isFullBandScan = false;
+ }
startSingleScan(isFullBandScan);
schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
@@ -785,7 +818,11 @@ public class WifiConnectivityManager {
ScanSettings settings = new ScanSettings();
if (!isFullBandScan) {
- if (!setScanChannels(settings)) {
+ if (mStateMachine.getScanCount() < mStateMachine.getMaxConfiguredScanCount()) {
+ if (!populateFreqList(settings)) {
+ isFullBandScan = true;
+ }
+ } else if (!setScanChannels(settings)) {
isFullBandScan = true;
}
}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 67a7a423e..26f662adb 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -53,7 +53,7 @@ import java.io.PrintWriter;
*/
public class WifiController extends StateMachine {
private static final String TAG = "WifiController";
- private static final boolean DBG = false;
+ private static boolean DBG = false;
private Context mContext;
private boolean mScreenOff;
private boolean mDeviceIdle;
@@ -62,6 +62,7 @@ public class WifiController extends StateMachine {
private long mIdleMillis;
private int mSleepPolicy;
private boolean mFirstUserSignOnSeen = false;
+ private boolean mStaAndApConcurrency = false;
private AlarmManager mAlarmManager;
private PendingIntent mIdleIntent;
@@ -93,8 +94,9 @@ public class WifiController extends StateMachine {
"com.android.server.WifiManager.action.DEVICE_IDLE";
/* References to values tracked in WifiService */
- private final WifiStateMachine mWifiStateMachine;
- private final WifiSettingsStore mSettingsStore;
+ final WifiStateMachine mWifiStateMachine;
+ private SoftApStateMachine mSoftApStateMachine = null;
+ final WifiSettingsStore mSettingsStore;
private final WifiLockManager mWifiLockManager;
/**
@@ -135,7 +137,9 @@ public class WifiController extends StateMachine {
private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState();
private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState();
private ApEnabledState mApEnabledState = new ApEnabledState();
+ private ApStaEnabledState mApStaEnabledState = new ApStaEnabledState();
private DeviceActiveState mDeviceActiveState = new DeviceActiveState();
+ private DeviceActiveHighPerfState mDeviceActiveHighPerfState = new DeviceActiveHighPerfState();
private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState();
private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState();
private FullLockHeldState mFullLockHeldState = new FullLockHeldState();
@@ -159,7 +163,9 @@ public class WifiController extends StateMachine {
addState(mDefaultState);
addState(mApStaDisabledState, mDefaultState);
addState(mStaEnabledState, mDefaultState);
+ addState(mApStaEnabledState, mDefaultState);
addState(mDeviceActiveState, mStaEnabledState);
+ addState(mDeviceActiveHighPerfState, mDeviceActiveState);
addState(mDeviceInactiveState, mStaEnabledState);
addState(mScanOnlyLockHeldState, mDeviceInactiveState);
addState(mFullLockHeldState, mDeviceInactiveState);
@@ -349,6 +355,20 @@ public class WifiController extends StateMachine {
mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
}
+ public void setSoftApStateMachine(SoftApStateMachine machine) {
+ mSoftApStateMachine = machine;
+ mStaAndApConcurrency = true;
+ Slog.d(TAG, "mStaAndApConcurrency="+mStaAndApConcurrency);
+ }
+
+ void enableVerboseLogging(int verbose) {
+ if (verbose > 0) {
+ DBG = true;
+ } else {
+ DBG = false;
+ }
+ }
+
class DefaultState extends State {
@Override
public boolean processMessage(Message msg) {
@@ -458,7 +478,7 @@ public class WifiController extends StateMachine {
break;
}
if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
} else {
checkLocksAndTransitionWhenDeviceIdle();
}
@@ -476,8 +496,13 @@ public class WifiController extends StateMachine {
if (msg.arg2 == 0) { // previous wifi state has not been saved yet
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
}
- mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
- true);
+ if (mStaAndApConcurrency) {
+ mSoftApStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
+ true);
+ } else {
+ mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
+ true);
+ }
transitionTo(mApEnabledState);
}
break;
@@ -517,6 +542,90 @@ public class WifiController extends StateMachine {
}
+ class ApStaEnabledState extends State {
+ private State mPendingState = null;
+ private int mDeferredEnableSerialNumber = 0;
+ private boolean mHaveDeferredEnable = false;
+ private long mDisabledTimestamp;
+
+ @Override
+ public void enter() {
+ if (DBG) {
+ Slog.d(TAG,"ApStaEnabledState enter");
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_SET_AP:
+ if (msg.arg1 == 1) {
+ if (DBG) {
+ Slog.d(TAG,"ApStaEnabledState CMD_SET_AP setHostApRunning true");
+ }
+ mSoftApStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
+ true);
+ } else {
+ if (DBG) {
+ Slog.d(TAG,"ApStaEnabledState CMD_SET_AP setHostApRunning false");
+ }
+ mSoftApStateMachine.setHostApRunning(null, false);
+ transitionTo(mStaEnabledState);
+ }
+ break;
+ case CMD_WIFI_TOGGLED:
+ if (mSettingsStore.isWifiToggleEnabled()) {
+ if (doDeferEnable(msg)) {
+ if (mHaveDeferredEnable) {
+ // have 2 toggles now, inc serial number an ignore both
+ mDeferredEnableSerialNumber++;
+ }
+ mHaveDeferredEnable = !mHaveDeferredEnable;
+ break;
+ }
+ if (DBG) {
+ Slog.d(TAG,"ApStaEnabledState CMD_WIFI_TOGGLED setSupplicantRunning true");
+ }
+ mWifiStateMachine.setSupplicantRunning(true);
+ } else {
+ if (DBG) {
+ Slog.d(TAG,"ApStaEnabledState CMD_WIFI_TOGGLED setSupplicantRunning false");
+ }
+ mWifiStateMachine.setSupplicantRunning(false);
+ transitionTo(mApEnabledState);
+ }
+ break;
+ case CMD_AIRPLANE_TOGGLED:
+ mSoftApStateMachine.setHostApRunning(null, false);
+ mPendingState = mApStaDisabledState;
+ break;
+ case CMD_AP_STOPPED:
+ if(mPendingState != null) {
+ transitionTo(mPendingState);
+ }
+ }
+ return HANDLED;
+ }
+
+ private boolean doDeferEnable(Message msg) {
+ long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
+ if (delaySoFar >= mReEnableDelayMillis) {
+ return false;
+ }
+
+ log("WifiController msg " + msg + " deferred for " +
+ (mReEnableDelayMillis - delaySoFar) + "ms");
+
+ // need to defer this action.
+ Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
+ deferredMsg.obj = Message.obtain(msg);
+ deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
+ sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
+ return true;
+ }
+
+ }
+
class StaEnabledState extends State {
@Override
public void enter() {
@@ -563,7 +672,11 @@ public class WifiController extends StateMachine {
// remeber that we were enabled
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED);
deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
- transitionTo(mApStaDisabledState);
+ if (mStaAndApConcurrency) {
+ transitionTo(mApStaEnabledState);
+ } else {
+ transitionTo(mApStaDisabledState);
+ }
}
break;
default:
@@ -607,7 +720,7 @@ public class WifiController extends StateMachine {
break;
}
if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
} else {
checkLocksAndTransitionWhenDeviceIdle();
}
@@ -683,7 +796,9 @@ public class WifiController extends StateMachine {
*/
private State getNextWifiState() {
if (mSettingsStore.getWifiSavedState() == WifiSettingsStore.WIFI_ENABLED) {
- return mDeviceActiveState;
+ if (!mStaAndApConcurrency) {
+ return mDeviceActiveState;
+ }
}
if (mSettingsStore.isScanAlwaysAvailable()) {
@@ -698,20 +813,36 @@ public class WifiController extends StateMachine {
switch (msg.what) {
case CMD_AIRPLANE_TOGGLED:
if (mSettingsStore.isAirplaneModeOn()) {
- mWifiStateMachine.setHostApRunning(null, false);
+ if (mStaAndApConcurrency) {
+ mSoftApStateMachine.setHostApRunning(null, false);
+ } else {
+ mWifiStateMachine.setHostApRunning(null, false);
+ }
mPendingState = mApStaDisabledState;
}
break;
case CMD_WIFI_TOGGLED:
if (mSettingsStore.isWifiToggleEnabled()) {
- mWifiStateMachine.setHostApRunning(null, false);
- mPendingState = mDeviceActiveState;
+ if (mStaAndApConcurrency) {
+ deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
+ if (DBG) {
+ Slog.d(TAG,"ApEnabledState CMD_WIFI_TOGGLED transition To ApStaEnabledState");
+ }
+ transitionTo(mApStaEnabledState);
+ } else {
+ mWifiStateMachine.setHostApRunning(null, false);
+ mPendingState = mStaEnabledState;
+ }
}
break;
case CMD_SET_AP:
if (msg.arg1 == 0) {
- mWifiStateMachine.setHostApRunning(null, false);
- mPendingState = getNextWifiState();
+ if (mStaAndApConcurrency) {
+ mSoftApStateMachine.setHostApRunning(null, false);
+ } else {
+ mWifiStateMachine.setHostApRunning(null, false);
+ mPendingState = getNextWifiState();
+ }
}
break;
case CMD_AP_STOPPED:
@@ -733,7 +864,11 @@ public class WifiController extends StateMachine {
case CMD_EMERGENCY_CALL_STATE_CHANGED:
case CMD_EMERGENCY_MODE_CHANGED:
if (msg.arg1 == 1) {
- mWifiStateMachine.setHostApRunning(null, false);
+ if (mStaAndApConcurrency) {
+ mSoftApStateMachine.setHostApRunning(null, false);
+ } else {
+ mWifiStateMachine.setHostApRunning(null, false);
+ }
mPendingState = mEcmState;
}
break;
@@ -799,7 +934,7 @@ public class WifiController extends StateMachine {
if (exitEcm) {
if (mSettingsStore.isWifiToggleEnabled()) {
if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
} else {
checkLocksAndTransitionWhenDeviceIdle();
}
@@ -826,6 +961,9 @@ public class WifiController extends StateMachine {
if (msg.what == CMD_DEVICE_IDLE) {
checkLocksAndTransitionWhenDeviceIdle();
// We let default state handle the rest of work
+ } else if (msg.what == CMD_LOCKS_CHANGED) {
+ checkLocksAndTransitionWhenDeviceActive();
+ return HANDLED;
} else if (msg.what == CMD_USER_PRESENT) {
// TLS networks can't connect until user unlocks keystore. KeyStore
// unlocks when the user punches PIN after the reboot. So use this
@@ -844,6 +982,16 @@ public class WifiController extends StateMachine {
}
}
+ /* Parent: DeviceActiveState. Device is active, and an app is holding a high perf lock. */
+ class DeviceActiveHighPerfState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setHighPerfModeEnabled(true);
+ }
+ }
+
/* Parent: StaEnabledState */
class DeviceInactiveState extends State {
@Override
@@ -854,7 +1002,7 @@ public class WifiController extends StateMachine {
updateBatteryWorkSource();
return HANDLED;
case CMD_SCREEN_ON:
- transitionTo(mDeviceActiveState);
+ checkLocksAndTransitionWhenDeviceActive();
// More work in default state
return NOT_HANDLED;
default:
@@ -900,6 +1048,17 @@ public class WifiController extends StateMachine {
}
}
+ private void checkLocksAndTransitionWhenDeviceActive() {
+ if (mWifiLockManager.getStrongestLockMode() == WIFI_MODE_FULL_HIGH_PERF) {
+ // It is possible for the screen to be off while the device is
+ // is active (mIdleMillis), so we need the high-perf mode
+ // otherwise powersaving mode will be turned on.
+ transitionTo(mDeviceActiveHighPerfState);
+ } else {
+ transitionTo(mDeviceActiveState);
+ }
+ }
+
private void checkLocksAndTransitionWhenDeviceIdle() {
switch (mWifiLockManager.getStrongestLockMode()) {
case WIFI_MODE_NO_LOCKS_HELD:
diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java
index 13396562a..a6974776b 100644
--- a/service/java/com/android/server/wifi/WifiCountryCode.java
+++ b/service/java/com/android/server/wifi/WifiCountryCode.java
@@ -160,6 +160,11 @@ public class WifiCountryCode {
* country code.
* Returns null if no Country Code was sent to driver.
*/
+ public synchronized String getCurrentCountryCode() {
+ mCurrentCountryCode = pickCountryCode();
+ return mCurrentCountryCode;
+ }
+
public synchronized String getCountryCodeSentToDriver() {
return mCurrentCountryCode;
}
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 6583db242..6cf87fef0 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -933,8 +933,9 @@ public class WifiMetrics {
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mLock) {
- if (args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
- // Dump serialized WifiLog proto
+ pw.println("WifiMetrics:");
+ if ((args != null) && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) {
+ //Dump serialized WifiLog proto
consolidateProto(true);
for (ConnectionEvent event : mConnectionEventList) {
if (mCurrentConnectionEvent != event) {
diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java
index 1f2b39713..d9366e766 100644
--- a/service/java/com/android/server/wifi/WifiMonitor.java
+++ b/service/java/com/android/server/wifi/WifiMonitor.java
@@ -81,6 +81,10 @@ public class WifiMonitor {
private static final int UNKNOWN = 14;
private static final int SCAN_FAILED = 15;
+ /** Vendor defined events from supplicant daemon */
+ private static final int WIFI_VENDOR_EVENT_BASE = 255;
+ private static final int SUBNET_STATUS_UPDATE = WIFI_VENDOR_EVENT_BASE + 1;
+
/** All events coming from the supplicant start with this prefix */
private static final String EVENT_PREFIX_STR = "CTRL-EVENT-";
private static final int EVENT_PREFIX_LEN_STR = EVENT_PREFIX_STR.length();
@@ -429,6 +433,12 @@ public class WifiMonitor {
*/
private static final String P2P_SERV_DISC_RESP_STR = "P2P-SERV-DISC-RESP";
+ /* P2P-REMOVE-AND-REFORM-GROUP */
+ /* Supplicant is supposed to generate this event only when p2p
+ * is connected
+ */
+ private static final String P2P_REMOVE_AND_REFORM_GROUP_STR = "P2P-REMOVE-AND-REFORM-GROUP";
+
private static final String HOST_AP_EVENT_PREFIX_STR = "AP";
/* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */
private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED";
@@ -437,8 +447,12 @@ public class WifiMonitor {
private static final String ANQP_DONE_STR = "ANQP-QUERY-DONE";
private static final String HS20_ICON_STR = "RX-HS20-ICON";
+ /* WPA_EVENT_SUBNET_STATUS_UPDATE status=0|1|2 */
+ private static final String SUBNET_STATUS_UPDATE_STR ="SUBNET-STATUS-UPDATE";
+
/* Supplicant events reported to a state machine */
private static final int BASE = Protocol.BASE_WIFI_MONITOR;
+ private static final int VENDOR_BASE_WIFI_MONITOR = 255;
/* Connection to supplicant established */
public static final int SUP_CONNECTION_EVENT = BASE + 1;
@@ -497,6 +511,7 @@ public class WifiMonitor {
public static final int P2P_FIND_STOPPED_EVENT = BASE + 37;
public static final int P2P_SERV_DISC_RESP_EVENT = BASE + 38;
public static final int P2P_PROV_DISC_FAILURE_EVENT = BASE + 39;
+ public static final int P2P_REMOVE_AND_REFORM_GROUP_EVENT = BASE + 40;
/* hostap events */
public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41;
@@ -514,6 +529,9 @@ public class WifiMonitor {
/* hotspot 2.0 events */
public static final int HS20_REMEDIATION_EVENT = BASE + 61;
+ /* subnet status change event */
+ public static final int SUBNET_STATUS_UPDATE_EVENT = VENDOR_BASE_WIFI_MONITOR + 62;
+
/**
* This indicates a read error on the monitor socket conenction
*/
@@ -597,9 +615,9 @@ public class WifiMonitor {
new MonitorThread(mWifiNative.getLocalLog()).start();
return true;
}
- if (connectTries++ < 5) {
+ if (connectTries++ < 50) {
try {
- Thread.sleep(1000);
+ Thread.sleep(100);
} catch (InterruptedException ignore) {
}
} else {
@@ -763,11 +781,17 @@ public class WifiMonitor {
int space = eventStr.indexOf(' ');
if (space != -1) {
iface = eventStr.substring(7, space);
- if (!mHandlerMap.containsKey(iface) && iface.startsWith("p2p-")) {
- // p2p interfaces are created dynamically, but we have
- // only one P2p state machine monitoring all of them; look
- // for it explicitly, and send messages there ..
- iface = "p2p0";
+ if (!mHandlerMap.containsKey(iface)) {
+ if (iface.startsWith("p2p-")) {
+ // p2p interfaces are created dynamically, but we have
+ // only one P2p state machine monitoring all of them; look
+ // for it explicitly, and send messages there ..
+ iface = "p2p0";
+ } else {
+ Log.i(TAG, "Ignoring event from unexpected interface: "
+ + eventStr);
+ return false;
+ }
}
eventStr = eventStr.substring(space + 1);
} else {
@@ -812,7 +836,10 @@ public class WifiMonitor {
}
if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
- if (eventStr.startsWith(WPS_SUCCESS_STR)) {
+ if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
+ 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
+ sendMessage(iface, AUTHENTICATION_FAILURE_EVENT);
+ } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
sendMessage(iface, WPS_SUCCESS_EVENT);
} else if (eventStr.startsWith(WPS_FAIL_STR)) {
handleWpsFailEvent(eventStr, iface);
@@ -921,6 +948,8 @@ public class WifiMonitor {
event = BSS_ADDED;
} else if (eventName.equals(BSS_REMOVED_STR)) {
event = BSS_REMOVED;
+ } else if (eventName.equals(SUBNET_STATUS_UPDATE_STR)) {
+ event = SUBNET_STATUS_UPDATE;
} else
event = UNKNOWN;
@@ -1066,6 +1095,10 @@ public class WifiMonitor {
sendMessage(iface, SCAN_FAILED_EVENT);
break;
+ case SUBNET_STATUS_UPDATE:
+ handleSupplicantVendorDebugEvent(iface, remainder);
+ break;
+
case UNKNOWN:
if (DBG) {
Log.w(TAG, "handleEvent unknown: " + Integer.toString(event) + " " + remainder);
@@ -1221,6 +1254,9 @@ public class WifiMonitor {
} else {
Log.e(TAG, "Null service resp " + dataString);
}
+ } else if (dataString.startsWith(P2P_REMOVE_AND_REFORM_GROUP_STR)) {
+ Log.d(TAG, "Received event= " + dataString);
+ sendMessage(iface, P2P_REMOVE_AND_REFORM_GROUP_EVENT);
}
}
@@ -1451,4 +1487,47 @@ public class WifiMonitor {
sendMessage(iface, NETWORK_DISCONNECTION_EVENT, local, reason, BSSID);
}
}
+
+ /**
+ * Send subnet change status to state machine
+ */
+ private void notifyIpSubnetStatusChange(String iface, int subnetStatus) {
+ /* valid values for subnet status are:
+ * 0 = unknown, 1 = unchanged, 2 = changed
+ */
+ if (subnetStatus < 0 || subnetStatus > 2) {
+ Log.e(TAG, "Invalid IP subnet status: " + subnetStatus);
+ return;
+ }
+
+ sendMessage(iface, SUBNET_STATUS_UPDATE_EVENT, subnetStatus);
+ }
+
+ /**
+ * Handle vendor specific events from the supplicant
+ */
+ private void handleSupplicantVendorDebugEvent(String iface, String eventStr) {
+ int subnetStatus = 0;
+
+ if (DBG) Log.w(TAG, "IP subnet status change event - " + eventStr);
+
+ String[] tokens = eventStr.split(" ");
+ if (tokens.length < 2) {
+ Log.e(TAG, "IP subnet status event: Invalid tokens");
+ return;
+ }
+ String[] nameValue = tokens[1].split("=");
+ if (nameValue.length != 2) {
+ Log.e(TAG, "IP subnet status event: Invalid nameValue");
+ return;
+ }
+
+ try {
+ subnetStatus = Integer.parseInt(nameValue[1]);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+
+ notifyIpSubnetStatusChange(iface, subnetStatus);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 13876f324..f6931c1fe 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -898,6 +898,17 @@ public class WifiNative {
doBooleanCommand("SET update_config 1");
}
+ public void enableTdlsExtControl() {
+ doBooleanCommand("SET tdls_external_control 1");
+ }
+
+ public void disableScanOffload() {
+ doBooleanCommand("SET disable_scan_offload 1");
+ }
+
+ public void setP2pDisable() {
+ doBooleanCommand("SET p2p_disabled 1");
+ }
public boolean saveConfig() {
return doBooleanCommand("SAVE_CONFIG");
}
@@ -1538,6 +1549,8 @@ public class WifiNative {
}
}
+ public native static boolean setApMode(boolean enable);
+
/* WIFI HAL support */
// HAL command ids
diff --git a/service/java/com/android/server/wifi/WifiNetworkHistory.java b/service/java/com/android/server/wifi/WifiNetworkHistory.java
index edbc51649..5b285f5f3 100644
--- a/service/java/com/android/server/wifi/WifiNetworkHistory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkHistory.java
@@ -333,6 +333,8 @@ public class WifiNetworkHistory {
String bssid = null;
String ssid = null;
+ String key = null;
+ String value = null;
int freq = 0;
int status = 0;
@@ -347,12 +349,16 @@ public class WifiNetworkHistory {
break;
}
int colon = line.indexOf(':');
- if (colon < 0) {
+ char slash = line.charAt(0);
+ if ((colon < 0)&& (slash != '/')) {
continue;
}
-
- String key = line.substring(0, colon).trim();
- String value = line.substring(colon + 1).trim();
+ if (slash == '/') {
+ key = line.trim();
+ } else {
+ key = line.substring(0, colon).trim();
+ value = line.substring(colon + 1).trim();
+ }
if (key.equals(CONFIG_KEY)) {
config = configs.get(value);
@@ -486,8 +492,15 @@ public class WifiNetworkHistory {
break;
case BSSID_KEY:
status = 0;
- ssid = null;
- bssid = null;
+ /*
+ * The intention here is to put the scanDetail in to
+ * the scanDetailCache per config , as done in
+ * BSSID_KEY_END . Thus store bssid value and
+ * comment ssid = null to ensure the code in the if
+ * loop is executed for the case BSSID_KEY_END.
+ */
+ // ssid = null;
+ bssid = value;
freq = 0;
seen = 0;
rssi = WifiConfiguration.INVALID_RSSI;
diff --git a/service/java/com/android/server/wifi/WifiNotificationController.java b/service/java/com/android/server/wifi/WifiNotificationController.java
index 6df2eb81e..413e4c8e5 100644
--- a/service/java/com/android/server/wifi/WifiNotificationController.java
+++ b/service/java/com/android/server/wifi/WifiNotificationController.java
@@ -174,7 +174,8 @@ final class WifiNotificationController {
//A capability of [ESS] represents an open access point
//that is available for an STA to connect
if (scanResult.capabilities != null &&
- scanResult.capabilities.equals("[ESS]")) {
+ (scanResult.capabilities.equals("[ESS]") ||
+ scanResult.capabilities.equals("[WPS][ESS]"))) {
numOpenNetworks++;
}
}
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
index 1e7560346..e429d835a 100644
--- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
@@ -64,8 +64,9 @@ public class WifiQualifiedNetworkSelector {
private WifiNetworkScoreCache mNetworkScoreCache;
private Clock mClock;
private static final String TAG = "WifiQualifiedNetworkSelector:";
+ private boolean skipQualifiedNetworkSelectionForAutoConnect = false;
// Always enable debugging logs for now since QNS is still a new feature.
- private static final boolean FORCE_DEBUG = true;
+ private static final boolean FORCE_DEBUG = false;
private boolean mDbg = FORCE_DEBUG;
private WifiConfiguration mCurrentConnectedNetwork = null;
private String mCurrentBssid = null;
@@ -137,6 +138,7 @@ public class WifiQualifiedNetworkSelector {
private void localLog(String log) {
if (mDbg) {
+ Log.d(TAG, log);
mLocalLog.log(log);
}
}
@@ -344,6 +346,9 @@ public class WifiQualifiedNetworkSelector {
return true;
}
+ public void skipQualifiedNetworkSelectionForAutoConnect(boolean enable) {
+ skipQualifiedNetworkSelectionForAutoConnect = enable;
+ }
/**
* check whether QualifiedNetworkSelection is needed or not
*
@@ -370,6 +375,10 @@ public class WifiQualifiedNetworkSelector {
localLog("Need not Qualified Network Selection during L2 debouncing");
return false;
}
+ if (skipQualifiedNetworkSelectionForAutoConnect) {
+ localLog("Skip network selction, since auto connection disabled");
+ return false;
+ }
if (isConnected) {
//already connected. Just try to find better candidate
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index ae42db0de..bea194908 100644..100755
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -30,6 +30,7 @@ import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
import android.Manifest;
import android.app.ActivityManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -64,6 +65,7 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -96,7 +98,15 @@ import com.android.server.wifi.configparse.ConfigBuilder;
import org.xml.sax.SAXException;
import java.io.BufferedReader;
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.nio.channels.FileChannel;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
@@ -114,6 +124,8 @@ import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import android.app.AppOpsManager;
+import android.os.SystemProperties;
/**
* WifiService handles remote WiFi operation requests by implementing
@@ -125,6 +137,8 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private static final String TAG = "WifiService";
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ private boolean mIsFactoryResetOn = false;
+ private boolean mSubSystemRestart = false;
private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode";
final WifiStateMachine mWifiStateMachine;
@@ -132,6 +146,19 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private final Context mContext;
private final FrameworkFacade mFacade;
+ private SoftApStateMachine mSoftApStateMachine;
+ private int mStaAndApConcurrency = 0;
+ private String mSoftApInterfaceName = null;
+ private int mSoftApChannel = 0;
+ private static final String SEPARATOR_KEY = "\n";
+ private static final String ENABLE_STA_SAP
+ = "ENABLE_STA_SAP_CONCURRENCY:";
+ private static final String SAP_INTERFACE_NAME
+ = "SAP_INTERFACE_NAME:";
+ private static final String SAP_CHANNEL
+ = "SAP_CHANNEL:";
+ private static final String mConcurrencyCfgTemplateFile =
+ "/etc/wifi/wifi_concurrency_cfg.txt";
private final List<Multicaster> mMulticasters =
new ArrayList<Multicaster>();
private int mMulticastEnabled;
@@ -157,6 +184,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private final WifiCertManager mCertManager;
private final WifiInjector mWifiInjector;
+ private boolean mIsControllerStarted = false;
/**
* Asynchronous channel to WifiStateMachine
*/
@@ -350,6 +378,20 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
mWifiController = new WifiController(mContext, mWifiStateMachine,
mSettingsStore, mWifiLockManager, wifiThread.getLooper(), mFacade);
+ if (ensureConcurrencyFileExist()) {
+ readConcurrencyConfig();
+ }
+ if (mStaAndApConcurrency == 1) {
+ mWifiStateMachine.setStaSoftApConcurrency();
+ mSoftApStateMachine = mWifiStateMachine.getSoftApStateMachine();
+ if (mSoftApInterfaceName != null) {
+ mSoftApStateMachine.setSoftApInterfaceName(mSoftApInterfaceName);
+ }
+ if (mSoftApChannel != 0) {
+ mSoftApStateMachine.setSoftApChannel(mSoftApChannel);
+ }
+ mWifiController.setSoftApStateMachine(mSoftApStateMachine);
+ }
// Set the WifiController for WifiLastResortWatchdog
mWifiInjector.getWifiLastResortWatchdog().setWifiController(mWifiController);
@@ -413,6 +455,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mInIdleMode = mPowerManager.isDeviceIdleMode();
mWifiController.start();
+ mIsControllerStarted = true;
// If we are already disabled (could be due to airplane mode), avoid changing persist
// state here
@@ -555,6 +598,10 @@ public class WifiServiceImpl extends IWifiManager.Stub {
"ConnectivityService");
}
+ private boolean isStrictOpEnable() {
+ return SystemProperties.getBoolean("persist.sys.strict_op_enable", false);
+ }
+
/**
* see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
* @param enable {@code true} to enable, {@code false} to disable.
@@ -566,7 +613,15 @@ public class WifiServiceImpl extends IWifiManager.Stub {
enforceChangePermission();
Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
-
+ if(isStrictOpEnable()){
+ if((Binder.getCallingUid() > 10000) && (packageName.indexOf("android.uid.systemui") !=0) && (packageName.indexOf("android.uid.system") != 0)) {
+ AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ int result = mAppOpsManager.noteOp(AppOpsManager.OP_CHANGE_WIFI_STATE,Binder.getCallingUid(),packageName);
+ if(result == AppOpsManager.MODE_IGNORED){
+ return false;
+ }
+ }
+ }
/*
* Caller might not have WRITE_SECURE_SETTINGS,
* only CHANGE_WIFI_STATE is enforced
@@ -581,6 +636,10 @@ public class WifiServiceImpl extends IWifiManager.Stub {
Binder.restoreCallingIdentity(ident);
}
+ if (!mIsControllerStarted) {
+ Slog.e(TAG,"WifiController is not yet started, abort setWifiEnabled");
+ return false;
+ }
if (mPermissionReviewRequired) {
final int wiFiEnabledState = getWifiEnabledState();
@@ -1236,7 +1295,10 @@ public class WifiServiceImpl extends IWifiManager.Stub {
if (dhcpResults.ipAddress != null &&
dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
- info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
+ info.ipAddress = NetworkUtils.inetAddressToInt(
+ (Inet4Address) dhcpResults.ipAddress.getAddress());
+ info.netmask = NetworkUtils.prefixLengthToNetmaskInt(
+ dhcpResults.ipAddress.getNetworkPrefixLength());
}
if (dhcpResults.gateway != null) {
@@ -1429,6 +1491,54 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
} else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
handleIdleModeChanged();
+ } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN);
+ if (state == WifiManager.WIFI_STATE_ENABLED) {
+ if (mIsFactoryResetOn) {
+ resetWifiNetworks();
+ mIsFactoryResetOn = false;
+ }
+ if (mSubSystemRestart) {
+ setWifiApEnabled(null, true);
+ }
+ } else if ( state == WifiManager.WIFI_STATE_DISABLED) {
+ if (mSubSystemRestart) {
+ try {
+ setWifiEnabled(mContext.getPackageName(), true);
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+ }
+ }
+ } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+ int wifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
+ WifiManager.WIFI_AP_STATE_FAILED);
+ if (mSubSystemRestart) {
+ if (wifiApState == WifiManager.WIFI_AP_STATE_DISABLED) {
+ if (getWifiEnabledState() == WifiManager.WIFI_STATE_ENABLED) {
+ try {
+ setWifiEnabled(mContext.getPackageName(), false);
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+ } else {
+ /**
+ * STA in DISABLED state, hence just restart SAP.
+ * This should cover two scenarios
+ * 1. Only SAP ON ( before SSR ) in STA + SAP.
+ * 2. No STA + SAP.
+ */
+ setWifiApEnabled(null, true);
+ mSubSystemRestart = false;
+ }
+ } else if (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED) {
+ mSubSystemRestart = false;
+ }
+ }
+
+ } else if (action.equals(WifiManager.WIFI_AP_SUB_SYSTEM_RESTART)) {
+ handleSubSystemRestart();
}
}
};
@@ -1485,10 +1595,12 @@ public class WifiServiceImpl extends IWifiManager.Stub {
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-
+ intentFilter.addAction(WifiManager.WIFI_AP_SUB_SYSTEM_RESTART);
+ intentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
boolean trackEmergencyCallState = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
if (trackEmergencyCallState) {
@@ -1748,6 +1860,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public void enableVerboseLogging(int verbose) {
enforceAccessPermission();
mWifiStateMachine.enableVerboseLogging(verbose);
+ mWifiController.enableVerboseLogging(verbose);
mWifiLockManager.enableVerboseLogging(verbose);
}
@@ -1798,6 +1911,21 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
}
+ public boolean getWifiStaSapConcurrency() {
+ return mStaAndApConcurrency == 1;
+ }
+
+ private void resetWifiNetworks() {
+ // Delete all Wifi SSIDs
+ List<WifiConfiguration> networks = getConfiguredNetworks();
+ if (networks != null) {
+ for (WifiConfiguration config : networks) {
+ removeNetwork(config.networkId);
+ }
+ saveConfiguration();
+ }
+ }
+
public void factoryReset() {
enforceConnectivityInternalPermission();
@@ -1811,19 +1939,16 @@ public class WifiServiceImpl extends IWifiManager.Stub {
}
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
- // Enable wifi
- try {
- setWifiEnabled(mContext.getOpPackageName(), true);
- } catch (RemoteException e) {
- /* ignore - local call */
- }
- // Delete all Wifi SSIDs
- List<WifiConfiguration> networks = getConfiguredNetworks();
- if (networks != null) {
- for (WifiConfiguration config : networks) {
- removeNetwork(config.networkId);
+ if (getWifiEnabledState() == WifiManager.WIFI_STATE_ENABLED) {
+ resetWifiNetworks();
+ } else {
+ mIsFactoryResetOn = true;
+ // Enable wifi
+ try {
+ setWifiEnabled(mContext.getOpPackageName(), true);
+ } catch (RemoteException e) {
+ /* ignore - local call */
}
- saveConfiguration();
}
}
}
@@ -1975,4 +2100,101 @@ public class WifiServiceImpl extends IWifiManager.Stub {
enforceConnectivityInternalPermission();
mWifiStateMachine.enableWifiConnectivityManager(enabled);
}
+
+ private void readConcurrencyConfig() {
+ BufferedReader reader = null;
+ try {
+ if (mConcurrencyCfgTemplateFile != null) {
+ Log.d(TAG, "mConcurrencyCfgTemplateFile : "
+ + mConcurrencyCfgTemplateFile);
+ }
+ reader = new BufferedReader(new FileReader(mConcurrencyCfgTemplateFile));
+ for (String key = reader.readLine(); key != null;
+ key = reader.readLine()) {
+ if (key != null) {
+ Log.d(TAG, "mConcurrencyCfgTemplateFile line: " + key);
+ }
+ if (key.startsWith(ENABLE_STA_SAP)) {
+ String st = key.replace(ENABLE_STA_SAP, "");
+ st = st.replace(SEPARATOR_KEY, "");
+ try {
+ mStaAndApConcurrency = Integer.parseInt(st);
+ Log.d(TAG,"mConcurrencyCfgTemplateFile EnableConcurrency = "
+ + mStaAndApConcurrency);
+ } catch (NumberFormatException e) {
+ Log.e(TAG,"mConcurrencyCfgTemplateFile: incorrect format :"
+ + key);
+ }
+ }
+ if (key.startsWith(SAP_INTERFACE_NAME)) {
+ String st = key.replace(SAP_INTERFACE_NAME, "");
+ st = st.replace(SEPARATOR_KEY, "");
+ try {
+ mSoftApInterfaceName = st;
+ Log.d(TAG,"mConcurrencyCfgTemplateFile SAPInterfaceName = "
+ + mSoftApInterfaceName);
+ } catch (NumberFormatException e) {
+ Log.e(TAG,"mConcurrencyCfgTemplateFile: incorrect format :"
+ + key);
+ }
+ }
+ if (key.startsWith(SAP_CHANNEL)) {
+ String st = key.replace(SAP_CHANNEL, "");
+ st = st.replace(SEPARATOR_KEY, "");
+ try {
+ mSoftApChannel = Integer.parseInt(st);
+ Log.d(TAG,"mConcurrencyCfgTemplateFile SAPChannel = "
+ + mSoftApChannel);
+ } catch (NumberFormatException e) {
+ Log.e(TAG,"mConcurrencyCfgTemplateFile: incorrect format :"
+ + key);
+ }
+ }
+ }
+ } catch (EOFException ignore) {
+ if (reader != null) {
+ try {
+ reader.close();
+ reader = null;
+ } catch (Exception e) {
+ Log.e(TAG, "mConcurrencyCfgTemplateFile: Error closing file" + e);
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "mConcurrencyCfgTemplateFile: Error parsing configuration" + e);
+ }
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (Exception e) {
+ Log.e(TAG, "mConcurrencyCfgTemplateFile: Error closing file" + e);
+ }
+ }
+ }
+
+ private boolean ensureConcurrencyFileExist() {
+ FileOutputStream dstStream = null;
+ FileInputStream srcStream = null;
+ DataInputStream in = null;
+ // check ConcurrencyCfgTemplateFile exist
+ try {
+ in = new DataInputStream(new BufferedInputStream(new FileInputStream(
+ mConcurrencyCfgTemplateFile)));
+ } catch (Exception e) {
+ Log.e(TAG, "ensureConcurrencyFile template file doesnt exist" + e);
+ return false;
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {}
+ }
+ }
+ return true;
+ }
+
+ private void handleSubSystemRestart() {
+ mSubSystemRestart = true;
+ setWifiApEnabled(null, false);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 89aabcf3e..f34d0b1e9 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -26,6 +26,7 @@ import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+import static android.provider.Settings.Secure.WIFI_DISCONNECT_DELAY_DURATION;
import android.Manifest;
import android.app.ActivityManager;
@@ -94,6 +95,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.os.SystemProperties;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -202,6 +204,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
private final PropertyService mPropertyService;
private final BuildProperties mBuildProperties;
private final WifiCountryCode mCountryCode;
+ private boolean mStaAndAPConcurrency = false;
+ private SoftApStateMachine mSoftApStateMachine = null;
+
+
+ private int mNumSelectiveChannelScan = 0;
+ private int mMaxInitialSavedChannelScan;
/* Scan results handling */
private List<ScanDetail> mScanResults = new ArrayList<>();
@@ -218,6 +226,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
private final boolean mBackgroundScanSupported;
private final String mInterfaceName;
+ /* The interface for ipManager */
+ private String mDataInterfaceName;
/* Tethering interface could be separate from wlan interface */
private String mTetherInterfaceName;
@@ -263,6 +273,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
private boolean testNetworkDisconnect = false;
private boolean mEnableRssiPolling = false;
+ private boolean mIsRandomMacCleared = false;
private int mRssiPollToken = 0;
/* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
* In CONNECT_MODE, the STA can scan and connect to an access point
@@ -406,6 +417,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
autoRoamSetBSSID(mWifiConfigManager.getWifiConfiguration(netId), bssid);
}
+ public int getScanCount() {
+ return mNumSelectiveChannelScan;
+ }
+
+ public int getMaxConfiguredScanCount() {
+ return mMaxInitialSavedChannelScan;
+ }
+ public void setScanCount(int count) {
+ mNumSelectiveChannelScan = count;
+ }
+
public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) {
boolean ret = true;
if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any";
@@ -527,7 +549,21 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
- private final IpManager mIpManager;
+ private IpManager mIpManager;
+ public SoftApStateMachine getSoftApStateMachine() {
+ return mSoftApStateMachine;
+ }
+
+ public void setStaSoftApConcurrency() {
+ mStaAndAPConcurrency = true;
+ mSoftApStateMachine =
+ new SoftApStateMachine(mContext, this, mFacade, mInterfaceName,
+ mWifiConfigManager, mWifiMonitor,
+ mBackupManagerProxy,
+ mNwService, mBatteryStats, mCountryCode);
+ logd("mSoftApStateMachine is created");
+ }
+
private AlarmManager mAlarmManager;
private PendingIntent mScanIntent;
@@ -568,6 +604,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// Provide packet filter capabilities to ConnectivityService.
private final NetworkMisc mNetworkMisc = new NetworkMisc();
+ private static final int WIFI_AUTO_CONNECT_TYPE_AUTO = 0;
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
@@ -875,6 +912,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
private long mSupplicantScanIntervalMs;
/**
+ * Delay configured for delayed disconnect.
+ **/
+ private int mDisconnectDelayDuration;
+
+ /**
* Minimum time interval between enabling all networks.
* A device can end up repeatedly connecting to a bad network on screen on/off toggle
* due to enabling every time. We add a threshold to avoid this.
@@ -1019,6 +1061,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// TODO refactor WifiNative use of context out into it's own class
mWifiNative.initContext(mContext);
mInterfaceName = mWifiNative.getInterfaceName();
+
+ updateDataInterface();
+
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
mBatteryStats = IBatteryStats.Stub.asInterface(mFacade.getService(
BatteryStats.SERVICE_NAME));
@@ -1058,7 +1103,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
mLastSignalLevel = -1;
- mIpManager = mFacade.makeIpManager(mContext, mInterfaceName, new IpManagerCallback());
+ mIpManager = mFacade.makeIpManager(mContext, mDataInterfaceName, new IpManagerCallback());
mIpManager.setMulticastFilter(true);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -1080,6 +1125,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mPrimaryDeviceType = mContext.getResources().getString(
R.string.config_wifi_p2p_device_type);
+ mMaxInitialSavedChannelScan = mContext.getResources().getInteger(
+ R.integer.config_max_initial_scans_on_selective_channels);
+
mCountryCode = countryCode;
mUserWantsSuspendOpt.set(mFacade.getIntegerSetting(mContext,
@@ -1130,6 +1178,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
},
new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
+ mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.WIFI_AUTO_CONNECT_TYPE), false,
+ new ContentObserver(getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ checkAndSetAutoConnection();
+ }
+ });
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName());
@@ -1343,6 +1399,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
if (mWifiConnectivityManager != null) {
mWifiConnectivityManager.enableVerboseLogging(mVerboseLoggingLevel);
}
+ if (mStaAndAPConcurrency) {
+ mSoftApStateMachine.enableVerboseLogging(mVerboseLoggingLevel);
+ }
}
private static final String SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL = "log.tag.WifiHAL";
@@ -1399,6 +1458,32 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
return mWifiConfigManager.getEnableAutoJoinWhenAssociated();
}
+ private void updateDataInterface() {
+ String defaultRateUpgradeInterfaceName = "bond0"; // interface used for fst
+ int fstEnabled = SystemProperties.getInt("persist.fst.rate.upgrade.en", 0);
+ String prevDataInterfaceName = mDataInterfaceName;
+ String rateUpgradeDataInterfaceName = SystemProperties.get("persist.fst.data.interface",
+ defaultRateUpgradeInterfaceName);
+
+ // When fst is not enabled, data interface is the same as the wlan interface
+ mDataInterfaceName = (fstEnabled == 1) ? rateUpgradeDataInterfaceName : mInterfaceName;
+
+ // as long as we did not change from fst enabled to disabled state
+ // and vise-versa data interface does not change
+ if (mDataInterfaceName.equals(prevDataInterfaceName)) {
+ return;
+ }
+
+ logd("fst " + ((fstEnabled == 1) ? "enabled" : "disabled"));
+
+ if (mIpManager != null) {
+ mIpManager.shutdown();
+ mIpManager = mFacade.makeIpManager(mContext, mDataInterfaceName,
+ new IpManagerCallback());
+ mIpManager.setMulticastFilter(true);
+ }
+ }
+
private boolean setRandomMacOui() {
String oui = mContext.getResources().getString(R.string.config_wifi_random_mac_oui);
if (TextUtils.isEmpty(oui)) {
@@ -1413,6 +1498,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
logd("Setting OUI to " + oui);
return mWifiNative.setScanningMacOui(ouiBytes);
}
+ private boolean clearRandomMacOui() {
+ byte[] ouiBytes = new byte[]{0,0,0};
+ logd("Clear random OUI");
+ return mWifiNative.setScanningMacOui(ouiBytes);
+ }
/**
* ******************************************************
@@ -1575,8 +1665,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
}
if (stats == null || mWifiLinkLayerStatsSupported <= 0) {
- long mTxPkts = mFacade.getTxPackets(mInterfaceName);
- long mRxPkts = mFacade.getRxPackets(mInterfaceName);
+ long mTxPkts = mFacade.getTxPackets(mDataInterfaceName);
+ long mRxPkts = mFacade.getRxPackets(mDataInterfaceName);
mWifiInfo.updatePacketRates(mTxPkts, mRxPkts);
} else {
mWifiInfo.updatePacketRates(stats);
@@ -1626,13 +1716,20 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
Set<Integer> freqs = null;
- if (settings != null && settings.channelSet != null) {
- freqs = new HashSet<Integer>();
- for (WifiChannel channel : settings.channelSet) {
- freqs.add(channel.freqMHz);
+ freqs = new HashSet<Integer>();
+ if (mNumSelectiveChannelScan < mMaxInitialSavedChannelScan) {
+ freqs = mWifiConfigManager.getConfiguredChannelList();
+ }
+ if (freqs != null && (freqs.size() == 0)) {
+ freqs = null;
+ }
+ if (freqs == null) {
+ if (settings != null && settings.channelSet != null) {
+ for (WifiChannel channel : settings.channelSet) {
+ freqs.add(channel.freqMHz);
+ }
}
}
-
// Retrieve the list of hidden networkId's to scan for.
Set<Integer> hiddenNetworkIds = mWifiConfigManager.getHiddenConfiguredNetworkIds();
@@ -1716,6 +1813,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
// ignore all events since WifiStateMachine is registered for the supplicant events
public void onSuccess() {
+ /* As part of optimizing time for initial scans for
+ * saved profiles, increment the scan trigger count
+ * upon receiving a success.
+ */
+ if (mNumSelectiveChannelScan < mMaxInitialSavedChannelScan)
+ mNumSelectiveChannelScan++;
}
public void onFailure(int reason, String description) {
mIsScanOngoing = false;
@@ -1740,9 +1843,26 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
*/
public void setSupplicantRunning(boolean enable) {
if (enable) {
+ WifiNative.setApMode(false);
sendMessage(CMD_START_SUPPLICANT);
} else {
- sendMessage(CMD_STOP_SUPPLICANT);
+ mDisconnectDelayDuration = -1;
+ try {
+ mDisconnectDelayDuration = Settings.Secure.getInt(mContext.getContentResolver(),
+ WIFI_DISCONNECT_DELAY_DURATION,0) ;
+ } catch (NumberFormatException ex) {
+ mDisconnectDelayDuration = 0;
+ Log.e(TAG, " get mDisconnectDelayDuration caught exception ");
+ }
+ if ((mDisconnectDelayDuration > 0) && (mNetworkInfo.getState()
+ == NetworkInfo.State.CONNECTED)) {
+ Intent intent = new Intent(WifiManager.ACTION_WIFI_DISCONNECT_IN_PROGRESS);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ Log.e(TAG, " Disconnection delayed by " + mDisconnectDelayDuration + " seconds");
+ sendMessageDelayed(CMD_STOP_SUPPLICANT, mDisconnectDelayDuration * 1000);
+ } else {
+ sendMessage(CMD_STOP_SUPPLICANT);
+ }
}
}
@@ -1751,6 +1871,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
*/
public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
if (enable) {
+ WifiNative.setApMode(true);
sendMessage(CMD_START_AP, wifiConfig);
} else {
sendMessage(CMD_STOP_AP);
@@ -1758,10 +1879,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
public void setWifiApConfiguration(WifiConfiguration config) {
+ if (mStaAndAPConcurrency) {
+ mSoftApStateMachine.setWifiApConfiguration(config);
+ return ;
+ }
mWifiApConfigStore.setApConfiguration(config);
}
public WifiConfiguration syncGetWifiApConfiguration() {
+ if (mStaAndAPConcurrency) {
+ return mSoftApStateMachine.syncGetWifiApConfiguration();
+ }
return mWifiApConfigStore.getApConfiguration();
}
@@ -1796,6 +1924,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
* TODO: doc
*/
public int syncGetWifiApState() {
+ if (mStaAndAPConcurrency) {
+ return mSoftApStateMachine.syncGetWifiApState();
+ }
return mWifiApState.get();
}
@@ -2329,7 +2460,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
+ if (args != null && args.length > 1 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])
&& WifiMetrics.CLEAN_DUMP_ARG.equals(args[1])) {
// Dump only wifi metrics serialized proto bytes (base64)
updateWifiMetrics();
@@ -3594,7 +3725,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
stopRssiMonitoringOffload();
clearCurrentConfigBSSID("handleNetworkDisconnect");
-
+ if (mContext.getResources().getBoolean(R.bool.wifi_autocon)
+ && !shouldAutoConnect()) {
+ /*
+ * The following logic shall address the requirement for the DUT to
+ * not reconnect to the last connected network when the Auto
+ * Connect is disabled. This asks for the user prompt for any
+ * connection attempt (as per the requirement)
+ */
+ disableLastNetwork();
+ }
stopIpManager();
/* Reset data structures */
@@ -3637,27 +3777,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
void handlePreDhcpSetup() {
- if (!mBluetoothConnectionActive) {
- /*
- * There are problems setting the Wi-Fi driver's power
- * mode to active when bluetooth coexistence mode is
- * enabled or sense.
- * <p>
- * We set Wi-Fi to active mode when
- * obtaining an IP address because we've found
- * compatibility issues with some routers with low power
- * mode.
- * <p>
- * In order for this active power mode to properly be set,
- * we disable coexistence mode until we're done with
- * obtaining an IP address. One exception is if we
- * are currently connected to a headset, since disabling
- * coexistence would interrupt that connection.
- */
- // Disable the coexistence mode
- mWifiNative.setBluetoothCoexistenceMode(
- mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
- }
+ // Disable the coexistence mode
+ mWifiNative.setBluetoothCoexistenceMode(
+ mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
// Disable power save and suspend optimizations during DHCP
// Note: The order here is important for now. Brcm driver changes
@@ -3878,8 +4000,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
}
try {
- mNwService.wifiFirmwareReload(mInterfaceName, "AP");
- if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
+ if (!SystemProperties.getBoolean("ro.disableWifiApFirmwareReload", false)) {
+ mNwService.wifiFirmwareReload(mInterfaceName, "AP");
+ if (DBG) Log.d(TAG, "Firmware reloaded in AP mode");
+ }
} catch (Exception e) {
Log.e(TAG, "Failed to reload AP firmware " + e);
}
@@ -4322,8 +4446,19 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
class InitialState extends State {
@Override
public void enter() {
- mWifiNative.stopHal();
- mWifiNative.unloadDriver();
+ boolean skipUnload = false;
+ if (mStaAndAPConcurrency) {
+ int wifiApState = mSoftApStateMachine.syncGetWifiApState();
+ if ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED)) {
+ log("Avoid unloading driver, AP_STATE is enabled/enabling");
+ skipUnload = true;
+ }
+ }
+ if (!skipUnload) {
+ mWifiNative.stopHal();
+ mWifiNative.unloadDriver();
+ }
if (mWifiP2pChannel == null) {
mWifiP2pChannel = new AsyncChannel();
mWifiP2pChannel.connect(mContext, getHandler(),
@@ -4340,6 +4475,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
logStateAndMessage(message, this);
switch (message.what) {
case CMD_START_SUPPLICANT:
+ /* Stop a running supplicant after a runtime restart
+ * Avoids issues with drivers that do not handle interface down
+ * on a running supplicant properly.
+ */
+ mWifiMonitor.killSupplicant(mP2pSupported);
+
if (mWifiNative.loadDriver()) {
try {
mNwService.wifiFirmwareReload(mInterfaceName, "STA");
@@ -4356,33 +4497,29 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// Ensure interface is down and we have no IP
// addresses before a supplicant start.
mNwService.setInterfaceDown(mInterfaceName);
- mNwService.clearInterfaceAddresses(mInterfaceName);
+ mNwService.clearInterfaceAddresses(mDataInterfaceName);
// Set privacy extensions
- mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
+ mNwService.setInterfaceIpv6PrivacyExtensions(mDataInterfaceName, true);
// IPv6 is enabled only as long as access point is connected since:
// - IPv6 addresses and routes stick around after disconnection
// - kernel is unaware when connected and fails to start IPv6 negotiation
// - kernel can start autoconfiguration when 802.1x is not complete
- mNwService.disableIpv6(mInterfaceName);
+ mNwService.disableIpv6(mDataInterfaceName);
} catch (RemoteException re) {
loge("Unable to change interface settings: " + re);
} catch (IllegalStateException ie) {
loge("Unable to change interface settings: " + ie);
}
- /* Stop a running supplicant after a runtime restart
- * Avoids issues with drivers that do not handle interface down
- * on a running supplicant properly.
- */
- mWifiMonitor.killSupplicant(mP2pSupported);
-
if (mWifiNative.startHal() == false) {
/* starting HAL is optional */
loge("Failed to start HAL");
}
+ updateDataInterface();
+
if (mWifiNative.startSupplicant(mP2pSupported)) {
setSupplicantLogLevel();
setWifiState(WIFI_STATE_ENABLING);
@@ -4477,7 +4614,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
if (mWifiConfigManager.mEnableVerboseLogging.get() > 0) {
enableVerboseLogging(mWifiConfigManager.mEnableVerboseLogging.get());
}
+ if (mContext.getResources().getBoolean(R.bool.wifi_autocon)
+ && !shouldAutoConnect()) {
+ mWifiConfigManager.disableAllNetworksNative();
+ }
initializeWpsDetails();
+ mWifiNative.enableTdlsExtControl();
+ mWifiNative.disableScanOffload();
+ mWifiNative.setP2pDisable();
sendSupplicantConnectionChangedBroadcast(true);
transitionTo(mDriverStartedState);
@@ -4532,6 +4676,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
setRandomMacOui();
mWifiNative.enableAutoConnect(false);
+ checkAndSetAutoConnection();
mCountryCode.setReadyForChange(true);
}
@@ -4775,6 +4920,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiLogger.startLogging(DBG);
mIsRunning = true;
updateBatteryWorkSource(null);
+ mNumSelectiveChannelScan = 0;
/**
* Enable bluetooth coexistence scan mode when bluetooth connection is active.
* When this mode is on, some of the low-level scan parameters used by the
@@ -4898,7 +5044,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
break;
case CMD_START_DRIVER:
if (mOperationalMode == CONNECT_MODE) {
- mWifiConfigManager.enableAllNetworks();
+ if (mContext.getResources().getBoolean(R.bool.wifi_autocon)
+ && !shouldAutoConnect()) {
+ if (DBG) {
+ logd("Auto connect disabled, skip enable networks");
+ }
+ } else {
+ mWifiConfigManager.enableAllNetworks();
+ }
}
break;
case CMD_SET_SUSPEND_OPT_ENABLED:
@@ -5114,7 +5267,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiConfigManager.loadAndEnableAllNetworks();
mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
} else {
- mWifiConfigManager.enableAllNetworks();
+ if (mContext.getResources().getBoolean(R.bool.wifi_autocon)
+ && !shouldAutoConnect()) {
+ if (DBG) {
+ logd("No auto, skip enable networks on mode change");
+ }
+ } else {
+ mWifiConfigManager.enableAllNetworks();
+ }
}
// Loose last selection choice since user toggled WiFi
@@ -5463,6 +5623,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
break;
case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
+ Intent intent = new Intent(WifiManager.ACTION_AUTH_PASSWORD_WRONG);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
mWifiLogger.captureBugReportData(WifiLogger.REPORT_REASON_AUTH_FAILURE);
mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
if (mTargetNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
@@ -5527,7 +5689,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
// If we have COMPLETED a connection to a BSSID, start doing
// DNAv4/DNAv6 -style probing for on-link neighbors of
// interest (e.g. routers); harmless if none are configured.
- if (state == SupplicantState.COMPLETED) {
+ if (isRoaming() && state == SupplicantState.COMPLETED) {
mIpManager.confirmConfiguration();
}
break;
@@ -6151,7 +6313,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
log("Reconfiguring IP on connection");
// TODO: clear addresses and disable IPv6
// to simplify obtainingIpState.
- transitionTo(mObtainingIpState);
+ mWifiNative.disconnect();
+ handleNetworkDisconnect();
+ transitionTo(mDisconnectedState);
}
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
@@ -6243,6 +6407,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
WpsResult wpsResult;
switch (wpsInfo.setup) {
case WpsInfo.PBC:
+ clearRandomMacOui();
+ mIsRandomMacCleared = true;
wpsResult = mWifiConfigManager.startWpsPbc(wpsInfo);
break;
case WpsInfo.KEYPAD:
@@ -6339,6 +6505,25 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
res = mWifiConfigManager.matchProviderWithCurrentNetwork((String) message.obj);
replyToMessage(message, message.what, res);
break;
+ case WifiMonitor.SUBNET_STATUS_UPDATE_EVENT:
+ // subnet status change event comes from the supplicant
+ // after roaming. IP refresh is required if the device
+ // has roamed into a different IP subnet
+ if (DBG) log("SUBNET_STATUS_UPDATE_EVENT event");
+ if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+ int subnetStatus = message.arg1;
+ // 0 = unknown, 1 = unchanged, 2 = changed
+ if (subnetStatus == 2) {
+ if (DBG) log("Change in IP subnet, announce loss of IP reachability");
+ sendMessage(CMD_IP_REACHABILITY_LOST);
+ }
+ }
+ break;
+ case CMD_IP_REACHABILITY_LOST:
+ if (DBG && message.obj != null) log((String) message.obj);
+ handleIpReachabilityLost();
+ transitionTo(mDisconnectingState);
+ break;
default:
return NOT_HANDLED;
}
@@ -7166,8 +7351,20 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
testNetworkDisconnectCounter, 0), 15000);
}
- // Reenable all networks, allow for hidden networks to be scanned
- mWifiConfigManager.enableAllNetworks();
+ if (!getEnableAutoJoinWhenAssociated()) {
+ if (mContext.getResources().getBoolean(R.bool.wifi_autocon)
+ && !shouldAutoConnect()) {
+ if (DBG) {
+ logd("Auto connect disabled, skip enable networks");
+ }
+ } else {
+ // Reenable all networks, allow for hidden networks to be scanned
+ mWifiConfigManager.enableAllNetworks();
+ }
+ } else {
+ // Reenable all networks, allow for hidden networks to be scanned
+ mWifiConfigManager.enableAllNetworks();
+ }
mLastDriverRoamAttempt = 0;
mTargetNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
@@ -7421,6 +7618,25 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mNetworkAgent.onPacketKeepaliveEvent(slot, result);
break;
}
+ case WifiMonitor.SUBNET_STATUS_UPDATE_EVENT:
+ // subnet status change event comes from the supplicant
+ // after roaming. IP refresh is required if the device
+ // has roamed into a different IP subnet
+ if (DBG) log("SUBNET_STATUS_UPDATE_EVENT event");
+ if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+ int subnetStatus = message.arg1;
+ // 0 = unknown, 1 = unchanged, 2 = changed
+ if (subnetStatus == 2) {
+ if (DBG) log("Change in IP subnet, announce loss of IP reachability");
+ sendMessage(CMD_IP_REACHABILITY_LOST);
+ }
+ }
+ break;
+ case CMD_IP_REACHABILITY_LOST:
+ if (DBG && message.obj != null) log((String) message.obj);
+ handleIpReachabilityLost();
+ transitionTo(mDisconnectingState);
+ break;
default:
return NOT_HANDLED;
}
@@ -7765,6 +7981,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
public void exit() {
mWifiConfigManager.enableAllNetworks();
mWifiConfigManager.loadConfiguredNetworks();
+ if (mIsRandomMacCleared) {
+ setRandomMacOui();
+ mIsRandomMacCleared = false;
+ }
}
}
@@ -8341,6 +8561,42 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
return null;
}
+ boolean shouldAutoConnect() {
+ int autoConnectPolicy = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.WIFI_AUTO_CONNECT_TYPE,
+ WIFI_AUTO_CONNECT_TYPE_AUTO);
+ if (DBG) {
+ if (autoConnectPolicy == WIFI_AUTO_CONNECT_TYPE_AUTO) {
+ Log.d(TAG, "Wlan connection type is auto, should auto connect");
+ } else {
+ Log.d(TAG, "Shouldn't auto connect");
+ }
+ }
+ return (autoConnectPolicy == WIFI_AUTO_CONNECT_TYPE_AUTO);
+ }
+
+ void disableLastNetwork() {
+ if (getCurrentState() != mSupplicantStoppingState) {
+ mWifiConfigManager.disableNetwork(mLastNetworkId);
+ }
+ }
+
+ void checkAndSetAutoConnection() {
+ if (mContext.getResources().getBoolean(R.bool.wifi_autocon)) {
+ if (shouldAutoConnect()){
+ mWifiQualifiedNetworkSelector.skipQualifiedNetworkSelectionForAutoConnect(false);
+ } else {
+ mWifiQualifiedNetworkSelector.skipQualifiedNetworkSelectionForAutoConnect(true);
+ /*
+ * This is AutoConnect -> Manual selection case
+ * Device should not auto connect to network, hence
+ * disable supplicants auto connection ability.
+ */
+ mWifiNative.enableAutoConnect(false);
+ }
+ }
+ }
/**
* Check if there is any connection request for WiFi network.
* Note, caller of this helper function must acquire mWifiReqCountLock.
diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java b/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java
index e967212e7..ea94457bb 100644
--- a/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java
@@ -233,12 +233,16 @@ public class PasspointManagementObjectManager {
if (!mEnabled) {
throw new IOException("HS2.0 not enabled on this device");
}
- if (mSPs.containsKey(homeSP.getFQDN())) {
+ if (mSPs.containsKey(homeSP.getFQDN())
+ && getHomeSP(homeSP.getFQDN()).getCredential() != null
+ && getHomeSP(homeSP.getFQDN()).getCredential().getImsi() != null
+ && getHomeSP(homeSP.getFQDN()).getCredential().getImsi()
+ .equals(homeSP.getCredential().getImsi())) {
Log.d(Utils.hs2LogTag(getClass()), "HS20 profile for "
+ homeSP.getFQDN() + " already exists");
return;
}
- Log.d(Utils.hs2LogTag(getClass()), "Adding new HS20 profile for " + homeSP.getFQDN());
+ Log.d(Utils.hs2LogTag(getClass()), "Adding or updating HS20 profile for " + homeSP.getFQDN());
OMAConstructed dummyRoot = new OMAConstructed(null, TAG_PerProviderSubscription, null);
buildHomeSPTree(homeSP, dummyRoot, mSPs.size() + 1);
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index c1d9445b0..8f02b7824 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -186,6 +186,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
public static final int ENABLED = 1;
public static final int DISABLED = 0;
+ static final int P2P_BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
+ static final int P2P_BLUETOOTH_COEXISTENCE_MODE_SENSE = 2;
+
private final boolean mP2pSupported;
private WifiP2pDevice mThisDevice = new WifiP2pDevice();
@@ -198,6 +201,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
/* Invitation to join an existing p2p group */
private boolean mJoinExistingGroup;
+ private boolean mIsInvite = false;
+
/* Track whether we are in p2p discovery. This is used to avoid sending duplicate
* broadcasts
*/
@@ -569,6 +574,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
});
private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
private WifiP2pGroup mGroup;
+ private boolean mIsBTCoexDisabled = false;
+ private boolean mPendingReformGroupIndication = false;
// Saved WifiP2pConfig for an ongoing peer connection. This will never be null.
// The deviceAddress will be an empty string when the device is inactive
@@ -1303,6 +1310,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
@Override
public void enter() {
if (DBG) logd(getName());
+ mIsInvite = false;
mSavedPeerConfig.invalidate();
}
@@ -1398,16 +1406,28 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
mAutonomousGroup = false;
mJoinExistingGroup = true;
+ mIsInvite = true;
transitionTo(mUserAuthorizingInviteRequestState);
break;
case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
- case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
//We let the supplicant handle the provision discovery response
//and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
//Handling provision discovery and issuing a p2p_connect before
//group negotiation comes through causes issues
break;
+ case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
+ WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
+ WifiP2pDevice device = provDisc.device;
+ if (device == null) {
+ Slog.d(TAG, "Device entry is null");
+ break;
+ }
+ notifyP2pProvDiscShowPinRequest(provDisc.pin, device.deviceAddress);
+ mPeers.updateStatus(device.deviceAddress, WifiP2pDevice.INVITED);
+ sendPeersChangedBroadcast();
+ transitionTo(mGroupNegotiationState);
+ break;
case WifiP2pManager.CREATE_GROUP:
mAutonomousGroup = true;
int netId = message.arg1;
@@ -1723,6 +1743,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
@Override
public void enter() {
if (DBG) logd(getName());
+ mPendingReformGroupIndication = false;
}
@Override
@@ -1735,6 +1756,13 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
if (DBG) logd(getName() + " go success");
break;
+ // Action of removing and reforming group will be taken
+ // when we enter in GroupCreatedState
+ case WifiMonitor.P2P_REMOVE_AND_REFORM_GROUP_EVENT:
+ logd("P2P_REMOVE_AND_REFORM_GROUP_EVENT event received"
+ + " in GroupNegotiationState state");
+ mPendingReformGroupIndication = true;
+ break;
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
if (DBG) logd(getName() + " group started");
@@ -1743,7 +1771,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
/*
* update cache information and set network id to mGroup.
*/
- updatePersistentNetworks(NO_RELOAD);
+ updatePersistentNetworks(RELOAD);
String devAddr = mGroup.getOwner().deviceAddress;
mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
mGroup.getNetworkName()));
@@ -1766,6 +1794,9 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
} else {
mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
startIpManager(mGroup.getInterface());
+ mWifiNative.setBluetoothCoexistenceMode(
+ P2P_BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+ mIsBTCoexDisabled = true;
WifiP2pDevice groupOwner = mGroup.getOwner();
WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
if (peer != null) {
@@ -1936,24 +1967,50 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
}
class GroupCreatedState extends State {
+
+ private boolean handlP2pGroupRestart() {
+ boolean remove = true;
+ if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
+ Slog.d(TAG, "Removed P2P group successfully");
+ transitionTo(mOngoingGroupRemovalState);
+ } else {
+ Slog.d(TAG, "Failed to remove the P2P group");
+ handleGroupRemoved();
+ transitionTo(mInactiveState);
+ remove = false;
+ }
+ if (mAutonomousGroup) {
+ Slog.d(TAG, "AutonomousGroup is set, reform P2P Group");
+ sendMessage(WifiP2pManager.CREATE_GROUP);
+ } else {
+ Slog.d(TAG, "AutonomousGroup is not set, will not reform P2P Group");
+ }
+ return remove;
+ }
+
@Override
public void enter() {
- if (DBG) logd(getName());
- // Once connected, peer config details are invalid
- mSavedPeerConfig.invalidate();
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+ logd(getName() + "mPendingReformGroupIndication=" + mPendingReformGroupIndication);
+ if (mPendingReformGroupIndication) {
+ mPendingReformGroupIndication = false;
+ handlP2pGroupRestart();
+ } else {
+ // Once connected, peer config details are invalid
+ mSavedPeerConfig.invalidate();
+ mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
- updateThisDevice(WifiP2pDevice.CONNECTED);
+ updateThisDevice(WifiP2pDevice.CONNECTED);
- //DHCP server has already been started if I am a group owner
- if (mGroup.isGroupOwner()) {
- setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
- }
+ //DHCP server has already been started if I am a group owner
+ if (mGroup.isGroupOwner()) {
+ setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
+ }
- // In case of a negotiation group, connection changed is sent
- // after a client joins. For autonomous, send now
- if (mAutonomousGroup) {
- sendP2pConnectionChangedBroadcast();
+ // In case of a negotiation group, connection changed is sent
+ // after a client joins. For autonomous, send now
+ if (mAutonomousGroup) {
+ sendP2pConnectionChangedBroadcast();
+ }
}
}
@@ -2014,6 +2071,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
break;
case IPM_POST_DHCP_ACTION:
mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
+ enableBTCoex();
break;
case IPM_DHCP_RESULTS:
mDhcpResults = (DhcpResults) message.obj;
@@ -2036,6 +2094,11 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
break;
case WifiP2pManager.REMOVE_GROUP:
if (DBG) logd(getName() + " remove group");
+ /* We need to check BTCOex state, because some times
+ * user can interupt connection before dhcp sucess, then
+ * BTcoex will be in disabled state.
+ */
+ enableBTCoex();
if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
transitionTo(mOngoingGroupRemovalState);
replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
@@ -2059,9 +2122,29 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
*/
case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
if (DBG) logd(getName() + " group removed");
+ /* We need to check BTCOex state, because if group
+ * is removed at GO side before dhcp sucess, then
+ * BTCoex will be in disabled state.
+ */
+ enableBTCoex();
handleGroupRemoved();
+ mWifiNative.p2pFlush();
transitionTo(mInactiveState);
break;
+ case WifiMonitor.P2P_REMOVE_AND_REFORM_GROUP_EVENT:
+ /* First remove p2p group and then restart only if
+ * autonoums group formation is set to true
+ */
+ Slog.d(TAG, "Received event P2P_REMOVE_AND_REFORM_GROUP, remove P2P group");
+ if (handlP2pGroupRestart()) {
+ replyToMessage(message,
+ WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
+ } else {
+ replyToMessage(message,
+ WifiP2pManager.REMOVE_GROUP_FAILED,
+ WifiP2pManager.ERROR);
+ }
+ break;
case WifiMonitor.P2P_DEVICE_LOST_EVENT:
device = (WifiP2pDevice) message.obj;
//Device loss for a connected device indicates it is not in discovery any more
@@ -2140,7 +2223,6 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
mSavedPeerConfig.deviceAddress, false)) {
// not found the client on the list
loge("Already removed the client, ignore");
- break;
}
// try invitation.
sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
@@ -2407,6 +2489,36 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
dialog.show();
}
+ private void notifyP2pProvDiscShowPinRequest(String pin, String peerAddress) {
+ Resources r = Resources.getSystem();
+ final String tempDevAddress = peerAddress;
+ final String tempPin = pin;
+
+ final View textEntryView = LayoutInflater.from(mContext)
+ .inflate(R.layout.wifi_p2p_dialog, null);
+
+ ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
+ addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
+ addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
+
+ AlertDialog dialog = new AlertDialog.Builder(mContext)
+ .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
+ .setView(textEntryView)
+ .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mSavedPeerConfig = new WifiP2pConfig();
+ mSavedPeerConfig.deviceAddress = tempDevAddress;
+ mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
+ mSavedPeerConfig.wps.pin = tempPin;
+ mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP);
+ }
+ })
+ .setCancelable(false)
+ .create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ dialog.show();
+ }
+
private void notifyInvitationReceived() {
Resources r = Resources.getSystem();
final WpsInfo wps = mSavedPeerConfig.wps;
@@ -2590,15 +2702,22 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
* @param config for the peer
*/
private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
+ boolean join = false;
WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
+ if (mIsInvite) {
+ join = true;
+ } else {
+ join = dev.isGroupOwner();
+ }
- String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
+ String pin = mWifiNative.p2pConnect(config, join);
try {
Integer.parseInt(pin);
notifyInvitationSent(pin, config.deviceAddress);
} catch (NumberFormatException ignore) {
// do nothing if p2pConnect did not return a pin
}
+ mIsInvite = false;
}
/**
@@ -2773,6 +2892,11 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
String deviceName = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.WIFI_P2P_DEVICE_NAME);
if (deviceName == null) {
+ String wifi_direct_name = mContext.getResources().getString(
+ R.string.def_wifi_direct_name);
+ if (!TextUtils.isEmpty(wifi_direct_name)){
+ return wifi_direct_name;
+ }
/* We use the 4 digits of the ANDROID_ID to have a friendly
* default that has low likelihood of collision with a peer */
String id = Settings.Secure.getString(mContext.getContentResolver(),
@@ -3207,6 +3331,17 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
return clientInfo;
}
+ /**
+ * Enable BTCOEXMODE after DHCP or GROUP REMOVE
+ */
+ private void enableBTCoex() {
+ if (mIsBTCoexDisabled) {
+ mWifiNative.setBluetoothCoexistenceMode(
+ P2P_BLUETOOTH_COEXISTENCE_MODE_SENSE);
+ mIsBTCoexDisabled = false;
+ }
+ }
+
}
/**
diff --git a/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java
index f0cac0fb6..ac5db5a4f 100644
--- a/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/SupplicantWifiScannerImpl.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
+import android.provider.Settings;
import com.android.internal.R;
import com.android.server.wifi.Clock;
@@ -679,6 +680,14 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
Log.e(TAG, "Set priority failed for: " + network.networkId);
return false;
}
+ int autoConnectPolicy = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.WIFI_AUTO_CONNECT_TYPE,0);
+ if (autoConnectPolicy == 1) {
+ Log.d(TAG,"Do not enable network,since auto connect disabled");
+ return true;
+ }
+
if (!mWifiNative.enableNetworkWithoutConnect(network.networkId)) {
Log.e(TAG, "Enable network failed for: " + network.networkId);
return false;
diff --git a/service/jni/COPYING b/service/jni/COPYING
new file mode 100755
index 000000000..7efce0dee
--- /dev/null
+++ b/service/jni/COPYING
@@ -0,0 +1,22 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+
+See the README file for the current license terms.
+
+This software was previously distributed under BSD/GPL v2 dual license
+terms that allowed either of those license alternatives to be
+selected. As of February 11, 2012, the project has chosen to use only
+the BSD license option for future distribution. As such, the GPL v2
+license option is no longer used. It should be noted that the BSD
+license option (the one with advertisement clause removed) is compatible
+with GPL and as such, does not prevent use of this software in projects
+that use GPL.
+
+Some of the files may still include pointers to GPL version 2 license
+terms. However, such copyright and license notifications are maintained
+only for attribution purposes and any distribution of this software
+after February 11, 2012 is no longer under the GPL v2 option.
diff --git a/service/jni/README b/service/jni/README
new file mode 100644
index 000000000..8de14a64f
--- /dev/null
+++ b/service/jni/README
@@ -0,0 +1,56 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+These programs are licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+This package may include either wpa_supplicant, hostapd, or both. See
+README file respective subdirectories (wpa_supplicant/README or
+hostapd/README) for more details.
+
+Source code files were moved around in v0.6.x releases and compared to
+earlier releases, the programs are now built by first going to a
+subdirectory (wpa_supplicant or hostapd) and creating build
+configuration (.config) and running 'make' there (for Linux/BSD/cygwin
+builds).
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/service/jni/com_android_server_wifi_Gbk2Utf.cpp b/service/jni/com_android_server_wifi_Gbk2Utf.cpp
new file mode 100644
index 000000000..4b8c9b977
--- /dev/null
+++ b/service/jni/com_android_server_wifi_Gbk2Utf.cpp
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#define LOG_TAG "wifi_gbk2utf"
+
+#include "jni.h"
+#include "com_android_server_wifi_Gbk2Utf.h"
+
+#define BUF_SIZE 256
+#define CONVERT_LINE_LEN 2048
+#define CHARSET_CN ("gbk")
+
+namespace android {
+
+static jint DBG = false;
+
+struct accessPointObjectItem *g_pItemList = NULL;
+struct accessPointObjectItem *g_pLastNode = NULL;
+pthread_mutex_t *g_pItemListMutex = NULL;
+
+static void addAPObjectItem(const char *ssid, const char *ssid_utf8)
+{
+ if (NULL == ssid || NULL == ssid_utf8) {
+ ALOGE("ssid or ssid_utf8 is NULL");
+ return;
+ }
+
+ struct accessPointObjectItem *pTmpItemNode = NULL;
+ struct accessPointObjectItem *pItemNode = NULL;
+ bool foundItem = false;
+
+ pthread_mutex_lock(g_pItemListMutex);
+ pTmpItemNode = g_pItemList;
+ while (pTmpItemNode) {
+ if (pTmpItemNode->ssid && (*(pTmpItemNode->ssid) == ssid)) {
+ foundItem = true;
+ break;
+ }
+ pTmpItemNode = pTmpItemNode->pNext;
+ }
+ if (foundItem) {
+ if (DBG)
+ ALOGD("Found AP %s", pTmpItemNode->ssid->string());
+ } else {
+ pItemNode = new struct accessPointObjectItem();
+ if (NULL == pItemNode) {
+ ALOGE("Failed to allocate memory for new item!");
+ goto EXIT;
+ }
+ memset(pItemNode, 0, sizeof(accessPointObjectItem));
+ pItemNode->ssid_utf8 = new String8(ssid_utf8);
+ if (NULL == pItemNode->ssid_utf8) {
+ ALOGE("Failed to allocate memory for new ssid_utf8!");
+ delete pItemNode;
+ goto EXIT;
+ }
+ pItemNode->ssid = new String8(ssid);
+ if (NULL == pItemNode->ssid) {
+ ALOGE("Failed to allocate memory for new ssid!");
+ delete pItemNode;
+ goto EXIT;
+ }
+
+ pItemNode->pNext = NULL;
+ if (DBG)
+ ALOGD("AP doesn't exist, new one for %s", ssid);
+ if (NULL == g_pItemList) {
+ g_pItemList = pItemNode;
+ g_pLastNode = g_pItemList;
+ } else {
+ g_pLastNode->pNext = pItemNode;
+ g_pLastNode = pItemNode;
+ }
+ }
+
+EXIT:
+ pthread_mutex_unlock(g_pItemListMutex);
+}
+
+static int hex2num(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+
+static int hex2byte(const char *hex)
+{
+ int a, b;
+ a = hex2num(*hex++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*hex++);
+ if (b < 0)
+ return -1;
+ return (a << 4) | b;
+}
+
+/* parse SSID string encoded from wpa_supplicant to normal string */
+static size_t ssid_decode(char *buf, size_t maxlen, const char *str)
+{
+ const char *pos = str;
+ size_t len = 0;
+ int val;
+
+ while (*pos) {
+ if (len == maxlen)
+ break;
+ switch (*pos) {
+ case '\\':
+ pos++;
+ switch (*pos) {
+ case '\\':
+ buf[len++] = '\\';
+ pos++;
+ break;
+ case '"':
+ buf[len++] = '"';
+ pos++;
+ break;
+ case 'n':
+ buf[len++] = '\n';
+ pos++;
+ break;
+ case 'r':
+ buf[len++] = '\r';
+ pos++;
+ break;
+ case 't':
+ buf[len++] = '\t';
+ pos++;
+ break;
+ case 'e':
+ buf[len++] = '\e';
+ pos++;
+ break;
+ case 'x':
+ pos++;
+ val = hex2byte(pos);
+ if (val < 0) {
+ val = hex2num(*pos);
+ if (val < 0)
+ break;
+ buf[len++] = val;
+ pos++;
+ } else {
+ buf[len++] = val;
+ pos += 2;
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = *pos++ - '0';
+ if (*pos >= '0' && *pos <= '7')
+ val = val * 8 + (*pos++ - '0');
+ if (*pos >= '0' && *pos <= '7')
+ val = val * 8 + (*pos++ - '0');
+ buf[len++] = val;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ buf[len++] = *pos++;
+ break;
+ }
+ }
+
+ return len;
+}
+
+/* This function can be used to convert SSIDs into printable form. Since wifi
+ * framework layer needs to parse printable form string.
+*/
+static void ssid_encode(char *txt, size_t maxlen, const char *data, unsigned int len)
+{
+ char *end = txt + maxlen;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (txt + 4 > end)
+ break;
+
+ switch (data[i]) {
+ case '\"':
+ *txt++ = '\\';
+ *txt++ = '\"';
+ break;
+ case '\\':
+ *txt++ = '\\';
+ *txt++ = '\\';
+ break;
+ case '\e':
+ *txt++ = '\\';
+ *txt++ = 'e';
+ break;
+ case '\n':
+ *txt++ = '\\';
+ *txt++ = 'n';
+ break;
+ case '\r':
+ *txt++ = '\\';
+ *txt++ = 'r';
+ break;
+ case '\t':
+ *txt++ = '\\';
+ *txt++ = 't';
+ break;
+ default:
+ if (data[i] >= 32 && data[i] < 127) {
+ *txt++ = data[i];
+ } else {
+ txt += snprintf(txt, end - txt, "\\x%02x",
+ data[i]);
+ }
+ break;
+ }
+ }
+ *txt = '\0';
+}
+
+/* check if the SSID string is UTF coded */
+static bool isUTF8String(const char* str, int length)
+{
+ unsigned int nBytes = 0;
+ unsigned char chr;
+ bool bAllAscii = true;
+ for (int i = 0; i < length; i++) {
+ chr = *(str+i);
+ if ((chr & 0x80) != 0) {
+ bAllAscii = false;
+ }
+ if (0 == nBytes) {
+ if (chr >= 0x80) {
+ if (chr >= 0xFC && chr <= 0xFD) {
+ nBytes = 6;
+ } else if (chr >= 0xF8) {
+ nBytes = 5;
+ } else if (chr >= 0xF0) {
+ nBytes = 4;
+ } else if (chr >= 0xE0) {
+ nBytes = 3;
+ } else if (chr >= 0xC0) {
+ nBytes = 2;
+ } else {
+ return false;
+ }
+ nBytes--;
+ }
+ } else {
+ if ((chr & 0xC0) != 0x80) {
+ return false;
+ }
+ nBytes--;
+ }
+ }
+
+ if (nBytes > 0 || bAllAscii) {
+ return false;
+ }
+ return true;
+}
+
+/*
+ * https://en.wikipedia.org/wiki/GBK
+ *
+ * GBK character is encoded as 1 or 2 bytes.
+ * - A single byte with range 0x00-0x7f is ASCII.
+ * - A byte with the high bit set indicates that it is
+ * the first of 2 bytes.
+ * byte1: (0x81-0xFE)
+ * byte2: (0x40-0xFE) except 0x7F
+ *
+ * This function only returns true only it is GBK string
+ * but not all character is ASCII.
+ */
+static bool isGBKString(const char *str, int length) {
+ unsigned char byte1;
+ unsigned char byte2;
+ bool isAllASCII = true;
+
+ for (int i = 0; i < length; i ++) {
+ byte1 = *(str+i);
+
+ if (byte1 >= 0x81 && byte1 < 0xFF && (i+1) < length) {
+ byte2 = *(str+i+1);
+ if (byte2 >= 0x40 && byte2 < 0xFF && byte2 != 0x7F) {
+ // GBK
+ isAllASCII = false;
+ i ++;
+ continue;
+ } else {
+ return false;
+ }
+ } else if (byte1 < 0x80){
+ // ASCII
+ continue;
+ } else {
+ return false;
+ }
+ }
+
+ if (isAllASCII)
+ return false;
+
+ return true;
+}
+
+static void createFromHex(char *buf, int maxlen, const char *str)
+{
+ const char *pos = str;
+ int len = 0;
+ int val;
+
+ while(*pos){
+ if (len == maxlen)
+ break;
+ val = hex2byte(pos);
+ if (val < 0) {
+ val = hex2num(*pos);
+ if (val < 0)
+ break;
+ buf[len++] = val;
+ } else {
+ buf[len++] = val;
+ pos += 2;
+ }
+ }
+}
+
+static size_t createToHex(char *buf, size_t buf_size, const char *str, unsigned int len)
+{
+ size_t i;
+ char *pos = buf, *end = buf + buf_size;
+ int ret;
+ if (buf_size == 0)
+ return 0;
+ for (i = 0; i < len; i++) {
+ ret = snprintf(pos, end - pos, "%02x", str[i]);
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return pos - buf;
+ }
+ pos += ret;
+ }
+ end[-1] = '\0';
+ return pos - buf;
+}
+
+void parseScanResults(String16& str, const char *reply)
+{
+ unsigned int lineBeg = 0, lineEnd = 0;
+ size_t replyLen = strlen(reply);
+ char ssid[BUF_SIZE] = {0};
+ char ssid_utf8[BUF_SIZE] = {0};
+ char ssid_txt[BUF_SIZE] = {0};
+ bool isUTF8 = false, isCh = false;
+ char buf[BUF_SIZE] = {0};
+ String8 line;
+
+ UConverterType conType = UCNV_UTF8;
+ char dest[CONVERT_LINE_LEN] = {0};
+ UErrorCode err = U_ZERO_ERROR;
+ UConverter* pConverter = ucnv_open(CHARSET_CN, &err);
+ if (U_FAILURE(err)) {
+ ALOGE("ucnv_open error");
+ return;
+ }
+
+ /* Parse every line of the reply to construct accessPointObjectItem list */
+ for (lineBeg = 0, lineEnd = 0; lineEnd <= replyLen; ++lineEnd) {
+ if (lineEnd == replyLen || '\n' == reply[lineEnd]) {
+ line.setTo(reply + lineBeg, lineEnd - lineBeg + 1);
+ if (DBG)
+ ALOGD("%s, line=%s ", __FUNCTION__, line.string());
+ if (strncmp(line.string(), "ssid=", 5) == 0) {
+ sscanf(line.string() + 5, "%[^\n]", ssid);
+ ssid_decode(buf,BUF_SIZE,ssid);
+ isUTF8 = isUTF8String(buf,sizeof(buf));
+ isCh = isGBKString(buf, sizeof(buf));
+ if (DBG)
+ ALOGD("%s, ssid = %s, buf = %s,isUTF8= %d, isCh = %d",
+ __FUNCTION__, ssid, buf ,isUTF8, isCh);
+ if (!isUTF8 && isCh) {
+ ucnv_toAlgorithmic(conType, pConverter, dest, CONVERT_LINE_LEN,
+ buf, strlen(buf), &err);
+ if (U_FAILURE(err)) {
+ ALOGE("ucnv_toUChars error");
+ goto EXIT;
+ }
+ ssid_encode(ssid_txt, BUF_SIZE, dest, strlen(dest));
+ if (DBG)
+ ALOGD("%s, ssid_txt = %s", __FUNCTION__,ssid_txt);
+ str += String16("ssid=");
+ str += String16(ssid_txt);
+ str += String16("\n");
+ memset(ssid_utf8, 0, BUF_SIZE);
+ strlcpy(ssid_utf8, dest, BUF_SIZE);
+ memset(dest, 0, CONVERT_LINE_LEN);
+ memset(ssid_txt, 0, BUF_SIZE);
+ } else {
+ memset(buf, 0, BUF_SIZE);
+ str += String16(line.string());
+ }
+ } else if (strncmp(line.string(), "====", 4) == 0) {
+ if (DBG)
+ ALOGD("After sscanf,ssid:%s, isCh:%d",
+ ssid, isCh);
+ if( !isUTF8 && isCh){
+ addAPObjectItem(buf, ssid_utf8);
+ memset(buf, 0, BUF_SIZE);
+ }
+ }
+ if (strncmp(line.string(), "ssid=", 5) != 0)
+ str += String16(line.string());
+ lineBeg = lineEnd + 1;
+ }
+ }
+
+EXIT:
+ ucnv_close(pConverter);
+}
+
+void constructSsid(String16& str, const char *reply)
+{
+ char ssid[BUF_SIZE] = {0};
+ char buf[BUF_SIZE] = {0};
+ char ssid_txt[BUF_SIZE] ={0};
+ bool isUTF8 = false, isCh = false;
+
+ char dest[CONVERT_LINE_LEN] = {0};
+ UConverterType conType = UCNV_UTF8;
+ UErrorCode err = U_ZERO_ERROR;
+ UConverter* pConverter = ucnv_open(CHARSET_CN, &err);
+ if (U_FAILURE(err)) {
+ ALOGE("ucnv_open error");
+ return;
+ }
+ sscanf(reply, "%[^\n]", ssid);
+ if (DBG)
+ ALOGD("%s, ssid = %s", __FUNCTION__, ssid);
+ createFromHex(buf, BUF_SIZE, ssid);
+ isUTF8 = isUTF8String(buf, sizeof(buf));
+ isCh = isGBKString(buf, sizeof(buf));
+ if (!isUTF8 && isCh) {
+ ucnv_toAlgorithmic(conType, pConverter, dest, CONVERT_LINE_LEN,
+ buf, strlen(buf), &err);
+ if (U_FAILURE(err)) {
+ ALOGE("ucnv_toUChars error");
+ goto EXIT;
+ }
+ createToHex(ssid_txt, strlen(dest)*2 + 1, dest, strlen(dest));
+ if (DBG)
+ ALOGD("%s, ssid_txt = %s, dest = %s \n" ,
+ __FUNCTION__, ssid_txt, dest);
+ str += String16(ssid_txt);
+ str += String16("\n");
+ memset(dest, 0, CONVERT_LINE_LEN);
+ memset(buf, 0, BUF_SIZE);
+ memset(ssid_txt, 0, BUF_SIZE);
+ } else {
+ memset(buf, 0, BUF_SIZE);
+ str += String16(reply);
+ }
+
+EXIT:
+ ucnv_close(pConverter);
+}
+
+jboolean setNetworkVariable(char *buf)
+{
+ struct accessPointObjectItem *pTmpItemNode = NULL;
+ bool gbk_found = false;
+
+ unsigned int netId;
+ char name[BUF_SIZE] = {0};
+ char value[BUF_SIZE] = {0};
+ char interface[BUF_SIZE] = {0};
+ char dummy[BUF_SIZE] = {0};
+ char ssid[BUF_SIZE] = {0};
+ if (strnlen(buf, BUF_SIZE) == BUF_SIZE) {
+ ALOGE("setNetworkVariable failed due to invalid length");
+ return JNI_FALSE;
+ }
+
+ /* parse SET_NETWORK command*/
+ sscanf(buf, "%s %s %d %s %s", interface, dummy, &netId, name, value);
+
+ /* L Framework will convert string to HEX, so we convert it back here for comparation */
+ if (0 == strncmp(name, "ssid", 4)) {
+ createFromHex(ssid, BUF_SIZE, value);
+ }
+
+ if (DBG)
+ ALOGD("parse SET_NETWORK command success, netId = %d, name = %s, value =%s, length=%d",
+ netId, name, value, strlen(value));
+
+ if (NULL == g_pItemListMutex) {
+ /* Driver is unloaded, g_pItemList, g_pItemListMutex are NULL */
+ return JNI_TRUE;
+ }
+ pthread_mutex_lock(g_pItemListMutex);
+ pTmpItemNode = g_pItemList;
+ if (NULL == pTmpItemNode) {
+ if (DBG)
+ ALOGD("g_pItemList is NULL");
+ }
+ while (pTmpItemNode) {
+ if (pTmpItemNode->ssid_utf8) {
+ ALOGD("ssid_utf8 = %s, length=%d, value =%s, length=%d",
+ pTmpItemNode->ssid_utf8->string(),strlen(pTmpItemNode->ssid_utf8->string()), ssid, strlen(ssid));
+
+ if (0 == strcmp(pTmpItemNode->ssid_utf8->string(), ssid)) {
+ gbk_found = true;
+ break;
+ }
+ }
+ pTmpItemNode = pTmpItemNode->pNext;
+ }
+
+ if (0 == strncmp(name, "ssid", 4) && gbk_found) {
+ snprintf(buf, BUF_SIZE, "%s SET_NETWORK %d ssid \"%s\"", interface, netId, pTmpItemNode->ssid->string());
+ if (DBG)
+ ALOGD("new SET_NETWORK command is: %s", buf);
+ }
+
+ pthread_mutex_unlock(g_pItemListMutex);
+
+
+ return JNI_TRUE;
+}
+
+void constructEventSsid(char *eventstr)
+{
+ char *tmp = NULL;
+ char ssid[BUF_SIZE] = {0};
+ char ssid_txt[BUF_SIZE] = {0};
+ char buf[BUF_SIZE] = {0};
+ bool isUTF8 = false, isCh = false;
+
+ UConverterType conType = UCNV_UTF8;
+ char dest[CONVERT_LINE_LEN] = {0};
+ UErrorCode err = U_ZERO_ERROR;
+ UConverter* pConverter = ucnv_open(CHARSET_CN, &err);
+ if (U_FAILURE(err)) {
+ ALOGE("ucnv_open error");
+ return;
+ }
+
+ tmp = strstr(eventstr, " SSID");
+ if (tmp&&(strlen(tmp) > 6 )) {
+ if(!strstr(tmp,"="))
+ sscanf(tmp + 7, "%[^\']", ssid);
+ else
+ sscanf(tmp + 6, "%s", ssid);
+ if (DBG)
+ ALOGD("%s, SSID = %s", __FUNCTION__, ssid);
+ ssid_decode(buf,BUF_SIZE,ssid);
+ isUTF8 = isUTF8String(buf,sizeof(buf));
+ isCh = isGBKString(buf, sizeof(buf));
+ if (!isUTF8 && isCh) {
+ ucnv_toAlgorithmic(conType, pConverter, dest, CONVERT_LINE_LEN,
+ buf, strlen(buf), &err);
+ if (U_FAILURE(err)) {
+ ALOGE("ucnv_toUChars error");
+ goto EXIT;
+ }
+ ssid_encode(ssid_txt, BUF_SIZE, dest, strlen(dest));
+ if (!strstr(tmp,"="))
+ snprintf(eventstr + (strlen(eventstr) - strlen(tmp)), strlen(eventstr), " SSID \'%s\'", ssid_txt);
+ else
+ snprintf(eventstr + (strlen(eventstr) - strlen(tmp)), strlen(eventstr), " SSID=%s", ssid_txt);
+ if (DBG)
+ ALOGD("%s, ssid_txt = %s, eventsrt = %s", __FUNCTION__, ssid_txt, eventstr);
+ }
+ }
+
+EXIT:
+ ucnv_close(pConverter);
+}
+
+} //namespace android
diff --git a/service/jni/com_android_server_wifi_Gbk2Utf.h b/service/jni/com_android_server_wifi_Gbk2Utf.h
new file mode 100644
index 000000000..37e7a2b75
--- /dev/null
+++ b/service/jni/com_android_server_wifi_Gbk2Utf.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <pthread.h>
+#include <unicode/ucnv.h>
+#include <unicode/ucsdet.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/wireless.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+namespace android {
+
+struct accessPointObjectItem {
+ String8 *ssid_utf8;
+ String8 *ssid;
+ struct accessPointObjectItem *pNext;
+};
+
+extern void parseScanResults(String16& str, const char *reply);
+
+extern void constructSsid(String16& str, const char *reply);
+
+extern void constructEventSsid(char *eventstr);
+
+extern jboolean setNetworkVariable(char *buf);
+
+} //namespace android
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index ad7d464ae..7e70d95a7 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -20,9 +20,10 @@
#include "JniConstants.h"
#include <ScopedUtfChars.h>
#include <ScopedBytes.h>
-#include <utils/misc.h>
-#include <utils/Log.h>
-#include <utils/String16.h>
+//#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+//#include <utils/Log.h>
+//#include <utils/String16.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/socket.h>
@@ -43,6 +44,11 @@
#define EVENT_BUF_SIZE 2048
#define WAKE_REASON_TYPE_MAX 10
+#define CONVERT_LINE_LEN 2048
+#define CHARSET_CN ("gbk")
+
+#include "com_android_server_wifi_Gbk2Utf.h"
+
namespace android {
extern "C"
@@ -52,13 +58,21 @@ static jint DBG = false;
//Please put all HAL function call here and call from the function table instead of directly call
wifi_hal_fn hal_fn;
+extern struct accessPointObjectItem *g_pItemList;
+extern struct accessPointObjectItem *g_pLastNode;
+extern pthread_mutex_t *g_pItemListMutex;
+extern String8 *g_pCurrentSSID;
static bool doCommand(JNIEnv* env, jstring javaCommand,
char* reply, size_t reply_len) {
ScopedUtfChars command(env, javaCommand);
if (command.c_str() == NULL) {
return false; // ScopedUtfChars already threw on error.
}
-
+ if(strstr(command.c_str(), "SET_NETWORK")) {
+ if(!setNetworkVariable((char *)command.c_str())) {
+ return false;
+ }
+ }
if (DBG) {
ALOGD("doCommand: %s", command.c_str());
}
@@ -101,10 +115,30 @@ static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) {
// Send a command to the supplicant, and return the reply as a String.
static jstring doStringCommand(JNIEnv* env, jstring javaCommand) {
char reply[REPLY_BUF_SIZE];
+ ScopedUtfChars command(env, javaCommand);
+ if (command.c_str() == NULL) {
+ return NULL;
+ }
if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
return NULL;
}
- return env->NewStringUTF(reply);
+ if (DBG) ALOGD("cmd = %s, reply: %s", command.c_str(), reply);
+ String16 str;
+ if (strstr(command.c_str(),"BSS RANGE=")) {
+ parseScanResults(str,reply);
+ } else if (strstr(command.c_str(),"GET_NETWORK") &&
+ strstr(command.c_str(),"ssid") && !strstr(command.c_str(),"bssid")
+ && !strstr(command.c_str(),"scan_ssid")){
+ constructSsid(str, reply);
+ } else {
+ str += String16((char *)reply);
+ }
+ return env->NewString((const jchar *)str.string(), str.size());
+}
+
+static jboolean android_net_wifi_setApMode(JNIEnv* env, jobject, jboolean enable)
+{
+ return (jboolean)(::wifi_set_mode(enable ? 1 : 0) == 0);
}
static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jclass)
@@ -114,11 +148,41 @@ static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jclass)
static jboolean android_net_wifi_loadDriver(JNIEnv* env, jclass)
{
+ g_pItemListMutex = new pthread_mutex_t;
+ if (NULL == g_pItemListMutex) {
+ ALOGE("Failed to allocate memory for g_pItemListMutex!");
+ return JNI_FALSE;
+ }
+ pthread_mutex_init(g_pItemListMutex, NULL);
return (::wifi_load_driver() == 0);
}
static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jclass)
{
+ if (g_pItemListMutex != NULL) {
+ pthread_mutex_lock(g_pItemListMutex);
+ struct accessPointObjectItem *pCurrentNode = g_pItemList;
+ struct accessPointObjectItem *pNextNode = NULL;
+ while (pCurrentNode) {
+ pNextNode = pCurrentNode->pNext;
+ if (NULL != pCurrentNode->ssid) {
+ delete pCurrentNode->ssid;
+ pCurrentNode->ssid = NULL;
+ }
+ if (NULL != pCurrentNode->ssid_utf8) {
+ delete pCurrentNode->ssid_utf8;
+ pCurrentNode->ssid_utf8 = NULL;
+ }
+ delete pCurrentNode;
+ pCurrentNode = pNextNode;
+ }
+ g_pItemList = NULL;
+ g_pLastNode = NULL;
+ pthread_mutex_unlock(g_pItemListMutex);
+ pthread_mutex_destroy(g_pItemListMutex);
+ delete g_pItemListMutex;
+ g_pItemListMutex = NULL;
+ }
return (::wifi_unload_driver() == 0);
}
@@ -147,6 +211,9 @@ static jstring android_net_wifi_waitForEvent(JNIEnv* env, jclass)
char buf[EVENT_BUF_SIZE];
int nread = ::wifi_wait_for_event(buf, sizeof buf);
if (nread > 0) {
+ if (strstr(buf, " SSID=") || strstr(buf, " SSID ")){
+ constructEventSsid(buf);
+ }
return env->NewStringUTF(buf);
} else {
return NULL;
@@ -2534,6 +2601,7 @@ static JNINativeMethod gWifiMethods[] = {
{ "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
{ "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
(void*) android_net_wifi_doStringCommand },
+ { "setApMode", "(Z)Z", (void*) android_net_wifi_setApMode},
{ "startHalNative", "()Z", (void*) android_net_wifi_startHal },
{ "stopHalNative", "()V", (void*) android_net_wifi_stopHal },
{ "waitForHalEventNative", "()V", (void*) android_net_wifi_waitForHalEvents },