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