From ffadfb9ffdced62db215319d3edc7717802088fb Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Fri, 6 Dec 2013 15:12:41 -0800 Subject: Move Wifi/P2p service components under services Some methods need to be public, since frameworks/base complies before frameworks/base/services; and services takes build dependency on base. Similar issue exists with WifiEnterpriseConfig constants. Bug: 9907308 Change-Id: Ied0e3dee0b25c939067dbc66867a9814b3b3b68e --- .../java/android/net/wifi/NetworkUpdateResult.java | 70 - wifi/java/android/net/wifi/StateChangeResult.java | 38 - wifi/java/android/net/wifi/SupplicantState.java | 6 +- .../android/net/wifi/SupplicantStateTracker.java | 361 -- wifi/java/android/net/wifi/WifiApConfigStore.java | 211 - wifi/java/android/net/wifi/WifiConfigStore.java | 2022 --------- wifi/java/android/net/wifi/WifiConfiguration.java | 2 +- .../android/net/wifi/WifiEnterpriseConfig.java | 134 +- wifi/java/android/net/wifi/WifiInfo.java | 27 +- wifi/java/android/net/wifi/WifiManager.java | 3 + wifi/java/android/net/wifi/WifiMonitor.java | 936 ----- wifi/java/android/net/wifi/WifiNative.java | 970 ----- wifi/java/android/net/wifi/WifiStateMachine.java | 4408 -------------------- .../android/net/wifi/WifiWatchdogStateMachine.java | 1209 ------ wifi/java/android/net/wifi/p2p/WifiP2pConfig.java | 3 +- wifi/java/android/net/wifi/p2p/WifiP2pDevice.java | 2 +- .../android/net/wifi/p2p/WifiP2pDeviceList.java | 6 +- .../android/net/wifi/p2p/WifiP2pGroupList.java | 27 +- wifi/java/android/net/wifi/p2p/WifiP2pService.java | 2949 ------------- 19 files changed, 145 insertions(+), 13239 deletions(-) delete mode 100644 wifi/java/android/net/wifi/NetworkUpdateResult.java delete mode 100644 wifi/java/android/net/wifi/StateChangeResult.java delete mode 100644 wifi/java/android/net/wifi/SupplicantStateTracker.java delete mode 100644 wifi/java/android/net/wifi/WifiApConfigStore.java delete mode 100644 wifi/java/android/net/wifi/WifiConfigStore.java delete mode 100644 wifi/java/android/net/wifi/WifiMonitor.java delete mode 100644 wifi/java/android/net/wifi/WifiNative.java delete mode 100644 wifi/java/android/net/wifi/WifiStateMachine.java delete mode 100644 wifi/java/android/net/wifi/WifiWatchdogStateMachine.java delete mode 100644 wifi/java/android/net/wifi/p2p/WifiP2pService.java (limited to 'wifi/java/android/net') diff --git a/wifi/java/android/net/wifi/NetworkUpdateResult.java b/wifi/java/android/net/wifi/NetworkUpdateResult.java deleted file mode 100644 index 234bbe1..0000000 --- a/wifi/java/android/net/wifi/NetworkUpdateResult.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 android.net.wifi; - -import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; - -class NetworkUpdateResult { - int netId; - boolean ipChanged; - boolean proxyChanged; - boolean isNewNetwork = false; - - public NetworkUpdateResult(int id) { - netId = id; - ipChanged = false; - proxyChanged = false; - } - - public NetworkUpdateResult(boolean ip, boolean proxy) { - netId = INVALID_NETWORK_ID; - ipChanged = ip; - proxyChanged = proxy; - } - - public void setNetworkId(int id) { - netId = id; - } - - public int getNetworkId() { - return netId; - } - - public void setIpChanged(boolean ip) { - ipChanged = ip; - } - - public boolean hasIpChanged() { - return ipChanged; - } - - public void setProxyChanged(boolean proxy) { - proxyChanged = proxy; - } - - public boolean hasProxyChanged() { - return proxyChanged; - } - - public boolean isNewNetwork() { - return isNewNetwork; - } - - public void setIsNewNetwork(boolean isNew) { - isNewNetwork = isNew; - } -} diff --git a/wifi/java/android/net/wifi/StateChangeResult.java b/wifi/java/android/net/wifi/StateChangeResult.java deleted file mode 100644 index c334b91..0000000 --- a/wifi/java/android/net/wifi/StateChangeResult.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2011 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 android.net.wifi; - -/** - * Stores supplicant state change information passed from WifiMonitor to - * a state machine. WifiStateMachine, SupplicantStateTracker and WpsStateMachine - * are example state machines that handle it. - * @hide - */ -public class StateChangeResult { - StateChangeResult(int networkId, WifiSsid wifiSsid, String BSSID, - SupplicantState state) { - this.state = state; - this.wifiSsid= wifiSsid; - this.BSSID = BSSID; - this.networkId = networkId; - } - - int networkId; - WifiSsid wifiSsid; - String BSSID; - SupplicantState state; -} diff --git a/wifi/java/android/net/wifi/SupplicantState.java b/wifi/java/android/net/wifi/SupplicantState.java index 4a2037d..369d3a8 100644 --- a/wifi/java/android/net/wifi/SupplicantState.java +++ b/wifi/java/android/net/wifi/SupplicantState.java @@ -194,7 +194,8 @@ public enum SupplicantState implements Parcelable { } } - static boolean isConnecting(SupplicantState state) { + /** @hide */ + public static boolean isConnecting(SupplicantState state) { switch(state) { case AUTHENTICATING: case ASSOCIATING: @@ -216,7 +217,8 @@ public enum SupplicantState implements Parcelable { } } - static boolean isDriverActive(SupplicantState state) { + /** @hide */ + public static boolean isDriverActive(SupplicantState state) { switch(state) { case DISCONNECTED: case DORMANT: diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java deleted file mode 100644 index e76eb17..0000000 --- a/wifi/java/android/net/wifi/SupplicantStateTracker.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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 android.net.wifi; - -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - -import android.net.wifi.StateChangeResult; -import android.content.Context; -import android.content.Intent; -import android.os.Handler; -import android.os.Message; -import android.os.Parcelable; -import android.os.UserHandle; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Tracks the state changes in supplicant and provides functionality - * that is based on these state changes: - * - detect a failed WPA handshake that loops indefinitely - * - authentication failure handling - */ -class SupplicantStateTracker extends StateMachine { - - private static final String TAG = "SupplicantStateTracker"; - private static final boolean DBG = false; - - private WifiStateMachine mWifiStateMachine; - private WifiConfigStore mWifiConfigStore; - private int mAuthenticationFailuresCount = 0; - private int mAssociationRejectCount = 0; - /* Indicates authentication failure in supplicant broadcast. - * TODO: enhance auth failure reporting to include notification - * for all type of failures: EAP, WPS & WPA networks */ - private boolean mAuthFailureInSupplicantBroadcast = false; - - /* Maximum retries on a authentication failure notification */ - private static final int MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2; - - /* Maximum retries on assoc rejection events */ - private static final int MAX_RETRIES_ON_ASSOCIATION_REJECT = 16; - - /* Tracks if networks have been disabled during a connection */ - private boolean mNetworksDisabledDuringConnect = false; - - private Context mContext; - - private State mUninitializedState = new UninitializedState(); - private State mDefaultState = new DefaultState(); - private State mInactiveState = new InactiveState(); - private State mDisconnectState = new DisconnectedState(); - private State mScanState = new ScanState(); - private State mHandshakeState = new HandshakeState(); - private State mCompletedState = new CompletedState(); - private State mDormantState = new DormantState(); - - public SupplicantStateTracker(Context c, WifiStateMachine wsm, WifiConfigStore wcs, Handler t) { - super(TAG, t.getLooper()); - - mContext = c; - mWifiStateMachine = wsm; - mWifiConfigStore = wcs; - addState(mDefaultState); - addState(mUninitializedState, mDefaultState); - addState(mInactiveState, mDefaultState); - addState(mDisconnectState, mDefaultState); - addState(mScanState, mDefaultState); - addState(mHandshakeState, mDefaultState); - addState(mCompletedState, mDefaultState); - addState(mDormantState, mDefaultState); - - setInitialState(mUninitializedState); - setLogRecSize(50); - setLogOnlyTransitions(true); - //start the state machine - start(); - } - - private void handleNetworkConnectionFailure(int netId, int disableReason) { - /* If other networks disabled during connection, enable them */ - if (mNetworksDisabledDuringConnect) { - mWifiConfigStore.enableAllNetworks(); - mNetworksDisabledDuringConnect = false; - } - /* Disable failed network */ - mWifiConfigStore.disableNetwork(netId, disableReason); - } - - private void transitionOnSupplicantStateChange(StateChangeResult stateChangeResult) { - SupplicantState supState = (SupplicantState) stateChangeResult.state; - - if (DBG) Log.d(TAG, "Supplicant state: " + supState.toString() + "\n"); - - switch (supState) { - case DISCONNECTED: - transitionTo(mDisconnectState); - break; - case INTERFACE_DISABLED: - //we should have received a disconnection already, do nothing - break; - case SCANNING: - transitionTo(mScanState); - break; - case AUTHENTICATING: - case ASSOCIATING: - case ASSOCIATED: - case FOUR_WAY_HANDSHAKE: - case GROUP_HANDSHAKE: - transitionTo(mHandshakeState); - break; - case COMPLETED: - transitionTo(mCompletedState); - break; - case DORMANT: - transitionTo(mDormantState); - break; - case INACTIVE: - transitionTo(mInactiveState); - break; - case UNINITIALIZED: - case INVALID: - transitionTo(mUninitializedState); - break; - default: - Log.e(TAG, "Unknown supplicant state " + supState); - break; - } - } - - private void sendSupplicantStateChangedBroadcast(SupplicantState state, boolean failedAuth) { - Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT - | Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable) state); - if (failedAuth) { - intent.putExtra( - WifiManager.EXTRA_SUPPLICANT_ERROR, - WifiManager.ERROR_AUTHENTICATING); - } - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - /******************************************************** - * HSM states - *******************************************************/ - - class DefaultState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: - mAuthenticationFailuresCount++; - mAuthFailureInSupplicantBroadcast = true; - break; - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - SupplicantState state = stateChangeResult.state; - sendSupplicantStateChangedBroadcast(state, mAuthFailureInSupplicantBroadcast); - mAuthFailureInSupplicantBroadcast = false; - transitionOnSupplicantStateChange(stateChangeResult); - break; - case WifiStateMachine.CMD_RESET_SUPPLICANT_STATE: - transitionTo(mUninitializedState); - break; - case WifiManager.CONNECT_NETWORK: - mNetworksDisabledDuringConnect = true; - mAssociationRejectCount = 0; - break; - case WifiMonitor.ASSOCIATION_REJECTION_EVENT: - mAssociationRejectCount++; - break; - default: - Log.e(TAG, "Ignoring " + message); - break; - } - return HANDLED; - } - } - - /* - * This indicates that the supplicant state as seen - * by the framework is not initialized yet. We are - * in this state right after establishing a control - * channel connection before any supplicant events - * or after we have lost the control channel - * connection to the supplicant - */ - class UninitializedState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - } - - class InactiveState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - } - - class DisconnectedState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - /* If a disconnect event happens after authentication failure - * exceeds maximum retries, disable the network - */ - Message message = getCurrentMessage(); - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - - if (mAuthenticationFailuresCount >= MAX_RETRIES_ON_AUTHENTICATION_FAILURE) { - Log.d(TAG, "Failed to authenticate, disabling network " + - stateChangeResult.networkId); - handleNetworkConnectionFailure(stateChangeResult.networkId, - WifiConfiguration.DISABLED_AUTH_FAILURE); - mAuthenticationFailuresCount = 0; - } - else if (mAssociationRejectCount >= MAX_RETRIES_ON_ASSOCIATION_REJECT) { - Log.d(TAG, "Association getting rejected, disabling network " + - stateChangeResult.networkId); - handleNetworkConnectionFailure(stateChangeResult.networkId, - WifiConfiguration.DISABLED_ASSOCIATION_REJECT); - mAssociationRejectCount = 0; - } - } - } - - class ScanState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - } - - class HandshakeState extends State { - /** - * The max number of the WPA supplicant loop iterations before we - * decide that the loop should be terminated: - */ - private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4; - private int mLoopDetectIndex; - private int mLoopDetectCount; - - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - mLoopDetectIndex = 0; - mLoopDetectCount = 0; - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch (message.what) { - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - SupplicantState state = stateChangeResult.state; - if (SupplicantState.isHandshakeState(state)) { - if (mLoopDetectIndex > state.ordinal()) { - mLoopDetectCount++; - } - if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { - Log.d(TAG, "Supplicant loop detected, disabling network " + - stateChangeResult.networkId); - handleNetworkConnectionFailure(stateChangeResult.networkId, - WifiConfiguration.DISABLED_AUTH_FAILURE); - } - mLoopDetectIndex = state.ordinal(); - sendSupplicantStateChangedBroadcast(state, - mAuthFailureInSupplicantBroadcast); - } else { - //Have the DefaultState handle the transition - return NOT_HANDLED; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class CompletedState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - /* Reset authentication failure count */ - mAuthenticationFailuresCount = 0; - mAssociationRejectCount = 0; - if (mNetworksDisabledDuringConnect) { - mWifiConfigStore.enableAllNetworks(); - mNetworksDisabledDuringConnect = false; - } - } - @Override - public boolean processMessage(Message message) { - if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); - switch(message.what) { - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - SupplicantState state = stateChangeResult.state; - sendSupplicantStateChangedBroadcast(state, mAuthFailureInSupplicantBroadcast); - /* Ignore any connecting state in completed state. Group re-keying - * events and other auth events that do not affect connectivity are - * ignored - */ - if (SupplicantState.isConnecting(state)) { - break; - } - transitionOnSupplicantStateChange(stateChangeResult); - break; - case WifiStateMachine.CMD_RESET_SUPPLICANT_STATE: - sendSupplicantStateChangedBroadcast(SupplicantState.DISCONNECTED, false); - transitionTo(mUninitializedState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - //TODO: remove after getting rid of the state in supplicant - class DormantState extends State { - @Override - public void enter() { - if (DBG) Log.d(TAG, getName() + "\n"); - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); - pw.println("mAuthenticationFailuresCount " + mAuthenticationFailuresCount); - pw.println("mAuthFailureInSupplicantBroadcast " + mAuthFailureInSupplicantBroadcast); - pw.println("mNetworksDisabledDuringConnect " + mNetworksDisabledDuringConnect); - pw.println(); - } -} diff --git a/wifi/java/android/net/wifi/WifiApConfigStore.java b/wifi/java/android/net/wifi/WifiApConfigStore.java deleted file mode 100644 index e675ad4..0000000 --- a/wifi/java/android/net/wifi/WifiApConfigStore.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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 android.net.wifi; - -import android.content.Context; -import android.net.wifi.WifiConfiguration.KeyMgmt; -import android.os.Environment; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.util.Log; - -import com.android.internal.util.AsyncChannel; -import com.android.internal.R; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.UUID; - -/** - * Provides API to the WifiStateMachine for doing read/write access - * to soft access point configuration - */ -class WifiApConfigStore extends StateMachine { - - private Context mContext; - private static final String TAG = "WifiApConfigStore"; - - private static final String AP_CONFIG_FILE = Environment.getDataDirectory() + - "/misc/wifi/softap.conf"; - - private static final int AP_CONFIG_FILE_VERSION = 1; - - private State mDefaultState = new DefaultState(); - private State mInactiveState = new InactiveState(); - private State mActiveState = new ActiveState(); - - private WifiConfiguration mWifiApConfig = null; - private AsyncChannel mReplyChannel = new AsyncChannel(); - - WifiApConfigStore(Context context, Handler target) { - super(TAG, target.getLooper()); - - mContext = context; - addState(mDefaultState); - addState(mInactiveState, mDefaultState); - addState(mActiveState, mDefaultState); - - setInitialState(mInactiveState); - } - - public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) { - WifiApConfigStore s = new WifiApConfigStore(context, target); - s.start(); - return s; - } - - class DefaultState extends State { - public boolean processMessage(Message message) { - switch (message.what) { - case WifiStateMachine.CMD_SET_AP_CONFIG: - case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: - Log.e(TAG, "Unexpected message: " + message); - break; - case WifiStateMachine.CMD_REQUEST_AP_CONFIG: - mReplyChannel.replyToMessage(message, - WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig); - break; - default: - Log.e(TAG, "Failed to handle " + message); - break; - } - return HANDLED; - } - } - - class InactiveState extends State { - public boolean processMessage(Message message) { - switch (message.what) { - case WifiStateMachine.CMD_SET_AP_CONFIG: - mWifiApConfig = (WifiConfiguration) message.obj; - transitionTo(mActiveState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class ActiveState extends State { - public void enter() { - new Thread(new Runnable() { - public void run() { - writeApConfiguration(mWifiApConfig); - sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED); - } - }).start(); - } - - public boolean processMessage(Message message) { - switch (message.what) { - //TODO: have feedback to the user when we do this - //to indicate the write is currently in progress - case WifiStateMachine.CMD_SET_AP_CONFIG: - deferMessage(message); - break; - case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: - transitionTo(mInactiveState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - void loadApConfiguration() { - DataInputStream in = null; - try { - WifiConfiguration config = new WifiConfiguration(); - in = new DataInputStream(new BufferedInputStream(new FileInputStream( - AP_CONFIG_FILE))); - - int version = in.readInt(); - if (version != 1) { - Log.e(TAG, "Bad version on hotspot configuration file, set defaults"); - setDefaultApConfiguration(); - return; - } - config.SSID = in.readUTF(); - int authType = in.readInt(); - config.allowedKeyManagement.set(authType); - if (authType != KeyMgmt.NONE) { - config.preSharedKey = in.readUTF(); - } - mWifiApConfig = config; - } catch (IOException ignore) { - setDefaultApConfiguration(); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) {} - } - } - } - - Messenger getMessenger() { - return new Messenger(getHandler()); - } - - private void writeApConfiguration(final WifiConfiguration config) { - DataOutputStream out = null; - try { - out = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(AP_CONFIG_FILE))); - - out.writeInt(AP_CONFIG_FILE_VERSION); - out.writeUTF(config.SSID); - int authType = config.getAuthType(); - out.writeInt(authType); - if(authType != KeyMgmt.NONE) { - out.writeUTF(config.preSharedKey); - } - } catch (IOException e) { - Log.e(TAG, "Error writing hotspot configuration" + e); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) {} - } - } - } - - /* Generate a default WPA2 based configuration with a random password. - We are changing the Wifi Ap configuration storage from secure settings to a - flat file accessible only by the system. A WPA2 based default configuration - will keep the device secure after the update */ - private void setDefaultApConfiguration() { - WifiConfiguration config = new WifiConfiguration(); - config.SSID = mContext.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); - sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config); - } -} diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java deleted file mode 100644 index e45c2e7..0000000 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ /dev/null @@ -1,2022 +0,0 @@ -/* - * 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 android.net.wifi; - -import android.content.Context; -import android.content.Intent; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NetworkUtils; -import android.net.NetworkInfo.DetailedState; -import android.net.ProxyProperties; -import android.net.RouteInfo; -import android.net.wifi.WifiConfiguration.IpAssignment; -import android.net.wifi.WifiConfiguration.KeyMgmt; -import android.net.wifi.WifiConfiguration.ProxySettings; -import android.net.wifi.WifiConfiguration.Status; -import android.net.wifi.NetworkUpdateResult; -import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; - -import android.os.Environment; -import android.os.FileObserver; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Process; -import android.os.UserHandle; -import android.security.Credentials; -import android.security.KeyChain; -import android.security.KeyStore; -import android.text.TextUtils; -import android.util.LocalLog; -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -/** - * This class provides the API to manage configured - * wifi networks. The API is not thread safe is being - * used only from WifiStateMachine. - * - * It deals with the following - * - Add/update/remove a WifiConfiguration - * The configuration contains two types of information. - * = IP and proxy configuration that is handled by WifiConfigStore and - * is saved to disk on any change. - * - * The format of configuration file is as follows: - * - * ... - * ... - * .. - * - * (key, value) pairs for a given network are grouped together and can - * be in any order. A EOS at the end of a set of (key, value) pairs - * indicates that the next set of (key, value) pairs are for a new - * network. A network is identified by a unique ID_KEY. If there is no - * ID_KEY in the (key, value) pairs, the data is discarded. - * - * An invalid version on read would result in discarding the contents of - * the file. On the next write, the latest version is written to file. - * - * Any failures during read or write to the configuration file are ignored - * without reporting to the user since the likelihood of these errors are - * low and the impact on connectivity is low. - * - * = SSID & security details that is pushed to the supplicant. - * supplicant saves these details to the disk on calling - * saveConfigCommand(). - * - * We have two kinds of APIs exposed: - * > public API calls that provide fine grained control - * - enableNetwork, disableNetwork, addOrUpdateNetwork(), - * removeNetwork(). For these calls, the config is not persisted - * to the disk. (TODO: deprecate these calls in WifiManager) - * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). - * These calls persist the supplicant config to disk. - * - * - Maintain a list of configured networks for quick access - * - */ -class WifiConfigStore { - - private Context mContext; - private static final String TAG = "WifiConfigStore"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - - private static final String SUPPLICANT_CONFIG_FILE = "/data/misc/wifi/wpa_supplicant.conf"; - - /* configured networks with network id as the key */ - private HashMap mConfiguredNetworks = - new HashMap(); - - /* A network id is a unique identifier for a network configured in the - * supplicant. Network ids are generated when the supplicant reads - * the configuration file at start and can thus change for networks. - * We store the IP configuration for networks along with a unique id - * that is generated from SSID and security type of the network. A mapping - * from the generated unique id to network id of the network is needed to - * map supplicant config to IP configuration. */ - private HashMap mNetworkIds = - new HashMap(); - - /* Tracks the highest priority of configured networks */ - private int mLastPriority = -1; - - private static final String ipConfigFile = Environment.getDataDirectory() + - "/misc/wifi/ipconfig.txt"; - - private static final int IPCONFIG_FILE_VERSION = 2; - - /* IP and proxy configuration keys */ - private static final String ID_KEY = "id"; - private static final String IP_ASSIGNMENT_KEY = "ipAssignment"; - private static final String LINK_ADDRESS_KEY = "linkAddress"; - private static final String GATEWAY_KEY = "gateway"; - private static final String DNS_KEY = "dns"; - private static final String PROXY_SETTINGS_KEY = "proxySettings"; - private static final String PROXY_HOST_KEY = "proxyHost"; - private static final String PROXY_PORT_KEY = "proxyPort"; - private static final String PROXY_PAC_FILE = "proxyPac"; - private static final String EXCLUSION_LIST_KEY = "exclusionList"; - private static final String EOS = "eos"; - - - /* Enterprise configuration keys */ - /** - * In old configurations, the "private_key" field was used. However, newer - * configurations use the key_id field with the engine_id set to "keystore". - * If this field is found in the configuration, the migration code is - * triggered. - */ - public static final String OLD_PRIVATE_KEY_NAME = "private_key"; - - /** - * String representing the keystore OpenSSL ENGINE's ID. - */ - public static final String ENGINE_ID_KEYSTORE = "keystore"; - - /** - * String representing the keystore URI used for wpa_supplicant. - */ - public static final String KEYSTORE_URI = "keystore://"; - - /** - * String to set the engine value to when it should be enabled. - */ - public static final String ENGINE_ENABLE = "1"; - - /** - * String to set the engine value to when it should be disabled. - */ - public static final String ENGINE_DISABLE = "0"; - - public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; - public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE; - public static final String EAP_KEY = "eap"; - public static final String PHASE2_KEY = "phase2"; - public static final String IDENTITY_KEY = "identity"; - public static final String ANON_IDENTITY_KEY = "anonymous_identity"; - public static final String PASSWORD_KEY = "password"; - public static final String CLIENT_CERT_KEY = "client_cert"; - public static final String CA_CERT_KEY = "ca_cert"; - public static final String SUBJECT_MATCH_KEY = "subject_match"; - public static final String ENGINE_KEY = "engine"; - public static final String ENGINE_ID_KEY = "engine_id"; - public static final String PRIVATE_KEY_ID_KEY = "key_id"; - public static final String OPP_KEY_CACHING = "proactive_key_caching"; - - /** This represents an empty value of an enterprise field. - * NULL is used at wpa_supplicant to indicate an empty value - */ - static final String EMPTY_VALUE = "NULL"; - - /** Internal use only */ - private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { EAP_KEY, - PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY, CLIENT_CERT_KEY, - CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY, PRIVATE_KEY_ID_KEY }; - - private final LocalLog mLocalLog; - private final WpaConfigFileObserver mFileObserver; - - private WifiNative mWifiNative; - private final KeyStore mKeyStore = KeyStore.getInstance(); - - WifiConfigStore(Context c, WifiNative wn) { - mContext = c; - mWifiNative = wn; - - if (VDBG) { - mLocalLog = mWifiNative.getLocalLog(); - mFileObserver = new WpaConfigFileObserver(); - mFileObserver.startWatching(); - } else { - mLocalLog = null; - mFileObserver = null; - } - } - - class WpaConfigFileObserver extends FileObserver { - - public WpaConfigFileObserver() { - super(SUPPLICANT_CONFIG_FILE, CLOSE_WRITE); - } - - @Override - public void onEvent(int event, String path) { - if (event == CLOSE_WRITE) { - File file = new File(SUPPLICANT_CONFIG_FILE); - if (VDBG) localLog("wpa_supplicant.conf changed; new size = " + file.length()); - } - } - } - - - /** - * Fetch the list of configured networks - * and enable all stored networks in supplicant. - */ - void loadAndEnableAllNetworks() { - if (DBG) log("Loading config and enabling all networks"); - loadConfiguredNetworks(); - enableAllNetworks(); - } - - /** - * Fetch the list of currently configured networks - * @return List of networks - */ - List getConfiguredNetworks() { - List networks = new ArrayList(); - for(WifiConfiguration config : mConfiguredNetworks.values()) { - networks.add(new WifiConfiguration(config)); - } - return networks; - } - - /** - * enable all networks and save config. This will be a no-op if the list - * of configured networks indicates all networks as being enabled - */ - void enableAllNetworks() { - boolean networkEnabledStateChanged = false; - for(WifiConfiguration config : mConfiguredNetworks.values()) { - if(config != null && config.status == Status.DISABLED) { - if(mWifiNative.enableNetwork(config.networkId, false)) { - networkEnabledStateChanged = true; - config.status = Status.ENABLED; - } else { - loge("Enable network failed on " + config.networkId); - } - } - } - - if (networkEnabledStateChanged) { - mWifiNative.saveConfig(); - sendConfiguredNetworksChangedBroadcast(); - } - } - - - /** - * Selects the specified network for connection. This involves - * updating the priority of all the networks and enabling the given - * network while disabling others. - * - * Selecting a network will leave the other networks disabled and - * a call to enableAllNetworks() needs to be issued upon a connection - * or a failure event from supplicant - * - * @param netId network to select for connection - * @return false if the network id is invalid - */ - boolean selectNetwork(int netId) { - if (VDBG) localLog("selectNetwork", netId); - if (netId == INVALID_NETWORK_ID) return false; - - // Reset the priority of each network at start or if it goes too high. - if (mLastPriority == -1 || mLastPriority > 1000000) { - for(WifiConfiguration config : mConfiguredNetworks.values()) { - if (config.networkId != INVALID_NETWORK_ID) { - config.priority = 0; - addOrUpdateNetworkNative(config); - } - } - mLastPriority = 0; - } - - // Set to the highest priority and save the configuration. - WifiConfiguration config = new WifiConfiguration(); - config.networkId = netId; - config.priority = ++mLastPriority; - - addOrUpdateNetworkNative(config); - mWifiNative.saveConfig(); - - /* Enable the given network while disabling all other networks */ - enableNetworkWithoutBroadcast(netId, true); - - /* Avoid saving the config & sending a broadcast to prevent settings - * from displaying a disabled list of networks */ - return true; - } - - /** - * Add/update the specified configuration and save config - * - * @param config WifiConfiguration to be saved - * @return network update result - */ - NetworkUpdateResult saveNetwork(WifiConfiguration config) { - if (VDBG) localLog("saveNetwork", config.networkId); - // A new network cannot have null SSID - if (config == null || (config.networkId == INVALID_NETWORK_ID && - config.SSID == null)) { - return new NetworkUpdateResult(INVALID_NETWORK_ID); - } - - boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); - NetworkUpdateResult result = addOrUpdateNetworkNative(config); - int netId = result.getNetworkId(); - /* enable a new network */ - if (newNetwork && netId != INVALID_NETWORK_ID) { - mWifiNative.enableNetwork(netId, false); - mConfiguredNetworks.get(netId).status = Status.ENABLED; - } - mWifiNative.saveConfig(); - sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ? - WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE); - return result; - } - - void updateStatus(int netId, DetailedState state) { - if (netId != INVALID_NETWORK_ID) { - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config == null) return; - switch (state) { - case CONNECTED: - config.status = Status.CURRENT; - break; - case DISCONNECTED: - //If network is already disabled, keep the status - if (config.status == Status.CURRENT) { - config.status = Status.ENABLED; - } - break; - default: - //do nothing, retain the existing state - break; - } - } - } - - /** - * Forget the specified network and save config - * - * @param netId network to forget - * @return {@code true} if it succeeds, {@code false} otherwise - */ - boolean forgetNetwork(int netId) { - if (VDBG) localLog("forgetNetwork", netId); - if (mWifiNative.removeNetwork(netId)) { - mWifiNative.saveConfig(); - removeConfigAndSendBroadcastIfNeeded(netId); - return true; - } else { - loge("Failed to remove network " + netId); - return false; - } - } - - /** - * Add/update a network. Note that there is no saveConfig operation. - * This function is retained for compatibility with the public - * API. The more powerful saveNetwork() is used by the - * state machine - * - * @param config wifi configuration to add/update - * @return network Id - */ - int addOrUpdateNetwork(WifiConfiguration config) { - if (VDBG) localLog("addOrUpdateNetwork", config.networkId); - NetworkUpdateResult result = addOrUpdateNetworkNative(config); - if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { - sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()), - result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED : - WifiManager.CHANGE_REASON_CONFIG_CHANGE); - } - return result.getNetworkId(); - } - - /** - * Remove a network. Note that there is no saveConfig operation. - * This function is retained for compatibility with the public - * API. The more powerful forgetNetwork() is used by the - * state machine for network removal - * - * @param netId network to be removed - * @return {@code true} if it succeeds, {@code false} otherwise - */ - boolean removeNetwork(int netId) { - if (VDBG) localLog("removeNetwork", netId); - boolean ret = mWifiNative.removeNetwork(netId); - if (ret) { - removeConfigAndSendBroadcastIfNeeded(netId); - } - return ret; - } - - private void removeConfigAndSendBroadcastIfNeeded(int netId) { - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config != null) { - // Remove any associated keys - if (config.enterpriseConfig != null) { - removeKeys(config.enterpriseConfig); - } - mConfiguredNetworks.remove(netId); - mNetworkIds.remove(configKey(config)); - - writeIpAndProxyConfigurations(); - sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); - } - } - - /** - * Enable a network. Note that there is no saveConfig operation. - * This function is retained for compatibility with the public - * API. The more powerful selectNetwork()/saveNetwork() is used by the - * state machine for connecting to a network - * - * @param netId network to be enabled - * @return {@code true} if it succeeds, {@code false} otherwise - */ - boolean enableNetwork(int netId, boolean disableOthers) { - boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers); - if (disableOthers) { - if (VDBG) localLog("enableNetwork(disableOthers=true) ", netId); - sendConfiguredNetworksChangedBroadcast(); - } else { - if (VDBG) localLog("enableNetwork(disableOthers=false) ", netId); - WifiConfiguration enabledNetwork = null; - synchronized(mConfiguredNetworks) { - enabledNetwork = mConfiguredNetworks.get(netId); - } - // check just in case the network was removed by someone else. - if (enabledNetwork != null) { - sendConfiguredNetworksChangedBroadcast(enabledNetwork, - WifiManager.CHANGE_REASON_CONFIG_CHANGE); - } - } - return ret; - } - - boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) { - boolean ret = mWifiNative.enableNetwork(netId, disableOthers); - - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config != null) config.status = Status.ENABLED; - - if (disableOthers) { - markAllNetworksDisabledExcept(netId); - } - return ret; - } - - void disableAllNetworks() { - if (VDBG) localLog("disableAllNetworks"); - boolean networkDisabled = false; - for(WifiConfiguration config : mConfiguredNetworks.values()) { - if(config != null && config.status != Status.DISABLED) { - if(mWifiNative.disableNetwork(config.networkId)) { - networkDisabled = true; - config.status = Status.DISABLED; - } else { - loge("Disable network failed on " + config.networkId); - } - } - } - - if (networkDisabled) { - sendConfiguredNetworksChangedBroadcast(); - } - } - /** - * Disable a network. Note that there is no saveConfig operation. - * @param netId network to be disabled - * @return {@code true} if it succeeds, {@code false} otherwise - */ - boolean disableNetwork(int netId) { - return disableNetwork(netId, WifiConfiguration.DISABLED_UNKNOWN_REASON); - } - - /** - * Disable a network. Note that there is no saveConfig operation. - * @param netId network to be disabled - * @param reason reason code network was disabled - * @return {@code true} if it succeeds, {@code false} otherwise - */ - boolean disableNetwork(int netId, int reason) { - if (VDBG) localLog("disableNetwork", netId); - boolean ret = mWifiNative.disableNetwork(netId); - WifiConfiguration network = null; - WifiConfiguration config = mConfiguredNetworks.get(netId); - /* Only change the reason if the network was not previously disabled */ - if (config != null && config.status != Status.DISABLED) { - config.status = Status.DISABLED; - config.disableReason = reason; - network = config; - } - if (network != null) { - sendConfiguredNetworksChangedBroadcast(network, - WifiManager.CHANGE_REASON_CONFIG_CHANGE); - } - return ret; - } - - /** - * Save the configured networks in supplicant to disk - * @return {@code true} if it succeeds, {@code false} otherwise - */ - boolean saveConfig() { - return mWifiNative.saveConfig(); - } - - /** - * Start WPS pin method configuration with pin obtained - * from the access point - * @param config WPS configuration - * @return Wps result containing status and pin - */ - WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { - WpsResult result = new WpsResult(); - if (mWifiNative.startWpsRegistrar(config.BSSID, config.pin)) { - /* WPS leaves all networks disabled */ - markAllNetworksDisabled(); - result.status = WpsResult.Status.SUCCESS; - } else { - loge("Failed to start WPS pin method configuration"); - result.status = WpsResult.Status.FAILURE; - } - return result; - } - - /** - * Start WPS pin method configuration with pin obtained - * from the device - * @return WpsResult indicating status and pin - */ - WpsResult startWpsWithPinFromDevice(WpsInfo config) { - WpsResult result = new WpsResult(); - result.pin = mWifiNative.startWpsPinDisplay(config.BSSID); - /* WPS leaves all networks disabled */ - if (!TextUtils.isEmpty(result.pin)) { - markAllNetworksDisabled(); - result.status = WpsResult.Status.SUCCESS; - } else { - loge("Failed to start WPS pin method configuration"); - result.status = WpsResult.Status.FAILURE; - } - return result; - } - - /** - * Start WPS push button configuration - * @param config WPS configuration - * @return WpsResult indicating status and pin - */ - WpsResult startWpsPbc(WpsInfo config) { - WpsResult result = new WpsResult(); - if (mWifiNative.startWpsPbc(config.BSSID)) { - /* WPS leaves all networks disabled */ - markAllNetworksDisabled(); - result.status = WpsResult.Status.SUCCESS; - } else { - loge("Failed to start WPS push button configuration"); - result.status = WpsResult.Status.FAILURE; - } - return result; - } - - /** - * Fetch the link properties for a given network id - * @return LinkProperties for the given network id - */ - LinkProperties getLinkProperties(int netId) { - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config != null) return new LinkProperties(config.linkProperties); - return null; - } - - /** - * set IP configuration for a given network id - */ - void setLinkProperties(int netId, LinkProperties linkProperties) { - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config != null) { - // add old proxy details - TODO - is this still needed? - if(config.linkProperties != null) { - linkProperties.setHttpProxy(config.linkProperties.getHttpProxy()); - } - config.linkProperties = linkProperties; - } - } - - /** - * clear IP configuration for a given network id - * @param network id - */ - void clearLinkProperties(int netId) { - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config != null && config.linkProperties != null) { - // Clear everything except proxy - ProxyProperties proxy = config.linkProperties.getHttpProxy(); - config.linkProperties.clear(); - config.linkProperties.setHttpProxy(proxy); - } - } - - - /** - * Fetch the proxy properties for a given network id - * @param network id - * @return ProxyProperties for the network id - */ - ProxyProperties getProxyProperties(int netId) { - LinkProperties linkProperties = getLinkProperties(netId); - if (linkProperties != null) { - return new ProxyProperties(linkProperties.getHttpProxy()); - } - return null; - } - - /** - * Return if the specified network is using static IP - * @param network id - * @return {@code true} if using static ip for netId - */ - boolean isUsingStaticIp(int netId) { - WifiConfiguration config = mConfiguredNetworks.get(netId); - if (config != null && config.ipAssignment == IpAssignment.STATIC) { - return true; - } - return false; - } - - /** - * Should be called when a single network configuration is made. - * @param network The network configuration that changed. - * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, - * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. - */ - private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, - int reason) { - Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); - intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); - intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - - /** - * Should be called when multiple network configuration changes are made. - */ - private void sendConfiguredNetworksChangedBroadcast() { - Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - - void loadConfiguredNetworks() { - String listStr = mWifiNative.listNetworks(); - mLastPriority = 0; - - mConfiguredNetworks.clear(); - mNetworkIds.clear(); - - if (listStr == null) - return; - - String[] lines = listStr.split("\n"); - // Skip the first line, which is a header - for (int i = 1; i < lines.length; i++) { - String[] result = lines[i].split("\t"); - // network-id | ssid | bssid | flags - WifiConfiguration config = new WifiConfiguration(); - try { - config.networkId = Integer.parseInt(result[0]); - } catch(NumberFormatException e) { - loge("Failed to read network-id '" + result[0] + "'"); - continue; - } - if (result.length > 3) { - if (result[3].indexOf("[CURRENT]") != -1) - config.status = WifiConfiguration.Status.CURRENT; - else if (result[3].indexOf("[DISABLED]") != -1) - config.status = WifiConfiguration.Status.DISABLED; - else - config.status = WifiConfiguration.Status.ENABLED; - } else { - config.status = WifiConfiguration.Status.ENABLED; - } - readNetworkVariables(config); - if (config.priority > mLastPriority) { - mLastPriority = config.priority; - } - config.ipAssignment = IpAssignment.DHCP; - config.proxySettings = ProxySettings.NONE; - - if (mNetworkIds.containsKey(configKey(config))) { - // That SSID is already known, just ignore this duplicate entry - if (VDBG) localLog("discarded duplicate network", config.networkId); - } else { - mConfiguredNetworks.put(config.networkId, config); - mNetworkIds.put(configKey(config), config.networkId); - if (VDBG) localLog("loaded configured network", config.networkId); - } - } - - readIpAndProxyConfigurations(); - sendConfiguredNetworksChangedBroadcast(); - - if (VDBG) localLog("loadConfiguredNetworks loaded " + mNetworkIds.size() + " networks"); - - if (mNetworkIds.size() == 0) { - // no networks? Lets log if the wpa_supplicant.conf file contents - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(SUPPLICANT_CONFIG_FILE)); - if (VDBG) localLog("--- Begin wpa_supplicant.conf Contents ---"); - for (String line = reader.readLine(); line != null; line = reader.readLine()) { - if (VDBG) localLog(line); - } - if (VDBG) localLog("--- End wpa_supplicant.conf Contents ---"); - } catch (FileNotFoundException e) { - if (VDBG) localLog("Could not open " + SUPPLICANT_CONFIG_FILE + ", " + e); - } catch (IOException e) { - if (VDBG) localLog("Could not read " + SUPPLICANT_CONFIG_FILE + ", " + e); - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException e) { - // Just ignore the fact that we couldn't close - } - } - } - } - - /* Mark all networks except specified netId as disabled */ - private void markAllNetworksDisabledExcept(int netId) { - for(WifiConfiguration config : mConfiguredNetworks.values()) { - if(config != null && config.networkId != netId) { - if (config.status != Status.DISABLED) { - config.status = Status.DISABLED; - config.disableReason = WifiConfiguration.DISABLED_UNKNOWN_REASON; - } - } - } - } - - private void markAllNetworksDisabled() { - markAllNetworksDisabledExcept(INVALID_NETWORK_ID); - } - - boolean needsUnlockedKeyStore() { - - // Any network using certificates to authenticate access requires - // unlocked key store; unless the certificates can be stored with - // hardware encryption - - for(WifiConfiguration config : mConfiguredNetworks.values()) { - - if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) - && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { - - if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { - return true; - } - } - } - - return false; - } - - private void writeIpAndProxyConfigurations() { - - /* Make a copy */ - List networks = new ArrayList(); - for(WifiConfiguration config : mConfiguredNetworks.values()) { - networks.add(new WifiConfiguration(config)); - } - - DelayedDiskWrite.write(networks); - } - - private static class DelayedDiskWrite { - - private static HandlerThread sDiskWriteHandlerThread; - private static Handler sDiskWriteHandler; - /* Tracks multiple writes on the same thread */ - private static int sWriteSequence = 0; - private static final String TAG = "DelayedDiskWrite"; - - static void write (final List networks) { - - /* Do a delayed write to disk on a seperate handler thread */ - synchronized (DelayedDiskWrite.class) { - if (++sWriteSequence == 1) { - sDiskWriteHandlerThread = new HandlerThread("WifiConfigThread"); - sDiskWriteHandlerThread.start(); - sDiskWriteHandler = new Handler(sDiskWriteHandlerThread.getLooper()); - } - } - - sDiskWriteHandler.post(new Runnable() { - @Override - public void run() { - onWriteCalled(networks); - } - }); - } - - private static void onWriteCalled(List networks) { - - DataOutputStream out = null; - try { - out = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(ipConfigFile))); - - out.writeInt(IPCONFIG_FILE_VERSION); - - for(WifiConfiguration config : networks) { - boolean writeToFile = false; - - try { - LinkProperties linkProperties = config.linkProperties; - switch (config.ipAssignment) { - case STATIC: - out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.ipAssignment.toString()); - for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { - out.writeUTF(LINK_ADDRESS_KEY); - out.writeUTF(linkAddr.getAddress().getHostAddress()); - out.writeInt(linkAddr.getNetworkPrefixLength()); - } - for (RouteInfo route : linkProperties.getRoutes()) { - out.writeUTF(GATEWAY_KEY); - LinkAddress dest = route.getDestination(); - if (dest != null) { - out.writeInt(1); - out.writeUTF(dest.getAddress().getHostAddress()); - out.writeInt(dest.getNetworkPrefixLength()); - } else { - out.writeInt(0); - } - if (route.getGateway() != null) { - out.writeInt(1); - out.writeUTF(route.getGateway().getHostAddress()); - } else { - out.writeInt(0); - } - } - for (InetAddress inetAddr : linkProperties.getDnses()) { - out.writeUTF(DNS_KEY); - out.writeUTF(inetAddr.getHostAddress()); - } - writeToFile = true; - break; - case DHCP: - out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.ipAssignment.toString()); - writeToFile = true; - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid ip assignment while writing"); - break; - } - - switch (config.proxySettings) { - case STATIC: - ProxyProperties proxyProperties = linkProperties.getHttpProxy(); - String exclusionList = proxyProperties.getExclusionList(); - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); - out.writeUTF(PROXY_HOST_KEY); - out.writeUTF(proxyProperties.getHost()); - out.writeUTF(PROXY_PORT_KEY); - out.writeInt(proxyProperties.getPort()); - out.writeUTF(EXCLUSION_LIST_KEY); - out.writeUTF(exclusionList); - writeToFile = true; - break; - case PAC: - ProxyProperties proxyPacProperties = linkProperties.getHttpProxy(); - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); - out.writeUTF(PROXY_PAC_FILE); - out.writeUTF(proxyPacProperties.getPacFileUrl()); - writeToFile = true; - break; - case NONE: - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); - writeToFile = true; - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignthisore invalid proxy settings while writing"); - break; - } - if (writeToFile) { - out.writeUTF(ID_KEY); - out.writeInt(configKey(config)); - } - } catch (NullPointerException e) { - loge("Failure in writing " + config.linkProperties + e); - } - out.writeUTF(EOS); - } - - } catch (IOException e) { - loge("Error writing data file"); - } finally { - if (out != null) { - try { - out.close(); - } catch (Exception e) {} - } - - //Quit if no more writes sent - synchronized (DelayedDiskWrite.class) { - if (--sWriteSequence == 0) { - sDiskWriteHandler.getLooper().quit(); - sDiskWriteHandler = null; - sDiskWriteHandlerThread = null; - } - } - } - } - - private static void loge(String s) { - Log.e(TAG, s); - } - } - - private void readIpAndProxyConfigurations() { - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(new FileInputStream( - ipConfigFile))); - - int version = in.readInt(); - if (version != 2 && version != 1) { - loge("Bad version on IP configuration file, ignore read"); - return; - } - - while (true) { - int id = -1; - // Default is DHCP with no proxy - IpAssignment ipAssignment = IpAssignment.DHCP; - ProxySettings proxySettings = ProxySettings.NONE; - LinkProperties linkProperties = new LinkProperties(); - String proxyHost = null; - String pacFileUrl = null; - int proxyPort = -1; - String exclusionList = null; - String key; - - do { - key = in.readUTF(); - try { - if (key.equals(ID_KEY)) { - id = in.readInt(); - } else if (key.equals(IP_ASSIGNMENT_KEY)) { - ipAssignment = IpAssignment.valueOf(in.readUTF()); - } else if (key.equals(LINK_ADDRESS_KEY)) { - LinkAddress linkAddr = new LinkAddress( - NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); - linkProperties.addLinkAddress(linkAddr); - } else if (key.equals(GATEWAY_KEY)) { - LinkAddress dest = null; - InetAddress gateway = null; - if (version == 1) { - // only supported default gateways - leave the dest/prefix empty - gateway = NetworkUtils.numericToInetAddress(in.readUTF()); - } else { - if (in.readInt() == 1) { - dest = new LinkAddress( - NetworkUtils.numericToInetAddress(in.readUTF()), - in.readInt()); - } - if (in.readInt() == 1) { - gateway = NetworkUtils.numericToInetAddress(in.readUTF()); - } - } - linkProperties.addRoute(new RouteInfo(dest, gateway)); - } else if (key.equals(DNS_KEY)) { - linkProperties.addDns( - NetworkUtils.numericToInetAddress(in.readUTF())); - } else if (key.equals(PROXY_SETTINGS_KEY)) { - proxySettings = ProxySettings.valueOf(in.readUTF()); - } else if (key.equals(PROXY_HOST_KEY)) { - proxyHost = in.readUTF(); - } else if (key.equals(PROXY_PORT_KEY)) { - proxyPort = in.readInt(); - } else if (key.equals(PROXY_PAC_FILE)) { - pacFileUrl = in.readUTF(); - } else if (key.equals(EXCLUSION_LIST_KEY)) { - exclusionList = in.readUTF(); - } else if (key.equals(EOS)) { - break; - } else { - loge("Ignore unknown key " + key + "while reading"); - } - } catch (IllegalArgumentException e) { - loge("Ignore invalid address while reading" + e); - } - } while (true); - - if (id != -1) { - WifiConfiguration config = mConfiguredNetworks.get( - mNetworkIds.get(id)); - - if (config == null) { - loge("configuration found for missing network, ignored"); - } else { - config.linkProperties = linkProperties; - switch (ipAssignment) { - case STATIC: - case DHCP: - config.ipAssignment = ipAssignment; - break; - case UNASSIGNED: - loge("BUG: Found UNASSIGNED IP on file, use DHCP"); - config.ipAssignment = IpAssignment.DHCP; - break; - default: - loge("Ignore invalid ip assignment while reading"); - break; - } - - switch (proxySettings) { - case STATIC: - config.proxySettings = proxySettings; - ProxyProperties proxyProperties = - new ProxyProperties(proxyHost, proxyPort, exclusionList); - linkProperties.setHttpProxy(proxyProperties); - break; - case PAC: - config.proxySettings = proxySettings; - ProxyProperties proxyPacProperties = - new ProxyProperties(pacFileUrl); - linkProperties.setHttpProxy(proxyPacProperties); - break; - case NONE: - config.proxySettings = proxySettings; - break; - case UNASSIGNED: - loge("BUG: Found UNASSIGNED proxy on file, use NONE"); - config.proxySettings = ProxySettings.NONE; - break; - default: - loge("Ignore invalid proxy settings while reading"); - break; - } - } - } else { - if (DBG) log("Missing id while parsing configuration"); - } - } - } catch (EOFException ignore) { - } catch (IOException e) { - loge("Error parsing configuration" + e); - } finally { - if (in != null) { - try { - in.close(); - } catch (Exception e) {} - } - } - } - - private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) { - /* - * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty - * network configuration. Otherwise, the networkId should - * refer to an existing configuration. - */ - - if (VDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); - - int netId = config.networkId; - boolean newNetwork = false; - // networkId of INVALID_NETWORK_ID means we want to create a new network - if (netId == INVALID_NETWORK_ID) { - Integer savedNetId = mNetworkIds.get(configKey(config)); - if (savedNetId != null) { - netId = savedNetId; - } else { - newNetwork = true; - netId = mWifiNative.addNetwork(); - if (netId < 0) { - loge("Failed to add a network!"); - return new NetworkUpdateResult(INVALID_NETWORK_ID); - } - } - } - - boolean updateFailed = true; - - setVariables: { - - if (config.SSID != null && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.ssidVarName, - config.SSID)) { - loge("failed to set SSID: "+config.SSID); - break setVariables; - } - - if (config.BSSID != null && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.bssidVarName, - config.BSSID)) { - loge("failed to set BSSID: "+config.BSSID); - break setVariables; - } - - String allowedKeyManagementString = - makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); - if (config.allowedKeyManagement.cardinality() != 0 && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.KeyMgmt.varName, - allowedKeyManagementString)) { - loge("failed to set key_mgmt: "+ - allowedKeyManagementString); - break setVariables; - } - - String allowedProtocolsString = - makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); - if (config.allowedProtocols.cardinality() != 0 && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.Protocol.varName, - allowedProtocolsString)) { - loge("failed to set proto: "+ - allowedProtocolsString); - break setVariables; - } - - String allowedAuthAlgorithmsString = - makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); - if (config.allowedAuthAlgorithms.cardinality() != 0 && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.AuthAlgorithm.varName, - allowedAuthAlgorithmsString)) { - loge("failed to set auth_alg: "+ - allowedAuthAlgorithmsString); - break setVariables; - } - - String allowedPairwiseCiphersString = - makeString(config.allowedPairwiseCiphers, - WifiConfiguration.PairwiseCipher.strings); - if (config.allowedPairwiseCiphers.cardinality() != 0 && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.PairwiseCipher.varName, - allowedPairwiseCiphersString)) { - loge("failed to set pairwise: "+ - allowedPairwiseCiphersString); - break setVariables; - } - - String allowedGroupCiphersString = - makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); - if (config.allowedGroupCiphers.cardinality() != 0 && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.GroupCipher.varName, - allowedGroupCiphersString)) { - loge("failed to set group: "+ - allowedGroupCiphersString); - break setVariables; - } - - // Prevent client screw-up by passing in a WifiConfiguration we gave it - // by preventing "*" as a key. - if (config.preSharedKey != null && !config.preSharedKey.equals("*") && - !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.pskVarName, - config.preSharedKey)) { - loge("failed to set psk"); - break setVariables; - } - - boolean hasSetKey = false; - if (config.wepKeys != null) { - for (int i = 0; i < config.wepKeys.length; i++) { - // Prevent client screw-up by passing in a WifiConfiguration we gave it - // by preventing "*" as a key. - if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { - if (!mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.wepKeyVarNames[i], - config.wepKeys[i])) { - loge("failed to set wep_key" + i + ": " + config.wepKeys[i]); - break setVariables; - } - hasSetKey = true; - } - } - } - - if (hasSetKey) { - if (!mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.wepTxKeyIdxVarName, - Integer.toString(config.wepTxKeyIndex))) { - loge("failed to set wep_tx_keyidx: " + config.wepTxKeyIndex); - break setVariables; - } - } - - if (!mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.priorityVarName, - Integer.toString(config.priority))) { - loge(config.SSID + ": failed to set priority: " - +config.priority); - break setVariables; - } - - if (config.hiddenSSID && !mWifiNative.setNetworkVariable( - netId, - WifiConfiguration.hiddenSSIDVarName, - Integer.toString(config.hiddenSSID ? 1 : 0))) { - loge(config.SSID + ": failed to set hiddenSSID: "+ - config.hiddenSSID); - break setVariables; - } - - if (config.enterpriseConfig != null && - config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { - - WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; - - if (needsKeyStore(enterpriseConfig)) { - /** - * Keyguard settings may eventually be controlled by device policy. - * We check here if keystore is unlocked before installing - * credentials. - * TODO: Do we need a dialog here ? - */ - if (mKeyStore.state() != KeyStore.State.UNLOCKED) { - loge(config.SSID + ": key store is locked"); - break setVariables; - } - - try { - /* config passed may include only fields being updated. - * In order to generate the key id, fetch uninitialized - * fields from the currently tracked configuration - */ - WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); - String keyId = config.getKeyIdForCredentials(currentConfig); - - if (!installKeys(enterpriseConfig, keyId)) { - loge(config.SSID + ": failed to install keys"); - break setVariables; - } - } catch (IllegalStateException e) { - loge(config.SSID + " invalid config for key installation"); - break setVariables; - } - } - - HashMap enterpriseFields = enterpriseConfig.getFields(); - for (String key : enterpriseFields.keySet()) { - String value = enterpriseFields.get(key); - if (!mWifiNative.setNetworkVariable( - netId, - key, - value)) { - removeKeys(enterpriseConfig); - loge(config.SSID + ": failed to set " + key + - ": " + value); - break setVariables; - } - } - } - updateFailed = false; - } //end of setVariables - - if (updateFailed) { - if (newNetwork) { - mWifiNative.removeNetwork(netId); - loge("Failed to set a network variable, removed network: " + netId); - } - return new NetworkUpdateResult(INVALID_NETWORK_ID); - } - - /* An update of the network variables requires reading them - * back from the supplicant to update mConfiguredNetworks. - * This is because some of the variables (SSID, wep keys & - * passphrases) reflect different values when read back than - * when written. For example, wep key is stored as * irrespective - * of the value sent to the supplicant - */ - WifiConfiguration currentConfig = mConfiguredNetworks.get(netId); - if (currentConfig == null) { - currentConfig = new WifiConfiguration(); - currentConfig.ipAssignment = IpAssignment.DHCP; - currentConfig.proxySettings = ProxySettings.NONE; - currentConfig.networkId = netId; - } - - readNetworkVariables(currentConfig); - - mConfiguredNetworks.put(netId, currentConfig); - mNetworkIds.put(configKey(currentConfig), netId); - - NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config); - result.setIsNewNetwork(newNetwork); - result.setNetworkId(netId); - return result; - } - - /* Compare current and new configuration and write to file on change */ - private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( - WifiConfiguration currentConfig, - WifiConfiguration newConfig) { - boolean ipChanged = false; - boolean proxyChanged = false; - LinkProperties linkProperties = null; - - switch (newConfig.ipAssignment) { - case STATIC: - Collection currentLinkAddresses = currentConfig.linkProperties - .getLinkAddresses(); - Collection newLinkAddresses = newConfig.linkProperties - .getLinkAddresses(); - Collection currentDnses = currentConfig.linkProperties.getDnses(); - Collection newDnses = newConfig.linkProperties.getDnses(); - Collection currentRoutes = currentConfig.linkProperties.getRoutes(); - Collection newRoutes = newConfig.linkProperties.getRoutes(); - - boolean linkAddressesDiffer = - (currentLinkAddresses.size() != newLinkAddresses.size()) || - !currentLinkAddresses.containsAll(newLinkAddresses); - boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) || - !currentDnses.containsAll(newDnses); - boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) || - !currentRoutes.containsAll(newRoutes); - - if ((currentConfig.ipAssignment != newConfig.ipAssignment) || - linkAddressesDiffer || - dnsesDiffer || - routesDiffer) { - ipChanged = true; - } - break; - case DHCP: - if (currentConfig.ipAssignment != newConfig.ipAssignment) { - ipChanged = true; - } - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid ip assignment during write"); - break; - } - - switch (newConfig.proxySettings) { - case STATIC: - case PAC: - ProxyProperties newHttpProxy = newConfig.linkProperties.getHttpProxy(); - ProxyProperties currentHttpProxy = currentConfig.linkProperties.getHttpProxy(); - - if (newHttpProxy != null) { - proxyChanged = !newHttpProxy.equals(currentHttpProxy); - } else { - proxyChanged = (currentHttpProxy != null); - } - break; - case NONE: - if (currentConfig.proxySettings != newConfig.proxySettings) { - proxyChanged = true; - } - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid proxy configuration during write"); - break; - } - - if (!ipChanged) { - linkProperties = copyIpSettingsFromConfig(currentConfig); - } else { - currentConfig.ipAssignment = newConfig.ipAssignment; - linkProperties = copyIpSettingsFromConfig(newConfig); - log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " + - linkProperties.toString()); - } - - - if (!proxyChanged) { - linkProperties.setHttpProxy(currentConfig.linkProperties.getHttpProxy()); - } else { - currentConfig.proxySettings = newConfig.proxySettings; - linkProperties.setHttpProxy(newConfig.linkProperties.getHttpProxy()); - log("proxy changed SSID = " + currentConfig.SSID); - if (linkProperties.getHttpProxy() != null) { - log(" proxyProperties: " + linkProperties.getHttpProxy().toString()); - } - } - - if (ipChanged || proxyChanged) { - currentConfig.linkProperties = linkProperties; - writeIpAndProxyConfigurations(); - sendConfiguredNetworksChangedBroadcast(currentConfig, - WifiManager.CHANGE_REASON_CONFIG_CHANGE); - } - return new NetworkUpdateResult(ipChanged, proxyChanged); - } - - private LinkProperties copyIpSettingsFromConfig(WifiConfiguration config) { - LinkProperties linkProperties = new LinkProperties(); - linkProperties.setInterfaceName(config.linkProperties.getInterfaceName()); - for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) { - linkProperties.addLinkAddress(linkAddr); - } - for (RouteInfo route : config.linkProperties.getRoutes()) { - linkProperties.addRoute(route); - } - for (InetAddress dns : config.linkProperties.getDnses()) { - linkProperties.addDns(dns); - } - return linkProperties; - } - - /** - * Read the variables from the supplicant daemon that are needed to - * fill in the WifiConfiguration object. - * - * @param config the {@link WifiConfiguration} object to be filled in. - */ - private void readNetworkVariables(WifiConfiguration config) { - - int netId = config.networkId; - if (netId < 0) - return; - - /* - * TODO: maybe should have a native method that takes an array of - * variable names and returns an array of values. But we'd still - * be doing a round trip to the supplicant daemon for each variable. - */ - String value; - - value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.ssidVarName); - if (!TextUtils.isEmpty(value)) { - if (value.charAt(0) != '"') { - config.SSID = "\"" + WifiSsid.createFromHex(value).toString() + "\""; - //TODO: convert a hex string that is not UTF-8 decodable to a P-formatted - //supplicant string - } else { - config.SSID = value; - } - } else { - config.SSID = null; - } - - value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.bssidVarName); - if (!TextUtils.isEmpty(value)) { - config.BSSID = value; - } else { - config.BSSID = null; - } - - value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.priorityVarName); - config.priority = -1; - if (!TextUtils.isEmpty(value)) { - try { - config.priority = Integer.parseInt(value); - } catch (NumberFormatException ignore) { - } - } - - value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName); - config.hiddenSSID = false; - if (!TextUtils.isEmpty(value)) { - try { - config.hiddenSSID = Integer.parseInt(value) != 0; - } catch (NumberFormatException ignore) { - } - } - - value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName); - config.wepTxKeyIndex = -1; - if (!TextUtils.isEmpty(value)) { - try { - config.wepTxKeyIndex = Integer.parseInt(value); - } catch (NumberFormatException ignore) { - } - } - - for (int i = 0; i < 4; i++) { - value = mWifiNative.getNetworkVariable(netId, - WifiConfiguration.wepKeyVarNames[i]); - if (!TextUtils.isEmpty(value)) { - config.wepKeys[i] = value; - } else { - config.wepKeys[i] = null; - } - } - - value = mWifiNative.getNetworkVariable(netId, WifiConfiguration.pskVarName); - if (!TextUtils.isEmpty(value)) { - config.preSharedKey = value; - } else { - config.preSharedKey = null; - } - - value = mWifiNative.getNetworkVariable(config.networkId, - WifiConfiguration.Protocol.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.Protocol.strings); - if (0 <= index) { - config.allowedProtocols.set(index); - } - } - } - - value = mWifiNative.getNetworkVariable(config.networkId, - WifiConfiguration.KeyMgmt.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.KeyMgmt.strings); - if (0 <= index) { - config.allowedKeyManagement.set(index); - } - } - } - - value = mWifiNative.getNetworkVariable(config.networkId, - WifiConfiguration.AuthAlgorithm.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.AuthAlgorithm.strings); - if (0 <= index) { - config.allowedAuthAlgorithms.set(index); - } - } - } - - value = mWifiNative.getNetworkVariable(config.networkId, - WifiConfiguration.PairwiseCipher.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.PairwiseCipher.strings); - if (0 <= index) { - config.allowedPairwiseCiphers.set(index); - } - } - } - - value = mWifiNative.getNetworkVariable(config.networkId, - WifiConfiguration.GroupCipher.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.GroupCipher.strings); - if (0 <= index) { - config.allowedGroupCiphers.set(index); - } - } - } - - if (config.enterpriseConfig == null) { - config.enterpriseConfig = new WifiEnterpriseConfig(); - } - HashMap enterpriseFields = config.enterpriseConfig.getFields(); - for (String key : ENTERPRISE_CONFIG_SUPPLICANT_KEYS) { - value = mWifiNative.getNetworkVariable(netId, key); - if (!TextUtils.isEmpty(value)) { - enterpriseFields.put(key, removeDoubleQuotes(value)); - } else { - enterpriseFields.put(key, EMPTY_VALUE); - } - } - - if (migrateOldEapTlsNative(config.enterpriseConfig, netId)) { - saveConfig(); - } - - migrateCerts(config.enterpriseConfig); - // initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore); - } - - private String removeDoubleQuotes(String string) { - int length = string.length(); - if ((length > 1) && (string.charAt(0) == '"') - && (string.charAt(length - 1) == '"')) { - return string.substring(1, length - 1); - } - return string; - } - - private String convertToQuotedString(String string) { - return "\"" + string + "\""; - } - - private String makeString(BitSet set, String[] strings) { - StringBuffer buf = new StringBuffer(); - int nextSetBit = -1; - - /* Make sure all set bits are in [0, strings.length) to avoid - * going out of bounds on strings. (Shouldn't happen, but...) */ - set = set.get(0, strings.length); - - while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { - buf.append(strings[nextSetBit].replace('_', '-')).append(' '); - } - - // remove trailing space - if (set.cardinality() > 0) { - buf.setLength(buf.length() - 1); - } - - return buf.toString(); - } - - private int lookupString(String string, String[] strings) { - int size = strings.length; - - string = string.replace('-', '_'); - - for (int i = 0; i < size; i++) - if (string.equals(strings[i])) - return i; - - // if we ever get here, we should probably add the - // value to WifiConfiguration to reflect that it's - // supported by the WPA supplicant - loge("Failed to look-up a string: " + string); - - return -1; - } - - /* Returns a unique for a given configuration */ - private static int configKey(WifiConfiguration config) { - String key; - - if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { - key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK]; - } else if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || - config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { - key = config.SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP]; - } else if (config.wepKeys[0] != null) { - key = config.SSID + "WEP"; - } else { - key = config.SSID + KeyMgmt.strings[KeyMgmt.NONE]; - } - - return key.hashCode(); - } - - void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("WifiConfigStore"); - pw.println("mLastPriority " + mLastPriority); - pw.println("Configured networks"); - for (WifiConfiguration conf : getConfiguredNetworks()) { - pw.println(conf); - } - pw.println(); - - if (mLocalLog != null) { - pw.println("WifiConfigStore - Log Begin ----"); - mLocalLog.dump(fd, pw, args); - pw.println("WifiConfigStore - Log End ----"); - } - } - - public String getConfigFile() { - return ipConfigFile; - } - - private void loge(String s) { - Log.e(TAG, s); - } - - private void log(String s) { - Log.d(TAG, s); - } - - private void localLog(String s) { - if (mLocalLog != null) { - mLocalLog.log(s); - } - } - - private void localLog(String s, int netId) { - if (mLocalLog == null) { - return; - } - - WifiConfiguration config; - synchronized(mConfiguredNetworks) { - config = mConfiguredNetworks.get(netId); - } - - if (config != null) { - mLocalLog.log(s + " " + config.getPrintableSsid()); - } else { - mLocalLog.log(s + " " + netId); - } - } - - // Certificate and privake key management for EnterpriseConfig - boolean needsKeyStore(WifiEnterpriseConfig config) { - // Has no keys to be installed - if (config.getClientCertificate() == null && config.getCaCertificate() == null) - return false; - return true; - } - - static boolean isHardwareBackedKey(PrivateKey key) { - return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); - } - - static boolean hasHardwareBackedKey(Certificate certificate) { - return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); - } - - boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { - String client = config.getClientCertificateAlias(); - if (!TextUtils.isEmpty(client)) { - // a valid client certificate is configured - - // BUGBUG: keyStore.get() never returns certBytes; because it is not - // taking WIFI_UID as a parameter. It always looks for certificate - // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that - // all certificates need software keystore until we get the get() API - // fixed. - - return true; - } - - /* - try { - - if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials - .USER_CERTIFICATE + client); - - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - if (factory == null) { - Slog.e(TAG, "Error getting certificate factory"); - return; - } - - byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); - if (certBytes != null) { - Certificate cert = (X509Certificate) factory.generateCertificate( - new ByteArrayInputStream(certBytes)); - - if (cert != null) { - mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); - - if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials - .USER_CERTIFICATE + client); - if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : - "does not need" ) + " software key store"); - } else { - Slog.d(TAG, "could not generate certificate"); - } - } else { - Slog.e(TAG, "Could not load client certificate " + Credentials - .USER_CERTIFICATE + client); - mNeedsSoftwareKeystore = true; - } - - } catch(CertificateException e) { - Slog.e(TAG, "Could not read certificates"); - mCaCert = null; - mClientCertificate = null; - } - */ - - return false; - } - - boolean installKeys(WifiEnterpriseConfig config, String name) { - boolean ret = true; - String privKeyName = Credentials.USER_PRIVATE_KEY + name; - String userCertName = Credentials.USER_CERTIFICATE + name; - String caCertName = Credentials.CA_CERTIFICATE + name; - if (config.getClientCertificate() != null) { - byte[] privKeyData = config.getClientPrivateKey().getEncoded(); - if (isHardwareBackedKey(config.getClientPrivateKey())) { - // Hardware backed key store is secure enough to store keys un-encrypted, this - // removes the need for user to punch a PIN to get access to these keys - if (DBG) Log.d(TAG, "importing keys " + name + " in hardware backed store"); - ret = mKeyStore.importKey(privKeyName, privKeyData, android.os.Process.WIFI_UID, - KeyStore.FLAG_NONE); - } else { - // Software backed key store is NOT secure enough to store keys un-encrypted. - // Save keys encrypted so they are protected with user's PIN. User will - // have to unlock phone before being able to use these keys and connect to - // networks. - if (DBG) Log.d(TAG, "importing keys " + name + " in software backed store"); - ret = mKeyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, - KeyStore.FLAG_ENCRYPTED); - } - if (ret == false) { - return ret; - } - - ret = putCertInKeyStore(userCertName, config.getClientCertificate()); - if (ret == false) { - // Remove private key installed - mKeyStore.delKey(privKeyName, Process.WIFI_UID); - return ret; - } - } - - if (config.getCaCertificate() != null) { - ret = putCertInKeyStore(caCertName, config.getCaCertificate()); - if (ret == false) { - if (config.getClientCertificate() != null) { - // Remove client key+cert - mKeyStore.delKey(privKeyName, Process.WIFI_UID); - mKeyStore.delete(userCertName, Process.WIFI_UID); - } - return ret; - } - } - - // Set alias names - if (config.getClientCertificate() != null) { - config.setClientCertificateAlias(name); - config.resetClientKeyEntry(); - } - - if (config.getCaCertificate() != null) { - config.setCaCertificateAlias(name); - config.resetCaCertificate(); - } - - return ret; - } - - private boolean putCertInKeyStore(String name, Certificate cert) { - try { - byte[] certData = Credentials.convertToPem(cert); - if (DBG) Log.d(TAG, "putting certificate " + name + " in keystore"); - return mKeyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); - - } catch (IOException e1) { - return false; - } catch (CertificateException e2) { - return false; - } - } - - void removeKeys(WifiEnterpriseConfig config) { - String client = config.getClientCertificateAlias(); - // a valid client certificate is configured - if (!TextUtils.isEmpty(client)) { - if (DBG) Log.d(TAG, "removing client private key and user cert"); - mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); - mKeyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); - } - - String ca = config.getCaCertificateAlias(); - // a valid ca certificate is configured - if (!TextUtils.isEmpty(ca)) { - if (DBG) Log.d(TAG, "removing CA cert"); - mKeyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); - } - } - - - /** Migrates the old style TLS config to the new config style. This should only be used - * when restoring an old wpa_supplicant.conf or upgrading from a previous - * platform version. - * @return true if the config was updated - * @hide - */ - boolean migrateOldEapTlsNative(WifiEnterpriseConfig config, int netId) { - String oldPrivateKey = mWifiNative.getNetworkVariable(netId, OLD_PRIVATE_KEY_NAME); - /* - * If the old configuration value is not present, then there is nothing - * to do. - */ - if (TextUtils.isEmpty(oldPrivateKey)) { - return false; - } else { - // Also ignore it if it's empty quotes. - oldPrivateKey = removeDoubleQuotes(oldPrivateKey); - if (TextUtils.isEmpty(oldPrivateKey)) { - return false; - } - } - - config.setFieldValue(ENGINE_KEY, ENGINE_ENABLE); - config.setFieldValue(ENGINE_ID_KEY, ENGINE_ID_KEYSTORE); - - /* - * The old key started with the keystore:// URI prefix, but we don't - * need that anymore. Trim it off if it exists. - */ - final String keyName; - if (oldPrivateKey.startsWith(KEYSTORE_URI)) { - keyName = new String(oldPrivateKey.substring(KEYSTORE_URI.length())); - } else { - keyName = oldPrivateKey; - } - config.setFieldValue(PRIVATE_KEY_ID_KEY, keyName); - - mWifiNative.setNetworkVariable(netId, ENGINE_KEY, config.getFieldValue(ENGINE_KEY, "")); - - mWifiNative.setNetworkVariable(netId, ENGINE_ID_KEY, - config.getFieldValue(ENGINE_ID_KEY, "")); - - mWifiNative.setNetworkVariable(netId, PRIVATE_KEY_ID_KEY, - config.getFieldValue(PRIVATE_KEY_ID_KEY, "")); - - // Remove old private_key string so we don't run this again. - mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE); - - return true; - } - - /** Migrate certs from global pool to wifi UID if not already done */ - void migrateCerts(WifiEnterpriseConfig config) { - String client = config.getClientCertificateAlias(); - // a valid client certificate is configured - if (!TextUtils.isEmpty(client)) { - if (!mKeyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) { - mKeyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1, - Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); - mKeyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1, - Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); - } - } - - String ca = config.getCaCertificateAlias(); - // a valid ca certificate is configured - if (!TextUtils.isEmpty(ca)) { - if (!mKeyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) { - mKeyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1, - Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); - } - } - } -} diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 87afa88..6562462 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -499,7 +499,7 @@ public class WifiConfiguration implements Parcelable { * @throws IllegalStateException if config is invalid for key id generation * @hide */ - String getKeyIdForCredentials(WifiConfiguration current) { + public String getKeyIdForCredentials(WifiConfiguration current) { String keyMgmt = null; try { diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 452d84b..69be2cf 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -33,12 +33,67 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.util.HashMap; import java.util.Map; -/** +/** * Enterprise configuration details for Wi-Fi. Stores details about the EAP method * and any associated credentials. */ public class WifiEnterpriseConfig implements Parcelable { + /** @hide */ + public static final String EMPTY_VALUE = "NULL"; + /** @hide */ + public static final String EAP_KEY = "eap"; + /** @hide */ + public static final String PHASE2_KEY = "phase2"; + /** @hide */ + public static final String IDENTITY_KEY = "identity"; + /** @hide */ + public static final String ANON_IDENTITY_KEY = "anonymous_identity"; + /** @hide */ + public static final String PASSWORD_KEY = "password"; + /** @hide */ + public static final String SUBJECT_MATCH_KEY = "subject_match"; + /** @hide */ + public static final String OPP_KEY_CACHING = "proactive_key_caching"; + /** + * String representing the keystore OpenSSL ENGINE's ID. + * @hide + */ + public static final String ENGINE_ID_KEYSTORE = "keystore"; + + /** + * String representing the keystore URI used for wpa_supplicant. + * @hide + */ + public static final String KEYSTORE_URI = "keystore://"; + + /** + * String to set the engine value to when it should be enabled. + * @hide + */ + public static final String ENGINE_ENABLE = "1"; + + /** + * String to set the engine value to when it should be disabled. + * @hide + */ + public static final String ENGINE_DISABLE = "0"; + + /** @hide */ + public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE; + /** @hide */ + public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE; + /** @hide */ + public static final String CLIENT_CERT_KEY = "client_cert"; + /** @hide */ + public static final String CA_CERT_KEY = "ca_cert"; + /** @hide */ + public static final String ENGINE_KEY = "engine"; + /** @hide */ + public static final String ENGINE_ID_KEY = "engine_id"; + /** @hide */ + public static final String PRIVATE_KEY_ID_KEY = "key_id"; + private HashMap mFields = new HashMap(); private X509Certificate mCaCert; private PrivateKey mClientPrivateKey; @@ -189,15 +244,17 @@ public class WifiEnterpriseConfig implements Parcelable { public static final int GTC = 4; private static final String PREFIX = "auth="; /** @hide */ - public static final String[] strings = {WifiConfigStore.EMPTY_VALUE, "PAP", "MSCHAP", + public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" }; /** Prevent initialization */ private Phase2() {} } - /** Internal use only */ - HashMap getFields() { + /** Internal use only + * @hide + */ + public HashMap getFields() { return mFields; } @@ -214,8 +271,8 @@ public class WifiEnterpriseConfig implements Parcelable { case Eap.PWD: case Eap.TLS: case Eap.TTLS: - mFields.put(WifiConfigStore.EAP_KEY, Eap.strings[eapMethod]); - mFields.put(WifiConfigStore.OPP_KEY_CACHING, "1"); + mFields.put(EAP_KEY, Eap.strings[eapMethod]); + mFields.put(OPP_KEY_CACHING, "1"); break; default: throw new IllegalArgumentException("Unknown EAP method"); @@ -227,7 +284,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return eap method configured */ public int getEapMethod() { - String eapMethod = mFields.get(WifiConfigStore.EAP_KEY); + String eapMethod = mFields.get(EAP_KEY); return getStringIndex(Eap.strings, eapMethod, Eap.NONE); } @@ -243,14 +300,14 @@ public class WifiEnterpriseConfig implements Parcelable { public void setPhase2Method(int phase2Method) { switch (phase2Method) { case Phase2.NONE: - mFields.put(WifiConfigStore.PHASE2_KEY, WifiConfigStore.EMPTY_VALUE); + mFields.put(PHASE2_KEY, EMPTY_VALUE); break; /** Valid methods */ case Phase2.PAP: case Phase2.MSCHAP: case Phase2.MSCHAPV2: case Phase2.GTC: - mFields.put(WifiConfigStore.PHASE2_KEY, convertToQuotedString( + mFields.put(PHASE2_KEY, convertToQuotedString( Phase2.PREFIX + Phase2.strings[phase2Method])); break; default: @@ -263,7 +320,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return a phase 2 method defined at {@link Phase2} * */ public int getPhase2Method() { - String phase2Method = removeDoubleQuotes(mFields.get(WifiConfigStore.PHASE2_KEY)); + String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY)); // Remove auth= prefix if (phase2Method.startsWith(Phase2.PREFIX)) { phase2Method = phase2Method.substring(Phase2.PREFIX.length()); @@ -276,7 +333,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @param identity */ public void setIdentity(String identity) { - setFieldValue(WifiConfigStore.IDENTITY_KEY, identity, ""); + setFieldValue(IDENTITY_KEY, identity, ""); } /** @@ -284,7 +341,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return the identity */ public String getIdentity() { - return getFieldValue(WifiConfigStore.IDENTITY_KEY, ""); + return getFieldValue(IDENTITY_KEY, ""); } /** @@ -293,14 +350,14 @@ public class WifiEnterpriseConfig implements Parcelable { * @param anonymousIdentity the anonymous identity */ public void setAnonymousIdentity(String anonymousIdentity) { - setFieldValue(WifiConfigStore.ANON_IDENTITY_KEY, anonymousIdentity, ""); + setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, ""); } /** Get the anonymous identity * @return anonymous identity */ public String getAnonymousIdentity() { - return getFieldValue(WifiConfigStore.ANON_IDENTITY_KEY, ""); + return getFieldValue(ANON_IDENTITY_KEY, ""); } /** @@ -308,7 +365,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @param password the password */ public void setPassword(String password) { - setFieldValue(WifiConfigStore.PASSWORD_KEY, password, ""); + setFieldValue(PASSWORD_KEY, password, ""); } /** @@ -318,7 +375,7 @@ public class WifiEnterpriseConfig implements Parcelable { * framework, returns "*". */ public String getPassword() { - return getFieldValue(WifiConfigStore.PASSWORD_KEY, ""); + return getFieldValue(PASSWORD_KEY, ""); } /** @@ -331,7 +388,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public void setCaCertificateAlias(String alias) { - setFieldValue(WifiConfigStore.CA_CERT_KEY, alias, WifiConfigStore.CA_CERT_PREFIX); + setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX); } /** @@ -340,7 +397,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public String getCaCertificateAlias() { - return getFieldValue(WifiConfigStore.CA_CERT_KEY, WifiConfigStore.CA_CERT_PREFIX); + return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); } /** @@ -381,8 +438,7 @@ public class WifiEnterpriseConfig implements Parcelable { mCaCert = null; } - /** - * Set Client certificate alias. + /** Set Client certificate alias. * *

See the {@link android.security.KeyChain} for details on installing or choosing * a certificate @@ -391,16 +447,15 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public void setClientCertificateAlias(String alias) { - setFieldValue(WifiConfigStore.CLIENT_CERT_KEY, alias, WifiConfigStore.CLIENT_CERT_PREFIX); - setFieldValue(WifiConfigStore.PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); + setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX); + setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); // Also, set engine parameters if (TextUtils.isEmpty(alias)) { - mFields.put(WifiConfigStore.ENGINE_KEY, WifiConfigStore.ENGINE_DISABLE); - mFields.put(WifiConfigStore.ENGINE_ID_KEY, WifiConfigStore.EMPTY_VALUE); + mFields.put(ENGINE_KEY, ENGINE_DISABLE); + mFields.put(ENGINE_ID_KEY, EMPTY_VALUE); } else { - mFields.put(WifiConfigStore.ENGINE_KEY, WifiConfigStore.ENGINE_ENABLE); - mFields.put(WifiConfigStore.ENGINE_ID_KEY, - convertToQuotedString(WifiConfigStore.ENGINE_ID_KEYSTORE)); + mFields.put(ENGINE_KEY, ENGINE_ENABLE); + mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE)); } } @@ -410,7 +465,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @hide */ public String getClientCertificateAlias() { - return getFieldValue(WifiConfigStore.CLIENT_CERT_KEY, WifiConfigStore.CLIENT_CERT_PREFIX); + return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); } /** @@ -472,7 +527,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @param subjectMatch substring to be matched */ public void setSubjectMatch(String subjectMatch) { - setFieldValue(WifiConfigStore.SUBJECT_MATCH_KEY, subjectMatch, ""); + setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, ""); } /** @@ -480,20 +535,20 @@ public class WifiEnterpriseConfig implements Parcelable { * @return the subject match string */ public String getSubjectMatch() { - return getFieldValue(WifiConfigStore.SUBJECT_MATCH_KEY, ""); + return getFieldValue(SUBJECT_MATCH_KEY, ""); } /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */ String getKeyId(WifiEnterpriseConfig current) { - String eap = mFields.get(WifiConfigStore.EAP_KEY); - String phase2 = mFields.get(WifiConfigStore.PHASE2_KEY); + String eap = mFields.get(EAP_KEY); + String phase2 = mFields.get(PHASE2_KEY); // If either eap or phase2 are not initialized, use current config details if (TextUtils.isEmpty((eap))) { - eap = current.mFields.get(WifiConfigStore.EAP_KEY); + eap = current.mFields.get(EAP_KEY); } if (TextUtils.isEmpty(phase2)) { - phase2 = current.mFields.get(WifiConfigStore.PHASE2_KEY); + phase2 = current.mFields.get(PHASE2_KEY); } return eap + "_" + phase2; } @@ -532,10 +587,10 @@ public class WifiEnterpriseConfig implements Parcelable { * @return value * @hide */ - String getFieldValue(String key, String prefix) { + public String getFieldValue(String key, String prefix) { String value = mFields.get(key); // Uninitialized or known to be empty after reading from supplicant - if (TextUtils.isEmpty(value) || WifiConfigStore.EMPTY_VALUE.equals(value)) return ""; + if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return ""; value = removeDoubleQuotes(value); if (value.startsWith(prefix)) { @@ -549,10 +604,11 @@ public class WifiEnterpriseConfig implements Parcelable { * @param key into the hash * @param value to be set * @param prefix an optional value to be prefixed to actual value + * @hide */ - private void setFieldValue(String key, String value, String prefix) { + public void setFieldValue(String key, String value, String prefix) { if (TextUtils.isEmpty(value)) { - mFields.put(key, WifiConfigStore.EMPTY_VALUE); + mFields.put(key, EMPTY_VALUE); } else { mFields.put(key, convertToQuotedString(prefix + value)); } @@ -567,7 +623,7 @@ public class WifiEnterpriseConfig implements Parcelable { */ public void setFieldValue(String key, String value) { if (TextUtils.isEmpty(value)) { - mFields.put(key, WifiConfigStore.EMPTY_VALUE); + mFields.put(key, EMPTY_VALUE); } else { mFields.put(key, convertToQuotedString(value)); } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index dea0c6c..6a13067 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -78,7 +78,8 @@ public class WifiInfo implements Parcelable { */ private boolean mMeteredHint; - WifiInfo() { + /** @hide */ + public WifiInfo() { mWifiSsid = null; mBSSID = null; mNetworkId = -1; @@ -105,7 +106,8 @@ public class WifiInfo implements Parcelable { } } - void setSSID(WifiSsid wifiSsid) { + /** @hide */ + public void setSSID(WifiSsid wifiSsid) { mWifiSsid = wifiSsid; } @@ -133,7 +135,8 @@ public class WifiInfo implements Parcelable { return mWifiSsid; } - void setBSSID(String BSSID) { + /** @hide */ + public void setBSSID(String BSSID) { mBSSID = BSSID; } @@ -156,7 +159,8 @@ public class WifiInfo implements Parcelable { return mRssi; } - void setRssi(int rssi) { + /** @hide */ + public void setRssi(int rssi) { mRssi = rssi; } @@ -169,15 +173,17 @@ public class WifiInfo implements Parcelable { return mLinkSpeed; } - void setLinkSpeed(int linkSpeed) { + /** @hide */ + public void setLinkSpeed(int linkSpeed) { this.mLinkSpeed = linkSpeed; } /** * Record the MAC address of the WLAN interface * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form + * @hide */ - void setMacAddress(String macAddress) { + public void setMacAddress(String macAddress) { this.mMacAddress = macAddress; } @@ -195,7 +201,8 @@ public class WifiInfo implements Parcelable { return mMeteredHint; } - void setNetworkId(int id) { + /** @hide */ + public void setNetworkId(int id) { mNetworkId = id; } @@ -218,11 +225,13 @@ public class WifiInfo implements Parcelable { return mSupplicantState; } - void setSupplicantState(SupplicantState state) { + /** @hide */ + public void setSupplicantState(SupplicantState state) { mSupplicantState = state; } - void setInetAddress(InetAddress address) { + /** @hide */ + public void setInetAddress(InetAddress address) { mIpAddress = address; } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index ae1fbf7..aabe007 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -522,6 +522,9 @@ public class WifiManager { /** @hide */ public static final int DATA_ACTIVITY_INOUT = 0x03; + /** @hide */ + public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false; + /* Maximum number of active locks we allow. * This limit was added to prevent apps from creating a ridiculous number * of locks and crashing the system by overflowing the global ref table. diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java deleted file mode 100644 index a18954c..0000000 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ /dev/null @@ -1,936 +0,0 @@ -/* - * Copyright (C) 2008 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 android.net.wifi; - -import android.net.NetworkInfo; -import android.net.wifi.p2p.WifiP2pConfig; -import android.net.wifi.p2p.WifiP2pDevice; -import android.net.wifi.p2p.WifiP2pGroup; -import android.net.wifi.p2p.WifiP2pProvDiscEvent; -import android.net.wifi.p2p.WifiP2pService.P2pStatus; -import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; -import android.os.Message; -import android.util.Log; - -import com.android.internal.util.Protocol; -import com.android.internal.util.StateMachine; - -import java.util.HashMap; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Listens for events from the wpa_supplicant server, and passes them on - * to the {@link StateMachine} for handling. Runs in its own thread. - * - * @hide - */ -public class WifiMonitor { - - private static final boolean DBG = false; - private static final String TAG = "WifiMonitor"; - - /** Events we receive from the supplicant daemon */ - - private static final int CONNECTED = 1; - private static final int DISCONNECTED = 2; - private static final int STATE_CHANGE = 3; - private static final int SCAN_RESULTS = 4; - private static final int LINK_SPEED = 5; - private static final int TERMINATING = 6; - private static final int DRIVER_STATE = 7; - private static final int EAP_FAILURE = 8; - private static final int ASSOC_REJECT = 9; - private static final int UNKNOWN = 10; - - /** 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(); - - /** All WPA events coming from the supplicant start with this prefix */ - private static final String WPA_EVENT_PREFIX_STR = "WPA:"; - private static final String PASSWORD_MAY_BE_INCORRECT_STR = - "pre-shared key may be incorrect"; - - /* WPS events */ - private static final String WPS_SUCCESS_STR = "WPS-SUCCESS"; - - /* Format: WPS-FAIL msg=%d [config_error=%d] [reason=%d (%s)] */ - private static final String WPS_FAIL_STR = "WPS-FAIL"; - private static final String WPS_FAIL_PATTERN = - "WPS-FAIL msg=\\d+(?: config_error=(\\d+))?(?: reason=(\\d+))?"; - - /* config error code values for config_error=%d */ - private static final int CONFIG_MULTIPLE_PBC_DETECTED = 12; - private static final int CONFIG_AUTH_FAILURE = 18; - - /* reason code values for reason=%d */ - private static final int REASON_TKIP_ONLY_PROHIBITED = 1; - private static final int REASON_WEP_PROHIBITED = 2; - - private static final String WPS_OVERLAP_STR = "WPS-OVERLAP-DETECTED"; - private static final String WPS_TIMEOUT_STR = "WPS-TIMEOUT"; - - /** - * Names of events from wpa_supplicant (minus the prefix). In the - * format descriptions, * "x" - * designates a dynamic value that needs to be parsed out from the event - * string - */ - /** - *

-     * CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed
-     * 
- * xx:xx:xx:xx:xx:xx is the BSSID of the associated access point - */ - private static final String CONNECTED_STR = "CONNECTED"; - /** - *
-     * CTRL-EVENT-DISCONNECTED - Disconnect event - remove keys
-     * 
- */ - private static final String DISCONNECTED_STR = "DISCONNECTED"; - /** - *
-     * CTRL-EVENT-STATE-CHANGE x
-     * 
- * x is the numerical value of the new state. - */ - private static final String STATE_CHANGE_STR = "STATE-CHANGE"; - /** - *
-     * CTRL-EVENT-SCAN-RESULTS ready
-     * 
- */ - private static final String SCAN_RESULTS_STR = "SCAN-RESULTS"; - - /** - *
-     * CTRL-EVENT-LINK-SPEED x Mb/s
-     * 
- * {@code x} is the link speed in Mb/sec. - */ - private static final String LINK_SPEED_STR = "LINK-SPEED"; - /** - *
-     * CTRL-EVENT-TERMINATING - signal x
-     * 
- * x is the signal that caused termination. - */ - private static final String TERMINATING_STR = "TERMINATING"; - /** - *
-     * CTRL-EVENT-DRIVER-STATE state
-     * 
- * state can be HANGED - */ - private static final String DRIVER_STATE_STR = "DRIVER-STATE"; - /** - *
-     * CTRL-EVENT-EAP-FAILURE EAP authentication failed
-     * 
- */ - private static final String EAP_FAILURE_STR = "EAP-FAILURE"; - - /** - * This indicates an authentication failure on EAP FAILURE event - */ - private static final String EAP_AUTH_FAILURE_STR = "EAP authentication failed"; - - /** - * This indicates an assoc reject event - */ - private static final String ASSOC_REJECT_STR = "ASSOC-REJECT"; - - /** - * Regex pattern for extracting an Ethernet-style MAC address from a string. - * Matches a strings like the following:
-     * CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]
- */ - private static Pattern mConnectedEventPattern = - Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) "); - - /** P2P events */ - private static final String P2P_EVENT_PREFIX_STR = "P2P"; - - /* P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13 pri_dev_type=1-0050F204-1 - name='p2p-TEST1' config_methods=0x188 dev_capab=0x27 group_capab=0x0 */ - private static final String P2P_DEVICE_FOUND_STR = "P2P-DEVICE-FOUND"; - - /* P2P-DEVICE-LOST p2p_dev_addr=42:fc:89:e1:e2:27 */ - private static final String P2P_DEVICE_LOST_STR = "P2P-DEVICE-LOST"; - - /* P2P-FIND-STOPPED */ - private static final String P2P_FIND_STOPPED_STR = "P2P-FIND-STOPPED"; - - /* P2P-GO-NEG-REQUEST 42:fc:89:a8:96:09 dev_passwd_id=4 */ - private static final String P2P_GO_NEG_REQUEST_STR = "P2P-GO-NEG-REQUEST"; - - private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS"; - - /* P2P-GO-NEG-FAILURE status=x */ - private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE"; - - private static final String P2P_GROUP_FORMATION_SUCCESS_STR = - "P2P-GROUP-FORMATION-SUCCESS"; - - private static final String P2P_GROUP_FORMATION_FAILURE_STR = - "P2P-GROUP-FORMATION-FAILURE"; - - /* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437 - [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|passphrase="fKG4jMe3"] - go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT] */ - private static final String P2P_GROUP_STARTED_STR = "P2P-GROUP-STARTED"; - - /* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED */ - private static final String P2P_GROUP_REMOVED_STR = "P2P-GROUP-REMOVED"; - - /* P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13 - bssid=fa:7b:7a:42:82:13 unknown-network */ - private static final String P2P_INVITATION_RECEIVED_STR = "P2P-INVITATION-RECEIVED"; - - /* P2P-INVITATION-RESULT status=1 */ - private static final String P2P_INVITATION_RESULT_STR = "P2P-INVITATION-RESULT"; - - /* P2P-PROV-DISC-PBC-REQ 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 - pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 - group_capab=0x0 */ - private static final String P2P_PROV_DISC_PBC_REQ_STR = "P2P-PROV-DISC-PBC-REQ"; - - /* P2P-PROV-DISC-PBC-RESP 02:12:47:f2:5a:36 */ - private static final String P2P_PROV_DISC_PBC_RSP_STR = "P2P-PROV-DISC-PBC-RESP"; - - /* P2P-PROV-DISC-ENTER-PIN 42:fc:89:e1:e2:27 p2p_dev_addr=42:fc:89:e1:e2:27 - pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 - group_capab=0x0 */ - private static final String P2P_PROV_DISC_ENTER_PIN_STR = "P2P-PROV-DISC-ENTER-PIN"; - /* P2P-PROV-DISC-SHOW-PIN 42:fc:89:e1:e2:27 44490607 p2p_dev_addr=42:fc:89:e1:e2:27 - pri_dev_type=1-0050F204-1 name='p2p-TEST2' config_methods=0x188 dev_capab=0x27 - group_capab=0x0 */ - private static final String P2P_PROV_DISC_SHOW_PIN_STR = "P2P-PROV-DISC-SHOW-PIN"; - /* P2P-PROV-DISC-FAILURE p2p_dev_addr=42:fc:89:e1:e2:27 */ - private static final String P2P_PROV_DISC_FAILURE_STR = "P2P-PROV-DISC-FAILURE"; - - /* - * Protocol format is as follows.
- * See the Table.62 in the WiFi Direct specification for the detail. - * ______________________________________________________________ - * | Length(2byte) | Type(1byte) | TransId(1byte)}| - * ______________________________________________________________ - * | status(1byte) | vendor specific(variable) | - * - * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300000101 - * length=3, service type=0(ALL Service), transaction id=1, - * status=1(service protocol type not available)
- * - * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 0300020201 - * length=3, service type=2(UPnP), transaction id=2, - * status=1(service protocol type not available) - * - * P2P-SERV-DISC-RESP 42:fc:89:e1:e2:27 1 990002030010757569643a3131323 - * 2646534652d383537342d353961622d393332322d3333333435363738393034343a3 - * a75726e3a736368656d61732d75706e702d6f72673a736572766963653a436f6e746 - * 56e744469726563746f72793a322c757569643a36383539646564652d383537342d3 - * 53961622d393333322d3132333435363738393031323a3a75706e703a726f6f74646 - * 576696365 - * length=153,type=2(UPnP),transaction id=3,status=0 - * - * UPnP Protocol format is as follows. - * ______________________________________________________ - * | Version (1) | USN (Variable) | - * - * version=0x10(UPnP1.0) data=usn:uuid:1122de4e-8574-59ab-9322-33345678 - * 9044::urn:schemas-upnp-org:service:ContentDirectory:2,usn:uuid:6859d - * ede-8574-59ab-9332-123456789012::upnp:rootdevice - * - * P2P-SERV-DISC-RESP 58:17:0c:bc:dd:ca 21 1900010200045f6970 - * 70c00c000c01094d795072696e746572c027 - * length=25, type=1(Bonjour),transaction id=2,status=0 - * - * Bonjour Protocol format is as follows. - * __________________________________________________________ - * |DNS Name(Variable)|DNS Type(1)|Version(1)|RDATA(Variable)| - * - * DNS Name=_ipp._tcp.local.,DNS type=12(PTR), Version=1, - * RDATA=MyPrinter._ipp._tcp.local. - * - */ - private static final String P2P_SERV_DISC_RESP_STR = "P2P-SERV-DISC-RESP"; - - 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"; - /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */ - private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; - - /* Supplicant events reported to a state machine */ - private static final int BASE = Protocol.BASE_WIFI_MONITOR; - - /* Connection to supplicant established */ - public static final int SUP_CONNECTION_EVENT = BASE + 1; - /* Connection to supplicant lost */ - public static final int SUP_DISCONNECTION_EVENT = BASE + 2; - /* Network connection completed */ - public static final int NETWORK_CONNECTION_EVENT = BASE + 3; - /* Network disconnection completed */ - public static final int NETWORK_DISCONNECTION_EVENT = BASE + 4; - /* Scan results are available */ - public static final int SCAN_RESULTS_EVENT = BASE + 5; - /* Supplicate state changed */ - public static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 6; - /* Password failure and EAP authentication failure */ - public static final int AUTHENTICATION_FAILURE_EVENT = BASE + 7; - /* WPS success detected */ - public static final int WPS_SUCCESS_EVENT = BASE + 8; - /* WPS failure detected */ - public static final int WPS_FAIL_EVENT = BASE + 9; - /* WPS overlap detected */ - public static final int WPS_OVERLAP_EVENT = BASE + 10; - /* WPS timeout detected */ - public static final int WPS_TIMEOUT_EVENT = BASE + 11; - /* Driver was hung */ - public static final int DRIVER_HUNG_EVENT = BASE + 12; - - /* P2P events */ - public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21; - public static final int P2P_DEVICE_LOST_EVENT = BASE + 22; - public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT = BASE + 23; - public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT = BASE + 25; - public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT = BASE + 26; - public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT = BASE + 27; - public static final int P2P_GROUP_FORMATION_FAILURE_EVENT = BASE + 28; - public static final int P2P_GROUP_STARTED_EVENT = BASE + 29; - public static final int P2P_GROUP_REMOVED_EVENT = BASE + 30; - public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31; - public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32; - public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33; - public static final int P2P_PROV_DISC_PBC_RSP_EVENT = BASE + 34; - public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 35; - public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 36; - 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; - - /* hostap events */ - public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41; - public static final int AP_STA_CONNECTED_EVENT = BASE + 42; - - /* Indicates assoc reject event */ - public static final int ASSOCIATION_REJECTION_EVENT = BASE + 43; - - /** - * This indicates a read error on the monitor socket conenction - */ - private static final String WPA_RECV_ERROR_STR = "recv error"; - - /** - * Max errors before we close supplicant connection - */ - private static final int MAX_RECV_ERRORS = 10; - - private final String mInterfaceName; - private final WifiNative mWifiNative; - private final StateMachine mStateMachine; - private boolean mMonitoring; - - // This is a global counter, since it's not monitor specific. However, the existing - // implementation forwards all "global" control events like CTRL-EVENT-TERMINATING - // to the p2p0 monitor. Is that expected ? It seems a bit surprising. - // - // TODO: If the p2p0 monitor isn't registered, the behaviour is even more surprising. - // The event will be dispatched to all monitors, and each of them will end up incrementing - // it in their dispatchXXX method. If we have 5 registered monitors (say), 2 consecutive - // recv errors will cause us to disconnect from the supplicant (instead of the intended 10). - // - // This variable is always accessed and modified under a WifiMonitorSingleton lock. - private static int sRecvErrors; - - public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) { - if (DBG) Log.d(TAG, "Creating WifiMonitor"); - mWifiNative = wifiNative; - mInterfaceName = wifiNative.mInterfaceName; - mStateMachine = wifiStateMachine; - mMonitoring = false; - - WifiMonitorSingleton.sInstance.registerInterfaceMonitor(mInterfaceName, this); - } - - public void startMonitoring() { - WifiMonitorSingleton.sInstance.startMonitoring(mInterfaceName); - } - - public void stopMonitoring() { - WifiMonitorSingleton.sInstance.stopMonitoring(mInterfaceName); - } - - public void stopSupplicant() { - WifiMonitorSingleton.sInstance.stopSupplicant(); - } - - public void killSupplicant(boolean p2pSupported) { - WifiMonitorSingleton.sInstance.killSupplicant(p2pSupported); - } - - private static class WifiMonitorSingleton { - private static final WifiMonitorSingleton sInstance = new WifiMonitorSingleton(); - - private final HashMap mIfaceMap = new HashMap(); - private boolean mConnected = false; - private WifiNative mWifiNative; - - private WifiMonitorSingleton() { - } - - public synchronized void startMonitoring(String iface) { - WifiMonitor m = mIfaceMap.get(iface); - if (m == null) { - Log.e(TAG, "startMonitor called with unknown iface=" + iface); - return; - } - - Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected); - - if (mConnected) { - m.mMonitoring = true; - m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); - } else { - if (DBG) Log.d(TAG, "connecting to supplicant"); - int connectTries = 0; - while (true) { - if (mWifiNative.connectToSupplicant()) { - m.mMonitoring = true; - m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); - new MonitorThread(mWifiNative, this).start(); - mConnected = true; - break; - } - if (connectTries++ < 5) { - try { - Thread.sleep(1000); - } catch (InterruptedException ignore) { - } - } else { - mIfaceMap.remove(iface); - m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); - Log.e(TAG, "startMonitoring(" + iface + ") failed!"); - break; - } - } - } - } - - public synchronized void stopMonitoring(String iface) { - WifiMonitor m = mIfaceMap.get(iface); - if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mStateMachine); - m.mMonitoring = false; - m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); - } - - public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) { - if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mStateMachine + ")"); - mIfaceMap.put(iface, m); - if (mWifiNative == null) { - mWifiNative = m.mWifiNative; - } - } - - public synchronized void unregisterInterfaceMonitor(String iface) { - // REVIEW: When should we call this? If this isn't called, then WifiMonitor - // objects will remain in the mIfaceMap; and won't ever get deleted - - WifiMonitor m = mIfaceMap.remove(iface); - if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mStateMachine + ")"); - } - - public synchronized void stopSupplicant() { - mWifiNative.stopSupplicant(); - } - - public synchronized void killSupplicant(boolean p2pSupported) { - WifiNative.killSupplicant(p2pSupported); - mConnected = false; - for (WifiMonitor m : mIfaceMap.values()) { - m.mMonitoring = false; - } - } - - private synchronized boolean dispatchEvent(String eventStr) { - String iface; - if (eventStr.startsWith("IFNAME=")) { - int space = eventStr.indexOf(' '); - if (space != -1) { - iface = eventStr.substring(7, space); - if (!mIfaceMap.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"; - } - eventStr = eventStr.substring(space + 1); - } else { - // No point dispatching this event to any interface, the dispatched - // event string will begin with "IFNAME=" which dispatchEvent can't really - // do anything about. - Log.e(TAG, "Dropping malformed event (unparsable iface): " + eventStr); - return false; - } - } else { - // events without prefix belong to p2p0 monitor - iface = "p2p0"; - } - - if (DBG) Log.d(TAG, "Dispatching event to interface: " + iface); - - WifiMonitor m = mIfaceMap.get(iface); - if (m != null) { - if (m.mMonitoring) { - if (m.dispatchEvent(eventStr)) { - mConnected = false; - return true; - } - - return false; - } else { - if (DBG) Log.d(TAG, "Dropping event because (" + iface + ") is stopped"); - return false; - } - } else { - if (DBG) Log.d(TAG, "Sending to all monitors because there's no matching iface"); - boolean done = false; - for (WifiMonitor monitor : mIfaceMap.values()) { - if (monitor.mMonitoring && monitor.dispatchEvent(eventStr)) { - done = true; - } - } - - if (done) { - mConnected = false; - } - - return done; - } - } - } - - private static class MonitorThread extends Thread { - private final WifiNative mWifiNative; - private final WifiMonitorSingleton mWifiMonitorSingleton; - - public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) { - super("WifiMonitor"); - mWifiNative = wifiNative; - mWifiMonitorSingleton = wifiMonitorSingleton; - } - - public void run() { - //noinspection InfiniteLoopStatement - for (;;) { - String eventStr = mWifiNative.waitForEvent(); - - // Skip logging the common but mostly uninteresting scan-results event - if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { - Log.d(TAG, "Event [" + eventStr + "]"); - } - - if (mWifiMonitorSingleton.dispatchEvent(eventStr)) { - if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events"); - break; - } - } - } - } - - /* @return true if the event was supplicant disconnection */ - private boolean dispatchEvent(String eventStr) { - - if (!eventStr.startsWith(EVENT_PREFIX_STR)) { - if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) && - 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) { - mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); - } else if (eventStr.startsWith(WPS_SUCCESS_STR)) { - mStateMachine.sendMessage(WPS_SUCCESS_EVENT); - } else if (eventStr.startsWith(WPS_FAIL_STR)) { - handleWpsFailEvent(eventStr); - } else if (eventStr.startsWith(WPS_OVERLAP_STR)) { - mStateMachine.sendMessage(WPS_OVERLAP_EVENT); - } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) { - mStateMachine.sendMessage(WPS_TIMEOUT_EVENT); - } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) { - handleP2pEvents(eventStr); - } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) { - handleHostApEvents(eventStr); - } - else { - if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr); - } - return false; - } - - String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR); - int nameEnd = eventName.indexOf(' '); - if (nameEnd != -1) - eventName = eventName.substring(0, nameEnd); - if (eventName.length() == 0) { - if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name"); - return false; - } - /* - * Map event name into event enum - */ - int event; - if (eventName.equals(CONNECTED_STR)) - event = CONNECTED; - else if (eventName.equals(DISCONNECTED_STR)) - event = DISCONNECTED; - else if (eventName.equals(STATE_CHANGE_STR)) - event = STATE_CHANGE; - else if (eventName.equals(SCAN_RESULTS_STR)) - event = SCAN_RESULTS; - else if (eventName.equals(LINK_SPEED_STR)) - event = LINK_SPEED; - else if (eventName.equals(TERMINATING_STR)) - event = TERMINATING; - else if (eventName.equals(DRIVER_STATE_STR)) - event = DRIVER_STATE; - else if (eventName.equals(EAP_FAILURE_STR)) - event = EAP_FAILURE; - else if (eventName.equals(ASSOC_REJECT_STR)) - event = ASSOC_REJECT; - else - event = UNKNOWN; - - String eventData = eventStr; - if (event == DRIVER_STATE || event == LINK_SPEED) - eventData = eventData.split(" ")[1]; - else if (event == STATE_CHANGE || event == EAP_FAILURE) { - int ind = eventStr.indexOf(" "); - if (ind != -1) { - eventData = eventStr.substring(ind + 1); - } - } else { - int ind = eventStr.indexOf(" - "); - if (ind != -1) { - eventData = eventStr.substring(ind + 3); - } - } - - if (event == STATE_CHANGE) { - handleSupplicantStateChange(eventData); - } else if (event == DRIVER_STATE) { - handleDriverEvent(eventData); - } else if (event == TERMINATING) { - /** - * Close the supplicant connection if we see - * too many recv errors - */ - if (eventData.startsWith(WPA_RECV_ERROR_STR)) { - if (++sRecvErrors > MAX_RECV_ERRORS) { - if (DBG) { - Log.d(TAG, "too many recv errors, closing connection"); - } - } else { - return false; - } - } - - // notify and exit - mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); - return true; - } else if (event == EAP_FAILURE) { - if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) { - mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); - } - } else if (event == ASSOC_REJECT) { - mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT); - } else { - handleEvent(event, eventData); - } - sRecvErrors = 0; - return false; - } - - private void handleDriverEvent(String state) { - if (state == null) { - return; - } - if (state.equals("HANGED")) { - mStateMachine.sendMessage(DRIVER_HUNG_EVENT); - } - } - - /** - * Handle all supplicant events except STATE-CHANGE - * @param event the event type - * @param remainder the rest of the string following the - * event name and " — " - */ - void handleEvent(int event, String remainder) { - switch (event) { - case DISCONNECTED: - handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder); - break; - - case CONNECTED: - handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder); - break; - - case SCAN_RESULTS: - mStateMachine.sendMessage(SCAN_RESULTS_EVENT); - break; - - case UNKNOWN: - break; - } - } - - private void handleWpsFailEvent(String dataString) { - final Pattern p = Pattern.compile(WPS_FAIL_PATTERN); - Matcher match = p.matcher(dataString); - if (match.find()) { - String cfgErr = match.group(1); - String reason = match.group(2); - - if (reason != null) { - switch(Integer.parseInt(reason)) { - case REASON_TKIP_ONLY_PROHIBITED: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_TKIP_ONLY_PROHIBITED, 0)); - return; - case REASON_WEP_PROHIBITED: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_WEP_PROHIBITED, 0)); - return; - } - } - if (cfgErr != null) { - switch(Integer.parseInt(cfgErr)) { - case CONFIG_AUTH_FAILURE: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_AUTH_FAILURE, 0)); - return; - case CONFIG_MULTIPLE_PBC_DETECTED: - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.WPS_OVERLAP_ERROR, 0)); - return; - } - } - } - //For all other errors, return a generic internal error - mStateMachine.sendMessage(mStateMachine.obtainMessage(WPS_FAIL_EVENT, - WifiManager.ERROR, 0)); - } - - /* status= and the special case of reason=FREQ_CONFLICT */ - private P2pStatus p2pError(String dataString) { - P2pStatus err = P2pStatus.UNKNOWN; - String[] tokens = dataString.split(" "); - if (tokens.length < 2) return err; - String[] nameValue = tokens[1].split("="); - if (nameValue.length != 2) return err; - - /* Handle the special case of reason=FREQ+CONFLICT */ - if (nameValue[1].equals("FREQ_CONFLICT")) { - return P2pStatus.NO_COMMON_CHANNEL; - } - try { - err = P2pStatus.valueOf(Integer.parseInt(nameValue[1])); - } catch (NumberFormatException e) { - e.printStackTrace(); - } - return err; - } - - /** - * Handle p2p events - */ - private void handleP2pEvents(String dataString) { - if (dataString.startsWith(P2P_DEVICE_FOUND_STR)) { - mStateMachine.sendMessage(P2P_DEVICE_FOUND_EVENT, new WifiP2pDevice(dataString)); - } else if (dataString.startsWith(P2P_DEVICE_LOST_STR)) { - mStateMachine.sendMessage(P2P_DEVICE_LOST_EVENT, new WifiP2pDevice(dataString)); - } else if (dataString.startsWith(P2P_FIND_STOPPED_STR)) { - mStateMachine.sendMessage(P2P_FIND_STOPPED_EVENT); - } else if (dataString.startsWith(P2P_GO_NEG_REQUEST_STR)) { - mStateMachine.sendMessage(P2P_GO_NEGOTIATION_REQUEST_EVENT, - new WifiP2pConfig(dataString)); - } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) { - mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT); - } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) { - mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString)); - } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) { - mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT); - } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) { - mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString)); - } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) { - mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString)); - } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) { - mStateMachine.sendMessage(P2P_GROUP_REMOVED_EVENT, new WifiP2pGroup(dataString)); - } else if (dataString.startsWith(P2P_INVITATION_RECEIVED_STR)) { - mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT, - new WifiP2pGroup(dataString)); - } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) { - mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, p2pError(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_PBC_RSP_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_PBC_RSP_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_ENTER_PIN_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_ENTER_PIN_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_SHOW_PIN_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_SHOW_PIN_EVENT, - new WifiP2pProvDiscEvent(dataString)); - } else if (dataString.startsWith(P2P_PROV_DISC_FAILURE_STR)) { - mStateMachine.sendMessage(P2P_PROV_DISC_FAILURE_EVENT); - } else if (dataString.startsWith(P2P_SERV_DISC_RESP_STR)) { - List list = WifiP2pServiceResponse.newInstance(dataString); - if (list != null) { - mStateMachine.sendMessage(P2P_SERV_DISC_RESP_EVENT, list); - } else { - Log.e(TAG, "Null service resp " + dataString); - } - } - } - - /** - * Handle hostap events - */ - private void handleHostApEvents(String dataString) { - String[] tokens = dataString.split(" "); - /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ - if (tokens[0].equals(AP_STA_CONNECTED_STR)) { - mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString)); - /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */ - } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) { - mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString)); - } - } - - /** - * Handle the supplicant STATE-CHANGE event - * @param dataString New supplicant state string in the format: - * id=network-id state=new-state - */ - private void handleSupplicantStateChange(String dataString) { - WifiSsid wifiSsid = null; - int index = dataString.lastIndexOf("SSID="); - if (index != -1) { - wifiSsid = WifiSsid.createFromAsciiEncoded( - dataString.substring(index + 5)); - } - String[] dataTokens = dataString.split(" "); - - String BSSID = null; - int networkId = -1; - int newState = -1; - for (String token : dataTokens) { - String[] nameValue = token.split("="); - if (nameValue.length != 2) { - continue; - } - - if (nameValue[0].equals("BSSID")) { - BSSID = nameValue[1]; - continue; - } - - int value; - try { - value = Integer.parseInt(nameValue[1]); - } catch (NumberFormatException e) { - continue; - } - - if (nameValue[0].equals("id")) { - networkId = value; - } else if (nameValue[0].equals("state")) { - newState = value; - } - } - - if (newState == -1) return; - - SupplicantState newSupplicantState = SupplicantState.INVALID; - for (SupplicantState state : SupplicantState.values()) { - if (state.ordinal() == newState) { - newSupplicantState = state; - break; - } - } - if (newSupplicantState == SupplicantState.INVALID) { - Log.w(TAG, "Invalid supplicant state: " + newState); - } - notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState); - } - - private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) { - String BSSID = null; - int networkId = -1; - if (newState == NetworkInfo.DetailedState.CONNECTED) { - Matcher match = mConnectedEventPattern.matcher(data); - if (!match.find()) { - if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string"); - } else { - BSSID = match.group(1); - try { - networkId = Integer.parseInt(match.group(2)); - } catch (NumberFormatException e) { - networkId = -1; - } - } - notifyNetworkStateChange(newState, BSSID, networkId); - } - } - - /** - * Send the state machine a notification that the state of Wifi connectivity - * has changed. - * @param newState the new network state - * @param BSSID when the new state is {@link NetworkInfo.DetailedState#CONNECTED}, - * this is the MAC address of the access point. Otherwise, it - * is {@code null}. - * @param netId the configured network on which the state change occurred - */ - void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) { - if (newState == NetworkInfo.DetailedState.CONNECTED) { - Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT, - netId, 0, BSSID); - mStateMachine.sendMessage(m); - } else { - Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT, - netId, 0, BSSID); - mStateMachine.sendMessage(m); - } - } - - /** - * Send the state machine a notification that the state of the supplicant - * has changed. - * @param networkId the configured network on which the state change occurred - * @param wifiSsid network name - * @param BSSID network address - * @param newState the new {@code SupplicantState} - */ - void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID, - SupplicantState newState) { - mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, - new StateChangeResult(networkId, wifiSsid, BSSID, newState))); - } -} diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java deleted file mode 100644 index c2f278a..0000000 --- a/wifi/java/android/net/wifi/WifiNative.java +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Copyright (C) 2008 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 android.net.wifi; - -import android.net.wifi.p2p.WifiP2pConfig; -import android.net.wifi.p2p.WifiP2pGroup; -import android.text.TextUtils; -import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; -import android.util.LocalLog; -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** - * Native calls for bring up/shut down of the supplicant daemon and for - * sending requests to the supplicant daemon - * - * waitForEvent() is called on the monitor thread for events. All other methods - * must be serialized from the framework. - * - * {@hide} - */ -public class WifiNative { - - private static final boolean DBG = false; - private final String mTAG; - private static final int DEFAULT_GROUP_OWNER_INTENT = 6; - - static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; - static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; - static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; - - static final int SCAN_WITHOUT_CONNECTION_SETUP = 1; - static final int SCAN_WITH_CONNECTION_SETUP = 2; - - // Hold this lock before calling supplicant - it is required to - // mutually exclude access from Wifi and P2p state machines - static final Object mLock = new Object(); - - public final String mInterfaceName; - public final String mInterfacePrefix; - - private boolean mSuspendOptEnabled = false; - - public native static boolean loadDriver(); - - public native static boolean isDriverLoaded(); - - public native static boolean unloadDriver(); - - public native static boolean startSupplicant(boolean p2pSupported); - - /* Sends a kill signal to supplicant. To be used when we have lost connection - or when the supplicant is hung */ - public native static boolean killSupplicant(boolean p2pSupported); - - private native boolean connectToSupplicantNative(); - - private native void closeSupplicantConnectionNative(); - - /** - * Wait for the supplicant to send an event, returning the event string. - * @return the event string sent by the supplicant. - */ - private native String waitForEventNative(); - - private native boolean doBooleanCommandNative(String command); - - private native int doIntCommandNative(String command); - - private native String doStringCommandNative(String command); - - public WifiNative(String interfaceName) { - mInterfaceName = interfaceName; - mTAG = "WifiNative-" + interfaceName; - if (!interfaceName.equals("p2p0")) { - mInterfacePrefix = "IFNAME=" + interfaceName + " "; - } else { - // commands for p2p0 interface don't need prefix - mInterfacePrefix = ""; - } - } - - private static final LocalLog mLocalLog = new LocalLog(1024); - - // hold mLock before accessing mCmdIdLock - private int mCmdId; - - public LocalLog getLocalLog() { - return mLocalLog; - } - - private int getNewCmdIdLocked() { - return mCmdId++; - } - - private void localLog(String s) { - if (mLocalLog != null) - mLocalLog.log(mInterfaceName + ": " + s); - } - - public boolean connectToSupplicant() { - // No synchronization necessary .. it is implemented in WifiMonitor - localLog(mInterfacePrefix + "connectToSupplicant"); - return connectToSupplicantNative(); - } - - public void closeSupplicantConnection() { - localLog(mInterfacePrefix + "closeSupplicantConnection"); - closeSupplicantConnectionNative(); - } - - public String waitForEvent() { - // No synchronization necessary .. it is implemented in WifiMonitor - return waitForEventNative(); - } - - private boolean doBooleanCommand(String command) { - if (DBG) Log.d(mTAG, "doBoolean: " + command); - synchronized (mLock) { - int cmdId = getNewCmdIdLocked(); - localLog(cmdId + "->" + mInterfacePrefix + command); - boolean result = doBooleanCommandNative(mInterfacePrefix + command); - localLog(cmdId + "<-" + result); - if (DBG) Log.d(mTAG, " returned " + result); - return result; - } - } - - private int doIntCommand(String command) { - if (DBG) Log.d(mTAG, "doInt: " + command); - synchronized (mLock) { - int cmdId = getNewCmdIdLocked(); - localLog(cmdId + "->" + mInterfacePrefix + command); - int result = doIntCommandNative(mInterfacePrefix + command); - localLog(cmdId + "<-" + result); - if (DBG) Log.d(mTAG, " returned " + result); - return result; - } - } - - private String doStringCommand(String command) { - if (DBG) Log.d(mTAG, "doString: " + command); - synchronized (mLock) { - int cmdId = getNewCmdIdLocked(); - localLog(cmdId + "->" + mInterfacePrefix + command); - String result = doStringCommandNative(mInterfacePrefix + command); - localLog(cmdId + "<-" + result); - if (DBG) Log.d(mTAG, " returned " + result); - return result; - } - } - - private String doStringCommandWithoutLogging(String command) { - if (DBG) Log.d(mTAG, "doString: " + command); - synchronized (mLock) { - return doStringCommandNative(mInterfacePrefix + command); - } - } - - public boolean ping() { - String pong = doStringCommand("PING"); - return (pong != null && pong.equals("PONG")); - } - - public boolean scan(int type) { - if (type == SCAN_WITHOUT_CONNECTION_SETUP) { - return doBooleanCommand("SCAN TYPE=ONLY"); - } else if (type == SCAN_WITH_CONNECTION_SETUP) { - return doBooleanCommand("SCAN"); - } else { - throw new IllegalArgumentException("Invalid scan type"); - } - } - - /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. - * - * Note that underneath we use a harsh-sounding "terminate" supplicant command - * for a graceful stop and a mild-sounding "stop" interface - * to kill the process - */ - public boolean stopSupplicant() { - return doBooleanCommand("TERMINATE"); - } - - public String listNetworks() { - return doStringCommand("LIST_NETWORKS"); - } - - public int addNetwork() { - return doIntCommand("ADD_NETWORK"); - } - - public boolean setNetworkVariable(int netId, String name, String value) { - if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false; - return doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value); - } - - public String getNetworkVariable(int netId, String name) { - if (TextUtils.isEmpty(name)) return null; - - // GET_NETWORK will likely flood the logs ... - return doStringCommandWithoutLogging("GET_NETWORK " + netId + " " + name); - } - - public boolean removeNetwork(int netId) { - return doBooleanCommand("REMOVE_NETWORK " + netId); - } - - public boolean enableNetwork(int netId, boolean disableOthers) { - if (disableOthers) { - return doBooleanCommand("SELECT_NETWORK " + netId); - } else { - return doBooleanCommand("ENABLE_NETWORK " + netId); - } - } - - public boolean disableNetwork(int netId) { - return doBooleanCommand("DISABLE_NETWORK " + netId); - } - - public boolean reconnect() { - return doBooleanCommand("RECONNECT"); - } - - public boolean reassociate() { - return doBooleanCommand("REASSOCIATE"); - } - - public boolean disconnect() { - return doBooleanCommand("DISCONNECT"); - } - - public String status() { - return doStringCommand("STATUS"); - } - - public String getMacAddress() { - //Macaddr = XX.XX.XX.XX.XX.XX - String ret = doStringCommand("DRIVER MACADDR"); - if (!TextUtils.isEmpty(ret)) { - String[] tokens = ret.split(" = "); - if (tokens.length == 2) return tokens[1]; - } - return null; - } - - /** - * Format of results: - * ================= - * id=1 - * bssid=68:7f:74:d7:1b:6e - * freq=2412 - * level=-43 - * tsf=1344621975160944 - * age=2623 - * flags=[WPA2-PSK-CCMP][WPS][ESS] - * ssid=zubyb - * ==== - * - * RANGE=ALL gets all scan results - * RANGE=ID- gets results from ID - * MASK= see wpa_supplicant/src/common/wpa_ctrl.h for details - */ - public String scanResults(int sid) { - return doStringCommandWithoutLogging("BSS RANGE=" + sid + "- MASK=0x21987"); - } - - /** - * Format of command - * DRIVER WLS_BATCHING SET SCANFREQ=x MSCAN=r BESTN=y CHANNEL= RTT=s - * where x is an ascii representation of an integer number of seconds between scans - * r is an ascii representation of an integer number of scans per batch - * y is an ascii representation of an integer number of the max AP to remember per scan - * z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values - * indicating entire ranges of channels - * s is an ascii representation of an integer number of highest-strength AP - * for which we'd like approximate distance reported - * - * The return value is an ascii integer representing a guess of the number of scans - * the firmware can remember before it runs out of buffer space or -1 on error - */ - public String setBatchedScanSettings(BatchedScanSettings settings) { - if (settings == null) { - return doStringCommand("DRIVER WLS_BATCHING STOP"); - } - String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec; - cmd += " MSCAN=" + settings.maxScansPerBatch; - if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) { - cmd += " BESTN=" + settings.maxApPerScan; - } - if (settings.channelSet != null && !settings.channelSet.isEmpty()) { - cmd += " CHANNEL=<"; - int i = 0; - for (String channel : settings.channelSet) { - cmd += (i > 0 ? "," : "") + channel; - ++i; - } - cmd += ">"; - } - if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) { - cmd += " RTT=" + settings.maxApForDistance; - } - return doStringCommand(cmd); - } - - public String getBatchedScanResults() { - return doStringCommand("DRIVER WLS_BATCHING GET"); - } - - public boolean startDriver() { - return doBooleanCommand("DRIVER START"); - } - - public boolean stopDriver() { - return doBooleanCommand("DRIVER STOP"); - } - - - /** - * Start filtering out Multicast V4 packets - * @return {@code true} if the operation succeeded, {@code false} otherwise - * - * Multicast filtering rules work as follows: - * - * The driver can filter multicast (v4 and/or v6) and broadcast packets when in - * a power optimized mode (typically when screen goes off). - * - * In order to prevent the driver from filtering the multicast/broadcast packets, we have to - * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective - * - * DRIVER RXFILTER-ADD Num - * where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6 - * - * and DRIVER RXFILTER-START - * In order to stop the usage of these rules, we do - * - * DRIVER RXFILTER-STOP - * DRIVER RXFILTER-REMOVE Num - * where Num is as described for RXFILTER-ADD - * - * The SETSUSPENDOPT driver command overrides the filtering rules - */ - public boolean startFilteringMulticastV4Packets() { - return doBooleanCommand("DRIVER RXFILTER-STOP") - && doBooleanCommand("DRIVER RXFILTER-REMOVE 2") - && doBooleanCommand("DRIVER RXFILTER-START"); - } - - /** - * Stop filtering out Multicast V4 packets. - * @return {@code true} if the operation succeeded, {@code false} otherwise - */ - public boolean stopFilteringMulticastV4Packets() { - return doBooleanCommand("DRIVER RXFILTER-STOP") - && doBooleanCommand("DRIVER RXFILTER-ADD 2") - && doBooleanCommand("DRIVER RXFILTER-START"); - } - - /** - * Start filtering out Multicast V6 packets - * @return {@code true} if the operation succeeded, {@code false} otherwise - */ - public boolean startFilteringMulticastV6Packets() { - return doBooleanCommand("DRIVER RXFILTER-STOP") - && doBooleanCommand("DRIVER RXFILTER-REMOVE 3") - && doBooleanCommand("DRIVER RXFILTER-START"); - } - - /** - * Stop filtering out Multicast V6 packets. - * @return {@code true} if the operation succeeded, {@code false} otherwise - */ - public boolean stopFilteringMulticastV6Packets() { - return doBooleanCommand("DRIVER RXFILTER-STOP") - && doBooleanCommand("DRIVER RXFILTER-ADD 3") - && doBooleanCommand("DRIVER RXFILTER-START"); - } - - public int getBand() { - String ret = doStringCommand("DRIVER GETBAND"); - if (!TextUtils.isEmpty(ret)) { - //reply is "BAND X" where X is the band - String[] tokens = ret.split(" "); - try { - if (tokens.length == 2) return Integer.parseInt(tokens[1]); - } catch (NumberFormatException e) { - return -1; - } - } - return -1; - } - - public boolean setBand(int band) { - return doBooleanCommand("DRIVER SETBAND " + band); - } - - /** - * Sets the bluetooth coexistence mode. - * - * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, - * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or - * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. - * @return Whether the mode was successfully set. - */ - public boolean setBluetoothCoexistenceMode(int mode) { - return doBooleanCommand("DRIVER BTCOEXMODE " + mode); - } - - /** - * Enable or disable Bluetooth coexistence scan mode. When this mode is on, - * some of the low-level scan parameters used by the driver are changed to - * reduce interference with A2DP streaming. - * - * @param isSet whether to enable or disable this mode - * @return {@code true} if the command succeeded, {@code false} otherwise. - */ - public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) { - if (setCoexScanMode) { - return doBooleanCommand("DRIVER BTCOEXSCAN-START"); - } else { - return doBooleanCommand("DRIVER BTCOEXSCAN-STOP"); - } - } - - public boolean saveConfig() { - return doBooleanCommand("SAVE_CONFIG"); - } - - public boolean addToBlacklist(String bssid) { - if (TextUtils.isEmpty(bssid)) return false; - return doBooleanCommand("BLACKLIST " + bssid); - } - - public boolean clearBlacklist() { - return doBooleanCommand("BLACKLIST clear"); - } - - public boolean setSuspendOptimizations(boolean enabled) { - if (mSuspendOptEnabled == enabled) return true; - mSuspendOptEnabled = enabled; - if (enabled) { - return doBooleanCommand("DRIVER SETSUSPENDMODE 1"); - } else { - return doBooleanCommand("DRIVER SETSUSPENDMODE 0"); - } - } - - public boolean setCountryCode(String countryCode) { - return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT)); - } - - public void enableBackgroundScan(boolean enable) { - if (enable) { - doBooleanCommand("SET pno 1"); - } else { - doBooleanCommand("SET pno 0"); - } - } - - public void setScanInterval(int scanInterval) { - doBooleanCommand("SCAN_INTERVAL " + scanInterval); - } - - public void startTdls(String macAddr, boolean enable) { - if (enable) { - doBooleanCommand("TDLS_DISCOVER " + macAddr); - doBooleanCommand("TDLS_SETUP " + macAddr); - } else { - doBooleanCommand("TDLS_TEARDOWN " + macAddr); - } - } - - /** Example output: - * RSSI=-65 - * LINKSPEED=48 - * NOISE=9999 - * FREQUENCY=0 - */ - public String signalPoll() { - return doStringCommandWithoutLogging("SIGNAL_POLL"); - } - - /** Example outout: - * TXGOOD=396 - * TXBAD=1 - */ - public String pktcntPoll() { - return doStringCommand("PKTCNT_POLL"); - } - - public void bssFlush() { - doBooleanCommand("BSS_FLUSH 0"); - } - - public boolean startWpsPbc(String bssid) { - if (TextUtils.isEmpty(bssid)) { - return doBooleanCommand("WPS_PBC"); - } else { - return doBooleanCommand("WPS_PBC " + bssid); - } - } - - public boolean startWpsPbc(String iface, String bssid) { - synchronized (mLock) { - if (TextUtils.isEmpty(bssid)) { - return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC"); - } else { - return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid); - } - } - } - - public boolean startWpsPinKeypad(String pin) { - if (TextUtils.isEmpty(pin)) return false; - return doBooleanCommand("WPS_PIN any " + pin); - } - - public boolean startWpsPinKeypad(String iface, String pin) { - if (TextUtils.isEmpty(pin)) return false; - synchronized (mLock) { - return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin); - } - } - - - public String startWpsPinDisplay(String bssid) { - if (TextUtils.isEmpty(bssid)) { - return doStringCommand("WPS_PIN any"); - } else { - return doStringCommand("WPS_PIN " + bssid); - } - } - - public String startWpsPinDisplay(String iface, String bssid) { - synchronized (mLock) { - if (TextUtils.isEmpty(bssid)) { - return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any"); - } else { - return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid); - } - } - } - - /* Configures an access point connection */ - public boolean startWpsRegistrar(String bssid, String pin) { - if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false; - return doBooleanCommand("WPS_REG " + bssid + " " + pin); - } - - public boolean cancelWps() { - return doBooleanCommand("WPS_CANCEL"); - } - - public boolean setPersistentReconnect(boolean enabled) { - int value = (enabled == true) ? 1 : 0; - return doBooleanCommand("SET persistent_reconnect " + value); - } - - public boolean setDeviceName(String name) { - return doBooleanCommand("SET device_name " + name); - } - - public boolean setDeviceType(String type) { - return doBooleanCommand("SET device_type " + type); - } - - public boolean setConfigMethods(String cfg) { - return doBooleanCommand("SET config_methods " + cfg); - } - - public boolean setManufacturer(String value) { - return doBooleanCommand("SET manufacturer " + value); - } - - public boolean setModelName(String value) { - return doBooleanCommand("SET model_name " + value); - } - - public boolean setModelNumber(String value) { - return doBooleanCommand("SET model_number " + value); - } - - public boolean setSerialNumber(String value) { - return doBooleanCommand("SET serial_number " + value); - } - - public boolean setP2pSsidPostfix(String postfix) { - return doBooleanCommand("SET p2p_ssid_postfix " + postfix); - } - - public boolean setP2pGroupIdle(String iface, int time) { - synchronized (mLock) { - return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time); - } - } - - public void setPowerSave(boolean enabled) { - if (enabled) { - doBooleanCommand("SET ps 1"); - } else { - doBooleanCommand("SET ps 0"); - } - } - - public boolean setP2pPowerSave(String iface, boolean enabled) { - synchronized (mLock) { - if (enabled) { - return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1"); - } else { - return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0"); - } - } - } - - public boolean setWfdEnable(boolean enable) { - return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0")); - } - - public boolean setWfdDeviceInfo(String hex) { - return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex); - } - - /** - * "sta" prioritizes STA connection over P2P and "p2p" prioritizes - * P2P connection over STA - */ - public boolean setConcurrencyPriority(String s) { - return doBooleanCommand("P2P_SET conc_pref " + s); - } - - public boolean p2pFind() { - return doBooleanCommand("P2P_FIND"); - } - - public boolean p2pFind(int timeout) { - if (timeout <= 0) { - return p2pFind(); - } - return doBooleanCommand("P2P_FIND " + timeout); - } - - public boolean p2pStopFind() { - return doBooleanCommand("P2P_STOP_FIND"); - } - - public boolean p2pListen() { - return doBooleanCommand("P2P_LISTEN"); - } - - public boolean p2pListen(int timeout) { - if (timeout <= 0) { - return p2pListen(); - } - return doBooleanCommand("P2P_LISTEN " + timeout); - } - - public boolean p2pExtListen(boolean enable, int period, int interval) { - if (enable && interval < period) { - return false; - } - return doBooleanCommand("P2P_EXT_LISTEN" - + (enable ? (" " + period + " " + interval) : "")); - } - - public boolean p2pSetChannel(int lc, int oc) { - if (DBG) Log.d(mTAG, "p2pSetChannel: lc="+lc+", oc="+oc); - - if (lc >=1 && lc <= 11) { - if (!doBooleanCommand("P2P_SET listen_channel " + lc)) { - return false; - } - } else if (lc != 0) { - return false; - } - - if (oc >= 1 && oc <= 165 ) { - int freq = (oc <= 14 ? 2407 : 5000) + oc * 5; - return doBooleanCommand("P2P_SET disallow_freq 1000-" - + (freq - 5) + "," + (freq + 5) + "-6000"); - } else if (oc == 0) { - /* oc==0 disables "P2P_SET disallow_freq" (enables all freqs) */ - return doBooleanCommand("P2P_SET disallow_freq \"\""); - } - - return false; - } - - public boolean p2pFlush() { - return doBooleanCommand("P2P_FLUSH"); - } - - /* p2p_connect [label|display|keypad] - [persistent] [join|auth] [go_intent=<0..15>] [freq=] */ - public String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { - if (config == null) return null; - List args = new ArrayList(); - WpsInfo wps = config.wps; - args.add(config.deviceAddress); - - switch (wps.setup) { - case WpsInfo.PBC: - args.add("pbc"); - break; - case WpsInfo.DISPLAY: - if (TextUtils.isEmpty(wps.pin)) { - args.add("pin"); - } else { - args.add(wps.pin); - } - args.add("display"); - break; - case WpsInfo.KEYPAD: - args.add(wps.pin); - args.add("keypad"); - break; - case WpsInfo.LABEL: - args.add(wps.pin); - args.add("label"); - default: - break; - } - - if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) { - args.add("persistent"); - } - - if (joinExistingGroup) { - args.add("join"); - } else { - //TODO: This can be adapted based on device plugged in state and - //device battery state - int groupOwnerIntent = config.groupOwnerIntent; - if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { - groupOwnerIntent = DEFAULT_GROUP_OWNER_INTENT; - } - args.add("go_intent=" + groupOwnerIntent); - } - - String command = "P2P_CONNECT "; - for (String s : args) command += s + " "; - - return doStringCommand(command); - } - - public boolean p2pCancelConnect() { - return doBooleanCommand("P2P_CANCEL"); - } - - public boolean p2pProvisionDiscovery(WifiP2pConfig config) { - if (config == null) return false; - - switch (config.wps.setup) { - case WpsInfo.PBC: - return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); - case WpsInfo.DISPLAY: - //We are doing display, so provision discovery is keypad - return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); - case WpsInfo.KEYPAD: - //We are doing keypad, so provision discovery is display - return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); - default: - break; - } - return false; - } - - public boolean p2pGroupAdd(boolean persistent) { - if (persistent) { - return doBooleanCommand("P2P_GROUP_ADD persistent"); - } - return doBooleanCommand("P2P_GROUP_ADD"); - } - - public boolean p2pGroupAdd(int netId) { - return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId); - } - - public boolean p2pGroupRemove(String iface) { - if (TextUtils.isEmpty(iface)) return false; - synchronized (mLock) { - return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface); - } - } - - public boolean p2pReject(String deviceAddress) { - return doBooleanCommand("P2P_REJECT " + deviceAddress); - } - - /* Invite a peer to a group */ - public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { - if (TextUtils.isEmpty(deviceAddress)) return false; - - if (group == null) { - return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); - } else { - return doBooleanCommand("P2P_INVITE group=" + group.getInterface() - + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); - } - } - - /* Reinvoke a persistent connection */ - public boolean p2pReinvoke(int netId, String deviceAddress) { - if (TextUtils.isEmpty(deviceAddress) || netId < 0) return false; - - return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); - } - - public String p2pGetSsid(String deviceAddress) { - return p2pGetParam(deviceAddress, "oper_ssid"); - } - - public String p2pGetDeviceAddress() { - String status = status(); - if (status == null) return ""; - - String[] tokens = status.split("\n"); - for (String token : tokens) { - if (token.startsWith("p2p_device_address=")) { - String[] nameValue = token.split("="); - if (nameValue.length != 2) break; - return nameValue[1]; - } - } - return ""; - } - - public int getGroupCapability(String deviceAddress) { - int gc = 0; - if (TextUtils.isEmpty(deviceAddress)) return gc; - String peerInfo = p2pPeer(deviceAddress); - if (TextUtils.isEmpty(peerInfo)) return gc; - - String[] tokens = peerInfo.split("\n"); - for (String token : tokens) { - if (token.startsWith("group_capab=")) { - String[] nameValue = token.split("="); - if (nameValue.length != 2) break; - try { - return Integer.decode(nameValue[1]); - } catch(NumberFormatException e) { - return gc; - } - } - } - return gc; - } - - public String p2pPeer(String deviceAddress) { - return doStringCommand("P2P_PEER " + deviceAddress); - } - - private String p2pGetParam(String deviceAddress, String key) { - if (deviceAddress == null) return null; - - String peerInfo = p2pPeer(deviceAddress); - if (peerInfo == null) return null; - String[] tokens= peerInfo.split("\n"); - - key += "="; - for (String token : tokens) { - if (token.startsWith(key)) { - String[] nameValue = token.split("="); - if (nameValue.length != 2) break; - return nameValue[1]; - } - } - return null; - } - - public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) { - /* - * P2P_SERVICE_ADD bonjour - * P2P_SERVICE_ADD upnp - * - * e.g) - * [Bonjour] - * # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) - * P2P_SERVICE_ADD bonjour 045f697070c00c000c01 094d795072696e746572c027 - * # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) - * P2P_SERVICE_ADD bonjour 096d797072696e746572045f697070c00c001001 - * 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 - * - * [UPnP] - * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 - * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice - * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp - * -org:device:InternetGatewayDevice:1 - * P2P_SERVICE_ADD upnp 10 uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp - * -org:service:ContentDirectory:2 - */ - for (String s : servInfo.getSupplicantQueryList()) { - String command = "P2P_SERVICE_ADD"; - command += (" " + s); - if (!doBooleanCommand(command)) { - return false; - } - } - return true; - } - - public boolean p2pServiceDel(WifiP2pServiceInfo servInfo) { - /* - * P2P_SERVICE_DEL bonjour - * P2P_SERVICE_DEL upnp - */ - for (String s : servInfo.getSupplicantQueryList()) { - String command = "P2P_SERVICE_DEL "; - - String[] data = s.split(" "); - if (data.length < 2) { - return false; - } - if ("upnp".equals(data[0])) { - command += s; - } else if ("bonjour".equals(data[0])) { - command += data[0]; - command += (" " + data[1]); - } else { - return false; - } - if (!doBooleanCommand(command)) { - return false; - } - } - return true; - } - - public boolean p2pServiceFlush() { - return doBooleanCommand("P2P_SERVICE_FLUSH"); - } - - public String p2pServDiscReq(String addr, String query) { - String command = "P2P_SERV_DISC_REQ"; - command += (" " + addr); - command += (" " + query); - - return doStringCommand(command); - } - - public boolean p2pServDiscCancelReq(String id) { - return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id); - } - - /* Set the current mode of miracast operation. - * 0 = disabled - * 1 = operating as source - * 2 = operating as sink - */ - public void setMiracastMode(int mode) { - // Note: optional feature on the driver. It is ok for this to fail. - doBooleanCommand("DRIVER MIRACAST " + mode); - } -} diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java deleted file mode 100644 index 149f08d..0000000 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ /dev/null @@ -1,4408 +0,0 @@ -/* - * 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 android.net.wifi; - -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; - -/** - * TODO: - * Deprecate WIFI_STATE_UNKNOWN - */ -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 android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.backup.IBackupManager; -import android.bluetooth.BluetoothAdapter; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.net.ConnectivityManager; -import android.net.DhcpResults; -import android.net.DhcpStateMachine; -import android.net.InterfaceConfiguration; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkUtils; -import android.net.RouteInfo; -import android.net.wifi.WpsResult.Status; -import android.net.wifi.p2p.WifiP2pManager; -import android.net.wifi.p2p.WifiP2pService; -import android.os.BatteryStats; -import android.os.Bundle; -import android.os.IBinder; -import android.os.INetworkManagementService; -import android.os.Message; -import android.os.Messenger; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.WorkSource; -import android.provider.Settings; -import android.util.LruCache; -import android.text.TextUtils; - -import com.android.internal.R; -import com.android.internal.app.IBatteryStats; -import com.android.internal.util.AsyncChannel; -import com.android.internal.util.Protocol; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - -import com.android.server.net.BaseNetworkObserver; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Iterator; -import java.util.regex.Pattern; - -/** - * 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 WifiStateMachine extends StateMachine { - - private static final String NETWORKTYPE = "WIFI"; - private static final boolean DBG = false; - - private WifiMonitor mWifiMonitor; - private WifiNative mWifiNative; - private WifiConfigStore mWifiConfigStore; - private INetworkManagementService mNwService; - private ConnectivityManager mCm; - - private final boolean mP2pSupported; - private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); - private boolean mTemporarilyDisconnectWifi = false; - private final String mPrimaryDeviceType; - - /* Scan results handling */ - private List mScanResults = new ArrayList(); - private static final Pattern scanResultPattern = Pattern.compile("\t+"); - private static final int SCAN_RESULT_CACHE_SIZE = 80; - private final LruCache mScanResultCache; - - /* Batch scan results */ - private final List mBatchedScanResults = - new ArrayList(); - private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; - private int mExpectedBatchedScans = 0; - private long mBatchedScanMinPollTime = 0; - - /* Chipset supports background scan */ - private final boolean mBackgroundScanSupported; - - private String mInterfaceName; - /* Tethering interface could be separate from wlan interface */ - private String mTetherInterfaceName; - - private int mLastSignalLevel = -1; - private String mLastBssid; - private int mLastNetworkId; - private boolean mEnableRssiPolling = false; - private boolean mEnableBackgroundScan = false; - private int mRssiPollToken = 0; - private int mReconnectCount = 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 - * In SCAN_ONLY_MODE, the STA can only scan for access points - * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off - */ - private int mOperationalMode = CONNECT_MODE; - private boolean mScanResultIsPending = false; - private WorkSource mScanWorkSource = null; - private static final int UNKNOWN_SCAN_SOURCE = -1; - /* Tracks if state machine has received any screen state change broadcast yet. - * We can miss one of these at boot. - */ - private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); - - private boolean mBluetoothConnectionActive = false; - - private PowerManager.WakeLock mSuspendWakeLock; - - /** - * Interval in milliseconds between polling for RSSI - * and linkspeed information - */ - private static final int POLL_RSSI_INTERVAL_MSECS = 3000; - - /** - * Delay between supplicant restarts upon failure to establish connection - */ - private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; - - /** - * Number of times we attempt to restart supplicant - */ - private static final int SUPPLICANT_RESTART_TRIES = 5; - - private int mSupplicantRestartCount = 0; - /* Tracks sequence number on stop failure message */ - private int mSupplicantStopFailureToken = 0; - - /** - * 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; - - /** - * Driver start time out. - */ - private static final int DRIVER_START_TIME_OUT_MSECS = 10000; - - /* Tracks sequence number on a driver time out */ - private int mDriverStartToken = 0; - - /** - * The link properties of the wifi interface. - * Do not modify this directly; use updateLinkProperties instead. - */ - private LinkProperties mLinkProperties; - - /** - * Subset of link properties coming from netlink. - * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers - * and domains obtained from router advertisements (RFC 6106). - */ - private final LinkProperties mNetlinkLinkProperties; - - /* Tracks sequence number on a periodic scan message */ - private int mPeriodicScanToken = 0; - - // Wakelock held during wifi start/stop and driver load/unload - private PowerManager.WakeLock mWakeLock; - - private Context mContext; - - private final Object mDhcpResultsLock = new Object(); - private DhcpResults mDhcpResults; - private WifiInfo mWifiInfo; - private NetworkInfo mNetworkInfo; - private SupplicantStateTracker mSupplicantStateTracker; - private DhcpStateMachine mDhcpStateMachine; - private boolean mDhcpActive = false; - - private class InterfaceObserver extends BaseNetworkObserver { - private WifiStateMachine mWifiStateMachine; - - InterfaceObserver(WifiStateMachine wifiStateMachine) { - super(); - mWifiStateMachine = wifiStateMachine; - } - - private void maybeLog(String operation, String iface, LinkAddress address) { - if (DBG) { - log(operation + ": " + address + " on " + iface + - " flags " + address.getFlags() + " scope " + address.getScope()); - } - } - - @Override - public void addressUpdated(String iface, LinkAddress address) { - if (mWifiStateMachine.mInterfaceName.equals(iface)) { - maybeLog("addressUpdated", iface, address); - mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, address); - } - } - - @Override - public void addressRemoved(String iface, LinkAddress address) { - if (mWifiStateMachine.mInterfaceName.equals(iface)) { - maybeLog("addressRemoved", iface, address); - mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, address); - } - } - } - - private InterfaceObserver mInterfaceObserver; - - private AlarmManager mAlarmManager; - private PendingIntent mScanIntent; - private PendingIntent mDriverStopIntent; - private PendingIntent mBatchedScanIntervalIntent; - - /* Tracks current frequency mode */ - private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); - - /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ - private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); - - // Channel for sending replies. - private AsyncChannel mReplyChannel = new AsyncChannel(); - - private WifiP2pManager mWifiP2pManager; - //Used to initiate a connection with WifiP2pService - private AsyncChannel mWifiP2pChannel; - private AsyncChannel mWifiApConfigChannel; - - /* The base for wifi message types */ - static final int BASE = Protocol.BASE_WIFI; - /* Start the supplicant */ - static final int CMD_START_SUPPLICANT = BASE + 11; - /* Stop the supplicant */ - static final int CMD_STOP_SUPPLICANT = BASE + 12; - /* Start the driver */ - static final int CMD_START_DRIVER = BASE + 13; - /* Stop the driver */ - static final int CMD_STOP_DRIVER = BASE + 14; - /* Indicates Static IP succeeded */ - static final int CMD_STATIC_IP_SUCCESS = BASE + 15; - /* Indicates Static IP failed */ - static final int CMD_STATIC_IP_FAILURE = BASE + 16; - /* Indicates supplicant stop failed */ - static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; - /* Delayed stop to avoid shutting down driver too quick*/ - static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; - /* A delayed message sent to start driver when it fail to come up */ - static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; - - /* Start the soft access point */ - static final int CMD_START_AP = BASE + 21; - /* Indicates soft ap start succeeded */ - static final int CMD_START_AP_SUCCESS = BASE + 22; - /* Indicates soft ap start failed */ - static final int CMD_START_AP_FAILURE = BASE + 23; - /* Stop the soft access point */ - static final int CMD_STOP_AP = BASE + 24; - /* Set the soft access point configuration */ - static final int CMD_SET_AP_CONFIG = BASE + 25; - /* Soft access point configuration set completed */ - static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; - /* Request the soft access point configuration */ - static final int CMD_REQUEST_AP_CONFIG = BASE + 27; - /* Response to access point configuration request */ - static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; - /* Invoked when getting a tether state change notification */ - static final int CMD_TETHER_STATE_CHANGE = BASE + 29; - /* A delayed message sent to indicate tether state change failed to arrive */ - static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; - - static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; - - /* Supplicant commands */ - /* Is supplicant alive ? */ - static final int CMD_PING_SUPPLICANT = BASE + 51; - /* Add/update a network configuration */ - static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; - /* Delete a network */ - static final int CMD_REMOVE_NETWORK = BASE + 53; - /* Enable a network. The device will attempt a connection to the given network. */ - static final int CMD_ENABLE_NETWORK = BASE + 54; - /* Enable all networks */ - static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; - /* Blacklist network. De-prioritizes the given BSSID for connection. */ - static final int CMD_BLACKLIST_NETWORK = BASE + 56; - /* Clear the blacklist network list */ - static final int CMD_CLEAR_BLACKLIST = BASE + 57; - /* Save configuration */ - static final int CMD_SAVE_CONFIG = BASE + 58; - /* Get configured networks*/ - static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; - - /* Supplicant commands after driver start*/ - /* Initiate a scan */ - static final int CMD_START_SCAN = BASE + 71; - /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ - static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; - /* Disconnect from a network */ - static final int CMD_DISCONNECT = BASE + 73; - /* Reconnect to a network */ - static final int CMD_RECONNECT = BASE + 74; - /* Reassociate to a network */ - static final int CMD_REASSOCIATE = BASE + 75; - /* Controls suspend mode optimizations - * - * When high perf mode is enabled, suspend mode optimizations are disabled - * - * When high perf mode is disabled, suspend mode optimizations are enabled - * - * Suspend mode optimizations include: - * - packet filtering - * - turn off roaming - * - DTIM wake up settings - */ - static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; - /* Set the country code */ - static final int CMD_SET_COUNTRY_CODE = BASE + 80; - /* Enables RSSI poll */ - static final int CMD_ENABLE_RSSI_POLL = BASE + 82; - /* RSSI poll */ - static final int CMD_RSSI_POLL = BASE + 83; - /* Set up packet filtering */ - static final int CMD_START_PACKET_FILTERING = BASE + 84; - /* Clear packet filter */ - static final int CMD_STOP_PACKET_FILTERING = BASE + 85; - /* Enable suspend mode optimizations in the driver */ - static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; - /* When there are no saved networks, we do a periodic scan to notify user of - * an open network */ - static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; - - /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ - static final int MULTICAST_V6 = 1; - static final int MULTICAST_V4 = 0; - - /* Set the frequency band */ - static final int CMD_SET_FREQUENCY_BAND = BASE + 90; - /* Enable background scan for configured networks */ - static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; - /* Enable TDLS on a specific MAC address */ - static final int CMD_ENABLE_TDLS = BASE + 92; - - /* Commands from/to the SupplicantStateTracker */ - /* Reset the supplicant state tracker */ - static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; - - /* P2p commands */ - /* We are ok with no response here since we wont do much with it anyway */ - public static final int CMD_ENABLE_P2P = BASE + 131; - /* In order to shut down supplicant cleanly, we wait till p2p has - * been disabled */ - public static final int CMD_DISABLE_P2P_REQ = BASE + 132; - public static final int CMD_DISABLE_P2P_RSP = BASE + 133; - - public static final int CMD_BOOT_COMPLETED = BASE + 134; - - /* change the batch scan settings. - * arg1 = responsible UID - * arg2 = csph (channel scans per hour) - * obj = bundle with the new settings and the optional worksource - */ - public static final int CMD_SET_BATCHED_SCAN = BASE + 135; - public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; - public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; - - /* Link configuration (IP address, DNS, ...) changes */ - /* An new IP address was added to our interface, or an existing IP address was updated */ - static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; - /* An IP address was removed from our interface */ - static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; - /* Reload all networks and reconnect */ - static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; - - /* Wifi state machine modes of operation */ - /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ - public static final int CONNECT_MODE = 1; - /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ - public static final int SCAN_ONLY_MODE = 2; - /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ - public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; - - private static final int SUCCESS = 1; - private static final int FAILURE = -1; - - /** - * The maximum number of times we will retry a connection to an access point - * for which we have failed in acquiring an IP address from DHCP. A value of - * N means that we will make N+1 connection attempts in all. - *

- * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default - * value if a Settings value is not present. - */ - private static final int DEFAULT_MAX_DHCP_RETRIES = 9; - - /* Tracks if suspend optimizations need to be disabled by DHCP, - * screen or due to high perf mode. - * When any of them needs to disable it, we keep the suspend optimizations - * disabled - */ - private int mSuspendOptNeedsDisabled = 0; - - private static final int SUSPEND_DUE_TO_DHCP = 1; - private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; - private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; - - /* Tracks if user has enabled suspend optimizations through settings */ - private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); - - /** - * Default framework scan interval in milliseconds. This is used in the scenario in which - * wifi chipset does not support background scanning to set up a - * periodic wake up scan so that the device can connect to a new access - * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can - * override this. - */ - private final int mDefaultFrameworkScanIntervalMs; - - /** - * Supplicant scan interval in milliseconds. - * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or - * from the default config if the setting is not set - */ - private long mSupplicantScanIntervalMs; - - /** - * 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. - */ - private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ - private long mLastEnableAllNetworksTime; - - /** - * Starting and shutting down driver too quick causes problems leading to driver - * being in a bad state. Delay driver stop. - */ - private final int mDriverStopDelayMs; - private int mDelayedStopCounter; - private boolean mInDelayedStop = false; - - // sometimes telephony gives us this data before boot is complete and we can't store it - // until after, so the write is deferred - private volatile String mPersistedCountryCode; - - // Supplicant doesn't like setting the same country code multiple times (it may drop - // currently connected network), so we save the country code here to avoid redundency - private String mLastSetCountryCode; - - private static final int MIN_RSSI = -200; - private static final int MAX_RSSI = 256; - - /* Default parent state */ - private State mDefaultState = new DefaultState(); - /* Temporary initial state */ - private State mInitialState = new InitialState(); - /* Driver loaded, waiting for supplicant to start */ - private State mSupplicantStartingState = new SupplicantStartingState(); - /* Driver loaded and supplicant ready */ - private State mSupplicantStartedState = new SupplicantStartedState(); - /* Waiting for supplicant to stop and monitor to exit */ - private State mSupplicantStoppingState = new SupplicantStoppingState(); - /* Driver start issued, waiting for completed event */ - private State mDriverStartingState = new DriverStartingState(); - /* Driver started */ - private State mDriverStartedState = new DriverStartedState(); - /* Wait until p2p is disabled - * This is a special state which is entered right after we exit out of DriverStartedState - * before transitioning to another state. - */ - private State mWaitForP2pDisableState = new WaitForP2pDisableState(); - /* Driver stopping */ - private State mDriverStoppingState = new DriverStoppingState(); - /* Driver stopped */ - private State mDriverStoppedState = new DriverStoppedState(); - /* Scan for networks, no connection will be established */ - private State mScanModeState = new ScanModeState(); - /* Connecting to an access point */ - private State mConnectModeState = new ConnectModeState(); - /* Connected at 802.11 (L2) level */ - private State mL2ConnectedState = new L2ConnectedState(); - /* fetching IP after connection to access point (assoc+auth complete) */ - private State mObtainingIpState = new ObtainingIpState(); - /* Waiting for link quality verification to be complete */ - private State mVerifyingLinkState = new VerifyingLinkState(); - /* Connected with IP addr */ - private State mConnectedState = new ConnectedState(); - /* disconnect issued, waiting for network disconnect confirmation */ - private State mDisconnectingState = new DisconnectingState(); - /* Network is not connected, supplicant assoc+auth is not complete */ - private State mDisconnectedState = new DisconnectedState(); - /* Waiting for WPS to be completed*/ - private State mWpsRunningState = new WpsRunningState(); - - /* Soft ap is starting up */ - private State mSoftApStartingState = new SoftApStartingState(); - /* Soft ap is running */ - private State mSoftApStartedState = new SoftApStartedState(); - /* Soft ap is running and we are waiting for tether notification */ - private State mTetheringState = new TetheringState(); - /* Soft ap is running and we are tethered through connectivity service */ - private State mTetheredState = new TetheredState(); - /* Waiting for untether confirmation before stopping soft Ap */ - private State mUntetheringState = new UntetheringState(); - - private class TetherStateChange { - ArrayList available; - ArrayList active; - TetherStateChange(ArrayList av, ArrayList ac) { - available = av; - active = ac; - } - } - - - /** - * One of {@link WifiManager#WIFI_STATE_DISABLED}, - * {@link WifiManager#WIFI_STATE_DISABLING}, - * {@link WifiManager#WIFI_STATE_ENABLED}, - * {@link WifiManager#WIFI_STATE_ENABLING}, - * {@link WifiManager#WIFI_STATE_UNKNOWN} - * - */ - private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); - - /** - * 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 static final int SCAN_REQUEST = 0; - private static final String ACTION_START_SCAN = - "com.android.server.WifiManager.action.START_SCAN"; - - private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; - private static final int DRIVER_STOP_REQUEST = 0; - private static final String ACTION_DELAYED_DRIVER_STOP = - "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; - - private static final String ACTION_REFRESH_BATCHED_SCAN = - "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; - /** - * Keep track of whether WIFI is running. - */ - private boolean mIsRunning = false; - - /** - * Keep track of whether we last told the battery stats we had started. - */ - private boolean mReportedRunning = false; - - /** - * Most recently set source of starting WIFI. - */ - private final WorkSource mRunningWifiUids = new WorkSource(); - - /** - * The last reported UIDs that were responsible for starting WIFI. - */ - private final WorkSource mLastRunningWifiUids = new WorkSource(); - - private final IBatteryStats mBatteryStats; - - private BatchedScanSettings mBatchedScanSettings = null; - - /** - * Track the worksource/cost of the current settings and track what's been noted - * to the battery stats, so we can mark the end of the previous when changing. - */ - private WorkSource mBatchedScanWorkSource = null; - private int mBatchedScanCsph = 0; - private WorkSource mNotedBatchedScanWorkSource = null; - private int mNotedBatchedScanCsph = 0; - - - public WifiStateMachine(Context context, String wlanInterface) { - super("WifiStateMachine"); - mContext = context; - mInterfaceName = wlanInterface; - - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); - mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( - BatteryStats.SERVICE_NAME)); - - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNwService = INetworkManagementService.Stub.asInterface(b); - - mP2pSupported = mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI_DIRECT); - - mWifiNative = new WifiNative(mInterfaceName); - mWifiConfigStore = new WifiConfigStore(context, mWifiNative); - mWifiMonitor = new WifiMonitor(this, mWifiNative); - mWifiInfo = new WifiInfo(); - mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, - getHandler()); - mLinkProperties = new LinkProperties(); - mNetlinkLinkProperties = new LinkProperties(); - - mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE); - - mNetworkInfo.setIsAvailable(false); - mLastBssid = null; - mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; - mLastSignalLevel = -1; - - mInterfaceObserver = new InterfaceObserver(this); - try { - mNwService.registerObserver(mInterfaceObserver); - } catch (RemoteException e) { - loge("Couldn't register interface observer: " + e.toString()); - } - - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - Intent scanIntent = new Intent(ACTION_START_SCAN, null); - mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); - - Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); - mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); - - mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( - R.integer.config_wifi_framework_scan_interval); - - mDriverStopDelayMs = mContext.getResources().getInteger( - R.integer.config_wifi_driver_stop_delay); - - mBackgroundScanSupported = mContext.getResources().getBoolean( - R.bool.config_wifi_background_scan_support); - - mPrimaryDeviceType = mContext.getResources().getString( - R.string.config_wifi_p2p_device_type); - - mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); - - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - ArrayList available = intent.getStringArrayListExtra( - ConnectivityManager.EXTRA_AVAILABLE_TETHER); - ArrayList active = intent.getStringArrayListExtra( - ConnectivityManager.EXTRA_ACTIVE_TETHER); - sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); - } - },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); - - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final WorkSource workSource = null; - startScan(UNKNOWN_SCAN_SOURCE, workSource); - } - }, - new IntentFilter(ACTION_START_SCAN)); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(ACTION_REFRESH_BATCHED_SCAN); - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(Intent.ACTION_SCREEN_ON)) { - handleScreenStateChanged(true); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - handleScreenStateChanged(false); - } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { - startNextBatchedScanAsync(); - } - } - }, filter); - - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); - sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); - } - }, - new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); - - mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( - Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, - new ContentObserver(getHandler()) { - @Override - public void onChange(boolean selfChange) { - mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); - } - }); - - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - sendMessage(CMD_BOOT_COMPLETED); - } - }, - new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); - - mScanResultCache = new LruCache(SCAN_RESULT_CACHE_SIZE); - - PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); - - mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); - mSuspendWakeLock.setReferenceCounted(false); - - addState(mDefaultState); - addState(mInitialState, mDefaultState); - addState(mSupplicantStartingState, mDefaultState); - addState(mSupplicantStartedState, mDefaultState); - addState(mDriverStartingState, mSupplicantStartedState); - addState(mDriverStartedState, mSupplicantStartedState); - addState(mScanModeState, mDriverStartedState); - addState(mConnectModeState, mDriverStartedState); - addState(mL2ConnectedState, mConnectModeState); - addState(mObtainingIpState, mL2ConnectedState); - addState(mVerifyingLinkState, mL2ConnectedState); - addState(mConnectedState, mL2ConnectedState); - addState(mDisconnectingState, mConnectModeState); - addState(mDisconnectedState, mConnectModeState); - addState(mWpsRunningState, mConnectModeState); - addState(mWaitForP2pDisableState, mSupplicantStartedState); - addState(mDriverStoppingState, mSupplicantStartedState); - addState(mDriverStoppedState, mSupplicantStartedState); - addState(mSupplicantStoppingState, mDefaultState); - addState(mSoftApStartingState, mDefaultState); - addState(mSoftApStartedState, mDefaultState); - addState(mTetheringState, mSoftApStartedState); - addState(mTetheredState, mSoftApStartedState); - addState(mUntetheringState, mSoftApStartedState); - - setInitialState(mInitialState); - - setLogRecSize(2000); - setLogOnlyTransitions(false); - if (DBG) setDbg(true); - - //start the state machine - start(); - - final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - /********************************************************* - * Methods exposed for public use - ********************************************************/ - - public Messenger getMessenger() { - return new Messenger(getHandler()); - } - /** - * TODO: doc - */ - public boolean syncPingSupplicant(AsyncChannel channel) { - Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); - boolean result = (resultMsg.arg1 != FAILURE); - resultMsg.recycle(); - return result; - } - - /** - * Initiate a wifi scan. If workSource is not null, blame is given to it, - * otherwise blame is given to callingUid. - * - * @param callingUid The uid initiating the wifi scan. Blame will be given - * here unless workSource is specified. - * @param workSource If not null, blame is given to workSource. - */ - public void startScan(int callingUid, WorkSource workSource) { - sendMessage(CMD_START_SCAN, callingUid, 0, workSource); - } - - /** - * start or stop batched scanning using the given settings - */ - private static final String BATCHED_SETTING = "batched_settings"; - private static final String BATCHED_WORKSOURCE = "batched_worksource"; - public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, - WorkSource workSource) { - Bundle bundle = new Bundle(); - bundle.putParcelable(BATCHED_SETTING, settings); - bundle.putParcelable(BATCHED_WORKSOURCE, workSource); - sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); - } - - public List syncGetBatchedScanResultsList() { - synchronized (mBatchedScanResults) { - List batchedScanList = - new ArrayList(mBatchedScanResults.size()); - for(BatchedScanResult result: mBatchedScanResults) { - batchedScanList.add(new BatchedScanResult(result)); - } - return batchedScanList; - } - } - - public void requestBatchedScanPoll() { - sendMessage(CMD_POLL_BATCHED_SCAN); - } - - private void startBatchedScan() { - if (mBatchedScanSettings == null) return; - - if (mDhcpActive) { - if (DBG) log("not starting Batched Scans due to DHCP"); - return; - } - - // first grab any existing data - retrieveBatchedScanData(); - - mAlarmManager.cancel(mBatchedScanIntervalIntent); - - String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); - try { - mExpectedBatchedScans = Integer.parseInt(scansExpected); - setNextBatchedAlarm(mExpectedBatchedScans); - if (mExpectedBatchedScans > 0) noteBatchedScanStart(); - } catch (NumberFormatException e) { - stopBatchedScan(); - loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); - } - } - - // called from BroadcastListener - private void startNextBatchedScanAsync() { - sendMessage(CMD_START_NEXT_BATCHED_SCAN); - } - - private void startNextBatchedScan() { - // first grab any existing data - retrieveBatchedScanData(); - - setNextBatchedAlarm(mExpectedBatchedScans); - } - - private void handleBatchedScanPollRequest() { - if (DBG) { - log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + - mBatchedScanMinPollTime + " , mBatchedScanSettings=" + - mBatchedScanSettings); - } - // if there is no appropriate PollTime that's because we either aren't - // batching or we've already set a time for a poll request - if (mBatchedScanMinPollTime == 0) return; - if (mBatchedScanSettings == null) return; - - long now = System.currentTimeMillis(); - - if (now > mBatchedScanMinPollTime) { - // do the poll and reset our timers - startNextBatchedScan(); - } else { - mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, - mBatchedScanIntervalIntent); - mBatchedScanMinPollTime = 0; - } - } - - // return true if new/different - private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { - BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); - WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); - - if (DBG) { - log("set batched scan to " + settings + " for uid=" + responsibleUid + - ", worksource=" + responsibleWorkSource); - } - if (settings != null) { - if (settings.equals(mBatchedScanSettings)) return false; - } else { - if (mBatchedScanSettings == null) return false; - } - mBatchedScanSettings = settings; - if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); - mBatchedScanWorkSource = responsibleWorkSource; - mBatchedScanCsph = csph; - return true; - } - - private void stopBatchedScan() { - mAlarmManager.cancel(mBatchedScanIntervalIntent); - retrieveBatchedScanData(); - mWifiNative.setBatchedScanSettings(null); - noteBatchedScanStop(); - } - - private void setNextBatchedAlarm(int scansExpected) { - - if (mBatchedScanSettings == null || scansExpected < 1) return; - - mBatchedScanMinPollTime = System.currentTimeMillis() + - mBatchedScanSettings.scanIntervalSec * 1000; - - if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { - scansExpected = mBatchedScanSettings.maxScansPerBatch; - } - - int secToFull = mBatchedScanSettings.scanIntervalSec; - secToFull *= scansExpected; - - int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); - if (debugPeriod > 0) secToFull = debugPeriod; - - // set the alarm to do the next poll. We set it a little short as we'd rather - // wake up wearly than miss a scan due to buffer overflow - mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() - + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), - mBatchedScanIntervalIntent); - } - - /** - * Start reading new scan data - * Data comes in as: - * "scancount=5\n" - * "nextcount=5\n" - * "apcount=3\n" - * "trunc\n" (optional) - * "bssid=...\n" - * "ssid=...\n" - * "freq=...\n" (in Mhz) - * "level=...\n" - * "dist=...\n" (in cm) - * "distsd=...\n" (standard deviation, in cm) - * "====" - * "bssid=...\n" - * etc - * "====" - * "bssid=...\n" - * etc - * "%%%%" - * "apcount=2\n" - * "bssid=...\n" - * etc - * "%%%% - * etc - * "----" - */ - private final static boolean DEBUG_PARSE = false; - private void retrieveBatchedScanData() { - String rawData = mWifiNative.getBatchedScanResults(); - if (DEBUG_PARSE) log("rawData = " + rawData); - mBatchedScanMinPollTime = 0; - if (rawData == null || rawData.equalsIgnoreCase("OK")) { - loge("Unexpected BatchedScanResults :" + rawData); - return; - } - - int scanCount = 0; - final String END_OF_BATCHES = "----"; - final String SCANCOUNT = "scancount="; - final String TRUNCATED = "trunc"; - final String AGE = "age="; - final String DIST = "dist="; - final String DISTSD = "distSd="; - - String splitData[] = rawData.split("\n"); - int n = 0; - if (splitData[n].startsWith(SCANCOUNT)) { - try { - scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); - } catch (NumberFormatException e) { - loge("scancount parseInt Exception from " + splitData[n]); - } - } else log("scancount not found"); - if (scanCount == 0) { - loge("scanCount==0 - aborting"); - return; - } - - final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - - synchronized (mBatchedScanResults) { - mBatchedScanResults.clear(); - BatchedScanResult batchedScanResult = new BatchedScanResult(); - - String bssid = null; - WifiSsid wifiSsid = null; - int level = 0; - int freq = 0; - int dist, distSd; - long tsf = 0; - dist = distSd = ScanResult.UNSPECIFIED; - final long now = SystemClock.elapsedRealtime(); - final int bssidStrLen = BSSID_STR.length(); - - while (true) { - while (n < splitData.length) { - if (DEBUG_PARSE) logd("parsing " + splitData[n]); - if (splitData[n].equals(END_OF_BATCHES)) { - if (n+1 != splitData.length) { - loge("didn't consume " + (splitData.length-n)); - } - if (mBatchedScanResults.size() > 0) { - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - logd("retrieveBatchedScanResults X"); - return; - } - if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { - if (bssid != null) { - batchedScanResult.scanResults.add(new ScanResult( - wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); - wifiSsid = null; - bssid = null; - level = 0; - freq = 0; - tsf = 0; - dist = distSd = ScanResult.UNSPECIFIED; - } - if (splitData[n].equals(END_STR)) { - if (batchedScanResult.scanResults.size() != 0) { - mBatchedScanResults.add(batchedScanResult); - batchedScanResult = new BatchedScanResult(); - } else { - logd("Found empty batch"); - } - } - } else if (splitData[n].equals(TRUNCATED)) { - batchedScanResult.truncated = true; - } else if (splitData[n].startsWith(BSSID_STR)) { - bssid = new String(splitData[n].getBytes(), bssidStrLen, - splitData[n].length() - bssidStrLen); - } else if (splitData[n].startsWith(FREQ_STR)) { - try { - freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); - } catch (NumberFormatException e) { - loge("Invalid freqency: " + splitData[n]); - freq = 0; - } - } else if (splitData[n].startsWith(AGE)) { - try { - tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); - tsf *= 1000; // convert mS -> uS - } catch (NumberFormatException e) { - loge("Invalid timestamp: " + splitData[n]); - tsf = 0; - } - } else if (splitData[n].startsWith(SSID_STR)) { - wifiSsid = WifiSsid.createFromAsciiEncoded( - splitData[n].substring(SSID_STR.length())); - } else if (splitData[n].startsWith(LEVEL_STR)) { - try { - level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); - if (level > 0) level -= 256; - } catch (NumberFormatException e) { - loge("Invalid level: " + splitData[n]); - level = 0; - } - } else if (splitData[n].startsWith(DIST)) { - try { - dist = Integer.parseInt(splitData[n].substring(DIST.length())); - } catch (NumberFormatException e) { - loge("Invalid distance: " + splitData[n]); - dist = ScanResult.UNSPECIFIED; - } - } else if (splitData[n].startsWith(DISTSD)) { - try { - distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); - } catch (NumberFormatException e) { - loge("Invalid distanceSd: " + splitData[n]); - distSd = ScanResult.UNSPECIFIED; - } - } else { - loge("Unable to parse batched scan result line: " + splitData[n]); - } - n++; - } - rawData = mWifiNative.getBatchedScanResults(); - if (DEBUG_PARSE) log("reading more data:\n" + rawData); - if (rawData == null) { - loge("Unexpected null BatchedScanResults"); - return; - } - splitData = rawData.split("\n"); - if (splitData.length == 0 || splitData[0].equals("ok")) { - loge("batch scan results just ended!"); - if (mBatchedScanResults.size() > 0) { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - return; - } - n = 0; - } - } - } - - // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. - private void noteScanStart(int callingUid, WorkSource workSource) { - if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) { - mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); - try { - mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); - } catch (RemoteException e) { - log(e.toString()); - } - } - } - - private void noteScanEnd() { - if (mScanWorkSource != null) { - try { - mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); - } catch (RemoteException e) { - log(e.toString()); - } finally { - mScanWorkSource = null; - } - } - } - - private void noteBatchedScanStart() { - // note the end of a previous scan set - if (mNotedBatchedScanWorkSource != null && - (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || - mNotedBatchedScanCsph != mBatchedScanCsph)) { - try { - mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); - } catch (RemoteException e) { - log(e.toString()); - } finally { - mNotedBatchedScanWorkSource = null; - mNotedBatchedScanCsph = 0; - } - } - // note the start of the new - try { - mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, - mBatchedScanCsph); - mNotedBatchedScanWorkSource = mBatchedScanWorkSource; - mNotedBatchedScanCsph = mBatchedScanCsph; - } catch (RemoteException e) { - log(e.toString()); - } - } - - private void noteBatchedScanStop() { - if (mNotedBatchedScanWorkSource != null) { - try { - mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); - } catch (RemoteException e) { - log(e.toString()); - } finally { - mNotedBatchedScanWorkSource = null; - mNotedBatchedScanCsph = 0; - } - } - } - - private void startScanNative(int type) { - mWifiNative.scan(type); - mScanResultIsPending = true; - } - - /** - * TODO: doc - */ - public void setSupplicantRunning(boolean enable) { - if (enable) { - sendMessage(CMD_START_SUPPLICANT); - } else { - sendMessage(CMD_STOP_SUPPLICANT); - } - } - - /** - * TODO: doc - */ - public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { - if (enable) { - sendMessage(CMD_START_AP, wifiConfig); - } else { - sendMessage(CMD_STOP_AP); - } - } - - public void setWifiApConfiguration(WifiConfiguration config) { - mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); - } - - public WifiConfiguration syncGetWifiApConfiguration() { - Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); - WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; - resultMsg.recycle(); - return ret; - } - - /** - * TODO: doc - */ - public int syncGetWifiState() { - return mWifiState.get(); - } - - /** - * TODO: doc - */ - public String syncGetWifiStateByName() { - switch (mWifiState.get()) { - case WIFI_STATE_DISABLING: - return "disabling"; - case WIFI_STATE_DISABLED: - return "disabled"; - case WIFI_STATE_ENABLING: - return "enabling"; - case WIFI_STATE_ENABLED: - return "enabled"; - case WIFI_STATE_UNKNOWN: - return "unknown state"; - default: - return "[invalid state]"; - } - } - - /** - * TODO: doc - */ - public int syncGetWifiApState() { - return mWifiApState.get(); - } - - /** - * TODO: doc - */ - 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]"; - } - } - - /** - * Get status information for the current connection, if any. - * @return a {@link WifiInfo} object containing information about the current connection - * - */ - public WifiInfo syncRequestConnectionInfo() { - return mWifiInfo; - } - - public DhcpResults syncGetDhcpResults() { - synchronized (mDhcpResultsLock) { - return new DhcpResults(mDhcpResults); - } - } - - /** - * TODO: doc - */ - public void setDriverStart(boolean enable) { - if (enable) { - sendMessage(CMD_START_DRIVER); - } else { - sendMessage(CMD_STOP_DRIVER); - } - } - - /** - * TODO: doc - */ - public void setOperationalMode(int mode) { - if (DBG) log("setting operational mode to " + String.valueOf(mode)); - sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); - } - - /** - * TODO: doc - */ - public List syncGetScanResultsList() { - synchronized (mScanResultCache) { - List scanList = new ArrayList(); - for(ScanResult result: mScanResults) { - scanList.add(new ScanResult(result)); - } - return scanList; - } - } - - /** - * Disconnect from Access Point - */ - public void disconnectCommand() { - sendMessage(CMD_DISCONNECT); - } - - /** - * Initiate a reconnection to AP - */ - public void reconnectCommand() { - sendMessage(CMD_RECONNECT); - } - - /** - * Initiate a re-association to AP - */ - public void reassociateCommand() { - sendMessage(CMD_REASSOCIATE); - } - - /** - * Reload networks and then reconnect; helps load correct data for TLS networks - */ - - public void reloadTlsNetworksAndReconnect() { - sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); - } - - /** - * Add a network synchronously - * - * @return network id of the new network - */ - public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { - Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); - int result = resultMsg.arg1; - resultMsg.recycle(); - return result; - } - - public List syncGetConfiguredNetworks(AsyncChannel channel) { - Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); - List result = (List) resultMsg.obj; - resultMsg.recycle(); - return result; - } - - /** - * Delete a network - * - * @param networkId id of the network to be removed - */ - public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { - Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); - boolean result = (resultMsg.arg1 != FAILURE); - resultMsg.recycle(); - return result; - } - - /** - * Enable a network - * - * @param netId network id of the network - * @param disableOthers true, if all other networks have to be disabled - * @return {@code true} if the operation succeeds, {@code false} otherwise - */ - public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { - Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, - disableOthers ? 1 : 0); - boolean result = (resultMsg.arg1 != FAILURE); - resultMsg.recycle(); - return result; - } - - /** - * Disable a network - * - * @param netId network id of the network - * @return {@code true} if the operation succeeds, {@code false} otherwise - */ - public boolean syncDisableNetwork(AsyncChannel channel, int netId) { - Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); - boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); - resultMsg.recycle(); - return result; - } - - /** - * Blacklist a BSSID. This will avoid the AP if there are - * alternate APs to connect - * - * @param bssid BSSID of the network - */ - public void addToBlacklist(String bssid) { - sendMessage(CMD_BLACKLIST_NETWORK, bssid); - } - - /** - * Clear the blacklist list - * - */ - public void clearBlacklist() { - sendMessage(CMD_CLEAR_BLACKLIST); - } - - public void enableRssiPolling(boolean enabled) { - sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); - } - - public void enableBackgroundScanCommand(boolean enabled) { - sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); - } - - public void enableAllNetworks() { - sendMessage(CMD_ENABLE_ALL_NETWORKS); - } - - /** - * Start filtering Multicast v4 packets - */ - public void startFilteringMulticastV4Packets() { - mFilteringMulticastV4Packets.set(true); - sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); - } - - /** - * Stop filtering Multicast v4 packets - */ - public void stopFilteringMulticastV4Packets() { - mFilteringMulticastV4Packets.set(false); - sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); - } - - /** - * Start filtering Multicast v4 packets - */ - public void startFilteringMulticastV6Packets() { - sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); - } - - /** - * Stop filtering Multicast v4 packets - */ - public void stopFilteringMulticastV6Packets() { - sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); - } - - /** - * Set high performance mode of operation. - * Enabling would set active power mode and disable suspend optimizations; - * disabling would set auto power mode and enable suspend optimizations - * @param enable true if enable, false otherwise - */ - public void setHighPerfModeEnabled(boolean enable) { - sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); - } - - /** - * Set the country code - * @param countryCode following ISO 3166 format - * @param persist {@code true} if the setting should be remembered. - */ - public void setCountryCode(String countryCode, boolean persist) { - if (persist) { - mPersistedCountryCode = countryCode; - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.WIFI_COUNTRY_CODE, - countryCode); - } - sendMessage(CMD_SET_COUNTRY_CODE, countryCode); - mWifiP2pChannel.sendMessage(WifiP2pService.SET_COUNTRY_CODE, countryCode); - } - - /** - * Set the operational frequency band - * @param band - * @param persist {@code true} if the setting should be remembered. - */ - public void setFrequencyBand(int band, boolean persist) { - if (persist) { - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WIFI_FREQUENCY_BAND, - band); - } - sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); - } - - /** - * Enable TDLS for a specific MAC address - */ - public void enableTdls(String remoteMacAddress, boolean enable) { - int enabler = enable ? 1 : 0; - sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); - } - - /** - * Returns the operational frequency band - */ - public int getFrequencyBand() { - return mFrequencyBand.get(); - } - - /** - * Returns the wifi configuration file - */ - public String getConfigFile() { - return mWifiConfigStore.getConfigFile(); - } - - /** - * Send a message indicating bluetooth adapter connection state changed - */ - public void sendBluetoothAdapterStateChange(int state) { - sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); - } - - /** - * Save configuration on supplicant - * - * @return {@code true} if the operation succeeds, {@code false} otherwise - * - * TODO: deprecate this - */ - public boolean syncSaveConfig(AsyncChannel channel) { - Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); - boolean result = (resultMsg.arg1 != FAILURE); - resultMsg.recycle(); - return result; - } - - public void updateBatteryWorkSource(WorkSource newSource) { - synchronized (mRunningWifiUids) { - try { - if (newSource != null) { - mRunningWifiUids.set(newSource); - } - if (mIsRunning) { - if (mReportedRunning) { - // If the work source has changed since last time, need - // to remove old work from battery stats. - if (mLastRunningWifiUids.diff(mRunningWifiUids)) { - mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, - mRunningWifiUids); - mLastRunningWifiUids.set(mRunningWifiUids); - } - } else { - // Now being started, report it. - mBatteryStats.noteWifiRunning(mRunningWifiUids); - mLastRunningWifiUids.set(mRunningWifiUids); - mReportedRunning = true; - } - } else { - if (mReportedRunning) { - // Last reported we were running, time to stop. - mBatteryStats.noteWifiStopped(mLastRunningWifiUids); - mLastRunningWifiUids.clear(); - mReportedRunning = false; - } - } - mWakeLock.setWorkSource(newSource); - } catch (RemoteException ignore) { - } - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); - mSupplicantStateTracker.dump(fd, pw, args); - pw.println("mLinkProperties " + mLinkProperties); - pw.println("mWifiInfo " + mWifiInfo); - pw.println("mDhcpResults " + mDhcpResults); - pw.println("mNetworkInfo " + mNetworkInfo); - pw.println("mLastSignalLevel " + mLastSignalLevel); - pw.println("mLastBssid " + mLastBssid); - pw.println("mLastNetworkId " + mLastNetworkId); - pw.println("mReconnectCount " + mReconnectCount); - pw.println("mOperationalMode " + mOperationalMode); - pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); - pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); - pw.println("Supplicant status " + mWifiNative.status()); - pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); - pw.println(); - mWifiConfigStore.dump(fd, pw, args); - } - - /********************************************************* - * Internal private functions - ********************************************************/ - - private void handleScreenStateChanged(boolean screenOn) { - if (DBG) log("handleScreenStateChanged: " + screenOn); - enableRssiPolling(screenOn); - if (mBackgroundScanSupported) { - enableBackgroundScanCommand(screenOn == false); - } - - if (screenOn) enableAllNetworks(); - if (mUserWantsSuspendOpt.get()) { - if (screenOn) { - sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); - } else { - //Allow 2s for suspend optimizations to be set - mSuspendWakeLock.acquire(2000); - sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); - } - } - mScreenBroadcastReceived.set(true); - } - - private void checkAndSetConnectivityInstance() { - if (mCm == null) { - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - } - } - - private boolean startTethering(ArrayList available) { - - boolean wifiAvailable = false; - - checkAndSetConnectivityInstance(); - - String[] wifiRegexs = mCm.getTetherableWifiRegexs(); - - for (String intf : available) { - for (String regex : wifiRegexs) { - if (intf.matches(regex)) { - - InterfaceConfiguration ifcg = null; - try { - ifcg = mNwService.getInterfaceConfig(intf); - if (ifcg != null) { - /* IP/netmask: 192.168.43.1/255.255.255.0 */ - ifcg.setLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); - ifcg.setInterfaceUp(); - - mNwService.setInterfaceConfig(intf, ifcg); - } - } catch (Exception e) { - loge("Error configuring interface " + intf + ", :" + e); - return false; - } - - if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { - loge("Error tethering on " + intf); - return false; - } - mTetherInterfaceName = intf; - return true; - } - } - } - // We found no interfaces to tether - return false; - } - - private void stopTethering() { - - checkAndSetConnectivityInstance(); - - /* Clear the interface config to allow dhcp correctly configure new - ip settings */ - InterfaceConfiguration ifcg = null; - try { - ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); - if (ifcg != null) { - ifcg.setLinkAddress( - new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); - mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); - } - } catch (Exception e) { - loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); - } - - if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { - loge("Untether initiate failed!"); - } - } - - private boolean isWifiTethered(ArrayList active) { - - checkAndSetConnectivityInstance(); - - String[] wifiRegexs = mCm.getTetherableWifiRegexs(); - for (String intf : active) { - for (String regex : wifiRegexs) { - if (intf.matches(regex)) { - return true; - } - } - } - // We found no interfaces that are tethered - return false; - } - - /** - * Set the country code from the system setting value, if any. - */ - private void setCountryCode() { - String countryCode = Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.WIFI_COUNTRY_CODE); - if (countryCode != null && !countryCode.isEmpty()) { - setCountryCode(countryCode, false); - } else { - //use driver default - } - } - - /** - * Set the frequency band from the system setting value, if any. - */ - private void setFrequencyBand() { - int band = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); - setFrequencyBand(band, false); - } - - private void setSuspendOptimizationsNative(int reason, boolean enabled) { - if (DBG) log("setSuspendOptimizationsNative: " + reason + " " + enabled); - if (enabled) { - mSuspendOptNeedsDisabled &= ~reason; - /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ - if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { - mWifiNative.setSuspendOptimizations(true); - } - } else { - mSuspendOptNeedsDisabled |= reason; - mWifiNative.setSuspendOptimizations(false); - } - } - - private void setSuspendOptimizations(int reason, boolean enabled) { - if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); - if (enabled) { - mSuspendOptNeedsDisabled &= ~reason; - } else { - mSuspendOptNeedsDisabled |= reason; - } - if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); - } - - private void setWifiState(int wifiState) { - final int previousWifiState = mWifiState.get(); - - try { - if (wifiState == WIFI_STATE_ENABLED) { - mBatteryStats.noteWifiOn(); - } else if (wifiState == WIFI_STATE_DISABLED) { - mBatteryStats.noteWifiOff(); - } - } catch (RemoteException e) { - loge("Failed to note battery stats in wifi"); - } - - mWifiState.set(wifiState); - - if (DBG) log("setWifiState: " + syncGetWifiStateByName()); - - final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); - intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void setWifiApState(int wifiApState) { - 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) { - loge("Failed to note battery stats in wifi"); - } - - // Update state - mWifiApState.set(wifiApState); - - if (DBG) log("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); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private static final String ID_STR = "id="; - private static final String BSSID_STR = "bssid="; - private static final String FREQ_STR = "freq="; - private static final String LEVEL_STR = "level="; - private static final String TSF_STR = "tsf="; - private static final String FLAGS_STR = "flags="; - private static final String SSID_STR = "ssid="; - private static final String DELIMITER_STR = "===="; - private static final String END_STR = "####"; - - /** - * Format: - * - * id=1 - * bssid=68:7f:76:d7:1a:6e - * freq=2412 - * level=-44 - * tsf=1344626243700342 - * flags=[WPA2-PSK-CCMP][WPS][ESS] - * ssid=zfdy - * ==== - * id=2 - * bssid=68:5f:74:d7:1a:6f - * freq=5180 - * level=-73 - * tsf=1344626243700373 - * flags=[WPA2-PSK-CCMP][WPS][ESS] - * ssid=zuby - * ==== - */ - private void setScanResults() { - String bssid = ""; - int level = 0; - int freq = 0; - long tsf = 0; - String flags = ""; - WifiSsid wifiSsid = null; - String scanResults; - String tmpResults; - StringBuffer scanResultsBuf = new StringBuffer(); - int sid = 0; - - while (true) { - tmpResults = mWifiNative.scanResults(sid); - if (TextUtils.isEmpty(tmpResults)) break; - scanResultsBuf.append(tmpResults); - scanResultsBuf.append("\n"); - String[] lines = tmpResults.split("\n"); - sid = -1; - for (int i=lines.length - 1; i >= 0; i--) { - if (lines[i].startsWith(END_STR)) { - break; - } else if (lines[i].startsWith(ID_STR)) { - try { - sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; - } catch (NumberFormatException e) { - // Nothing to do - } - break; - } - } - if (sid == -1) break; - } - - scanResults = scanResultsBuf.toString(); - if (TextUtils.isEmpty(scanResults)) { - return; - } - - // note that all these splits and substrings keep references to the original - // huge string buffer while the amount we really want is generally pretty small - // so make copies instead (one example b/11087956 wasted 400k of heap here). - synchronized(mScanResultCache) { - mScanResults = new ArrayList(); - String[] lines = scanResults.split("\n"); - final int bssidStrLen = BSSID_STR.length(); - final int flagLen = FLAGS_STR.length(); - - for (String line : lines) { - if (line.startsWith(BSSID_STR)) { - bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); - } else if (line.startsWith(FREQ_STR)) { - try { - freq = Integer.parseInt(line.substring(FREQ_STR.length())); - } catch (NumberFormatException e) { - freq = 0; - } - } else if (line.startsWith(LEVEL_STR)) { - try { - level = Integer.parseInt(line.substring(LEVEL_STR.length())); - /* some implementations avoid negative values by adding 256 - * so we need to adjust for that here. - */ - if (level > 0) level -= 256; - } catch(NumberFormatException e) { - level = 0; - } - } else if (line.startsWith(TSF_STR)) { - try { - tsf = Long.parseLong(line.substring(TSF_STR.length())); - } catch (NumberFormatException e) { - tsf = 0; - } - } else if (line.startsWith(FLAGS_STR)) { - flags = new String(line.getBytes(), flagLen, line.length() - flagLen); - } else if (line.startsWith(SSID_STR)) { - wifiSsid = WifiSsid.createFromAsciiEncoded( - line.substring(SSID_STR.length())); - } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { - if (bssid != null) { - String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; - String key = bssid + ssid; - ScanResult scanResult = mScanResultCache.get(key); - if (scanResult != null) { - scanResult.level = level; - scanResult.wifiSsid = wifiSsid; - // Keep existing API - scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : - WifiSsid.NONE; - scanResult.capabilities = flags; - scanResult.frequency = freq; - scanResult.timestamp = tsf; - } else { - scanResult = - new ScanResult( - wifiSsid, bssid, flags, level, freq, tsf); - mScanResultCache.put(key, scanResult); - } - mScanResults.add(scanResult); - } - bssid = null; - level = 0; - freq = 0; - tsf = 0; - flags = ""; - wifiSsid = null; - } - } - } - } - - /* - * Fetch RSSI and linkspeed on current connection - */ - private void fetchRssiAndLinkSpeedNative() { - int newRssi = -1; - int newLinkSpeed = -1; - - String signalPoll = mWifiNative.signalPoll(); - - if (signalPoll != null) { - String[] lines = signalPoll.split("\n"); - for (String line : lines) { - String[] prop = line.split("="); - if (prop.length < 2) continue; - try { - if (prop[0].equals("RSSI")) { - newRssi = Integer.parseInt(prop[1]); - } else if (prop[0].equals("LINKSPEED")) { - newLinkSpeed = Integer.parseInt(prop[1]); - } - } catch (NumberFormatException e) { - //Ignore, defaults on rssi and linkspeed are assigned - } - } - } - - if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values - /* some implementations avoid negative values by adding 256 - * so we need to adjust for that here. - */ - if (newRssi > 0) newRssi -= 256; - mWifiInfo.setRssi(newRssi); - /* - * Rather then sending the raw RSSI out every time it - * changes, we precalculate the signal level that would - * be displayed in the status bar, and only send the - * broadcast if that much more coarse-grained number - * changes. This cuts down greatly on the number of - * broadcasts, at the cost of not informing others - * interested in RSSI of all the changes in signal - * level. - */ - int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); - if (newSignalLevel != mLastSignalLevel) { - sendRssiChangeBroadcast(newRssi); - } - mLastSignalLevel = newSignalLevel; - } else { - mWifiInfo.setRssi(MIN_RSSI); - } - - if (newLinkSpeed != -1) { - mWifiInfo.setLinkSpeed(newLinkSpeed); - } - } - - /* - * Fetch TX packet counters on current connection - */ - private void fetchPktcntNative(RssiPacketCountInfo info) { - String pktcntPoll = mWifiNative.pktcntPoll(); - - if (pktcntPoll != null) { - String[] lines = pktcntPoll.split("\n"); - for (String line : lines) { - String[] prop = line.split("="); - if (prop.length < 2) continue; - try { - if (prop[0].equals("TXGOOD")) { - info.txgood = Integer.parseInt(prop[1]); - } else if (prop[0].equals("TXBAD")) { - info.txbad = Integer.parseInt(prop[1]); - } - } catch (NumberFormatException e) { - //Ignore - } - } - } - } - - /** - * Updates mLinkProperties by merging information from various sources. - * - * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, - * netlink, static configuration, ...). When one of these sources of information has updated - * link properties, we can't just assign them to mLinkProperties or we'd lose track of the - * information that came from other sources. Instead, when one of those sources has new - * information, we update the object that tracks the information from that source and then - * call this method to apply the change to mLinkProperties. - * - * The information in mLinkProperties is currently obtained as follows: - * - Interface name: set in the constructor. - * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver. - * - IPv4 routes, DNS servers, and domains: DHCP. - * - HTTP proxy: the wifi config store. - */ - private void updateLinkProperties() { - LinkProperties newLp = new LinkProperties(); - - // Interface name and proxy are locally configured. - newLp.setInterfaceName(mInterfaceName); - newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); - - // IPv4 and IPv6 addresses come from netlink. - newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses()); - - // For now, routing and DNS only come from DHCP or static configuration. In the future, - // we'll need to merge IPv6 DNS servers and domains coming from netlink. - synchronized (mDhcpResultsLock) { - // Even when we're using static configuration, we don't need to look at the config - // store, because static IP configuration also populates mDhcpResults. - if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { - LinkProperties lp = mDhcpResults.linkProperties; - for (RouteInfo route: lp.getRoutes()) { - newLp.addRoute(route); - } - for (InetAddress dns: lp.getDnses()) { - newLp.addDns(dns); - } - newLp.setDomains(lp.getDomains()); - } - } - - // If anything has changed, and we're already connected, send out a notification. - // If we're still connecting, apps will be notified when we connect. - if (!newLp.equals(mLinkProperties)) { - if (DBG) { - log("Link configuration changed for netId: " + mLastNetworkId - + " old: " + mLinkProperties + "new: " + newLp); - } - mLinkProperties = newLp; - if (getNetworkDetailedState() == DetailedState.CONNECTED) { - sendLinkConfigurationChangedBroadcast(); - } - } - } - - /** - * Clears all our link properties. - */ - private void clearLinkProperties() { - // If the network used DHCP, clear the LinkProperties we stored in the config store. - if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - mWifiConfigStore.clearLinkProperties(mLastNetworkId); - } - - // Clear the link properties obtained from DHCP and netlink. - synchronized(mDhcpResultsLock) { - if (mDhcpResults != null && mDhcpResults.linkProperties != null) { - mDhcpResults.linkProperties.clear(); - } - } - mNetlinkLinkProperties.clear(); - - // Now clear the merged link properties. - mLinkProperties.clear(); - } - - private int getMaxDhcpRetries() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, - DEFAULT_MAX_DHCP_RETRIES); - } - - private void sendScanResultsAvailableBroadcast() { - noteScanEnd(); - Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendRssiChangeBroadcast(final int newRssi) { - Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendNetworkStateChangeBroadcast(String bssid) { - Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); - intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); - if (bssid != null) - intent.putExtra(WifiManager.EXTRA_BSSID, bssid); - if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || - mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { - intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); - } - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendLinkConfigurationChangedBroadcast() { - Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendSupplicantConnectionChangedBroadcast(boolean connected) { - Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - - /** - * Record the detailed state of a network. - * @param state the new {@code DetailedState} - */ - private void setNetworkDetailedState(NetworkInfo.DetailedState state) { - if (DBG) { - log("setDetailed state, old =" - + mNetworkInfo.getDetailedState() + " and new state=" + state); - } - - if (state != mNetworkInfo.getDetailedState()) { - mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); - } - } - - private DetailedState getNetworkDetailedState() { - return mNetworkInfo.getDetailedState(); - } - - - private SupplicantState handleSupplicantStateChange(Message message) { - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - SupplicantState state = stateChangeResult.state; - // Supplicant state change - // [31-13] Reserved for future use - // [8 - 0] Supplicant state (as defined in SupplicantState.java) - // 50023 supplicant_state_changed (custom|1|5) - mWifiInfo.setSupplicantState(state); - // Network id is only valid when we start connecting - if (SupplicantState.isConnecting(state)) { - mWifiInfo.setNetworkId(stateChangeResult.networkId); - } else { - mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); - } - - mWifiInfo.setBSSID(stateChangeResult.BSSID); - mWifiInfo.setSSID(stateChangeResult.wifiSsid); - - mSupplicantStateTracker.sendMessage(Message.obtain(message)); - - return state; - } - - /** - * Resets the Wi-Fi Connections by clearing any state, resetting any sockets - * using the interface, stopping DHCP & disabling interface - */ - private void handleNetworkDisconnect() { - if (DBG) log("Stopping DHCP and clearing IP"); - - stopDhcp(); - - try { - mNwService.clearInterfaceAddresses(mInterfaceName); - mNwService.disableIpv6(mInterfaceName); - } catch (Exception e) { - loge("Failed to clear addresses or disable ipv6" + e); - } - - /* Reset data structures */ - mWifiInfo.setInetAddress(null); - mWifiInfo.setBSSID(null); - mWifiInfo.setSSID(null); - mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); - mWifiInfo.setRssi(MIN_RSSI); - mWifiInfo.setLinkSpeed(-1); - mWifiInfo.setMeteredHint(false); - - setNetworkDetailedState(DetailedState.DISCONNECTED); - mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); - - /* Clear network properties */ - clearLinkProperties(); - - /* send event to CM & network change broadcast */ - sendNetworkStateChangeBroadcast(mLastBssid); - - mLastBssid= null; - mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; - } - - private void handleSupplicantConnectionLoss() { - /* Socket connection can be lost when we do a graceful shutdown - * or when the driver is hung. Ensure supplicant is stopped here. - */ - mWifiMonitor.killSupplicant(mP2pSupported); - sendSupplicantConnectionChangedBroadcast(false); - setWifiState(WIFI_STATE_DISABLED); - } - - void handlePreDhcpSetup() { - mDhcpActive = true; - if (!mBluetoothConnectionActive) { - /* - * There are problems setting the Wi-Fi driver's power - * mode to active when bluetooth coexistence mode is - * enabled or sense. - *

- * 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. - *

- * 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 power save and suspend optimizations during DHCP */ - // Note: The order here is important for now. Brcm driver changes - // power settings when we control suspend mode optimizations. - // TODO: Remove this comment when the driver is fixed. - setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); - mWifiNative.setPowerSave(false); - - stopBatchedScan(); - - /* P2p discovery breaks dhcp, shut it down in order to get through this */ - Message msg = new Message(); - msg.what = WifiP2pService.BLOCK_DISCOVERY; - msg.arg1 = WifiP2pService.ENABLED; - msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; - msg.obj = mDhcpStateMachine; - mWifiP2pChannel.sendMessage(msg); - } - - - void startDhcp() { - if (mDhcpStateMachine == null) { - mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( - mContext, WifiStateMachine.this, mInterfaceName); - - } - mDhcpStateMachine.registerForPreDhcpNotification(); - mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); - } - - void stopDhcp() { - if (mDhcpStateMachine != null) { - /* In case we were in middle of DHCP operation restore back powermode */ - handlePostDhcpSetup(); - mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); - } - } - - void handlePostDhcpSetup() { - /* Restore power save and suspend optimizations */ - setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); - mWifiNative.setPowerSave(true); - - mWifiP2pChannel.sendMessage(WifiP2pService.BLOCK_DISCOVERY, WifiP2pService.DISABLED); - - // Set the coexistence mode back to its default value - mWifiNative.setBluetoothCoexistenceMode( - mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); - - mDhcpActive = false; - - startBatchedScan(); - } - - private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { - mLastSignalLevel = -1; // force update of signal strength - mReconnectCount = 0; //Reset IP failure tracking - synchronized (mDhcpResultsLock) { - mDhcpResults = dhcpResults; - } - LinkProperties linkProperties = dhcpResults.linkProperties; - mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); - InetAddress addr = null; - Iterator addrs = linkProperties.getAddresses().iterator(); - if (addrs.hasNext()) { - addr = addrs.next(); - } - mWifiInfo.setInetAddress(addr); - mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); - updateLinkProperties(); - } - - private void handleFailedIpConfiguration() { - loge("IP configuration failed"); - - mWifiInfo.setInetAddress(null); - mWifiInfo.setMeteredHint(false); - /** - * If we've exceeded the maximum number of retries for DHCP - * to a given network, disable the network - */ - int maxRetries = getMaxDhcpRetries(); - // maxRetries == 0 means keep trying forever - if (maxRetries > 0 && ++mReconnectCount > maxRetries) { - loge("Failed " + - mReconnectCount + " times, Disabling " + mLastNetworkId); - mWifiConfigStore.disableNetwork(mLastNetworkId, - WifiConfiguration.DISABLED_DHCP_FAILURE); - mReconnectCount = 0; - } - - /* DHCP times out after about 30 seconds, we do a - * disconnect and an immediate reconnect to try again - */ - mWifiNative.disconnect(); - mWifiNative.reconnect(); - } - - /* Current design is to not set the config on a running hostapd but instead - * stop and start tethering when user changes config on a running access point - * - * TODO: Add control channel setup through hostapd that allows changing config - * on a running daemon - */ - private void startSoftApWithConfig(final WifiConfiguration config) { - // start hostapd on a seperate thread - new Thread(new Runnable() { - public void run() { - try { - mNwService.startAccessPoint(config, mInterfaceName); - } catch (Exception e) { - loge("Exception in softap start " + e); - try { - mNwService.stopAccessPoint(mInterfaceName); - mNwService.startAccessPoint(config, mInterfaceName); - } catch (Exception e1) { - loge("Exception in softap re-start " + e1); - sendMessage(CMD_START_AP_FAILURE); - return; - } - } - if (DBG) log("Soft AP start successful"); - sendMessage(CMD_START_AP_SUCCESS); - } - }).start(); - } - - /******************************************************** - * HSM states - *******************************************************/ - - class DefaultState extends State { - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - } else { - loge("WifiP2pService connection failure, error=" + message.arg1); - } - break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); - //TODO: Re-establish connection to state machine after a delay - //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); - break; - case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: - mBluetoothConnectionActive = (message.arg1 != - BluetoothAdapter.STATE_DISCONNECTED); - break; - /* Synchronous call returns */ - case CMD_PING_SUPPLICANT: - case CMD_ENABLE_NETWORK: - case CMD_ADD_OR_UPDATE_NETWORK: - case CMD_REMOVE_NETWORK: - case CMD_SAVE_CONFIG: - replyToMessage(message, message.what, FAILURE); - break; - case CMD_GET_CONFIGURED_NETWORKS: - replyToMessage(message, message.what, (List) null); - break; - case CMD_ENABLE_RSSI_POLL: - mEnableRssiPolling = (message.arg1 == 1); - break; - case CMD_ENABLE_BACKGROUND_SCAN: - mEnableBackgroundScan = (message.arg1 == 1); - break; - case CMD_SET_HIGH_PERF_MODE: - if (message.arg1 == 1) { - setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); - } else { - setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); - } - break; - case CMD_BOOT_COMPLETED: - String countryCode = mPersistedCountryCode; - if (TextUtils.isEmpty(countryCode) == false) { - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.WIFI_COUNTRY_CODE, - countryCode); - // it may be that the state transition that should send this info - // to the driver happened between mPersistedCountryCode getting set - // and now, so simply persisting it here would mean we have sent - // nothing to the driver. Send the cmd so it might be set now. - sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode); - } - break; - case CMD_SET_BATCHED_SCAN: - recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); - break; - case CMD_POLL_BATCHED_SCAN: - handleBatchedScanPollRequest(); - break; - case CMD_START_NEXT_BATCHED_SCAN: - startNextBatchedScan(); - break; - /* Discard */ - case CMD_START_SCAN: - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_STOP_SUPPLICANT_FAILED: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_DELAYED_STOP_DRIVER: - case CMD_DRIVER_START_TIMED_OUT: - case CMD_START_AP: - case CMD_START_AP_SUCCESS: - case CMD_START_AP_FAILURE: - case CMD_STOP_AP: - case CMD_TETHER_STATE_CHANGE: - case CMD_TETHER_NOTIFICATION_TIMED_OUT: - case CMD_DISCONNECT: - case CMD_RECONNECT: - case CMD_REASSOCIATE: - case CMD_RELOAD_TLS_AND_RECONNECT: - case WifiMonitor.SUP_CONNECTION_EVENT: - case WifiMonitor.SUP_DISCONNECTION_EVENT: - case WifiMonitor.NETWORK_CONNECTION_EVENT: - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - case WifiMonitor.SCAN_RESULTS_EVENT: - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: - case WifiMonitor.ASSOCIATION_REJECTION_EVENT: - case WifiMonitor.WPS_OVERLAP_EVENT: - case CMD_BLACKLIST_NETWORK: - case CMD_CLEAR_BLACKLIST: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_RSSI_POLL: - case CMD_ENABLE_ALL_NETWORKS: - case DhcpStateMachine.CMD_PRE_DHCP_ACTION: - case DhcpStateMachine.CMD_POST_DHCP_ACTION: - /* Handled by WifiApConfigStore */ - case CMD_SET_AP_CONFIG: - case CMD_SET_AP_CONFIG_COMPLETED: - case CMD_REQUEST_AP_CONFIG: - case CMD_RESPONSE_AP_CONFIG: - case WifiWatchdogStateMachine.POOR_LINK_DETECTED: - case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: - case CMD_NO_NETWORKS_PERIODIC_SCAN: - case CMD_DISABLE_P2P_RSP: - break; - case DhcpStateMachine.CMD_ON_QUIT: - mDhcpStateMachine = null; - break; - case CMD_SET_SUSPEND_OPT_ENABLED: - if (message.arg1 == 1) { - mSuspendWakeLock.release(); - setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); - } else { - setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); - } - break; - case WifiMonitor.DRIVER_HUNG_EVENT: - setSupplicantRunning(false); - setSupplicantRunning(true); - break; - case WifiManager.CONNECT_NETWORK: - replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, - WifiManager.BUSY); - break; - case WifiManager.FORGET_NETWORK: - replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, - WifiManager.BUSY); - break; - case WifiManager.SAVE_NETWORK: - replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, - WifiManager.BUSY); - break; - case WifiManager.START_WPS: - replyToMessage(message, WifiManager.WPS_FAILED, - WifiManager.BUSY); - break; - case WifiManager.CANCEL_WPS: - replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, - WifiManager.BUSY); - break; - case WifiManager.DISABLE_NETWORK: - replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, - WifiManager.BUSY); - break; - case WifiManager.RSSI_PKTCNT_FETCH: - replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, - WifiManager.BUSY); - break; - case WifiP2pService.P2P_CONNECTION_CHANGED: - NetworkInfo info = (NetworkInfo) message.obj; - mP2pConnected.set(info.isConnected()); - break; - case WifiP2pService.DISCONNECT_WIFI_REQUEST: - mTemporarilyDisconnectWifi = (message.arg1 == 1); - replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE); - break; - case CMD_IP_ADDRESS_UPDATED: - // addLinkAddress is a no-op if called more than once with the same address. - if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) { - updateLinkProperties(); - } - break; - case CMD_IP_ADDRESS_REMOVED: - if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) { - updateLinkProperties(); - } - break; - default: - loge("Error! unhandled message" + message); - break; - } - return HANDLED; - } - } - - class InitialState extends State { - @Override - public void enter() { - mWifiNative.unloadDriver(); - - if (mWifiP2pChannel == null) { - mWifiP2pChannel = new AsyncChannel(); - mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); - } - - if (mWifiApConfigChannel == null) { - mWifiApConfigChannel = new AsyncChannel(); - WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( - mContext, getHandler()); - wifiApConfigStore.loadApConfiguration(); - mWifiApConfigChannel.connectSync(mContext, getHandler(), - wifiApConfigStore.getMessenger()); - } - } - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case CMD_START_SUPPLICANT: - if (mWifiNative.loadDriver()) { - try { - mNwService.wifiFirmwareReload(mInterfaceName, "STA"); - } catch (Exception e) { - loge("Failed to reload STA firmware " + e); - // continue - } - - try { - // A runtime crash can leave the interface up and - // this affects connectivity when supplicant starts up. - // Ensure interface is down before a supplicant start. - mNwService.setInterfaceDown(mInterfaceName); - // Set privacy extensions - mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, 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); - } 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.startSupplicant(mP2pSupported)) { - setWifiState(WIFI_STATE_ENABLING); - if (DBG) log("Supplicant start successful"); - mWifiMonitor.startMonitoring(); - transitionTo(mSupplicantStartingState); - } else { - loge("Failed to start supplicant!"); - } - } else { - loge("Failed to load driver"); - } - break; - case CMD_START_AP: - if (mWifiNative.loadDriver()) { - setWifiApState(WIFI_AP_STATE_ENABLING); - transitionTo(mSoftApStartingState); - } else { - loge("Failed to load driver for softap"); - } - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class SupplicantStartingState extends State { - private void initializeWpsDetails() { - String detail; - detail = SystemProperties.get("ro.product.name", ""); - if (!mWifiNative.setDeviceName(detail)) { - loge("Failed to set device name " + detail); - } - detail = SystemProperties.get("ro.product.manufacturer", ""); - if (!mWifiNative.setManufacturer(detail)) { - loge("Failed to set manufacturer " + detail); - } - detail = SystemProperties.get("ro.product.model", ""); - if (!mWifiNative.setModelName(detail)) { - loge("Failed to set model name " + detail); - } - detail = SystemProperties.get("ro.product.model", ""); - if (!mWifiNative.setModelNumber(detail)) { - loge("Failed to set model number " + detail); - } - detail = SystemProperties.get("ro.serialno", ""); - if (!mWifiNative.setSerialNumber(detail)) { - loge("Failed to set serial number " + detail); - } - if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { - loge("Failed to set WPS config methods"); - } - if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { - loge("Failed to set primary device type " + mPrimaryDeviceType); - } - } - - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case WifiMonitor.SUP_CONNECTION_EVENT: - if (DBG) log("Supplicant connection established"); - setWifiState(WIFI_STATE_ENABLED); - mSupplicantRestartCount = 0; - /* Reset the supplicant state to indicate the supplicant - * state is not known at this time */ - mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); - /* Initialize data structures */ - mLastBssid = null; - mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; - mLastSignalLevel = -1; - - mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); - mWifiConfigStore.loadAndEnableAllNetworks(); - initializeWpsDetails(); - - sendSupplicantConnectionChangedBroadcast(true); - transitionTo(mDriverStartedState); - break; - case WifiMonitor.SUP_DISCONNECTION_EVENT: - if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { - loge("Failed to setup control channel, restart supplicant"); - mWifiMonitor.killSupplicant(mP2pSupported); - transitionTo(mInitialState); - sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); - } else { - loge("Failed " + mSupplicantRestartCount + - " times to start supplicant, unload driver"); - mSupplicantRestartCount = 0; - setWifiState(WIFI_STATE_UNKNOWN); - transitionTo(mInitialState); - } - break; - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class SupplicantStartedState extends State { - @Override - public void enter() { - /* Wifi is available as long as we have a connection to supplicant */ - mNetworkInfo.setIsAvailable(true); - - int defaultInterval = mContext.getResources().getInteger( - R.integer.config_wifi_supplicant_scan_interval); - - mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), - Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, - defaultInterval); - - mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ - if (mP2pSupported) { - transitionTo(mWaitForP2pDisableState); - } else { - transitionTo(mSupplicantStoppingState); - } - break; - case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ - loge("Connection lost, restart supplicant"); - handleSupplicantConnectionLoss(); - handleNetworkDisconnect(); - mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); - if (mP2pSupported) { - transitionTo(mWaitForP2pDisableState); - } else { - transitionTo(mInitialState); - } - sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); - break; - case WifiMonitor.SCAN_RESULTS_EVENT: - setScanResults(); - sendScanResultsAvailableBroadcast(); - mScanResultIsPending = false; - break; - case CMD_PING_SUPPLICANT: - boolean ok = mWifiNative.ping(); - replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); - break; - /* Cannot start soft AP while in client mode */ - case CMD_START_AP: - loge("Failed to start soft AP with a running supplicant"); - setWifiApState(WIFI_AP_STATE_FAILED); - break; - case CMD_SET_OPERATIONAL_MODE: - mOperationalMode = message.arg1; - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - mNetworkInfo.setIsAvailable(false); - } - } - - class SupplicantStoppingState extends State { - @Override - public void enter() { - /* Send any reset commands to supplicant before shutting it down */ - handleNetworkDisconnect(); - if (mDhcpStateMachine != null) { - mDhcpStateMachine.doQuit(); - } - - if (DBG) log("stopping supplicant"); - mWifiMonitor.stopSupplicant(); - - /* Send ourselves a delayed message to indicate failure after a wait time */ - sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, - ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); - setWifiState(WIFI_STATE_DISABLING); - mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case WifiMonitor.SUP_CONNECTION_EVENT: - loge("Supplicant connection received while stopping"); - break; - case WifiMonitor.SUP_DISCONNECTION_EVENT: - if (DBG) log("Supplicant connection lost"); - handleSupplicantConnectionLoss(); - transitionTo(mInitialState); - break; - case CMD_STOP_SUPPLICANT_FAILED: - if (message.arg1 == mSupplicantStopFailureToken) { - loge("Timed out on a supplicant stop, kill and proceed"); - handleSupplicantConnectionLoss(); - transitionTo(mInitialState); - } - break; - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class DriverStartingState extends State { - private int mTries; - @Override - public void enter() { - mTries = 1; - /* Send ourselves a delayed message to start driver a second time */ - sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, - ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - SupplicantState state = handleSupplicantStateChange(message); - /* If suplicant is exiting out of INTERFACE_DISABLED state into - * a state that indicates driver has started, it is ready to - * receive driver commands - */ - if (SupplicantState.isDriverActive(state)) { - transitionTo(mDriverStartedState); - } - break; - case CMD_DRIVER_START_TIMED_OUT: - if (message.arg1 == mDriverStartToken) { - if (mTries >= 2) { - loge("Failed to start driver after " + mTries); - transitionTo(mDriverStoppedState); - } else { - loge("Driver start failed, retrying"); - mWakeLock.acquire(); - mWifiNative.startDriver(); - mWakeLock.release(); - - ++mTries; - /* Send ourselves a delayed message to start driver again */ - sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, - ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); - } - } - break; - /* Queue driver commands & connection events */ - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case WifiMonitor.NETWORK_CONNECTION_EVENT: - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: - case WifiMonitor.ASSOCIATION_REJECTION_EVENT: - case WifiMonitor.WPS_OVERLAP_EVENT: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - case CMD_START_SCAN: - case CMD_DISCONNECT: - case CMD_REASSOCIATE: - case CMD_RECONNECT: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class DriverStartedState extends State { - @Override - public void enter() { - mIsRunning = true; - mInDelayedStop = false; - mDelayedStopCounter++; - updateBatteryWorkSource(null); - /** - * 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 - * driver are changed to reduce interference with bluetooth - */ - mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); - /* set country code */ - setCountryCode(); - /* set frequency band of operation */ - setFrequencyBand(); - /* initialize network state */ - setNetworkDetailedState(DetailedState.DISCONNECTED); - - /* Remove any filtering on Multicast v6 at start */ - mWifiNative.stopFilteringMulticastV6Packets(); - - /* Reset Multicast v4 filtering state */ - if (mFilteringMulticastV4Packets.get()) { - mWifiNative.startFilteringMulticastV4Packets(); - } else { - mWifiNative.stopFilteringMulticastV4Packets(); - } - - mDhcpActive = false; - - startBatchedScan(); - - if (mOperationalMode != CONNECT_MODE) { - mWifiNative.disconnect(); - mWifiConfigStore.disableAllNetworks(); - if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { - setWifiState(WIFI_STATE_DISABLED); - } - transitionTo(mScanModeState); - } else { - /* Driver stop may have disabled networks, enable right after start */ - mWifiConfigStore.enableAllNetworks(); - - if (DBG) log("Attempting to reconnect to wifi network .."); - mWifiNative.reconnect(); - - // Status pulls in the current supplicant state and network connection state - // events over the monitor connection. This helps framework sync up with - // current supplicant state - mWifiNative.status(); - transitionTo(mDisconnectedState); - } - - // We may have missed screen update at boot - if (mScreenBroadcastReceived.get() == false) { - PowerManager powerManager = (PowerManager)mContext.getSystemService( - Context.POWER_SERVICE); - handleScreenStateChanged(powerManager.isScreenOn()); - } else { - // Set the right suspend mode settings - mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 - && mUserWantsSuspendOpt.get()); - } - mWifiNative.setPowerSave(true); - - if (mP2pSupported) { - if (mOperationalMode == CONNECT_MODE) { - mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); - } else { - // P2P statemachine starts in disabled state, and is not enabled until - // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to - // keep it disabled. - } - } - - final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_START_SCAN: - noteScanStart(message.arg1, (WorkSource) message.obj); - startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); - break; - case CMD_SET_BATCHED_SCAN: - if (recordBatchedScanSettings(message.arg1, message.arg2, - (Bundle)message.obj)) { - startBatchedScan(); - } - break; - case CMD_SET_COUNTRY_CODE: - String country = (String) message.obj; - if (DBG) log("set country code " + country); - if (country != null) { - country = country.toUpperCase(Locale.ROOT); - if (mLastSetCountryCode == null - || country.equals(mLastSetCountryCode) == false) { - if (mWifiNative.setCountryCode(country)) { - mLastSetCountryCode = country; - } else { - loge("Failed to set country code " + country); - } - } - } - break; - case CMD_SET_FREQUENCY_BAND: - int band = message.arg1; - if (DBG) log("set frequency band " + band); - if (mWifiNative.setBand(band)) { - mFrequencyBand.set(band); - // flush old data - like scan results - mWifiNative.bssFlush(); - //Fetch the latest scan results when frequency band is set - startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); - } else { - loge("Failed to set frequency band " + band); - } - break; - case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: - mBluetoothConnectionActive = (message.arg1 != - BluetoothAdapter.STATE_DISCONNECTED); - mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); - break; - case CMD_STOP_DRIVER: - int mode = message.arg1; - - /* Already doing a delayed stop */ - if (mInDelayedStop) { - if (DBG) log("Already in delayed stop"); - break; - } - /* disconnect right now, but leave the driver running for a bit */ - mWifiConfigStore.disableAllNetworks(); - - mInDelayedStop = true; - mDelayedStopCounter++; - if (DBG) log("Delayed stop message " + mDelayedStopCounter); - - /* send regular delayed shut down */ - Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); - driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); - mDriverStopIntent = PendingIntent.getBroadcast(mContext, - DRIVER_STOP_REQUEST, driverStopIntent, - PendingIntent.FLAG_UPDATE_CURRENT); - - mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() - + mDriverStopDelayMs, mDriverStopIntent); - break; - case CMD_START_DRIVER: - if (mInDelayedStop) { - mInDelayedStop = false; - mDelayedStopCounter++; - mAlarmManager.cancel(mDriverStopIntent); - if (DBG) log("Delayed stop ignored due to start"); - if (mOperationalMode == CONNECT_MODE) { - mWifiConfigStore.enableAllNetworks(); - } - } - break; - case CMD_DELAYED_STOP_DRIVER: - if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); - if (message.arg1 != mDelayedStopCounter) break; - if (getCurrentState() != mDisconnectedState) { - mWifiNative.disconnect(); - handleNetworkDisconnect(); - } - mWakeLock.acquire(); - mWifiNative.stopDriver(); - mWakeLock.release(); - if (mP2pSupported) { - transitionTo(mWaitForP2pDisableState); - } else { - transitionTo(mDriverStoppingState); - } - break; - case CMD_START_PACKET_FILTERING: - if (message.arg1 == MULTICAST_V6) { - mWifiNative.startFilteringMulticastV6Packets(); - } else if (message.arg1 == MULTICAST_V4) { - mWifiNative.startFilteringMulticastV4Packets(); - } else { - loge("Illegal arugments to CMD_START_PACKET_FILTERING"); - } - break; - case CMD_STOP_PACKET_FILTERING: - if (message.arg1 == MULTICAST_V6) { - mWifiNative.stopFilteringMulticastV6Packets(); - } else if (message.arg1 == MULTICAST_V4) { - mWifiNative.stopFilteringMulticastV4Packets(); - } else { - loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); - } - break; - case CMD_SET_SUSPEND_OPT_ENABLED: - if (message.arg1 == 1) { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); - mSuspendWakeLock.release(); - } else { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); - } - break; - case CMD_SET_HIGH_PERF_MODE: - if (message.arg1 == 1) { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); - } else { - setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); - } - break; - case CMD_ENABLE_TDLS: - if (message.obj != null) { - String remoteAddress = (String) message.obj; - boolean enable = (message.arg1 == 1); - mWifiNative.startTdls(remoteAddress, enable); - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - @Override - public void exit() { - mIsRunning = false; - updateBatteryWorkSource(null); - mScanResults = new ArrayList(); - - stopBatchedScan(); - - final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - noteScanEnd(); // wrap up any pending request. - - mLastSetCountryCode = null; - } - } - - class WaitForP2pDisableState extends State { - private State mTransitionToState; - @Override - public void enter() { - switch (getCurrentMessage().what) { - case WifiMonitor.SUP_DISCONNECTION_EVENT: - mTransitionToState = mInitialState; - break; - case CMD_DELAYED_STOP_DRIVER: - mTransitionToState = mDriverStoppingState; - break; - case CMD_STOP_SUPPLICANT: - mTransitionToState = mSupplicantStoppingState; - break; - default: - mTransitionToState = mDriverStoppingState; - break; - } - mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case WifiStateMachine.CMD_DISABLE_P2P_RSP: - transitionTo(mTransitionToState); - break; - /* Defer wifi start/shut and driver commands */ - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - case CMD_START_SCAN: - case CMD_DISCONNECT: - case CMD_REASSOCIATE: - case CMD_RECONNECT: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class DriverStoppingState extends State { - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - SupplicantState state = handleSupplicantStateChange(message); - if (state == SupplicantState.INTERFACE_DISABLED) { - transitionTo(mDriverStoppedState); - } - break; - /* Queue driver commands */ - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - case CMD_START_SCAN: - case CMD_DISCONNECT: - case CMD_REASSOCIATE: - case CMD_RECONNECT: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class DriverStoppedState extends State { - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - SupplicantState state = stateChangeResult.state; - // A WEXT bug means that we can be back to driver started state - // unexpectedly - if (SupplicantState.isDriverActive(state)) { - transitionTo(mDriverStartedState); - } - break; - case CMD_START_DRIVER: - mWakeLock.acquire(); - mWifiNative.startDriver(); - mWakeLock.release(); - transitionTo(mDriverStartingState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class ScanModeState extends State { - private int mLastOperationMode; - @Override - public void enter() { - mLastOperationMode = mOperationalMode; - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_SET_OPERATIONAL_MODE: - if (message.arg1 == CONNECT_MODE) { - - if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { - setWifiState(WIFI_STATE_ENABLED); - // Load and re-enable networks when going back to enabled state - // This is essential for networks to show up after restore - mWifiConfigStore.loadAndEnableAllNetworks(); - mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); - } else { - mWifiConfigStore.enableAllNetworks(); - } - - mWifiNative.reconnect(); - - mOperationalMode = CONNECT_MODE; - transitionTo(mDisconnectedState); - } else { - // Nothing to do - return HANDLED; - } - break; - // Handle scan. All the connection related commands are - // handled only in ConnectModeState - case CMD_START_SCAN: - noteScanStart(message.arg1, (WorkSource) message.obj); - startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class ConnectModeState extends State { - @Override - public boolean processMessage(Message message) { - WifiConfiguration config; - boolean ok; - switch(message.what) { - case WifiMonitor.ASSOCIATION_REJECTION_EVENT: - mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); - break; - case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: - mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); - break; - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - SupplicantState state = handleSupplicantStateChange(message); - // A driver/firmware hang can now put the interface in a down state. - // We detect the interface going down and recover from it - if (!SupplicantState.isDriverActive(state)) { - if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { - handleNetworkDisconnect(); - } - log("Detected an interface down, restart driver"); - transitionTo(mDriverStoppedState); - sendMessage(CMD_START_DRIVER); - break; - } - - // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT - // when authentication times out after a successful connection, - // we can figure this from the supplicant state. If supplicant - // state is DISCONNECTED, but the mNetworkInfo says we are not - // disconnected, we need to handle a disconnection - if (state == SupplicantState.DISCONNECTED && - mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { - if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); - handleNetworkDisconnect(); - transitionTo(mDisconnectedState); - } - break; - case WifiP2pService.DISCONNECT_WIFI_REQUEST: - if (message.arg1 == 1) { - mWifiNative.disconnect(); - mTemporarilyDisconnectWifi = true; - } else { - mWifiNative.reconnect(); - mTemporarilyDisconnectWifi = false; - } - break; - case CMD_ADD_OR_UPDATE_NETWORK: - config = (WifiConfiguration) message.obj; - replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, - mWifiConfigStore.addOrUpdateNetwork(config)); - break; - case CMD_REMOVE_NETWORK: - ok = mWifiConfigStore.removeNetwork(message.arg1); - replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); - break; - case CMD_ENABLE_NETWORK: - ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); - replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); - break; - case CMD_ENABLE_ALL_NETWORKS: - long time = android.os.SystemClock.elapsedRealtime(); - if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { - mWifiConfigStore.enableAllNetworks(); - mLastEnableAllNetworksTime = time; - } - break; - case WifiManager.DISABLE_NETWORK: - if (mWifiConfigStore.disableNetwork(message.arg1, - WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { - replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); - } else { - replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, - WifiManager.ERROR); - } - break; - case CMD_BLACKLIST_NETWORK: - mWifiNative.addToBlacklist((String)message.obj); - break; - case CMD_CLEAR_BLACKLIST: - mWifiNative.clearBlacklist(); - break; - case CMD_SAVE_CONFIG: - ok = mWifiConfigStore.saveConfig(); - replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); - - // Inform the backup manager about a data change - IBackupManager ibm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - if (ibm != null) { - try { - ibm.dataChanged("com.android.providers.settings"); - } catch (Exception e) { - // Try again later - } - } - break; - case CMD_GET_CONFIGURED_NETWORKS: - replyToMessage(message, message.what, - mWifiConfigStore.getConfiguredNetworks()); - break; - /* Do a redundant disconnect without transition */ - case CMD_DISCONNECT: - mWifiNative.disconnect(); - break; - case CMD_RECONNECT: - mWifiNative.reconnect(); - break; - case CMD_REASSOCIATE: - mWifiNative.reassociate(); - break; - case CMD_RELOAD_TLS_AND_RECONNECT: - if (mWifiConfigStore.needsUnlockedKeyStore()) { - logd("Reconnecting to give a chance to un-connected TLS networks"); - mWifiNative.disconnect(); - mWifiNative.reconnect(); - } - break; - case WifiManager.CONNECT_NETWORK: - /* The connect message can contain a network id passed as arg1 on message or - * or a config passed as obj on message. - * For a new network, a config is passed to create and connect. - * For an existing network, a network id is passed - */ - int netId = message.arg1; - config = (WifiConfiguration) message.obj; - - /* Save the network config */ - if (config != null) { - NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); - netId = result.getNetworkId(); - } - - if (mWifiConfigStore.selectNetwork(netId) && - mWifiNative.reconnect()) { - /* The state tracker handles enabling networks upon completion/failure */ - mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); - replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); - /* Expect a disconnection from the old connection */ - transitionTo(mDisconnectingState); - } else { - loge("Failed to connect config: " + config + " netId: " + netId); - replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, - WifiManager.ERROR); - break; - } - break; - case WifiManager.SAVE_NETWORK: - config = (WifiConfiguration) message.obj; - NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); - if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { - replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); - } else { - loge("Failed to save network"); - replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, - WifiManager.ERROR); - } - break; - case WifiManager.FORGET_NETWORK: - if (mWifiConfigStore.forgetNetwork(message.arg1)) { - replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); - } else { - loge("Failed to forget network"); - replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, - WifiManager.ERROR); - } - break; - case WifiManager.START_WPS: - WpsInfo wpsInfo = (WpsInfo) message.obj; - WpsResult wpsResult; - switch (wpsInfo.setup) { - case WpsInfo.PBC: - wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); - break; - case WpsInfo.KEYPAD: - wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); - break; - case WpsInfo.DISPLAY: - wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); - break; - default: - wpsResult = new WpsResult(Status.FAILURE); - loge("Invalid setup for WPS"); - break; - } - if (wpsResult.status == Status.SUCCESS) { - replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); - transitionTo(mWpsRunningState); - } else { - loge("Failed to start WPS with config " + wpsInfo.toString()); - replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); - } - break; - case WifiMonitor.NETWORK_CONNECTION_EVENT: - if (DBG) log("Network connection established"); - mLastNetworkId = message.arg1; - mLastBssid = (String) message.obj; - - mWifiInfo.setBSSID(mLastBssid); - mWifiInfo.setNetworkId(mLastNetworkId); - /* send event to CM & network change broadcast */ - setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); - sendNetworkStateChangeBroadcast(mLastBssid); - transitionTo(mObtainingIpState); - break; - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - if (DBG) log("Network connection lost"); - handleNetworkDisconnect(); - transitionTo(mDisconnectedState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class L2ConnectedState extends State { - @Override - public void enter() { - mRssiPollToken++; - if (mEnableRssiPolling) { - sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); - } - } - - @Override - public void exit() { - handleNetworkDisconnect(); - } - - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case DhcpStateMachine.CMD_PRE_DHCP_ACTION: - handlePreDhcpSetup(); - break; - case DhcpStateMachine.CMD_POST_DHCP_ACTION: - handlePostDhcpSetup(); - if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { - if (DBG) log("DHCP successful"); - handleSuccessfulIpConfiguration((DhcpResults) message.obj); - transitionTo(mVerifyingLinkState); - } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { - if (DBG) log("DHCP failed"); - handleFailedIpConfiguration(); - transitionTo(mDisconnectingState); - } - break; - case CMD_DISCONNECT: - mWifiNative.disconnect(); - transitionTo(mDisconnectingState); - break; - case WifiP2pService.DISCONNECT_WIFI_REQUEST: - if (message.arg1 == 1) { - mWifiNative.disconnect(); - mTemporarilyDisconnectWifi = true; - transitionTo(mDisconnectingState); - } - break; - case CMD_SET_OPERATIONAL_MODE: - if (message.arg1 != CONNECT_MODE) { - sendMessage(CMD_DISCONNECT); - deferMessage(message); - } - break; - case CMD_START_SCAN: - /* Do not attempt to connect when we are already connected */ - noteScanStart(message.arg1, (WorkSource) message.obj); - startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); - break; - /* Ignore connection to same network */ - case WifiManager.CONNECT_NETWORK: - int netId = message.arg1; - if (mWifiInfo.getNetworkId() == netId) { - break; - } - return NOT_HANDLED; - case WifiManager.SAVE_NETWORK: - WifiConfiguration config = (WifiConfiguration) message.obj; - NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); - if (mWifiInfo.getNetworkId() == result.getNetworkId()) { - if (result.hasIpChanged()) { - log("Reconfiguring IP on connection"); - transitionTo(mObtainingIpState); - } - if (result.hasProxyChanged()) { - log("Reconfiguring proxy on connection"); - updateLinkProperties(); - } - } - - if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { - replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); - } else { - loge("Failed to save network"); - replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, - WifiManager.ERROR); - } - break; - /* Ignore */ - case WifiMonitor.NETWORK_CONNECTION_EVENT: - break; - case CMD_RSSI_POLL: - if (message.arg1 == mRssiPollToken) { - // Get Info and continue polling - fetchRssiAndLinkSpeedNative(); - sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, - mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); - } else { - // Polling has completed - } - break; - case CMD_ENABLE_RSSI_POLL: - mEnableRssiPolling = (message.arg1 == 1); - mRssiPollToken++; - if (mEnableRssiPolling) { - // first poll - fetchRssiAndLinkSpeedNative(); - sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, - mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); - } - break; - case WifiManager.RSSI_PKTCNT_FETCH: - RssiPacketCountInfo info = new RssiPacketCountInfo(); - fetchRssiAndLinkSpeedNative(); - info.rssi = mWifiInfo.getRssi(); - fetchPktcntNative(info); - replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); - break; - default: - return NOT_HANDLED; - } - - return HANDLED; - } - } - - class ObtainingIpState extends State { - @Override - public void enter() { - if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { - // TODO: If we're switching between static IP configuration and DHCP, remove the - // static configuration first. - startDhcp(); - } else { - // stop any running dhcp before assigning static IP - stopDhcp(); - DhcpResults dhcpResults = new DhcpResults( - mWifiConfigStore.getLinkProperties(mLastNetworkId)); - InterfaceConfiguration ifcg = new InterfaceConfiguration(); - Iterator addrs = - dhcpResults.linkProperties.getLinkAddresses().iterator(); - if (!addrs.hasNext()) { - loge("Static IP lacks address"); - sendMessage(CMD_STATIC_IP_FAILURE); - } else { - ifcg.setLinkAddress(addrs.next()); - ifcg.setInterfaceUp(); - try { - mNwService.setInterfaceConfig(mInterfaceName, ifcg); - if (DBG) log("Static IP configuration succeeded"); - sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); - } catch (RemoteException re) { - loge("Static IP configuration failed: " + re); - sendMessage(CMD_STATIC_IP_FAILURE); - } catch (IllegalStateException e) { - loge("Static IP configuration failed: " + e); - sendMessage(CMD_STATIC_IP_FAILURE); - } - } - } - } - @Override - public boolean processMessage(Message message) { - if (DBG) log(getName() + message.toString() + "\n"); - switch(message.what) { - case CMD_STATIC_IP_SUCCESS: - handleSuccessfulIpConfiguration((DhcpResults) message.obj); - transitionTo(mVerifyingLinkState); - break; - case CMD_STATIC_IP_FAILURE: - handleFailedIpConfiguration(); - transitionTo(mDisconnectingState); - break; - case WifiManager.SAVE_NETWORK: - deferMessage(message); - break; - /* Defer any power mode changes since we must keep active power mode at DHCP */ - case CMD_SET_HIGH_PERF_MODE: - deferMessage(message); - break; - /* Defer scan request since we should not switch to other channels at DHCP */ - case CMD_START_SCAN: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class VerifyingLinkState extends State { - @Override - public void enter() { - log(getName() + " enter"); - setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); - mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); - sendNetworkStateChangeBroadcast(mLastBssid); - } - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case WifiWatchdogStateMachine.POOR_LINK_DETECTED: - //stay here - log(getName() + " POOR_LINK_DETECTED: no transition"); - break; - case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: - log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); - // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve - // existing behaviour. The captive portal check really happens after we - // transition into DetailedState.CONNECTED. - setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); - mWifiConfigStore.updateStatus(mLastNetworkId, - DetailedState.CAPTIVE_PORTAL_CHECK); - sendNetworkStateChangeBroadcast(mLastBssid); - - // NOTE: This might look like an odd place to enable IPV6 but this is in - // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable - // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. - try { - mNwService.enableIpv6(mInterfaceName); - } catch (RemoteException re) { - loge("Failed to enable IPv6: " + re); - } catch (IllegalStateException e) { - loge("Failed to enable IPv6: " + e); - } - - log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); - setNetworkDetailedState(DetailedState.CONNECTED); - mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); - sendNetworkStateChangeBroadcast(mLastBssid); - transitionTo(mConnectedState); - - break; - default: - if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); - return NOT_HANDLED; - } - return HANDLED; - } - } - - class ConnectedState extends State { - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case WifiWatchdogStateMachine.POOR_LINK_DETECTED: - if (DBG) log("Watchdog reports poor link"); - try { - mNwService.disableIpv6(mInterfaceName); - } catch (RemoteException re) { - loge("Failed to disable IPv6: " + re); - } catch (IllegalStateException e) { - loge("Failed to disable IPv6: " + e); - } - /* Report a disconnect */ - setNetworkDetailedState(DetailedState.DISCONNECTED); - mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); - sendNetworkStateChangeBroadcast(mLastBssid); - - transitionTo(mVerifyingLinkState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - /* Request a CS wakelock during transition to mobile */ - checkAndSetConnectivityInstance(); - mCm.requestNetworkTransitionWakelock(getName()); - } - } - - class DisconnectingState extends State { - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case CMD_SET_OPERATIONAL_MODE: - if (message.arg1 != CONNECT_MODE) { - deferMessage(message); - } - break; - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT - * we have missed the network disconnection, transition to mDisconnectedState - * and handle the rest of the events there - */ - deferMessage(message); - handleNetworkDisconnect(); - transitionTo(mDisconnectedState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class DisconnectedState extends State { - private boolean mAlarmEnabled = false; - /* This is set from the overlay config file or from a secure setting. - * A value of 0 disables scanning in the framework. - */ - private long mFrameworkScanIntervalMs; - - private void setScanAlarm(boolean enabled) { - if (enabled == mAlarmEnabled) return; - if (enabled) { - if (mFrameworkScanIntervalMs > 0) { - mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, - System.currentTimeMillis() + mFrameworkScanIntervalMs, - mFrameworkScanIntervalMs, - mScanIntent); - mAlarmEnabled = true; - } - } else { - mAlarmManager.cancel(mScanIntent); - mAlarmEnabled = false; - } - } - - @Override - public void enter() { - // We dont scan frequently if this is a temporary disconnect - // due to p2p - if (mTemporarilyDisconnectWifi) { - mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE); - return; - } - - mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), - Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, - mDefaultFrameworkScanIntervalMs); - /* - * We initiate background scanning if it is enabled, otherwise we - * initiate an infrequent scan that wakes up the device to ensure - * a user connects to an access point on the move - */ - if (mEnableBackgroundScan) { - /* If a regular scan result is pending, do not initiate background - * scan until the scan results are returned. This is needed because - * initiating a background scan will cancel the regular scan and - * scan results will not be returned until background scanning is - * cleared - */ - if (!mScanResultIsPending) { - mWifiNative.enableBackgroundScan(true); - } - } else { - setScanAlarm(true); - } - - /** - * If we have no networks saved, the supplicant stops doing the periodic scan. - * The scans are useful to notify the user of the presence of an open network. - * Note that these are not wake up scans. - */ - if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { - sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, - ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); - } - } - @Override - public boolean processMessage(Message message) { - boolean ret = HANDLED; - switch (message.what) { - case CMD_NO_NETWORKS_PERIODIC_SCAN: - if (mP2pConnected.get()) break; - if (message.arg1 == mPeriodicScanToken && - mWifiConfigStore.getConfiguredNetworks().size() == 0) { - sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE, 0, (WorkSource) null); - sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, - ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); - } - break; - case WifiManager.FORGET_NETWORK: - case CMD_REMOVE_NETWORK: - // Set up a delayed message here. After the forget/remove is handled - // the handled delayed message will determine if there is a need to - // scan and continue - sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, - ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); - ret = NOT_HANDLED; - break; - case CMD_SET_OPERATIONAL_MODE: - if (message.arg1 != CONNECT_MODE) { - mOperationalMode = message.arg1; - - mWifiConfigStore.disableAllNetworks(); - if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { - mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); - setWifiState(WIFI_STATE_DISABLED); - } - - transitionTo(mScanModeState); - } - break; - case CMD_ENABLE_BACKGROUND_SCAN: - mEnableBackgroundScan = (message.arg1 == 1); - if (mEnableBackgroundScan) { - mWifiNative.enableBackgroundScan(true); - setScanAlarm(false); - } else { - mWifiNative.enableBackgroundScan(false); - setScanAlarm(true); - } - break; - /* Ignore network disconnect */ - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - break; - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - StateChangeResult stateChangeResult = (StateChangeResult) message.obj; - setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); - /* ConnectModeState does the rest of the handling */ - ret = NOT_HANDLED; - break; - case CMD_START_SCAN: - /* Disable background scan temporarily during a regular scan */ - if (mEnableBackgroundScan) { - mWifiNative.enableBackgroundScan(false); - } - /* Handled in parent state */ - ret = NOT_HANDLED; - break; - case WifiMonitor.SCAN_RESULTS_EVENT: - /* Re-enable background scan when a pending scan result is received */ - if (mEnableBackgroundScan && mScanResultIsPending) { - mWifiNative.enableBackgroundScan(true); - } - /* Handled in parent state */ - ret = NOT_HANDLED; - break; - case WifiP2pService.P2P_CONNECTION_CHANGED: - NetworkInfo info = (NetworkInfo) message.obj; - mP2pConnected.set(info.isConnected()); - if (mP2pConnected.get()) { - int defaultInterval = mContext.getResources().getInteger( - R.integer.config_wifi_scan_interval_p2p_connected); - long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), - Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, - defaultInterval); - mWifiNative.setScanInterval((int) scanIntervalMs/1000); - } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { - if (DBG) log("Turn on scanning after p2p disconnected"); - sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, - ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); - } - case CMD_RECONNECT: - case CMD_REASSOCIATE: - if (mTemporarilyDisconnectWifi) { - // Drop a third party reconnect/reassociate if STA is - // temporarily disconnected for p2p - break; - } else { - // ConnectModeState handles it - ret = NOT_HANDLED; - } - break; - default: - ret = NOT_HANDLED; - } - return ret; - } - - @Override - public void exit() { - /* No need for a background scan upon exit from a disconnected state */ - if (mEnableBackgroundScan) { - mWifiNative.enableBackgroundScan(false); - } - setScanAlarm(false); - } - } - - class WpsRunningState extends State { - //Tracks the source to provide a reply - private Message mSourceMessage; - @Override - public void enter() { - mSourceMessage = Message.obtain(getCurrentMessage()); - } - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case WifiMonitor.WPS_SUCCESS_EVENT: - // Ignore intermediate success, wait for full connection - break; - case WifiMonitor.NETWORK_CONNECTION_EVENT: - replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); - mSourceMessage.recycle(); - mSourceMessage = null; - deferMessage(message); - transitionTo(mDisconnectedState); - break; - case WifiMonitor.WPS_OVERLAP_EVENT: - replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, - WifiManager.WPS_OVERLAP_ERROR); - mSourceMessage.recycle(); - mSourceMessage = null; - transitionTo(mDisconnectedState); - break; - case WifiMonitor.WPS_FAIL_EVENT: - //arg1 has the reason for the failure - replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); - mSourceMessage.recycle(); - mSourceMessage = null; - transitionTo(mDisconnectedState); - break; - case WifiMonitor.WPS_TIMEOUT_EVENT: - replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, - WifiManager.WPS_TIMED_OUT); - mSourceMessage.recycle(); - mSourceMessage = null; - transitionTo(mDisconnectedState); - break; - case WifiManager.START_WPS: - replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); - break; - case WifiManager.CANCEL_WPS: - if (mWifiNative.cancelWps()) { - replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); - } else { - replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); - } - transitionTo(mDisconnectedState); - break; - /* Defer all commands that can cause connections to a different network - * or put the state machine out of connect mode - */ - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case WifiManager.CONNECT_NETWORK: - case CMD_ENABLE_NETWORK: - case CMD_RECONNECT: - case CMD_REASSOCIATE: - deferMessage(message); - break; - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - if (DBG) log("Network connection lost"); - handleNetworkDisconnect(); - break; - case WifiMonitor.ASSOCIATION_REJECTION_EVENT: - if (DBG) log("Ignore Assoc reject event during WPS Connection"); - break; - case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: - // Disregard auth failure events during WPS connection. The - // EAP sequence is retried several times, and there might be - // failures (especially for wps pin). We will get a WPS_XXX - // event at the end of the sequence anyway. - if (DBG) log("Ignore auth failure during WPS connection"); - break; - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - //Throw away supplicant state changes when WPS is running. - //We will start getting supplicant state changes once we get - //a WPS success or failure - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - mWifiConfigStore.enableAllNetworks(); - mWifiConfigStore.loadConfiguredNetworks(); - } - } - - class SoftApStartingState extends State { - @Override - public void enter() { - final Message message = getCurrentMessage(); - if (message.what == CMD_START_AP) { - final WifiConfiguration config = (WifiConfiguration) message.obj; - - if (config == null) { - mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); - } else { - mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); - startSoftApWithConfig(config); - } - } else { - throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); - } - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - case CMD_TETHER_STATE_CHANGE: - deferMessage(message); - break; - case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: - WifiConfiguration config = (WifiConfiguration) message.obj; - if (config != null) { - startSoftApWithConfig(config); - } else { - loge("Softap config is null!"); - sendMessage(CMD_START_AP_FAILURE); - } - break; - case CMD_START_AP_SUCCESS: - setWifiApState(WIFI_AP_STATE_ENABLED); - transitionTo(mSoftApStartedState); - break; - case CMD_START_AP_FAILURE: - setWifiApState(WIFI_AP_STATE_FAILED); - transitionTo(mInitialState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class SoftApStartedState extends State { - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_STOP_AP: - if (DBG) log("Stopping Soft AP"); - /* We have not tethered at this point, so we just shutdown soft Ap */ - try { - mNwService.stopAccessPoint(mInterfaceName); - } catch(Exception e) { - loge("Exception in stopAccessPoint()"); - } - setWifiApState(WIFI_AP_STATE_DISABLED); - transitionTo(mInitialState); - break; - case CMD_START_AP: - // Ignore a start on a running access point - break; - /* Fail client mode operation when soft AP is enabled */ - case CMD_START_SUPPLICANT: - loge("Cannot start supplicant with a running soft AP"); - setWifiState(WIFI_STATE_UNKNOWN); - break; - case CMD_TETHER_STATE_CHANGE: - TetherStateChange stateChange = (TetherStateChange) message.obj; - if (startTethering(stateChange.available)) { - transitionTo(mTetheringState); - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class TetheringState extends State { - @Override - public void enter() { - /* Send ourselves a delayed message to shut down if tethering fails to notify */ - sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, - ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_TETHER_STATE_CHANGE: - TetherStateChange stateChange = (TetherStateChange) message.obj; - if (isWifiTethered(stateChange.active)) { - transitionTo(mTetheredState); - } - return HANDLED; - case CMD_TETHER_NOTIFICATION_TIMED_OUT: - if (message.arg1 == mTetherToken) { - loge("Failed to get tether update, shutdown soft access point"); - transitionTo(mSoftApStartedState); - // Needs to be first thing handled - sendMessageAtFrontOfQueue(CMD_STOP_AP); - } - break; - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class TetheredState extends State { - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_TETHER_STATE_CHANGE: - TetherStateChange stateChange = (TetherStateChange) message.obj; - if (!isWifiTethered(stateChange.active)) { - loge("Tethering reports wifi as untethered!, shut down soft Ap"); - setHostApRunning(null, false); - setHostApRunning(null, true); - } - return HANDLED; - case CMD_STOP_AP: - if (DBG) log("Untethering before stopping AP"); - setWifiApState(WIFI_AP_STATE_DISABLING); - stopTethering(); - transitionTo(mUntetheringState); - // More work to do after untethering - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class UntetheringState extends State { - @Override - public void enter() { - /* Send ourselves a delayed message to shut down if tethering fails to notify */ - sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, - ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); - - } - @Override - public boolean processMessage(Message message) { - switch(message.what) { - case CMD_TETHER_STATE_CHANGE: - TetherStateChange stateChange = (TetherStateChange) message.obj; - - /* Wait till wifi is untethered */ - if (isWifiTethered(stateChange.active)) break; - - transitionTo(mSoftApStartedState); - break; - case CMD_TETHER_NOTIFICATION_TIMED_OUT: - if (message.arg1 == mTetherToken) { - loge("Failed to get tether update, force stop access point"); - transitionTo(mSoftApStartedState); - } - break; - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - //State machine initiated requests can have replyTo set to null indicating - //there are no recepients, we ignore those reply actions - private void replyToMessage(Message msg, int what) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessageWithArg2(msg); - dstMsg.what = what; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - private void replyToMessage(Message msg, int what, int arg1) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessageWithArg2(msg); - dstMsg.what = what; - dstMsg.arg1 = arg1; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - private void replyToMessage(Message msg, int what, Object obj) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessageWithArg2(msg); - dstMsg.what = what; - dstMsg.obj = obj; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - /** - * arg2 on the source message has a unique id that needs to be retained in replies - * to match the request - - * see WifiManager for details - */ - private Message obtainMessageWithArg2(Message srcMsg) { - Message msg = Message.obtain(); - msg.arg2 = srcMsg.arg2; - return msg; - } -} diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java deleted file mode 100644 index c2823e8..0000000 --- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * Copyright (C) 2011 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 android.net.wifi; - -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.database.ContentObserver; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.NetworkInfo; -import android.net.wifi.RssiPacketCountInfo; -import android.os.Message; -import android.os.SystemClock; -import android.provider.Settings; -import android.util.LruCache; - -import com.android.internal.util.AsyncChannel; -import com.android.internal.util.Protocol; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.text.DecimalFormat; - -/** - * WifiWatchdogStateMachine monitors the connection to a WiFi network. When WiFi - * connects at L2 layer, the beacons from access point reach the device and it - * can maintain a connection, but the application connectivity can be flaky (due - * to bigger packet size exchange). - *

- * We now monitor the quality of the last hop on WiFi using packet loss ratio as - * an indicator to decide if the link is good enough to switch to Wi-Fi as the - * uplink. - *

- * When WiFi is connected, the WiFi watchdog keeps sampling the RSSI and the - * instant packet loss, and record it as per-AP loss-to-rssi statistics. When - * the instant packet loss is higher than a threshold, the WiFi watchdog sends a - * poor link notification to avoid WiFi connection temporarily. - *

- * While WiFi is being avoided, the WiFi watchdog keep watching the RSSI to - * bring the WiFi connection back. Once the RSSI is high enough to achieve a - * lower packet loss, a good link detection is sent such that the WiFi - * connection become available again. - *

- * BSSID roaming has been taken into account. When user is moving across - * multiple APs, the WiFi watchdog will detect that and keep watching the - * currently connected AP. - *

- * Power impact should be minimal since much of the measurement relies on - * passive statistics already being tracked at the driver and the polling is - * done when screen is turned on and the RSSI is in a certain range. - * - * @hide - */ -public class WifiWatchdogStateMachine extends StateMachine { - - private static final boolean DBG = false; - - private static final int BASE = Protocol.BASE_WIFI_WATCHDOG; - - /* Internal events */ - private static final int EVENT_WATCHDOG_TOGGLED = BASE + 1; - private static final int EVENT_NETWORK_STATE_CHANGE = BASE + 2; - private static final int EVENT_RSSI_CHANGE = BASE + 3; - private static final int EVENT_SUPPLICANT_STATE_CHANGE = BASE + 4; - private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5; - private static final int EVENT_WATCHDOG_SETTINGS_CHANGE = BASE + 6; - private static final int EVENT_BSSID_CHANGE = BASE + 7; - private static final int EVENT_SCREEN_ON = BASE + 8; - private static final int EVENT_SCREEN_OFF = BASE + 9; - - /* Internal messages */ - private static final int CMD_RSSI_FETCH = BASE + 11; - - /* Notifications from/to WifiStateMachine */ - static final int POOR_LINK_DETECTED = BASE + 21; - static final int GOOD_LINK_DETECTED = BASE + 22; - - public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false; - - /* - * RSSI levels as used by notification icon - * Level 4 -55 <= RSSI - * Level 3 -66 <= RSSI < -55 - * Level 2 -77 <= RSSI < -67 - * Level 1 -88 <= RSSI < -78 - * Level 0 RSSI < -88 - */ - - /** - * WiFi link statistics is monitored and recorded actively below this threshold. - *

- * Larger threshold is more adaptive but increases sampling cost. - */ - private static final int LINK_MONITOR_LEVEL_THRESHOLD = WifiManager.RSSI_LEVELS - 1; - - /** - * Remember packet loss statistics of how many BSSIDs. - *

- * Larger size is usually better but requires more space. - */ - private static final int BSSID_STAT_CACHE_SIZE = 20; - - /** - * RSSI range of a BSSID statistics. - * Within the range, (RSSI -> packet loss %) mappings are stored. - *

- * Larger range is usually better but requires more space. - */ - private static final int BSSID_STAT_RANGE_LOW_DBM = -105; - - /** - * See {@link #BSSID_STAT_RANGE_LOW_DBM}. - */ - private static final int BSSID_STAT_RANGE_HIGH_DBM = -45; - - /** - * How many consecutive empty data point to trigger a empty-cache detection. - * In this case, a preset/default loss value (function on RSSI) is used. - *

- * In normal uses, some RSSI values may never be seen due to channel randomness. - * However, the size of such empty RSSI chunk in normal use is generally 1~2. - */ - private static final int BSSID_STAT_EMPTY_COUNT = 3; - - /** - * Sample interval for packet loss statistics, in msec. - *

- * Smaller interval is more accurate but increases sampling cost (battery consumption). - */ - private static final long LINK_SAMPLING_INTERVAL_MS = 1 * 1000; - - /** - * Coefficients (alpha) for moving average for packet loss tracking. - * Must be within (0.0, 1.0). - *

- * Equivalent number of samples: N = 2 / alpha - 1 . - * We want the historic loss to base on more data points to be statistically reliable. - * We want the current instant loss to base on less data points to be responsive. - */ - private static final double EXP_COEFFICIENT_RECORD = 0.1; - - /** - * See {@link #EXP_COEFFICIENT_RECORD}. - */ - private static final double EXP_COEFFICIENT_MONITOR = 0.5; - - /** - * Thresholds for sending good/poor link notifications, in packet loss %. - * Good threshold must be smaller than poor threshold. - * Use smaller poor threshold to avoid WiFi more aggressively. - * Use smaller good threshold to bring back WiFi more conservatively. - *

- * When approaching the boundary, loss ratio jumps significantly within a few dBs. - * 50% loss threshold is a good balance between accuracy and reponsiveness. - * <=10% good threshold is a safe value to avoid jumping back to WiFi too easily. - */ - private static final double POOR_LINK_LOSS_THRESHOLD = 0.5; - - /** - * See {@link #POOR_LINK_LOSS_THRESHOLD}. - */ - private static final double GOOD_LINK_LOSS_THRESHOLD = 0.1; - - /** - * Number of samples to confirm before sending a poor link notification. - * Response time = confirm_count * sample_interval . - *

- * A smaller threshold improves response speed but may suffer from randomness. - * According to experiments, 3~5 are good values to achieve a balance. - * These parameters should be tuned along with {@link #LINK_SAMPLING_INTERVAL_MS}. - */ - private static final int POOR_LINK_SAMPLE_COUNT = 3; - - /** - * Minimum volume (converted from pkt/sec) to detect a poor link, to avoid randomness. - *

- * According to experiments, 1pkt/sec is too sensitive but 3pkt/sec is slightly unresponsive. - */ - private static final double POOR_LINK_MIN_VOLUME = 2.0 * LINK_SAMPLING_INTERVAL_MS / 1000.0; - - /** - * When a poor link is detected, we scan over this range (based on current - * poor link RSSI) for a target RSSI that satisfies a target packet loss. - * Refer to {@link #GOOD_LINK_TARGET}. - *

- * We want range_min not too small to avoid jumping back to WiFi too easily. - */ - private static final int GOOD_LINK_RSSI_RANGE_MIN = 3; - - /** - * See {@link #GOOD_LINK_RSSI_RANGE_MIN}. - */ - private static final int GOOD_LINK_RSSI_RANGE_MAX = 20; - - /** - * Adaptive good link target to avoid flapping. - * When a poor link is detected, a good link target is calculated as follows: - *

- * targetRSSI = min { rssi | loss(rssi) < GOOD_LINK_LOSS_THRESHOLD } + rssi_adj[i], - * where rssi is within the above GOOD_LINK_RSSI_RANGE. - * targetCount = sample_count[i] . - *

- * While WiFi is being avoided, we keep monitoring its signal strength. - * Good link notification is sent when we see current RSSI >= targetRSSI - * for targetCount consecutive times. - *

- * Index i is incremented each time after a poor link detection. - * Index i is decreased to at most k if the last poor link was at lease reduce_time[k] ago. - *

- * Intuitively, larger index i makes it more difficult to get back to WiFi, avoiding flapping. - * In experiments, (+9 dB / 30 counts) makes it quite difficult to achieve. - * Avoid using it unless flapping is really bad (say, last poor link is < 1 min ago). - */ - private static final GoodLinkTarget[] GOOD_LINK_TARGET = { - /* rssi_adj, sample_count, reduce_time */ - new GoodLinkTarget( 0, 3, 30 * 60000 ), - new GoodLinkTarget( 3, 5, 5 * 60000 ), - new GoodLinkTarget( 6, 10, 1 * 60000 ), - new GoodLinkTarget( 9, 30, 0 * 60000 ), - }; - - /** - * The max time to avoid a BSSID, to prevent avoiding forever. - * If current RSSI is at least min_rssi[i], the max avoidance time is at most max_time[i] - *

- * It is unusual to experience high packet loss at high RSSI. Something unusual must be - * happening (e.g. strong interference). For higher signal strengths, we set the avoidance - * time to be low to allow for quick turn around from temporary interference. - *

- * See {@link BssidStatistics#poorLinkDetected}. - */ - private static final MaxAvoidTime[] MAX_AVOID_TIME = { - /* max_time, min_rssi */ - new MaxAvoidTime( 30 * 60000, -200 ), - new MaxAvoidTime( 5 * 60000, -70 ), - new MaxAvoidTime( 0 * 60000, -55 ), - }; - - /* Framework related */ - private Context mContext; - private ContentResolver mContentResolver; - private WifiManager mWifiManager; - private IntentFilter mIntentFilter; - private BroadcastReceiver mBroadcastReceiver; - private AsyncChannel mWsmChannel = new AsyncChannel(); - private WifiInfo mWifiInfo; - private LinkProperties mLinkProperties; - - /* System settingss related */ - private static boolean sWifiOnly = false; - private boolean mPoorNetworkDetectionEnabled; - - /* Poor link detection related */ - private LruCache mBssidCache = - new LruCache(BSSID_STAT_CACHE_SIZE); - private int mRssiFetchToken = 0; - private int mCurrentSignalLevel; - private BssidStatistics mCurrentBssid; - private VolumeWeightedEMA mCurrentLoss; - private boolean mIsScreenOn = true; - private static double sPresetLoss[]; - - /* WiFi watchdog state machine related */ - private DefaultState mDefaultState = new DefaultState(); - private WatchdogDisabledState mWatchdogDisabledState = new WatchdogDisabledState(); - private WatchdogEnabledState mWatchdogEnabledState = new WatchdogEnabledState(); - private NotConnectedState mNotConnectedState = new NotConnectedState(); - private VerifyingLinkState mVerifyingLinkState = new VerifyingLinkState(); - private ConnectedState mConnectedState = new ConnectedState(); - private OnlineWatchState mOnlineWatchState = new OnlineWatchState(); - private LinkMonitoringState mLinkMonitoringState = new LinkMonitoringState(); - private OnlineState mOnlineState = new OnlineState(); - - /** - * STATE MAP - * Default - * / \ - * Disabled Enabled - * / \ \ - * NotConnected Verifying Connected - * /---------\ - * (all other states) - */ - private WifiWatchdogStateMachine(Context context) { - super("WifiWatchdogStateMachine"); - mContext = context; - mContentResolver = context.getContentResolver(); - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - mWsmChannel.connectSync(mContext, getHandler(), - mWifiManager.getWifiStateMachineMessenger()); - - setupNetworkReceiver(); - - // the content observer to listen needs a handler - registerForSettingsChanges(); - registerForWatchdogToggle(); - addState(mDefaultState); - addState(mWatchdogDisabledState, mDefaultState); - addState(mWatchdogEnabledState, mDefaultState); - addState(mNotConnectedState, mWatchdogEnabledState); - addState(mVerifyingLinkState, mWatchdogEnabledState); - addState(mConnectedState, mWatchdogEnabledState); - addState(mOnlineWatchState, mConnectedState); - addState(mLinkMonitoringState, mConnectedState); - addState(mOnlineState, mConnectedState); - - if (isWatchdogEnabled()) { - setInitialState(mNotConnectedState); - } else { - setInitialState(mWatchdogDisabledState); - } - setLogRecSize(25); - setLogOnlyTransitions(true); - updateSettings(); - } - - public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) { - ContentResolver contentResolver = context.getContentResolver(); - - ConnectivityManager cm = (ConnectivityManager) context.getSystemService( - Context.CONNECTIVITY_SERVICE); - sWifiOnly = (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false); - - // Watchdog is always enabled. Poor network detection can be seperately turned on/off - // TODO: Remove this setting & clean up state machine since we always have - // watchdog in an enabled state - putSettingsGlobalBoolean(contentResolver, Settings.Global.WIFI_WATCHDOG_ON, true); - - WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context); - wwsm.start(); - return wwsm; - } - - private void setupNetworkReceiver() { - mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { - obtainMessage(EVENT_RSSI_CHANGE, - intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200), 0).sendToTarget(); - } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { - sendMessage(EVENT_SUPPLICANT_STATE_CHANGE, intent); - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - sendMessage(EVENT_NETWORK_STATE_CHANGE, intent); - } else if (action.equals(Intent.ACTION_SCREEN_ON)) { - sendMessage(EVENT_SCREEN_ON); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - sendMessage(EVENT_SCREEN_OFF); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - sendMessage(EVENT_WIFI_RADIO_STATE_CHANGE,intent.getIntExtra( - WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)); - } - } - }; - - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mIntentFilter.addAction(Intent.ACTION_SCREEN_ON); - mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF); - mContext.registerReceiver(mBroadcastReceiver, mIntentFilter); - } - - /** - * Observes the watchdog on/off setting, and takes action when changed. - */ - private void registerForWatchdogToggle() { - ContentObserver contentObserver = new ContentObserver(this.getHandler()) { - @Override - public void onChange(boolean selfChange) { - sendMessage(EVENT_WATCHDOG_TOGGLED); - } - }; - - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.WIFI_WATCHDOG_ON), - false, contentObserver); - } - - /** - * Observes watchdogs secure setting changes. - */ - private void registerForSettingsChanges() { - ContentObserver contentObserver = new ContentObserver(this.getHandler()) { - @Override - public void onChange(boolean selfChange) { - sendMessage(EVENT_WATCHDOG_SETTINGS_CHANGE); - } - }; - - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED), - false, contentObserver); - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); - pw.println("mWifiInfo: [" + mWifiInfo + "]"); - pw.println("mLinkProperties: [" + mLinkProperties + "]"); - pw.println("mCurrentSignalLevel: [" + mCurrentSignalLevel + "]"); - pw.println("mPoorNetworkDetectionEnabled: [" + mPoorNetworkDetectionEnabled + "]"); - } - - private boolean isWatchdogEnabled() { - boolean ret = getSettingsGlobalBoolean( - mContentResolver, Settings.Global.WIFI_WATCHDOG_ON, true); - if (DBG) logd("Watchdog enabled " + ret); - return ret; - } - - private void updateSettings() { - if (DBG) logd("Updating secure settings"); - - // disable poor network avoidance - if (sWifiOnly) { - logd("Disabling poor network avoidance for wi-fi only device"); - mPoorNetworkDetectionEnabled = false; - } else { - mPoorNetworkDetectionEnabled = getSettingsGlobalBoolean(mContentResolver, - Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, - DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED); - } - } - - /** - * Default state, guard for unhandled messages. - */ - class DefaultState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_WATCHDOG_SETTINGS_CHANGE: - updateSettings(); - if (DBG) logd("Updating wifi-watchdog secure settings"); - break; - case EVENT_RSSI_CHANGE: - mCurrentSignalLevel = calculateSignalLevel(msg.arg1); - break; - case EVENT_WIFI_RADIO_STATE_CHANGE: - case EVENT_NETWORK_STATE_CHANGE: - case EVENT_SUPPLICANT_STATE_CHANGE: - case EVENT_BSSID_CHANGE: - case CMD_RSSI_FETCH: - case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: - case WifiManager.RSSI_PKTCNT_FETCH_FAILED: - // ignore - break; - case EVENT_SCREEN_ON: - mIsScreenOn = true; - break; - case EVENT_SCREEN_OFF: - mIsScreenOn = false; - break; - default: - loge("Unhandled message " + msg + " in state " + getCurrentState().getName()); - break; - } - return HANDLED; - } - } - - /** - * WiFi watchdog is disabled by the setting. - */ - class WatchdogDisabledState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_WATCHDOG_TOGGLED: - if (isWatchdogEnabled()) - transitionTo(mNotConnectedState); - return HANDLED; - case EVENT_NETWORK_STATE_CHANGE: - Intent intent = (Intent) msg.obj; - NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - - switch (networkInfo.getDetailedState()) { - case VERIFYING_POOR_LINK: - if (DBG) logd("Watchdog disabled, verify link"); - sendLinkStatusNotification(true); - break; - default: - break; - } - break; - } - return NOT_HANDLED; - } - } - - /** - * WiFi watchdog is enabled by the setting. - */ - class WatchdogEnabledState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message msg) { - Intent intent; - switch (msg.what) { - case EVENT_WATCHDOG_TOGGLED: - if (!isWatchdogEnabled()) - transitionTo(mWatchdogDisabledState); - break; - - case EVENT_NETWORK_STATE_CHANGE: - intent = (Intent) msg.obj; - NetworkInfo networkInfo = - (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - if (DBG) logd("Network state change " + networkInfo.getDetailedState()); - - mWifiInfo = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); - updateCurrentBssid(mWifiInfo != null ? mWifiInfo.getBSSID() : null); - - switch (networkInfo.getDetailedState()) { - case VERIFYING_POOR_LINK: - mLinkProperties = (LinkProperties) intent.getParcelableExtra( - WifiManager.EXTRA_LINK_PROPERTIES); - if (mPoorNetworkDetectionEnabled) { - if (mWifiInfo == null || mCurrentBssid == null) { - loge("Ignore, wifiinfo " + mWifiInfo +" bssid " + mCurrentBssid); - sendLinkStatusNotification(true); - } else { - transitionTo(mVerifyingLinkState); - } - } else { - sendLinkStatusNotification(true); - } - break; - case CONNECTED: - transitionTo(mOnlineWatchState); - break; - default: - transitionTo(mNotConnectedState); - break; - } - break; - - case EVENT_SUPPLICANT_STATE_CHANGE: - intent = (Intent) msg.obj; - SupplicantState supplicantState = (SupplicantState) intent.getParcelableExtra( - WifiManager.EXTRA_NEW_STATE); - if (supplicantState == SupplicantState.COMPLETED) { - mWifiInfo = mWifiManager.getConnectionInfo(); - updateCurrentBssid(mWifiInfo.getBSSID()); - } - break; - - case EVENT_WIFI_RADIO_STATE_CHANGE: - if (msg.arg1 == WifiManager.WIFI_STATE_DISABLING) { - transitionTo(mNotConnectedState); - } - break; - - default: - return NOT_HANDLED; - } - - return HANDLED; - } - } - - /** - * WiFi is disconnected. - */ - class NotConnectedState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - } - - /** - * WiFi is connected, but waiting for good link detection message. - */ - class VerifyingLinkState extends State { - - private int mSampleCount; - - @Override - public void enter() { - if (DBG) logd(getName()); - mSampleCount = 0; - mCurrentBssid.newLinkDetected(); - sendMessage(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0)); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_WATCHDOG_SETTINGS_CHANGE: - updateSettings(); - if (!mPoorNetworkDetectionEnabled) { - sendLinkStatusNotification(true); - } - break; - - case EVENT_BSSID_CHANGE: - transitionTo(mVerifyingLinkState); - break; - - case CMD_RSSI_FETCH: - if (msg.arg1 == mRssiFetchToken) { - mWsmChannel.sendMessage(WifiManager.RSSI_PKTCNT_FETCH); - sendMessageDelayed(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0), - LINK_SAMPLING_INTERVAL_MS); - } - break; - - case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: - RssiPacketCountInfo info = (RssiPacketCountInfo) msg.obj; - int rssi = info.rssi; - if (DBG) logd("Fetch RSSI succeed, rssi=" + rssi); - - long time = mCurrentBssid.mBssidAvoidTimeMax - SystemClock.elapsedRealtime(); - if (time <= 0) { - // max avoidance time is met - if (DBG) logd("Max avoid time elapsed"); - sendLinkStatusNotification(true); - } else { - if (rssi >= mCurrentBssid.mGoodLinkTargetRssi) { - if (++mSampleCount >= mCurrentBssid.mGoodLinkTargetCount) { - // link is good again - if (DBG) logd("Good link detected, rssi=" + rssi); - mCurrentBssid.mBssidAvoidTimeMax = 0; - sendLinkStatusNotification(true); - } - } else { - mSampleCount = 0; - if (DBG) logd("Link is still poor, time left=" + time); - } - } - break; - - case WifiManager.RSSI_PKTCNT_FETCH_FAILED: - if (DBG) logd("RSSI_FETCH_FAILED"); - break; - - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - /** - * WiFi is connected and link is verified. - */ - class ConnectedState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_WATCHDOG_SETTINGS_CHANGE: - updateSettings(); - if (mPoorNetworkDetectionEnabled) { - transitionTo(mOnlineWatchState); - } else { - transitionTo(mOnlineState); - } - return HANDLED; - } - return NOT_HANDLED; - } - } - - /** - * RSSI is high enough and don't need link monitoring. - */ - class OnlineWatchState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - if (mPoorNetworkDetectionEnabled) { - // treat entry as an rssi change - handleRssiChange(); - } else { - transitionTo(mOnlineState); - } - } - - private void handleRssiChange() { - if (mCurrentSignalLevel <= LINK_MONITOR_LEVEL_THRESHOLD && mCurrentBssid != null) { - transitionTo(mLinkMonitoringState); - } else { - // stay here - } - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_RSSI_CHANGE: - mCurrentSignalLevel = calculateSignalLevel(msg.arg1); - handleRssiChange(); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - /** - * Keep sampling the link and monitor any poor link situation. - */ - class LinkMonitoringState extends State { - - private int mSampleCount; - - private int mLastRssi; - private int mLastTxGood; - private int mLastTxBad; - - @Override - public void enter() { - if (DBG) logd(getName()); - mSampleCount = 0; - mCurrentLoss = new VolumeWeightedEMA(EXP_COEFFICIENT_MONITOR); - sendMessage(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0)); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_RSSI_CHANGE: - mCurrentSignalLevel = calculateSignalLevel(msg.arg1); - if (mCurrentSignalLevel <= LINK_MONITOR_LEVEL_THRESHOLD) { - // stay here; - } else { - // we don't need frequent RSSI monitoring any more - transitionTo(mOnlineWatchState); - } - break; - - case EVENT_BSSID_CHANGE: - transitionTo(mLinkMonitoringState); - break; - - case CMD_RSSI_FETCH: - if (!mIsScreenOn) { - transitionTo(mOnlineState); - } else if (msg.arg1 == mRssiFetchToken) { - mWsmChannel.sendMessage(WifiManager.RSSI_PKTCNT_FETCH); - sendMessageDelayed(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0), - LINK_SAMPLING_INTERVAL_MS); - } - break; - - case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: - RssiPacketCountInfo info = (RssiPacketCountInfo) msg.obj; - int rssi = info.rssi; - int mrssi = (mLastRssi + rssi) / 2; - int txbad = info.txbad; - int txgood = info.txgood; - if (DBG) logd("Fetch RSSI succeed, rssi=" + rssi + " mrssi=" + mrssi + " txbad=" - + txbad + " txgood=" + txgood); - - // skip the first data point as we want incremental values - long now = SystemClock.elapsedRealtime(); - if (now - mCurrentBssid.mLastTimeSample < LINK_SAMPLING_INTERVAL_MS * 2) { - - // update packet loss statistics - int dbad = txbad - mLastTxBad; - int dgood = txgood - mLastTxGood; - int dtotal = dbad + dgood; - - if (dtotal > 0) { - // calculate packet loss in the last sampling interval - double loss = ((double) dbad) / ((double) dtotal); - - mCurrentLoss.update(loss, dtotal); - - if (DBG) { - DecimalFormat df = new DecimalFormat("#.##"); - logd("Incremental loss=" + dbad + "/" + dtotal + " Current loss=" - + df.format(mCurrentLoss.mValue * 100) + "% volume=" - + df.format(mCurrentLoss.mVolume)); - } - - mCurrentBssid.updateLoss(mrssi, loss, dtotal); - - // check for high packet loss and send poor link notification - if (mCurrentLoss.mValue > POOR_LINK_LOSS_THRESHOLD - && mCurrentLoss.mVolume > POOR_LINK_MIN_VOLUME) { - if (++mSampleCount >= POOR_LINK_SAMPLE_COUNT) - if (mCurrentBssid.poorLinkDetected(rssi)) { - sendLinkStatusNotification(false); - ++mRssiFetchToken; - } - } else { - mSampleCount = 0; - } - } - } - - mCurrentBssid.mLastTimeSample = now; - mLastTxBad = txbad; - mLastTxGood = txgood; - mLastRssi = rssi; - break; - - case WifiManager.RSSI_PKTCNT_FETCH_FAILED: - // can happen if we are waiting to get a disconnect notification - if (DBG) logd("RSSI_FETCH_FAILED"); - break; - - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - /** - * Child state of ConnectedState indicating that we are online and there is nothing to do. - */ - class OnlineState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_SCREEN_ON: - mIsScreenOn = true; - if (mPoorNetworkDetectionEnabled) - transitionTo(mOnlineWatchState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - private void updateCurrentBssid(String bssid) { - if (DBG) logd("Update current BSSID to " + (bssid != null ? bssid : "null")); - - // if currently not connected, then set current BSSID to null - if (bssid == null) { - if (mCurrentBssid == null) return; - mCurrentBssid = null; - if (DBG) logd("BSSID changed"); - sendMessage(EVENT_BSSID_CHANGE); - return; - } - - // if it is already the current BSSID, then done - if (mCurrentBssid != null && bssid.equals(mCurrentBssid.mBssid)) return; - - // search for the new BSSID in the cache, add to cache if not found - mCurrentBssid = mBssidCache.get(bssid); - if (mCurrentBssid == null) { - mCurrentBssid = new BssidStatistics(bssid); - mBssidCache.put(bssid, mCurrentBssid); - } - - // send BSSID change notification - if (DBG) logd("BSSID changed"); - sendMessage(EVENT_BSSID_CHANGE); - } - - private int calculateSignalLevel(int rssi) { - int signalLevel = WifiManager.calculateSignalLevel(rssi, WifiManager.RSSI_LEVELS); - if (DBG) - logd("RSSI current: " + mCurrentSignalLevel + " new: " + rssi + ", " + signalLevel); - return signalLevel; - } - - private void sendLinkStatusNotification(boolean isGood) { - if (DBG) logd("########################################"); - if (isGood) { - mWsmChannel.sendMessage(GOOD_LINK_DETECTED); - if (mCurrentBssid != null) { - mCurrentBssid.mLastTimeGood = SystemClock.elapsedRealtime(); - } - if (DBG) logd("Good link notification is sent"); - } else { - mWsmChannel.sendMessage(POOR_LINK_DETECTED); - if (mCurrentBssid != null) { - mCurrentBssid.mLastTimePoor = SystemClock.elapsedRealtime(); - } - logd("Poor link notification is sent"); - } - } - - /** - * Convenience function for retrieving a single secure settings value as a - * boolean. Note that internally setting values are always stored as - * strings; this function converts the string to a boolean for you. The - * default value will be returned if the setting is not defined or not a - * valid boolean. - * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. - * @param def Value to return if the setting is not defined. - * @return The setting's current value, or 'def' if it is not defined or not - * a valid boolean. - */ - private static boolean getSettingsGlobalBoolean(ContentResolver cr, String name, boolean def) { - return Settings.Global.getInt(cr, name, def ? 1 : 0) == 1; - } - - /** - * Convenience function for updating a single settings value as an integer. - * This will either create a new entry in the table if the given name does - * not exist, or modify the value of the existing row with that name. Note - * that internally setting values are always stored as strings, so this - * function converts the given value to a string before storing it. - * - * @param cr The ContentResolver to access. - * @param name The name of the setting to modify. - * @param value The new value for the setting. - * @return true if the value was set, false on database errors - */ - private static boolean putSettingsGlobalBoolean(ContentResolver cr, String name, boolean value) { - return Settings.Global.putInt(cr, name, value ? 1 : 0); - } - - /** - * Bundle of good link count parameters - */ - private static class GoodLinkTarget { - public final int RSSI_ADJ_DBM; - public final int SAMPLE_COUNT; - public final int REDUCE_TIME_MS; - public GoodLinkTarget(int adj, int count, int time) { - RSSI_ADJ_DBM = adj; - SAMPLE_COUNT = count; - REDUCE_TIME_MS = time; - } - } - - /** - * Bundle of max avoidance time parameters - */ - private static class MaxAvoidTime { - public final int TIME_MS; - public final int MIN_RSSI_DBM; - public MaxAvoidTime(int time, int rssi) { - TIME_MS = time; - MIN_RSSI_DBM = rssi; - } - } - - /** - * Volume-weighted Exponential Moving Average (V-EMA) - * - volume-weighted: each update has its own weight (number of packets) - * - exponential: O(1) time and O(1) space for both update and query - * - moving average: reflect most recent results and expire old ones - */ - private class VolumeWeightedEMA { - private double mValue; - private double mVolume; - private double mProduct; - private final double mAlpha; - - public VolumeWeightedEMA(double coefficient) { - mValue = 0.0; - mVolume = 0.0; - mProduct = 0.0; - mAlpha = coefficient; - } - - public void update(double newValue, int newVolume) { - if (newVolume <= 0) return; - // core update formulas - double newProduct = newValue * newVolume; - mProduct = mAlpha * newProduct + (1 - mAlpha) * mProduct; - mVolume = mAlpha * newVolume + (1 - mAlpha) * mVolume; - mValue = mProduct / mVolume; - } - } - - /** - * Record (RSSI -> pakce loss %) mappings of one BSSID - */ - private class BssidStatistics { - - /* MAC address of this BSSID */ - private final String mBssid; - - /* RSSI -> packet loss % mappings */ - private VolumeWeightedEMA[] mEntries; - private int mRssiBase; - private int mEntriesSize; - - /* Target to send good link notification, set when poor link is detected */ - private int mGoodLinkTargetRssi; - private int mGoodLinkTargetCount; - - /* Index of GOOD_LINK_TARGET array */ - private int mGoodLinkTargetIndex; - - /* Timestamps of some last events */ - private long mLastTimeSample; - private long mLastTimeGood; - private long mLastTimePoor; - - /* Max time to avoid this BSSID */ - private long mBssidAvoidTimeMax; - - /** - * Constructor - * - * @param bssid is the address of this BSSID - */ - public BssidStatistics(String bssid) { - this.mBssid = bssid; - mRssiBase = BSSID_STAT_RANGE_LOW_DBM; - mEntriesSize = BSSID_STAT_RANGE_HIGH_DBM - BSSID_STAT_RANGE_LOW_DBM + 1; - mEntries = new VolumeWeightedEMA[mEntriesSize]; - for (int i = 0; i < mEntriesSize; i++) - mEntries[i] = new VolumeWeightedEMA(EXP_COEFFICIENT_RECORD); - } - - /** - * Update this BSSID cache - * - * @param rssi is the RSSI - * @param value is the new instant loss value at this RSSI - * @param volume is the volume for this single update - */ - public void updateLoss(int rssi, double value, int volume) { - if (volume <= 0) return; - int index = rssi - mRssiBase; - if (index < 0 || index >= mEntriesSize) return; - mEntries[index].update(value, volume); - if (DBG) { - DecimalFormat df = new DecimalFormat("#.##"); - logd("Cache updated: loss[" + rssi + "]=" + df.format(mEntries[index].mValue * 100) - + "% volume=" + df.format(mEntries[index].mVolume)); - } - } - - /** - * Get preset loss if the cache has insufficient data, observed from experiments. - * - * @param rssi is the input RSSI - * @return preset loss of the given RSSI - */ - public double presetLoss(int rssi) { - if (rssi <= -90) return 1.0; - if (rssi > 0) return 0.0; - - if (sPresetLoss == null) { - // pre-calculate all preset losses only once, then reuse them - final int size = 90; - sPresetLoss = new double[size]; - for (int i = 0; i < size; i++) sPresetLoss[i] = 1.0 / Math.pow(90 - i, 1.5); - } - return sPresetLoss[-rssi]; - } - - /** - * A poor link is detected, calculate a target RSSI to bring WiFi back. - * - * @param rssi is the current RSSI - * @return true iff the current BSSID should be avoided - */ - public boolean poorLinkDetected(int rssi) { - if (DBG) logd("Poor link detected, rssi=" + rssi); - - long now = SystemClock.elapsedRealtime(); - long lastGood = now - mLastTimeGood; - long lastPoor = now - mLastTimePoor; - - // reduce the difficulty of good link target if last avoidance was long time ago - while (mGoodLinkTargetIndex > 0 - && lastPoor >= GOOD_LINK_TARGET[mGoodLinkTargetIndex - 1].REDUCE_TIME_MS) - mGoodLinkTargetIndex--; - mGoodLinkTargetCount = GOOD_LINK_TARGET[mGoodLinkTargetIndex].SAMPLE_COUNT; - - // scan for a target RSSI at which the link is good - int from = rssi + GOOD_LINK_RSSI_RANGE_MIN; - int to = rssi + GOOD_LINK_RSSI_RANGE_MAX; - mGoodLinkTargetRssi = findRssiTarget(from, to, GOOD_LINK_LOSS_THRESHOLD); - mGoodLinkTargetRssi += GOOD_LINK_TARGET[mGoodLinkTargetIndex].RSSI_ADJ_DBM; - if (mGoodLinkTargetIndex < GOOD_LINK_TARGET.length - 1) mGoodLinkTargetIndex++; - - // calculate max avoidance time to prevent avoiding forever - int p = 0, pmax = MAX_AVOID_TIME.length - 1; - while (p < pmax && rssi >= MAX_AVOID_TIME[p + 1].MIN_RSSI_DBM) p++; - long avoidMax = MAX_AVOID_TIME[p].TIME_MS; - - // don't avoid if max avoidance time is 0 (RSSI is super high) - if (avoidMax <= 0) return false; - - // set max avoidance time, send poor link notification - mBssidAvoidTimeMax = now + avoidMax; - - if (DBG) logd("goodRssi=" + mGoodLinkTargetRssi + " goodCount=" + mGoodLinkTargetCount - + " lastGood=" + lastGood + " lastPoor=" + lastPoor + " avoidMax=" + avoidMax); - - return true; - } - - /** - * A new BSSID is connected, recalculate target RSSI threshold - */ - public void newLinkDetected() { - // if this BSSID is currently being avoided, the reuse those values - if (mBssidAvoidTimeMax > 0) { - if (DBG) logd("Previous avoidance still in effect, rssi=" + mGoodLinkTargetRssi - + " count=" + mGoodLinkTargetCount); - return; - } - - // calculate a new RSSI threshold for new link verifying - int from = BSSID_STAT_RANGE_LOW_DBM; - int to = BSSID_STAT_RANGE_HIGH_DBM; - mGoodLinkTargetRssi = findRssiTarget(from, to, GOOD_LINK_LOSS_THRESHOLD); - mGoodLinkTargetCount = 1; - mBssidAvoidTimeMax = SystemClock.elapsedRealtime() + MAX_AVOID_TIME[0].TIME_MS; - if (DBG) logd("New link verifying target set, rssi=" + mGoodLinkTargetRssi + " count=" - + mGoodLinkTargetCount); - } - - /** - * Return the first RSSI within the range where loss[rssi] < threshold - * - * @param from start scanning from this RSSI - * @param to stop scanning at this RSSI - * @param threshold target threshold for scanning - * @return target RSSI - */ - public int findRssiTarget(int from, int to, double threshold) { - from -= mRssiBase; - to -= mRssiBase; - int emptyCount = 0; - int d = from < to ? 1 : -1; - for (int i = from; i != to; i += d) - // don't use a data point if it volume is too small (statistically unreliable) - if (i >= 0 && i < mEntriesSize && mEntries[i].mVolume > 1.0) { - emptyCount = 0; - if (mEntries[i].mValue < threshold) { - // scan target found - int rssi = mRssiBase + i; - if (DBG) { - DecimalFormat df = new DecimalFormat("#.##"); - logd("Scan target found: rssi=" + rssi + " threshold=" - + df.format(threshold * 100) + "% value=" - + df.format(mEntries[i].mValue * 100) + "% volume=" - + df.format(mEntries[i].mVolume)); - } - return rssi; - } - } else if (++emptyCount >= BSSID_STAT_EMPTY_COUNT) { - // cache has insufficient data around this RSSI, use preset loss instead - int rssi = mRssiBase + i; - double lossPreset = presetLoss(rssi); - if (lossPreset < threshold) { - if (DBG) { - DecimalFormat df = new DecimalFormat("#.##"); - logd("Scan target found: rssi=" + rssi + " threshold=" - + df.format(threshold * 100) + "% value=" - + df.format(lossPreset * 100) + "% volume=preset"); - } - return rssi; - } - } - - return mRssiBase + to; - } - } -} diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java index 482d9cb..b019fd7 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java @@ -60,7 +60,8 @@ public class WifiP2pConfig implements Parcelable { wps.setup = WpsInfo.PBC; } - void invalidate() { + /** @hide */ + public void invalidate() { deviceAddress = ""; } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java index 398d987..a0cb035 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -274,7 +274,7 @@ public class WifiP2pDevice implements Parcelable { } /** Updates details obtained from supplicant @hide */ - void updateSupplicantDetails(WifiP2pDevice device) { + public void updateSupplicantDetails(WifiP2pDevice device) { if (device == null) { throw new IllegalArgumentException("device is null"); } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java index fbcf09b..3d0bb3d 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java @@ -89,7 +89,7 @@ public class WifiP2pDeviceList implements Parcelable { } /** Only updates details fetched from the supplicant @hide */ - void updateSupplicantDetails(WifiP2pDevice device) { + public void updateSupplicantDetails(WifiP2pDevice device) { validateDevice(device); WifiP2pDevice d = mDevices.get(device.deviceAddress); if (d != null) { @@ -107,7 +107,7 @@ public class WifiP2pDeviceList implements Parcelable { } /** @hide */ - void updateGroupCapability(String deviceAddress, int groupCapab) { + public void updateGroupCapability(String deviceAddress, int groupCapab) { validateDeviceAddress(deviceAddress); WifiP2pDevice d = mDevices.get(deviceAddress); if (d != null) { @@ -116,7 +116,7 @@ public class WifiP2pDeviceList implements Parcelable { } /** @hide */ - void updateStatus(String deviceAddress, int status) { + public void updateStatus(String deviceAddress, int status) { validateDeviceAddress(deviceAddress); WifiP2pDevice d = mDevices.get(deviceAddress); if (d != null) { diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java index 98f0972..64bb00b 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java @@ -42,11 +42,13 @@ public class WifiP2pGroupList implements Parcelable { public void onDeleteGroup(int netId); } - WifiP2pGroupList() { + /** @hide */ + public WifiP2pGroupList() { this(null, null); } - WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) { + /** @hide */ + public WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) { mListener = listener; mGroups = new LruCache(CREDENTIAL_MAX_NUM) { @Override @@ -78,8 +80,9 @@ public class WifiP2pGroupList implements Parcelable { * Add the specified group to this group list. * * @param group + * @hide */ - void add(WifiP2pGroup group) { + public void add(WifiP2pGroup group) { mGroups.put(group.getNetworkId(), group); } @@ -87,8 +90,9 @@ public class WifiP2pGroupList implements Parcelable { * Remove the group with the specified network id from this group list. * * @param netId + * @hide */ - void remove(int netId) { + public void remove(int netId) { mGroups.remove(netId); } @@ -103,8 +107,9 @@ public class WifiP2pGroupList implements Parcelable { /** * Clear the group. + * @hide */ - boolean clear() { + public boolean clear() { if (mGroups.size() == 0) return false; isClearCalled = true; mGroups.evictAll(); @@ -120,8 +125,9 @@ public class WifiP2pGroupList implements Parcelable { * * @param deviceAddress p2p device address. * @return the network id. if not found, return -1. + * @hide */ - int getNetworkId(String deviceAddress) { + public int getNetworkId(String deviceAddress) { if (deviceAddress == null) return -1; final Collection groups = mGroups.snapshot().values(); @@ -142,8 +148,9 @@ public class WifiP2pGroupList implements Parcelable { * @param deviceAddress p2p device address. * @param ssid ssid. * @return the network id. if not found, return -1. + * @hide */ - int getNetworkId(String deviceAddress, String ssid) { + public int getNetworkId(String deviceAddress, String ssid) { if (deviceAddress == null || ssid == null) { return -1; } @@ -166,8 +173,9 @@ public class WifiP2pGroupList implements Parcelable { * * @param netId network id. * @return the address. if not found, return null. + * @hide */ - String getOwnerAddr(int netId) { + public String getOwnerAddr(int netId) { WifiP2pGroup grp = mGroups.get(netId); if (grp != null) { return grp.getOwner().deviceAddress; @@ -182,8 +190,9 @@ public class WifiP2pGroupList implements Parcelable { * * @param netId network id. * @return true if the specified network id is present in this group list. + * @hide */ - boolean contains(int netId) { + public boolean contains(int netId) { final Collection groups = mGroups.snapshot().values(); for (WifiP2pGroup grp: groups) { if (netId == grp.getNetworkId()) { diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java deleted file mode 100644 index 7803f7d..0000000 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ /dev/null @@ -1,2949 +0,0 @@ -/* - * Copyright (C) 2011 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 android.net.wifi.p2p; - -import android.app.AlertDialog; -import android.app.Notification; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.DhcpResults; -import android.net.DhcpStateMachine; -import android.net.InterfaceConfiguration; -import android.net.LinkAddress; -import android.net.NetworkInfo; -import android.net.NetworkUtils; -import android.net.wifi.WifiMonitor; -import android.net.wifi.WifiNative; -import android.net.wifi.WifiStateMachine; -import android.net.wifi.WpsInfo; -import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener; -import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; -import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; -import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.INetworkManagementService; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Slog; -import android.util.SparseArray; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.EditText; -import android.widget.TextView; - -import com.android.internal.R; -import com.android.internal.util.AsyncChannel; -import com.android.internal.util.Protocol; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; - - -/** - * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications - * communicate with this service to issue device discovery and connectivity requests - * through the WifiP2pManager interface. The state machine communicates with the wifi - * driver through wpa_supplicant and handles the event responses through WifiMonitor. - * - * Note that the term Wifi when used without a p2p suffix refers to the client mode - * of Wifi operation - * @hide - */ -public class WifiP2pService extends IWifiP2pManager.Stub { - private static final String TAG = "WifiP2pService"; - private static final boolean DBG = false; - private static final String NETWORKTYPE = "WIFI_P2P"; - - private Context mContext; - private String mInterface; - private Notification mNotification; - - INetworkManagementService mNwService; - private DhcpStateMachine mDhcpStateMachine; - - private P2pStateMachine mP2pStateMachine; - private AsyncChannel mReplyChannel = new AsyncChannel(); - private AsyncChannel mWifiChannel; - - private static final Boolean JOIN_GROUP = true; - private static final Boolean FORM_GROUP = false; - - private static final Boolean RELOAD = true; - private static final Boolean NO_RELOAD = false; - - /* Two minutes comes from the wpa_supplicant setting */ - private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000; - private static int mGroupCreatingTimeoutIndex = 0; - - private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000; - private static int mDisableP2pTimeoutIndex = 0; - - /* Set a two minute discover timeout to avoid STA scans from being blocked */ - private static final int DISCOVER_TIMEOUT_S = 120; - - /* Idle time after a peer is gone when the group is torn down */ - private static final int GROUP_IDLE_TIME_S = 10; - - private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE; - - /* Delayed message to timeout group creation */ - public static final int GROUP_CREATING_TIMED_OUT = BASE + 1; - - /* User accepted a peer request */ - private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2; - /* User rejected a peer request */ - private static final int PEER_CONNECTION_USER_REJECT = BASE + 3; - /* User wants to disconnect wifi in favour of p2p */ - private static final int DROP_WIFI_USER_ACCEPT = BASE + 4; - /* User wants to keep his wifi connection and drop p2p */ - private static final int DROP_WIFI_USER_REJECT = BASE + 5; - /* Delayed message to timeout p2p disable */ - public static final int DISABLE_P2P_TIMED_OUT = BASE + 6; - - - /* Commands to the WifiStateMachine */ - public static final int P2P_CONNECTION_CHANGED = BASE + 11; - - /* These commands are used to temporarily disconnect wifi when we detect - * a frequency conflict which would make it impossible to have with p2p - * and wifi active at the same time. - * - * If the user chooses to disable wifi temporarily, we keep wifi disconnected - * until the p2p connection is done and terminated at which point we will - * bring back wifi up - * - * DISCONNECT_WIFI_REQUEST - * msg.arg1 = 1 enables temporary disconnect and 0 disables it. - */ - public static final int DISCONNECT_WIFI_REQUEST = BASE + 12; - public static final int DISCONNECT_WIFI_RESPONSE = BASE + 13; - - public static final int SET_MIRACAST_MODE = BASE + 14; - - // During dhcp (and perhaps other times) we can't afford to drop packets - // but Discovery will switch our channel enough we will. - // msg.arg1 = ENABLED for blocking, DISABLED for resumed. - // msg.arg2 = msg to send when blocked - // msg.obj = StateMachine to send to when blocked - public static final int BLOCK_DISCOVERY = BASE + 15; - - // set country code - public static final int SET_COUNTRY_CODE = BASE + 16; - - public static final int ENABLED = 1; - public static final int DISABLED = 0; - - private final boolean mP2pSupported; - - private WifiP2pDevice mThisDevice = new WifiP2pDevice(); - - /* When a group has been explicitly created by an app, we persist the group - * even after all clients have been disconnected until an explicit remove - * is invoked */ - private boolean mAutonomousGroup; - - /* Invitation to join an existing p2p group */ - private boolean mJoinExistingGroup; - - /* Track whether we are in p2p discovery. This is used to avoid sending duplicate - * broadcasts - */ - private boolean mDiscoveryStarted; - /* Track whether servcice/peer discovery is blocked in favor of other wifi actions - * (notably dhcp) - */ - private boolean mDiscoveryBlocked; - - // Supplicant doesn't like setting the same country code multiple times (it may drop - // current connected network), so we save the country code here to avoid redundency - private String mLastSetCountryCode; - - /* - * remember if we were in a scan when it had to be stopped - */ - private boolean mDiscoveryPostponed = false; - - private NetworkInfo mNetworkInfo; - - private boolean mTempoarilyDisconnectedWifi = false; - - /* The transaction Id of service discovery request */ - private byte mServiceTransactionId = 0; - - /* Service discovery request ID of wpa_supplicant. - * null means it's not set yet. */ - private String mServiceDiscReqId; - - /* clients(application) information list. */ - private HashMap mClientInfoList = new HashMap(); - - /* Is chosen as a unique range to avoid conflict with - the range defined in Tethering.java */ - private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"}; - private static final String SERVER_ADDRESS = "192.168.49.1"; - - /** - * Error code definition. - * see the Table.8 in the WiFi Direct specification for the detail. - */ - public static enum P2pStatus { - /* Success. */ - SUCCESS, - - /* The target device is currently unavailable. */ - INFORMATION_IS_CURRENTLY_UNAVAILABLE, - - /* Protocol error. */ - INCOMPATIBLE_PARAMETERS, - - /* The target device reached the limit of the number of the connectable device. - * For example, device limit or group limit is set. */ - LIMIT_REACHED, - - /* Protocol error. */ - INVALID_PARAMETER, - - /* Unable to accommodate request. */ - UNABLE_TO_ACCOMMODATE_REQUEST, - - /* Previous protocol error, or disruptive behavior. */ - PREVIOUS_PROTOCOL_ERROR, - - /* There is no common channels the both devices can use. */ - NO_COMMON_CHANNEL, - - /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group, - * but device B has removed the specified credential already. */ - UNKNOWN_P2P_GROUP, - - /* Both p2p devices indicated an intent of 15 in group owner negotiation. */ - BOTH_GO_INTENT_15, - - /* Incompatible provisioning method. */ - INCOMPATIBLE_PROVISIONING_METHOD, - - /* Rejected by user */ - REJECTED_BY_USER, - - /* Unknown error */ - UNKNOWN; - - public static P2pStatus valueOf(int error) { - switch(error) { - case 0 : - return SUCCESS; - case 1: - return INFORMATION_IS_CURRENTLY_UNAVAILABLE; - case 2: - return INCOMPATIBLE_PARAMETERS; - case 3: - return LIMIT_REACHED; - case 4: - return INVALID_PARAMETER; - case 5: - return UNABLE_TO_ACCOMMODATE_REQUEST; - case 6: - return PREVIOUS_PROTOCOL_ERROR; - case 7: - return NO_COMMON_CHANNEL; - case 8: - return UNKNOWN_P2P_GROUP; - case 9: - return BOTH_GO_INTENT_15; - case 10: - return INCOMPATIBLE_PROVISIONING_METHOD; - case 11: - return REJECTED_BY_USER; - default: - return UNKNOWN; - } - } - } - - public WifiP2pService(Context context) { - mContext = context; - - //STOPSHIP: get this from native side - mInterface = "p2p0"; - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, ""); - - mP2pSupported = mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI_DIRECT); - - mThisDevice.primaryDeviceType = mContext.getResources().getString( - com.android.internal.R.string.config_wifi_p2p_device_type); - - mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported); - mP2pStateMachine.start(); - } - - public void connectivityServiceReady() { - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNwService = INetworkManagementService.Stub.asInterface(b); - } - - private void enforceAccessPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, - "WifiP2pService"); - } - - private void enforceChangePermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, - "WifiP2pService"); - } - - private void enforceConnectivityInternalPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, - "WifiP2pService"); - } - - /** - * Get a reference to handler. This is used by a client to establish - * an AsyncChannel communication with WifiP2pService - */ - public Messenger getMessenger() { - enforceAccessPermission(); - enforceChangePermission(); - return new Messenger(mP2pStateMachine.getHandler()); - } - - /** This is used to provide information to drivers to optimize performance depending - * on the current mode of operation. - * 0 - disabled - * 1 - source operation - * 2 - sink operation - * - * As an example, the driver could reduce the channel dwell time during scanning - * when acting as a source or sink to minimize impact on miracast. - */ - public void setMiracastMode(int mode) { - enforceConnectivityInternalPermission(); - mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump WifiP2pService from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - mP2pStateMachine.dump(fd, pw, args); - pw.println("mAutonomousGroup " + mAutonomousGroup); - pw.println("mJoinExistingGroup " + mJoinExistingGroup); - pw.println("mDiscoveryStarted " + mDiscoveryStarted); - pw.println("mNetworkInfo " + mNetworkInfo); - pw.println("mTempoarilyDisconnectedWifi " + mTempoarilyDisconnectedWifi); - pw.println("mServiceDiscReqId " + mServiceDiscReqId); - pw.println(); - } - - - /** - * Handles interaction with WifiStateMachine - */ - private class P2pStateMachine extends StateMachine { - - private DefaultState mDefaultState = new DefaultState(); - private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState(); - private P2pDisablingState mP2pDisablingState = new P2pDisablingState(); - private P2pDisabledState mP2pDisabledState = new P2pDisabledState(); - private P2pEnablingState mP2pEnablingState = new P2pEnablingState(); - private P2pEnabledState mP2pEnabledState = new P2pEnabledState(); - // Inactive is when p2p is enabled with no connectivity - private InactiveState mInactiveState = new InactiveState(); - private GroupCreatingState mGroupCreatingState = new GroupCreatingState(); - private UserAuthorizingInviteRequestState mUserAuthorizingInviteRequestState - = new UserAuthorizingInviteRequestState(); - private UserAuthorizingNegotiationRequestState mUserAuthorizingNegotiationRequestState - = new UserAuthorizingNegotiationRequestState(); - private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState(); - private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState(); - private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState(); - - private GroupCreatedState mGroupCreatedState = new GroupCreatedState(); - private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState(); - private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState(); - - private WifiNative mWifiNative = new WifiNative(mInterface); - private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative); - - private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList(); - /* During a connection, supplicant can tell us that a device was lost. From a supplicant's - * perspective, the discovery stops during connection and it purges device since it does - * not get latest updates about the device without being in discovery state. - * - * From the framework perspective, the device is still there since we are connecting or - * connected to it. so we keep these devices in a separate list, so that they are removed - * when connection is cancelled or lost - */ - private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList(); - private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null, - new GroupDeleteListener() { - @Override - public void onDeleteGroup(int netId) { - if (DBG) logd("called onDeleteGroup() netId=" + netId); - mWifiNative.removeNetwork(netId); - mWifiNative.saveConfig(); - sendP2pPersistentGroupsChangedBroadcast(); - } - }); - private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo(); - private WifiP2pGroup mGroup; - - // Saved WifiP2pConfig for an ongoing peer connection. This will never be null. - // The deviceAddress will be an empty string when the device is inactive - // or if it is connected without any ongoing join request - private WifiP2pConfig mSavedPeerConfig = new WifiP2pConfig(); - - // Saved WifiP2pGroup from invitation request - private WifiP2pGroup mSavedP2pGroup; - - P2pStateMachine(String name, boolean p2pSupported) { - super(name); - - addState(mDefaultState); - addState(mP2pNotSupportedState, mDefaultState); - addState(mP2pDisablingState, mDefaultState); - addState(mP2pDisabledState, mDefaultState); - addState(mP2pEnablingState, mDefaultState); - addState(mP2pEnabledState, mDefaultState); - addState(mInactiveState, mP2pEnabledState); - addState(mGroupCreatingState, mP2pEnabledState); - addState(mUserAuthorizingInviteRequestState, mGroupCreatingState); - addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState); - addState(mProvisionDiscoveryState, mGroupCreatingState); - addState(mGroupNegotiationState, mGroupCreatingState); - addState(mFrequencyConflictState, mGroupCreatingState); - addState(mGroupCreatedState, mP2pEnabledState); - addState(mUserAuthorizingJoinState, mGroupCreatedState); - addState(mOngoingGroupRemovalState, mGroupCreatedState); - - if (p2pSupported) { - setInitialState(mP2pDisabledState); - } else { - setInitialState(mP2pNotSupportedState); - } - setLogRecSize(50); - setLogOnlyTransitions(true); - } - - class DefaultState extends State { - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (DBG) logd("Full connection with WifiStateMachine established"); - mWifiChannel = (AsyncChannel) message.obj; - } else { - loge("Full connection failure, error = " + message.arg1); - mWifiChannel = null; - } - break; - - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - loge("Send failed, client connection lost"); - } else { - loge("Client connection lost with reason: " + message.arg1); - } - mWifiChannel = null; - break; - - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: - AsyncChannel ac = new AsyncChannel(); - ac.connect(mContext, getHandler(), message.replyTo); - break; - case BLOCK_DISCOVERY: - mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false); - // always reset this - we went to a state that doesn't support discovery so - // it would have stopped regardless - mDiscoveryPostponed = false; - if (mDiscoveryBlocked) { - try { - StateMachine m = (StateMachine)message.obj; - m.sendMessage(message.arg2); - } catch (Exception e) { - loge("unable to send BLOCK_DISCOVERY response: " + e); - } - } - break; - case WifiP2pManager.DISCOVER_PEERS: - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.STOP_DISCOVERY: - replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.DISCOVER_SERVICES: - replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CONNECT: - replyToMessage(message, WifiP2pManager.CONNECT_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CANCEL_CONNECT: - replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CREATE_GROUP: - replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.REMOVE_GROUP: - replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.ADD_LOCAL_SERVICE: - replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.REMOVE_LOCAL_SERVICE: - replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CLEAR_LOCAL_SERVICES: - replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.ADD_SERVICE_REQUEST: - replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.REMOVE_SERVICE_REQUEST: - replyToMessage(message, - WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CLEAR_SERVICE_REQUESTS: - replyToMessage(message, - WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.SET_DEVICE_NAME: - replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.DELETE_PERSISTENT_GROUP: - replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.SET_WFD_INFO: - replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.REQUEST_PEERS: - replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, - new WifiP2pDeviceList(mPeers)); - break; - case WifiP2pManager.REQUEST_CONNECTION_INFO: - replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, - new WifiP2pInfo(mWifiP2pInfo)); - break; - case WifiP2pManager.REQUEST_GROUP_INFO: - replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, - mGroup != null ? new WifiP2pGroup(mGroup) : null); - break; - case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO: - replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO, - new WifiP2pGroupList(mGroups, null)); - break; - case WifiP2pManager.START_WPS: - replyToMessage(message, WifiP2pManager.START_WPS_FAILED, - WifiP2pManager.BUSY); - break; - // Ignore - case WifiMonitor.P2P_INVITATION_RESULT_EVENT: - case WifiMonitor.SCAN_RESULTS_EVENT: - case WifiMonitor.SUP_CONNECTION_EVENT: - case WifiMonitor.SUP_DISCONNECTION_EVENT: - case WifiMonitor.NETWORK_CONNECTION_EVENT: - case WifiMonitor.NETWORK_DISCONNECTION_EVENT: - case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: - case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: - case WifiMonitor.WPS_SUCCESS_EVENT: - case WifiMonitor.WPS_FAIL_EVENT: - case WifiMonitor.WPS_OVERLAP_EVENT: - case WifiMonitor.WPS_TIMEOUT_EVENT: - case WifiMonitor.P2P_GROUP_REMOVED_EVENT: - case WifiMonitor.P2P_DEVICE_FOUND_EVENT: - case WifiMonitor.P2P_DEVICE_LOST_EVENT: - case WifiMonitor.P2P_FIND_STOPPED_EVENT: - case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: - case PEER_CONNECTION_USER_ACCEPT: - case PEER_CONNECTION_USER_REJECT: - case DISCONNECT_WIFI_RESPONSE: - case DROP_WIFI_USER_ACCEPT: - case DROP_WIFI_USER_REJECT: - case GROUP_CREATING_TIMED_OUT: - case DISABLE_P2P_TIMED_OUT: - case DhcpStateMachine.CMD_PRE_DHCP_ACTION: - case DhcpStateMachine.CMD_POST_DHCP_ACTION: - case DhcpStateMachine.CMD_ON_QUIT: - case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT: - case SET_MIRACAST_MODE: - case WifiP2pManager.START_LISTEN: - case WifiP2pManager.STOP_LISTEN: - case WifiP2pManager.SET_CHANNEL: - case SET_COUNTRY_CODE: - break; - case WifiStateMachine.CMD_ENABLE_P2P: - // Enable is lazy and has no response - break; - case WifiStateMachine.CMD_DISABLE_P2P_REQ: - // If we end up handling in default, p2p is not enabled - mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); - break; - /* unexpected group created, remove */ - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - mGroup = (WifiP2pGroup) message.obj; - loge("Unexpected group creation, remove " + mGroup); - mWifiNative.p2pGroupRemove(mGroup.getInterface()); - break; - // A group formation failure is always followed by - // a group removed event. Flushing things at group formation - // failure causes supplicant issues. Ignore right now. - case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: - break; - default: - loge("Unhandled message " + message); - return NOT_HANDLED; - } - return HANDLED; - } - } - - class P2pNotSupportedState extends State { - @Override - public boolean processMessage(Message message) { - switch (message.what) { - case WifiP2pManager.DISCOVER_PEERS: - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.STOP_DISCOVERY: - replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.DISCOVER_SERVICES: - replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.CONNECT: - replyToMessage(message, WifiP2pManager.CONNECT_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.CANCEL_CONNECT: - replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.CREATE_GROUP: - replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.REMOVE_GROUP: - replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.ADD_LOCAL_SERVICE: - replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.REMOVE_LOCAL_SERVICE: - replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.CLEAR_LOCAL_SERVICES: - replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.ADD_SERVICE_REQUEST: - replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.REMOVE_SERVICE_REQUEST: - replyToMessage(message, - WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.CLEAR_SERVICE_REQUESTS: - replyToMessage(message, - WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.SET_DEVICE_NAME: - replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.DELETE_PERSISTENT_GROUP: - replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.SET_WFD_INFO: - replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.START_WPS: - replyToMessage(message, WifiP2pManager.START_WPS_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.START_LISTEN: - replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.STOP_LISTEN: - replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class P2pDisablingState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT, - ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiMonitor.SUP_DISCONNECTION_EVENT: - if (DBG) logd("p2p socket connection lost"); - transitionTo(mP2pDisabledState); - break; - case WifiStateMachine.CMD_ENABLE_P2P: - case WifiStateMachine.CMD_DISABLE_P2P_REQ: - deferMessage(message); - break; - case DISABLE_P2P_TIMED_OUT: - if (mGroupCreatingTimeoutIndex == message.arg1) { - loge("P2p disable timed out"); - transitionTo(mP2pDisabledState); - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); - } - } - - class P2pDisabledState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiStateMachine.CMD_ENABLE_P2P: - try { - mNwService.setInterfaceUp(mInterface); - } catch (RemoteException re) { - loge("Unable to change interface settings: " + re); - } catch (IllegalStateException ie) { - loge("Unable to change interface settings: " + ie); - } - mWifiMonitor.startMonitoring(); - transitionTo(mP2pEnablingState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class P2pEnablingState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiMonitor.SUP_CONNECTION_EVENT: - if (DBG) logd("P2p socket connection successful"); - transitionTo(mInactiveState); - break; - case WifiMonitor.SUP_DISCONNECTION_EVENT: - loge("P2p socket connection failed"); - transitionTo(mP2pDisabledState); - break; - case WifiStateMachine.CMD_ENABLE_P2P: - case WifiStateMachine.CMD_DISABLE_P2P_REQ: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class P2pEnabledState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - sendP2pStateChangedBroadcast(true); - mNetworkInfo.setIsAvailable(true); - sendP2pConnectionChangedBroadcast(); - initializeP2pSettings(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiMonitor.SUP_DISCONNECTION_EVENT: - loge("Unexpected loss of p2p socket connection"); - transitionTo(mP2pDisabledState); - break; - case WifiStateMachine.CMD_ENABLE_P2P: - //Nothing to do - break; - case WifiStateMachine.CMD_DISABLE_P2P_REQ: - if (mPeers.clear()) { - sendPeersChangedBroadcast(); - } - if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast(); - - mWifiMonitor.stopMonitoring(); - transitionTo(mP2pDisablingState); - break; - case WifiP2pManager.SET_DEVICE_NAME: - { - WifiP2pDevice d = (WifiP2pDevice) message.obj; - if (d != null && setAndPersistDeviceName(d.deviceName)) { - if (DBG) logd("set device name " + d.deviceName); - replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, - WifiP2pManager.ERROR); - } - break; - } - case WifiP2pManager.SET_WFD_INFO: - { - WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj; - if (d != null && setWfdInfo(d)) { - replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, - WifiP2pManager.ERROR); - } - break; - } - case BLOCK_DISCOVERY: - boolean blocked = (message.arg1 == ENABLED ? true : false); - if (mDiscoveryBlocked == blocked) break; - mDiscoveryBlocked = blocked; - if (blocked && mDiscoveryStarted) { - mWifiNative.p2pStopFind(); - mDiscoveryPostponed = true; - } - if (!blocked && mDiscoveryPostponed) { - mDiscoveryPostponed = false; - mWifiNative.p2pFind(DISCOVER_TIMEOUT_S); - } - if (blocked) { - try { - StateMachine m = (StateMachine)message.obj; - m.sendMessage(message.arg2); - } catch (Exception e) { - loge("unable to send BLOCK_DISCOVERY response: " + e); - } - } - break; - case WifiP2pManager.DISCOVER_PEERS: - if (mDiscoveryBlocked) { - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, - WifiP2pManager.BUSY); - break; - } - // do not send service discovery request while normal find operation. - clearSupplicantServiceRequest(); - if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); - sendP2pDiscoveryChangedBroadcast(true); - } else { - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, - WifiP2pManager.ERROR); - } - break; - case WifiMonitor.P2P_FIND_STOPPED_EVENT: - sendP2pDiscoveryChangedBroadcast(false); - break; - case WifiP2pManager.STOP_DISCOVERY: - if (mWifiNative.p2pStopFind()) { - replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, - WifiP2pManager.ERROR); - } - break; - case WifiP2pManager.DISCOVER_SERVICES: - if (mDiscoveryBlocked) { - replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, - WifiP2pManager.BUSY); - break; - } - if (DBG) logd(getName() + " discover services"); - if (!updateSupplicantServiceRequest()) { - replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, - WifiP2pManager.NO_SERVICE_REQUESTS); - break; - } - if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { - replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, - WifiP2pManager.ERROR); - } - break; - case WifiMonitor.P2P_DEVICE_FOUND_EVENT: - WifiP2pDevice device = (WifiP2pDevice) message.obj; - if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break; - mPeers.updateSupplicantDetails(device); - sendPeersChangedBroadcast(); - break; - case WifiMonitor.P2P_DEVICE_LOST_EVENT: - device = (WifiP2pDevice) message.obj; - // Gets current details for the one removed - device = mPeers.remove(device.deviceAddress); - if (device != null) { - sendPeersChangedBroadcast(); - } - break; - case WifiP2pManager.ADD_LOCAL_SERVICE: - if (DBG) logd(getName() + " add service"); - WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj; - if (addLocalService(message.replyTo, servInfo)) { - replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED); - } - break; - case WifiP2pManager.REMOVE_LOCAL_SERVICE: - if (DBG) logd(getName() + " remove service"); - servInfo = (WifiP2pServiceInfo)message.obj; - removeLocalService(message.replyTo, servInfo); - replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED); - break; - case WifiP2pManager.CLEAR_LOCAL_SERVICES: - if (DBG) logd(getName() + " clear service"); - clearLocalServices(message.replyTo); - replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED); - break; - case WifiP2pManager.ADD_SERVICE_REQUEST: - if (DBG) logd(getName() + " add service request"); - if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) { - replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED); - break; - } - replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED); - break; - case WifiP2pManager.REMOVE_SERVICE_REQUEST: - if (DBG) logd(getName() + " remove service request"); - removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj); - replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED); - break; - case WifiP2pManager.CLEAR_SERVICE_REQUESTS: - if (DBG) logd(getName() + " clear service request"); - clearServiceRequests(message.replyTo); - replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED); - break; - case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: - if (DBG) logd(getName() + " receive service response"); - List sdRespList = - (List) message.obj; - for (WifiP2pServiceResponse resp : sdRespList) { - WifiP2pDevice dev = - mPeers.get(resp.getSrcDevice().deviceAddress); - resp.setSrcDevice(dev); - sendServiceResponse(resp); - } - break; - case WifiP2pManager.DELETE_PERSISTENT_GROUP: - if (DBG) logd(getName() + " delete persistent group"); - mGroups.remove(message.arg1); - replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED); - break; - case SET_MIRACAST_MODE: - mWifiNative.setMiracastMode(message.arg1); - break; - case WifiP2pManager.START_LISTEN: - if (DBG) logd(getName() + " start listen mode"); - mWifiNative.p2pFlush(); - if (mWifiNative.p2pExtListen(true, 500, 500)) { - replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); - } - break; - case WifiP2pManager.STOP_LISTEN: - if (DBG) logd(getName() + " stop listen mode"); - if (mWifiNative.p2pExtListen(false, 0, 0)) { - replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); - } - mWifiNative.p2pFlush(); - break; - case WifiP2pManager.SET_CHANNEL: - Bundle p2pChannels = (Bundle) message.obj; - int lc = p2pChannels.getInt("lc", 0); - int oc = p2pChannels.getInt("oc", 0); - if (DBG) logd(getName() + " set listen and operating channel"); - if (mWifiNative.p2pSetChannel(lc, oc)) { - replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED); - } - break; - case SET_COUNTRY_CODE: - String countryCode = (String) message.obj; - countryCode = countryCode.toUpperCase(Locale.ROOT); - if (mLastSetCountryCode == null || - countryCode.equals(mLastSetCountryCode) == false) { - if (mWifiNative.setCountryCode(countryCode)) { - mLastSetCountryCode = countryCode; - } - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - sendP2pDiscoveryChangedBroadcast(false); - sendP2pStateChangedBroadcast(false); - mNetworkInfo.setIsAvailable(false); - - mLastSetCountryCode = null; - } - } - - class InactiveState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - mSavedPeerConfig.invalidate(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiP2pManager.CONNECT: - if (DBG) logd(getName() + " sending connect"); - WifiP2pConfig config = (WifiP2pConfig) message.obj; - if (isConfigInvalid(config)) { - loge("Dropping connect requeset " + config); - replyToMessage(message, WifiP2pManager.CONNECT_FAILED); - break; - } - - mAutonomousGroup = false; - mWifiNative.p2pStopFind(); - if (reinvokePersistentGroup(config)) { - transitionTo(mGroupNegotiationState); - } else { - transitionTo(mProvisionDiscoveryState); - } - mSavedPeerConfig = config; - mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); - sendPeersChangedBroadcast(); - replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); - break; - case WifiP2pManager.STOP_DISCOVERY: - if (mWifiNative.p2pStopFind()) { - // When discovery stops in inactive state, flush to clear - // state peer data - mWifiNative.p2pFlush(); - mServiceDiscReqId = null; - replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, - WifiP2pManager.ERROR); - } - break; - case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: - config = (WifiP2pConfig) message.obj; - if (isConfigInvalid(config)) { - loge("Dropping GO neg request " + config); - break; - } - mSavedPeerConfig = config; - mAutonomousGroup = false; - mJoinExistingGroup = false; - transitionTo(mUserAuthorizingNegotiationRequestState); - break; - case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: - WifiP2pGroup group = (WifiP2pGroup) message.obj; - WifiP2pDevice owner = group.getOwner(); - - if (owner == null) { - loge("Ignored invitation from null owner"); - break; - } - - config = new WifiP2pConfig(); - config.deviceAddress = group.getOwner().deviceAddress; - - if (isConfigInvalid(config)) { - loge("Dropping invitation request " + config); - break; - } - mSavedPeerConfig = config; - - //Check if we have the owner in peer list and use appropriate - //wps method. Default is to use PBC. - if ((owner = mPeers.get(owner.deviceAddress)) != null) { - if (owner.wpsPbcSupported()) { - mSavedPeerConfig.wps.setup = WpsInfo.PBC; - } else if (owner.wpsKeypadSupported()) { - mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; - } else if (owner.wpsDisplaySupported()) { - mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; - } - } - - mAutonomousGroup = false; - mJoinExistingGroup = 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 WifiP2pManager.CREATE_GROUP: - mAutonomousGroup = true; - int netId = message.arg1; - boolean ret = false; - if (netId == WifiP2pGroup.PERSISTENT_NET_ID) { - // check if the go persistent group is present. - netId = mGroups.getNetworkId(mThisDevice.deviceAddress); - if (netId != -1) { - ret = mWifiNative.p2pGroupAdd(netId); - } else { - ret = mWifiNative.p2pGroupAdd(true); - } - } else { - ret = mWifiNative.p2pGroupAdd(false); - } - - if (ret) { - replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED); - transitionTo(mGroupNegotiationState); - } else { - replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, - WifiP2pManager.ERROR); - // remain at this state. - } - break; - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - mGroup = (WifiP2pGroup) message.obj; - if (DBG) logd(getName() + " group started"); - - // We hit this scenario when a persistent group is reinvoked - if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) { - mAutonomousGroup = false; - deferMessage(message); - transitionTo(mGroupNegotiationState); - } else { - loge("Unexpected group creation, remove " + mGroup); - mWifiNative.p2pGroupRemove(mGroup.getInterface()); - } - break; - case WifiP2pManager.START_LISTEN: - if (DBG) logd(getName() + " start listen mode"); - mWifiNative.p2pFlush(); - if (mWifiNative.p2pExtListen(true, 500, 500)) { - replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); - } - break; - case WifiP2pManager.STOP_LISTEN: - if (DBG) logd(getName() + " stop listen mode"); - if (mWifiNative.p2pExtListen(false, 0, 0)) { - replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); - } - mWifiNative.p2pFlush(); - break; - case WifiP2pManager.SET_CHANNEL: - Bundle p2pChannels = (Bundle) message.obj; - int lc = p2pChannels.getInt("lc", 0); - int oc = p2pChannels.getInt("oc", 0); - if (DBG) logd(getName() + " set listen and operating channel"); - if (mWifiNative.p2pSetChannel(lc, oc)) { - replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED); - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class GroupCreatingState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT, - ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - boolean ret = HANDLED; - switch (message.what) { - case GROUP_CREATING_TIMED_OUT: - if (mGroupCreatingTimeoutIndex == message.arg1) { - if (DBG) logd("Group negotiation timed out"); - handleGroupCreationFailure(); - transitionTo(mInactiveState); - } - break; - case WifiMonitor.P2P_DEVICE_LOST_EVENT: - WifiP2pDevice device = (WifiP2pDevice) message.obj; - if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) { - if (DBG) { - logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress + - "device " + device.deviceAddress); - } - // Do the regular device lost handling - ret = NOT_HANDLED; - break; - } - // Do nothing - if (DBG) logd("Add device to lost list " + device); - mPeersLostDuringConnection.updateSupplicantDetails(device); - break; - case WifiP2pManager.DISCOVER_PEERS: - /* Discovery will break negotiation */ - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.CANCEL_CONNECT: - //Do a supplicant p2p_cancel which only cancels an ongoing - //group negotiation. This will fail for a pending provision - //discovery or for a pending user action, but at the framework - //level, we always treat cancel as succeeded and enter - //an inactive state - mWifiNative.p2pCancelConnect(); - handleGroupCreationFailure(); - transitionTo(mInactiveState); - replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED); - break; - default: - ret = NOT_HANDLED; - } - return ret; - } - } - - class UserAuthorizingNegotiationRequestState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - notifyInvitationReceived(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - boolean ret = HANDLED; - switch (message.what) { - case PEER_CONNECTION_USER_ACCEPT: - mWifiNative.p2pStopFind(); - p2pConnectWithPinDisplay(mSavedPeerConfig); - mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); - sendPeersChangedBroadcast(); - transitionTo(mGroupNegotiationState); - break; - case PEER_CONNECTION_USER_REJECT: - if (DBG) logd("User rejected negotiation " + mSavedPeerConfig); - transitionTo(mInactiveState); - break; - default: - return NOT_HANDLED; - } - return ret; - } - - @Override - public void exit() { - //TODO: dismiss dialog if not already done - } - } - - class UserAuthorizingInviteRequestState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - notifyInvitationReceived(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - boolean ret = HANDLED; - switch (message.what) { - case PEER_CONNECTION_USER_ACCEPT: - mWifiNative.p2pStopFind(); - if (!reinvokePersistentGroup(mSavedPeerConfig)) { - // Do negotiation when persistence fails - p2pConnectWithPinDisplay(mSavedPeerConfig); - } - mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); - sendPeersChangedBroadcast(); - transitionTo(mGroupNegotiationState); - break; - case PEER_CONNECTION_USER_REJECT: - if (DBG) logd("User rejected invitation " + mSavedPeerConfig); - transitionTo(mInactiveState); - break; - default: - return NOT_HANDLED; - } - return ret; - } - - @Override - public void exit() { - //TODO: dismiss dialog if not already done - } - } - - - - class ProvisionDiscoveryState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - WifiP2pProvDiscEvent provDisc; - WifiP2pDevice device; - switch (message.what) { - case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT: - provDisc = (WifiP2pProvDiscEvent) message.obj; - device = provDisc.device; - if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; - - if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { - if (DBG) logd("Found a match " + mSavedPeerConfig); - p2pConnectWithPinDisplay(mSavedPeerConfig); - transitionTo(mGroupNegotiationState); - } - break; - case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: - provDisc = (WifiP2pProvDiscEvent) message.obj; - device = provDisc.device; - if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; - - if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) { - if (DBG) logd("Found a match " + mSavedPeerConfig); - /* we already have the pin */ - if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) { - p2pConnectWithPinDisplay(mSavedPeerConfig); - transitionTo(mGroupNegotiationState); - } else { - mJoinExistingGroup = false; - transitionTo(mUserAuthorizingNegotiationRequestState); - } - } - break; - case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: - provDisc = (WifiP2pProvDiscEvent) message.obj; - device = provDisc.device; - if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; - - if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) { - if (DBG) logd("Found a match " + mSavedPeerConfig); - mSavedPeerConfig.wps.pin = provDisc.pin; - p2pConnectWithPinDisplay(mSavedPeerConfig); - notifyInvitationSent(provDisc.pin, device.deviceAddress); - transitionTo(mGroupNegotiationState); - } - break; - case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT: - loge("provision discovery failed"); - handleGroupCreationFailure(); - transitionTo(mInactiveState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class GroupNegotiationState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - // We ignore these right now, since we get a GROUP_STARTED notification - // afterwards - case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: - case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: - if (DBG) logd(getName() + " go success"); - break; - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - mGroup = (WifiP2pGroup) message.obj; - if (DBG) logd(getName() + " group started"); - - if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) { - /* - * update cache information and set network id to mGroup. - */ - updatePersistentNetworks(NO_RELOAD); - String devAddr = mGroup.getOwner().deviceAddress; - mGroup.setNetworkId(mGroups.getNetworkId(devAddr, - mGroup.getNetworkName())); - } - - if (mGroup.isGroupOwner()) { - /* Setting an idle time out on GO causes issues with certain scenarios - * on clients where it can be off-channel for longer and with the power - * save modes used. - * - * TODO: Verify multi-channel scenarios and supplicant behavior are - * better before adding a time out in future - */ - //Set group idle timeout of 10 sec, to avoid GO beaconing incase of any - //failure during 4-way Handshake. - if (!mAutonomousGroup) { - mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S); - } - startDhcpServer(mGroup.getInterface()); - } else { - mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S); - mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, - P2pStateMachine.this, mGroup.getInterface()); - // TODO: We should use DHCP state machine PRE message like WifiStateMachine - mWifiNative.setP2pPowerSave(mGroup.getInterface(), false); - mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); - WifiP2pDevice groupOwner = mGroup.getOwner(); - WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress); - if (peer != null) { - // update group owner details with peer details found at discovery - groupOwner.updateSupplicantDetails(peer); - mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED); - sendPeersChangedBroadcast(); - } else { - // A supplicant bug can lead to reporting an invalid - // group owner address (all zeroes) at times. Avoid a - // crash, but continue group creation since it is not - // essential. - logw("Unknown group owner " + groupOwner); - } - } - transitionTo(mGroupCreatedState); - break; - case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: - P2pStatus status = (P2pStatus) message.obj; - if (status == P2pStatus.NO_COMMON_CHANNEL) { - transitionTo(mFrequencyConflictState); - break; - } - /* continue with group removal handling */ - case WifiMonitor.P2P_GROUP_REMOVED_EVENT: - if (DBG) logd(getName() + " go failure"); - handleGroupCreationFailure(); - transitionTo(mInactiveState); - break; - // A group formation failure is always followed by - // a group removed event. Flushing things at group formation - // failure causes supplicant issues. Ignore right now. - case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: - status = (P2pStatus) message.obj; - if (status == P2pStatus.NO_COMMON_CHANNEL) { - transitionTo(mFrequencyConflictState); - break; - } - break; - case WifiMonitor.P2P_INVITATION_RESULT_EVENT: - status = (P2pStatus)message.obj; - if (status == P2pStatus.SUCCESS) { - // invocation was succeeded. - // wait P2P_GROUP_STARTED_EVENT. - break; - } - loge("Invitation result " + status); - if (status == P2pStatus.UNKNOWN_P2P_GROUP) { - // target device has already removed the credential. - // So, remove this credential accordingly. - int netId = mSavedPeerConfig.netId; - if (netId >= 0) { - if (DBG) logd("Remove unknown client from the list"); - removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true); - } - - // Reinvocation has failed, try group negotiation - mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID; - p2pConnectWithPinDisplay(mSavedPeerConfig); - } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) { - - // Devices setting persistent_reconnect to 0 in wpa_supplicant - // always defer the invocation request and return - // "information is currently unable" error. - // So, try another way to connect for interoperability. - mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID; - p2pConnectWithPinDisplay(mSavedPeerConfig); - } else if (status == P2pStatus.NO_COMMON_CHANNEL) { - transitionTo(mFrequencyConflictState); - } else { - handleGroupCreationFailure(); - transitionTo(mInactiveState); - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class FrequencyConflictState extends State { - private AlertDialog mFrequencyConflictDialog; - @Override - public void enter() { - if (DBG) logd(getName()); - notifyFrequencyConflict(); - } - - private void notifyFrequencyConflict() { - logd("Notify frequency conflict"); - Resources r = Resources.getSystem(); - - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message, - getDeviceName(mSavedPeerConfig.deviceAddress))) - .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - sendMessage(DROP_WIFI_USER_ACCEPT); - } - }) - .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - sendMessage(DROP_WIFI_USER_REJECT); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface arg0) { - sendMessage(DROP_WIFI_USER_REJECT); - } - }) - .create(); - - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - mFrequencyConflictDialog = dialog; - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: - case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: - loge(getName() + "group sucess during freq conflict!"); - break; - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - loge(getName() + "group started after freq conflict, handle anyway"); - deferMessage(message); - transitionTo(mGroupNegotiationState); - break; - case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: - case WifiMonitor.P2P_GROUP_REMOVED_EVENT: - case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: - // Ignore failures since we retry again - break; - case DROP_WIFI_USER_REJECT: - // User rejected dropping wifi in favour of p2p - handleGroupCreationFailure(); - transitionTo(mInactiveState); - break; - case DROP_WIFI_USER_ACCEPT: - // User accepted dropping wifi in favour of p2p - mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 1); - mTempoarilyDisconnectedWifi = true; - break; - case DISCONNECT_WIFI_RESPONSE: - // Got a response from wifistatemachine, retry p2p - if (DBG) logd(getName() + "Wifi disconnected, retry p2p"); - transitionTo(mInactiveState); - sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - public void exit() { - if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss(); - } - } - - class GroupCreatedState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - // Once connected, peer config details are invalid - mSavedPeerConfig.invalidate(); - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); - - updateThisDevice(WifiP2pDevice.CONNECTED); - - //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(); - } - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiMonitor.AP_STA_CONNECTED_EVENT: - WifiP2pDevice device = (WifiP2pDevice) message.obj; - String deviceAddress = device.deviceAddress; - // Clear timeout that was set when group was started. - mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); - if (deviceAddress != null) { - if (mPeers.get(deviceAddress) != null) { - mGroup.addClient(mPeers.get(deviceAddress)); - } else { - mGroup.addClient(deviceAddress); - } - mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED); - if (DBG) logd(getName() + " ap sta connected"); - sendPeersChangedBroadcast(); - } else { - loge("Connect on null device address, ignore"); - } - sendP2pConnectionChangedBroadcast(); - break; - case WifiMonitor.AP_STA_DISCONNECTED_EVENT: - device = (WifiP2pDevice) message.obj; - deviceAddress = device.deviceAddress; - if (deviceAddress != null) { - mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE); - if (mGroup.removeClient(deviceAddress)) { - if (DBG) logd("Removed client " + deviceAddress); - if (!mAutonomousGroup && mGroup.isClientListEmpty()) { - logd("Client list empty, remove non-persistent p2p group"); - mWifiNative.p2pGroupRemove(mGroup.getInterface()); - // We end up sending connection changed broadcast - // when this happens at exit() - } else { - // Notify when a client disconnects from group - sendP2pConnectionChangedBroadcast(); - } - } else { - if (DBG) logd("Failed to remove client " + deviceAddress); - for (WifiP2pDevice c : mGroup.getClientList()) { - if (DBG) logd("client " + c.deviceAddress); - } - } - sendPeersChangedBroadcast(); - if (DBG) logd(getName() + " ap sta disconnected"); - } else { - loge("Disconnect on unknown device: " + device); - } - break; - case DhcpStateMachine.CMD_POST_DHCP_ACTION: - DhcpResults dhcpResults = (DhcpResults) message.obj; - if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS && - dhcpResults != null) { - if (DBG) logd("DhcpResults: " + dhcpResults); - setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress); - sendP2pConnectionChangedBroadcast(); - //Turn on power save on client - mWifiNative.setP2pPowerSave(mGroup.getInterface(), true); - } else { - loge("DHCP failed"); - mWifiNative.p2pGroupRemove(mGroup.getInterface()); - } - break; - case WifiP2pManager.REMOVE_GROUP: - if (DBG) logd(getName() + " remove group"); - if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) { - transitionTo(mOngoingGroupRemovalState); - replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); - } else { - handleGroupRemoved(); - transitionTo(mInactiveState); - replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, - WifiP2pManager.ERROR); - } - break; - /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal - * handling since supplicant actually tries to reconnect after a temporary - * disconnect until group idle time out. Eventually, a group removal event - * will come when group has been removed. - * - * When there are connectivity issues during temporary disconnect, the application - * will also just remove the group. - * - * Treating network disconnection as group removal causes race conditions since - * supplicant would still maintain the group at that stage. - */ - case WifiMonitor.P2P_GROUP_REMOVED_EVENT: - if (DBG) logd(getName() + " group removed"); - handleGroupRemoved(); - transitionTo(mInactiveState); - 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 - if (mGroup.contains(device)) { - if (DBG) logd("Add device to lost list " + device); - mPeersLostDuringConnection.updateSupplicantDetails(device); - return HANDLED; - } - // Do the regular device lost handling - return NOT_HANDLED; - case WifiStateMachine.CMD_DISABLE_P2P_REQ: - sendMessage(WifiP2pManager.REMOVE_GROUP); - deferMessage(message); - break; - // This allows any client to join the GO during the - // WPS window - case WifiP2pManager.START_WPS: - WpsInfo wps = (WpsInfo) message.obj; - if (wps == null) { - replyToMessage(message, WifiP2pManager.START_WPS_FAILED); - break; - } - boolean ret = true; - if (wps.setup == WpsInfo.PBC) { - ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null); - } else { - if (wps.pin == null) { - String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface()); - try { - Integer.parseInt(pin); - notifyInvitationSent(pin, "any"); - } catch (NumberFormatException ignore) { - ret = false; - } - } else { - ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(), - wps.pin); - } - } - replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED : - WifiP2pManager.START_WPS_FAILED); - break; - case WifiP2pManager.CONNECT: - WifiP2pConfig config = (WifiP2pConfig) message.obj; - if (isConfigInvalid(config)) { - loge("Dropping connect requeset " + config); - replyToMessage(message, WifiP2pManager.CONNECT_FAILED); - break; - } - logd("Inviting device : " + config.deviceAddress); - mSavedPeerConfig = config; - if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) { - mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED); - sendPeersChangedBroadcast(); - replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); - } else { - replyToMessage(message, WifiP2pManager.CONNECT_FAILED, - WifiP2pManager.ERROR); - } - // TODO: figure out updating the status to declined when invitation is rejected - break; - case WifiMonitor.P2P_INVITATION_RESULT_EVENT: - P2pStatus status = (P2pStatus)message.obj; - if (status == P2pStatus.SUCCESS) { - // invocation was succeeded. - break; - } - loge("Invitation result " + status); - if (status == P2pStatus.UNKNOWN_P2P_GROUP) { - // target device has already removed the credential. - // So, remove this credential accordingly. - int netId = mGroup.getNetworkId(); - if (netId >= 0) { - if (DBG) logd("Remove unknown client from the list"); - if (!removeClientFromList(netId, - mSavedPeerConfig.deviceAddress, false)) { - // not found the client on the list - loge("Already removed the client, ignore"); - break; - } - // try invitation. - sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig); - } - } - 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: - WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj; - mSavedPeerConfig = new WifiP2pConfig(); - mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress; - if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { - mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; - } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { - mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; - mSavedPeerConfig.wps.pin = provDisc.pin; - } else { - mSavedPeerConfig.wps.setup = WpsInfo.PBC; - } - transitionTo(mUserAuthorizingJoinState); - break; - case WifiMonitor.P2P_GROUP_STARTED_EVENT: - loge("Duplicate group creation event notice, ignore"); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - public void exit() { - updateThisDevice(WifiP2pDevice.AVAILABLE); - resetWifiP2pInfo(); - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); - sendP2pConnectionChangedBroadcast(); - } - } - - class UserAuthorizingJoinState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - notifyInvitationReceived(); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: - case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: - case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: - //Ignore more client requests - break; - case PEER_CONNECTION_USER_ACCEPT: - //Stop discovery to avoid failure due to channel switch - mWifiNative.p2pStopFind(); - if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { - mWifiNative.startWpsPbc(mGroup.getInterface(), null); - } else { - mWifiNative.startWpsPinKeypad(mGroup.getInterface(), - mSavedPeerConfig.wps.pin); - } - transitionTo(mGroupCreatedState); - break; - case PEER_CONNECTION_USER_REJECT: - if (DBG) logd("User rejected incoming request"); - transitionTo(mGroupCreatedState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - @Override - public void exit() { - //TODO: dismiss dialog if not already done - } - } - - class OngoingGroupRemovalState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - // Group removal ongoing. Multiple calls - // end up removing persisted network. Do nothing. - case WifiP2pManager.REMOVE_GROUP: - replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); - break; - // Parent state will transition out of this state - // when removal is complete - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); - pw.println("mWifiP2pInfo " + mWifiP2pInfo); - pw.println("mGroup " + mGroup); - pw.println("mSavedPeerConfig " + mSavedPeerConfig); - pw.println("mSavedP2pGroup " + mSavedP2pGroup); - pw.println(); - } - - private void sendP2pStateChangedBroadcast(boolean enabled) { - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (enabled) { - intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, - WifiP2pManager.WIFI_P2P_STATE_ENABLED); - } else { - intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, - WifiP2pManager.WIFI_P2P_STATE_DISABLED); - } - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendP2pDiscoveryChangedBroadcast(boolean started) { - if (mDiscoveryStarted == started) return; - mDiscoveryStarted = started; - - if (DBG) logd("discovery change broadcast " + started); - - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ? - WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED : - WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendThisDeviceChangedBroadcast() { - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice)); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendPeersChangedBroadcast() { - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); - intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers)); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - - private void sendP2pConnectionChangedBroadcast() { - if (DBG) logd("sending p2p connection changed broadcast"); - Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT - | Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo)); - intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup)); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - mWifiChannel.sendMessage(WifiP2pService.P2P_CONNECTION_CHANGED, - new NetworkInfo(mNetworkInfo)); - } - - private void sendP2pPersistentGroupsChangedBroadcast() { - if (DBG) logd("sending p2p persistent groups changed broadcast"); - Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private void startDhcpServer(String intf) { - InterfaceConfiguration ifcg = null; - try { - ifcg = mNwService.getInterfaceConfig(intf); - ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress( - SERVER_ADDRESS), 24)); - ifcg.setInterfaceUp(); - mNwService.setInterfaceConfig(intf, ifcg); - /* This starts the dnsmasq server */ - mNwService.startTethering(DHCP_RANGE); - } catch (Exception e) { - loge("Error configuring interface " + intf + ", :" + e); - return; - } - - logd("Started Dhcp server on " + intf); - } - - private void stopDhcpServer(String intf) { - try { - mNwService.stopTethering(); - } catch (Exception e) { - loge("Error stopping Dhcp server" + e); - return; - } - - logd("Stopped Dhcp server"); - } - - private void notifyP2pEnableFailure() { - Resources r = Resources.getSystem(); - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) - .setMessage(r.getString(R.string.wifi_p2p_failed_message)) - .setPositiveButton(r.getString(R.string.ok), null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - } - - private void addRowToDialog(ViewGroup group, int stringId, String value) { - Resources r = Resources.getSystem(); - View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row, - group, false); - ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId)); - ((TextView) row.findViewById(R.id.value)).setText(value); - group.addView(row); - } - - private void notifyInvitationSent(String pin, String peerAddress) { - Resources r = Resources.getSystem(); - - 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.ok), null) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - } - - private void notifyInvitationReceived() { - Resources r = Resources.getSystem(); - final WpsInfo wps = mSavedPeerConfig.wps; - 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_from_message, getDeviceName( - mSavedPeerConfig.deviceAddress)); - - final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin); - - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title)) - .setView(textEntryView) - .setPositiveButton(r.getString(R.string.accept), new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (wps.setup == WpsInfo.KEYPAD) { - mSavedPeerConfig.wps.pin = pin.getText().toString(); - } - if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig); - sendMessage(PEER_CONNECTION_USER_ACCEPT); - } - }) - .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (DBG) logd(getName() + " ignore connect"); - sendMessage(PEER_CONNECTION_USER_REJECT); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface arg0) { - if (DBG) logd(getName() + " ignore connect"); - sendMessage(PEER_CONNECTION_USER_REJECT); - } - }) - .create(); - - //make the enter pin area or the display pin area visible - switch (wps.setup) { - case WpsInfo.KEYPAD: - if (DBG) logd("Enter pin section visible"); - textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE); - break; - case WpsInfo.DISPLAY: - if (DBG) logd("Shown pin section visible"); - addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin); - break; - default: - break; - } - - if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) == - Configuration.UI_MODE_TYPE_APPLIANCE) { - // For appliance devices, add a key listener which accepts. - dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { - - @Override - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - // TODO: make the actual key come from a config value. - if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { - sendMessage(PEER_CONNECTION_USER_ACCEPT); - dialog.dismiss(); - return true; - } - return false; - } - }); - // TODO: add timeout for this dialog. - // TODO: update UI in appliance mode to tell user what to do. - } - - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - } - - /** - * Synchronize the persistent group list between - * wpa_supplicant and mGroups. - */ - private void updatePersistentNetworks(boolean reload) { - String listStr = mWifiNative.listNetworks(); - if (listStr == null) return; - - boolean isSaveRequired = false; - String[] lines = listStr.split("\n"); - if (lines == null) return; - - if (reload) mGroups.clear(); - - // Skip the first line, which is a header - for (int i = 1; i < lines.length; i++) { - String[] result = lines[i].split("\t"); - if (result == null || result.length < 4) { - continue; - } - // network-id | ssid | bssid | flags - int netId = -1; - String ssid = result[1]; - String bssid = result[2]; - String flags = result[3]; - try { - netId = Integer.parseInt(result[0]); - } catch(NumberFormatException e) { - e.printStackTrace(); - continue; - } - - if (flags.indexOf("[CURRENT]") != -1) { - continue; - } - if (flags.indexOf("[P2P-PERSISTENT]") == -1) { - /* - * The unused profile is sometimes remained when the p2p group formation is failed. - * So, we clean up the p2p group here. - */ - if (DBG) logd("clean up the unused persistent group. netId=" + netId); - mWifiNative.removeNetwork(netId); - isSaveRequired = true; - continue; - } - - if (mGroups.contains(netId)) { - continue; - } - - WifiP2pGroup group = new WifiP2pGroup(); - group.setNetworkId(netId); - group.setNetworkName(ssid); - String mode = mWifiNative.getNetworkVariable(netId, "mode"); - if (mode != null && mode.equals("3")) { - group.setIsGroupOwner(true); - } - if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) { - group.setOwner(mThisDevice); - } else { - WifiP2pDevice device = new WifiP2pDevice(); - device.deviceAddress = bssid; - group.setOwner(device); - } - mGroups.add(group); - isSaveRequired = true; - } - - if (reload || isSaveRequired) { - mWifiNative.saveConfig(); - sendP2pPersistentGroupsChangedBroadcast(); - } - } - - /** - * A config is valid if it has a peer address that has already been - * discovered - * @return true if it is invalid, false otherwise - */ - private boolean isConfigInvalid(WifiP2pConfig config) { - if (config == null) return true; - if (TextUtils.isEmpty(config.deviceAddress)) return true; - if (mPeers.get(config.deviceAddress) == null) return true; - return false; - } - - /* TODO: The supplicant does not provide group capability changes as an event. - * Having it pushed as an event would avoid polling for this information right - * before a connection - */ - private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) { - /* Fetch & update group capability from supplicant on the device */ - int gc = mWifiNative.getGroupCapability(config.deviceAddress); - mPeers.updateGroupCapability(config.deviceAddress, gc); - return mPeers.get(config.deviceAddress); - } - - /** - * Start a p2p group negotiation and display pin if necessary - * @param config for the peer - */ - private void p2pConnectWithPinDisplay(WifiP2pConfig config) { - WifiP2pDevice dev = fetchCurrentDeviceDetails(config); - - String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner()); - try { - Integer.parseInt(pin); - notifyInvitationSent(pin, config.deviceAddress); - } catch (NumberFormatException ignore) { - // do nothing if p2pConnect did not return a pin - } - } - - /** - * Reinvoke a persistent group. - * - * @param config for the peer - * @return true on success, false on failure - */ - private boolean reinvokePersistentGroup(WifiP2pConfig config) { - WifiP2pDevice dev = fetchCurrentDeviceDetails(config); - - boolean join = dev.isGroupOwner(); - String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress); - if (DBG) logd("target ssid is " + ssid + " join:" + join); - - if (join && dev.isGroupLimit()) { - if (DBG) logd("target device reaches group limit."); - - // if the target group has reached the limit, - // try group formation. - join = false; - } else if (join) { - int netId = mGroups.getNetworkId(dev.deviceAddress, ssid); - if (netId >= 0) { - // Skip WPS and start 4way handshake immediately. - if (!mWifiNative.p2pGroupAdd(netId)) { - return false; - } - return true; - } - } - - if (!join && dev.isDeviceLimit()) { - loge("target device reaches the device limit."); - return false; - } - - if (!join && dev.isInvitationCapable()) { - int netId = WifiP2pGroup.PERSISTENT_NET_ID; - if (config.netId >= 0) { - if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) { - netId = config.netId; - } - } else { - netId = mGroups.getNetworkId(dev.deviceAddress); - } - if (netId < 0) { - netId = getNetworkIdFromClientList(dev.deviceAddress); - } - if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId); - if (netId >= 0) { - // Invoke the persistent group. - if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) { - // Save network id. It'll be used when an invitation result event is received. - config.netId = netId; - return true; - } else { - loge("p2pReinvoke() failed, update networks"); - updatePersistentNetworks(RELOAD); - return false; - } - } - } - - return false; - } - - /** - * Return the network id of the group owner profile which has the p2p client with - * the specified device address in it's client list. - * If more than one persistent group of the same address is present in its client - * lists, return the first one. - * - * @param deviceAddress p2p device address. - * @return the network id. if not found, return -1. - */ - private int getNetworkIdFromClientList(String deviceAddress) { - if (deviceAddress == null) return -1; - - Collection groups = mGroups.getGroupList(); - for (WifiP2pGroup group : groups) { - int netId = group.getNetworkId(); - String[] p2pClientList = getClientList(netId); - if (p2pClientList == null) continue; - for (String client : p2pClientList) { - if (deviceAddress.equalsIgnoreCase(client)) { - return netId; - } - } - } - return -1; - } - - /** - * Return p2p client list associated with the specified network id. - * @param netId network id. - * @return p2p client list. if not found, return null. - */ - private String[] getClientList(int netId) { - String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list"); - if (p2pClients == null) { - return null; - } - return p2pClients.split(" "); - } - - /** - * Remove the specified p2p client from the specified profile. - * @param netId network id of the profile. - * @param addr p2p client address to be removed. - * @param isRemovable if true, remove the specified profile if its client list becomes empty. - * @return whether removing the specified p2p client is successful or not. - */ - private boolean removeClientFromList(int netId, String addr, boolean isRemovable) { - StringBuilder modifiedClientList = new StringBuilder(); - String[] currentClientList = getClientList(netId); - boolean isClientRemoved = false; - if (currentClientList != null) { - for (String client : currentClientList) { - if (!client.equalsIgnoreCase(addr)) { - modifiedClientList.append(" "); - modifiedClientList.append(client); - } else { - isClientRemoved = true; - } - } - } - if (modifiedClientList.length() == 0 && isRemovable) { - // the client list is empty. so remove it. - if (DBG) logd("Remove unknown network"); - mGroups.remove(netId); - return true; - } - - if (!isClientRemoved) { - // specified p2p client is not found. already removed. - return false; - } - - if (DBG) logd("Modified client list: " + modifiedClientList); - if (modifiedClientList.length() == 0) { - modifiedClientList.append("\"\""); - } - mWifiNative.setNetworkVariable(netId, - "p2p_client_list", modifiedClientList.toString()); - mWifiNative.saveConfig(); - return true; - } - - private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) { - mWifiP2pInfo.groupFormed = true; - mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner(); - mWifiP2pInfo.groupOwnerAddress = serverInetAddress; - } - - private void resetWifiP2pInfo() { - mWifiP2pInfo.groupFormed = false; - mWifiP2pInfo.isGroupOwner = false; - mWifiP2pInfo.groupOwnerAddress = null; - } - - private String getDeviceName(String deviceAddress) { - WifiP2pDevice d = mPeers.get(deviceAddress); - if (d != null) { - return d.deviceName; - } - //Treat the address as name if there is no match - return deviceAddress; - } - - private String getPersistedDeviceName() { - String deviceName = Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.WIFI_P2P_DEVICE_NAME); - if (deviceName == null) { - /* 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(), - Settings.Secure.ANDROID_ID); - return "Android_" + id.substring(0,4); - } - return deviceName; - } - - private boolean setAndPersistDeviceName(String devName) { - if (devName == null) return false; - - if (!mWifiNative.setDeviceName(devName)) { - loge("Failed to set device name " + devName); - return false; - } - - mThisDevice.deviceName = devName; - mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); - - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.WIFI_P2P_DEVICE_NAME, devName); - sendThisDeviceChangedBroadcast(); - return true; - } - - private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) { - boolean success; - - if (!wfdInfo.isWfdEnabled()) { - success = mWifiNative.setWfdEnable(false); - } else { - success = - mWifiNative.setWfdEnable(true) - && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex()); - } - - if (!success) { - loge("Failed to set wfd properties"); - return false; - } - - mThisDevice.wfdInfo = wfdInfo; - sendThisDeviceChangedBroadcast(); - return true; - } - - private void initializeP2pSettings() { - mWifiNative.setPersistentReconnect(true); - mThisDevice.deviceName = getPersistedDeviceName(); - mWifiNative.setDeviceName(mThisDevice.deviceName); - // DIRECT-XY-DEVICENAME (XY is randomly generated) - mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); - mWifiNative.setDeviceType(mThisDevice.primaryDeviceType); - // Supplicant defaults to using virtual display with display - // which refers to a remote display. Use physical_display - mWifiNative.setConfigMethods("virtual_push_button physical_display keypad"); - // STA has higher priority over P2P - mWifiNative.setConcurrencyPriority("sta"); - - mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress(); - updateThisDevice(WifiP2pDevice.AVAILABLE); - if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress); - - mClientInfoList.clear(); - mWifiNative.p2pFlush(); - mWifiNative.p2pServiceFlush(); - mServiceTransactionId = 0; - mServiceDiscReqId = null; - - String countryCode = Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.WIFI_COUNTRY_CODE); - if (countryCode != null && !countryCode.isEmpty()) { - mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode); - } - - updatePersistentNetworks(RELOAD); - } - - private void updateThisDevice(int status) { - mThisDevice.status = status; - sendThisDeviceChangedBroadcast(); - } - - private void handleGroupCreationFailure() { - resetWifiP2pInfo(); - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null); - sendP2pConnectionChangedBroadcast(); - - // Remove only the peer we failed to connect to so that other devices discovered - // that have not timed out still remain in list for connection - boolean peersChanged = mPeers.remove(mPeersLostDuringConnection); - if (mPeers.remove(mSavedPeerConfig.deviceAddress) != null) { - peersChanged = true; - } - if (peersChanged) { - sendPeersChangedBroadcast(); - } - - mPeersLostDuringConnection.clear(); - mServiceDiscReqId = null; - sendMessage(WifiP2pManager.DISCOVER_PEERS); - } - - private void handleGroupRemoved() { - if (mGroup.isGroupOwner()) { - stopDhcpServer(mGroup.getInterface()); - } else { - if (DBG) logd("stop DHCP client"); - mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); - mDhcpStateMachine.doQuit(); - mDhcpStateMachine = null; - } - - try { - mNwService.clearInterfaceAddresses(mGroup.getInterface()); - } catch (Exception e) { - loge("Failed to clear addresses " + e); - } - NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES); - - // Clear any timeout that was set. This is essential for devices - // that reuse the main p2p interface for a created group. - mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); - - boolean peersChanged = false; - // Remove only peers part of the group, so that other devices discovered - // that have not timed out still remain in list for connection - for (WifiP2pDevice d : mGroup.getClientList()) { - if (mPeers.remove(d)) peersChanged = true; - } - if (mPeers.remove(mGroup.getOwner())) peersChanged = true; - if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true; - if (peersChanged) { - sendPeersChangedBroadcast(); - } - - mGroup = null; - mPeersLostDuringConnection.clear(); - mServiceDiscReqId = null; - - if (mTempoarilyDisconnectedWifi) { - mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0); - mTempoarilyDisconnectedWifi = false; - } - } - - //State machine initiated requests can have replyTo set to null indicating - //there are no recipients, we ignore those reply actions - private void replyToMessage(Message msg, int what) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessage(msg); - dstMsg.what = what; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - private void replyToMessage(Message msg, int what, int arg1) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessage(msg); - dstMsg.what = what; - dstMsg.arg1 = arg1; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - private void replyToMessage(Message msg, int what, Object obj) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessage(msg); - dstMsg.what = what; - dstMsg.obj = obj; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - /* arg2 on the source message has a hash code that needs to be retained in replies - * see WifiP2pManager for details */ - private Message obtainMessage(Message srcMsg) { - Message msg = Message.obtain(); - msg.arg2 = srcMsg.arg2; - return msg; - } - - @Override - protected void logd(String s) { - Slog.d(TAG, s); - } - - @Override - protected void loge(String s) { - Slog.e(TAG, s); - } - - /** - * Update service discovery request to wpa_supplicant. - */ - private boolean updateSupplicantServiceRequest() { - clearSupplicantServiceRequest(); - - StringBuffer sb = new StringBuffer(); - for (ClientInfo c: mClientInfoList.values()) { - int key; - WifiP2pServiceRequest req; - for (int i=0; i < c.mReqList.size(); i++) { - req = c.mReqList.valueAt(i); - if (req != null) { - sb.append(req.getSupplicantQuery()); - } - } - } - - if (sb.length() == 0) { - return false; - } - - mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString()); - if (mServiceDiscReqId == null) { - return false; - } - return true; - } - - /** - * Clear service discovery request in wpa_supplicant - */ - private void clearSupplicantServiceRequest() { - if (mServiceDiscReqId == null) return; - - mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId); - mServiceDiscReqId = null; - } - - /* TODO: We could track individual service adds separately and avoid - * having to do update all service requests on every new request - */ - private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) { - clearClientDeadChannels(); - ClientInfo clientInfo = getClientInfo(m, true); - if (clientInfo == null) { - return false; - } - - ++mServiceTransactionId; - //The Wi-Fi p2p spec says transaction id should be non-zero - if (mServiceTransactionId == 0) ++mServiceTransactionId; - req.setTransactionId(mServiceTransactionId); - clientInfo.mReqList.put(mServiceTransactionId, req); - - if (mServiceDiscReqId == null) { - return true; - } - - return updateSupplicantServiceRequest(); - } - - private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) { - ClientInfo clientInfo = getClientInfo(m, false); - if (clientInfo == null) { - return; - } - - //Application does not have transaction id information - //go through stored requests to remove - boolean removed = false; - for (int i=0; i deadClients = new ArrayList(); - - for (ClientInfo c : mClientInfoList.values()) { - Message msg = Message.obtain(); - msg.what = WifiP2pManager.PING; - msg.arg1 = 0; - msg.arg2 = 0; - msg.obj = null; - try { - c.mMessenger.send(msg); - } catch (RemoteException e) { - if (DBG) logd("detect dead channel"); - deadClients.add(c.mMessenger); - } - } - - for (Messenger m : deadClients) { - clearClientInfo(m); - } - } - - /** - * Return the specified ClientInfo. - * @param m Messenger - * @param createIfNotExist if true and the specified channel info does not exist, - * create new client info. - * @return the specified ClientInfo. - */ - private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) { - ClientInfo clientInfo = mClientInfoList.get(m); - - if (clientInfo == null && createIfNotExist) { - if (DBG) logd("add a new client"); - clientInfo = new ClientInfo(m); - mClientInfoList.put(m, clientInfo); - } - - return clientInfo; - } - - } - - /** - * Information about a particular client and we track the service discovery requests - * and the local services registered by the client. - */ - private class ClientInfo { - - /* - * A reference to WifiP2pManager.Channel handler. - * The response of this request is notified to WifiP2pManager.Channel handler - */ - private Messenger mMessenger; - - /* - * A service discovery request list. - */ - private SparseArray mReqList; - - /* - * A local service information list. - */ - private List mServList; - - private ClientInfo(Messenger m) { - mMessenger = m; - mReqList = new SparseArray(); - mServList = new ArrayList(); - } - } -} -- cgit v1.1