WifiVendorHal.java revision 699cb92ca94c3fbd883472937ab3b071cafadf77
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.hardware.wifi.V1_0.IWifiApIface;
19import android.hardware.wifi.V1_0.IWifiChip;
20import android.hardware.wifi.V1_0.IWifiChipEventCallback;
21import android.hardware.wifi.V1_0.IWifiIface;
22import android.hardware.wifi.V1_0.IWifiRttController;
23import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
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.RttBw;
28import android.hardware.wifi.V1_0.RttConfig;
29import android.hardware.wifi.V1_0.RttPeerType;
30import android.hardware.wifi.V1_0.RttPreamble;
31import android.hardware.wifi.V1_0.RttResponder;
32import android.hardware.wifi.V1_0.RttResult;
33import android.hardware.wifi.V1_0.RttType;
34import android.hardware.wifi.V1_0.StaBackgroundScanBucketEventReportSchemeMask;
35import android.hardware.wifi.V1_0.StaBackgroundScanBucketParameters;
36import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
37import android.hardware.wifi.V1_0.StaLinkLayerStats;
38import android.hardware.wifi.V1_0.StaRoamingConfig;
39import android.hardware.wifi.V1_0.StaRoamingState;
40import android.hardware.wifi.V1_0.StaScanData;
41import android.hardware.wifi.V1_0.StaScanDataFlagMask;
42import android.hardware.wifi.V1_0.StaScanResult;
43import android.hardware.wifi.V1_0.WifiBand;
44import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
45import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
46import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
47import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
48import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
49import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
50import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
51import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
52import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
53import android.hardware.wifi.V1_0.WifiInformationElement;
54import android.hardware.wifi.V1_0.WifiStatus;
55import android.hardware.wifi.V1_0.WifiStatusCode;
56import android.net.apf.ApfCapabilities;
57import android.net.wifi.RttManager;
58import android.net.wifi.RttManager.ResponderConfig;
59import android.net.wifi.ScanResult;
60import android.net.wifi.WifiInfo;
61import android.net.wifi.WifiLinkLayerStats;
62import android.net.wifi.WifiManager;
63import android.net.wifi.WifiScanner;
64import android.net.wifi.WifiSsid;
65import android.net.wifi.WifiWakeReasonAndCounts;
66import android.os.HandlerThread;
67import android.os.RemoteException;
68import android.util.MutableBoolean;
69import android.util.MutableInt;
70
71import com.android.internal.annotations.VisibleForTesting;
72import com.android.internal.util.ArrayUtils;
73import com.android.server.connectivity.KeepalivePacketData;
74import com.android.server.wifi.util.BitMask;
75import com.android.server.wifi.util.NativeUtil;
76
77import java.util.ArrayList;
78import java.util.Set;
79
80/**
81 * Vendor HAL via HIDL
82 */
83public class WifiVendorHal {
84
85    private static final WifiLog sNoLog = new FakeWifiLog();
86
87    /**
88     * Chatty logging should use mVerboseLog
89     */
90    @VisibleForTesting
91    WifiLog mVerboseLog = sNoLog;
92
93    /**
94     * Errors should use mLog
95     */
96    @VisibleForTesting
97    WifiLog mLog = new LogcatLog("WifiVendorHal");
98
99    /**
100     * Enables or disables verbose logging
101     *
102     * @param verbose - with the obvious interpretation
103     */
104    public void enableVerboseLogging(boolean verbose) {
105        synchronized (sLock) {
106            if (verbose) {
107                mVerboseLog = mLog;
108                enter("verbose=true").flush();
109            } else {
110                enter("verbose=false").flush();
111                mVerboseLog = sNoLog;
112            }
113        }
114    }
115
116    /**
117     * Checks for a successful status result.
118     *
119     * Failures are logged to mLog.
120     *
121     * @param status is the WifiStatus generated by a hal call
122     * @return true for success, false for failure
123     */
124    private boolean ok(WifiStatus status) {
125        if (status.code == WifiStatusCode.SUCCESS) return true;
126
127        Thread cur = Thread.currentThread();
128        StackTraceElement[] trace = cur.getStackTrace();
129
130        mLog.err("% failed %")
131                .c(niceMethodName(trace, 3))
132                .c(status.toString())
133                .flush();
134
135        return false;
136    }
137
138    /**
139     * Logs if the argument is false.
140     *
141     * Always returns its argument.
142     */
143    private boolean boolResult(boolean result) {
144        if (mVerboseLog == sNoLog) return result;
145        // Currently only seen if verbose logging is on
146
147        Thread cur = Thread.currentThread();
148        StackTraceElement[] trace = cur.getStackTrace();
149
150        mVerboseLog.err("% returns %")
151                .c(niceMethodName(trace, 3))
152                .c(result)
153                .flush();
154
155        return result;
156    }
157
158    /**
159     * Logs at method entry
160     *
161     * @param format string with % placeholders
162     * @return LogMessage formatter (remember to .flush())
163     */
164    private WifiLog.LogMessage enter(String format) {
165        if (mVerboseLog == sNoLog) return sNoLog.info(format);
166        Thread cur = Thread.currentThread();
167        StackTraceElement[] trace = cur.getStackTrace();
168        return mVerboseLog.trace("% " + format).c(trace[3].getMethodName());
169    }
170
171    /**
172     * Gets the method name and line number from a stack trace.
173     *
174     * Attempts to skip frames created by lambdas to get a human-sensible name.
175     *
176     * @param trace, fo example obtained by Thread.currentThread().getStackTrace()
177     * @param start  frame number to log, typically 3
178     * @return string cotaining the method name and line number
179     */
180    private static String niceMethodName(StackTraceElement[] trace, int start) {
181        if (start >= trace.length) return "";
182        StackTraceElement s = trace[start];
183        String name = s.getMethodName();
184        if (name.contains("lambda$")) {
185            // Try to find a friendlier method name
186            String myFile = s.getFileName();
187            if (myFile != null) {
188                for (int i = start + 1; i < trace.length; i++) {
189                    if (myFile.equals(trace[i].getFileName())) {
190                        name = trace[i].getMethodName();
191                        break;
192                    }
193                }
194            }
195        }
196        return (name + "(l." + s.getLineNumber() + ")");
197    }
198
199    // Vendor HAL HIDL interface objects.
200    private IWifiChip mIWifiChip;
201    private IWifiStaIface mIWifiStaIface;
202    private IWifiApIface mIWifiApIface;
203    private IWifiRttController mIWifiRttController;
204    private final HalDeviceManager mHalDeviceManager;
205    private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
206    private final HandlerThread mWifiStateMachineHandlerThread;
207    private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
208    private final IWifiChipEventCallback mIWifiChipEventCallback;
209
210    public WifiVendorHal(HalDeviceManager halDeviceManager,
211                         HandlerThread wifiStateMachineHandlerThread) {
212        mHalDeviceManager = halDeviceManager;
213        mWifiStateMachineHandlerThread = wifiStateMachineHandlerThread;
214        mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
215        mIWifiStaIfaceEventCallback = new StaIfaceEventCallback();
216        mIWifiChipEventCallback = new ChipEventCallback();
217    }
218
219    // TODO(mplass): figure out where we need locking in hidl world. b/33383725
220    public static final Object sLock = new Object();
221
222    private void handleRemoteException(RemoteException e) {
223        String methodName = niceMethodName(Thread.currentThread().getStackTrace(), 3);
224        mLog.err("% RemoteException in HIDL call %").c(methodName).c(e.toString()).flush();
225    }
226
227    /**
228     * Initialize the Hal device manager and register for status callbacks.
229     *
230     * @return
231     */
232    public boolean initialize() {
233        mHalDeviceManager.initialize();
234        mHalDeviceManager.registerStatusListener(
235                mHalDeviceManagerStatusCallbacks, mWifiStateMachineHandlerThread.getLooper());
236        return true;
237    }
238
239    /**
240     * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
241     *
242     * @return true for success
243     */
244    public boolean startVendorHalAp() {
245        return startVendorHal(AP_MODE);
246    }
247
248    /**
249     * Bring up the HIDL Vendor HAL and configure for STA (Station) mode
250     *
251     * @return true for success
252     */
253    public boolean startVendorHalSta() {
254        return startVendorHal(STA_MODE);
255    }
256
257    public static final boolean STA_MODE = true;
258    public static final boolean AP_MODE = false;
259
260    /**
261     * Bring up the HIDL Vendor HAL and configure for STA mode or AP mode.
262     *
263     * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
264     */
265    public boolean startVendorHal(boolean isStaMode) {
266        if (!mHalDeviceManager.start()) {
267            mLog.e("Failed to start the vendor HAL");
268            return false;
269        }
270        IWifiIface iface;
271        if (isStaMode) {
272            mIWifiStaIface = mHalDeviceManager.createStaIface(null, null);
273            if (mIWifiStaIface == null) {
274                mLog.e("Failed to create STA Iface. Vendor Hal start failed");
275                mHalDeviceManager.stop();
276                return false;
277            }
278            iface = (IWifiIface) mIWifiStaIface;
279            if (!registerStaIfaceCallback()) {
280                mLog.e("Failed to register sta iface callback");
281                mHalDeviceManager.stop();
282                return false;
283            }
284            mIWifiRttController = mHalDeviceManager.createRttController(iface);
285            if (mIWifiRttController == null) {
286                mLog.e("Failed to create RTT controller. Vendor Hal start failed");
287                stopVendorHal();
288                return false;
289            }
290            enableLinkLayerStats();
291        } else {
292            mIWifiApIface = mHalDeviceManager.createApIface(null, null);
293            if (mIWifiApIface == null) {
294                mLog.e("Failed to create AP Iface. Vendor Hal start failed");
295                stopVendorHal();
296                return false;
297            }
298            iface = (IWifiIface) mIWifiApIface;
299        }
300        mIWifiChip = mHalDeviceManager.getChip(iface);
301        if (mIWifiChip == null) {
302            mLog.e("Failed to get the chip created for the Iface. Vendor Hal start failed");
303            stopVendorHal();
304            return false;
305        }
306        if (!registerChipCallback()) {
307            mLog.e("Failed to register chip callback");
308            mHalDeviceManager.stop();
309            return false;
310        }
311        mLog.i("Vendor Hal started successfully");
312        return true;
313    }
314
315    /**
316     * Registers the sta iface callback.
317     */
318    private boolean registerStaIfaceCallback() {
319        synchronized (sLock) {
320            if (mIWifiStaIface == null) return boolResult(false);
321            if (mIWifiStaIfaceEventCallback == null) return boolResult(false);
322            try {
323                WifiStatus status =
324                        mIWifiStaIface.registerEventCallback(mIWifiStaIfaceEventCallback);
325                return ok(status);
326            } catch (RemoteException e) {
327                handleRemoteException(e);
328                return false;
329            }
330        }
331    }
332
333    /**
334     * Registers the sta iface callback.
335     */
336    private boolean registerChipCallback() {
337        synchronized (sLock) {
338            if (mIWifiChip == null) return boolResult(false);
339            if (mIWifiChipEventCallback == null) return boolResult(false);
340            try {
341                WifiStatus status = mIWifiChip.registerEventCallback(mIWifiChipEventCallback);
342                return ok(status);
343            } catch (RemoteException e) {
344                handleRemoteException(e);
345                return false;
346            }
347        }
348    }
349
350    /**
351     * Stops the HAL
352     */
353    public void stopVendorHal() {
354        mHalDeviceManager.stop();
355        mLog.i("Vendor Hal stopped");
356    }
357
358    /**
359     * Tests whether the HAL is running or not
360     */
361    public boolean isHalStarted() {
362        // For external use only. Methods in this class should test for null directly.
363        return (mIWifiStaIface != null || mIWifiApIface != null);
364    }
365
366    /**
367     * Gets the scan capabilities
368     *
369     * @param capabilities object to be filled in
370     * @return true for success. false for failure
371     */
372    public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) {
373        synchronized (sLock) {
374            if (mIWifiStaIface == null) return boolResult(false);
375            try {
376                MutableBoolean ans = new MutableBoolean(false);
377                WifiNative.ScanCapabilities out = capabilities;
378                mIWifiStaIface.getBackgroundScanCapabilities((status, cap) -> {
379                            if (!ok(status)) return;
380                            mVerboseLog.info("scan capabilities %").c(cap.toString()).flush();
381                            out.max_scan_cache_size = cap.maxCacheSize;
382                            out.max_ap_cache_per_scan = cap.maxApCachePerScan;
383                            out.max_scan_buckets = cap.maxBuckets;
384                            out.max_rssi_sample_size = 0;
385                            out.max_scan_reporting_threshold = cap.maxReportingThreshold;
386                            out.max_hotlist_bssids = 0;
387                            out.max_significant_wifi_change_aps = 0;
388                            out.max_bssid_history_entries = 0;
389                            out.max_number_epno_networks = 0;
390                            out.max_number_epno_networks_by_ssid = 0;
391                            out.max_number_of_white_listed_ssid = 0;
392                            ans.value = true;
393                        }
394                );
395                return ans.value;
396            } catch (RemoteException e) {
397                handleRemoteException(e);
398                return false;
399            }
400        }
401    }
402
403    /**
404     * Holds the current background scan state, to implement pause and restart
405     */
406    @VisibleForTesting
407    class CurrentBackgroundScan {
408        public int cmdId;
409        public StaBackgroundScanParameters param;
410        public WifiNative.ScanEventHandler eventHandler = null;
411        public boolean paused = false;
412        public WifiScanner.ScanData[] latestScanResults = null;
413
414        CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) {
415            cmdId = id;
416            param = new StaBackgroundScanParameters();
417            param.basePeriodInMs = settings.base_period_ms;
418            param.maxApPerScan = settings.max_ap_per_scan;
419            param.reportThresholdPercent = settings.report_threshold_percent;
420            param.reportThresholdNumScans = settings.report_threshold_num_scans;
421            if (settings.buckets != null) {
422                for (WifiNative.BucketSettings bs : settings.buckets) {
423                    param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs));
424                }
425            }
426        }
427    }
428
429    /**
430     * Makes the Hal flavor of WifiNative.BucketSettings
431     *
432     * @param bs WifiNative.BucketSettings
433     * @return Hal flavor of bs
434     * @throws IllegalArgumentException if band value is not recognized
435     */
436    private StaBackgroundScanBucketParameters
437            makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs) {
438        StaBackgroundScanBucketParameters pa = new StaBackgroundScanBucketParameters();
439        pa.bucketIdx = bs.bucket;
440        pa.band = makeWifiBandFromFrameworkBand(bs.band);
441        if (bs.channels != null) {
442            for (WifiNative.ChannelSettings cs : bs.channels) {
443                pa.frequencies.add(cs.frequency);
444            }
445        }
446        pa.periodInMs = bs.period_ms;
447        pa.eventReportScheme = makeReportSchemeFromBucketSettingsReportEvents(bs.report_events);
448        pa.exponentialMaxPeriodInMs = bs.max_period_ms;
449        // Although HAL API allows configurable base value for the truncated
450        // exponential back off scan. Native API and above support only
451        // truncated binary exponential back off scan.
452        // Hard code value of base to 2 here.
453        pa.exponentialBase = 2;
454        pa.exponentialStepCount = bs.step_count;
455        return pa;
456    }
457
458    /**
459     * Makes the Hal flavor of WifiScanner's band indication
460     *
461     * @param frameworkBand one of WifiScanner.WIFI_BAND_*
462     * @return A WifiBand value
463     * @throws IllegalArgumentException if frameworkBand is not recognized
464     */
465    private int makeWifiBandFromFrameworkBand(int frameworkBand) {
466        switch (frameworkBand) {
467            case WifiScanner.WIFI_BAND_UNSPECIFIED:
468                return WifiBand.BAND_UNSPECIFIED;
469            case WifiScanner.WIFI_BAND_24_GHZ:
470                return WifiBand.BAND_24GHZ;
471            case WifiScanner.WIFI_BAND_5_GHZ:
472                return WifiBand.BAND_5GHZ;
473            case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
474                return WifiBand.BAND_5GHZ_DFS;
475            case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
476                return WifiBand.BAND_5GHZ_WITH_DFS;
477            case WifiScanner.WIFI_BAND_BOTH:
478                return WifiBand.BAND_24GHZ_5GHZ;
479            case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
480                return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS;
481            default:
482                throw new IllegalArgumentException("bad band " + frameworkBand);
483        }
484    }
485
486    /**
487     * Makes the Hal flavor of WifiScanner's report event mask
488     *
489     * @param reportUnderscoreEvents is logical OR of WifiScanner.REPORT_EVENT_* values
490     * @return Corresponding StaBackgroundScanBucketEventReportSchemeMask value
491     * @throws IllegalArgumentException if a mask bit is not recognized
492     */
493    private int makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents) {
494        int ans = 0;
495        BitMask in = new BitMask(reportUnderscoreEvents);
496        if (in.testAndClear(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)) {
497            ans |= StaBackgroundScanBucketEventReportSchemeMask.EACH_SCAN;
498        }
499        if (in.testAndClear(WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)) {
500            ans |= StaBackgroundScanBucketEventReportSchemeMask.FULL_RESULTS;
501        }
502        if (in.testAndClear(WifiScanner.REPORT_EVENT_NO_BATCH)) {
503            ans |= StaBackgroundScanBucketEventReportSchemeMask.NO_BATCH;
504        }
505        if (in.value != 0) throw new IllegalArgumentException("bad " + reportUnderscoreEvents);
506        return ans;
507    }
508
509    private int mLastScanCmdId; // For assigning cmdIds to scans
510
511    @VisibleForTesting
512    CurrentBackgroundScan mScan = null;
513
514    /**
515     * Starts a background scan
516     * <p>
517     * Any ongoing scan will be stopped first
518     *
519     * @param settings     to control the scan
520     * @param eventHandler to call with the results
521     * @return true for success
522     */
523    public boolean startScan(WifiNative.ScanSettings settings,
524                             WifiNative.ScanEventHandler eventHandler) {
525        WifiStatus status;
526        if (eventHandler == null) return boolResult(false);
527        synchronized (sLock) {
528            if (mIWifiStaIface == null) return boolResult(false);
529            try {
530                if (mScan != null && !mScan.paused) {
531                    ok(mIWifiStaIface.stopBackgroundScan(mScan.cmdId));
532                    mScan = null;
533                }
534                mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
535                CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
536                status = mIWifiStaIface.startBackgroundScan(scan.cmdId, scan.param);
537                if (!ok(status)) return false;
538                scan.eventHandler = eventHandler;
539                mScan = scan;
540                return true;
541            } catch (RemoteException e) {
542                handleRemoteException(e);
543                return false;
544            }
545        }
546    }
547
548
549    /**
550     * Stops any ongoing backgound scan
551     */
552    public void stopScan() {
553        WifiStatus status;
554        synchronized (sLock) {
555            if (mIWifiStaIface == null) return;
556            try {
557                if (mScan != null) {
558                    ok(mIWifiStaIface.stopBackgroundScan(mScan.cmdId));
559                    mScan = null;
560                }
561            } catch (RemoteException e) {
562                handleRemoteException(e);
563            }
564        }
565    }
566
567    /**
568     * Pauses an ongoing backgound scan
569     */
570    public void pauseScan() {
571        WifiStatus status;
572        synchronized (sLock) {
573            try {
574                if (mIWifiStaIface == null) return;
575                if (mScan != null && !mScan.paused) {
576                    status = mIWifiStaIface.stopBackgroundScan(mScan.cmdId);
577                    if (!ok(status)) return;
578                    mScan.paused = true;
579                }
580            } catch (RemoteException e) {
581                handleRemoteException(e);
582            }
583        }
584    }
585
586    /**
587     * Restarts a paused scan
588     */
589    public void restartScan() {
590        WifiStatus status;
591        synchronized (sLock) {
592            if (mIWifiStaIface == null) return;
593            try {
594                if (mScan != null && mScan.paused) {
595                    status = mIWifiStaIface.startBackgroundScan(mScan.cmdId, mScan.param);
596                    if (!ok(status)) return;
597                    mScan.paused = false;
598                }
599            } catch (RemoteException e) {
600                handleRemoteException(e);
601            }
602        }
603    }
604
605    /**
606     * Gets the latest scan results received from the HIDL interface callback.
607     * TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor
608     * WifiScanner to use the scan results from the callback.
609     */
610    public WifiScanner.ScanData[] getScanResults() {
611        synchronized (sLock) {
612            if (mIWifiStaIface == null) return null;
613            if (mScan == null) return null;
614            return mScan.latestScanResults;
615        }
616    }
617
618    /**
619     * Get the link layer statistics
620     *
621     * Note - we always enable link layer stats on a STA interface.
622     *
623     * @return the statistics, or null if unable to do so
624     */
625    public WifiLinkLayerStats getWifiLinkLayerStats() {
626        class AnswerBox {
627            public StaLinkLayerStats value = null;
628        }
629        AnswerBox answer = new AnswerBox();
630        synchronized (sLock) {
631            try {
632                if (mIWifiStaIface == null) return null;
633                mIWifiStaIface.getLinkLayerStats((status, stats) -> {
634                    if (!ok(status)) return;
635                    answer.value = stats;
636                });
637            } catch (RemoteException e) {
638                handleRemoteException(e);
639                return null;
640            }
641        }
642        WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats(answer.value);
643        return stats;
644    }
645
646    /**
647     * Makes the framework version of link layer stats from the hal version.
648     */
649    @VisibleForTesting
650    static WifiLinkLayerStats frameworkFromHalLinkLayerStats(StaLinkLayerStats stats) {
651        if (stats == null) return null;
652        WifiLinkLayerStats out = new WifiLinkLayerStats();
653        // unpopulated: out.status, out.SSID, out.BSSID
654        out.beacon_rx = stats.iface.beaconRx;
655        out.rssi_mgmt = stats.iface.avgRssiMgmt;
656        // Statistics are broken out by Wireless Multimedia Extensions categories
657        // WME Best Effort Access Category
658        out.rxmpdu_be = stats.iface.wmeBePktStats.rxMpdu;
659        out.txmpdu_be = stats.iface.wmeBePktStats.txMpdu;
660        out.lostmpdu_be = stats.iface.wmeBePktStats.lostMpdu;
661        out.retries_be = stats.iface.wmeBePktStats.retries;
662        // WME Background Access Category
663        out.rxmpdu_bk = stats.iface.wmeBkPktStats.rxMpdu;
664        out.txmpdu_bk = stats.iface.wmeBkPktStats.txMpdu;
665        out.lostmpdu_bk = stats.iface.wmeBkPktStats.lostMpdu;
666        out.retries_bk = stats.iface.wmeBkPktStats.retries;
667        // WME Video Access Category
668        out.rxmpdu_vi = stats.iface.wmeViPktStats.rxMpdu;
669        out.txmpdu_vi = stats.iface.wmeViPktStats.txMpdu;
670        out.lostmpdu_vi = stats.iface.wmeViPktStats.lostMpdu;
671        out.retries_vi = stats.iface.wmeViPktStats.retries;
672        // WME Voice Access Category
673        out.rxmpdu_vo = stats.iface.wmeVoPktStats.rxMpdu;
674        out.txmpdu_vo = stats.iface.wmeVoPktStats.txMpdu;
675        out.lostmpdu_vo = stats.iface.wmeVoPktStats.lostMpdu;
676        out.retries_vo = stats.iface.wmeVoPktStats.retries;
677        out.on_time = stats.radio.onTimeInMs;
678        out.tx_time = stats.radio.txTimeInMs;
679        out.tx_time_per_level = new int[stats.radio.txTimeInMsPerLevel.size()];
680        for (int i = 0; i < out.tx_time_per_level.length; i++) {
681            out.tx_time_per_level[i] = stats.radio.txTimeInMsPerLevel.get(i);
682        }
683        out.rx_time = stats.radio.rxTimeInMs;
684        out.on_time_scan = stats.radio.onTimeInMsForScan;
685        // unused: stats.timeStampInMs;
686        return out;
687    }
688
689    @VisibleForTesting
690    boolean mLinkLayerStatsDebug = false;  // Passed to Hal
691
692    /**
693     * Enables the linkLayerStats in the Hal.
694     *
695     * This is called unconditionally whenever we create a STA interface.
696     */
697    private void enableLinkLayerStats() {
698        synchronized (sLock) {
699            try {
700                WifiStatus status;
701                status = mIWifiStaIface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
702                if (!ok(status)) {
703                    mLog.e("unable to enable link layer stats collection");
704                }
705            } catch (RemoteException e) {
706                handleRemoteException(e);
707            }
708        }
709    }
710
711    /**
712     * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps
713     */
714    private static final int[][] sFeatureCapabilityTranslation = {
715            {WifiManager.WIFI_FEATURE_INFRA_5G,
716                    IWifiStaIface.StaIfaceCapabilityMask.STA_5G
717            },
718            {WifiManager.WIFI_FEATURE_PASSPOINT,
719                    IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
720            },
721            {WifiManager.WIFI_FEATURE_SCANNER,
722                    IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
723            },
724            {WifiManager.WIFI_FEATURE_PNO,
725                    IWifiStaIface.StaIfaceCapabilityMask.PNO
726            },
727            {WifiManager.WIFI_FEATURE_TDLS,
728                    IWifiStaIface.StaIfaceCapabilityMask.TDLS
729            },
730            {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
731                    IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
732            },
733            {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
734                    IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
735            },
736            {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
737                    IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
738            },
739            {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
740                    IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
741            },
742            {WifiManager.WIFI_FEATURE_CONFIG_NDO,
743                    IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
744            },
745            {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
746                    IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
747            },
748            {WifiManager.WIFI_FEATURE_IE_WHITELIST,
749                    IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
750            },
751            {WifiManager.WIFI_FEATURE_SCAN_RAND,
752                    IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
753            },
754    };
755
756    /**
757     * Feature bit mask translation for STAs
758     *
759     * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
760     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
761     */
762    @VisibleForTesting
763    int wifiFeatureMaskFromStaCapabilities(int capabilities) {
764        int features = 0;
765        for (int i = 0; i < sFeatureCapabilityTranslation.length; i++) {
766            if ((capabilities & sFeatureCapabilityTranslation[i][1]) != 0) {
767                features |= sFeatureCapabilityTranslation[i][0];
768            }
769        }
770        return features;
771    }
772
773    /**
774     * Get the supported features
775     * <p>
776     * Note that not all the WifiManager.WIFI_FEATURE_* bits are supplied through
777     * this call. //TODO(b/34900537) fix this
778     *
779     * @return bitmask defined by WifiManager.WIFI_FEATURE_*
780     */
781    public int getSupportedFeatureSet() {
782        int featureSet = 0;
783        try {
784            final MutableInt feat = new MutableInt(0);
785            synchronized (sLock) {
786                if (mIWifiStaIface != null) {
787                    mIWifiStaIface.getCapabilities((status, capabilities) -> {
788                        if (!ok(status)) return;
789                        feat.value = wifiFeatureMaskFromStaCapabilities(capabilities);
790                    });
791                }
792            }
793            featureSet = feat.value;
794        } catch (RemoteException e) {
795            handleRemoteException(e);
796            return 0;
797        }
798
799        Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
800        if (supportedIfaceTypes.contains(IfaceType.STA)) {
801            featureSet |= WifiManager.WIFI_FEATURE_INFRA;
802        }
803        if (supportedIfaceTypes.contains(IfaceType.AP)) {
804            featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
805        }
806        if (supportedIfaceTypes.contains(IfaceType.P2P)) {
807            featureSet |= WifiManager.WIFI_FEATURE_P2P;
808        }
809        if (supportedIfaceTypes.contains(IfaceType.NAN)) {
810            featureSet |= WifiManager.WIFI_FEATURE_AWARE;
811        }
812
813        return featureSet;
814    }
815
816    /* RTT related commands/events */
817
818    /**
819     * RTT (Round Trip Time) measurement capabilities of the device.
820     */
821    public RttManager.RttCapabilities getRttCapabilities() {
822        class AnswerBox {
823            public RttManager.RttCapabilities value = null;
824        }
825        synchronized (sLock) {
826            if (mIWifiRttController == null) return null;
827            try {
828                AnswerBox box = new AnswerBox();
829                mIWifiRttController.getCapabilities((status, capabilities) -> {
830                    if (!ok(status)) return;
831                    mVerboseLog.info("rtt capabilites %").c(capabilities.toString()).flush();
832                    RttManager.RttCapabilities ans = new RttManager.RttCapabilities();
833                    ans.oneSidedRttSupported = capabilities.rttOneSidedSupported;
834                    ans.twoSided11McRttSupported = capabilities.rttFtmSupported;
835                    ans.lciSupported = capabilities.lciSupported;
836                    ans.lcrSupported = capabilities.lcrSupported;
837                    ans.preambleSupported = frameworkPreambleFromHalPreamble(
838                            capabilities.preambleSupport);
839                    ans.bwSupported = frameworkBwFromHalBw(capabilities.bwSupport);
840                    ans.responderSupported = capabilities.responderSupported;
841                    ans.secureRttSupported = false;
842                    ans.mcVersion = ((int) capabilities.mcVersion) & 0xff;
843                    box.value = ans;
844                });
845                return box.value;
846            } catch (RemoteException e) {
847                handleRemoteException(e);
848                return null;
849            }
850        }
851    }
852
853    private int mRttCmdIdNext = 1;              // used to generate new command ids
854    private int mRttCmdId;                      // id of currently active request
855    private RttEventCallback mRttEventCallback; // currently active RTT callback
856
857    /**
858     * Receives a callback from the Hal and passes it along to our client using RttEventHandler
859     */
860    private class RttEventCallback extends IWifiRttControllerEventCallback.Stub {
861        WifiNative.RttEventHandler mRttEventHandler;
862        int mRttCmdId;
863
864        RttEventCallback(int cmdId, WifiNative.RttEventHandler rttEventHandler) {
865            mRttCmdId = cmdId;
866            mRttEventHandler = rttEventHandler;
867        }
868
869        @Override
870        public void onResults(int cmdId, java.util.ArrayList<RttResult> results) {
871            WifiNative.RttEventHandler eventHandler;
872            synchronized (sLock) {
873                if (cmdId != mRttCmdId || mRttEventHandler == null) return;
874                eventHandler = mRttEventHandler;
875            }
876            RttManager.RttResult[] rtt = new RttManager.RttResult[results.size()];
877            for (int i = 0; i < rtt.length; i++) {
878                rtt[i] = frameworkRttResultFromHalRttResult(results.get(i));
879            }
880            eventHandler.onRttResults(rtt);
881        }
882    }
883
884    /**
885     * Converts a Hal RttResult to a RttManager.RttResult
886     */
887    @VisibleForTesting
888    static RttManager.RttResult frameworkRttResultFromHalRttResult(RttResult result) {
889        RttManager.RttResult ans = new RttManager.RttResult();
890        ans.bssid = NativeUtil.macAddressFromByteArray(result.addr);
891        ans.burstNumber = result.burstNum;
892        ans.measurementFrameNumber = result.measurementNumber;
893        ans.successMeasurementFrameNumber = result.successNumber;
894        ans.frameNumberPerBurstPeer = result.numberPerBurstPeer;
895        ans.status = result.status; //TODO(b/34901744) - don't assume identity translation
896        ans.retryAfterDuration = result.retryAfterDuration;
897        ans.measurementType = result.type;
898        ans.rssi = result.rssi;
899        ans.rssiSpread = result.rssiSpread;
900        //TODO(b/35138520) Fix HAL and framework to use the same units
901        ans.txRate = result.txRate.bitRateInKbps;
902        ans.rxRate = result.rxRate.bitRateInKbps;
903        ans.rtt = result.rtt;
904        ans.rttStandardDeviation = result.rttSd;
905        ans.rttSpread = result.rttSpread;
906        //TODO(b/35138520) These divide-by-10s were in the legacy Hal
907        ans.distance = result.distanceInMm / 10; // Convert cm to mm
908        ans.distanceStandardDeviation = result.distanceSdInMm / 10; // Convert cm to mm
909        ans.distanceSpread = result.distanceSpreadInMm / 10;
910
911        ans.ts = result.timeStampInUs;
912        ans.burstDuration = result.burstDurationInMs;
913        ans.negotiatedBurstNum = result.negotiatedBurstNum;
914        ans.LCI = ieFromHal(result.lci);
915        ans.LCR = ieFromHal(result.lcr);
916        ans.secure = false; // Not present in HIDL HAL
917        return ans;
918    }
919
920    /**
921     * Convert a Hal WifiInformationElement to its RttManager equivalent
922     */
923    @VisibleForTesting
924    static RttManager.WifiInformationElement ieFromHal(
925            android.hardware.wifi.V1_0.WifiInformationElement ie) {
926        if (ie == null) return null;
927        RttManager.WifiInformationElement ans = new RttManager.WifiInformationElement();
928        ans.id = ie.id;
929        ans.data = NativeUtil.byteArrayFromArrayList(ie.data);
930        return ans;
931    }
932
933    @VisibleForTesting
934    static RttConfig halRttConfigFromFrameworkRttParams(RttManager.RttParams params) {
935        RttConfig rttConfig = new RttConfig();
936        if (params.bssid != null) {
937            byte[] addr = NativeUtil.macAddressToByteArray(params.bssid);
938            for (int i = 0; i < rttConfig.addr.length; i++) {
939                rttConfig.addr[i] = addr[i];
940            }
941        }
942        rttConfig.type = halRttTypeFromFrameworkRttType(params.requestType);
943        rttConfig.peer = halPeerFromFrameworkPeer(params.deviceType);
944        rttConfig.channel.width = halChannelWidthFromFrameworkChannelWidth(params.channelWidth);
945        rttConfig.channel.centerFreq = params.frequency;
946        rttConfig.channel.centerFreq0 = params.centerFreq0;
947        rttConfig.channel.centerFreq1 = params.centerFreq1;
948        rttConfig.burstPeriod = params.interval; // In 100ms units, 0 means no specific
949        rttConfig.numBurst = params.numberBurst;
950        rttConfig.numFramesPerBurst = params.numSamplesPerBurst;
951        rttConfig.numRetriesPerRttFrame = params.numRetriesPerMeasurementFrame;
952        rttConfig.numRetriesPerFtmr = params.numRetriesPerFTMR;
953        rttConfig.mustRequestLci = params.LCIRequest;
954        rttConfig.mustRequestLcr = params.LCRRequest;
955        rttConfig.burstDuration = params.burstTimeout;
956        rttConfig.preamble = halPreambleFromFrameworkPreamble(params.preamble);
957        rttConfig.bw = halBwFromFrameworkBw(params.bandwidth);
958        return rttConfig;
959    }
960
961    @VisibleForTesting
962    static int halRttTypeFromFrameworkRttType(int frameworkRttType) {
963        switch (frameworkRttType) {
964            case RttManager.RTT_TYPE_ONE_SIDED:
965                return RttType.ONE_SIDED;
966            case RttManager.RTT_TYPE_TWO_SIDED:
967                return RttType.TWO_SIDED;
968            default:
969                throw new IllegalArgumentException("bad " + frameworkRttType);
970        }
971    }
972
973    @VisibleForTesting
974    static int frameworkRttTypeFromHalRttType(int halType) {
975        switch (halType) {
976            case RttType.ONE_SIDED:
977                return RttManager.RTT_TYPE_ONE_SIDED;
978            case RttType.TWO_SIDED:
979                return RttManager.RTT_TYPE_TWO_SIDED;
980            default:
981                throw new IllegalArgumentException("bad " + halType);
982        }
983    }
984
985    @VisibleForTesting
986    static int halPeerFromFrameworkPeer(int frameworkPeer) {
987        switch (frameworkPeer) {
988            case RttManager.RTT_PEER_TYPE_AP:
989                return RttPeerType.AP;
990            case RttManager.RTT_PEER_TYPE_STA:
991                return RttPeerType.STA;
992            case RttManager.RTT_PEER_P2P_GO:
993                return RttPeerType.P2P_GO;
994            case RttManager.RTT_PEER_P2P_CLIENT:
995                return RttPeerType.P2P_CLIENT;
996            case RttManager.RTT_PEER_NAN:
997                return RttPeerType.NAN;
998            default:
999                throw new IllegalArgumentException("bad " + frameworkPeer);
1000        }
1001    }
1002
1003    @VisibleForTesting
1004    static int frameworkPeerFromHalPeer(int halPeer) {
1005        switch (halPeer) {
1006            case RttPeerType.AP:
1007                return RttManager.RTT_PEER_TYPE_AP;
1008            case RttPeerType.STA:
1009                return RttManager.RTT_PEER_TYPE_STA;
1010            case RttPeerType.P2P_GO:
1011                return RttManager.RTT_PEER_P2P_GO;
1012            case RttPeerType.P2P_CLIENT:
1013                return RttManager.RTT_PEER_P2P_CLIENT;
1014            case RttPeerType.NAN:
1015                return RttManager.RTT_PEER_NAN;
1016            default:
1017                throw new IllegalArgumentException("bad " + halPeer);
1018
1019        }
1020    }
1021
1022    @VisibleForTesting
1023    static int halChannelWidthFromFrameworkChannelWidth(int frameworkChannelWidth) {
1024        switch (frameworkChannelWidth) {
1025            case ScanResult.CHANNEL_WIDTH_20MHZ:
1026                return WifiChannelWidthInMhz.WIDTH_20;
1027            case ScanResult.CHANNEL_WIDTH_40MHZ:
1028                return WifiChannelWidthInMhz.WIDTH_40;
1029            case ScanResult.CHANNEL_WIDTH_80MHZ:
1030                return WifiChannelWidthInMhz.WIDTH_80;
1031            case ScanResult.CHANNEL_WIDTH_160MHZ:
1032                return WifiChannelWidthInMhz.WIDTH_160;
1033            case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
1034                return WifiChannelWidthInMhz.WIDTH_80P80;
1035            default:
1036                throw new IllegalArgumentException("bad " + frameworkChannelWidth);
1037        }
1038    }
1039
1040    @VisibleForTesting
1041    static int frameworkChannelWidthFromHalChannelWidth(int halChannelWidth) {
1042        switch (halChannelWidth) {
1043            case WifiChannelWidthInMhz.WIDTH_20:
1044                return ScanResult.CHANNEL_WIDTH_20MHZ;
1045            case WifiChannelWidthInMhz.WIDTH_40:
1046                return ScanResult.CHANNEL_WIDTH_40MHZ;
1047            case WifiChannelWidthInMhz.WIDTH_80:
1048                return ScanResult.CHANNEL_WIDTH_80MHZ;
1049            case WifiChannelWidthInMhz.WIDTH_160:
1050                return ScanResult.CHANNEL_WIDTH_160MHZ;
1051            case WifiChannelWidthInMhz.WIDTH_80P80:
1052                return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
1053            default:
1054                throw new IllegalArgumentException("bad " + halChannelWidth);
1055        }
1056    }
1057
1058    @VisibleForTesting
1059    static int halPreambleFromFrameworkPreamble(int rttManagerPreamble) {
1060        BitMask checkoff = new BitMask(rttManagerPreamble);
1061        int flags = 0;
1062        if (checkoff.testAndClear(RttManager.PREAMBLE_LEGACY)) {
1063            flags |= RttPreamble.LEGACY;
1064        }
1065        if (checkoff.testAndClear(RttManager.PREAMBLE_HT)) {
1066            flags |= RttPreamble.HT;
1067        }
1068        if (checkoff.testAndClear(RttManager.PREAMBLE_VHT)) {
1069            flags |= RttPreamble.VHT;
1070        }
1071        if (checkoff.value != 0) {
1072            throw new IllegalArgumentException("bad " + rttManagerPreamble);
1073        }
1074        return flags;
1075    }
1076
1077    @VisibleForTesting
1078    static int frameworkPreambleFromHalPreamble(int halPreamble) {
1079        BitMask checkoff = new BitMask(halPreamble);
1080        int flags = 0;
1081        if (checkoff.testAndClear(RttPreamble.LEGACY)) {
1082            flags |= RttManager.PREAMBLE_LEGACY;
1083        }
1084        if (checkoff.testAndClear(RttPreamble.HT)) {
1085            flags |= RttManager.PREAMBLE_HT;
1086        }
1087        if (checkoff.testAndClear(RttPreamble.VHT)) {
1088            flags |= RttManager.PREAMBLE_VHT;
1089        }
1090        if (checkoff.value != 0) {
1091            throw new IllegalArgumentException("bad " + halPreamble);
1092        }
1093        return flags;
1094    }
1095
1096    @VisibleForTesting
1097    static int halBwFromFrameworkBw(int rttManagerBandwidth) {
1098        BitMask checkoff = new BitMask(rttManagerBandwidth);
1099        int flags = 0;
1100        if (checkoff.testAndClear(RttManager.RTT_BW_5_SUPPORT)) {
1101            flags |= RttBw.BW_5MHZ;
1102        }
1103        if (checkoff.testAndClear(RttManager.RTT_BW_10_SUPPORT)) {
1104            flags |= RttBw.BW_10MHZ;
1105        }
1106        if (checkoff.testAndClear(RttManager.RTT_BW_20_SUPPORT)) {
1107            flags |= RttBw.BW_20MHZ;
1108        }
1109        if (checkoff.testAndClear(RttManager.RTT_BW_40_SUPPORT)) {
1110            flags |= RttBw.BW_40MHZ;
1111        }
1112        if (checkoff.testAndClear(RttManager.RTT_BW_80_SUPPORT)) {
1113            flags |= RttBw.BW_80MHZ;
1114        }
1115        if (checkoff.testAndClear(RttManager.RTT_BW_160_SUPPORT)) {
1116            flags |= RttBw.BW_160MHZ;
1117        }
1118        if (checkoff.value != 0) {
1119            throw new IllegalArgumentException("bad " + rttManagerBandwidth);
1120        }
1121        return flags;
1122    }
1123
1124    @VisibleForTesting
1125    static int frameworkBwFromHalBw(int rttBw) {
1126        BitMask checkoff = new BitMask(rttBw);
1127        int flags = 0;
1128        if (checkoff.testAndClear(RttBw.BW_5MHZ)) {
1129            flags |= RttManager.RTT_BW_5_SUPPORT;
1130        }
1131        if (checkoff.testAndClear(RttBw.BW_10MHZ)) {
1132            flags |= RttManager.RTT_BW_10_SUPPORT;
1133        }
1134        if (checkoff.testAndClear(RttBw.BW_20MHZ)) {
1135            flags |= RttManager.RTT_BW_20_SUPPORT;
1136        }
1137        if (checkoff.testAndClear(RttBw.BW_40MHZ)) {
1138            flags |= RttManager.RTT_BW_40_SUPPORT;
1139        }
1140        if (checkoff.testAndClear(RttBw.BW_80MHZ)) {
1141            flags |= RttManager.RTT_BW_80_SUPPORT;
1142        }
1143        if (checkoff.testAndClear(RttBw.BW_160MHZ)) {
1144            flags |= RttManager.RTT_BW_160_SUPPORT;
1145        }
1146        if (checkoff.value != 0) {
1147            throw new IllegalArgumentException("bad " + rttBw);
1148        }
1149        return flags;
1150    }
1151
1152    @VisibleForTesting
1153    static ArrayList<RttConfig> halRttConfigArrayFromFrameworkRttParamsArray(
1154            RttManager.RttParams[] params) {
1155        final int length = params.length;
1156        ArrayList<RttConfig> config = new ArrayList<RttConfig>(length);
1157        for (int i = 0; i < length; i++) {
1158            config.add(halRttConfigFromFrameworkRttParams(params[i]));
1159        }
1160        return config;
1161    }
1162
1163    /**
1164     * Starts a new rtt request
1165     *
1166     * @param params
1167     * @param handler
1168     * @return success indication
1169     */
1170    public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) {
1171        ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
1172        synchronized (sLock) {
1173            if (mIWifiRttController == null) return boolResult(false);
1174            if (mRttCmdId != 0) return boolResult(false);
1175            mRttCmdId = mRttCmdIdNext++;
1176            if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
1177            try {
1178                mRttEventCallback = new RttEventCallback(mRttCmdId, handler);
1179                WifiStatus status = mIWifiRttController.rangeRequest(mRttCmdId, rttConfigs);
1180                if (ok(status)) {
1181                    status = mIWifiRttController.registerEventCallback(mRttEventCallback);
1182                }
1183                if (ok(status)) return true;
1184                mRttCmdId = 0;
1185                return false;
1186            } catch (RemoteException e) {
1187                handleRemoteException(e);
1188                return false;
1189            }
1190        }
1191    }
1192
1193    /**
1194     * Cancels an outstanding rtt request
1195     *
1196     * @param params
1197     * @return true if there was an outstanding request and it was successfully cancelled
1198     */
1199    public boolean cancelRtt(RttManager.RttParams[] params) {
1200        ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
1201        synchronized (sLock) {
1202            if (mIWifiRttController == null) return boolResult(false);
1203            if (mRttCmdId == 0) return boolResult(false);
1204            ArrayList<byte[/* 6 */]> addrs = new ArrayList<byte[]>(rttConfigs.size());
1205            for (RttConfig x : rttConfigs) addrs.add(x.addr);
1206            try {
1207                WifiStatus status = mIWifiRttController.rangeCancel(mRttCmdId, addrs);
1208                mRttCmdId = 0;
1209                if (!ok(status)) return false;
1210                return true;
1211            } catch (RemoteException e) {
1212                handleRemoteException(e);
1213                return false;
1214            }
1215        }
1216    }
1217
1218    private int mRttResponderCmdId = 0;
1219
1220    /**
1221     * Get RTT responder information e.g. WiFi channel to enable responder on.
1222     *
1223     * @return info Instance of |RttResponder|, or null for error.
1224     */
1225    private RttResponder getRttResponder() {
1226        class AnswerBox {
1227            public RttResponder value = null;
1228        }
1229        synchronized (sLock) {
1230            if (mIWifiRttController == null) return null;
1231            AnswerBox answer = new AnswerBox();
1232            try {
1233                mIWifiRttController.getResponderInfo((status, info) -> {
1234                    if (!ok(status)) return;
1235                    answer.value = info;
1236                });
1237                return answer.value;
1238            } catch (RemoteException e) {
1239                handleRemoteException(e);
1240                return null;
1241            }
1242        }
1243    }
1244
1245    /**
1246     * Convert Hal RttResponder to a framework ResponderConfig
1247     *
1248     * @param info Instance of |RttResponder|
1249     * @return framework version of same
1250     */
1251    private ResponderConfig frameworkResponderConfigFromHalRttResponder(RttResponder info) {
1252        ResponderConfig config = new ResponderConfig();
1253        config.frequency = info.channel.centerFreq;
1254        config.centerFreq0 = info.channel.centerFreq0;
1255        config.centerFreq1 = info.channel.centerFreq1;
1256        config.channelWidth = frameworkChannelWidthFromHalChannelWidth(info.channel.width);
1257        config.preamble = frameworkPreambleFromHalPreamble(info.preamble);
1258        return config;
1259    }
1260
1261    /**
1262     * Enables RTT responder role on the device.
1263     *
1264     * @return {@link ResponderConfig} if the responder role is successfully enabled,
1265     * {@code null} otherwise.
1266     */
1267    public ResponderConfig enableRttResponder(int timeoutSeconds) {
1268        RttResponder info = getRttResponder();
1269        synchronized (sLock) {
1270            if (mIWifiRttController == null) return null;
1271            if (mRttResponderCmdId != 0) {
1272                mLog.e("responder mode already enabled - this shouldn't happen");
1273                return null;
1274            }
1275            ResponderConfig config = null;
1276            int id = mRttCmdIdNext++;
1277            if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
1278            try {
1279                WifiStatus status = mIWifiRttController.enableResponder(
1280                        /* cmdId */id,
1281                        /* WifiChannelInfo channelHint */null,
1282                        timeoutSeconds, info);
1283                if (ok(status)) {
1284                    mRttResponderCmdId = id;
1285                    config = frameworkResponderConfigFromHalRttResponder(info);
1286                    mVerboseLog.i("enabling rtt " + mRttResponderCmdId);
1287                }
1288                return config;
1289            } catch (RemoteException e) {
1290                handleRemoteException(e);
1291                return null;
1292            }
1293        }
1294    }
1295
1296    /**
1297     * Disables RTT responder role.
1298     *
1299     * @return {@code true} if responder role is successfully disabled,
1300     * {@code false} otherwise.
1301     */
1302    public boolean disableRttResponder() {
1303        synchronized (sLock) {
1304            if (mIWifiRttController == null) return boolResult(false);
1305            if (mRttResponderCmdId == 0) return boolResult(false);
1306            try {
1307                WifiStatus status = mIWifiRttController.disableResponder(mRttResponderCmdId);
1308                mRttResponderCmdId = 0;
1309                if (!ok(status)) return false;
1310                return true;
1311            } catch (RemoteException e) {
1312                handleRemoteException(e);
1313                return false;
1314            }
1315        }
1316    }
1317
1318    /**
1319     * Set the MAC OUI during scanning.
1320     * <p>
1321     * An OUI {Organizationally Unique Identifier} is a 24-bit number that
1322     * uniquely identifies a vendor or manufacturer.
1323     *
1324     * @param oui
1325     * @return true for success
1326     */
1327    public boolean setScanningMacOui(byte[] oui) {
1328        if (oui == null) return boolResult(false);
1329        if (oui.length != 3) return boolResult(false);
1330        synchronized (sLock) {
1331            try {
1332                if (mIWifiStaIface == null) return boolResult(false);
1333                WifiStatus status = mIWifiStaIface.setScanningMacOui(oui);
1334                if (!ok(status)) return false;
1335                return true;
1336            } catch (RemoteException e) {
1337                handleRemoteException(e);
1338                return false;
1339            }
1340        }
1341    }
1342
1343    /**
1344     * Query the list of valid frequencies for the provided band.
1345     * <p>
1346     * The result depends on the on the country code that has been set.
1347     *
1348     * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1349     * @return frequencies vector of valid frequencies (MHz), or null for error.
1350     * @throws IllegalArgumentException if band is not recognized.
1351     */
1352    public int[] getChannelsForBand(int band) {
1353        enter("%").c(band).flush();
1354        class AnswerBox {
1355            public int[] value = null;
1356        }
1357        synchronized (sLock) {
1358            try {
1359                AnswerBox box = new AnswerBox();
1360                int hb = makeWifiBandFromFrameworkBand(band);
1361                if (mIWifiStaIface != null) {
1362                    mIWifiStaIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
1363                        if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
1364                            mChannelsForBandSupport = false;
1365                        }
1366                        if (!ok(status)) return;
1367                        mChannelsForBandSupport = true;
1368                        box.value = intArrayFromArrayList(frequencies);
1369                    });
1370                } else if (mIWifiApIface != null) {
1371                    mIWifiApIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
1372                        if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
1373                            mChannelsForBandSupport = false;
1374                        }
1375                        if (!ok(status)) return;
1376                        mChannelsForBandSupport = true;
1377                        box.value = intArrayFromArrayList(frequencies);
1378                    });
1379                }
1380                return box.value;
1381            } catch (RemoteException e) {
1382                handleRemoteException(e);
1383                return null;
1384            }
1385        }
1386    }
1387
1388    private int[] intArrayFromArrayList(ArrayList<Integer> in) {
1389        int[] ans = new int[in.size()];
1390        int i = 0;
1391        for (Integer e : in) ans[i++] = e;
1392        return ans;
1393    }
1394
1395    /**
1396     * This holder is null until we know whether or not there is frequency-for-band support.
1397     * <p>
1398     * Set as a side-effect of getChannelsForBand.
1399     */
1400    @VisibleForTesting
1401    Boolean mChannelsForBandSupport = null;
1402
1403    /**
1404     * Indicates whether getChannelsForBand is supported.
1405     *
1406     * @return true if it is.
1407     */
1408    public boolean isGetChannelsForBandSupported() {
1409        if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
1410        getChannelsForBand(WifiBand.BAND_24GHZ);
1411        if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
1412        return false;
1413    }
1414
1415    /**
1416     * Set DFS - actually, this is always on.
1417     *
1418     * @param dfsOn
1419     * @return success indication
1420     */
1421    public boolean setDfsFlag(boolean dfsOn) {
1422        return dfsOn;
1423    }
1424
1425    /**
1426     * Get the APF (Android Packet Filter) capabilities of the device
1427     */
1428    public ApfCapabilities getApfCapabilities() {
1429        class AnswerBox {
1430            public ApfCapabilities value = sNoApfCapabilities;
1431        }
1432        synchronized (sLock) {
1433            try {
1434                if (mIWifiStaIface == null) return sNoApfCapabilities;
1435                AnswerBox box = new AnswerBox();
1436                mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
1437                    if (!ok(status)) return;
1438                    box.value = new ApfCapabilities(
1439                        /* apfVersionSupported */   capabilities.version,
1440                        /* maximumApfProgramSize */ capabilities.maxLength,
1441                        /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
1442                });
1443                return box.value;
1444            } catch (RemoteException e) {
1445                handleRemoteException(e);
1446                return sNoApfCapabilities;
1447            }
1448        }
1449    }
1450
1451    private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
1452
1453    /**
1454     * Installs an APF program on this iface, replacing any existing program.
1455     *
1456     * @param filter is the android packet filter program
1457     * @return true for success
1458     */
1459    public boolean installPacketFilter(byte[] filter) {
1460        int cmdId = 0; //TODO(b/34901818) We only aspire to support one program at a time
1461        if (filter == null) return boolResult(false);
1462        // Copy the program before taking the lock.
1463        ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter);
1464        enter("filter length %").c(filter.length).flush();
1465        synchronized (sLock) {
1466            try {
1467                if (mIWifiStaIface == null) return boolResult(false);
1468                WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
1469                if (!ok(status)) return false;
1470                return true;
1471            } catch (RemoteException e) {
1472                handleRemoteException(e);
1473                return false;
1474            }
1475        }
1476    }
1477
1478    /**
1479     * Set country code for this AP iface.
1480     *
1481     * @param countryCode - two-letter country code (as ISO 3166)
1482     * @return true for success
1483     */
1484    public boolean setCountryCodeHal(String countryCode) {
1485        if (countryCode == null) return boolResult(false);
1486        if (countryCode.length() != 2) return boolResult(false);
1487        byte[] code;
1488        try {
1489            code = NativeUtil.stringToByteArray(countryCode);
1490        } catch (IllegalArgumentException e) {
1491            return boolResult(false);
1492        }
1493        synchronized (sLock) {
1494            try {
1495                if (mIWifiApIface == null) return boolResult(false);
1496                WifiStatus status = mIWifiApIface.setCountryCode(code);
1497                if (!ok(status)) return false;
1498                return true;
1499            } catch (RemoteException e) {
1500                handleRemoteException(e);
1501                return false;
1502            }
1503        }
1504    }
1505
1506    private WifiNative.WifiLoggerEventHandler mVerboseLogEventHandler = null;
1507
1508    /**
1509     * Registers the logger callback and enables alerts.
1510     * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
1511     */
1512    public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
1513        if (handler == null) return boolResult(false);
1514        synchronized (sLock) {
1515            if (mIWifiChip == null) return boolResult(false);
1516            if (mVerboseLogEventHandler != null) return boolResult(false);
1517            try {
1518                WifiStatus status = mIWifiChip.enableDebugErrorAlerts(true);
1519                if (!ok(status)) return false;
1520                mVerboseLogEventHandler = handler;
1521                return true;
1522            } catch (RemoteException e) {
1523                handleRemoteException(e);
1524                return false;
1525            }
1526        }
1527    }
1528
1529    /**
1530     * Stops all logging and resets the logger callback.
1531     * This stops both the alerts and ring buffer data collection.
1532     */
1533    public boolean resetLogHandler() {
1534        synchronized (sLock) {
1535            if (mIWifiChip == null) return boolResult(false);
1536            if (mVerboseLogEventHandler == null) return boolResult(false);
1537            try {
1538                WifiStatus status = mIWifiChip.enableDebugErrorAlerts(false);
1539                if (!ok(status)) return false;
1540                status = mIWifiChip.stopLoggingToDebugRingBuffer();
1541                if (!ok(status)) return false;
1542                mVerboseLogEventHandler = null;
1543                return true;
1544            } catch (RemoteException e) {
1545                handleRemoteException(e);
1546                return false;
1547            }
1548        }
1549    }
1550
1551    /**
1552     * Control debug data collection
1553     *
1554     * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
1555     * @param flags              Ignored.
1556     * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
1557     * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
1558     * @param ringName           Name of the ring for which data collection is to start.
1559     * @return true for success
1560     */
1561    public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
1562                                          int minDataSizeInBytes, String ringName) {
1563        enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%")
1564                .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName)
1565                .flush();
1566        synchronized (sLock) {
1567            if (mIWifiChip == null) return boolResult(false);
1568            try {
1569                // note - flags are not used
1570                WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer(
1571                        ringName,
1572                        verboseLevel,
1573                        maxIntervalInSec,
1574                        minDataSizeInBytes
1575                );
1576                return ok(status);
1577            } catch (RemoteException e) {
1578                handleRemoteException(e);
1579                return false;
1580            }
1581        }
1582    }
1583
1584    /**
1585     * Pointlessly fail
1586     *
1587     * @return -1
1588     */
1589    public int getSupportedLoggerFeatureSet() {
1590        return -1;
1591    }
1592
1593    private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
1594
1595    /**
1596     * Vendor-provided wifi driver version string
1597     */
1598    public String getDriverVersion() {
1599        synchronized (sLock) {
1600            if (mDriverDescription == null) requestChipDebugInfo();
1601            return mDriverDescription;
1602        }
1603    }
1604
1605    private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
1606
1607    /**
1608     * Vendor-provided wifi firmware version string
1609     */
1610    public String getFirmwareVersion() {
1611        synchronized (sLock) {
1612            if (mFirmwareDescription == null) requestChipDebugInfo();
1613            return mFirmwareDescription;
1614        }
1615    }
1616
1617    /**
1618     * Refreshes our idea of the driver and firmware versions
1619     */
1620    private void requestChipDebugInfo() {
1621        mDriverDescription = null;
1622        mFirmwareDescription = null;
1623        try {
1624            if (mIWifiChip == null) return;
1625            mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
1626                if (!ok(status)) return;
1627                mDriverDescription = chipDebugInfo.driverDescription;
1628                mFirmwareDescription = chipDebugInfo.firmwareDescription;
1629            });
1630        } catch (RemoteException e) {
1631            handleRemoteException(e);
1632            return;
1633        }
1634        mLog.info("Driver: % Firmware: %")
1635                .c(mDriverDescription)
1636                .c(mFirmwareDescription)
1637                .flush();
1638    }
1639
1640    /**
1641     * Creates RingBufferStatus from the Hal version
1642     */
1643    private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) {
1644        WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus();
1645        ans.name = h.ringName;
1646        ans.flag = frameworkRingBufferFlagsFromHal(h.flags);
1647        ans.ringBufferId = h.ringId;
1648        ans.ringBufferByteSize = h.sizeInBytes;
1649        ans.verboseLevel = h.verboseLevel;
1650        // Remaining fields are unavailable
1651        //  writtenBytes;
1652        //  readBytes;
1653        //  writtenRecords;
1654        return ans;
1655    }
1656
1657    /**
1658     * Translates a hal wifiDebugRingBufferFlag to the WifiNative version
1659     */
1660    private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) {
1661        BitMask checkoff = new BitMask(wifiDebugRingBufferFlag);
1662        int flags = 0;
1663        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) {
1664            flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES;
1665        }
1666        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) {
1667            flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES;
1668        }
1669        if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) {
1670            flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES;
1671        }
1672        if (checkoff.value != 0) {
1673            throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value);
1674        }
1675        return flags;
1676    }
1677
1678    /**
1679     * Creates array of RingBufferStatus from the Hal version
1680     */
1681    private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray(
1682            ArrayList<WifiDebugRingBufferStatus> ringBuffers) {
1683        WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()];
1684        int i = 0;
1685        for (WifiDebugRingBufferStatus b : ringBuffers) {
1686            ans[i++] = ringBufferStatus(b);
1687        }
1688        return ans;
1689    }
1690
1691    /**
1692     * API to get the status of all ring buffers supported by driver
1693     */
1694    public WifiNative.RingBufferStatus[] getRingBufferStatus() {
1695        class AnswerBox {
1696            public WifiNative.RingBufferStatus[] value = null;
1697        }
1698        AnswerBox ans = new AnswerBox();
1699        synchronized (sLock) {
1700            if (mIWifiChip == null) return null;
1701            try {
1702                mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> {
1703                    if (!ok(status)) return;
1704                    ans.value = makeRingBufferStatusArray(ringBuffers);
1705                });
1706            } catch (RemoteException e) {
1707                handleRemoteException(e);
1708                return null;
1709            }
1710        }
1711        return ans.value;
1712    }
1713
1714    /**
1715     * Indicates to driver that all the data has to be uploaded urgently
1716     */
1717    public boolean getRingBufferData(String ringName) {
1718        enter("ringName %").c(ringName).flush();
1719        synchronized (sLock) {
1720            if (mIWifiChip == null) return boolResult(false);
1721            try {
1722                WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName);
1723                return ok(status);
1724            } catch (RemoteException e) {
1725                handleRemoteException(e);
1726                return false;
1727            }
1728        }
1729    }
1730
1731    /**
1732     * Request vendor debug info from the firmware
1733     */
1734    public byte[] getFwMemoryDump() {
1735        class AnswerBox {
1736            public byte[] value;
1737        }
1738        AnswerBox ans = new AnswerBox();
1739        synchronized (sLock) {
1740            if (mIWifiChip == null) return (null);
1741            try {
1742                mIWifiChip.requestFirmwareDebugDump((status, blob) -> {
1743                    if (!ok(status)) return;
1744                    ans.value = NativeUtil.byteArrayFromArrayList(blob);
1745                });
1746            } catch (RemoteException e) {
1747                handleRemoteException(e);
1748                return null;
1749            }
1750        }
1751        return ans.value;
1752    }
1753
1754    /**
1755     * Request vendor debug info from the driver
1756     */
1757    public byte[] getDriverStateDump() {
1758        class AnswerBox {
1759            public byte[] value;
1760        }
1761        AnswerBox ans = new AnswerBox();
1762        synchronized (sLock) {
1763            if (mIWifiChip == null) return (null);
1764            try {
1765                mIWifiChip.requestDriverDebugDump((status, blob) -> {
1766                    if (!ok(status)) return;
1767                    ans.value = NativeUtil.byteArrayFromArrayList(blob);
1768                });
1769            } catch (RemoteException e) {
1770                handleRemoteException(e);
1771                return null;
1772            }
1773        }
1774        return ans.value;
1775    }
1776
1777    /**
1778     * Start packet fate monitoring
1779     * <p>
1780     * Once started, monitoring remains active until HAL is unloaded.
1781     *
1782     * @return true for success
1783     */
1784    public boolean startPktFateMonitoring() {
1785        synchronized (sLock) {
1786            if (mIWifiStaIface == null) return boolResult(false);
1787            try {
1788                WifiStatus status = mIWifiStaIface.startDebugPacketFateMonitoring();
1789                return ok(status);
1790            } catch (RemoteException e) {
1791                handleRemoteException(e);
1792                return false;
1793            }
1794        }
1795    }
1796
1797    private byte halToFrameworkPktFateFrameType(int type) {
1798        switch (type) {
1799            case WifiDebugPacketFateFrameType.UNKNOWN:
1800                return WifiLoggerHal.FRAME_TYPE_UNKNOWN;
1801            case WifiDebugPacketFateFrameType.ETHERNET_II:
1802                return WifiLoggerHal.FRAME_TYPE_ETHERNET_II;
1803            case WifiDebugPacketFateFrameType.MGMT_80211:
1804                return WifiLoggerHal.FRAME_TYPE_80211_MGMT;
1805            default:
1806                throw new IllegalArgumentException("bad " + type);
1807        }
1808    }
1809
1810    private byte halToFrameworkRxPktFate(int type) {
1811        switch (type) {
1812            case WifiDebugRxPacketFate.SUCCESS:
1813                return WifiLoggerHal.RX_PKT_FATE_SUCCESS;
1814            case WifiDebugRxPacketFate.FW_QUEUED:
1815                return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED;
1816            case WifiDebugRxPacketFate.FW_DROP_FILTER:
1817                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER;
1818            case WifiDebugRxPacketFate.FW_DROP_INVALID:
1819                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID;
1820            case WifiDebugRxPacketFate.FW_DROP_NOBUFS:
1821                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS;
1822            case WifiDebugRxPacketFate.FW_DROP_OTHER:
1823                return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER;
1824            case WifiDebugRxPacketFate.DRV_QUEUED:
1825                return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED;
1826            case WifiDebugRxPacketFate.DRV_DROP_FILTER:
1827                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER;
1828            case WifiDebugRxPacketFate.DRV_DROP_INVALID:
1829                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID;
1830            case WifiDebugRxPacketFate.DRV_DROP_NOBUFS:
1831                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS;
1832            case WifiDebugRxPacketFate.DRV_DROP_OTHER:
1833                return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER;
1834            default:
1835                throw new IllegalArgumentException("bad " + type);
1836        }
1837    }
1838
1839    private byte halToFrameworkTxPktFate(int type) {
1840        switch (type) {
1841            case WifiDebugTxPacketFate.ACKED:
1842                return WifiLoggerHal.TX_PKT_FATE_ACKED;
1843            case WifiDebugTxPacketFate.SENT:
1844                return WifiLoggerHal.TX_PKT_FATE_SENT;
1845            case WifiDebugTxPacketFate.FW_QUEUED:
1846                return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED;
1847            case WifiDebugTxPacketFate.FW_DROP_INVALID:
1848                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID;
1849            case WifiDebugTxPacketFate.FW_DROP_NOBUFS:
1850                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS;
1851            case WifiDebugTxPacketFate.FW_DROP_OTHER:
1852                return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER;
1853            case WifiDebugTxPacketFate.DRV_QUEUED:
1854                return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED;
1855            case WifiDebugTxPacketFate.DRV_DROP_INVALID:
1856                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID;
1857            case WifiDebugTxPacketFate.DRV_DROP_NOBUFS:
1858                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS;
1859            case WifiDebugTxPacketFate.DRV_DROP_OTHER:
1860                return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER;
1861            default:
1862                throw new IllegalArgumentException("bad " + type);
1863        }
1864    }
1865
1866    /**
1867     * Retrieve fates of outbound packets
1868     * <p>
1869     * Reports the outbound frames for the most recent association (space allowing).
1870     *
1871     * @param reportBufs
1872     * @return true for success
1873     */
1874    public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
1875        if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
1876        synchronized (sLock) {
1877            if (mIWifiStaIface == null) return boolResult(false);
1878            try {
1879                MutableBoolean ok = new MutableBoolean(false);
1880                mIWifiStaIface.getDebugTxPacketFates((status, fates) -> {
1881                            if (!ok(status)) return;
1882                            int i = 0;
1883                            for (WifiDebugTxPacketFateReport fate : fates) {
1884                                if (i >= reportBufs.length) break;
1885                                byte code = halToFrameworkTxPktFate(fate.fate);
1886                                long us = fate.frameInfo.driverTimestampUsec;
1887                                byte type =
1888                                        halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1889                                byte[] frame =
1890                                        NativeUtil.byteArrayFromArrayList(
1891                                                fate.frameInfo.frameContent);
1892                                reportBufs[i++] =
1893                                        new WifiNative.TxFateReport(code, us, type, frame);
1894                            }
1895                            ok.value = true;
1896                        }
1897                );
1898                return ok.value;
1899            } catch (RemoteException e) {
1900                handleRemoteException(e);
1901                return false;
1902            }
1903        }
1904    }
1905
1906    /**
1907     * Retrieve fates of inbound packets
1908     * <p>
1909     * Reports the inbound frames for the most recent association (space allowing).
1910     *
1911     * @param reportBufs
1912     * @return true for success
1913     */
1914    public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
1915        if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
1916        synchronized (sLock) {
1917            if (mIWifiStaIface == null) return boolResult(false);
1918            try {
1919                MutableBoolean ok = new MutableBoolean(false);
1920                mIWifiStaIface.getDebugRxPacketFates((status, fates) -> {
1921                            if (!ok(status)) return;
1922                            int i = 0;
1923                            for (WifiDebugRxPacketFateReport fate : fates) {
1924                                if (i >= reportBufs.length) break;
1925                                byte code = halToFrameworkRxPktFate(fate.fate);
1926                                long us = fate.frameInfo.driverTimestampUsec;
1927                                byte type =
1928                                        halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1929                                byte[] frame =
1930                                        NativeUtil.byteArrayFromArrayList(
1931                                                fate.frameInfo.frameContent);
1932                                reportBufs[i++] =
1933                                        new WifiNative.RxFateReport(code, us, type, frame);
1934                            }
1935                            ok.value = true;
1936                        }
1937                );
1938                return ok.value;
1939            } catch (RemoteException e) {
1940                handleRemoteException(e);
1941                return false;
1942            }
1943        }
1944    }
1945
1946    /**
1947     * Start sending the specified keep alive packets periodically.
1948     *
1949     * @param slot
1950     * @param srcMac
1951     * @param keepAlivePacket
1952     * @param periodInMs
1953     * @return 0 for success, -1 for error
1954     */
1955    public int startSendingOffloadedPacket(
1956            int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs) {
1957        enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush();
1958
1959        ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(keepAlivePacket.data);
1960        short protocol = (short) (keepAlivePacket.protocol);
1961
1962        synchronized (sLock) {
1963            if (mIWifiStaIface == null) return -1;
1964            try {
1965                WifiStatus status = mIWifiStaIface.startSendingKeepAlivePackets(
1966                        slot,
1967                        data,
1968                        protocol,
1969                        srcMac,
1970                        keepAlivePacket.dstMac,
1971                        periodInMs);
1972                if (!ok(status)) return -1;
1973                return 0;
1974            } catch (RemoteException e) {
1975                handleRemoteException(e);
1976                return -1;
1977            }
1978        }
1979    }
1980
1981    /**
1982     * Stop sending the specified keep alive packets.
1983     *
1984     * @param slot id - same as startSendingOffloadedPacket call.
1985     * @return 0 for success, -1 for error
1986     */
1987    public int stopSendingOffloadedPacket(int slot) {
1988        enter("slot=%").c(slot).flush();
1989
1990        synchronized (sLock) {
1991            if (mIWifiStaIface == null) return -1;
1992            try {
1993                WifiStatus status = mIWifiStaIface.stopSendingKeepAlivePackets(slot);
1994                if (!ok(status)) return -1;
1995                return 0;
1996            } catch (RemoteException e) {
1997                handleRemoteException(e);
1998                return -1;
1999            }
2000        }
2001    }
2002
2003    /**
2004     * A fixed cmdId for our RssiMonitoring (we only do one at a time)
2005     */
2006    @VisibleForTesting
2007    static final int sRssiMonCmdId = 7551;
2008
2009    /**
2010     * Our client's handler
2011     */
2012    private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler;
2013
2014    /**
2015     * Start RSSI monitoring on the currently connected access point.
2016     *
2017     * @param maxRssi          Maximum RSSI threshold.
2018     * @param minRssi          Minimum RSSI threshold.
2019     * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
2020     * @return 0 for success, -1 for failure
2021     */
2022    public int startRssiMonitoring(byte maxRssi, byte minRssi,
2023                                   WifiNative.WifiRssiEventHandler rssiEventHandler) {
2024        enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush();
2025        if (maxRssi <= minRssi) return -1;
2026        if (rssiEventHandler == null) return -1;
2027        synchronized (sLock) {
2028            if (mIWifiStaIface == null) return -1;
2029            try {
2030                mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
2031                WifiStatus status;
2032                status = mIWifiStaIface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
2033                if (!ok(status)) return -1;
2034                mWifiRssiEventHandler = rssiEventHandler;
2035                return 0;
2036            } catch (RemoteException e) {
2037                handleRemoteException(e);
2038                return -1;
2039            }
2040        }
2041    }
2042
2043    /**
2044     * Stop RSSI monitoring
2045     *
2046     * @return 0 for success, -1 for failure
2047     */
2048    public int stopRssiMonitoring() {
2049        synchronized (sLock) {
2050            mWifiRssiEventHandler = null;
2051            if (mIWifiStaIface == null) return -1;
2052            try {
2053                mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
2054                WifiStatus status = mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
2055                if (!ok(status)) return -1;
2056                return 0;
2057            } catch (RemoteException e) {
2058                handleRemoteException(e);
2059                return -1;
2060            }
2061        }
2062    }
2063
2064    //TODO - belongs in NativeUtil
2065    private static int[] intsFromArrayList(ArrayList<Integer> a) {
2066        if (a == null) return null;
2067        int[] b = new int[a.size()];
2068        int i = 0;
2069        for (Integer e : a) b[i++] = e;
2070        return b;
2071    }
2072
2073    /**
2074     * Translates from Hal version of wake reason stats to the framework version of same
2075     *
2076     * @param h - Hal version of wake reason stats
2077     * @return framework version of same
2078     */
2079    private static WifiWakeReasonAndCounts halToFrameworkWakeReasons(
2080            WifiDebugHostWakeReasonStats h) {
2081        if (h == null) return null;
2082        WifiWakeReasonAndCounts ans = new WifiWakeReasonAndCounts();
2083        ans.totalCmdEventWake = h.totalCmdEventWakeCnt;
2084        ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt;
2085        ans.totalRxDataWake = h.totalRxPacketWakeCnt;
2086        ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt;
2087        ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt;
2088        ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt;
2089        ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt;
2090        ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt;
2091        ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra;
2092        ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na;
2093        ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns;
2094        ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt;
2095        ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt;
2096        ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt;
2097        ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType);
2098        ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType);
2099        return ans;
2100    }
2101
2102    /**
2103     * Fetch the host wakeup reasons stats from wlan driver.
2104     *
2105     * @return the |WifiWakeReasonAndCounts| from the wlan driver, or null on failure.
2106     */
2107    public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
2108        class AnswerBox {
2109            public WifiDebugHostWakeReasonStats value = null;
2110        }
2111        AnswerBox ans = new AnswerBox();
2112        synchronized (sLock) {
2113            if (mIWifiChip == null) return null;
2114            try {
2115                mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> {
2116                    if (ok(status)) {
2117                        ans.value = stats;
2118                    }
2119                });
2120                return halToFrameworkWakeReasons(ans.value);
2121            } catch (RemoteException e) {
2122                handleRemoteException(e);
2123                return null;
2124            }
2125        }
2126    }
2127
2128    /**
2129     * Enable/Disable Neighbour discovery offload functionality in the firmware.
2130     *
2131     * @param enabled true to enable, false to disable.
2132     */
2133    public boolean configureNeighborDiscoveryOffload(boolean enabled) {
2134        enter("enabled=%").c(enabled).flush();
2135        synchronized (sLock) {
2136            if (mIWifiStaIface == null) return boolResult(false);
2137            try {
2138                WifiStatus status = mIWifiStaIface.enableNdOffload(enabled);
2139                if (!ok(status)) return false;
2140            } catch (RemoteException e) {
2141                handleRemoteException(e);
2142                return false;
2143            }
2144        }
2145        return true;
2146    }
2147
2148    // Firmware roaming control.
2149
2150    /**
2151     * Query the firmware roaming capabilities.
2152     *
2153     * @param capabilities object to be filled in
2154     * @return true for success; false for failure
2155     */
2156    public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
2157        synchronized (sLock) {
2158            try {
2159                if (mIWifiStaIface == null) return boolResult(false);
2160                MutableBoolean ok = new MutableBoolean(false);
2161                WifiNative.RoamingCapabilities out = capabilities;
2162                mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
2163                    if (!ok(status)) return;
2164                    out.maxBlacklistSize = cap.maxBlacklistSize;
2165                    out.maxWhitelistSize = cap.maxWhitelistSize;
2166                    ok.value = true;
2167                });
2168                return ok.value;
2169            } catch (RemoteException e) {
2170                handleRemoteException(e);
2171                return false;
2172            }
2173        }
2174    }
2175
2176    /**
2177     * Enable/disable firmware roaming.
2178     *
2179     * @param state the intended roaming state
2180     * @return SUCCESS, FAILURE, or BUSY
2181     */
2182    public int enableFirmwareRoaming(int state) {
2183        synchronized (sLock) {
2184            if (mIWifiStaIface == null) return WifiStatusCode.ERROR_NOT_STARTED;
2185            try {
2186                byte val;
2187                switch (state) {
2188                    case WifiNative.DISABLE_FIRMWARE_ROAMING:
2189                        val = StaRoamingState.DISABLED;
2190                        break;
2191                    case WifiNative.ENABLE_FIRMWARE_ROAMING:
2192                        val = StaRoamingState.ENABLED;
2193                        break;
2194                    default:
2195                        mLog.e("enableFirmwareRoaming invalid argument " + state);
2196                        return WifiStatusCode.ERROR_INVALID_ARGS;
2197                }
2198
2199                WifiStatus status = mIWifiStaIface.setRoamingState(val);
2200                mVerboseLog.d("setRoamingState returned " + status.code);
2201                return status.code;
2202            } catch (RemoteException e) {
2203                handleRemoteException(e);
2204                return WifiStatusCode.ERROR_UNKNOWN;
2205            }
2206        }
2207    }
2208
2209    /**
2210     * Set firmware roaming configurations.
2211     *
2212     * @param config new roaming configuration object
2213     * @return true for success; false for failure
2214     */
2215    public boolean configureRoaming(WifiNative.RoamingConfig config) {
2216        synchronized (sLock) {
2217            if (mIWifiStaIface == null) return boolResult(false);
2218            try {
2219                StaRoamingConfig roamingConfig = new StaRoamingConfig();
2220
2221                // parse the blacklist BSSIDs if any
2222                if (config.blacklistBssids != null) {
2223                    for (String bssid : config.blacklistBssids) {
2224                        byte[] mac = NativeUtil.macAddressToByteArray(bssid);
2225                        roamingConfig.bssidBlacklist.add(mac);
2226                    }
2227                }
2228
2229                // parse the whitelist SSIDs if any
2230                if (config.whitelistSsids != null) {
2231                    for (String ssidStr : config.whitelistSsids) {
2232                        String unquotedSsidStr = WifiInfo.removeDoubleQuotes(ssidStr);
2233
2234                        int len = unquotedSsidStr.length();
2235                        if (len > 32) {
2236                            mLog.err("configureRoaming: skip invalid SSID %")
2237                                    .r(unquotedSsidStr).flush();
2238                            continue;
2239                        }
2240                        byte[] ssid = new byte[len];
2241                        for (int i = 0; i < len; i++) {
2242                            ssid[i] = (byte) unquotedSsidStr.charAt(i);
2243                        }
2244                        roamingConfig.ssidWhitelist.add(ssid);
2245                    }
2246                }
2247
2248                WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
2249                if (!ok(status)) return false;
2250            } catch (RemoteException e) {
2251                handleRemoteException(e);
2252                return false;
2253            }
2254            return true;
2255        }
2256    }
2257
2258    // This creates a blob of IE elements from the array received.
2259    // TODO: This ugly conversion can be removed if we put IE elements in ScanResult.
2260    private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) {
2261        if (ies == null || ies.isEmpty()) return new byte[0];
2262        ArrayList<Byte> ieBlob = new ArrayList<>();
2263        for (WifiInformationElement ie : ies) {
2264            ieBlob.add(ie.id);
2265            ieBlob.addAll(ie.data);
2266        }
2267        return NativeUtil.byteArrayFromArrayList(ieBlob);
2268    }
2269
2270    // This is only filling up the fields of Scan Result used by Gscan clients.
2271    private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) {
2272        if (scanResult == null) return null;
2273        ScanResult frameworkScanResult = new ScanResult();
2274        frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid);
2275        frameworkScanResult.wifiSsid =
2276                WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid));
2277        frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid);
2278        frameworkScanResult.level = scanResult.rssi;
2279        frameworkScanResult.frequency = scanResult.frequency;
2280        frameworkScanResult.timestamp = scanResult.timeStampInUs;
2281        frameworkScanResult.bytes = hidlIeArrayToFrameworkIeBlob(scanResult.informationElements);
2282        return frameworkScanResult;
2283    }
2284
2285    private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) {
2286        if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0];
2287        ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()];
2288        int i = 0;
2289        for (StaScanResult scanResult : scanResults) {
2290            frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult);
2291        }
2292        return frameworkScanResults;
2293    }
2294
2295    /**
2296     * This just returns whether the scan was interrupted or not.
2297     */
2298    private static int hidlToFrameworkScanDataFlags(int flag) {
2299        if (flag == StaScanDataFlagMask.INTERRUPTED) {
2300            return 1;
2301        } else {
2302            return 0;
2303        }
2304    }
2305
2306    private static WifiScanner.ScanData[] hidlToFrameworkScanDatas(
2307            int cmdId, ArrayList<StaScanData> scanDatas) {
2308        if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0];
2309        WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()];
2310        int i = 0;
2311        for (StaScanData scanData : scanDatas) {
2312            int flags = hidlToFrameworkScanDataFlags(scanData.flags);
2313            ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results);
2314            frameworkScanDatas[i++] =
2315                    new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned, false,
2316                            frameworkScanResults);
2317        }
2318        return frameworkScanDatas;
2319    }
2320
2321    /**
2322     * Callback for events on the STA interface.
2323     */
2324    private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
2325        @Override
2326        public void onBackgroundScanFailure(int cmdId) {
2327            mVerboseLog.d("onBackgroundScanFailure " + cmdId);
2328            WifiNative.ScanEventHandler eventHandler;
2329            synchronized (sLock) {
2330                if (mScan == null || cmdId != mScan.cmdId) return;
2331                eventHandler = mScan.eventHandler;
2332            }
2333            eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
2334        }
2335
2336        @Override
2337        public void onBackgroundFullScanResult(
2338                int cmdId, int bucketsScanned, StaScanResult result) {
2339            mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
2340            WifiNative.ScanEventHandler eventHandler;
2341            synchronized (sLock) {
2342                if (mScan == null || cmdId != mScan.cmdId) return;
2343                eventHandler = mScan.eventHandler;
2344            }
2345            eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned);
2346        }
2347
2348        @Override
2349        public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
2350            mVerboseLog.d("onBackgroundScanResults " + cmdId);
2351            WifiNative.ScanEventHandler eventHandler;
2352            // WifiScanner currently uses the results callback to fetch the scan results.
2353            // So, simulate that by sending out the notification and then caching the results
2354            // locally. This will then be returned to WifiScanner via getScanResults.
2355            synchronized (sLock) {
2356                if (mScan == null || cmdId != mScan.cmdId) return;
2357                eventHandler = mScan.eventHandler;
2358                mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
2359            }
2360            eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
2361        }
2362
2363        @Override
2364        public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
2365            mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
2366            WifiNative.WifiRssiEventHandler eventHandler;
2367            synchronized (sLock) {
2368                if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
2369                eventHandler = mWifiRssiEventHandler;
2370            }
2371            eventHandler.onRssiThresholdBreached((byte) currRssi);
2372        }
2373    }
2374
2375    /**
2376     * Callback for events on the STA interface.
2377     */
2378    private class ChipEventCallback extends IWifiChipEventCallback.Stub {
2379        @Override
2380        public void onChipReconfigured(int modeId) {
2381            mVerboseLog.d("onChipReconfigured " + modeId);
2382        }
2383
2384        @Override
2385        public void onChipReconfigureFailure(WifiStatus status) {
2386            mVerboseLog.d("onChipReconfigureFailure " + status);
2387        }
2388
2389        public void onIfaceAdded(int type, String name) {
2390            mVerboseLog.d("onIfaceAdded " + type + ", name: " + name);
2391        }
2392
2393        @Override
2394        public void onIfaceRemoved(int type, String name) {
2395            mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name);
2396        }
2397
2398        @Override
2399        public void onDebugRingBufferDataAvailable(
2400                WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
2401            //TODO(b/35875078) Reinstate logging when execessive callbacks are fixed
2402            // mVerboseLog.d("onDebugRingBufferDataAvailable " + status);
2403            WifiNative.WifiLoggerEventHandler eventHandler;
2404            synchronized (sLock) {
2405                if (mVerboseLogEventHandler == null || status == null || data == null) return;
2406                eventHandler = mVerboseLogEventHandler;
2407            }
2408            eventHandler.onRingBufferData(
2409                    ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data));
2410        }
2411
2412        @Override
2413        public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
2414            mVerboseLog.d("onDebugErrorAlert " + errorCode);
2415            WifiNative.WifiLoggerEventHandler eventHandler;
2416            synchronized (sLock) {
2417                if (mVerboseLogEventHandler == null || debugData == null) return;
2418                eventHandler = mVerboseLogEventHandler;
2419            }
2420            eventHandler.onWifiAlert(
2421                    errorCode, NativeUtil.byteArrayFromArrayList(debugData));
2422        }
2423    }
2424
2425    /**
2426     * Hal Device Manager callbacks.
2427     */
2428    public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
2429        @Override
2430        public void onStatusChanged() {
2431            boolean isReady = mHalDeviceManager.isReady();
2432            boolean isStarted = mHalDeviceManager.isStarted();
2433
2434            mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady
2435                    + ", isStarted(): " + isStarted);
2436            // Reset all our cached handles.
2437            // TODO(b/33384303) it could be dicey not having this grab the lock
2438            if (!isReady || !isStarted) {
2439                mIWifiChip = null;
2440                mIWifiStaIface = null;
2441                mIWifiApIface = null;
2442                mIWifiRttController = null;
2443                mDriverDescription = null;
2444                mFirmwareDescription = null;
2445                // TODO(b/33384303) likely other things to clear out
2446            }
2447        }
2448    }
2449}
2450