SupplicantStaIfaceHal.java revision 7651e69b6f5e2b28a4fee7284ac2522faa002c9f
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.server.wifi;
17
18import android.content.Context;
19import android.hardware.wifi.supplicant.V1_0.ISupplicant;
20import android.hardware.wifi.supplicant.V1_0.ISupplicantIface;
21import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork;
22import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface;
23import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork;
24import android.hardware.wifi.supplicant.V1_0.IfaceType;
25import android.hardware.wifi.supplicant.V1_0.SupplicantStatus;
26import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode;
27import android.hidl.manager.V1_0.IServiceManager;
28import android.hidl.manager.V1_0.IServiceNotification;
29import android.net.IpConfiguration;
30import android.net.wifi.WifiConfiguration;
31import android.os.RemoteException;
32import android.util.Log;
33import android.util.MutableBoolean;
34import android.util.SparseArray;
35
36import com.android.server.wifi.util.NativeUtil;
37
38import java.util.ArrayList;
39import java.util.HashMap;
40import java.util.List;
41import java.util.Map;
42
43/**
44 * Hal calls for bring up/shut down of the supplicant daemon and for
45 * sending requests to the supplicant daemon
46 */
47public class SupplicantStaIfaceHal {
48    private static final boolean DBG = false;
49    private static final String TAG = "SupplicantStaIfaceHal";
50    private static final String SERVICE_MANAGER_NAME = "manager";
51    private IServiceManager mIServiceManager = null;
52    // Supplicant HAL interface objects
53    private ISupplicant mISupplicant;
54    private ISupplicantStaIface mISupplicantStaIface;
55    // Currently configured network in wpa_supplicant
56    private SupplicantStaNetworkHal mCurrentNetwork;
57    // Currently configured network's framework network Id.
58    private int mFrameworkNetworkId;
59    private final Object mLock = new Object();
60    private final Context mContext;
61    private final WifiMonitor mWifiMonitor;
62
63    public SupplicantStaIfaceHal(Context context, WifiMonitor monitor) {
64        mContext = context;
65        mWifiMonitor = monitor;
66    }
67
68    /**
69     * Registers a service notification for the ISupplicant service, which triggers intialization of
70     * the ISupplicantStaIface
71     * @return true if the service notification was successfully registered
72     */
73    public boolean initialize() {
74        if (DBG) Log.i(TAG, "Registering ISupplicant service ready callback.");
75        synchronized (mLock) {
76            mISupplicant = null;
77            mISupplicantStaIface = null;
78            if (mIServiceManager != null) {
79                // Already have an IServiceManager and serviceNotification registered, don't
80                // don't register another.
81                return true;
82            }
83            try {
84                mIServiceManager = getServiceManagerMockable();
85                if (mIServiceManager == null) {
86                    Log.e(TAG, "Failed to get HIDL Service Manager");
87                    return false;
88                }
89                if (!mIServiceManager.linkToDeath(cookie -> {
90                    Log.wtf(TAG, "IServiceManager died: cookie=" + cookie);
91                    synchronized (mLock) {
92                        supplicantServiceDiedHandler();
93                        mIServiceManager = null; // Will need to register a new ServiceNotification
94                    }
95                }, 0)) {
96                    Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
97                    supplicantServiceDiedHandler();
98                    mIServiceManager = null; // Will need to register a new ServiceNotification
99                    return false;
100                }
101                IServiceNotification serviceNotificationCb = new IServiceNotification.Stub() {
102                    public void onRegistration(String fqName, String name, boolean preexisting) {
103                        synchronized (mLock) {
104                            if (DBG) {
105                                Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
106                                        + ", " + name + " preexisting=" + preexisting);
107                            }
108                            if (!initSupplicantService() || !initSupplicantStaIface()) {
109                                Log.e(TAG, "initalizing ISupplicantIfaces failed.");
110                                supplicantServiceDiedHandler();
111                            } else {
112                                Log.i(TAG, "Completed initialization of ISupplicant interfaces.");
113                            }
114                        }
115                    }
116                };
117                /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it
118                   exists */
119                if (!mIServiceManager.registerForNotifications(ISupplicant.kInterfaceName,
120                        "", serviceNotificationCb)) {
121                    Log.e(TAG, "Failed to register for notifications to "
122                            + ISupplicant.kInterfaceName);
123                    mIServiceManager = null; // Will need to register a new ServiceNotification
124                    return false;
125                }
126            } catch (RemoteException e) {
127                Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: "
128                        + e);
129                supplicantServiceDiedHandler();
130            }
131            return true;
132        }
133    }
134
135    private boolean initSupplicantService() {
136        synchronized (mLock) {
137            try {
138                mISupplicant = getSupplicantMockable();
139            } catch (RemoteException e) {
140                Log.e(TAG, "ISupplicant.getService exception: " + e);
141                return false;
142            }
143            if (mISupplicant == null) {
144                Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup");
145                return false;
146            }
147        }
148        return true;
149    }
150
151    private boolean initSupplicantStaIface() {
152        synchronized (mLock) {
153            /** List all supplicant Ifaces */
154            final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>();
155            try {
156                mISupplicant.listInterfaces((SupplicantStatus status,
157                        ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
158                    if (status.code != SupplicantStatusCode.SUCCESS) {
159                        Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
160                        return;
161                    }
162                    supplicantIfaces.addAll(ifaces);
163                });
164            } catch (RemoteException e) {
165                Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
166                return false;
167            }
168            if (supplicantIfaces.size() == 0) {
169                Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
170                return false;
171            }
172            Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
173            for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
174                if (ifaceInfo.type == IfaceType.STA) {
175                    try {
176                        mISupplicant.getInterface(ifaceInfo,
177                                (SupplicantStatus status, ISupplicantIface iface) -> {
178                                if (status.code != SupplicantStatusCode.SUCCESS) {
179                                    Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
180                                    return;
181                                }
182                                supplicantIface.value = iface;
183                            });
184                    } catch (RemoteException e) {
185                        Log.e(TAG, "ISupplicant.getInterface exception: " + e);
186                        return false;
187                    }
188                    break;
189                }
190            }
191            if (supplicantIface.value == null) {
192                Log.e(TAG, "initSupplicantStaIface got null iface");
193                return false;
194            }
195            mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value);
196            return true;
197        }
198    }
199
200    private void supplicantServiceDiedHandler() {
201        synchronized (mLock) {
202            mISupplicant = null;
203            mISupplicantStaIface = null;
204        }
205    }
206
207    /**
208     * Signals whether Initialization completed successfully. Only necessary for testing, is not
209     * needed to guard calls etc.
210     */
211    public boolean isInitializationComplete() {
212        return mISupplicantStaIface != null;
213    }
214
215    /**
216     * Wrapper functions to access static HAL methods, created to be mockable in unit tests
217     */
218    protected IServiceManager getServiceManagerMockable() throws RemoteException {
219        return IServiceManager.getService(SERVICE_MANAGER_NAME);
220    }
221
222    protected ISupplicant getSupplicantMockable() throws RemoteException {
223        return ISupplicant.getService();
224    }
225
226    protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) {
227        return ISupplicantStaIface.asInterface(iface.asBinder());
228    }
229
230    /**
231     * Add a network configuration to wpa_supplicant.
232     *
233     * @param config Config corresponding to the network.
234     * @return SupplicantStaNetwork of the added network in wpa_supplicant.
235     */
236    private SupplicantStaNetworkHal addNetwork(WifiConfiguration config) {
237        logi("addSupplicantStaNetwork via HIDL");
238        if (config == null) {
239            loge("Cannot add NULL network!");
240            return null;
241        }
242        SupplicantStaNetworkHal network = addNetwork();
243        if (network == null) {
244            loge("Failed to add a network!");
245            return null;
246        }
247        if (network.saveWifiConfiguration(config)) {
248            return network;
249        } else {
250            loge("Failed to save variables for: " + config.configKey());
251            return null;
252        }
253    }
254
255    /**
256     * Add the provided network configuration to wpa_supplicant and initiate connection to it.
257     * This method does the following:
258     * 1. Triggers disconnect command to wpa_supplicant (if |shouldDisconnect| is true).
259     * 2. Remove any existing network in wpa_supplicant.
260     * 3. Add a new network to wpa_supplicant.
261     * 4. Save the provided configuration to wpa_supplicant.
262     * 5. Select the new network in wpa_supplicant.
263     *
264     * @param config WifiConfiguration parameters for the provided network.
265     * @param shouldDisconnect whether to trigger a disconnection or not.
266     * @return {@code true} if it succeeds, {@code false} otherwise
267     */
268    public boolean connectToNetwork(WifiConfiguration config, boolean shouldDisconnect) {
269        mFrameworkNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
270        mCurrentNetwork = null;
271        logd("connectToNetwork " + config.configKey()
272                + " (shouldDisconnect " + shouldDisconnect + ")");
273        if (shouldDisconnect && !disconnect()) {
274            loge("Failed to trigger disconnect");
275            return false;
276        }
277        if (!removeAllNetworks()) {
278            loge("Failed to remove existing networks");
279            return false;
280        }
281        mCurrentNetwork = addNetwork(config);
282        if (mCurrentNetwork == null) {
283            loge("Failed to add/save network configuration: " + config.configKey());
284            return false;
285        }
286        if (!mCurrentNetwork.select()) {
287            loge("Failed to select network configuration: " + config.configKey());
288            return false;
289        }
290        mFrameworkNetworkId = config.networkId;
291        return true;
292    }
293
294    /**
295     * Initiates roaming to the already configured network in wpa_supplicant. If the network
296     * configuration provided does not match the already configured network, then this triggers
297     * a new connection attempt (instead of roam).
298     * 1. First check if we're attempting to connect to the same network as we currently have
299     * configured.
300     * 2. Set the new bssid for the network in wpa_supplicant.
301     * 3. Trigger reassociate command to wpa_supplicant.
302     *
303     * @param config WifiConfiguration parameters for the provided network.
304     * @return {@code true} if it succeeds, {@code false} otherwise
305     */
306    public boolean roamToNetwork(WifiConfiguration config) {
307        if (mFrameworkNetworkId != config.networkId || mCurrentNetwork == null) {
308            Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
309                    + "Current network ID: " + mFrameworkNetworkId);
310            return connectToNetwork(config, false);
311        }
312        String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
313        logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")");
314        if (!mCurrentNetwork.setBssid(bssid)) {
315            loge("Failed to set new bssid on network: " + config.configKey());
316            return false;
317        }
318        if (!reassociate()) {
319            loge("Failed to trigger reassociate");
320            return false;
321        }
322        return true;
323    }
324
325    /**
326     * Load all the configured networks from wpa_supplicant.
327     *
328     * @param configs       Map of configuration key to configuration objects corresponding to all
329     *                      the networks.
330     * @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
331     * @return true if succeeds, false otherwise.
332     */
333    public boolean loadNetworks(Map<String, WifiConfiguration> configs,
334                                SparseArray<Map<String, String>> networkExtras) {
335        List<Integer> networkIds = listNetworks();
336        if (networkIds == null) {
337            Log.e(TAG, "Failed to list networks");
338            return false;
339        }
340        for (Integer networkId : networkIds) {
341            SupplicantStaNetworkHal network = getNetwork(networkId);
342            if (network == null) {
343                Log.e(TAG, "Failed to get network with ID: " + networkId);
344                return false;
345            }
346            WifiConfiguration config = new WifiConfiguration();
347            Map<String, String> networkExtra = new HashMap<>();
348            if (!network.loadWifiConfiguration(config, networkExtra)) {
349                Log.e(TAG, "Failed to load wifi configuration for network with ID: " + networkId);
350                return false;
351            }
352            // Set the default IP assignments.
353            config.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
354            config.setProxySettings(IpConfiguration.ProxySettings.NONE);
355
356            networkExtras.put(networkId, networkExtra);
357            String configKey = networkExtra.get(SupplicantStaNetworkHal.ID_STRING_KEY_CONFIG_KEY);
358            final WifiConfiguration duplicateConfig = configs.put(configKey, config);
359            if (duplicateConfig != null) {
360                // The network is already known. Overwrite the duplicate entry.
361                Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId);
362                removeNetwork(duplicateConfig.networkId);
363                networkExtras.remove(duplicateConfig.networkId);
364            }
365        }
366        return true;
367    }
368
369    /**
370     * Remove all networks from supplicant
371     */
372    public boolean removeAllNetworks() {
373        synchronized (mLock) {
374            ArrayList<Integer> networks = listNetworks();
375            if (networks == null) {
376                Log.e(TAG, "removeAllNetworks failed, got null networks");
377                return false;
378            }
379            for (int id : networks) {
380                if (!removeNetwork(id)) {
381                    Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
382                    return false;
383                }
384            }
385        }
386        return true;
387    }
388
389    /**
390     * Gets the interface name.
391     *
392     * @return returns the name of Iface or null if the call fails
393     */
394    private String getName() {
395        synchronized (mLock) {
396            MutableBoolean statusSuccess = new MutableBoolean(false);
397            final String methodStr = "getName";
398            if (DBG) Log.i(TAG, methodStr);
399            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
400            final StringBuilder builder = new StringBuilder();
401            try {
402                mISupplicantStaIface.getName((SupplicantStatus status, String name) -> {
403                    statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS;
404                    if (!statusSuccess.value) {
405                        Log.e(TAG, methodStr + " failed: " + status.debugMessage);
406                    } else {
407                        builder.append(name);
408                    }
409                });
410            } catch (RemoteException e) {
411                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
412                supplicantServiceDiedHandler();
413            }
414            if (statusSuccess.value) {
415                return builder.toString();
416            } else {
417                return null;
418            }
419        }
420    }
421
422    /**
423     * Adds a new network.
424     *
425     * @return The ISupplicantNetwork object for the new network, or null if the call fails
426     */
427    private SupplicantStaNetworkHal addNetwork() {
428        synchronized (mLock) {
429            MutableBoolean statusSuccess = new MutableBoolean(false);
430            Mutable<ISupplicantNetwork> newNetwork = new Mutable<>();
431            final String methodStr = "addNetwork";
432            if (DBG) Log.i(TAG, methodStr);
433            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
434            try {
435                mISupplicantStaIface.addNetwork((SupplicantStatus status,
436                        ISupplicantNetwork network) -> {
437                    statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS;
438                    if (!statusSuccess.value) {
439                        Log.e(TAG, methodStr + " failed: " + status.debugMessage);
440                    } else {
441                        newNetwork.value = network;
442                    }
443                });
444            } catch (RemoteException e) {
445                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
446                supplicantServiceDiedHandler();
447            }
448            if (statusSuccess.value) {
449                return getStaNetworkMockable(
450                        ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
451            } else {
452                return null;
453            }
454        }
455    }
456
457    /**
458     * Remove network from supplicant with network Id
459     *
460     * @return true if request is sent successfully, false otherwise.
461     */
462    private boolean removeNetwork(int id) {
463        synchronized (mLock) {
464            final String methodStr = "removeNetwork";
465            if (DBG) Log.i(TAG, methodStr);
466            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
467            try {
468                SupplicantStatus status = mISupplicantStaIface.removeNetwork(id);
469                return checkStatusAndLogFailure(status, methodStr);
470            } catch (RemoteException e) {
471                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
472                supplicantServiceDiedHandler();
473                return false;
474            }
475        }
476    }
477
478    /**
479     * Use this to mock the creation of SupplicantStaNetworkHal instance.
480     *
481     * @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL.
482     * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
483     * the call fails
484     */
485    protected SupplicantStaNetworkHal getStaNetworkMockable(
486            ISupplicantStaNetwork iSupplicantStaNetwork) {
487        return new SupplicantStaNetworkHal(iSupplicantStaNetwork, mContext, mWifiMonitor);
488    }
489
490    /**
491     * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
492     * the call fails
493     */
494    private SupplicantStaNetworkHal getNetwork(int id) {
495        synchronized (mLock) {
496            MutableBoolean statusSuccess = new MutableBoolean(false);
497            Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>();
498            final String methodStr = "getNetwork";
499            if (DBG) Log.i(TAG, methodStr);
500            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
501            try {
502                mISupplicantStaIface.getNetwork(id, (SupplicantStatus status,
503                        ISupplicantNetwork network) -> {
504                    statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS;
505                    if (!statusSuccess.value) {
506                        Log.e(TAG, methodStr + " failed: " + status.debugMessage);
507                    } else {
508                        gotNetwork.value = network;
509                    }
510                });
511            } catch (RemoteException e) {
512                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
513                supplicantServiceDiedHandler();
514            }
515            if (statusSuccess.value) {
516                return getStaNetworkMockable(
517                        ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder()));
518            } else {
519                return null;
520            }
521        }
522    }
523
524    /**
525     * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
526     * null if the call fails
527     */
528    private java.util.ArrayList<Integer> listNetworks() {
529        synchronized (mLock) {
530            MutableBoolean statusSuccess = new MutableBoolean(false);
531            Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
532            final String methodStr = "listNetworks";
533            if (DBG) Log.i(TAG, methodStr);
534            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
535            try {
536                mISupplicantStaIface.listNetworks((SupplicantStatus status,
537                        java.util.ArrayList<Integer> networkIds) -> {
538                    statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS;
539                    if (!statusSuccess.value) {
540                        Log.e(TAG, methodStr + " failed: " + status.debugMessage);
541                    } else {
542                        networkIdList.value = networkIds;
543                    }
544                });
545            } catch (RemoteException e) {
546                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
547                supplicantServiceDiedHandler();
548            }
549            if (statusSuccess.value) {
550                return networkIdList.value;
551            } else {
552                return null;
553            }
554        }
555    }
556
557    /** See ISupplicantIface.hal for documentation */
558    private boolean setWpsDeviceName(String name) {
559        synchronized (mLock) {
560            final String methodStr = "setWpsDeviceName";
561            if (DBG) Log.i(TAG, methodStr);
562            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
563            try {
564                SupplicantStatus status = mISupplicantStaIface.setWpsDeviceName(name);
565                return checkStatusAndLogFailure(status, methodStr);
566            } catch (RemoteException e) {
567                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
568                supplicantServiceDiedHandler();
569                return false;
570            }
571        }
572    }
573
574    /** See ISupplicantIface.hal for documentation */
575    private boolean setWpsDeviceType(byte[/* 8 */] type) {
576        synchronized (mLock) {
577            final String methodStr = "setWpsDeviceType";
578            if (DBG) Log.i(TAG, methodStr);
579            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
580            try {
581                SupplicantStatus status = mISupplicantStaIface.setWpsDeviceType(type);
582                return checkStatusAndLogFailure(status, methodStr);
583            } catch (RemoteException e) {
584                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
585                supplicantServiceDiedHandler();
586                return false;
587            }
588        }
589    }
590
591    /** See ISupplicantIface.hal for documentation */
592    private boolean setWpsManufacturer(String manufacturer) {
593        synchronized (mLock) {
594            final String methodStr = "setWpsManufacturer";
595            if (DBG) Log.i(TAG, methodStr);
596            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
597            try {
598                SupplicantStatus status = mISupplicantStaIface.setWpsManufacturer(manufacturer);
599                return checkStatusAndLogFailure(status, methodStr);
600            } catch (RemoteException e) {
601                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
602                supplicantServiceDiedHandler();
603                return false;
604            }
605        }
606    }
607
608    /** See ISupplicantIface.hal for documentation */
609    private boolean setWpsModelName(String modelName) {
610        synchronized (mLock) {
611            final String methodStr = "setWpsModelName";
612            if (DBG) Log.i(TAG, methodStr);
613            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
614            try {
615                SupplicantStatus status = mISupplicantStaIface.setWpsModelName(modelName);
616                return checkStatusAndLogFailure(status, methodStr);
617            } catch (RemoteException e) {
618                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
619                supplicantServiceDiedHandler();
620                return false;
621            }
622        }
623    }
624
625    /** See ISupplicantIface.hal for documentation */
626    private boolean setWpsModelNumber(String modelNumber) {
627        synchronized (mLock) {
628            final String methodStr = "setWpsModelNumber";
629            if (DBG) Log.i(TAG, methodStr);
630            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
631            try {
632                SupplicantStatus status = mISupplicantStaIface.setWpsModelNumber(modelNumber);
633                return checkStatusAndLogFailure(status, methodStr);
634            } catch (RemoteException e) {
635                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
636                supplicantServiceDiedHandler();
637                return false;
638            }
639        }
640    }
641
642    /** See ISupplicantIface.hal for documentation */
643    private boolean setWpsSerialNumber(String serialNumber) {
644        synchronized (mLock) {
645            final String methodStr = "setWpsSerialNumber";
646            if (DBG) Log.i(TAG, methodStr);
647            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
648            try {
649                SupplicantStatus status = mISupplicantStaIface.setWpsSerialNumber(serialNumber);
650                return checkStatusAndLogFailure(status, methodStr);
651            } catch (RemoteException e) {
652                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
653                supplicantServiceDiedHandler();
654                return false;
655            }
656        }
657    }
658
659    /** See ISupplicantIface.hal for documentation */
660    private boolean setWpsConfigMethods(short configMethods) {
661        synchronized (mLock) {
662            final String methodStr = "setWpsConfigMethods";
663            if (DBG) Log.i(TAG, methodStr);
664            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
665            try {
666                SupplicantStatus status = mISupplicantStaIface.setWpsConfigMethods(configMethods);
667                return checkStatusAndLogFailure(status, methodStr);
668            } catch (RemoteException e) {
669                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
670                supplicantServiceDiedHandler();
671                return false;
672            }
673        }
674    }
675
676    /**
677     * Trigger a reassociation even if the iface is currently connected.
678     *
679     * @return true if request is sent successfully, false otherwise.
680     */
681    public boolean reassociate() {
682        synchronized (mLock) {
683            final String methodStr = "reassociate";
684            if (DBG) Log.i(TAG, methodStr);
685            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
686            try {
687                SupplicantStatus status = mISupplicantStaIface.reassociate();
688                return checkStatusAndLogFailure(status, methodStr);
689            } catch (RemoteException e) {
690                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
691                supplicantServiceDiedHandler();
692                return false;
693            }
694        }
695    }
696
697    /**
698     * Trigger a reconnection if the iface is disconnected.
699     *
700     * @return true if request is sent successfully, false otherwise.
701     */
702    public boolean reconnect() {
703        synchronized (mLock) {
704            final String methodStr = "reconnect";
705            if (DBG) Log.i(TAG, methodStr);
706            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
707            try {
708                SupplicantStatus status = mISupplicantStaIface.reconnect();
709                return checkStatusAndLogFailure(status, methodStr);
710            } catch (RemoteException e) {
711                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
712                supplicantServiceDiedHandler();
713                return false;
714            }
715        }
716    }
717
718    /**
719     * Trigger a disconnection from the currently connected network.
720     *
721     * @return true if request is sent successfully, false otherwise.
722     */
723    public boolean disconnect() {
724        synchronized (mLock) {
725            final String methodStr = "disconnect";
726            if (DBG) Log.i(TAG, methodStr);
727            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
728            try {
729                SupplicantStatus status = mISupplicantStaIface.disconnect();
730                return checkStatusAndLogFailure(status, methodStr);
731            } catch (RemoteException e) {
732                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
733                supplicantServiceDiedHandler();
734                return false;
735            }
736        }
737    }
738
739    /**
740     * Enable or disable power save mode.
741     *
742     * @param enable true to enable, false to disable.
743     * @return true if request is sent successfully, false otherwise.
744     */
745    public boolean setPowerSave(boolean enable) {
746        synchronized (mLock) {
747            final String methodStr = "setPowerSave";
748            if (DBG) Log.i(TAG, methodStr);
749            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
750            try {
751                SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable);
752                return checkStatusAndLogFailure(status, methodStr);
753            } catch (RemoteException e) {
754                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
755                supplicantServiceDiedHandler();
756                return false;
757            }
758        }
759    }
760
761    /**
762     * Initiate TDLS discover with the specified AP.
763     *
764     * @param macAddress MAC Address of the AP.
765     * @return true if request is sent successfully, false otherwise.
766     */
767    public boolean initiateTdlsDiscover(String macAddress) {
768        return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress));
769    }
770    /** See ISupplicantStaIface.hal for documentation */
771    private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) {
772        synchronized (mLock) {
773            final String methodStr = "initiateTdlsDiscover";
774            if (DBG) Log.i(TAG, methodStr);
775            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
776            try {
777                SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress);
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     * Initiate TDLS setup with the specified AP.
789     *
790     * @param macAddress MAC Address of the AP.
791     * @return true if request is sent successfully, false otherwise.
792     */
793    public boolean initiateTdlsSetup(String macAddress) {
794        return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress));
795    }
796    /** See ISupplicantStaIface.hal for documentation */
797    private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) {
798        synchronized (mLock) {
799            final String methodStr = "initiateTdlsSetup";
800            if (DBG) Log.i(TAG, methodStr);
801            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
802            try {
803                SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress);
804                return checkStatusAndLogFailure(status, methodStr);
805            } catch (RemoteException e) {
806                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
807                supplicantServiceDiedHandler();
808                return false;
809            }
810        }
811    }
812
813    /**
814     * Initiate TDLS teardown with the specified AP.
815     * @param macAddress MAC Address of the AP.
816     * @return true if request is sent successfully, false otherwise.
817     */
818    public boolean initiateTdlsTeardown(String macAddress) {
819        return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress));
820    }
821
822    /** See ISupplicantStaIface.hal for documentation */
823    private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) {
824        synchronized (mLock) {
825            final String methodStr = "initiateTdlsTeardown";
826            if (DBG) Log.i(TAG, methodStr);
827            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
828            try {
829                SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress);
830                return checkStatusAndLogFailure(status, methodStr);
831            } catch (RemoteException e) {
832                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
833                supplicantServiceDiedHandler();
834                return false;
835            }
836        }
837    }
838
839    /**
840     * Request the specified ANQP elements |elements| from the specified AP |bssid|.
841     *
842     * @param bssid BSSID of the AP
843     * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
844     * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
845     * @return true if request is sent successfully, false otherwise.
846     */
847    public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements,
848                                     ArrayList<Integer> hs20SubTypes) {
849        return initiateAnqpQuery(
850                NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes);
851    }
852
853    /** See ISupplicantStaIface.hal for documentation */
854    private boolean initiateAnqpQuery(byte[/* 6 */] macAddress,
855            java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) {
856        synchronized (mLock) {
857            final String methodStr = "initiateAnqpQuery";
858            if (DBG) Log.i(TAG, methodStr);
859            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
860            try {
861                SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress,
862                        infoElements, subTypes);
863                return checkStatusAndLogFailure(status, methodStr);
864            } catch (RemoteException e) {
865                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
866                supplicantServiceDiedHandler();
867                return false;
868            }
869        }
870    }
871
872    /**
873     * Request the specified ANQP ICON from the specified AP |bssid|.
874     *
875     * @param bssid BSSID of the AP
876     * @param fileName Name of the file to request.
877     * @return true if request is sent successfully, false otherwise.
878     */
879    public boolean initiateHs20IconQuery(String bssid, String fileName) {
880        return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName);
881    }
882
883    /** See ISupplicantStaIface.hal for documentation */
884    private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) {
885        synchronized (mLock) {
886            final String methodStr = "initiateHs20IconQuery";
887            if (DBG) Log.i(TAG, methodStr);
888            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
889            try {
890                SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress,
891                        fileName);
892                return checkStatusAndLogFailure(status, methodStr);
893            } catch (RemoteException e) {
894                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
895                supplicantServiceDiedHandler();
896                return false;
897            }
898        }
899    }
900
901    /**
902     * Makes a callback to HIDL to getMacAddress from supplicant
903     *
904     * @return string containing the MAC address, or null on a failed call
905     */
906    public String getMacAddress() {
907        synchronized (mLock) {
908            MutableBoolean statusSuccess = new MutableBoolean(false);
909            final String methodStr = "getMacAddress";
910            if (DBG) Log.i(TAG, methodStr);
911            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
912            Mutable<String> gotMac = new Mutable<>();
913            try {
914                mISupplicantStaIface.getMacAddress((SupplicantStatus status,
915                        byte[/* 6 */] macAddr) -> {
916                    statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS;
917                    if (!statusSuccess.value) {
918                        Log.e(TAG, methodStr + " failed: " + status.debugMessage);
919                    } else {
920                        gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
921                    }
922                });
923            } catch (RemoteException e) {
924                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e);
925                supplicantServiceDiedHandler();
926            }
927            if (statusSuccess.value) {
928                return gotMac.value;
929            } else {
930                return null;
931            }
932        }
933    }
934
935    /**
936     * Start using the added RX filters.
937     *
938     * @return true if request is sent successfully, false otherwise.
939     */
940    public boolean startRxFilter() {
941        synchronized (mLock) {
942            final String methodStr = "startRxFilter";
943            if (DBG) Log.i(TAG, methodStr);
944            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
945            try {
946                SupplicantStatus status = mISupplicantStaIface.startRxFilter();
947                return checkStatusAndLogFailure(status, methodStr);
948            } catch (RemoteException e) {
949                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
950                supplicantServiceDiedHandler();
951                return false;
952            }
953        }
954    }
955
956    /**
957     * Stop using the added RX filters.
958     *
959     * @return true if request is sent successfully, false otherwise.
960     */
961    public boolean stopRxFilter() {
962        synchronized (mLock) {
963            final String methodStr = "stopRxFilter";
964            if (DBG) Log.i(TAG, methodStr);
965            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
966            try {
967                SupplicantStatus status = mISupplicantStaIface.stopRxFilter();
968                return checkStatusAndLogFailure(status, methodStr);
969            } catch (RemoteException e) {
970                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
971                supplicantServiceDiedHandler();
972                return false;
973            }
974        }
975    }
976
977    public static final byte RX_FILTER_TYPE_V4_MULTICAST =
978            ISupplicantStaIface.RxFilterType.V6_MULTICAST;
979    public static final byte RX_FILTER_TYPE_V6_MULTICAST =
980            ISupplicantStaIface.RxFilterType.V6_MULTICAST;
981    /**
982     * Add an RX filter.
983     *
984     * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or
985     *        {@link #RX_FILTER_TYPE_V6_MULTICAST} values.
986     * @return true if request is sent successfully, false otherwise.
987     */
988    private boolean addRxFilter(byte type) {
989        synchronized (mLock) {
990            final String methodStr = "addRxFilter";
991            if (DBG) Log.i(TAG, methodStr);
992            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
993            try {
994                SupplicantStatus status = mISupplicantStaIface.addRxFilter(type);
995                return checkStatusAndLogFailure(status, methodStr);
996            } catch (RemoteException e) {
997                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
998                supplicantServiceDiedHandler();
999                return false;
1000            }
1001        }
1002    }
1003
1004    /**
1005     * Remove an RX filter.
1006     *
1007     * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or
1008     *        {@link #RX_FILTER_TYPE_V6_MULTICAST} values.
1009     * @return true if request is sent successfully, false otherwise.
1010     */
1011    private boolean removeRxFilter(byte type) {
1012        synchronized (mLock) {
1013            final String methodStr = "removeRxFilter";
1014            if (DBG) Log.i(TAG, methodStr);
1015            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1016            try {
1017                SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type);
1018                return checkStatusAndLogFailure(status, methodStr);
1019            } catch (RemoteException e) {
1020                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1021                supplicantServiceDiedHandler();
1022                return false;
1023            }
1024        }
1025    }
1026
1027    public static final byte BT_COEX_MODE_ENABLED = ISupplicantStaIface.BtCoexistenceMode.ENABLED;
1028    public static final byte BT_COEX_MODE_DISABLED = ISupplicantStaIface.BtCoexistenceMode.DISABLED;
1029    public static final byte BT_COEX_MODE_SENSE = ISupplicantStaIface.BtCoexistenceMode.SENSE;
1030    /**
1031     * Set Bt co existense mode.
1032     *
1033     * @param mode one of the above {@link #BT_COEX_MODE_ENABLED}, {@link #BT_COEX_MODE_DISABLED}
1034     *             or {@link #BT_COEX_MODE_SENSE} values.
1035     * @return true if request is sent successfully, false otherwise.
1036     */
1037    public boolean setBtCoexistenceMode(byte mode) {
1038        synchronized (mLock) {
1039            final String methodStr = "setBtCoexistenceMode";
1040            if (DBG) Log.i(TAG, methodStr);
1041            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1042            try {
1043                SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode);
1044                return checkStatusAndLogFailure(status, methodStr);
1045            } catch (RemoteException e) {
1046                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1047                supplicantServiceDiedHandler();
1048                return false;
1049            }
1050        }
1051    }
1052
1053    /** Enable or disable BT coexistence mode.
1054     *
1055     * @param enable true to enable, false to disable.
1056     * @return true if request is sent successfully, false otherwise.
1057     */
1058    public boolean setBtCoexistenceScanModeEnabled(boolean enable) {
1059        synchronized (mLock) {
1060            final String methodStr = "setBtCoexistenceScanModeEnabled";
1061            if (DBG) Log.i(TAG, methodStr);
1062            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1063            try {
1064                SupplicantStatus status =
1065                        mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable);
1066                return checkStatusAndLogFailure(status, methodStr);
1067            } catch (RemoteException e) {
1068                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1069                supplicantServiceDiedHandler();
1070                return false;
1071            }
1072        }
1073    }
1074
1075    /**
1076     * Enable or disable suspend mode optimizations.
1077     *
1078     * @param enable true to enable, false otherwise.
1079     */
1080    public boolean setSuspendModeEnabled(boolean enable) {
1081        synchronized (mLock) {
1082            final String methodStr = "setSuspendModeEnabled";
1083            if (DBG) Log.i(TAG, methodStr);
1084            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1085            try {
1086                SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable);
1087                return checkStatusAndLogFailure(status, methodStr);
1088            } catch (RemoteException e) {
1089                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1090                supplicantServiceDiedHandler();
1091                return false;
1092            }
1093        }
1094    }
1095
1096    /**
1097     * Set country code.
1098     *
1099     * @param codeStr 2 byte ASCII string. For ex: US, CA.
1100     * @return true if request is sent successfully, false otherwise.
1101     */
1102    public boolean setCountryCode(String codeStr) {
1103        return setCountryCode(NativeUtil.stringToByteArray(codeStr));
1104    }
1105
1106    /** See ISupplicantStaIface.hal for documentation */
1107    private boolean setCountryCode(byte[/* 2 */] code) {
1108        synchronized (mLock) {
1109            final String methodStr = "setCountryCode";
1110            if (DBG) Log.i(TAG, methodStr);
1111            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1112            try {
1113                SupplicantStatus status = mISupplicantStaIface.setCountryCode(code);
1114                return checkStatusAndLogFailure(status, methodStr);
1115            } catch (RemoteException e) {
1116                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1117                supplicantServiceDiedHandler();
1118                return false;
1119            }
1120        }
1121    }
1122
1123    /** See ISupplicantStaIface.hal for documentation */
1124    private boolean startWpsRegistrar(byte[/* 6 */] bssid, String pin) {
1125        synchronized (mLock) {
1126            final String methodStr = "startWpsRegistrar";
1127            if (DBG) Log.i(TAG, methodStr);
1128            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1129            try {
1130                SupplicantStatus status = mISupplicantStaIface.startWpsRegistrar(bssid, pin);
1131                return checkStatusAndLogFailure(status, methodStr);
1132            } catch (RemoteException e) {
1133                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1134                supplicantServiceDiedHandler();
1135                return false;
1136            }
1137        }
1138    }
1139
1140    /** See ISupplicantStaIface.hal for documentation */
1141    private boolean startWpsPbc(byte[/* 6 */] bssid) {
1142        synchronized (mLock) {
1143            final String methodStr = "startWpsPbc";
1144            if (DBG) Log.i(TAG, methodStr);
1145            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1146            try {
1147                SupplicantStatus status = mISupplicantStaIface.startWpsPbc(bssid);
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    /** See ISupplicantStaIface.hal for documentation */
1158    private boolean startWpsPinKeypad(String pin) {
1159        synchronized (mLock) {
1160            final String methodStr = "startWpsPinKeypad";
1161            if (DBG) Log.i(TAG, methodStr);
1162            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1163            try {
1164                SupplicantStatus status = mISupplicantStaIface.startWpsPinKeypad(pin);
1165                return checkStatusAndLogFailure(status, methodStr);
1166            } catch (RemoteException e) {
1167                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1168                supplicantServiceDiedHandler();
1169                return false;
1170            }
1171        }
1172    }
1173
1174    /** See ISupplicantStaIface.hal for documentation */
1175    private String startWpsPinDisplay(byte[/* 6 */] bssid) {
1176        synchronized (mLock) {
1177            final String methodStr = "startWpsPinDisplay";
1178            if (DBG) Log.i(TAG, methodStr);
1179            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
1180            final Mutable<String> gotPin = new Mutable<>();
1181            try {
1182                mISupplicantStaIface.startWpsPinDisplay(bssid,
1183                        (SupplicantStatus status, String pin) -> {
1184                            if (checkStatusAndLogFailure(status, methodStr)) {
1185                                gotPin.value = pin;
1186                            }
1187                        });
1188            } catch (RemoteException e) {
1189                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1190                supplicantServiceDiedHandler();
1191            }
1192            return gotPin.value;
1193        }
1194    }
1195
1196    /** See ISupplicantStaIface.hal for documentation */
1197    private boolean cancelWps() {
1198        synchronized (mLock) {
1199            final String methodStr = "cancelWps";
1200            if (DBG) Log.i(TAG, methodStr);
1201            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1202            try {
1203                SupplicantStatus status = mISupplicantStaIface.cancelWps();
1204                return checkStatusAndLogFailure(status, methodStr);
1205            } catch (RemoteException e) {
1206                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1207                supplicantServiceDiedHandler();
1208                return false;
1209            }
1210        }
1211    }
1212
1213    /** See ISupplicantStaIface.hal for documentation */
1214    private boolean setExternalSim(boolean useExternalSim) {
1215        synchronized (mLock) {
1216            final String methodStr = "setExternalSim";
1217            if (DBG) Log.i(TAG, methodStr);
1218            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
1219            try {
1220                SupplicantStatus status = mISupplicantStaIface.setExternalSim(useExternalSim);
1221                return checkStatusAndLogFailure(status, methodStr);
1222            } catch (RemoteException e) {
1223                Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e);
1224                supplicantServiceDiedHandler();
1225                return false;
1226            }
1227        }
1228    }
1229
1230    /**
1231     * Returns false if SupplicantStaIface is null, and logs failure to call methodStr
1232     */
1233    private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) {
1234        if (DBG) Log.i(TAG, methodStr);
1235        if (mISupplicantStaIface == null) {
1236            Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null");
1237            return false;
1238        }
1239        return true;
1240    }
1241
1242    /**
1243     * Returns true if provided status code is SUCCESS, logs debug message and returns false
1244     * otherwise
1245     */
1246    private static boolean checkStatusAndLogFailure(SupplicantStatus status,
1247            final String methodStr) {
1248        if (DBG) Log.i(TAG, methodStr);
1249        if (status.code != SupplicantStatusCode.SUCCESS) {
1250            Log.e(TAG, methodStr + " failed: " + supplicantStatusCodeToString(status.code) + ", "
1251                    + status.debugMessage);
1252            return false;
1253        }
1254        return true;
1255    }
1256
1257    /**
1258     * Converts SupplicantStatus code values to strings for debug logging
1259     * TODO(b/34811152) Remove this, or make it more break resistance
1260     */
1261    public static String supplicantStatusCodeToString(int code) {
1262        switch (code) {
1263            case 0:
1264                return "SUCCESS";
1265            case 1:
1266                return "FAILURE_UNKNOWN";
1267            case 2:
1268                return "FAILURE_ARGS_INVALID";
1269            case 3:
1270                return "FAILURE_IFACE_INVALID";
1271            case 4:
1272                return "FAILURE_IFACE_UNKNOWN";
1273            case 5:
1274                return "FAILURE_IFACE_EXISTS";
1275            case 6:
1276                return "FAILURE_IFACE_DISABLED";
1277            case 7:
1278                return "FAILURE_IFACE_NOT_DISCONNECTED";
1279            case 8:
1280                return "FAILURE_NETWORK_INVALID";
1281            case 9:
1282                return "FAILURE_NETWORK_UNKNOWN";
1283            default:
1284                return "??? UNKNOWN_CODE";
1285        }
1286    }
1287
1288    private static class Mutable<E> {
1289        public E value;
1290
1291        Mutable() {
1292            value = null;
1293        }
1294
1295        Mutable(E value) {
1296            this.value = value;
1297        }
1298    }
1299
1300    private void logd(String s) {
1301        Log.d(TAG, s);
1302    }
1303
1304    private void logi(String s) {
1305        Log.i(TAG, s);
1306    }
1307
1308    private void loge(String s) {
1309        Log.e(TAG, s);
1310    }
1311}
1312