blob: 02b11914dfda4d26649bbec13fcae9c428e22672 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import static android.net.wifi.WifiManager.EASY_CONNECT_NETWORK_ROLE_AP;
import android.content.Context;
import android.hardware.wifi.supplicant.V1_2.DppAkm;
import android.hardware.wifi.supplicant.V1_2.DppNetRole;
import android.hardware.wifi.supplicant.V1_3.DppFailureCode;
import android.hardware.wifi.supplicant.V1_3.DppProgressCode;
import android.hardware.wifi.supplicant.V1_3.DppSuccessCode;
import android.net.wifi.EasyConnectStatusCallback;
import android.net.wifi.IDppCallback;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.WakeupMessage;
import com.android.server.wifi.WifiNative.DppEventCallback;
import com.android.server.wifi.util.ApConfigUtil;
import java.util.ArrayList;
import java.util.List;
/**
* DPP Manager class
* Implements the DPP Initiator APIs and callbacks
*/
public class DppManager {
private static final String TAG = "DppManager";
private final Handler mHandler;
private DppRequestInfo mDppRequestInfo = null;
private final WifiNative mWifiNative;
private String mClientIfaceName;
private boolean mVerboseLoggingEnabled;
WifiConfigManager mWifiConfigManager;
private final Context mContext;
@VisibleForTesting
public WakeupMessage mDppTimeoutMessage = null;
private final Clock mClock;
private static final String DPP_TIMEOUT_TAG = TAG + " Request Timeout";
private static final int DPP_TIMEOUT_MS = 40_000; // 40 seconds
private final DppMetrics mDppMetrics;
private final ScanRequestProxy mScanRequestProxy;
private final DppEventCallback mDppEventCallback = new DppEventCallback() {
@Override
public void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration) {
mHandler.post(() -> {
DppManager.this.onSuccessConfigReceived(newWifiConfiguration);
});
}
@Override
public void onSuccess(int dppStatusCode) {
mHandler.post(() -> {
DppManager.this.onSuccess(dppStatusCode);
});
}
@Override
public void onProgress(int dppStatusCode) {
mHandler.post(() -> {
DppManager.this.onProgress(dppStatusCode);
});
}
@Override
public void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList) {
mHandler.post(() -> {
DppManager.this.onFailure(dppStatusCode, ssid, channelList, bandList);
});
}
};
DppManager(Handler handler, WifiNative wifiNative, WifiConfigManager wifiConfigManager,
Context context, DppMetrics dppMetrics, ScanRequestProxy scanRequestProxy) {
mHandler = handler;
mWifiNative = wifiNative;
mWifiConfigManager = wifiConfigManager;
mWifiNative.registerDppEventCallback(mDppEventCallback);
mContext = context;
mClock = new Clock();
mDppMetrics = dppMetrics;
mScanRequestProxy = scanRequestProxy;
// Setup timer
mDppTimeoutMessage = new WakeupMessage(mContext, mHandler,
DPP_TIMEOUT_TAG, () -> {
timeoutDppRequest();
});
}
private static String encodeStringToHex(String str) {
if ((str.length() > 1) && (str.charAt(0) == '"') && (str.charAt(str.length() - 1) == '"')) {
// Remove the surrounding quotes
str = str.substring(1, str.length() - 1);
// Convert to Hex
char[] charsArray = str.toCharArray();
StringBuffer hexBuffer = new StringBuffer();
for (int i = 0; i < charsArray.length; i++) {
hexBuffer.append(Integer.toHexString((int) charsArray[i]));
}
return hexBuffer.toString();
}
return str;
}
private void timeoutDppRequest() {
logd("DPP timeout");
if (mDppRequestInfo == null) {
Log.e(TAG, "DPP timeout with no request info");
return;
}
// Clean up supplicant resources
if (!mWifiNative.stopDppInitiator(mClientIfaceName)) {
Log.e(TAG, "Failed to stop DPP Initiator");
}
// Clean up resources and let the caller know about the timeout
onFailure(DppFailureCode.TIMEOUT);
}
/**
* Start DPP request in Configurator-Initiator mode. The goal of this call is to send the
* selected Wi-Fi configuration to a remote peer so it could join that network.
*
* @param uid User ID
* @param binder Binder object
* @param enrolleeUri The Enrollee URI, scanned externally (e.g. via QR code)
* @param selectedNetworkId The selected Wi-Fi network ID to be sent
* @param enrolleeNetworkRole Network role of remote enrollee: STA or AP
* @param callback DPP Callback object
*/
public void startDppAsConfiguratorInitiator(int uid, IBinder binder,
String enrolleeUri, int selectedNetworkId,
@WifiManager.EasyConnectNetworkRole int enrolleeNetworkRole, IDppCallback callback) {
mDppMetrics.updateDppConfiguratorInitiatorRequests();
if (mDppRequestInfo != null) {
try {
Log.e(TAG, "DPP request already in progress");
Log.e(TAG, "Ongoing request UID: " + mDppRequestInfo.uid + ", new UID: "
+ uid);
mDppMetrics.updateDppFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_BUSY);
// On going DPP. Call the failure callback directly
callback.onFailure(EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_BUSY, null,
null, new int[0]);
} catch (RemoteException e) {
// Empty
}
return;
}
mClientIfaceName = mWifiNative.getClientInterfaceName();
if (mClientIfaceName == null) {
try {
Log.e(TAG, "Wi-Fi client interface does not exist");
// On going DPP. Call the failure callback directly
mDppMetrics.updateDppFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_GENERIC);
callback.onFailure(EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC,
null, null, new int[0]);
} catch (RemoteException e) {
// Empty
}
return;
}
WifiConfiguration selectedNetwork = mWifiConfigManager
.getConfiguredNetworkWithoutMasking(selectedNetworkId);
if (selectedNetwork == null) {
try {
Log.e(TAG, "Selected network is null");
// On going DPP. Call the failure callback directly
mDppMetrics.updateDppFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK);
callback.onFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK, null, null, new int[0]);
} catch (RemoteException e) {
// Empty
}
return;
}
String password = null;
String psk = null;
int securityAkm;
// Currently support either SAE mode or PSK mode
if (selectedNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) {
// SAE
password = selectedNetwork.preSharedKey;
securityAkm = DppAkm.SAE;
} else if (selectedNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
if (selectedNetwork.preSharedKey.matches(String.format("[0-9A-Fa-f]{%d}", 64))) {
// PSK
psk = selectedNetwork.preSharedKey;
} else {
// Passphrase
password = selectedNetwork.preSharedKey;
}
securityAkm = DppAkm.PSK;
} else {
try {
// Key management must be either PSK or SAE
Log.e(TAG, "Key management must be either PSK or SAE");
mDppMetrics.updateDppFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK);
callback.onFailure(
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK, null,
null, new int[0]);
} catch (RemoteException e) {
// Empty
}
return;
}
mDppRequestInfo = new DppRequestInfo();
mDppRequestInfo.uid = uid;
mDppRequestInfo.binder = binder;
mDppRequestInfo.callback = callback;
if (!linkToDeath(mDppRequestInfo)) {
// Notify failure and clean up
onFailure(EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC);
return;
}
logd("Interface " + mClientIfaceName + ": Initializing URI: " + enrolleeUri);
mDppRequestInfo.startTime = mClock.getElapsedSinceBootMillis();
mDppTimeoutMessage.schedule(mDppRequestInfo.startTime + DPP_TIMEOUT_MS);
// Send Enrollee URI and get a peer ID
int peerId = mWifiNative.addDppPeerUri(mClientIfaceName, enrolleeUri);
if (peerId < 0) {
Log.e(TAG, "DPP add URI failure");
// Notify failure and clean up
onFailure(DppFailureCode.INVALID_URI);
return;
}
mDppRequestInfo.peerId = peerId;
// Auth init
logd("Authenticating");
String ssidEncoded = encodeStringToHex(selectedNetwork.SSID);
String passwordEncoded = null;
if (password != null) {
passwordEncoded = encodeStringToHex(selectedNetwork.preSharedKey);
}
if (!mWifiNative.startDppConfiguratorInitiator(mClientIfaceName,
mDppRequestInfo.peerId, 0, ssidEncoded, passwordEncoded, psk,
enrolleeNetworkRole == EASY_CONNECT_NETWORK_ROLE_AP ? DppNetRole.AP
: DppNetRole.STA,
securityAkm)) {
Log.e(TAG, "DPP Start Configurator Initiator failure");
// Notify failure and clean up
onFailure(DppFailureCode.FAILURE);
return;
}
logd("Success: Started DPP Initiator with peer ID "
+ mDppRequestInfo.peerId);
}
/**
* Start DPP request in Enrollee-Initiator mode. The goal of this call is to receive a
* Wi-Fi configuration object from the peer configurator in order to join a network.
*
* @param uid User ID
* @param binder Binder object
* @param configuratorUri The Configurator URI, scanned externally (e.g. via QR code)
* @param callback DPP Callback object
*/
public void startDppAsEnrolleeInitiator(int uid, IBinder binder,
String configuratorUri, IDppCallback callback) {
mDppMetrics.updateDppEnrolleeInitiatorRequests();
if (mDppRequestInfo != null) {
try {
Log.e(TAG, "DPP request already in progress");
Log.e(TAG, "Ongoing request UID: " + mDppRequestInfo.uid + ", new UID: "
+ uid);
mDppMetrics.updateDppFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_BUSY);
// On going DPP. Call the failure callback directly
callback.onFailure(EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_BUSY, null,
null, new int[0]);
} catch (RemoteException e) {
// Empty
}
return;
}
mDppRequestInfo = new DppRequestInfo();
mDppRequestInfo.uid = uid;
mDppRequestInfo.binder = binder;
mDppRequestInfo.callback = callback;
if (!linkToDeath(mDppRequestInfo)) {
// Notify failure and clean up
onFailure(DppFailureCode.FAILURE);
return;
}
mDppRequestInfo.startTime = mClock.getElapsedSinceBootMillis();
mDppTimeoutMessage.schedule(mDppRequestInfo.startTime + DPP_TIMEOUT_MS);
mClientIfaceName = mWifiNative.getClientInterfaceName();
logd("Interface " + mClientIfaceName + ": Initializing URI: " + configuratorUri);
// Send Configurator URI and get a peer ID
int peerId = mWifiNative.addDppPeerUri(mClientIfaceName, configuratorUri);
if (peerId < 0) {
Log.e(TAG, "DPP add URI failure");
onFailure(DppFailureCode.INVALID_URI);
return;
}
mDppRequestInfo.peerId = peerId;
// Auth init
logd("Authenticating");
if (!mWifiNative.startDppEnrolleeInitiator(mClientIfaceName, mDppRequestInfo.peerId,
0)) {
Log.e(TAG, "DPP Start Enrollee Initiator failure");
// Notify failure and clean up
onFailure(DppFailureCode.FAILURE);
return;
}
logd("Success: Started DPP Initiator with peer ID "
+ mDppRequestInfo.peerId);
}
/**
* Stop a current DPP session
*
* @param uid User ID
*/
public void stopDppSession(int uid) {
if (mDppRequestInfo == null) {
logd("UID " + uid + " called stop DPP session with no active DPP session");
return;
}
if (mDppRequestInfo.uid != uid) {
Log.e(TAG, "UID " + uid + " called stop DPP session but UID " + mDppRequestInfo.uid
+ " has started it");
return;
}
// Clean up supplicant resources
if (!mWifiNative.stopDppInitiator(mClientIfaceName)) {
Log.e(TAG, "Failed to stop DPP Initiator");
}
cleanupDppResources();
logd("Success: Stopped DPP Initiator");
}
private void cleanupDppResources() {
logd("DPP clean up resources");
if (mDppRequestInfo == null) {
return;
}
// Cancel pending timeout
mDppTimeoutMessage.cancel();
// Remove the URI from the supplicant list
if (!mWifiNative.removeDppUri(mClientIfaceName, mDppRequestInfo.peerId)) {
Log.e(TAG, "Failed to remove DPP URI ID " + mDppRequestInfo.peerId);
}
mDppRequestInfo.binder.unlinkToDeath(mDppRequestInfo.dr, 0);
mDppRequestInfo = null;
}
private static class DppRequestInfo {
public int uid;
public IBinder binder;
public IBinder.DeathRecipient dr;
public int peerId;
public IDppCallback callback;
public long startTime;
@Override
public String toString() {
return new StringBuilder("DppRequestInfo: uid=").append(uid).append(", binder=").append(
binder).append(", dr=").append(dr)
.append(", callback=").append(callback)
.append(", peerId=").append(peerId).toString();
}
}
/**
* Enable vervose logging from DppManager
*
* @param verbose 0 to disable verbose logging, or any other value to enable.
*/
public void enableVerboseLogging(int verbose) {
mVerboseLoggingEnabled = verbose != 0 ? true : false;
}
private void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration) {
try {
logd("onSuccessConfigReceived");
if (mDppRequestInfo != null) {
long now = mClock.getElapsedSinceBootMillis();
mDppMetrics.updateDppOperationTime((int) (now - mDppRequestInfo.startTime));
NetworkUpdateResult networkUpdateResult = mWifiConfigManager
.addOrUpdateNetwork(newWifiConfiguration, mDppRequestInfo.uid);
if (networkUpdateResult.isSuccess()) {
mDppMetrics.updateDppEnrolleeSuccess();
mDppRequestInfo.callback.onSuccessConfigReceived(
networkUpdateResult.getNetworkId());
} else {
Log.e(TAG, "DPP configuration received, but failed to update network");
mDppMetrics.updateDppFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_CONFIGURATION);
mDppRequestInfo.callback.onFailure(EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_CONFIGURATION, null, null, new int[0]);
}
} else {
Log.e(TAG, "Unexpected null Wi-Fi configuration object");
}
} catch (RemoteException e) {
Log.e(TAG, "Callback failure");
}
// Success, DPP is complete. Clear the DPP session automatically
cleanupDppResources();
}
private void onSuccess(int dppStatusCode) {
try {
if (mDppRequestInfo == null) {
Log.e(TAG, "onSuccess event without a request information object");
return;
}
logd("onSuccess: " + dppStatusCode);
long now = mClock.getElapsedSinceBootMillis();
mDppMetrics.updateDppOperationTime((int) (now - mDppRequestInfo.startTime));
int dppSuccessCode;
// Convert from HAL codes to WifiManager/user codes
switch (dppStatusCode) {
case DppSuccessCode.CONFIGURATION_SENT:
mDppMetrics.updateDppR1CapableEnrolleeResponderDevices();
dppSuccessCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT;
break;
case DppSuccessCode.CONFIGURATION_APPLIED:
dppSuccessCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED;
break;
default:
Log.e(TAG, "onSuccess: unknown code " + dppStatusCode);
// Success, DPP is complete. Clear the DPP session automatically
cleanupDppResources();
return;
}
mDppMetrics.updateDppConfiguratorSuccess(dppSuccessCode);
mDppRequestInfo.callback.onSuccess(dppSuccessCode);
} catch (RemoteException e) {
Log.e(TAG, "Callback failure");
}
// Success, DPP is complete. Clear the DPP session automatically
cleanupDppResources();
}
private void onProgress(int dppStatusCode) {
try {
if (mDppRequestInfo == null) {
Log.e(TAG, "onProgress event without a request information object");
return;
}
logd("onProgress: " + dppStatusCode);
int dppProgressCode;
// Convert from HAL codes to WifiManager/user codes
switch (dppStatusCode) {
case DppProgressCode.AUTHENTICATION_SUCCESS:
dppProgressCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS;
break;
case DppProgressCode.RESPONSE_PENDING:
dppProgressCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING;
break;
case DppProgressCode.CONFIGURATION_SENT_WAITING_RESPONSE:
mDppMetrics.updateDppR2CapableEnrolleeResponderDevices();
dppProgressCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE;
break;
case DppProgressCode.CONFIGURATION_ACCEPTED:
dppProgressCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED;
break;
default:
Log.e(TAG, "onProgress: unknown code " + dppStatusCode);
return;
}
mDppRequestInfo.callback.onProgress(dppProgressCode);
} catch (RemoteException e) {
Log.e(TAG, "Callback failure");
}
}
private void onFailure(int dppStatusCode) {
onFailure(dppStatusCode, null, null, null);
}
/**
*
* This function performs the Enrollee compatibility check with the network.
* Compatibilty check is done based on the channel match.
* The logic looks into the scan cache and checks if network's
* operating channel match with one of the channel in enrollee's scanned channel list.
*
* @param ssid Network name.
* @param channelList contains the list of operating class/channels enrollee used to search for
* the network.
* Reference: DPP spec section: DPP Connection Status Object section.
* (eg for channelList: "81/1,2,3,4,5,6,7,8,9,10,11,117/40,115/48")
* @return True On compatibility check failures due to error conditions or
* when AP is not seen in scan cache or when AP is seen in scan cache and
* operating channel is included in enrollee's scanned channel list.
* False when network's operating channel is not included in Enrollee's
* scanned channel list.
*
*/
private boolean isEnrolleeCompatibleWithNetwork(String ssid, String channelList) {
if (ssid == null || channelList == null) {
return true;
}
SparseArray<int[]> dppChannelList = WifiManager.parseDppChannelList(channelList);
if (dppChannelList.size() == 0) {
Log.d(TAG, "No channels found after parsing channel list string");
return true;
}
List<Integer> freqList = new ArrayList<Integer>();
/* Convert the received operatingClass/channels to list of frequencies */
for (int i = 0; i < dppChannelList.size(); i++) {
/* Derive the band corresponding to operating class */
int operatingClass = dppChannelList.keyAt(i);
int[] channels = dppChannelList.get(operatingClass);
int band = ApConfigUtil.getBandFromOperatingClass(operatingClass);
if (band < 0) {
Log.e(TAG, "Band corresponding to the operating class: " + operatingClass
+ " not found in the table");
continue;
}
/* Derive frequency list from channel and band */
for (int j = 0; j < channels.length; j++) {
int freq = ApConfigUtil.convertChannelToFrequency(channels[j], band);
if (freq < 0) {
Log.e(TAG, "Invalid frequency after converting channel: " + channels[j]
+ " band: " + band);
continue;
}
freqList.add(freq);
}
}
if (freqList.size() == 0) {
Log.d(TAG, "frequency list is empty");
return true;
}
/* Check the scan cache for the network enrollee tried to find */
boolean isNetworkInScanCache = false;
boolean channelMatch = false;
for (ScanResult scanResult : mScanRequestProxy.getScanResults()) {
if (!ssid.equals(scanResult.SSID)) {
continue;
}
isNetworkInScanCache = true;
if (freqList.contains(scanResult.frequency)) {
channelMatch = true;
break;
}
}
if (isNetworkInScanCache & !channelMatch) {
Log.d(TAG, "Update the error code to NOT_COMPATIBLE"
+ " as enrollee didn't scan network's operating channel");
mDppMetrics.updateDppR2EnrolleeResponderIncompatibleConfiguration();
return false;
}
return true;
}
private void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList) {
try {
if (mDppRequestInfo == null) {
Log.e(TAG, "onFailure event without a request information object");
return;
}
logd("OnFailure: " + dppStatusCode);
long now = mClock.getElapsedSinceBootMillis();
mDppMetrics.updateDppOperationTime((int) (now - mDppRequestInfo.startTime));
int dppFailureCode;
// Convert from HAL codes to WifiManager/user codes
switch (dppStatusCode) {
case DppFailureCode.INVALID_URI:
dppFailureCode =
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_INVALID_URI;
break;
case DppFailureCode.AUTHENTICATION:
dppFailureCode =
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION;
break;
case DppFailureCode.NOT_COMPATIBLE:
dppFailureCode =
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE;
break;
case DppFailureCode.CONFIGURATION:
dppFailureCode =
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_CONFIGURATION;
break;
case DppFailureCode.BUSY:
dppFailureCode = EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_BUSY;
break;
case DppFailureCode.TIMEOUT:
dppFailureCode = EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_TIMEOUT;
break;
case DppFailureCode.NOT_SUPPORTED:
dppFailureCode =
EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED;
break;
case DppFailureCode.CANNOT_FIND_NETWORK:
// This is the only case where channel list is populated, according to the
// DPP spec section 6.3.5.2 DPP Connection Status Object
if (isEnrolleeCompatibleWithNetwork(ssid, channelList)) {
dppFailureCode =
EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK;
} else {
dppFailureCode =
EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE;
}
break;
case DppFailureCode.ENROLLEE_AUTHENTICATION:
dppFailureCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION;
break;
case DppFailureCode.CONFIGURATION_REJECTED:
dppFailureCode = EasyConnectStatusCallback
.EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION;
break;
case DppFailureCode.FAILURE:
default:
dppFailureCode = EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC;
break;
}
mDppMetrics.updateDppFailure(dppFailureCode);
if (bandList == null) {
bandList = new int[0];
}
mDppRequestInfo.callback.onFailure(dppFailureCode, ssid, channelList, bandList);
} catch (RemoteException e) {
Log.e(TAG, "Callback failure");
}
// All failures are fatal, clear the DPP session
cleanupDppResources();
}
private void logd(String message) {
if (mVerboseLoggingEnabled) {
Log.d(TAG, message);
}
}
private boolean linkToDeath(DppRequestInfo dppRequestInfo) {
// register for binder death
dppRequestInfo.dr = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (dppRequestInfo == null) {
return;
}
logd("binderDied: uid=" + dppRequestInfo.uid);
mHandler.post(() -> {
cleanupDppResources();
});
}
};
try {
dppRequestInfo.binder.linkToDeath(dppRequestInfo.dr, 0);
} catch (RemoteException e) {
Log.e(TAG, "Error on linkToDeath - " + e);
dppRequestInfo.dr = null;
return false;
}
return true;
}
}