SupplicantStaIfaceHal.java revision 82c5c5f2ee520a1066cf5d6421885bb53bbfe269
13ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar/*
23ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * Copyright (C) 2017 The Android Open Source Project
33ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar *
43ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * Licensed under the Apache License, Version 2.0 (the "License");
53ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * you may not use this file except in compliance with the License.
63ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * You may obtain a copy of the License at
73ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar *
83ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar *      http://www.apache.org/licenses/LICENSE-2.0
93ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar *
103ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * Unless required by applicable law or agreed to in writing, software
113ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * distributed under the License is distributed on an "AS IS" BASIS,
123ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * See the License for the specific language governing permissions and
143ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * limitations under the License.
153ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar */
163ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarpackage com.android.server.wifi;
173ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
183ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQP3GPPNetwork;
193ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPDomName;
203ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPIPAddrAvailability;
213ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPNAIRealm;
223ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPRoamingConsortium;
233ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.ANQPVenueName;
243ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSConnCapability;
253ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSFriendlyName;
263ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSOSUProviders;
273ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport static com.android.server.wifi.hotspot2.anqp.Constants.ANQPElementType.HSWANMetrics;
283ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
293ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.content.Context;
303ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.ISupplicant;
313ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.ISupplicantIface;
323ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork;
3387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface;
343ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback;
353ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork;
363ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.IfaceType;
373ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.SupplicantStatus;
383ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode;
393ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hardware.wifi.supplicant.V1_0.WpsConfigMethods;
403ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hidl.manager.V1_0.IServiceManager;
413ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.hidl.manager.V1_0.IServiceNotification;
4287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarimport android.net.IpConfiguration;
433ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.net.wifi.SupplicantState;
443ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.net.wifi.WifiConfiguration;
453ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.net.wifi.WifiSsid;
463ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.os.RemoteException;
473ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.util.Log;
483ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport android.util.SparseArray;
493ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
503ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport com.android.server.wifi.hotspot2.AnqpEvent;
5187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarimport com.android.server.wifi.hotspot2.IconEvent;
523ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport com.android.server.wifi.hotspot2.WnmData;
533ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport com.android.server.wifi.hotspot2.anqp.ANQPElement;
543ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport com.android.server.wifi.hotspot2.anqp.ANQPParser;
553ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport com.android.server.wifi.hotspot2.anqp.Constants;
563ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport com.android.server.wifi.util.NativeUtil;
573ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
583ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.io.IOException;
593ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.nio.BufferUnderflowException;
6087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainarimport java.nio.ByteBuffer;
613ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.nio.ByteOrder;
623ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.util.ArrayList;
633ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.util.HashMap;
643ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.util.List;
653ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.util.Map;
663ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.util.regex.Matcher;
673ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarimport java.util.regex.Pattern;
683ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
693ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar/**
703ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * Hal calls for bring up/shut down of the supplicant daemon and for
713ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar * sending requests to the supplicant daemon
723ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar */
733ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainarpublic class SupplicantStaIfaceHal {
743ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private static final boolean DBG = false;
753ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private static final String TAG = "SupplicantStaIfaceHal";
763ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private static final String SERVICE_MANAGER_NAME = "manager";
773ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    /**
783ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Regex pattern for extracting the wps device type bytes.
793ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
803ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     */
813ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private static final Pattern WPS_DEVICE_TYPE_PATTERN =
823ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$");
833ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
843ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private IServiceManager mIServiceManager = null;
853ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    // Supplicant HAL interface objects
863ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private ISupplicant mISupplicant;
873ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private ISupplicantStaIface mISupplicantStaIface;
883ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private String mIfaceName;
893ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    // Currently configured network in wpa_supplicant
903ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private SupplicantStaNetworkHal mCurrentNetwork;
913ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    // Currently configured network's framework network Id.
923ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private int mFrameworkNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
933ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private final Object mLock = new Object();
943ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private final Context mContext;
953ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private final WifiMonitor mWifiMonitor;
963ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
973ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    public SupplicantStaIfaceHal(Context context, WifiMonitor monitor) {
983ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        mContext = context;
993ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        mWifiMonitor = monitor;
1003ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
1013ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
1023ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    /**
1033ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Registers a service notification for the ISupplicant service, which triggers intialization of
1043ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * the ISupplicantStaIface
1053ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * @return true if the service notification was successfully registered
1063ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     */
1073ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    public boolean initialize() {
1083ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        if (DBG) Log.i(TAG, "Registering ISupplicant service ready callback.");
1093ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        synchronized (mLock) {
1103ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            mISupplicant = null;
1113ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            mISupplicantStaIface = null;
1123ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            if (mIServiceManager != null) {
1133ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                // Already have an IServiceManager and serviceNotification registered, don't
1143ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                // don't register another.
1153ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return true;
1163ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
1173ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            try {
1183ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                mIServiceManager = getServiceManagerMockable();
1193ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                if (mIServiceManager == null) {
1203ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    Log.e(TAG, "Failed to get HIDL Service Manager");
1213ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    return false;
1223ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                }
1233ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                if (!mIServiceManager.linkToDeath(cookie -> {
1243ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    Log.wtf(TAG, "IServiceManager died: cookie=" + cookie);
1253ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    synchronized (mLock) {
1263ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        supplicantServiceDiedHandler();
1273ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        mIServiceManager = null; // Will need to register a new ServiceNotification
1283ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    }
12987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                }, 0)) {
1303ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
1313ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    supplicantServiceDiedHandler();
1323ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    mIServiceManager = null; // Will need to register a new ServiceNotification
1333ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    return false;
1343ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                }
1353ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                IServiceNotification serviceNotificationCb = new IServiceNotification.Stub() {
1363ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    public void onRegistration(String fqName, String name, boolean preexisting) {
1373ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        synchronized (mLock) {
1383ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            if (DBG) {
1393ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
1403ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                        + ", " + name + " preexisting=" + preexisting);
1413ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            }
1423ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            if (!initSupplicantService() || !initSupplicantStaIface()) {
1433ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                Log.e(TAG, "initalizing ISupplicantIfaces failed.");
1443ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                supplicantServiceDiedHandler();
1453ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            } else {
1463ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                Log.i(TAG, "Completed initialization of ISupplicant interfaces.");
1473ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            }
1483ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        }
1493ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    }
1503ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                };
1513ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it
1523ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                   exists */
1533ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                if (!mIServiceManager.registerForNotifications(ISupplicant.kInterfaceName,
1543ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        "", serviceNotificationCb)) {
1553ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    Log.e(TAG, "Failed to register for notifications to "
1563ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            + ISupplicant.kInterfaceName);
1573ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    mIServiceManager = null; // Will need to register a new ServiceNotification
1583ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    return false;
1593ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                }
1603ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            } catch (RemoteException e) {
1613ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: "
1623ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        + e);
1633ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                supplicantServiceDiedHandler();
1643ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
1653ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            return true;
1663ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
1673ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
1683ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
1693ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private boolean initSupplicantService() {
1703ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        synchronized (mLock) {
17187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            try {
1723ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                mISupplicant = getSupplicantMockable();
1733ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            } catch (RemoteException e) {
1743ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                Log.e(TAG, "ISupplicant.getService exception: " + e);
1753ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return false;
1763ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
1773ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            if (mISupplicant == null) {
1783ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup");
1793ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return false;
18087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
1813ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
1823ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        return true;
1833ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
1843ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
1853ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private boolean initSupplicantStaIface() {
1863ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        synchronized (mLock) {
1873ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            /** List all supplicant Ifaces */
1883ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>();
18987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            try {
1903ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                mISupplicant.listInterfaces((SupplicantStatus status,
1913ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
1923ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    if (status.code != SupplicantStatusCode.SUCCESS) {
1933ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
1943ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        return;
1953ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    }
1963ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    supplicantIfaces.addAll(ifaces);
1973ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                });
19887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            } catch (RemoteException e) {
1993ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
2003ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return false;
2013ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
2023ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            if (supplicantIfaces.size() == 0) {
2033ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
2043ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return false;
2053ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
2063ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
2073ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            Mutable<String> ifaceName = new Mutable<>();
2083ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
2093ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                if (ifaceInfo.type == IfaceType.STA) {
2103ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    try {
2113ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        mISupplicant.getInterface(ifaceInfo,
2123ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                (SupplicantStatus status, ISupplicantIface iface) -> {
2133ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                if (status.code != SupplicantStatusCode.SUCCESS) {
2143ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                    Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
2153ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                    return;
2163ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                }
2173ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                                supplicantIface.value = iface;
2183ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                            });
2193ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    } catch (RemoteException e) {
2203ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        Log.e(TAG, "ISupplicant.getInterface exception: " + e);
2213ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                        return false;
2223ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    }
2233ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    ifaceName.value = ifaceInfo.name;
2243ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    break;
2253ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                }
22687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
2273ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            if (supplicantIface.value == null) {
2283ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                Log.e(TAG, "initSupplicantStaIface got null iface");
2293ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return false;
2303ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
2313ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value);
2323ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            mIfaceName = ifaceName.value;
2333ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            if (!registerCallback(new SupplicantStaIfaceHalCallback())) {
2343ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                return false;
2353ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            }
2363ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            return true;
2373ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
2383ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2393ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2403ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private void supplicantServiceDiedHandler() {
2413ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        synchronized (mLock) {
2423ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            mISupplicant = null;
2433ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            mISupplicantStaIface = null;
2443ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
2453ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2463ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2473ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    /**
2483ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Signals whether Initialization completed successfully. Only necessary for testing, is not
2493ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * needed to guard calls etc.
2503ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     */
2513ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    public boolean isInitializationComplete() {
2523ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        return mISupplicantStaIface != null;
2533ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2543ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2553ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    /**
2563ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Wrapper functions to access static HAL methods, created to be mockable in unit tests
2573ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     */
2583ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    protected IServiceManager getServiceManagerMockable() throws RemoteException {
2593ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        return IServiceManager.getService(SERVICE_MANAGER_NAME);
2603ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2613ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2623ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    protected ISupplicant getSupplicantMockable() throws RemoteException {
2633ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        return ISupplicant.getService();
2643ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2653ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2663ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) {
2673ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        return ISupplicantStaIface.asInterface(iface.asBinder());
2683ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2693ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2703ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    /**
2713ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Add a network configuration to wpa_supplicant.
2723ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     *
2733ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * @param config Config corresponding to the network.
2743ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * @return SupplicantStaNetwork of the added network in wpa_supplicant.
2753ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     */
2763ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    private SupplicantStaNetworkHal addNetwork(WifiConfiguration config) {
2773ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        logi("addSupplicantStaNetwork via HIDL");
2783ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        if (config == null) {
2793ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            loge("Cannot add NULL network!");
2803ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            return null;
2813ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
2823ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        SupplicantStaNetworkHal network = addNetwork();
2833ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        if (network == null) {
2843ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            loge("Failed to add a network!");
2853ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            return null;
2863ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
2873ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        if (network.saveWifiConfiguration(config)) {
2883ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            return network;
2893ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        } else {
2903ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            loge("Failed to save variables for: " + config.configKey());
2913ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar            return null;
2923ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        }
2933ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    }
2943ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
2953ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar    /**
2963ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * Add the provided network configuration to wpa_supplicant and initiate connection to it.
2973ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * This method does the following:
2983ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * 1. Triggers disconnect command to wpa_supplicant (if |shouldDisconnect| is true).
2993ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * 2. Remove any existing network in wpa_supplicant.
3003ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar     * 3. Add a new network to wpa_supplicant.
30187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * 4. Save the provided configuration to wpa_supplicant.
30287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * 5. Select the new network in wpa_supplicant.
30387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     *
30487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @param config WifiConfiguration parameters for the provided network.
30587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @param shouldDisconnect whether to trigger a disconnection or not.
30687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @return {@code true} if it succeeds, {@code false} otherwise
30787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     */
30887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    public boolean connectToNetwork(WifiConfiguration config, boolean shouldDisconnect) {
30987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        mFrameworkNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
31087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        mCurrentNetwork = null;
31187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        logd("connectToNetwork " + config.configKey()
31287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                + " (shouldDisconnect " + shouldDisconnect + ")");
31387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (shouldDisconnect && !disconnect()) {
31487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            loge("Failed to trigger disconnect");
31587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
31687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
31787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (!removeAllNetworks()) {
31887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            loge("Failed to remove existing networks");
31987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
32087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
32187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        mCurrentNetwork = addNetwork(config);
32287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (mCurrentNetwork == null) {
32387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            loge("Failed to add/save network configuration: " + config.configKey());
32487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
32587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
32687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (!mCurrentNetwork.select()) {
32787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            loge("Failed to select network configuration: " + config.configKey());
32887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
32987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
33087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        mFrameworkNetworkId = config.networkId;
33187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        return true;
33287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
33387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
33487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    /**
33587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * Initiates roaming to the already configured network in wpa_supplicant. If the network
33687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * configuration provided does not match the already configured network, then this triggers
33787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * a new connection attempt (instead of roam).
33887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * 1. First check if we're attempting to connect to the same network as we currently have
33987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * configured.
34087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * 2. Set the new bssid for the network in wpa_supplicant.
34187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * 3. Trigger reassociate command to wpa_supplicant.
34287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     *
34387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @param config WifiConfiguration parameters for the provided network.
34487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @return {@code true} if it succeeds, {@code false} otherwise
34587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     */
34687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    public boolean roamToNetwork(WifiConfiguration config) {
34787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (mFrameworkNetworkId != config.networkId || mCurrentNetwork == null) {
34887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
34987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    + "Current network ID: " + mFrameworkNetworkId);
35087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return connectToNetwork(config, false);
35187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
35287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
35387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")");
35487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (!mCurrentNetwork.setBssid(bssid)) {
35587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            loge("Failed to set new bssid on network: " + config.configKey());
35687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
35787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
35887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (!reassociate()) {
35987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            loge("Failed to trigger reassociate");
36087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
36187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
36287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        return true;
36387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    }
36487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
36587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    /**
36687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * Load all the configured networks from wpa_supplicant.
36787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     *
36887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @param configs       Map of configuration key to configuration objects corresponding to all
36987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     *                      the networks.
37087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
37187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     * @return true if succeeds, false otherwise.
37287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar     */
37387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar    public boolean loadNetworks(Map<String, WifiConfiguration> configs,
37487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                SparseArray<Map<String, String>> networkExtras) {
37587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        List<Integer> networkIds = listNetworks();
37687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        if (networkIds == null) {
37787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            Log.e(TAG, "Failed to list networks");
37887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            return false;
37987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        }
38087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        for (Integer networkId : networkIds) {
38187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            SupplicantStaNetworkHal network = getNetwork(networkId);
38287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if (network == null) {
38387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                Log.e(TAG, "Failed to get network with ID: " + networkId);
38487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                return false;
38587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
38687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            WifiConfiguration config = new WifiConfiguration();
38787d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            Map<String, String> networkExtra = new HashMap<>();
38887d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            if (!network.loadWifiConfiguration(config, networkExtra)) {
38987d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId);
39087d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                return false;
39187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            }
39287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            // Set the default IP assignments.
39387d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            config.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
39487d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            config.setProxySettings(IpConfiguration.ProxySettings.NONE);
39587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar
39687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar            networkExtras.put(networkId, networkExtra);
397            String configKey = networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY);
398            final WifiConfiguration duplicateConfig = configs.put(configKey, config);
399            if (duplicateConfig != null) {
400                // The network is already known. Overwrite the duplicate entry.
401                Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId);
402                removeNetwork(duplicateConfig.networkId);
403                networkExtras.remove(duplicateConfig.networkId);
404            }
405        }
406        return true;
407    }
408
409    /**
410     * Remove all networks from supplicant
411     */
412    public boolean removeAllNetworks() {
413        synchronized (mLock) {
414            ArrayList<Integer> networks = listNetworks();
415            if (networks == null) {
416                Log.e(TAG, "removeAllNetworks failed, got null networks");
417                return false;
418            }
419            for (int id : networks) {
420                if (!removeNetwork(id)) {
421                    Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
422                    return false;
423                }
424            }
425        }
426        return true;
427    }
428
429    /**
430     * Set the currently configured network's bssid.
431     *
432     * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
433     * @return true if succeeds, false otherwise.
434     */
435    public boolean setCurrentNetworkBssid(String bssidStr) {
436        if (mCurrentNetwork == null) return false;
437        return mCurrentNetwork.setBssid(bssidStr);
438    }
439
440    /**
441     * Get the currently configured network's WPS NFC token.
442     *
443     * @return Hex string corresponding to the WPS NFC token.
444     */
445    public String getCurrentNetworkWpsNfcConfigurationToken() {
446        if (mCurrentNetwork == null) return null;
447        return mCurrentNetwork.getWpsNfcConfigurationToken();
448    }
449
450    /**
451     * Adds a new network.
452     *
453     * @return The ISupplicantNetwork object for the new network, or null if the call fails
454     */
455    private SupplicantStaNetworkHal addNetwork() {
456        synchronized (mLock) {
457            final String methodStr = "addNetwork";
458            if (DBG) Log.i(TAG, methodStr);
459            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
460            Mutable<ISupplicantNetwork> newNetwork = new Mutable<>();
461            try {
462                mISupplicantStaIface.addNetwork((SupplicantStatus status,
463                        ISupplicantNetwork network) -> {
464                    if (checkStatusAndLogFailure(status, methodStr)) {
465                        newNetwork.value = network;
466                    }
467                });
468            } catch (RemoteException e) {
469                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
470                supplicantServiceDiedHandler();
471            }
472            if (newNetwork.value != null) {
473                return getStaNetworkMockable(
474                        ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
475            } else {
476                return null;
477            }
478        }
479    }
480
481    /**
482     * Remove network from supplicant with network Id
483     *
484     * @return true if request is sent successfully, false otherwise.
485     */
486    private boolean removeNetwork(int id) {
487        synchronized (mLock) {
488            final String methodStr = "removeNetwork";
489            if (DBG) Log.i(TAG, methodStr);
490            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
491            try {
492                SupplicantStatus status = mISupplicantStaIface.removeNetwork(id);
493                return checkStatusAndLogFailure(status, methodStr);
494            } catch (RemoteException e) {
495                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
496                supplicantServiceDiedHandler();
497                return false;
498            }
499        }
500    }
501
502    /**
503     * Use this to mock the creation of SupplicantStaNetworkHal instance.
504     *
505     * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL.
506     * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
507     * the call fails
508     */
509    protected SupplicantStaNetworkHal getStaNetworkMockable(
510            ISupplicantStaNetwork iSupplicantStaNetwork) {
511        return new SupplicantStaNetworkHal(
512                iSupplicantStaNetwork, mIfaceName, mContext, mWifiMonitor);
513    }
514
515    /**
516     * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
517     * the call fails
518     */
519    private SupplicantStaNetworkHal getNetwork(int id) {
520        synchronized (mLock) {
521            final String methodStr = "getNetwork";
522            if (DBG) Log.i(TAG, methodStr);
523            Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>();
524            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
525            try {
526                mISupplicantStaIface.getNetwork(id, (SupplicantStatus status,
527                        ISupplicantNetwork network) -> {
528                    if (checkStatusAndLogFailure(status, methodStr)) {
529                        gotNetwork.value = network;
530                    }
531                });
532            } catch (RemoteException e) {
533                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
534                supplicantServiceDiedHandler();
535            }
536            if (gotNetwork.value != null) {
537                return getStaNetworkMockable(
538                        ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder()));
539            } else {
540                return null;
541            }
542        }
543    }
544
545    /** See ISupplicantStaNetwork.hal for documentation */
546    private boolean registerCallback(ISupplicantStaIfaceCallback callback) {
547        synchronized (mLock) {
548            final String methodStr = "registerCallback";
549            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
550            try {
551                SupplicantStatus status =  mISupplicantStaIface.registerCallback(callback);
552                return checkStatusAndLogFailure(status, methodStr);
553            } catch (RemoteException e) {
554                supplicantServiceDiedHandler();
555                return false;
556            }
557        }
558    }
559
560    /**
561     * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
562     * null if the call fails
563     */
564    private java.util.ArrayList<Integer> listNetworks() {
565        synchronized (mLock) {
566            final String methodStr = "listNetworks";
567            if (DBG) Log.i(TAG, methodStr);
568            Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
569            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
570            try {
571                mISupplicantStaIface.listNetworks((SupplicantStatus status,
572                        java.util.ArrayList<Integer> networkIds) -> {
573                    if (checkStatusAndLogFailure(status, methodStr)) {
574                        networkIdList.value = networkIds;
575                    }
576                });
577            } catch (RemoteException e) {
578                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
579                supplicantServiceDiedHandler();
580            }
581            return networkIdList.value;
582        }
583    }
584
585    /**
586     * Set WPS device name.
587     *
588     * @param name String to be set.
589     * @return true if request is sent successfully, false otherwise.
590     */
591    public boolean setWpsDeviceName(String name) {
592        synchronized (mLock) {
593            final String methodStr = "setWpsDeviceName";
594            if (DBG) Log.i(TAG, methodStr);
595            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
596            try {
597                SupplicantStatus status = mISupplicantStaIface.setWpsDeviceName(name);
598                return checkStatusAndLogFailure(status, methodStr);
599            } catch (RemoteException e) {
600                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
601                supplicantServiceDiedHandler();
602                return false;
603            }
604        }
605    }
606
607    /**
608     * Set WPS device type.
609     *
610     * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
611     * @return true if request is sent successfully, false otherwise.
612     */
613    public boolean setWpsDeviceType(String typeStr) {
614        Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
615        if (!match.find() || match.groupCount() != 3) {
616            Log.e(TAG, "Malformed WPS device type " + typeStr);
617            return false;
618        }
619        short categ = Short.parseShort(match.group(1));
620        byte[] oui = NativeUtil.hexStringToByteArray(match.group(2));
621        short subCateg = Short.parseShort(match.group(3));
622
623        byte[] bytes = new byte[8];
624        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
625        byteBuffer.putShort(categ);
626        byteBuffer.put(oui);
627        byteBuffer.putShort(subCateg);
628        return setWpsDeviceType(bytes);
629    }
630
631    private boolean setWpsDeviceType(byte[/* 8 */] type) {
632        synchronized (mLock) {
633            final String methodStr = "setWpsDeviceType";
634            if (DBG) Log.i(TAG, methodStr);
635            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
636            try {
637                SupplicantStatus status = mISupplicantStaIface.setWpsDeviceType(type);
638                return checkStatusAndLogFailure(status, methodStr);
639            } catch (RemoteException e) {
640                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
641                supplicantServiceDiedHandler();
642                return false;
643            }
644        }
645    }
646
647    /**
648     * Set WPS manufacturer.
649     *
650     * @param manufacturer String to be set.
651     * @return true if request is sent successfully, false otherwise.
652     */
653    public boolean setWpsManufacturer(String manufacturer) {
654        synchronized (mLock) {
655            final String methodStr = "setWpsManufacturer";
656            if (DBG) Log.i(TAG, methodStr);
657            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
658            try {
659                SupplicantStatus status = mISupplicantStaIface.setWpsManufacturer(manufacturer);
660                return checkStatusAndLogFailure(status, methodStr);
661            } catch (RemoteException e) {
662                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
663                supplicantServiceDiedHandler();
664                return false;
665            }
666        }
667    }
668
669    /**
670     * Set WPS model name.
671     *
672     * @param modelName String to be set.
673     * @return true if request is sent successfully, false otherwise.
674     */
675    public boolean setWpsModelName(String modelName) {
676        synchronized (mLock) {
677            final String methodStr = "setWpsModelName";
678            if (DBG) Log.i(TAG, methodStr);
679            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
680            try {
681                SupplicantStatus status = mISupplicantStaIface.setWpsModelName(modelName);
682                return checkStatusAndLogFailure(status, methodStr);
683            } catch (RemoteException e) {
684                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
685                supplicantServiceDiedHandler();
686                return false;
687            }
688        }
689    }
690
691    /**
692     * Set WPS model number.
693     *
694     * @param modelNumber String to be set.
695     * @return true if request is sent successfully, false otherwise.
696     */
697    public boolean setWpsModelNumber(String modelNumber) {
698        synchronized (mLock) {
699            final String methodStr = "setWpsModelNumber";
700            if (DBG) Log.i(TAG, methodStr);
701            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
702            try {
703                SupplicantStatus status = mISupplicantStaIface.setWpsModelNumber(modelNumber);
704                return checkStatusAndLogFailure(status, methodStr);
705            } catch (RemoteException e) {
706                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
707                supplicantServiceDiedHandler();
708                return false;
709            }
710        }
711    }
712
713    /**
714     * Set WPS serial number.
715     *
716     * @param serialNumber String to be set.
717     * @return true if request is sent successfully, false otherwise.
718     */
719    public boolean setWpsSerialNumber(String serialNumber) {
720        synchronized (mLock) {
721            final String methodStr = "setWpsSerialNumber";
722            if (DBG) Log.i(TAG, methodStr);
723            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
724            try {
725                SupplicantStatus status = mISupplicantStaIface.setWpsSerialNumber(serialNumber);
726                return checkStatusAndLogFailure(status, methodStr);
727            } catch (RemoteException e) {
728                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
729                supplicantServiceDiedHandler();
730                return false;
731            }
732        }
733    }
734
735    /**
736     * Set WPS config methods
737     *
738     * @param configMethodsStr List of config methods.
739     * @return true if request is sent successfully, false otherwise.
740     */
741    public boolean setWpsConfigMethods(String configMethodsStr) {
742        short configMethodsMask = 0;
743        String[] configMethodsStrArr = configMethodsStr.split("\\s+");
744        for (int i = 0; i < configMethodsStrArr.length; i++) {
745            configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
746        }
747        return setWpsConfigMethods(configMethodsMask);
748    }
749
750    private boolean setWpsConfigMethods(short configMethods) {
751        synchronized (mLock) {
752            final String methodStr = "setWpsConfigMethods";
753            if (DBG) Log.i(TAG, methodStr);
754            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
755            try {
756                SupplicantStatus status = mISupplicantStaIface.setWpsConfigMethods(configMethods);
757                return checkStatusAndLogFailure(status, methodStr);
758            } catch (RemoteException e) {
759                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
760                supplicantServiceDiedHandler();
761                return false;
762            }
763        }
764    }
765
766    /**
767     * Trigger a reassociation even if the iface is currently connected.
768     *
769     * @return true if request is sent successfully, false otherwise.
770     */
771    public boolean reassociate() {
772        synchronized (mLock) {
773            final String methodStr = "reassociate";
774            if (DBG) Log.i(TAG, methodStr);
775            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
776            try {
777                SupplicantStatus status = mISupplicantStaIface.reassociate();
778                return checkStatusAndLogFailure(status, methodStr);
779            } catch (RemoteException e) {
780                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
781                supplicantServiceDiedHandler();
782                return false;
783            }
784        }
785    }
786
787    /**
788     * Trigger a reconnection if the iface is disconnected.
789     *
790     * @return true if request is sent successfully, false otherwise.
791     */
792    public boolean reconnect() {
793        synchronized (mLock) {
794            final String methodStr = "reconnect";
795            if (DBG) Log.i(TAG, methodStr);
796            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
797            try {
798                SupplicantStatus status = mISupplicantStaIface.reconnect();
799                return checkStatusAndLogFailure(status, methodStr);
800            } catch (RemoteException e) {
801                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
802                supplicantServiceDiedHandler();
803                return false;
804            }
805        }
806    }
807
808    /**
809     * Trigger a disconnection from the currently connected network.
810     *
811     * @return true if request is sent successfully, false otherwise.
812     */
813    public boolean disconnect() {
814        synchronized (mLock) {
815            final String methodStr = "disconnect";
816            if (DBG) Log.i(TAG, methodStr);
817            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
818            try {
819                SupplicantStatus status = mISupplicantStaIface.disconnect();
820                return checkStatusAndLogFailure(status, methodStr);
821            } catch (RemoteException e) {
822                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
823                supplicantServiceDiedHandler();
824                return false;
825            }
826        }
827    }
828
829    /**
830     * Enable or disable power save mode.
831     *
832     * @param enable true to enable, false to disable.
833     * @return true if request is sent successfully, false otherwise.
834     */
835    public boolean setPowerSave(boolean enable) {
836        synchronized (mLock) {
837            final String methodStr = "setPowerSave";
838            if (DBG) Log.i(TAG, methodStr);
839            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
840            try {
841                SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable);
842                return checkStatusAndLogFailure(status, methodStr);
843            } catch (RemoteException e) {
844                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
845                supplicantServiceDiedHandler();
846                return false;
847            }
848        }
849    }
850
851    /**
852     * Initiate TDLS discover with the specified AP.
853     *
854     * @param macAddress MAC Address of the AP.
855     * @return true if request is sent successfully, false otherwise.
856     */
857    public boolean initiateTdlsDiscover(String macAddress) {
858        return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress));
859    }
860    /** See ISupplicantStaIface.hal for documentation */
861    private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) {
862        synchronized (mLock) {
863            final String methodStr = "initiateTdlsDiscover";
864            if (DBG) Log.i(TAG, methodStr);
865            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
866            try {
867                SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress);
868                return checkStatusAndLogFailure(status, methodStr);
869            } catch (RemoteException e) {
870                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
871                supplicantServiceDiedHandler();
872                return false;
873            }
874        }
875    }
876
877    /**
878     * Initiate TDLS setup with the specified AP.
879     *
880     * @param macAddress MAC Address of the AP.
881     * @return true if request is sent successfully, false otherwise.
882     */
883    public boolean initiateTdlsSetup(String macAddress) {
884        return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress));
885    }
886    /** See ISupplicantStaIface.hal for documentation */
887    private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) {
888        synchronized (mLock) {
889            final String methodStr = "initiateTdlsSetup";
890            if (DBG) Log.i(TAG, methodStr);
891            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
892            try {
893                SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress);
894                return checkStatusAndLogFailure(status, methodStr);
895            } catch (RemoteException e) {
896                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
897                supplicantServiceDiedHandler();
898                return false;
899            }
900        }
901    }
902
903    /**
904     * Initiate TDLS teardown with the specified AP.
905     * @param macAddress MAC Address of the AP.
906     * @return true if request is sent successfully, false otherwise.
907     */
908    public boolean initiateTdlsTeardown(String macAddress) {
909        return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress));
910    }
911
912    /** See ISupplicantStaIface.hal for documentation */
913    private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) {
914        synchronized (mLock) {
915            final String methodStr = "initiateTdlsTeardown";
916            if (DBG) Log.i(TAG, methodStr);
917            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
918            try {
919                SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress);
920                return checkStatusAndLogFailure(status, methodStr);
921            } catch (RemoteException e) {
922                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
923                supplicantServiceDiedHandler();
924                return false;
925            }
926        }
927    }
928
929    /**
930     * Request the specified ANQP elements |elements| from the specified AP |bssid|.
931     *
932     * @param bssid BSSID of the AP
933     * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
934     * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
935     * @return true if request is sent successfully, false otherwise.
936     */
937    public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements,
938                                     ArrayList<Integer> hs20SubTypes) {
939        return initiateAnqpQuery(
940                NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes);
941    }
942
943    /** See ISupplicantStaIface.hal for documentation */
944    private boolean initiateAnqpQuery(byte[/* 6 */] macAddress,
945            java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) {
946        synchronized (mLock) {
947            final String methodStr = "initiateAnqpQuery";
948            if (DBG) Log.i(TAG, methodStr);
949            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
950            try {
951                SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress,
952                        infoElements, subTypes);
953                return checkStatusAndLogFailure(status, methodStr);
954            } catch (RemoteException e) {
955                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
956                supplicantServiceDiedHandler();
957                return false;
958            }
959        }
960    }
961
962    /**
963     * Request the specified ANQP ICON from the specified AP |bssid|.
964     *
965     * @param bssid BSSID of the AP
966     * @param fileName Name of the file to request.
967     * @return true if request is sent successfully, false otherwise.
968     */
969    public boolean initiateHs20IconQuery(String bssid, String fileName) {
970        return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName);
971    }
972
973    /** See ISupplicantStaIface.hal for documentation */
974    private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) {
975        synchronized (mLock) {
976            final String methodStr = "initiateHs20IconQuery";
977            if (DBG) Log.i(TAG, methodStr);
978            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
979            try {
980                SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress,
981                        fileName);
982                return checkStatusAndLogFailure(status, methodStr);
983            } catch (RemoteException e) {
984                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
985                supplicantServiceDiedHandler();
986                return false;
987            }
988        }
989    }
990
991    /**
992     * Makes a callback to HIDL to getMacAddress from supplicant
993     *
994     * @return string containing the MAC address, or null on a failed call
995     */
996    public String getMacAddress() {
997        synchronized (mLock) {
998            final String methodStr = "getMacAddress";
999            if (DBG) Log.i(TAG, methodStr);
1000            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
1001            Mutable<String> gotMac = new Mutable<>();
1002            try {
1003                mISupplicantStaIface.getMacAddress((SupplicantStatus status,
1004                        byte[/* 6 */] macAddr) -> {
1005                    if (checkStatusAndLogFailure(status, methodStr)) {
1006                        gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
1007                    }
1008                });
1009            } catch (RemoteException e) {
1010                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
1011                supplicantServiceDiedHandler();
1012            }
1013            return gotMac.value;
1014        }
1015    }
1016
1017    /**
1018     * Start using the added RX filters.
1019     *
1020     * @return true if request is sent successfully, false otherwise.
1021     */
1022    public boolean startRxFilter() {
1023        synchronized (mLock) {
1024            final String methodStr = "startRxFilter";
1025            if (DBG) Log.i(TAG, methodStr);
1026            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1027            try {
1028                SupplicantStatus status = mISupplicantStaIface.startRxFilter();
1029                return checkStatusAndLogFailure(status, methodStr);
1030            } catch (RemoteException e) {
1031                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1032                supplicantServiceDiedHandler();
1033                return false;
1034            }
1035        }
1036    }
1037
1038    /**
1039     * Stop using the added RX filters.
1040     *
1041     * @return true if request is sent successfully, false otherwise.
1042     */
1043    public boolean stopRxFilter() {
1044        synchronized (mLock) {
1045            final String methodStr = "stopRxFilter";
1046            if (DBG) Log.i(TAG, methodStr);
1047            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1048            try {
1049                SupplicantStatus status = mISupplicantStaIface.stopRxFilter();
1050                return checkStatusAndLogFailure(status, methodStr);
1051            } catch (RemoteException e) {
1052                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1053                supplicantServiceDiedHandler();
1054                return false;
1055            }
1056        }
1057    }
1058
1059    public static final byte RX_FILTER_TYPE_V4_MULTICAST =
1060            ISupplicantStaIface.RxFilterType.V6_MULTICAST;
1061    public static final byte RX_FILTER_TYPE_V6_MULTICAST =
1062            ISupplicantStaIface.RxFilterType.V6_MULTICAST;
1063    /**
1064     * Add an RX filter.
1065     *
1066     * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or
1067     *        {@link #RX_FILTER_TYPE_V6_MULTICAST} values.
1068     * @return true if request is sent successfully, false otherwise.
1069     */
1070    private boolean addRxFilter(byte type) {
1071        synchronized (mLock) {
1072            final String methodStr = "addRxFilter";
1073            if (DBG) Log.i(TAG, methodStr);
1074            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1075            try {
1076                SupplicantStatus status = mISupplicantStaIface.addRxFilter(type);
1077                return checkStatusAndLogFailure(status, methodStr);
1078            } catch (RemoteException e) {
1079                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1080                supplicantServiceDiedHandler();
1081                return false;
1082            }
1083        }
1084    }
1085
1086    /**
1087     * Remove an RX filter.
1088     *
1089     * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or
1090     *        {@link #RX_FILTER_TYPE_V6_MULTICAST} values.
1091     * @return true if request is sent successfully, false otherwise.
1092     */
1093    private boolean removeRxFilter(byte type) {
1094        synchronized (mLock) {
1095            final String methodStr = "removeRxFilter";
1096            if (DBG) Log.i(TAG, methodStr);
1097            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1098            try {
1099                SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type);
1100                return checkStatusAndLogFailure(status, methodStr);
1101            } catch (RemoteException e) {
1102                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1103                supplicantServiceDiedHandler();
1104                return false;
1105            }
1106        }
1107    }
1108
1109    public static final byte BT_COEX_MODE_ENABLED = ISupplicantStaIface.BtCoexistenceMode.ENABLED;
1110    public static final byte BT_COEX_MODE_DISABLED = ISupplicantStaIface.BtCoexistenceMode.DISABLED;
1111    public static final byte BT_COEX_MODE_SENSE = ISupplicantStaIface.BtCoexistenceMode.SENSE;
1112    /**
1113     * Set Bt co existense mode.
1114     *
1115     * @param mode one of the above {@link #BT_COEX_MODE_ENABLED}, {@link #BT_COEX_MODE_DISABLED}
1116     *             or {@link #BT_COEX_MODE_SENSE} values.
1117     * @return true if request is sent successfully, false otherwise.
1118     */
1119    public boolean setBtCoexistenceMode(byte mode) {
1120        synchronized (mLock) {
1121            final String methodStr = "setBtCoexistenceMode";
1122            if (DBG) Log.i(TAG, methodStr);
1123            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1124            try {
1125                SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode);
1126                return checkStatusAndLogFailure(status, methodStr);
1127            } catch (RemoteException e) {
1128                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1129                supplicantServiceDiedHandler();
1130                return false;
1131            }
1132        }
1133    }
1134
1135    /** Enable or disable BT coexistence mode.
1136     *
1137     * @param enable true to enable, false to disable.
1138     * @return true if request is sent successfully, false otherwise.
1139     */
1140    public boolean setBtCoexistenceScanModeEnabled(boolean enable) {
1141        synchronized (mLock) {
1142            final String methodStr = "setBtCoexistenceScanModeEnabled";
1143            if (DBG) Log.i(TAG, methodStr);
1144            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1145            try {
1146                SupplicantStatus status =
1147                        mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable);
1148                return checkStatusAndLogFailure(status, methodStr);
1149            } catch (RemoteException e) {
1150                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1151                supplicantServiceDiedHandler();
1152                return false;
1153            }
1154        }
1155    }
1156
1157    /**
1158     * Enable or disable suspend mode optimizations.
1159     *
1160     * @param enable true to enable, false otherwise.
1161     * @return true if request is sent successfully, false otherwise.
1162     */
1163    public boolean setSuspendModeEnabled(boolean enable) {
1164        synchronized (mLock) {
1165            final String methodStr = "setSuspendModeEnabled";
1166            if (DBG) Log.i(TAG, methodStr);
1167            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1168            try {
1169                SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable);
1170                return checkStatusAndLogFailure(status, methodStr);
1171            } catch (RemoteException e) {
1172                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1173                supplicantServiceDiedHandler();
1174                return false;
1175            }
1176        }
1177    }
1178
1179    /**
1180     * Set country code.
1181     *
1182     * @param codeStr 2 byte ASCII string. For ex: US, CA.
1183     * @return true if request is sent successfully, false otherwise.
1184     */
1185    public boolean setCountryCode(String codeStr) {
1186        return setCountryCode(NativeUtil.stringToByteArray(codeStr));
1187    }
1188
1189    /** See ISupplicantStaIface.hal for documentation */
1190    private boolean setCountryCode(byte[/* 2 */] code) {
1191        synchronized (mLock) {
1192            final String methodStr = "setCountryCode";
1193            if (DBG) Log.i(TAG, methodStr);
1194            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1195            try {
1196                SupplicantStatus status = mISupplicantStaIface.setCountryCode(code);
1197                return checkStatusAndLogFailure(status, methodStr);
1198            } catch (RemoteException e) {
1199                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1200                supplicantServiceDiedHandler();
1201                return false;
1202            }
1203        }
1204    }
1205
1206    /**
1207     * Start WPS pin registrar operation with the specified peer and pin.
1208     *
1209     * @param bssidStr BSSID of the peer.
1210     * @param pin Pin to be used.
1211     * @return true if request is sent successfully, false otherwise.
1212     */
1213    public boolean startWpsRegistrar(String bssidStr, String pin) {
1214        return startWpsRegistrar(NativeUtil.macAddressToByteArray(bssidStr), pin);
1215    }
1216
1217    /** See ISupplicantStaIface.hal for documentation */
1218    private boolean startWpsRegistrar(byte[/* 6 */] bssid, String pin) {
1219        synchronized (mLock) {
1220            final String methodStr = "startWpsRegistrar";
1221            if (DBG) Log.i(TAG, methodStr);
1222            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1223            try {
1224                SupplicantStatus status = mISupplicantStaIface.startWpsRegistrar(bssid, pin);
1225                return checkStatusAndLogFailure(status, methodStr);
1226            } catch (RemoteException e) {
1227                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1228                supplicantServiceDiedHandler();
1229                return false;
1230            }
1231        }
1232    }
1233
1234    /**
1235     * Start WPS pin display operation with the specified peer.
1236     *
1237     * @param bssidStr BSSID of the peer.
1238     * @return true if request is sent successfully, false otherwise.
1239     */
1240    public boolean startWpsPbc(String bssidStr) {
1241        return startWpsPbc(NativeUtil.macAddressToByteArray(bssidStr));
1242    }
1243
1244    /** See ISupplicantStaIface.hal for documentation */
1245    private boolean startWpsPbc(byte[/* 6 */] bssid) {
1246        synchronized (mLock) {
1247            final String methodStr = "startWpsPbc";
1248            if (DBG) Log.i(TAG, methodStr);
1249            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1250            try {
1251                SupplicantStatus status = mISupplicantStaIface.startWpsPbc(bssid);
1252                return checkStatusAndLogFailure(status, methodStr);
1253            } catch (RemoteException e) {
1254                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1255                supplicantServiceDiedHandler();
1256                return false;
1257            }
1258        }
1259    }
1260
1261    /**
1262     * Start WPS pin keypad operation with the specified pin.
1263     *
1264     * @param pin Pin to be used.
1265     * @return true if request is sent successfully, false otherwise.
1266     */
1267    public boolean startWpsPinKeypad(String pin) {
1268        synchronized (mLock) {
1269            final String methodStr = "startWpsPinKeypad";
1270            if (DBG) Log.i(TAG, methodStr);
1271            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1272            try {
1273                SupplicantStatus status = mISupplicantStaIface.startWpsPinKeypad(pin);
1274                return checkStatusAndLogFailure(status, methodStr);
1275            } catch (RemoteException e) {
1276                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1277                supplicantServiceDiedHandler();
1278                return false;
1279            }
1280        }
1281    }
1282
1283    /**
1284     * Start WPS pin display operation with the specified peer.
1285     *
1286     * @param bssidStr BSSID of the peer.
1287     * @return new pin generated on success, null otherwise.
1288     */
1289    public String startWpsPinDisplay(String bssidStr) {
1290        return startWpsPinDisplay(NativeUtil.macAddressToByteArray(bssidStr));
1291    }
1292
1293    /** See ISupplicantStaIface.hal for documentation */
1294    private String startWpsPinDisplay(byte[/* 6 */] bssid) {
1295        synchronized (mLock) {
1296            final String methodStr = "startWpsPinDisplay";
1297            if (DBG) Log.i(TAG, methodStr);
1298            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
1299            final Mutable<String> gotPin = new Mutable<>();
1300            try {
1301                mISupplicantStaIface.startWpsPinDisplay(bssid,
1302                        (SupplicantStatus status, String pin) -> {
1303                            if (checkStatusAndLogFailure(status, methodStr)) {
1304                                gotPin.value = pin;
1305                            }
1306                        });
1307            } catch (RemoteException e) {
1308                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1309                supplicantServiceDiedHandler();
1310            }
1311            return gotPin.value;
1312        }
1313    }
1314
1315    /**
1316     * Cancels any ongoing WPS requests.
1317     *
1318     * @return true if request is sent successfully, false otherwise.
1319     */
1320    public boolean cancelWps() {
1321        synchronized (mLock) {
1322            final String methodStr = "cancelWps";
1323            if (DBG) Log.i(TAG, methodStr);
1324            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1325            try {
1326                SupplicantStatus status = mISupplicantStaIface.cancelWps();
1327                return checkStatusAndLogFailure(status, methodStr);
1328            } catch (RemoteException e) {
1329                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1330                supplicantServiceDiedHandler();
1331                return false;
1332            }
1333        }
1334    }
1335
1336    /**
1337     * Sets whether to use external sim for SIM/USIM processing.
1338     *
1339     * @param useExternalSim true to enable, false otherwise.
1340     * @return true if request is sent successfully, false otherwise.
1341     */
1342    public boolean setExternalSim(boolean useExternalSim) {
1343        synchronized (mLock) {
1344            final String methodStr = "setExternalSim";
1345            if (DBG) Log.i(TAG, methodStr);
1346            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1347            try {
1348                SupplicantStatus status = mISupplicantStaIface.setExternalSim(useExternalSim);
1349                return checkStatusAndLogFailure(status, methodStr);
1350            } catch (RemoteException e) {
1351                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1352                supplicantServiceDiedHandler();
1353                return false;
1354            }
1355        }
1356    }
1357
1358    public static final int LOG_LEVEL_EXCESSIVE = ISupplicant.DebugLevel.EXCESSIVE;
1359    public static final int LOG_LEVEL_MSGDUMP = ISupplicant.DebugLevel.MSGDUMP;
1360    public static final int LOG_LEVEL_DEBUG = ISupplicant.DebugLevel.DEBUG;
1361    public static final int LOG_LEVEL_INFO = ISupplicant.DebugLevel.INFO;
1362    public static final int LOG_LEVEL_WARNING = ISupplicant.DebugLevel.WARNING;
1363    public static final int LOG_LEVEL_ERROR = ISupplicant.DebugLevel.ERROR;
1364    /**
1365     * Set the debug log level for wpa_supplicant
1366     * @param level One of the above {@link #LOG_LEVEL_EXCESSIVE} - {@link #LOG_LEVEL_ERROR} value.
1367     * @return true if request is sent successfully, false otherwise.
1368     */
1369    public boolean setLogLevel(int level) {
1370        return setDebugParams(level, false, false);
1371    }
1372
1373    /** See ISupplicant.hal for documentation */
1374    private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) {
1375        synchronized (mLock) {
1376            final String methodStr = "setDebugParams";
1377            if (DBG) Log.i(TAG, methodStr);
1378            if (!checkSupplicantAndLogFailure(methodStr)) return false;
1379            try {
1380                SupplicantStatus status =
1381                        mISupplicant.setDebugParams(level, showTimestamp, showKeys);
1382                return checkStatusAndLogFailure(status, methodStr);
1383            } catch (RemoteException e) {
1384                Log.e(TAG, "ISupplicant." + methodStr + ": exception:" + e);
1385                supplicantServiceDiedHandler();
1386                return false;
1387            }
1388        }
1389    }
1390
1391    /**
1392     * Set concurrency priority between P2P & STA operations.
1393     *
1394     * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
1395     *                            false otherwise.
1396     * @return true if request is sent successfully, false otherwise.
1397     */
1398    public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
1399        if (isStaHigherPriority) {
1400            return setConcurrencyPriority(IfaceType.STA);
1401        } else {
1402            return setConcurrencyPriority(IfaceType.P2P);
1403        }
1404    }
1405
1406    /** See ISupplicant.hal for documentation */
1407    private boolean setConcurrencyPriority(int type) {
1408        synchronized (mLock) {
1409            final String methodStr = "setConcurrencyPriority";
1410            if (DBG) Log.i(TAG, methodStr);
1411            if (!checkSupplicantAndLogFailure(methodStr)) return false;
1412            try {
1413                SupplicantStatus status = mISupplicant.setConcurrencyPriority(type);
1414                return checkStatusAndLogFailure(status, methodStr);
1415            } catch (RemoteException e) {
1416                Log.e(TAG, "ISupplicant." + methodStr + ": exception:" + e);
1417                supplicantServiceDiedHandler();
1418                return false;
1419            }
1420        }
1421    }
1422
1423    /**
1424     * Returns false if Supplicant is null, and logs failure to call methodStr
1425     */
1426    private boolean checkSupplicantAndLogFailure(final String methodStr) {
1427        if (DBG) Log.i(TAG, methodStr);
1428        if (mISupplicant == null) {
1429            Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null");
1430            return false;
1431        }
1432        return true;
1433    }
1434
1435    /**
1436     * Returns false if SupplicantStaIface is null, and logs failure to call methodStr
1437     */
1438    private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) {
1439        if (DBG) Log.i(TAG, methodStr);
1440        if (mISupplicantStaIface == null) {
1441            Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null");
1442            return false;
1443        }
1444        return true;
1445    }
1446
1447    /**
1448     * Returns true if provided status code is SUCCESS, logs debug message and returns false
1449     * otherwise
1450     */
1451    private static boolean checkStatusAndLogFailure(SupplicantStatus status,
1452            final String methodStr) {
1453        if (DBG) Log.i(TAG, methodStr);
1454        if (status.code != SupplicantStatusCode.SUCCESS) {
1455            Log.e(TAG, methodStr + " failed: " + supplicantStatusCodeToString(status.code) + ", "
1456                    + status.debugMessage);
1457            return false;
1458        }
1459        return true;
1460    }
1461
1462    /**
1463     * Converts SupplicantStatus code values to strings for debug logging
1464     * TODO(b/34811152) Remove this, or make it more break resistance
1465     */
1466    public static String supplicantStatusCodeToString(int code) {
1467        switch (code) {
1468            case 0:
1469                return "SUCCESS";
1470            case 1:
1471                return "FAILURE_UNKNOWN";
1472            case 2:
1473                return "FAILURE_ARGS_INVALID";
1474            case 3:
1475                return "FAILURE_IFACE_INVALID";
1476            case 4:
1477                return "FAILURE_IFACE_UNKNOWN";
1478            case 5:
1479                return "FAILURE_IFACE_EXISTS";
1480            case 6:
1481                return "FAILURE_IFACE_DISABLED";
1482            case 7:
1483                return "FAILURE_IFACE_NOT_DISCONNECTED";
1484            case 8:
1485                return "FAILURE_NETWORK_INVALID";
1486            case 9:
1487                return "FAILURE_NETWORK_UNKNOWN";
1488            default:
1489                return "??? UNKNOWN_CODE";
1490        }
1491    }
1492
1493
1494    /**
1495     * Converts the Wps config method string to the equivalent enum value.
1496     */
1497    private static short stringToWpsConfigMethod(String configMethod) {
1498        switch (configMethod) {
1499            case "usba":
1500                return WpsConfigMethods.USBA;
1501            case "ethernet":
1502                return WpsConfigMethods.ETHERNET;
1503            case "label":
1504                return WpsConfigMethods.LABEL;
1505            case "display":
1506                return WpsConfigMethods.DISPLAY;
1507            case "int_nfc_token":
1508                return WpsConfigMethods.INT_NFC_TOKEN;
1509            case "ext_nfc_token":
1510                return WpsConfigMethods.EXT_NFC_TOKEN;
1511            case "nfc_interface":
1512                return WpsConfigMethods.NFC_INTERFACE;
1513            case "push_button":
1514                return WpsConfigMethods.PUSHBUTTON;
1515            case "keypad":
1516                return WpsConfigMethods.KEYPAD;
1517            case "virtual_push_button":
1518                return WpsConfigMethods.VIRT_PUSHBUTTON;
1519            case "physical_push_button":
1520                return WpsConfigMethods.PHY_PUSHBUTTON;
1521            case "p2ps":
1522                return WpsConfigMethods.P2PS;
1523            case "virtual_display":
1524                return WpsConfigMethods.VIRT_DISPLAY;
1525            case "physical_display":
1526                return WpsConfigMethods.PHY_DISPLAY;
1527            default:
1528                throw new IllegalArgumentException(
1529                        "Invalid WPS config method: " + configMethod);
1530        }
1531    }
1532
1533    /**
1534     * Converts the supplicant state received from HIDL to the equivalent framework state.
1535     */
1536    private static SupplicantState supplicantHidlStateToFrameworkState(int state) {
1537        switch (state) {
1538            case ISupplicantStaIfaceCallback.State.DISCONNECTED:
1539                return SupplicantState.DISCONNECTED;
1540            case ISupplicantStaIfaceCallback.State.IFACE_DISABLED:
1541                return SupplicantState.INTERFACE_DISABLED;
1542            case ISupplicantStaIfaceCallback.State.INACTIVE:
1543                return SupplicantState.INACTIVE;
1544            case ISupplicantStaIfaceCallback.State.SCANNING:
1545                return SupplicantState.SCANNING;
1546            case ISupplicantStaIfaceCallback.State.AUTHENTICATING:
1547                return SupplicantState.AUTHENTICATING;
1548            case ISupplicantStaIfaceCallback.State.ASSOCIATING:
1549                return SupplicantState.ASSOCIATING;
1550            case ISupplicantStaIfaceCallback.State.ASSOCIATED:
1551                return SupplicantState.ASSOCIATED;
1552            case ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE:
1553                return SupplicantState.FOUR_WAY_HANDSHAKE;
1554            case ISupplicantStaIfaceCallback.State.GROUP_HANDSHAKE:
1555                return SupplicantState.GROUP_HANDSHAKE;
1556            case ISupplicantStaIfaceCallback.State.COMPLETED:
1557                return SupplicantState.COMPLETED;
1558            default:
1559                throw new IllegalArgumentException("Invalid state: " + state);
1560        }
1561    }
1562
1563    private static class Mutable<E> {
1564        public E value;
1565
1566        Mutable() {
1567            value = null;
1568        }
1569
1570        Mutable(E value) {
1571            this.value = value;
1572        }
1573    }
1574
1575    private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub {
1576        /**
1577         * Parses the provided payload into an ANQP element.
1578         *
1579         * @param infoID  Element type.
1580         * @param payload Raw payload bytes.
1581         * @return AnqpElement instance on success, null on failure.
1582         */
1583        private ANQPElement parseAnqpElement(Constants.ANQPElementType infoID,
1584                                             ArrayList<Byte> payload) {
1585            try {
1586                return Constants.getANQPElementID(infoID) != null
1587                        ? ANQPParser.parseElement(
1588                        infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload)))
1589                        : ANQPParser.parseHS20Element(
1590                        infoID, ByteBuffer.wrap(NativeUtil.byteArrayFromArrayList(payload)));
1591            } catch (IOException | BufferUnderflowException e) {
1592                Log.e(TAG, "Failed parsing ANQP element payload: " + infoID, e);
1593                return null;
1594            }
1595        }
1596
1597        /**
1598         * Parse the ANQP element data and add to the provided elements map if successful.
1599         *
1600         * @param elementsMap Map to add the parsed out element to.
1601         * @param infoID  Element type.
1602         * @param payload Raw payload bytes.
1603         */
1604        private void addAnqpElementToMap(Map<Constants.ANQPElementType, ANQPElement> elementsMap,
1605                                         Constants.ANQPElementType infoID,
1606                                         ArrayList<Byte> payload) {
1607            if (payload == null || payload.isEmpty()) return;
1608            ANQPElement element = parseAnqpElement(infoID, payload);
1609            if (element != null) {
1610                elementsMap.put(infoID, element);
1611            }
1612        }
1613
1614        /**
1615         * Helper utility to convert the bssid bytes to long.
1616         */
1617        private Long toLongBssid(byte[] bssidBytes) {
1618            try {
1619                return ByteBufferReader.readInteger(
1620                        ByteBuffer.wrap(bssidBytes), ByteOrder.BIG_ENDIAN, bssidBytes.length);
1621            } catch (BufferUnderflowException | IllegalArgumentException e) {
1622                return 0L;
1623            }
1624        }
1625
1626        @Override
1627        public void onNetworkAdded(int id) {
1628        }
1629
1630        @Override
1631        public void onNetworkRemoved(int id) {
1632        }
1633
1634        @Override
1635        public void onStateChanged(int newState, byte[/* 6 */] bssid, int id,
1636                                   ArrayList<Byte> ssid) {
1637            SupplicantState newSupplicantState = supplicantHidlStateToFrameworkState(newState);
1638            WifiSsid wifiSsid =
1639                    WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(ssid));
1640            String bssidStr = NativeUtil.macAddressFromByteArray(bssid);
1641            mWifiMonitor.broadcastSupplicantStateChangeEvent(
1642                    mIfaceName, mFrameworkNetworkId, wifiSsid, bssidStr, newSupplicantState);
1643            if (newSupplicantState == SupplicantState.ASSOCIATED) {
1644                mWifiMonitor.broadcastAssociationSuccesfulEvent(mIfaceName, bssidStr);
1645            } else if (newSupplicantState == SupplicantState.COMPLETED) {
1646                mWifiMonitor.broadcastNetworkConnectionEvent(
1647                        mIfaceName, mFrameworkNetworkId, bssidStr);
1648            }
1649        }
1650
1651        @Override
1652        public void onAnqpQueryDone(byte[/* 6 */] bssid,
1653                                    ISupplicantStaIfaceCallback.AnqpData data,
1654                                    ISupplicantStaIfaceCallback.Hs20AnqpData hs20Data) {
1655            Map<Constants.ANQPElementType, ANQPElement> elementsMap = new HashMap<>();
1656            addAnqpElementToMap(elementsMap, ANQPVenueName, data.venueName);
1657            addAnqpElementToMap(elementsMap, ANQPRoamingConsortium, data.roamingConsortium);
1658            addAnqpElementToMap(elementsMap, ANQPIPAddrAvailability, data.ipAddrTypeAvailability);
1659            addAnqpElementToMap(elementsMap, ANQPNAIRealm, data.naiRealm);
1660            addAnqpElementToMap(elementsMap, ANQP3GPPNetwork, data.anqp3gppCellularNetwork);
1661            addAnqpElementToMap(elementsMap, ANQPDomName, data.domainName);
1662            addAnqpElementToMap(elementsMap, HSFriendlyName, hs20Data.operatorFriendlyName);
1663            addAnqpElementToMap(elementsMap, HSWANMetrics, hs20Data.wanMetrics);
1664            addAnqpElementToMap(elementsMap, HSConnCapability, hs20Data.connectionCapability);
1665            addAnqpElementToMap(elementsMap, HSOSUProviders, hs20Data.osuProvidersList);
1666            mWifiMonitor.broadcastAnqpDoneEvent(
1667                    mIfaceName, new AnqpEvent(toLongBssid(bssid), elementsMap));
1668        }
1669
1670        @Override
1671        public void onHs20IconQueryDone(byte[/* 6 */] bssid, String fileName,
1672                                        ArrayList<Byte> data) {
1673            mWifiMonitor.broadcastIconDoneEvent(
1674                    mIfaceName,
1675                    new IconEvent(toLongBssid(bssid), fileName, data.size(),
1676                            NativeUtil.byteArrayFromArrayList(data)));
1677        }
1678
1679        @Override
1680        public void onHs20SubscriptionRemediation(byte[/* 6 */] bssid, byte osuMethod, String url) {
1681            mWifiMonitor.broadcastWnmEvent(
1682                    mIfaceName, new WnmData(toLongBssid(bssid), url, osuMethod));
1683        }
1684
1685        @Override
1686        public void onHs20DeauthImminentNotice(byte[/* 6 */] bssid, int reasonCode,
1687                                               int reAuthDelayInSec, String url) {
1688            mWifiMonitor.broadcastWnmEvent(
1689                    mIfaceName,
1690                    new WnmData(toLongBssid(bssid), url, reasonCode == WnmData.ESS,
1691                            reAuthDelayInSec));
1692        }
1693
1694        @Override
1695        public void onDisconnected(byte[/* 6 */] bssid, boolean locallyGenerated, int reasonCode) {
1696        }
1697
1698        @Override
1699        public void onAssociationRejected(byte[/* 6 */] bssid, int statusCode) {
1700        }
1701
1702        @Override
1703        public void onAuthenticationTimeout(byte[/* 6 */] bssid) {
1704        }
1705
1706        @Override
1707        public void onEapFailure() {
1708        }
1709
1710        @Override
1711        public void onWpsEventSuccess() {
1712        }
1713
1714        @Override
1715        public void onWpsEventFail(byte[/* 6 */] bssid, short configError, short errorInd) {
1716        }
1717
1718        @Override
1719        public void onWpsEventPbcOverlap() {
1720        }
1721
1722        @Override
1723        public void onExtRadioWorkStart(int id) {
1724        }
1725
1726        @Override
1727        public void onExtRadioWorkTimeout(int id) {
1728        }
1729    }
1730
1731    private void logd(String s) {
1732        Log.d(TAG, s);
1733    }
1734
1735    private void logi(String s) {
1736        Log.i(TAG, s);
1737    }
1738
1739    private void loge(String s) {
1740        Log.e(TAG, s);
1741    }
1742}
1743