WifiVendorHal.java revision 542b204c2120a9c91324ccc86c6695012ac02ab7
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.annotation.Nullable;
19import android.hardware.wifi.V1_0.IWifiApIface;
20import android.hardware.wifi.V1_0.IWifiChip;
21import android.hardware.wifi.V1_0.IWifiChipEventCallback;
22import android.hardware.wifi.V1_0.IWifiIface;
23import android.hardware.wifi.V1_0.IWifiRttController;
24import android.hardware.wifi.V1_0.IWifiStaIface;
25import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback;
26import android.hardware.wifi.V1_0.IfaceType;
27import android.hardware.wifi.V1_0.StaRoamingConfig;
28import android.hardware.wifi.V1_0.StaRoamingState;
29import android.hardware.wifi.V1_0.StaScanData;
30import android.hardware.wifi.V1_0.StaScanResult;
31import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
32import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
33import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
34import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
35import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
36import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
37import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
38import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
39import android.hardware.wifi.V1_0.WifiStatus;
40import android.hardware.wifi.V1_0.WifiStatusCode;
41import android.net.apf.ApfCapabilities;
42import android.net.wifi.RttManager;
43import android.net.wifi.RttManager.ResponderConfig;
44import android.net.wifi.WifiInfo;
45import android.net.wifi.WifiLinkLayerStats;
46import android.net.wifi.WifiManager;
47import android.net.wifi.WifiScanner;
48import android.net.wifi.WifiWakeReasonAndCounts;
49import android.os.HandlerThread;
50import android.os.RemoteException;
51import android.util.Log;
52import android.util.MutableBoolean;
53import android.util.MutableInt;
54
55import com.android.internal.annotations.VisibleForTesting;
56import com.android.internal.util.ArrayUtils;
57import com.android.server.connectivity.KeepalivePacketData;
58import com.android.server.wifi.util.BitMask;
59import com.android.server.wifi.util.NativeUtil;
60
61import java.util.ArrayList;
62import java.util.Set;
63
64/**
65 * Vendor HAL via HIDL
66 */
67public class WifiVendorHal {
68
69    private static final String TAG = "WifiVendorHal";
70
71    // Vendor HAL HIDL interface objects.
72    private IWifiChip mIWifiChip;
73    private IWifiStaIface mIWifiStaIface;
74    private IWifiApIface mIWifiApIface;
75    private IWifiRttController mIWifiRttController;
76    private final HalDeviceManager mHalDeviceManager;
77    private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
78    private final HandlerThread mWifiStateMachineHandlerThread;
79    private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
80    private final IWifiChipEventCallback mIWifiChipEventCallback;
81
82    public WifiVendorHal(HalDeviceManager halDeviceManager,
83                         HandlerThread wifiStateMachineHandlerThread) {
84        mHalDeviceManager = halDeviceManager;
85        mWifiStateMachineHandlerThread = wifiStateMachineHandlerThread;
86        mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
87        mIWifiStaIfaceEventCallback = new StaIfaceEventCallback();
88        mIWifiChipEventCallback = new ChipEventCallback();
89    }
90
91    // TODO(mplass): figure out where we need locking in hidl world. b/33383725
92    public static final Object sLock = new Object();
93
94    private void handleRemoteException(RemoteException e) {
95        kilroy();
96        Log.e(TAG, "RemoteException in HIDL call " + e);
97    }
98
99    private void noteHidlError(WifiStatus status, String culprit) {
100        kilroy();
101        Log.e(TAG, "Error in " + culprit + " code: " + status.code
102                + " (" + status.description + ")");
103    }
104
105    /**
106     * Initialize the Hal device manager and register for status callbacks.
107     * @return
108     */
109    public boolean initialize() {
110        mHalDeviceManager.initialize();
111        mHalDeviceManager.registerStatusListener(
112                mHalDeviceManagerStatusCallbacks, mWifiStateMachineHandlerThread.getLooper());
113        return true;
114    }
115
116    /**
117     * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
118     * @return true for success
119     */
120    public boolean startVendorHalAp() {
121        return startVendorHal(AP_MODE);
122    }
123
124     /**
125     * Bring up the HIDL Vendor HAL and configure for STA (Station) mode
126     * @return true for success
127     */
128    public boolean startVendorHalSta() {
129        return startVendorHal(STA_MODE);
130    }
131
132
133    public static final boolean STA_MODE = true;
134    public static final boolean AP_MODE = false;
135
136    /**
137     * Bring up the HIDL Vendor HAL and configure for STA mode or AP mode.
138     *
139     * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
140     */
141    public boolean startVendorHal(boolean isStaMode) {
142        if (!mHalDeviceManager.start()) {
143            Log.e(TAG, "Failed to start the vendor HAL");
144            return false;
145        }
146        IWifiIface iface;
147        if (isStaMode) {
148            mIWifiStaIface = mHalDeviceManager.createStaIface(null, null);
149            if (mIWifiStaIface == null) {
150                Log.e(TAG, "Failed to create STA Iface. Vendor Hal start failed");
151                mHalDeviceManager.stop();
152                return false;
153            }
154            iface = (IWifiIface) mIWifiStaIface;
155            if (!registerStaIfaceCallback()) {
156                Log.e(TAG, "Failed to register sta iface callback");
157                mHalDeviceManager.stop();
158                return false;
159            }
160            mIWifiRttController = mHalDeviceManager.createRttController(iface);
161            if (mIWifiRttController == null) {
162                Log.e(TAG, "Failed to create RTT controller. Vendor Hal start failed");
163                stopVendorHal();
164                return false;
165            }
166            enableLinkLayerStats();
167        } else {
168            mIWifiApIface = mHalDeviceManager.createApIface(null, null);
169            if (mIWifiApIface == null) {
170                Log.e(TAG, "Failed to create AP Iface. Vendor Hal start failed");
171                stopVendorHal();
172                return false;
173            }
174            iface = (IWifiIface) mIWifiApIface;
175        }
176        mIWifiChip = mHalDeviceManager.getChip(iface);
177        if (mIWifiChip == null) {
178            Log.e(TAG, "Failed to get the chip created for the Iface. Vendor Hal start failed");
179            stopVendorHal();
180            return false;
181        }
182        if (!registerChipCallback()) {
183            Log.e(TAG, "Failed to register chip callback");
184            mHalDeviceManager.stop();
185            return false;
186        }
187        Log.i(TAG, "Vendor Hal started successfully");
188        return true;
189    }
190
191    /**
192     * Registers the sta iface callback.
193     */
194    private boolean registerStaIfaceCallback() {
195        synchronized (sLock) {
196            if (mIWifiStaIface == null || mIWifiStaIfaceEventCallback == null) return false;
197            try {
198                kilroy();
199                WifiStatus status =
200                        mIWifiStaIface.registerEventCallback(mIWifiStaIfaceEventCallback);
201                return (status.code == WifiStatusCode.SUCCESS);
202            } catch (RemoteException e) {
203                kilroy();
204                handleRemoteException(e);
205                return false;
206            }
207        }
208    }
209
210    /**
211     * Registers the sta iface callback.
212     */
213    private boolean registerChipCallback() {
214        synchronized (sLock) {
215            if (mIWifiChip == null || mIWifiChipEventCallback == null) return false;
216            try {
217                kilroy();
218                WifiStatus status = mIWifiChip.registerEventCallback(mIWifiChipEventCallback);
219                return (status.code == WifiStatusCode.SUCCESS);
220            } catch (RemoteException e) {
221                kilroy();
222                handleRemoteException(e);
223                return false;
224            }
225        }
226    }
227
228    /**
229     * Stops the HAL
230     */
231    public void stopVendorHal() {
232        mHalDeviceManager.stop();
233        Log.i(TAG, "Vendor Hal stopped");
234    }
235
236    /**
237     * Tests whether the HAL is running or not
238     */
239    public boolean isHalStarted() {
240        return (mIWifiStaIface != null || mIWifiApIface != null);
241    }
242
243    /**
244     * Gets the scan capabilities
245     *
246     * @param capabilities object to be filled in
247     * @return true for success. false for failure
248     */
249    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
250        kilroy();
251        throw new UnsupportedOperationException();
252    }
253
254    /**
255     * to be implemented
256     */
257    public boolean startScan(WifiNative.ScanSettings settings,
258                             WifiNative.ScanEventHandler eventHandler) {
259        kilroy();
260        throw new UnsupportedOperationException();
261    }
262
263    /**
264     * to be implemented
265     */
266    public void stopScan() {
267        kilroy();
268        throw new UnsupportedOperationException();
269    }
270
271    /**
272     * to be implemented
273     */
274    public void pauseScan() {
275        kilroy();
276        throw new UnsupportedOperationException();
277    }
278
279    /**
280     * to be implemented
281     */
282    public void restartScan() {
283        kilroy();
284        throw new UnsupportedOperationException();
285    }
286
287    /**
288     * to be implemented
289     */
290    public WifiScanner.ScanData[] getScanResults(boolean flush) {
291        kilroy();
292        throw new UnsupportedOperationException();
293    }
294
295    /**
296     * Get the link layer statistics
297     *
298     * Note - we always enable link layer stats on a STA interface.
299     *
300     * @return the statistics, or null if unable to do so
301     */
302    public WifiLinkLayerStats getWifiLinkLayerStats() {
303        kilroy();
304        synchronized (sLock) {
305            try {
306                if (mIWifiStaIface == null) return null;
307                kilroy();
308                WifiLinkLayerStats out = new WifiLinkLayerStats();
309                MutableBoolean ok = new MutableBoolean(false);
310                kilroy();
311                mIWifiStaIface.getLinkLayerStats((status, stats) -> {
312                            kilroy();
313                            if (status.code != WifiStatusCode.SUCCESS) return;
314                            out.status = 0; // TODO
315                            out.SSID = null; // TODO
316                            out.BSSID = null; // TODO
317                            out.beacon_rx = stats.iface.beaconRx;
318                            out.rssi_mgmt = stats.iface.avgRssiMgmt;
319                        /* WME Best Effort Access Category */
320                            out.rxmpdu_be = stats.iface.wmeBePktStats.rxMpdu;
321                            out.txmpdu_be = stats.iface.wmeBePktStats.txMpdu;
322                            out.lostmpdu_be = stats.iface.wmeBePktStats.lostMpdu;
323                            out.retries_be = stats.iface.wmeBePktStats.retries;
324                        /* WME Background Access Category */
325                            out.rxmpdu_bk = stats.iface.wmeBkPktStats.rxMpdu;
326                            out.txmpdu_bk = stats.iface.wmeBkPktStats.txMpdu;
327                            out.lostmpdu_bk = stats.iface.wmeBkPktStats.lostMpdu;
328                            out.retries_bk = stats.iface.wmeBkPktStats.retries;
329                        /* WME Video Access Category */
330                            out.rxmpdu_vi = stats.iface.wmeViPktStats.rxMpdu;
331                            out.txmpdu_vi = stats.iface.wmeViPktStats.txMpdu;
332                            out.lostmpdu_vi = stats.iface.wmeViPktStats.lostMpdu;
333                            out.retries_vi = stats.iface.wmeViPktStats.retries;
334                        /* WME Voice Access Category */
335                            out.rxmpdu_vo = stats.iface.wmeVoPktStats.rxMpdu;
336                            out.txmpdu_vo = stats.iface.wmeVoPktStats.txMpdu;
337                            out.lostmpdu_vo = stats.iface.wmeVoPktStats.lostMpdu;
338                            out.retries_vo = stats.iface.wmeVoPktStats.retries;
339                            out.on_time = stats.radio.onTimeInMs;
340                            out.tx_time = stats.radio.txTimeInMs;
341                            out.tx_time_per_level = new int[stats.radio.txTimeInMsPerLevel.size()];
342                            for (int i = 0; i < out.tx_time_per_level.length; i++) {
343                                out.tx_time_per_level[i] = stats.radio.txTimeInMsPerLevel.get(i);
344                            }
345                            out.rx_time = stats.radio.rxTimeInMs;
346                            out.on_time_scan = stats.radio.onTimeInMsForScan;
347                            kilroy();
348                            ok.value = true;
349                        }
350                );
351                return ok.value ? out : null;
352            } catch (RemoteException e) {
353                kilroy();
354                handleRemoteException(e);
355                return null;
356            }
357        }
358    }
359
360    @VisibleForTesting
361    boolean mLinkLayerStatsDebug = false;  // Passed to Hal
362
363    /**
364     * Enables the linkLayerStats in the Hal.
365     *
366     * This is called unconditionally whenever we create a STA interface.
367     *
368     */
369    private void enableLinkLayerStats() {
370        synchronized (sLock) {
371            try {
372                kilroy();
373                WifiStatus status;
374                status = mIWifiStaIface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
375                if (status.code != WifiStatusCode.SUCCESS) {
376                    kilroy();
377                    Log.e(TAG, "unable to enable link layer stats collection");
378                }
379            } catch (RemoteException e) {
380                kilroy();
381                handleRemoteException(e);
382            }
383        }
384    }
385
386    /**
387     * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps
388     */
389    private static final int[][] sFeatureCapabilityTranslation = {
390            {WifiManager.WIFI_FEATURE_INFRA_5G,
391                    IWifiStaIface.StaIfaceCapabilityMask.STA_5G
392            },
393            {WifiManager.WIFI_FEATURE_PASSPOINT,
394                    IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
395            },
396            {WifiManager.WIFI_FEATURE_SCANNER,
397                    IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
398            },
399            {WifiManager.WIFI_FEATURE_PNO,
400                    IWifiStaIface.StaIfaceCapabilityMask.PNO
401            },
402            {WifiManager.WIFI_FEATURE_TDLS,
403                    IWifiStaIface.StaIfaceCapabilityMask.TDLS
404            },
405            {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
406                    IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
407            },
408            {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
409                    IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
410            },
411            {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
412                    IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
413            },
414            {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
415                    IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
416            },
417            {WifiManager.WIFI_FEATURE_CONFIG_NDO,
418                    IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
419            },
420            {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
421                    IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
422            },
423            {WifiManager.WIFI_FEATURE_IE_WHITELIST,
424                    IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
425            },
426            {WifiManager.WIFI_FEATURE_SCAN_RAND,
427                    IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
428            },
429    };
430
431    /**
432     * Feature bit mask translation for STAs
433     *
434     * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
435     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
436     */
437    @VisibleForTesting
438    int wifiFeatureMaskFromStaCapabilities(int capabilities) {
439        int features = 0;
440        for (int i = 0; i < sFeatureCapabilityTranslation.length; i++) {
441            if ((capabilities & sFeatureCapabilityTranslation[i][1]) != 0) {
442                features |= sFeatureCapabilityTranslation[i][0];
443            }
444        }
445        return features;
446    }
447
448    /**
449     * Get the supported features
450     * <p>
451     * Note that not all the WifiManager.WIFI_FEATURE_* bits are supplied through
452     * this call. //TODO(b/34900537) fix this
453     *
454     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
455     */
456    public int getSupportedFeatureSet() {
457        int featureSet = 0;
458        try {
459            final MutableInt feat = new MutableInt(0);
460            synchronized (sLock) {
461                if (mIWifiStaIface != null) {
462                    mIWifiStaIface.getCapabilities((status, capabilities) -> {
463                        if (status.code != WifiStatusCode.SUCCESS) return;
464                        feat.value = wifiFeatureMaskFromStaCapabilities(capabilities);
465                    });
466                }
467            }
468            featureSet = feat.value;
469        } catch (RemoteException e) {
470            handleRemoteException(e);
471            return 0;
472        }
473
474        Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
475        if (supportedIfaceTypes.contains(IfaceType.STA)) {
476            featureSet |= WifiManager.WIFI_FEATURE_INFRA;
477        }
478        if (supportedIfaceTypes.contains(IfaceType.AP)) {
479            featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
480        }
481        if (supportedIfaceTypes.contains(IfaceType.P2P)) {
482            featureSet |= WifiManager.WIFI_FEATURE_P2P;
483        }
484        if (supportedIfaceTypes.contains(IfaceType.NAN)) {
485            featureSet |= WifiManager.WIFI_FEATURE_AWARE;
486        }
487
488        return featureSet;
489    }
490
491    /* RTT related commands/events */
492
493    /**
494     * Starts a new rtt request
495     *
496     * @param params
497     * @param handler
498     * @return success indication
499     */
500    public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) {
501        kilroy();
502        throw new UnsupportedOperationException();
503    }
504
505    /**
506     * Cancels an outstanding rtt request
507     *
508     * @param params
509     * @return true if there was an outstanding request and it was successfully cancelled
510     */
511    public boolean cancelRtt(RttManager.RttParams[] params) {
512        kilroy();
513        throw new UnsupportedOperationException();
514    }
515
516    /**
517     * Enables RTT responder role on the device.
518     *
519     * @return {@link ResponderConfig} if the responder role is successfully enabled,
520     * {@code null} otherwise.
521     */
522    @Nullable
523    public ResponderConfig enableRttResponder(int timeoutSeconds) {
524        kilroy();
525        throw new UnsupportedOperationException();
526    }
527
528    /**
529     * Disables RTT responder role.
530     *
531     * @return {@code true} if responder role is successfully disabled,
532     * {@code false} otherwise.
533     */
534    public boolean disableRttResponder() {
535        kilroy();
536        throw new UnsupportedOperationException();
537    }
538
539    /**
540     * Set the MAC OUI during scanning.
541     *
542     * An OUI {Organizationally Unique Identifier} is a 24-bit number that
543     * uniquely identifies a vendor or manufacturer.
544     *
545     * @param oui
546     * @return true for success
547     */
548    public boolean setScanningMacOui(byte[] oui) {
549        kilroy();
550        if (oui == null) return false;
551        kilroy();
552        if (oui.length != 3) return false;
553        kilroy();
554        synchronized (sLock) {
555            try {
556                if (mIWifiStaIface == null) return false;
557                WifiStatus status = mIWifiStaIface.setScanningMacOui(oui);
558                if (status.code != WifiStatusCode.SUCCESS) return false;
559                kilroy();
560                return true;
561            } catch (RemoteException e) {
562                handleRemoteException(e);
563                return false;
564            }
565        }
566    }
567
568    /**
569     * not supported
570     */
571    public int[] getChannelsForBand(int band) {
572        kilroy();
573        throw new UnsupportedOperationException();
574    }
575
576    /**
577     * not supported
578     */
579    public boolean isGetChannelsForBandSupported() {
580        kilroy();
581        throw new UnsupportedOperationException();
582    }
583
584    /**
585     * Set DFS - actually, this is always on.
586     *
587     * @param dfsOn
588     * @return success indication
589     */
590    public boolean setDfsFlag(boolean dfsOn) {
591        kilroy();
592        throw new UnsupportedOperationException();
593    }
594
595    /**
596     * RTT (Round Trip Time) measurement capabilities of the device.
597     */
598    public RttManager.RttCapabilities getRttCapabilities() {
599        kilroy();
600        throw new UnsupportedOperationException();
601    }
602
603    /**
604     * Get the APF (Android Packet Filter) capabilities of the device
605     */
606    public ApfCapabilities getApfCapabilities() {
607        class AnswerBox {
608            public ApfCapabilities value = sNoApfCapabilities;
609        }
610        synchronized (sLock) {
611            try {
612                if (mIWifiStaIface == null) return sNoApfCapabilities;
613                AnswerBox box = new AnswerBox();
614                mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
615                    if (status.code != WifiStatusCode.SUCCESS) return;
616                    box.value = new ApfCapabilities(
617                        /* apfVersionSupported */   capabilities.version,
618                        /* maximumApfProgramSize */ capabilities.maxLength,
619                        /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
620                });
621                return box.value;
622            } catch (RemoteException e) {
623                handleRemoteException(e);
624                return sNoApfCapabilities;
625            }
626        }
627    }
628
629    private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
630
631    /**
632     * Installs an APF program on this iface, replacing any existing program.
633     *
634     * @param filter is the android packet filter program
635     * @return true for success
636     */
637    public boolean installPacketFilter(byte[] filter) {
638        kilroy();
639        int cmdId = 0; //TODO(b/34901818) We only aspire to support one program at a time
640        if (filter == null) return false;
641        // Copy the program before taking the lock.
642        ArrayList<Byte> program = new ArrayList<>(filter.length);
643        for (byte b : filter) {
644            program.add(b);
645        }
646        synchronized (sLock) {
647            try {
648                if (mIWifiStaIface == null) return false;
649                WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
650                if (status.code != WifiStatusCode.SUCCESS) return false;
651                kilroy();
652                return true;
653            } catch (RemoteException e) {
654                handleRemoteException(e);
655                return false;
656            }
657        }
658    }
659
660    /**
661     * Set country code for this AP iface.
662     *
663     * @param countryCode - two-letter country code (as ISO 3166)
664     * @return true for success
665     */
666    public boolean setCountryCodeHal(String countryCode) {
667        kilroy();
668        if (countryCode == null) return false;
669        if (countryCode.length() != 2) return false;
670        byte[] code;
671        try {
672            code = NativeUtil.stringToByteArray(countryCode);
673        } catch (IllegalArgumentException e) {
674            kilroy();
675            return false;
676        }
677        synchronized (sLock) {
678            try {
679                if (mIWifiApIface == null) return false;
680                kilroy();
681                WifiStatus status = mIWifiApIface.setCountryCode(code);
682                if (status.code != WifiStatusCode.SUCCESS) return false;
683                kilroy();
684                return true;
685            } catch (RemoteException e) {
686                handleRemoteException(e);
687                return false;
688            }
689        }
690    }
691
692    /**
693     * to be implemented TODO(b/34901821)
694     */
695    public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
696        kilroy();
697        throw new UnsupportedOperationException();
698    }
699
700    /**
701     * Control debug data collection
702     *
703     * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
704     * @param flags              Ignored.
705     * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
706     * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
707     * @param ringName           Name of the ring for which data collection is to start.
708     * @return true for success
709     */
710    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
711                                          int minDataSizeInBytes, String ringName) {
712        kilroy();
713        synchronized (sLock) {
714            try {
715                if (mIWifiChip == null) return false;
716                kilroy();
717                // note - flags are not used
718                WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer(
719                        ringName,
720                        verboseLevel,
721                        maxIntervalInSec,
722                        minDataSizeInBytes
723                );
724                return status.code == WifiStatusCode.SUCCESS;
725            } catch (RemoteException e) {
726                kilroy();
727                handleRemoteException(e);
728                return false;
729            }
730        }
731    }
732
733    /**
734     * Pointlessly fail
735     *
736     * @return -1
737     */
738    public int getSupportedLoggerFeatureSet() {
739        return -1;
740    }
741
742    /**
743     * to be implemented TODO(b/34901821)
744     */
745    public boolean resetLogHandler() {
746        kilroy();
747        throw new UnsupportedOperationException();
748    }
749
750    private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
751
752    /**
753     * Vendor-provided wifi driver version string
754     */
755    public String getDriverVersion() {
756        synchronized (sLock) {
757            if (mDriverDescription == null) requestChipDebugInfo();
758            return mDriverDescription;
759        }
760    }
761
762    private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
763
764    /**
765     * Vendor-provided wifi firmware version string
766     */
767    public String getFirmwareVersion() {
768        synchronized (sLock) {
769            if (mFirmwareDescription == null) requestChipDebugInfo();
770            return mFirmwareDescription;
771        }
772    }
773
774    /**
775     * Refreshes our idea of the driver and firmware versions
776     */
777    private void requestChipDebugInfo() {
778        mDriverDescription = null;
779        mFirmwareDescription = null;
780        try {
781            if (mIWifiChip == null) return;
782            mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
783                if (status.code != WifiStatusCode.SUCCESS) return;
784                mDriverDescription = chipDebugInfo.driverDescription;
785                mFirmwareDescription = chipDebugInfo.firmwareDescription;
786            });
787        } catch (RemoteException e) {
788            handleRemoteException(e);
789            return;
790        }
791        Log.e(TAG, "Driver: " + mDriverDescription + " Firmware: " + mFirmwareDescription);
792    }
793
794    /**
795     * Creates RingBufferStatus from the Hal version
796     */
797    private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) {
798        WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus();
799        ans.name = h.ringName;
800        ans.flag = frameworkRingBufferFlagsFromHal(h.flags);
801        ans.ringBufferId = h.ringId;
802        ans.ringBufferByteSize = h.sizeInBytes;
803        ans.verboseLevel = h.verboseLevel;
804        // Remaining fields are unavailable
805        //  writtenBytes;
806        //  readBytes;
807        //  writtenRecords;
808        return ans;
809    }
810
811    /**
812     * Translates a hal wifiDebugRingBufferFlag to the WifiNative version
813     */
814    private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) {
815        BitMask checkoff = new BitMask(wifiDebugRingBufferFlag);
816        int flags = 0;
817        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) {
818            flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES;
819        }
820        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) {
821            flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES;
822        }
823        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) {
824            flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES;
825        }
826        if (checkoff.value != 0) {
827            throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value);
828        }
829        return flags;
830    }
831
832    /**
833     * Creates array of RingBufferStatus from the Hal version
834     */
835    private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray(
836            ArrayList<WifiDebugRingBufferStatus> ringBuffers) {
837        WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()];
838        int i = 0;
839        for (WifiDebugRingBufferStatus b : ringBuffers) {
840            ans[i++] = ringBufferStatus(b);
841        }
842        return ans;
843    }
844
845    /**
846     * API to get the status of all ring buffers supported by driver
847     */
848    public WifiNative.RingBufferStatus[] getRingBufferStatus() {
849        kilroy();
850        class AnswerBox {
851            public WifiNative.RingBufferStatus[] value = null;
852        }
853        AnswerBox ans = new AnswerBox();
854        synchronized (sLock) {
855            if (mIWifiChip == null) return null;
856            try {
857                kilroy();
858                mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> {
859                    kilroy();
860                    if (status.code != WifiStatusCode.SUCCESS) return;
861                    ans.value = makeRingBufferStatusArray(ringBuffers);
862                });
863            } catch (RemoteException e) {
864                kilroy();
865                handleRemoteException(e);
866                return null;
867            }
868        }
869        return ans.value;
870    }
871
872    /**
873     * indicates to driver that all
874     * the data has to be uploaded urgently
875     */
876    public boolean getRingBufferData(String ringName) {
877        kilroy();
878        synchronized (sLock) {
879            try {
880                if (mIWifiChip == null) return false;
881                kilroy();
882                WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName);
883                return status.code == WifiStatusCode.SUCCESS;
884            } catch (RemoteException e) {
885                handleRemoteException(e);
886                return false;
887            }
888        }
889    }
890
891    /**
892     * Request vendor debug info from the firmware
893     */
894    public byte[] getFwMemoryDump() {
895        kilroy();
896        class AnswerBox {
897            public byte[] value;
898        }
899        AnswerBox ans = new AnswerBox();
900        synchronized (sLock) {
901            if (mIWifiChip == null) return (null);
902            try {
903                kilroy();
904                mIWifiChip.requestFirmwareDebugDump((status, blob) -> {
905                    kilroy();
906                    if (status.code != WifiStatusCode.SUCCESS) return;
907                    kilroy();
908                    ans.value = NativeUtil.byteArrayFromArrayList(blob);
909                });
910            } catch (RemoteException e) {
911                kilroy();
912                handleRemoteException(e);
913                return null;
914            }
915        }
916        return ans.value;
917    }
918
919    /**
920     * Request vendor debug info from the driver
921     */
922    public byte[] getDriverStateDump() {
923        kilroy();
924        class AnswerBox {
925            public byte[] value;
926        }
927        AnswerBox ans = new AnswerBox();
928        synchronized (sLock) {
929            if (mIWifiChip == null) return (null);
930            try {
931                kilroy();
932                mIWifiChip.requestDriverDebugDump((status, blob) -> {
933                    kilroy();
934                    if (status.code != WifiStatusCode.SUCCESS) return;
935                    kilroy();
936                    ans.value = NativeUtil.byteArrayFromArrayList(blob);
937                });
938            } catch (RemoteException e) {
939                kilroy();
940                handleRemoteException(e);
941                return null;
942            }
943        }
944        return ans.value;
945    }
946
947    /**
948     * Start packet fate monitoring
949     *
950     * Once started, monitoring remains active until HAL is unloaded.
951     *
952     * @return true for success
953     */
954    public boolean startPktFateMonitoring() {
955        kilroy();
956        synchronized (sLock) {
957            if (mIWifiStaIface == null) return false;
958            try {
959                kilroy();
960                WifiStatus status = mIWifiStaIface.startDebugPacketFateMonitoring();
961                return status.code == WifiStatusCode.SUCCESS;
962            } catch (RemoteException e) {
963                kilroy();
964                handleRemoteException(e);
965                return false;
966            }
967        }
968    }
969
970    private byte halToFrameworkPktFateFrameType(int type) {
971        switch (type) {
972            case WifiDebugPacketFateFrameType.UNKNOWN:
973                return WifiLoggerHal.FRAME_TYPE_UNKNOWN;
974            case WifiDebugPacketFateFrameType.ETHERNET_II:
975                return WifiLoggerHal.FRAME_TYPE_ETHERNET_II;
976            case WifiDebugPacketFateFrameType.MGMT_80211:
977                return WifiLoggerHal.FRAME_TYPE_80211_MGMT;
978            default:
979                throw new IllegalArgumentException("bad " + type);
980        }
981    }
982
983    private byte halToFrameworkRxPktFate(int type) {
984        switch (type) {
985            case WifiDebugRxPacketFate.SUCCESS:
986                return WifiLoggerHal.RX_PKT_FATE_SUCCESS;
987            case WifiDebugRxPacketFate.FW_QUEUED:
988                return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED;
989            case WifiDebugRxPacketFate.FW_DROP_FILTER:
990                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER;
991            case WifiDebugRxPacketFate.FW_DROP_INVALID:
992                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID;
993            case WifiDebugRxPacketFate.FW_DROP_NOBUFS:
994                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS;
995            case WifiDebugRxPacketFate.FW_DROP_OTHER:
996                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER;
997            case WifiDebugRxPacketFate.DRV_QUEUED:
998                return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED;
999            case WifiDebugRxPacketFate.DRV_DROP_FILTER:
1000                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER;
1001            case WifiDebugRxPacketFate.DRV_DROP_INVALID:
1002                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID;
1003            case WifiDebugRxPacketFate.DRV_DROP_NOBUFS:
1004                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS;
1005            case WifiDebugRxPacketFate.DRV_DROP_OTHER:
1006                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER;
1007            default:
1008                throw new IllegalArgumentException("bad " + type);
1009        }
1010    }
1011
1012    private byte halToFrameworkTxPktFate(int type) {
1013        switch (type) {
1014            case WifiDebugTxPacketFate.ACKED:
1015                return WifiLoggerHal.TX_PKT_FATE_ACKED;
1016            case WifiDebugTxPacketFate.SENT:
1017                return WifiLoggerHal.TX_PKT_FATE_SENT;
1018            case WifiDebugTxPacketFate.FW_QUEUED:
1019                return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED;
1020            case WifiDebugTxPacketFate.FW_DROP_INVALID:
1021                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID;
1022            case WifiDebugTxPacketFate.FW_DROP_NOBUFS:
1023                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS;
1024            case WifiDebugTxPacketFate.FW_DROP_OTHER:
1025                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER;
1026            case WifiDebugTxPacketFate.DRV_QUEUED:
1027                return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED;
1028            case WifiDebugTxPacketFate.DRV_DROP_INVALID:
1029                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID;
1030            case WifiDebugTxPacketFate.DRV_DROP_NOBUFS:
1031                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS;
1032            case WifiDebugTxPacketFate.DRV_DROP_OTHER:
1033                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER;
1034            default:
1035                throw new IllegalArgumentException("bad " + type);
1036        }
1037    }
1038
1039    /**
1040     * Retrieve fates of outbound packets
1041     *
1042     * Reports the outbound frames for the most recent association (space allowing).
1043     *
1044     * @param reportBufs
1045     * @return true for success
1046     */
1047    public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
1048        kilroy();
1049        if (ArrayUtils.isEmpty(reportBufs)) return false;
1050        synchronized (sLock) {
1051            if (mIWifiStaIface == null) return false;
1052            try {
1053                kilroy();
1054                MutableBoolean ok = new MutableBoolean(false);
1055                mIWifiStaIface.getDebugTxPacketFates((status, fates) -> {
1056                            kilroy();
1057                            if (status.code != WifiStatusCode.SUCCESS) return;
1058                            int i = 0;
1059                            for (WifiDebugTxPacketFateReport fate : fates) {
1060                                kilroy();
1061                                if (i >= reportBufs.length) break;
1062                                byte code = halToFrameworkTxPktFate(fate.fate);
1063                                long us = fate.frameInfo.driverTimestampUsec;
1064                                byte type =
1065                                        halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1066                                byte[] frame =
1067                                        NativeUtil.byteArrayFromArrayList(
1068                                                fate.frameInfo.frameContent);
1069                                reportBufs[i++] =
1070                                        new WifiNative.TxFateReport(code, us, type, frame);
1071                            }
1072                            ok.value = true;
1073                        }
1074                );
1075                return ok.value;
1076            } catch (RemoteException e) {
1077                kilroy();
1078                handleRemoteException(e);
1079                return false;
1080            }
1081        }
1082    }
1083
1084    /**
1085     * Retrieve fates of inbound packets
1086     *
1087     * Reports the inbound frames for the most recent association (space allowing).
1088     *
1089     * @param reportBufs
1090     * @return true for success
1091     */
1092    public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
1093        kilroy();
1094        if (ArrayUtils.isEmpty(reportBufs)) return false;
1095        synchronized (sLock) {
1096            if (mIWifiStaIface == null) return false;
1097            try {
1098                kilroy();
1099                MutableBoolean ok = new MutableBoolean(false);
1100                mIWifiStaIface.getDebugRxPacketFates((status, fates) -> {
1101                            kilroy();
1102                            if (status.code != WifiStatusCode.SUCCESS) return;
1103                            int i = 0;
1104                            for (WifiDebugRxPacketFateReport fate : fates) {
1105                                kilroy();
1106                                if (i >= reportBufs.length) break;
1107                                byte code = halToFrameworkRxPktFate(fate.fate);
1108                                long us = fate.frameInfo.driverTimestampUsec;
1109                                byte type =
1110                                        halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1111                                byte[] frame =
1112                                        NativeUtil.byteArrayFromArrayList(
1113                                                fate.frameInfo.frameContent);
1114                                reportBufs[i++] =
1115                                        new WifiNative.RxFateReport(code, us, type, frame);
1116                            }
1117                            ok.value = true;
1118                        }
1119                );
1120                return ok.value;
1121            } catch (RemoteException e) {
1122                kilroy();
1123                handleRemoteException(e);
1124                return false;
1125            }
1126        }
1127    }
1128
1129    /**
1130     * Start sending the specified keep alive packets periodically.
1131     * @param slot
1132     * @param srcMac
1133     * @param keepAlivePacket
1134     * @param periodInMs
1135     * @return 0 for success, -1 for error
1136     */
1137    public int startSendingOffloadedPacket(
1138            int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs) {
1139        Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " periodInMs=" + periodInMs);
1140
1141        ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(keepAlivePacket.data);
1142        short protocol = (short) (keepAlivePacket.protocol);
1143
1144        synchronized (sLock) {
1145            if (mIWifiStaIface == null) return -1;
1146            try {
1147                WifiStatus status = mIWifiStaIface.startSendingKeepAlivePackets(
1148                        slot,
1149                        data,
1150                        protocol,
1151                        srcMac,
1152                        keepAlivePacket.dstMac,
1153                        periodInMs);
1154                if (status.code != WifiStatusCode.SUCCESS) return -1;
1155                return 0;
1156            } catch (RemoteException e) {
1157                kilroy();
1158                handleRemoteException(e);
1159                return -1;
1160            }
1161        }
1162    }
1163
1164    /**
1165     * Stop sending the specified keep alive packets.
1166     *
1167     * @param slot id - same as startSendingOffloadedPacket call.
1168     * @return 0 for success, -1 for error
1169     */
1170    public int stopSendingOffloadedPacket(int slot) {
1171        Log.d(TAG, "stopSendingOffloadedPacket " + slot);
1172
1173        synchronized (sLock) {
1174            if (mIWifiStaIface == null) return -1;
1175            try {
1176                WifiStatus wifiStatus = mIWifiStaIface.stopSendingKeepAlivePackets(slot);
1177                if (wifiStatus.code != WifiStatusCode.SUCCESS) return -1;
1178                kilroy();
1179                return 0;
1180            } catch (RemoteException e) {
1181                handleRemoteException(e);
1182                return -1;
1183            }
1184        }
1185    }
1186
1187    /**
1188     * Start RSSI monitoring on the currently connected access point.
1189     *
1190     * @param maxRssi          Maximum RSSI threshold.
1191     * @param minRssi          Minimum RSSI threshold.
1192     * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
1193     * @return 0 for success, -1 for failure
1194     */
1195    public int startRssiMonitoring(byte maxRssi, byte minRssi,
1196                                   WifiNative.WifiRssiEventHandler rssiEventHandler) {
1197        kilroy();
1198        throw new UnsupportedOperationException();
1199    }
1200
1201    /**
1202     * Stop RSSI monitoring
1203     *
1204     * @return 0 for success, -1 for failure
1205     */
1206    public int stopRssiMonitoring() {
1207        kilroy();
1208        throw new UnsupportedOperationException();
1209    }
1210
1211    //TODO - belongs in NativeUtil
1212    private static int[] intsFromArrayList(ArrayList<Integer> a) {
1213        if (a == null) return null;
1214        int[] b = new int[a.size()];
1215        int i = 0;
1216        for (Integer e : a) b[i++] = e;
1217        return b;
1218    }
1219
1220    /**
1221     * Translates from Hal version of wake reason stats to the framework version of same
1222     *
1223     * @param h - Hal version of wake reason stats
1224     * @return framework version of same
1225     */
1226    private static WifiWakeReasonAndCounts halToFrameworkWakeReasons(
1227            WifiDebugHostWakeReasonStats h) {
1228        if (h == null) return null;
1229        WifiWakeReasonAndCounts ans = new WifiWakeReasonAndCounts();
1230        ans.totalCmdEventWake = h.totalCmdEventWakeCnt;
1231        ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt;
1232        ans.totalRxDataWake = h.totalRxPacketWakeCnt;
1233        ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt;
1234        ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt;
1235        ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt;
1236        ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt;
1237        ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt;
1238        ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra;
1239        ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na;
1240        ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns;
1241        ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt;
1242        ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt;
1243        ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt;
1244        ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType);
1245        ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType);
1246        return ans;
1247    }
1248
1249    /**
1250     * Fetch the host wakeup reasons stats from wlan driver.
1251     *
1252     * @return the |WifiWakeReasonAndCounts| from the wlan driver, or null on failure.
1253     */
1254    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
1255        kilroy();
1256        class AnswerBox {
1257            public WifiDebugHostWakeReasonStats value = null;
1258        }
1259        AnswerBox ans = new AnswerBox();
1260        synchronized (sLock) {
1261            if (mIWifiChip == null) return null;
1262            try {
1263                kilroy();
1264                mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> {
1265                    kilroy();
1266                    if (status.code == WifiStatusCode.SUCCESS) {
1267                        ans.value = stats;
1268                    }
1269                });
1270                kilroy();
1271                return halToFrameworkWakeReasons(ans.value);
1272            } catch (RemoteException e) {
1273                kilroy();
1274                handleRemoteException(e);
1275                return null;
1276            }
1277        }
1278    }
1279
1280    /**
1281     * Enable/Disable Neighbour discovery offload functionality in the firmware.
1282     *
1283     * @param enabled true to enable, false to disable.
1284     */
1285    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
1286        kilroy();
1287        synchronized (sLock) {
1288            if (mIWifiStaIface == null) return false;
1289            kilroy();
1290            try {
1291                kilroy();
1292                WifiStatus wifiStatus = mIWifiStaIface.enableNdOffload(enabled);
1293                if (wifiStatus.code != WifiStatusCode.SUCCESS) {
1294                    kilroy();
1295                    noteHidlError(wifiStatus, "configureNeighborDiscoveryOffload");
1296                    return false;
1297                }
1298            } catch (RemoteException e) {
1299                kilroy();
1300                handleRemoteException(e);
1301                return false;
1302            }
1303        }
1304        return true;
1305    }
1306
1307    // Firmware roaming control.
1308
1309    /**
1310     * Query the firmware roaming capabilities.
1311     *
1312     * @param capabilities object to be filled in
1313     * @return true for success; false for failure
1314     */
1315    public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
1316        kilroy();
1317        synchronized (sLock) {
1318            kilroy();
1319            try {
1320                kilroy();
1321                if (!isHalStarted()) return false;
1322                MutableBoolean ok = new MutableBoolean(false);
1323                WifiNative.RoamingCapabilities out = capabilities;
1324                mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
1325                    kilroy();
1326                    if (status.code != WifiStatusCode.SUCCESS) return;
1327                    out.maxBlacklistSize = cap.maxBlacklistSize;
1328                    out.maxWhitelistSize = cap.maxWhitelistSize;
1329                    ok.value = true;
1330                });
1331                return ok.value;
1332            } catch (RemoteException e) {
1333                kilroy();
1334                handleRemoteException(e);
1335                return false;
1336            }
1337        }
1338    }
1339
1340    /**
1341     * Enable/disable firmware roaming.
1342     *
1343     * @param state the intended roaming state
1344     * @return SUCCESS, FAILURE, or BUSY
1345     */
1346    public int enableFirmwareRoaming(int state) {
1347        kilroy();
1348        synchronized (sLock) {
1349            if (mIWifiStaIface == null) return WifiStatusCode.ERROR_NOT_STARTED;
1350            kilroy();
1351            try {
1352                kilroy();
1353                byte val;
1354                switch (state) {
1355                    case WifiNative.DISABLE_FIRMWARE_ROAMING:
1356                        val = StaRoamingState.DISABLED;
1357                        break;
1358                    case WifiNative.ENABLE_FIRMWARE_ROAMING:
1359                        val = StaRoamingState.ENABLED;
1360                        break;
1361                    default:
1362                        Log.e(TAG, "enableFirmwareRoaming invalid argument " + state);
1363                        return WifiStatusCode.ERROR_INVALID_ARGS;
1364                }
1365
1366                kilroy();
1367                WifiStatus status = mIWifiStaIface.setRoamingState(val);
1368                Log.d(TAG, "setRoamingState returned " + status.code);
1369                return status.code;
1370            } catch (RemoteException e) {
1371                kilroy();
1372                handleRemoteException(e);
1373                return WifiStatusCode.ERROR_UNKNOWN;
1374            }
1375        }
1376    }
1377
1378    /**
1379     * Set firmware roaming configurations.
1380     *
1381     * @param config new roaming configuration object
1382     * @return true for success; false for failure
1383     */
1384    public boolean configureRoaming(WifiNative.RoamingConfig config) {
1385        kilroy();
1386        synchronized (sLock) {
1387            if (mIWifiStaIface == null) return false;
1388            kilroy();
1389            try {
1390                kilroy();
1391                StaRoamingConfig roamingConfig = new StaRoamingConfig();
1392
1393                // parse the blacklist BSSIDs if any
1394                if (config.blacklistBssids != null) {
1395                    kilroy();
1396                    for (String bssid : config.blacklistBssids) {
1397                        byte[] mac = NativeUtil.macAddressToByteArray(bssid);
1398                        roamingConfig.bssidBlacklist.add(mac);
1399                    }
1400                }
1401
1402                // parse the whitelist SSIDs if any
1403                if (config.whitelistSsids != null) {
1404                    kilroy();
1405                    for (String ssidStr : config.whitelistSsids) {
1406                        String unquotedSsidStr = WifiInfo.removeDoubleQuotes(ssidStr);
1407
1408                        int len = unquotedSsidStr.length();
1409                        if (len > 32) {
1410                            Log.e(TAG, "configureRoaming: skip invalid SSID " + unquotedSsidStr);
1411                            continue;
1412                        }
1413                        byte[] ssid = new byte[len];
1414                        for (int i = 0; i < len; i++) {
1415                            ssid[i] = (byte) unquotedSsidStr.charAt(i);
1416                        }
1417                        roamingConfig.ssidWhitelist.add(ssid);
1418                    }
1419                }
1420
1421                kilroy();
1422                WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
1423                if (status.code != WifiStatusCode.SUCCESS) {
1424                    kilroy();
1425                    noteHidlError(status, "configureRoaming");
1426                    return false;
1427                }
1428            } catch (RemoteException e) {
1429                kilroy();
1430                handleRemoteException(e);
1431                return false;
1432            }
1433            kilroy();
1434            return true;
1435        }
1436    }
1437
1438    StackTraceElement[] mTrace;
1439
1440    private void kilroy() {
1441        Thread cur = Thread.currentThread();
1442        mTrace = cur.getStackTrace();
1443        StackTraceElement s = mTrace[3];
1444        String name = s.getMethodName();
1445        if (name.contains("lambda$")) {
1446            // Try to find a friendlier method name
1447            String myFile = s.getFileName();
1448            if (myFile != null) {
1449                for (int i = 4; i < mTrace.length; i++) {
1450                    if (myFile.equals(mTrace[i].getFileName())) {
1451                        name = mTrace[i].getMethodName();
1452                        break;
1453                    }
1454                }
1455            }
1456        }
1457        Log.e(TAG, "th " + cur.getId() + " line " + s.getLineNumber() + " " + name);
1458    }
1459
1460    /**
1461     * Callback for events on the STA interface.
1462     */
1463    private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
1464        @Override
1465        public void onBackgroundScanFailure(int cmdId) {
1466            kilroy();
1467            Log.d(TAG, "onBackgroundScanFailure " + cmdId);
1468        }
1469
1470        @Override
1471        public void onBackgroundFullScanResult(int cmdId, StaScanResult result) {
1472            kilroy();
1473            Log.d(TAG, "onBackgroundFullScanResult " + cmdId);
1474        }
1475
1476        @Override
1477        public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
1478            kilroy();
1479            Log.d(TAG, "onBackgroundScanResults " + cmdId);
1480        }
1481
1482        @Override
1483        public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
1484            kilroy();
1485            Log.d(TAG, "onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
1486        }
1487    }
1488
1489    /**
1490     * Callback for events on the STA interface.
1491     */
1492    private class ChipEventCallback extends IWifiChipEventCallback.Stub {
1493        @Override
1494        public void onChipReconfigured(int modeId) {
1495            kilroy();
1496            Log.d(TAG, "onChipReconfigured " + modeId);
1497        }
1498
1499        @Override
1500        public void onChipReconfigureFailure(WifiStatus status) {
1501            kilroy();
1502            Log.d(TAG, "onChipReconfigureFailure " + status);
1503        }
1504
1505        public void onIfaceAdded(int type, String name) {
1506            kilroy();
1507            Log.d(TAG, "onIfaceAdded " + type + ", name: " + name);
1508        }
1509
1510        @Override
1511        public void onIfaceRemoved(int type, String name) {
1512            kilroy();
1513            Log.d(TAG, "onIfaceRemoved " + type + ", name: " + name);
1514        }
1515
1516        @Override
1517        public void onDebugRingBufferDataAvailable(
1518                WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
1519            kilroy();
1520            Log.d(TAG, "onDebugRingBufferDataAvailable " + status);
1521        }
1522
1523        @Override
1524        public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
1525            kilroy();
1526            Log.d(TAG, "onDebugErrorAlert " + errorCode);
1527        }
1528    }
1529
1530    /**
1531     * Hal Device Manager callbacks.
1532     */
1533    public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
1534        @Override
1535        public void onStatusChanged() {
1536            boolean isReady = mHalDeviceManager.isReady();
1537            boolean isStarted = mHalDeviceManager.isStarted();
1538
1539            Log.i(TAG, "Device Manager onStatusChanged. isReady(): " + isReady
1540                    + ", isStarted(): " + isStarted);
1541            // Reset all our cached handles.
1542            if (!isReady || !isStarted)  {
1543                kilroy();
1544                mIWifiChip = null;
1545                mIWifiStaIface = null;
1546                mIWifiApIface = null;
1547                mIWifiRttController = null;
1548                mDriverDescription = null;
1549                mFirmwareDescription = null;
1550            }
1551        }
1552    }
1553}
1554