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