in com/android/server/wifi/WifiStateMachine.java [4923:5502]
public boolean processMessage(Message message) {
WifiConfiguration config;
int netId;
boolean ok;
boolean didDisconnect;
String bssid;
String ssid;
NetworkUpdateResult result;
Set<Integer> removedNetworkIds;
int reasonCode;
boolean timedOut;
logStateAndMessage(message, this);
switch (message.what) {
case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
mWifiDiagnostics.captureBugReportData(
WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);
didBlackListBSSID = false;
bssid = (String) message.obj;
timedOut = message.arg1 > 0;
reasonCode = message.arg2;
Log.d(TAG, "Assocation Rejection event: bssid=" + bssid + " reason code="
+ reasonCode + " timedOut=" + Boolean.toString(timedOut));
if (bssid == null || TextUtils.isEmpty(bssid)) {
// If BSSID is null, use the target roam BSSID
bssid = mTargetRoamBSSID;
}
if (bssid != null) {
// If we have a BSSID, tell configStore to black list it
didBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid, false,
reasonCode);
}
mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,
WifiConfiguration.NetworkSelectionStatus
.DISABLED_ASSOCIATION_REJECTION);
mWifiConfigManager.setRecentFailureAssociationStatus(mTargetNetworkId,
reasonCode);
mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
// If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
mWifiInjector.getWifiLastResortWatchdog()
.noteConnectionFailureAndTriggerIfNeeded(
getTargetSsid(), bssid,
WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
break;
case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
mWifiDiagnostics.captureBugReportData(
WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);
mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
int disableReason = WifiConfiguration.NetworkSelectionStatus
.DISABLED_AUTHENTICATION_FAILURE;
// Check if this is a permanent wrong password failure.
if (isPermanentWrongPasswordFailure(mTargetNetworkId, message.arg2)) {
disableReason = WifiConfiguration.NetworkSelectionStatus
.DISABLED_BY_WRONG_PASSWORD;
WifiConfiguration targetedNetwork =
mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);
if (targetedNetwork != null) {
mWrongPasswordNotifier.onWrongPasswordError(
targetedNetwork.SSID);
}
}
mWifiConfigManager.updateNetworkSelectionStatus(
mTargetNetworkId, disableReason);
mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);
//If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
mWifiInjector.getWifiLastResortWatchdog()
.noteConnectionFailureAndTriggerIfNeeded(
getTargetSsid(), mTargetRoamBSSID,
WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
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");
// Rely on the fact that this will force us into killing supplicant and then
// restart supplicant from a clean state.
transitionTo(mSupplicantStoppingState);
sendMessage(CMD_START_SUPPLICANT);
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 (!isLinkDebouncing() && state == SupplicantState.DISCONNECTED &&
mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) {
if (mVerboseLoggingEnabled) {
log("Missed CTRL-EVENT-DISCONNECTED, disconnect");
}
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
}
// If we have COMPLETED a connection to a BSSID, start doing
// DNAv4/DNAv6 -style probing for on-link neighbors of
// interest (e.g. routers); harmless if none are configured.
if (state == SupplicantState.COMPLETED) {
mIpManager.confirmConfiguration();
}
break;
case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
if (message.arg1 == 1) {
mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST);
mWifiNative.disconnect();
mTemporarilyDisconnectWifi = true;
} else {
mWifiNative.reconnect();
mTemporarilyDisconnectWifi = false;
}
break;
case CMD_REMOVE_NETWORK:
if (!deleteNetworkConfigAndSendReply(message, false)) {
// failed to remove the config and caller was notified
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
break;
}
// we successfully deleted the network config
netId = message.arg1;
if (netId == mTargetNetworkId || netId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
sendMessage(CMD_DISCONNECT);
}
break;
case CMD_ENABLE_NETWORK:
boolean disableOthers = message.arg2 == 1;
netId = message.arg1;
if (disableOthers) {
// If the app has all the necessary permissions, this will trigger a connect
// attempt.
ok = connectToUserSelectNetwork(netId, message.sendingUid, false);
} else {
ok = mWifiConfigManager.enableNetwork(netId, false, message.sendingUid);
}
if (!ok) {
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
}
replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
break;
case WifiManager.DISABLE_NETWORK:
netId = message.arg1;
if (mWifiConfigManager.disableNetwork(netId, message.sendingUid)) {
replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
if (netId == mTargetNetworkId || netId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
sendMessage(CMD_DISCONNECT);
}
} else {
loge("Failed to disable network");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
WifiManager.ERROR);
}
break;
case CMD_DISABLE_EPHEMERAL_NETWORK:
config = mWifiConfigManager.disableEphemeralNetwork((String)message.obj);
if (config != null) {
if (config.networkId == mTargetNetworkId
|| config.networkId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
sendMessage(CMD_DISCONNECT);
}
}
break;
case CMD_SAVE_CONFIG:
ok = mWifiConfigManager.saveToStore(true);
replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
// Inform the backup manager about a data change
mBackupManagerProxy.notifyDataChanged();
break;
case WifiMonitor.SUP_REQUEST_IDENTITY:
int supplicantNetworkId = message.arg2;
netId = lookupFrameworkNetworkId(supplicantNetworkId);
boolean identitySent = false;
// For SIM & AKA/AKA' EAP method Only, get identity from ICC
if (targetWificonfiguration != null
&& targetWificonfiguration.networkId == netId
&& TelephonyUtil.isSimConfig(targetWificonfiguration)) {
String identity =
TelephonyUtil.getSimIdentity(getTelephonyManager(),
targetWificonfiguration);
if (identity != null) {
mWifiNative.simIdentityResponse(supplicantNetworkId, identity);
identitySent = true;
} else {
Log.e(TAG, "Unable to retrieve identity from Telephony");
}
}
if (!identitySent) {
// Supplicant lacks credentials to connect to that network, hence black list
ssid = (String) message.obj;
if (targetWificonfiguration != null && ssid != null
&& targetWificonfiguration.SSID != null
&& targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) {
mWifiConfigManager.updateNetworkSelectionStatus(
targetWificonfiguration.networkId,
WifiConfiguration.NetworkSelectionStatus
.DISABLED_AUTHENTICATION_NO_CREDENTIALS);
}
mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
StaEvent.DISCONNECT_GENERIC);
mWifiNative.disconnect();
}
break;
case WifiMonitor.SUP_REQUEST_SIM_AUTH:
logd("Received SUP_REQUEST_SIM_AUTH");
SimAuthRequestData requestData = (SimAuthRequestData) message.obj;
if (requestData != null) {
if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) {
handleGsmAuthRequest(requestData);
} else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA
|| requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) {
handle3GAuthRequest(requestData);
}
} else {
loge("Invalid sim auth request");
}
break;
case CMD_GET_MATCHING_CONFIG:
replyToMessage(message, message.what,
mPasspointManager.getMatchingWifiConfig((ScanResult) message.obj));
break;
case CMD_GET_MATCHING_OSU_PROVIDERS:
replyToMessage(message, message.what,
mPasspointManager.getMatchingOsuProviders((ScanResult) message.obj));
break;
case CMD_RECONNECT:
WorkSource workSource = (WorkSource) message.obj;
mWifiConnectivityManager.forceConnectivityScan(workSource);
break;
case CMD_REASSOCIATE:
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
mWifiNative.reassociate();
break;
case CMD_RELOAD_TLS_AND_RECONNECT:
if (mWifiConfigManager.needsUnlockedKeyStore()) {
logd("Reconnecting to give a chance to un-connected TLS networks");
mWifiNative.disconnect();
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
mWifiNative.reconnect();
}
break;
case CMD_START_ROAM:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
return HANDLED;
case CMD_START_CONNECT:
/* connect command coming from auto-join */
netId = message.arg1;
int uid = message.arg2;
bssid = (String) message.obj;
synchronized (mWifiReqCountLock) {
if (!hasConnectionRequests()) {
if (mNetworkAgent == null) {
loge("CMD_START_CONNECT but no requests and not connected,"
+ " bailing");
break;
} else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
loge("CMD_START_CONNECT but no requests and connected, but app "
+ "does not have sufficient permissions, bailing");
break;
}
}
}
config = mWifiConfigManager.getConfiguredNetworkWithPassword(netId);
logd("CMD_START_CONNECT sup state "
+ mSupplicantStateTracker.getSupplicantStateName()
+ " my state " + getCurrentState().getName()
+ " nid=" + Integer.toString(netId)
+ " roam=" + Boolean.toString(mIsAutoRoaming));
if (config == null) {
loge("CMD_START_CONNECT and no config, bail out...");
break;
}
mTargetNetworkId = netId;
setTargetBssid(config, bssid);
reportConnectionAttemptStart(config, mTargetRoamBSSID,
WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
if (mWifiNative.connectToNetwork(config)) {
mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
targetWificonfiguration = config;
mIsAutoRoaming = false;
if (isLinkDebouncing()) {
transitionTo(mRoamingState);
} else if (getCurrentState() != mDisconnectedState) {
transitionTo(mDisconnectingState);
}
} else {
loge("CMD_START_CONNECT Failed to start connection to network " + config);
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
break;
}
break;
case CMD_REMOVE_APP_CONFIGURATIONS:
removedNetworkIds =
mWifiConfigManager.removeNetworksForApp((ApplicationInfo) message.obj);
if (removedNetworkIds.contains(mTargetNetworkId) ||
removedNetworkIds.contains(mLastNetworkId)) {
// Disconnect and let autojoin reselect a new network.
sendMessage(CMD_DISCONNECT);
}
break;
case CMD_REMOVE_USER_CONFIGURATIONS:
removedNetworkIds =
mWifiConfigManager.removeNetworksForUser((Integer) message.arg1);
if (removedNetworkIds.contains(mTargetNetworkId) ||
removedNetworkIds.contains(mLastNetworkId)) {
// Disconnect and let autojoin reselect a new network.
sendMessage(CMD_DISCONNECT);
}
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
*/
netId = message.arg1;
config = (WifiConfiguration) message.obj;
mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
boolean hasCredentialChanged = false;
// New network addition.
if (config != null) {
result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
if (!result.isSuccess()) {
loge("CONNECT_NETWORK adding/updating config=" + config + " failed");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
break;
}
netId = result.getNetworkId();
hasCredentialChanged = result.hasCredentialChanged();
}
if (!connectToUserSelectNetwork(
netId, message.sendingUid, hasCredentialChanged)) {
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.NOT_AUTHORIZED);
break;
}
mWifiMetrics.logStaEvent(StaEvent.TYPE_CONNECT_NETWORK, config);
broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
break;
case WifiManager.SAVE_NETWORK:
result = saveNetworkConfigAndSendReply(message);
netId = result.getNetworkId();
if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
if (result.hasCredentialChanged()) {
config = (WifiConfiguration) message.obj;
// The network credentials changed and we're connected to this network,
// start a new connection with the updated credentials.
logi("SAVE_NETWORK credential changed for config=" + config.configKey()
+ ", Reconnecting.");
startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
} else {
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
mIpManager.setHttpProxy(
getCurrentWifiConfiguration().getHttpProxy());
}
if (result.hasIpChanged()) {
// The current connection configuration was changed
// We switched from DHCP to static or from static to DHCP, or the
// static IP address has changed.
log("Reconfiguring IP on connection");
// TODO(b/36576642): clear addresses and disable IPv6
// to simplify obtainingIpState.
transitionTo(mObtainingIpState);
}
}
}
break;
case WifiManager.FORGET_NETWORK:
if (!deleteNetworkConfigAndSendReply(message, true)) {
// Caller was notified of failure, nothing else to do
break;
}
// the network was deleted
netId = message.arg1;
if (netId == mTargetNetworkId || netId == mLastNetworkId) {
// Disconnect and let autojoin reselect a new network
sendMessage(CMD_DISCONNECT);
}
break;
case WifiManager.START_WPS:
WpsInfo wpsInfo = (WpsInfo) message.obj;
if (wpsInfo == null) {
loge("Cannot start WPS with null WpsInfo object");
replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
break;
}
WpsResult wpsResult = new WpsResult();
// TODO(b/32898136): Not needed when we start deleting networks from supplicant
// on disconnect.
if (!mWifiNative.removeAllNetworks()) {
loge("Failed to remove networks before WPS");
}
switch (wpsInfo.setup) {
case WpsInfo.PBC:
if (mWifiNative.startWpsPbc(wpsInfo.BSSID)) {
wpsResult.status = WpsResult.Status.SUCCESS;
} else {
Log.e(TAG, "Failed to start WPS push button configuration");
wpsResult.status = WpsResult.Status.FAILURE;
}
break;
case WpsInfo.KEYPAD:
if (mWifiNative.startWpsRegistrar(wpsInfo.BSSID, wpsInfo.pin)) {
wpsResult.status = WpsResult.Status.SUCCESS;
} else {
Log.e(TAG, "Failed to start WPS push button configuration");
wpsResult.status = WpsResult.Status.FAILURE;
}
break;
case WpsInfo.DISPLAY:
wpsResult.pin = mWifiNative.startWpsPinDisplay(wpsInfo.BSSID);
if (!TextUtils.isEmpty(wpsResult.pin)) {
wpsResult.status = WpsResult.Status.SUCCESS;
} else {
Log.e(TAG, "Failed to start WPS pin method configuration");
wpsResult.status = WpsResult.Status.FAILURE;
}
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 CMD_ASSOCIATED_BSSID:
// This is where we can confirm the connection BSSID. Use it to find the
// right ScanDetail to populate metrics.
String someBssid = (String) message.obj;
if (someBssid != null) {
// Get the ScanDetail associated with this BSSID.
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(mTargetNetworkId);
if (scanDetailCache != null) {
mWifiMetrics.setConnectionScanDetail(scanDetailCache.getScanDetail(
someBssid));
}
}
return NOT_HANDLED;
case WifiMonitor.NETWORK_CONNECTION_EVENT:
if (mVerboseLoggingEnabled) log("Network connection established");
mLastNetworkId = lookupFrameworkNetworkId(message.arg1);
mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
mLastBssid = (String) message.obj;
reasonCode = message.arg2;
// TODO: This check should not be needed after WifiStateMachinePrime refactor.
// Currently, the last connected network configuration is left in
// wpa_supplicant, this may result in wpa_supplicant initiating connection
// to it after a config store reload. Hence the old network Id lookups may not
// work, so disconnect the network and let network selector reselect a new
// network.
config = getCurrentWifiConfiguration();
if (config != null) {
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(config.networkId);
if (scanDetailCache != null && mLastBssid != null) {
ScanResult scanResult = scanDetailCache.getScanResult(mLastBssid);
if (scanResult != null) {
mWifiInfo.setFrequency(scanResult.frequency);
}
}
mWifiConnectivityManager.trackBssid(mLastBssid, true, reasonCode);
// We need to get the updated pseudonym from supplicant for EAP-SIM/AKA/AKA'
if (config.enterpriseConfig != null
&& TelephonyUtil.isSimEapMethod(
config.enterpriseConfig.getEapMethod())) {
String anonymousIdentity = mWifiNative.getEapAnonymousIdentity();
if (anonymousIdentity != null) {
config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
} else {
Log.d(TAG, "Failed to get updated anonymous identity"
+ " from supplicant, reset it in WifiConfiguration.");
config.enterpriseConfig.setAnonymousIdentity(null);
}
mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID);
}
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mObtainingIpState);
} else {
logw("Connected to unknown networkId " + mLastNetworkId
+ ", disconnecting...");
sendMessage(CMD_DISCONNECT);
}
break;
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
// Calling handleNetworkDisconnect here is redundant because we might already
// have called it when leaving L2ConnectedState to go to disconnecting state
// or thru other path
// We should normally check the mWifiInfo or mLastNetworkId so as to check
// if they are valid, and only in this case call handleNEtworkDisconnect,
// TODO: this should be fixed for a L MR release
// The side effect of calling handleNetworkDisconnect twice is that a bunch of
// idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
// at the chip etc...
if (mVerboseLoggingEnabled) log("ConnectModeState: Network connection lost ");
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
break;
case CMD_QUERY_OSU_ICON:
mPasspointManager.queryPasspointIcon(
((Bundle) message.obj).getLong(EXTRA_OSU_ICON_QUERY_BSSID),
((Bundle) message.obj).getString(EXTRA_OSU_ICON_QUERY_FILENAME));
break;
case CMD_MATCH_PROVIDER_NETWORK:
// TODO(b/31065385): Passpoint config management.
replyToMessage(message, message.what, 0);
break;
case CMD_ADD_OR_UPDATE_PASSPOINT_CONFIG:
PasspointConfiguration passpointConfig = (PasspointConfiguration) message.obj;
if (mPasspointManager.addOrUpdateProvider(passpointConfig, message.arg1)) {
String fqdn = passpointConfig.getHomeSp().getFqdn();
if (isProviderOwnedNetwork(mTargetNetworkId, fqdn)
|| isProviderOwnedNetwork(mLastNetworkId, fqdn)) {
logd("Disconnect from current network since its provider is updated");
sendMessage(CMD_DISCONNECT);
}
replyToMessage(message, message.what, SUCCESS);
} else {
replyToMessage(message, message.what, FAILURE);
}
break;
case CMD_REMOVE_PASSPOINT_CONFIG:
String fqdn = (String) message.obj;
if (mPasspointManager.removeProvider(fqdn)) {
if (isProviderOwnedNetwork(mTargetNetworkId, fqdn)
|| isProviderOwnedNetwork(mLastNetworkId, fqdn)) {
logd("Disconnect from current network since its provider is removed");
sendMessage(CMD_DISCONNECT);
}
replyToMessage(message, message.what, SUCCESS);
} else {
replyToMessage(message, message.what, FAILURE);
}
break;
case CMD_ENABLE_P2P:
p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}