WifiVendorHal.java revision ccac1c69ee6559b567e34b9b19e368efaa600174
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.IWifiIface;
22import android.hardware.wifi.V1_0.IWifiRttController;
23import android.hardware.wifi.V1_0.IWifiStaIface;
24import android.hardware.wifi.V1_0.StaRoamingConfig;
25import android.hardware.wifi.V1_0.StaRoamingState;
26import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
27import android.hardware.wifi.V1_0.WifiStatus;
28import android.hardware.wifi.V1_0.WifiStatusCode;
29import android.net.apf.ApfCapabilities;
30import android.net.wifi.RttManager;
31import android.net.wifi.RttManager.ResponderConfig;
32import android.net.wifi.WifiInfo;
33import android.net.wifi.WifiLinkLayerStats;
34import android.net.wifi.WifiManager;
35import android.net.wifi.WifiScanner;
36import android.net.wifi.WifiWakeReasonAndCounts;
37import android.os.HandlerThread;
38import android.os.RemoteException;
39import android.util.Log;
40import android.util.MutableBoolean;
41import android.util.MutableInt;
42
43import com.android.internal.annotations.VisibleForTesting;
44import com.android.server.connectivity.KeepalivePacketData;
45
46import java.util.ArrayList;
47
48/**
49 * Vendor HAL via HIDL
50 */
51public class WifiVendorHal {
52
53    private static final String TAG = "WifiVendorHal";
54
55    // Vendor HAL HIDL interface objects.
56    private IWifiChip mIWifiChip;
57    private IWifiStaIface mIWifiStaIface;
58    private IWifiApIface mIWifiApIface;
59    private IWifiRttController mIWifiRttController;
60    private final HalDeviceManager mHalDeviceManager;
61    private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
62    private final HandlerThread mWifiStateMachineHandlerThread;
63
64    public WifiVendorHal(HalDeviceManager halDeviceManager,
65                         HandlerThread wifiStateMachineHandlerThread) {
66        mHalDeviceManager = halDeviceManager;
67        mWifiStateMachineHandlerThread = wifiStateMachineHandlerThread;
68        mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
69    }
70
71    // TODO(mplass): figure out where we need locking in hidl world. b/33383725
72    public static final Object sLock = new Object();
73
74    private void handleRemoteException(RemoteException e) {
75        kilroy();
76        Log.e(TAG, "RemoteException in HIDL call " + e);
77    }
78
79    private void noteHidlError(WifiStatus status, String culprit) {
80        kilroy();
81        Log.e(TAG, "Error in " + culprit + " code: " + status.code
82                + " (" + status.description + ")");
83    }
84
85    /**
86     * Initialize the Hal device manager and register for status callbacks.
87     * @return
88     */
89    public boolean initialize() {
90        mHalDeviceManager.initialize();
91        mHalDeviceManager.registerStatusListener(
92                mHalDeviceManagerStatusCallbacks, mWifiStateMachineHandlerThread.getLooper());
93        return true;
94    }
95
96    /**
97     * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
98     * @return true for success
99     */
100    public boolean startVendorHalAp() {
101        return startVendorHal(AP_MODE);
102    }
103
104     /**
105     * Bring up the HIDL Vendor HAL and configure for STA (Station) mode
106     * @return true for success
107     */
108    public boolean startVendorHalSta() {
109        return startVendorHal(STA_MODE);
110    }
111
112
113    public static final boolean STA_MODE = true;
114    public static final boolean AP_MODE = false;
115
116    /**
117     * Bring up the HIDL Vendor HAL and configure for STA mode or AP mode.
118     *
119     * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
120     */
121    public boolean startVendorHal(boolean isStaMode) {
122        if (!mHalDeviceManager.start()) {
123            Log.e(TAG, "Failed to start the vendor HAL");
124            return false;
125        }
126        IWifiIface iface;
127        if (isStaMode) {
128            mIWifiStaIface = mHalDeviceManager.createStaIface(null, null);
129            if (mIWifiStaIface == null) {
130                Log.e(TAG, "Failed to create STA Iface. Vendor Hal start failed");
131                mHalDeviceManager.stop();
132                return false;
133            }
134            iface = (IWifiIface) mIWifiStaIface;
135            mIWifiRttController = mHalDeviceManager.createRttController(iface);
136            if (mIWifiRttController == null) {
137                Log.e(TAG, "Failed to create RTT controller. Vendor Hal start failed");
138                stopVendorHal();
139                return false;
140            }
141            enableLinkLayerStats();
142        } else {
143            mIWifiApIface = mHalDeviceManager.createApIface(null, null);
144            if (mIWifiApIface == null) {
145                Log.e(TAG, "Failed to create AP Iface. Vendor Hal start failed");
146                stopVendorHal();
147                return false;
148            }
149            iface = (IWifiIface) mIWifiApIface;
150        }
151        mIWifiChip = mHalDeviceManager.getChip(iface);
152        if (mIWifiChip == null) {
153            Log.e(TAG, "Failed to get the chip created for the Iface. Vendor Hal start failed");
154            stopVendorHal();
155            return false;
156        }
157        Log.i(TAG, "Vendor Hal started successfully");
158        return true;
159    }
160
161    /**
162     * Stops the HAL
163     */
164    public void stopVendorHal() {
165        mHalDeviceManager.stop();
166        Log.i(TAG, "Vendor Hal stopped");
167    }
168
169    /**
170     * Tests whether the HAL is running or not
171     */
172    public boolean isHalStarted() {
173        return (mIWifiStaIface != null || mIWifiApIface != null);
174    }
175
176    /**
177     * Gets the scan capabilities
178     *
179     * @param capabilities object to be filled in
180     * @return true for success. false for failure
181     */
182    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
183        kilroy();
184        throw new UnsupportedOperationException();
185    }
186
187    /**
188     * to be implemented
189     */
190    public boolean startScan(WifiNative.ScanSettings settings,
191                             WifiNative.ScanEventHandler eventHandler) {
192        kilroy();
193        throw new UnsupportedOperationException();
194    }
195
196    /**
197     * to be implemented
198     */
199    public void stopScan() {
200        kilroy();
201        throw new UnsupportedOperationException();
202    }
203
204    /**
205     * to be implemented
206     */
207    public void pauseScan() {
208        kilroy();
209        throw new UnsupportedOperationException();
210    }
211
212    /**
213     * to be implemented
214     */
215    public void restartScan() {
216        kilroy();
217        throw new UnsupportedOperationException();
218    }
219
220    /**
221     * to be implemented
222     */
223    public WifiScanner.ScanData[] getScanResults(boolean flush) {
224        kilroy();
225        throw new UnsupportedOperationException();
226    }
227
228    /**
229     * Get the link layer statistics
230     *
231     * Note - we always enable link layer stats on a STA interface.
232     *
233     * @return the statistics, or null if unable to do so
234     */
235    public WifiLinkLayerStats getWifiLinkLayerStats() {
236        kilroy();
237        synchronized (sLock) {
238            try {
239                if (mIWifiStaIface == null) return null;
240                kilroy();
241                WifiLinkLayerStats out = new WifiLinkLayerStats();
242                MutableBoolean ok = new MutableBoolean(false);
243                kilroy();
244                mIWifiStaIface.getLinkLayerStats((status, stats) -> {
245                            kilroy();
246                            if (status.code != WifiStatusCode.SUCCESS) return;
247                            out.status = 0; // TODO
248                            out.SSID = null; // TODO
249                            out.BSSID = null; // TODO
250                            out.beacon_rx = stats.iface.beaconRx;
251                            out.rssi_mgmt = stats.iface.avgRssiMgmt;
252                        /* WME Best Effort Access Category */
253                            out.rxmpdu_be = stats.iface.wmeBePktStats.rxMpdu;
254                            out.txmpdu_be = stats.iface.wmeBePktStats.txMpdu;
255                            out.lostmpdu_be = stats.iface.wmeBePktStats.lostMpdu;
256                            out.retries_be = stats.iface.wmeBePktStats.retries;
257                        /* WME Background Access Category */
258                            out.rxmpdu_bk = stats.iface.wmeBkPktStats.rxMpdu;
259                            out.txmpdu_bk = stats.iface.wmeBkPktStats.txMpdu;
260                            out.lostmpdu_bk = stats.iface.wmeBkPktStats.lostMpdu;
261                            out.retries_bk = stats.iface.wmeBkPktStats.retries;
262                        /* WME Video Access Category */
263                            out.rxmpdu_vi = stats.iface.wmeViPktStats.rxMpdu;
264                            out.txmpdu_vi = stats.iface.wmeViPktStats.txMpdu;
265                            out.lostmpdu_vi = stats.iface.wmeViPktStats.lostMpdu;
266                            out.retries_vi = stats.iface.wmeViPktStats.retries;
267                        /* WME Voice Access Category */
268                            out.rxmpdu_vo = stats.iface.wmeVoPktStats.rxMpdu;
269                            out.txmpdu_vo = stats.iface.wmeVoPktStats.txMpdu;
270                            out.lostmpdu_vo = stats.iface.wmeVoPktStats.lostMpdu;
271                            out.retries_vo = stats.iface.wmeVoPktStats.retries;
272                            out.on_time = stats.radio.onTimeInMs;
273                            out.tx_time = stats.radio.txTimeInMs;
274                            out.tx_time_per_level = new int[stats.radio.txTimeInMsPerLevel.size()];
275                            for (int i = 0; i < out.tx_time_per_level.length; i++) {
276                                out.tx_time_per_level[i] = stats.radio.txTimeInMsPerLevel.get(i);
277                            }
278                            out.rx_time = stats.radio.rxTimeInMs;
279                            out.on_time_scan = stats.radio.onTimeInMsForScan;
280                            kilroy();
281                            ok.value = true;
282                        }
283                );
284                return ok.value ? out : null;
285            } catch (RemoteException e) {
286                kilroy();
287                handleRemoteException(e);
288                return null;
289            }
290        }
291    }
292
293    @VisibleForTesting
294    boolean mLinkLayerStatsDebug = false;  // Passed to Hal
295
296    /**
297     * Enables the linkLayerStats in the Hal.
298     *
299     * This is called unconditionally whenever we create a STA interface.
300     *
301     */
302    private void enableLinkLayerStats() {
303        synchronized (sLock) {
304            try {
305                kilroy();
306                WifiStatus status;
307                status = mIWifiStaIface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
308                if (status.code != WifiStatusCode.SUCCESS) {
309                    kilroy();
310                    Log.e(TAG, "unable to enable link layer stats collection");
311                }
312            } catch (RemoteException e) {
313                kilroy();
314                handleRemoteException(e);
315            }
316        }
317    }
318
319    /**
320     * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps
321     */
322    private static final int[][] sFeatureCapabilityTranslation = {
323            {WifiManager.WIFI_FEATURE_INFRA_5G,
324                    IWifiStaIface.StaIfaceCapabilityMask.STA_5G
325            },
326            {WifiManager.WIFI_FEATURE_PASSPOINT,
327                    IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
328            },
329            {WifiManager.WIFI_FEATURE_SCANNER,
330                    IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
331            },
332            {WifiManager.WIFI_FEATURE_PNO,
333                    IWifiStaIface.StaIfaceCapabilityMask.PNO
334            },
335            {WifiManager.WIFI_FEATURE_TDLS,
336                    IWifiStaIface.StaIfaceCapabilityMask.TDLS
337            },
338            {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
339                    IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
340            },
341            {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
342                    IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
343            },
344            {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
345                    IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
346            },
347            {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
348                    IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
349            },
350            {WifiManager.WIFI_FEATURE_CONFIG_NDO,
351                    IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
352            },
353            {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
354                    IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
355            },
356            {WifiManager.WIFI_FEATURE_IE_WHITELIST,
357                    IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
358            },
359            {WifiManager.WIFI_FEATURE_SCAN_RAND,
360                    IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
361            },
362    };
363
364    /**
365     * Feature bit mask translation for STAs
366     *
367     * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
368     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
369     */
370    @VisibleForTesting
371    int wifiFeatureMaskFromStaCapabilities(int capabilities) {
372        int features = WifiManager.WIFI_FEATURE_INFRA; // Always set this if we have a STA interface
373        for (int i = 0; i < sFeatureCapabilityTranslation.length; i++) {
374            if ((capabilities & sFeatureCapabilityTranslation[i][1]) != 0) {
375                features |= sFeatureCapabilityTranslation[i][0];
376            }
377        }
378        return features;
379    }
380
381    /**
382     * Get the supported features
383     * <p>
384     * Note that not all the WifiManager.WIFI_FEATURE_* bits are supplied through
385     * this call. //TODO(b/34900537) fix this
386     *
387     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
388     */
389    public int getSupportedFeatureSet() {
390        try {
391            final MutableInt feat = new MutableInt(0);
392            synchronized (sLock) {
393                if (mIWifiStaIface != null) {
394                    mIWifiStaIface.getCapabilities((status, capabilities) -> {
395                        if (status.code != WifiStatusCode.SUCCESS) return;
396                        feat.value = wifiFeatureMaskFromStaCapabilities(capabilities);
397                    });
398                }
399            }
400            return feat.value;
401        } catch (RemoteException e) {
402            handleRemoteException(e);
403            return 0;
404        }
405    }
406
407    /* RTT related commands/events */
408
409    /**
410     * Starts a new rtt request
411     *
412     * @param params
413     * @param handler
414     * @return success indication
415     */
416    public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) {
417        kilroy();
418        throw new UnsupportedOperationException();
419    }
420
421    /**
422     * Cancels an outstanding rtt request
423     *
424     * @param params
425     * @return true if there was an outstanding request and it was successfully cancelled
426     */
427    public boolean cancelRtt(RttManager.RttParams[] params) {
428        kilroy();
429        throw new UnsupportedOperationException();
430    }
431
432    /**
433     * Enables RTT responder role on the device.
434     *
435     * @return {@link ResponderConfig} if the responder role is successfully enabled,
436     * {@code null} otherwise.
437     */
438    @Nullable
439    public ResponderConfig enableRttResponder(int timeoutSeconds) {
440        kilroy();
441        throw new UnsupportedOperationException();
442    }
443
444    /**
445     * Disables RTT responder role.
446     *
447     * @return {@code true} if responder role is successfully disabled,
448     * {@code false} otherwise.
449     */
450    public boolean disableRttResponder() {
451        kilroy();
452        throw new UnsupportedOperationException();
453    }
454
455    /**
456     * not supported
457     */
458    public boolean setScanningMacOui(byte[] oui) {
459        kilroy();
460        throw new UnsupportedOperationException();
461    }
462
463    /**
464     * not supported
465     */
466    public int[] getChannelsForBand(int band) {
467        kilroy();
468        throw new UnsupportedOperationException();
469    }
470
471    /**
472     * not supported
473     */
474    public boolean isGetChannelsForBandSupported() {
475        kilroy();
476        throw new UnsupportedOperationException();
477    }
478
479    /**
480     * Set DFS - actually, this is always on.
481     *
482     * @param dfsOn
483     * @return success indication
484     */
485    public boolean setDfsFlag(boolean dfsOn) {
486        kilroy();
487        throw new UnsupportedOperationException();
488    }
489
490    /**
491     * RTT (Round Trip Time) measurement capabilities of the device.
492     */
493    public RttManager.RttCapabilities getRttCapabilities() {
494        kilroy();
495        throw new UnsupportedOperationException();
496    }
497
498    /**
499     * Get the APF (Android Packet Filter) capabilities of the device
500     */
501    public ApfCapabilities getApfCapabilities() {
502        class AnswerBox {
503            public ApfCapabilities value = sNoApfCapabilities;
504        }
505        synchronized (sLock) {
506            try {
507                if (mIWifiStaIface == null) return sNoApfCapabilities;
508                AnswerBox box = new AnswerBox();
509                mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
510                    if (status.code != WifiStatusCode.SUCCESS) return;
511                    box.value = new ApfCapabilities(
512                        /* apfVersionSupported */   capabilities.version,
513                        /* maximumApfProgramSize */ capabilities.maxLength,
514                        /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
515                });
516                return box.value;
517            } catch (RemoteException e) {
518                handleRemoteException(e);
519                return sNoApfCapabilities;
520            }
521        }
522    }
523
524    private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
525
526    /**
527     * Installs an APF program on this iface, replacing any existing program.
528     *
529     * @param filter is the android packet filter program
530     * @return true for success
531     */
532    public boolean installPacketFilter(byte[] filter) {
533        kilroy();
534        int cmdId = 0; //TODO(b/34901818) We only aspire to support one program at a time
535        if (filter == null) return false;
536        // Copy the program before taking the lock.
537        ArrayList<Byte> program = new ArrayList<>(filter.length);
538        for (byte b : filter) {
539            program.add(b);
540        }
541        synchronized (sLock) {
542            try {
543                if (mIWifiStaIface == null) return false;
544                WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
545                if (status.code != WifiStatusCode.SUCCESS) return false;
546                kilroy();
547                return true;
548            } catch (RemoteException e) {
549                handleRemoteException(e);
550                return false;
551            }
552        }
553    }
554
555    /**
556     * to be implemented
557     */
558    public boolean setCountryCodeHal(String countryCode) {
559        kilroy();
560        throw new UnsupportedOperationException();
561    }
562
563    /**
564     * not to be implemented
565     */
566    public boolean enableDisableTdls(boolean enable, String macAdd,
567                                     WifiNative.TdlsEventHandler tdlsCallBack) {
568        kilroy();
569        throw new UnsupportedOperationException();
570    }
571
572    /**
573     * not to be implemented
574     */
575    public WifiNative.TdlsStatus getTdlsStatus(String macAdd) {
576        kilroy();
577        throw new UnsupportedOperationException();
578    }
579
580    /**
581     * not to be implemented
582     */
583    public WifiNative.TdlsCapabilities getTdlsCapabilities() {
584        kilroy();
585        throw new UnsupportedOperationException();
586    }
587
588    /**
589     * to be implemented
590     */
591    public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
592        kilroy();
593        throw new UnsupportedOperationException();
594    }
595
596    /**
597     * Control debug data collection
598     *
599     * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
600     * @param flags              Ignored.
601     * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
602     * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
603     * @param ringName           Name of the ring for which data collection is to start.
604     * @return true for success
605     */
606    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
607                                          int minDataSizeInBytes, String ringName) {
608        kilroy();
609        throw new UnsupportedOperationException();
610    }
611
612    /**
613     * Pointlessly fail
614     *
615     * @return -1
616     */
617    public int getSupportedLoggerFeatureSet() {
618        return -1;
619    }
620
621    /**
622     * to be implemented
623     */
624    public boolean resetLogHandler() {
625        kilroy();
626        throw new UnsupportedOperationException();
627    }
628
629    private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
630
631    /**
632     * Vendor-provided wifi driver version string
633     */
634    public String getDriverVersion() {
635        synchronized (sLock) {
636            if (mDriverDescription == null) requestChipDebugInfo();
637            return mDriverDescription;
638        }
639    }
640
641    private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
642
643    /**
644     * Vendor-provided wifi firmware version string
645     */
646    public String getFirmwareVersion() {
647        synchronized (sLock) {
648            if (mFirmwareDescription == null) requestChipDebugInfo();
649            return mFirmwareDescription;
650        }
651    }
652
653    /**
654     * Refreshes our idea of the driver and firmware versions
655     */
656    private void requestChipDebugInfo() {
657        mDriverDescription = null;
658        mFirmwareDescription = null;
659        try {
660            if (mIWifiChip == null) return;
661            mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
662                if (status.code != WifiStatusCode.SUCCESS) return;
663                mDriverDescription = chipDebugInfo.driverDescription;
664                mFirmwareDescription = chipDebugInfo.firmwareDescription;
665            });
666        } catch (RemoteException e) {
667            handleRemoteException(e);
668            return;
669        }
670        Log.e(TAG, "Driver: " + mDriverDescription + " Firmware: " + mFirmwareDescription);
671    }
672
673    /**
674     * API to get the status of all ring buffers supported by driver
675     */
676    public WifiNative.RingBufferStatus[] getRingBufferStatus() {
677        kilroy();
678        throw new UnsupportedOperationException();
679    }
680
681    /**
682     * indicates to driver that all
683     * the data has to be uploaded urgently
684     */
685    public boolean getRingBufferData(String ringName) {
686        kilroy();
687        throw new UnsupportedOperationException();
688    }
689
690    /**
691     * to be implemented via mIWifiChip.requestFirmwareDebugDump
692     */
693    public byte[] getFwMemoryDump() {
694        kilroy();
695        throw new UnsupportedOperationException();
696    }
697
698    /**
699     * Request vendor debug info from the driver
700     */
701    public byte[] getDriverStateDump() {
702        kilroy();
703        throw new UnsupportedOperationException();
704    }
705
706    /**
707     * Start packet fate monitoring
708     * <p>
709     * Once started, monitoring remains active until HAL is unloaded.
710     *
711     * @return true for success
712     */
713    public boolean startPktFateMonitoring() {
714        kilroy();
715        throw new UnsupportedOperationException();
716    }
717
718    /**
719     * Retrieve fates of outbound packets
720     * <p>
721     * Reports the outbound frames for the most recent association (space allowing).
722     *
723     * @param reportBufs
724     * @return true for success
725     */
726    public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
727        kilroy();
728        throw new UnsupportedOperationException();
729    }
730
731    /**
732     * Retrieve fates of inbound packets
733     * <p>
734     * Reports the inbound frames for the most recent association (space allowing).
735     *
736     * @param reportBufs
737     * @return true for success
738     */
739    public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
740        kilroy();
741        throw new UnsupportedOperationException();
742    }
743
744    /**
745     * Start sending the specified keep alive packets periodically.
746     *
747     * @return 0 for success, -1 for error
748     */
749    public int startSendingOffloadedPacket(
750            int slot, KeepalivePacketData keepAlivePacket, int periodInMs) {
751        kilroy();
752        throw new UnsupportedOperationException();
753    }
754
755    /**
756     * Stop sending the specified keep alive packets.
757     *
758     * @param slot id - same as startSendingOffloadedPacket call.
759     * @return 0 for success, -1 for error
760     */
761    public int stopSendingOffloadedPacket(int slot) {
762        kilroy();
763        throw new UnsupportedOperationException();
764    }
765
766    /**
767     * Start RSSI monitoring on the currently connected access point.
768     *
769     * @param maxRssi          Maximum RSSI threshold.
770     * @param minRssi          Minimum RSSI threshold.
771     * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
772     * @return 0 for success, -1 for failure
773     */
774    public int startRssiMonitoring(byte maxRssi, byte minRssi,
775                                   WifiNative.WifiRssiEventHandler rssiEventHandler) {
776        kilroy();
777        throw new UnsupportedOperationException();
778    }
779
780    /**
781     * Stop RSSI monitoring
782     *
783     * @return 0 for success, -1 for failure
784     */
785    public int stopRssiMonitoring() {
786        kilroy();
787        throw new UnsupportedOperationException();
788    }
789
790    private WifiDebugHostWakeReasonStats mWifiDebugHostWakeReasonStats;
791
792    /**
793     * Fetch the host wakeup reasons stats from wlan driver.
794     *
795     * @return the |WifiWakeReasonAndCounts| object retrieved from the wlan driver.
796     */
797    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
798        kilroy();
799        throw new UnsupportedOperationException();
800    }
801
802    /**
803     * Enable/Disable Neighbour discovery offload functionality in the firmware.
804     */
805    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
806        kilroy();
807        throw new UnsupportedOperationException();
808    }
809
810    // Firmware roaming control.
811
812    /**
813     * Query the firmware roaming capabilities.
814     *
815     * @param capabilities object to be filled in
816     * @return true for success; false for failure
817     */
818    public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
819        kilroy();
820        synchronized (sLock) {
821            kilroy();
822            try {
823                kilroy();
824                if (!isHalStarted()) return false;
825                MutableBoolean ok = new MutableBoolean(false);
826                WifiNative.RoamingCapabilities out = capabilities;
827                mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
828                    kilroy();
829                    if (status.code != WifiStatusCode.SUCCESS) return;
830                    out.maxBlacklistSize = cap.maxBlacklistSize;
831                    out.maxWhitelistSize = cap.maxWhitelistSize;
832                    ok.value = true;
833                });
834                return ok.value;
835            } catch (RemoteException e) {
836                kilroy();
837                handleRemoteException(e);
838                return false;
839            }
840        }
841    }
842
843    /**
844     * Enable/disable firmware roaming.
845     *
846     * @param state the intended roaming state
847     * @return SUCCESS, FAILURE, or BUSY
848     */
849    public int enableFirmwareRoaming(int state) {
850        kilroy();
851        synchronized (sLock) {
852            kilroy();
853            try {
854                kilroy();
855                if (!isHalStarted()) return WifiStatusCode.ERROR_NOT_STARTED;
856                byte val;
857                switch (state) {
858                    case WifiNative.DISABLE_FIRMWARE_ROAMING:
859                        val = StaRoamingState.DISABLED;
860                        break;
861                    case WifiNative.ENABLE_FIRMWARE_ROAMING:
862                        val = StaRoamingState.ENABLED;
863                        break;
864                    default:
865                        Log.e(TAG, "enableFirmwareRoaming invalid argument " + state);
866                        return WifiStatusCode.ERROR_INVALID_ARGS;
867                }
868
869                kilroy();
870                WifiStatus status = mIWifiStaIface.setRoamingState(val);
871                Log.d(TAG, "setRoamingState returned " + status.code);
872                return status.code;
873            } catch (RemoteException e) {
874                kilroy();
875                handleRemoteException(e);
876                return WifiStatusCode.ERROR_UNKNOWN;
877            }
878        }
879    }
880
881    /**
882     * Set firmware roaming configurations.
883     *
884     * @param config new roaming configuration object
885     * @return true for success; false for failure
886     */
887    public boolean configureRoaming(WifiNative.RoamingConfig config) {
888        kilroy();
889        synchronized (sLock) {
890            kilroy();
891            try {
892                kilroy();
893                if (!isHalStarted()) return false;
894                StaRoamingConfig roamingConfig = new StaRoamingConfig();
895
896                // parse the blacklist BSSIDs if any
897                if (config.blacklistBssids != null) {
898                    kilroy();
899                    for (String bssid : config.blacklistBssids) {
900                        String unquotedMacStr = WifiInfo.removeDoubleQuotes(bssid);
901                        byte[] mac = new byte[6];
902                        parseUnquotedMacStrToByteArray(unquotedMacStr, mac);
903                        roamingConfig.bssidBlacklist.add(mac);
904                    }
905                }
906
907                // parse the whitelist SSIDs if any
908                if (config.whitelistSsids != null) {
909                    kilroy();
910                    for (String ssidStr : config.whitelistSsids) {
911                        String unquotedSsidStr = WifiInfo.removeDoubleQuotes(ssidStr);
912
913                        int len = unquotedSsidStr.length();
914                        if (len > 32) {
915                            Log.e(TAG, "configureRoaming: skip invalid SSID " + unquotedSsidStr);
916                            continue;
917                        }
918                        byte[] ssid = new byte[len];
919                        for (int i = 0; i < len; i++) {
920                            ssid[i] = (byte) unquotedSsidStr.charAt(i);
921                        }
922                        roamingConfig.ssidWhitelist.add(ssid);
923                    }
924                }
925
926                kilroy();
927                WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
928                if (status.code != WifiStatusCode.SUCCESS) {
929                    kilroy();
930                    noteHidlError(status, "configureRoaming");
931                    return false;
932                }
933            } catch (RemoteException e) {
934                kilroy();
935                handleRemoteException(e);
936                return false;
937            }
938            kilroy();
939            return true;
940        }
941    }
942
943    /**
944     * Helper function that parses unquoted MAC address string to a byte array
945     *
946     * @param macWithColons mac address string without double quotes
947     * @param mac an array of 6 bytes to receive the parsed mac address
948     */
949    @VisibleForTesting
950    void parseUnquotedMacStrToByteArray(String macWithColons, byte[] mac) {
951        String[] macAddrStr = macWithColons.split(":");
952        for (int i = 0; i < 6; i++) {
953            Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
954            mac[i] = hexVal.byteValue();
955        }
956    }
957
958    StackTraceElement[] mTrace;
959
960    private void kilroy() {
961        Thread cur = Thread.currentThread();
962        mTrace = cur.getStackTrace();
963        StackTraceElement s = mTrace[3];
964        String name = s.getMethodName();
965        if (name.contains("lambda$")) {
966            // Try to find a friendlier method name
967            String myFile = s.getFileName();
968            if (myFile != null) {
969                for (int i = 4; i < mTrace.length; i++) {
970                    if (myFile.equals(mTrace[i].getFileName())) {
971                        name = mTrace[i].getMethodName();
972                        break;
973                    }
974                }
975            }
976        }
977        Log.e(TAG, "th " + cur.getId() + " line " + s.getLineNumber() + " " + name);
978    }
979
980    /**
981     * Hal Device Manager callbacks.
982     */
983    public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
984        @Override
985        public void onStatusChanged() {
986            boolean isReady = mHalDeviceManager.isReady();
987            boolean isStarted = mHalDeviceManager.isStarted();
988
989            Log.i(TAG, "Device Manager onStatusChanged. isReady(): " + isReady
990                    + ", isStarted(): " + isStarted);
991            // Reset all our cached handles.
992            if (!isReady || !isStarted)  {
993                kilroy();
994                mIWifiChip = null;
995                mIWifiStaIface = null;
996                mIWifiApIface = null;
997                mIWifiRttController = null;
998                mDriverDescription = null;
999                mFirmwareDescription = null;
1000            }
1001        }
1002    }
1003}
1004