HalDeviceManager.java revision 8131b04dc799cb0c75240c7b9eb0517ba1f00be8
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 */
16
17package com.android.server.wifi;
18
19import android.hardware.wifi.V1_0.IWifi;
20import android.hardware.wifi.V1_0.IWifiApIface;
21import android.hardware.wifi.V1_0.IWifiChip;
22import android.hardware.wifi.V1_0.IWifiChipEventCallback;
23import android.hardware.wifi.V1_0.IWifiEventCallback;
24import android.hardware.wifi.V1_0.IWifiIface;
25import android.hardware.wifi.V1_0.IWifiNanIface;
26import android.hardware.wifi.V1_0.IWifiP2pIface;
27import android.hardware.wifi.V1_0.IWifiRttController;
28import android.hardware.wifi.V1_0.IWifiStaIface;
29import android.hardware.wifi.V1_0.IfaceType;
30import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
31import android.hardware.wifi.V1_0.WifiStatus;
32import android.hardware.wifi.V1_0.WifiStatusCode;
33import android.hidl.manager.V1_0.IServiceManager;
34import android.hidl.manager.V1_0.IServiceNotification;
35import android.os.Handler;
36import android.os.HwRemoteBinder;
37import android.os.Looper;
38import android.os.Message;
39import android.os.RemoteException;
40import android.util.Log;
41import android.util.MutableBoolean;
42import android.util.MutableInt;
43import android.util.SparseArray;
44
45import com.android.internal.annotations.VisibleForTesting;
46
47import java.io.FileDescriptor;
48import java.io.PrintWriter;
49import java.util.ArrayList;
50import java.util.Arrays;
51import java.util.HashMap;
52import java.util.HashSet;
53import java.util.Iterator;
54import java.util.List;
55import java.util.Map;
56import java.util.Set;
57
58/**
59 * Handles device management through the HAL (HIDL) interface.
60 */
61public class HalDeviceManager {
62    private static final String TAG = "HalDeviceManager";
63    private static final boolean DBG = false;
64
65    private static final int START_HAL_RETRY_INTERVAL_MS = 20;
66    // Number of attempts a start() is re-tried. A value of 0 means no retries after a single
67    // attempt.
68    @VisibleForTesting
69    public static final int START_HAL_RETRY_TIMES = 3;
70    @VisibleForTesting
71    public static final String HAL_INSTANCE_NAME = "default";
72
73    // public API
74    public HalDeviceManager() {
75        mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashSet<>());
76        mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashSet<>());
77        mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashSet<>());
78        mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashSet<>());
79    }
80
81    /**
82     * Actually starts the HalDeviceManager: separate from constructor since may want to phase
83     * at a later time.
84     *
85     * TODO: if decide that no need for separating construction from initialization (e.g. both are
86     * done at injector) then move to constructor.
87     */
88    public void initialize() {
89        initializeInternal();
90    }
91
92    /**
93     * Register a ManagerStatusListener to get information about the status of the manager. Use the
94     * isReady() and isStarted() methods to check status immediately after registration and when
95     * triggered.
96     *
97     * It is safe to re-register the same callback object - duplicates are detected and only a
98     * single copy kept.
99     *
100     * @param listener ManagerStatusListener listener object.
101     * @param looper Looper on which to dispatch listener. Null implies current looper.
102     */
103    public void registerStatusListener(ManagerStatusListener listener, Looper looper) {
104        synchronized (mLock) {
105            if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener,
106                    looper == null ? Looper.myLooper() : looper))) {
107                Log.w(TAG, "registerStatusListener: duplicate registration ignored");
108            }
109        }
110    }
111
112    /**
113     * Returns whether the vendor HAL is supported on this device or not.
114     */
115    public boolean isSupported() {
116        return isSupportedInternal();
117    }
118
119    /**
120     * Returns the current status of the HalDeviceManager: whether or not it is ready to execute
121     * commands. A return of 'false' indicates that the HAL service (IWifi) is not available. Use
122     * the registerStatusListener() to listener for status changes.
123     */
124    public boolean isReady() {
125        return mWifi != null;
126    }
127
128    /**
129     * Returns the current status of Wi-Fi: started (true) or stopped (false).
130     *
131     * Note: direct call to HIDL.
132     */
133    public boolean isStarted() {
134        return isWifiStarted();
135    }
136
137    /**
138     * Attempts to start Wi-Fi (using HIDL). Returns the success (true) or failure (false) or
139     * the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
140     * success.
141     *
142     * Note: direct call to HIDL.
143     */
144    public boolean start() {
145        return startWifi();
146    }
147
148    /**
149     * Stops Wi-Fi. Will also dispatch any registeredManagerStatusCallback.onStop().
150     *
151     * Note: direct call to HIDL - failure is not-expected.
152     */
153    public void stop() {
154        stopWifi();
155    }
156
157    /**
158     * HAL device manager status change listener.
159     */
160    public interface ManagerStatusListener {
161        /**
162         * Indicates that the status of the HalDeviceManager has changed. Use isReady() and
163         * isStarted() to obtain status information.
164         */
165        void onStatusChanged();
166    }
167
168    /**
169     * Return the set of supported interface types across all Wi-Fi chips on the device.
170     *
171     * @return A set of IfaceTypes constants (possibly empty, e.g. on error).
172     */
173    Set<Integer> getSupportedIfaceTypes() {
174        return getSupportedIfaceTypesInternal(null);
175    }
176
177    /**
178     * Return the set of supported interface types for the specified Wi-Fi chip.
179     *
180     * @return A set of IfaceTypes constants  (possibly empty, e.g. on error).
181     */
182    Set<Integer> getSupportedIfaceTypes(IWifiChip chip) {
183        return getSupportedIfaceTypesInternal(chip);
184    }
185
186    // interface-specific behavior
187
188    /**
189     * Create a STA interface if possible. Changes chip mode and removes conflicting interfaces if
190     * needed and permitted by priority.
191     *
192     * @param destroyedListener Optional (nullable) listener to call when the allocated interface
193     *                          is removed. Will only be registered and used if an interface is
194     *                          created successfully.
195     * @param looper The looper on which to dispatch the listener. A null value indicates the
196     *               current thread.
197     * @return A newly created interface - or null if the interface could not be created.
198     */
199    public IWifiStaIface createStaIface(InterfaceDestroyedListener destroyedListener,
200            Looper looper) {
201        return (IWifiStaIface) createIface(IfaceType.STA, destroyedListener, looper);
202    }
203
204    /**
205     * Create AP interface if possible (see createStaIface doc).
206     */
207    public IWifiApIface createApIface(InterfaceDestroyedListener destroyedListener,
208            Looper looper) {
209        return (IWifiApIface) createIface(IfaceType.AP, destroyedListener, looper);
210    }
211
212    /**
213     * Create P2P interface if possible (see createStaIface doc).
214     */
215    public IWifiP2pIface createP2pIface(InterfaceDestroyedListener destroyedListener,
216            Looper looper) {
217        return (IWifiP2pIface) createIface(IfaceType.P2P, destroyedListener, looper);
218    }
219
220    /**
221     * Create NAN interface if possible (see createStaIface doc).
222     */
223    public IWifiNanIface createNanIface(InterfaceDestroyedListener destroyedListener,
224            Looper looper) {
225        return (IWifiNanIface) createIface(IfaceType.NAN, destroyedListener, looper);
226    }
227
228    /**
229     * Removes (releases/destroys) the given interface. Will trigger any registered
230     * InterfaceDestroyedListeners and possibly some InterfaceAvailableForRequestListeners if we
231     * can potentially create some other interfaces as a result of removing this interface.
232     */
233    public boolean removeIface(IWifiIface iface) {
234        boolean success = removeIfaceInternal(iface);
235        dispatchAvailableForRequestListeners();
236        return success;
237    }
238
239    /**
240     * Returns the IWifiChip corresponding to the specified interface (or null on error).
241     *
242     * Note: clients must not perform chip mode changes or interface management (create/delete)
243     * operations on IWifiChip directly. However, they can use the IWifiChip interface to perform
244     * other functions - e.g. calling the debug/trace methods.
245     */
246    public IWifiChip getChip(IWifiIface iface) {
247        if (DBG) Log.d(TAG, "getChip: iface(name)=" + getName(iface));
248
249        synchronized (mLock) {
250            InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(iface);
251            if (cacheEntry == null) {
252                Log.e(TAG, "getChip: no entry for iface(name)=" + getName(iface));
253                return null;
254            }
255
256            return cacheEntry.chip;
257        }
258    }
259
260    /**
261     * Register an InterfaceDestroyedListener to the specified iface - returns true on success
262     * and false on failure. This listener is in addition to the one registered when the interface
263     * was created - allowing non-creators to monitor interface status.
264     *
265     * Listener called-back on the specified looper - or on the current looper if a null is passed.
266     */
267    public boolean registerDestroyedListener(IWifiIface iface,
268            InterfaceDestroyedListener destroyedListener,
269            Looper looper) {
270        if (DBG) Log.d(TAG, "registerDestroyedListener: iface(name)=" + getName(iface));
271
272        synchronized (mLock) {
273            InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(iface);
274            if (cacheEntry == null) {
275                Log.e(TAG, "registerDestroyedListener: no entry for iface(name)="
276                        + getName(iface));
277                return false;
278            }
279
280            return cacheEntry.destroyedListeners.add(
281                    new InterfaceDestroyedListenerProxy(destroyedListener,
282                            looper == null ? Looper.myLooper() : looper));
283        }
284    }
285
286    /**
287     * Register a listener to be called when an interface of the specified type could be requested.
288     * No guarantees are provided (some other entity could request it first). The listener is
289     * active from registration until unregistration - using
290     * unregisterInterfaceAvailableForRequestListener().
291     *
292     * Only a single instance of a listener will be registered (even if the specified looper is
293     * different).
294     *
295     * Note that if it is possible to create the specified interface type at registration time
296     * then the callback will be triggered immediately.
297     *
298     * @param ifaceType The interface type (IfaceType) to be monitored.
299     * @param listener Listener to call when an interface of the requested
300     *                 type could be created
301     * @param looper The looper on which to dispatch the listener. A null value indicates the
302     *               current thread.
303     */
304    public void registerInterfaceAvailableForRequestListener(int ifaceType,
305            InterfaceAvailableForRequestListener listener, Looper looper) {
306        mInterfaceAvailableForRequestListeners.get(ifaceType).add(
307                new InterfaceAvailableForRequestListenerProxy(listener,
308                        looper == null ? Looper.myLooper() : looper));
309
310        WifiChipInfo[] chipInfos = getAllChipInfo();
311        if (chipInfos == null) {
312            Log.e(TAG,
313                    "registerInterfaceAvailableForRequestListener: no chip info found - but "
314                            + "possibly registered pre-started - ignoring");
315            return;
316        }
317        dispatchAvailableForRequestListenersForType(ifaceType, chipInfos);
318    }
319
320    /**
321     * Unregisters a listener registered with registerInterfaceAvailableForRequestListener().
322     */
323    public void unregisterInterfaceAvailableForRequestListener(
324            int ifaceType,
325            InterfaceAvailableForRequestListener listener) {
326        Iterator<InterfaceAvailableForRequestListenerProxy> it =
327                mInterfaceAvailableForRequestListeners.get(ifaceType).iterator();
328        while (it.hasNext()) {
329            if (it.next().mListener == listener) {
330                it.remove();
331                return;
332            }
333        }
334    }
335
336    /**
337     * Return the name of the input interface or null on error.
338     */
339    public static String getName(IWifiIface iface) {
340        if (iface == null) {
341            return "<null>";
342        }
343
344        Mutable<String> nameResp = new Mutable<>();
345        try {
346            iface.getName((WifiStatus status, String name) -> {
347                if (status.code == WifiStatusCode.SUCCESS) {
348                    nameResp.value = name;
349                } else {
350                    Log.e(TAG, "Error on getName: " + statusString(status));
351                }
352            });
353        } catch (RemoteException e) {
354            Log.e(TAG, "Exception on getName: " + e);
355        }
356
357        return nameResp.value;
358    }
359
360    /**
361     * Called when interface is destroyed.
362     */
363    public interface InterfaceDestroyedListener {
364        /**
365         * Called for every interface on which registered when destroyed - whether
366         * destroyed by releaseIface() or through chip mode change or through Wi-Fi
367         * going down.
368         *
369         * Can be registered when the interface is requested with createXxxIface() - will
370         * only be valid if the interface creation was successful - i.e. a non-null was returned.
371         */
372        void onDestroyed();
373    }
374
375    /**
376     * Called when an interface type is possibly available for creation.
377     */
378    public interface InterfaceAvailableForRequestListener {
379        /**
380         * Registered when an interface type could be requested. Registered with
381         * registerInterfaceAvailableForRequestListener() and unregistered with
382         * unregisterInterfaceAvailableForRequestListener().
383         */
384        void onAvailableForRequest();
385    }
386
387    /**
388     * Creates a IWifiRttController corresponding to the input interface. A direct match to the
389     * IWifiChip.createRttController() method.
390     *
391     * Returns the created IWifiRttController or a null on error.
392     */
393    public IWifiRttController createRttController(IWifiIface boundIface) {
394        if (DBG) Log.d(TAG, "createRttController: boundIface(name)=" + getName(boundIface));
395        synchronized (mLock) {
396            if (mWifi == null) {
397                Log.e(TAG, "createRttController: null IWifi -- boundIface(name)="
398                        + getName(boundIface));
399                return null;
400            }
401
402            IWifiChip chip = getChip(boundIface);
403            if (chip == null) {
404                Log.e(TAG, "createRttController: null IWifiChip -- boundIface(name)="
405                        + getName(boundIface));
406                return null;
407            }
408
409            Mutable<IWifiRttController> rttResp = new Mutable<>();
410            try {
411                chip.createRttController(boundIface,
412                        (WifiStatus status, IWifiRttController rtt) -> {
413                            if (status.code == WifiStatusCode.SUCCESS) {
414                                rttResp.value = rtt;
415                            } else {
416                                Log.e(TAG, "IWifiChip.createRttController failed: " + statusString(
417                                        status));
418                            }
419                        });
420            } catch (RemoteException e) {
421                Log.e(TAG, "IWifiChip.createRttController exception: " + e);
422            }
423
424            return rttResp.value;
425        }
426    }
427
428    // internal state
429
430    /* This "PRIORITY" is not for deciding interface elimination (that is controlled by
431     * allowedToDeleteIfaceTypeForRequestedType. This priority is used for:
432     * - Comparing 2 configuration options
433     * - Order of dispatch of available for request listeners
434     */
435    private static final int[] IFACE_TYPES_BY_PRIORITY =
436            {IfaceType.AP, IfaceType.STA, IfaceType.P2P, IfaceType.NAN};
437
438    private final Object mLock = new Object();
439
440    private IServiceManager mServiceManager;
441    private IWifi mWifi;
442    private final WifiEventCallback mWifiEventCallback = new WifiEventCallback();
443    private final Set<ManagerStatusListenerProxy> mManagerStatusListeners = new HashSet<>();
444    private final SparseArray<Set<InterfaceAvailableForRequestListenerProxy>>
445            mInterfaceAvailableForRequestListeners = new SparseArray<>();
446
447    /*
448     * This is the only place where we cache HIDL information in this manager. Necessary since
449     * we need to keep a list of registered destroyed listeners. Will be validated regularly
450     * in getAllChipInfoAndValidateCache().
451     */
452    private final Map<IWifiIface, InterfaceCacheEntry> mInterfaceInfoCache = new HashMap<>();
453
454    private class InterfaceCacheEntry {
455        public IWifiChip chip;
456        public int chipId;
457        public String name;
458        public int type;
459        public Set<InterfaceDestroyedListenerProxy> destroyedListeners = new HashSet<>();
460
461        @Override
462        public String toString() {
463            StringBuilder sb = new StringBuilder();
464            sb.append("{name=").append(name).append(", type=").append(type)
465                    .append(", destroyedListeners.size()=").append(destroyedListeners.size())
466                    .append("}");
467            return sb.toString();
468        }
469    }
470
471    private class WifiIfaceInfo {
472        public String name;
473        public IWifiIface iface;
474    }
475
476    private class WifiChipInfo {
477        public IWifiChip chip;
478        public int chipId;
479        public ArrayList<IWifiChip.ChipMode> availableModes;
480        public boolean currentModeIdValid;
481        public int currentModeId;
482        public WifiIfaceInfo[][] ifaces = new WifiIfaceInfo[IFACE_TYPES_BY_PRIORITY.length][];
483
484        @Override
485        public String toString() {
486            StringBuilder sb = new StringBuilder();
487            sb.append("{chipId=").append(chipId).append(", availableModes=").append(availableModes)
488                    .append(", currentModeIdValid=").append(currentModeIdValid)
489                    .append(", currentModeId=").append(currentModeId);
490            for (int type: IFACE_TYPES_BY_PRIORITY) {
491                sb.append(", ifaces[" + type + "].length=").append(ifaces[type].length);
492            }
493            sb.append(")");
494            return sb.toString();
495        }
496    }
497
498    /**
499     * Wrapper function to access the HIDL services. Created to be mockable in unit-tests.
500     */
501    protected IWifi getWifiServiceMockable() {
502        try {
503            return IWifi.getService();
504        } catch (RemoteException e) {
505            Log.e(TAG, "Exception getting IWifi service: " + e);
506            return null;
507        }
508    }
509
510    protected IServiceManager getServiceManagerMockable() {
511        try {
512            return IServiceManager.getService();
513        } catch (RemoteException e) {
514            Log.e(TAG, "Exception getting IServiceManager: " + e);
515            return null;
516        }
517    }
518
519    // internal implementation
520
521    private void initializeInternal() {
522        initIServiceManagerIfNecessary();
523    }
524
525    private void teardownInternal() {
526        managerStatusListenerDispatch();
527        dispatchAllDestroyedListeners();
528        mInterfaceAvailableForRequestListeners.get(IfaceType.STA).clear();
529        mInterfaceAvailableForRequestListeners.get(IfaceType.AP).clear();
530        mInterfaceAvailableForRequestListeners.get(IfaceType.P2P).clear();
531        mInterfaceAvailableForRequestListeners.get(IfaceType.NAN).clear();
532    }
533
534    private final HwRemoteBinder.DeathRecipient mServiceManagerDeathRecipient =
535            cookie -> {
536                Log.wtf(TAG, "IServiceManager died: cookie=" + cookie);
537                synchronized (mLock) {
538                    mServiceManager = null;
539                    // theoretically can call initServiceManager again here - but
540                    // there's no point since most likely system is going to reboot
541                }
542            };
543
544    private final IServiceNotification mServiceNotificationCallback =
545            new IServiceNotification.Stub() {
546                @Override
547                public void onRegistration(String fqName, String name,
548                                           boolean preexisting) {
549                    Log.d(TAG, "IWifi registration notification: fqName=" + fqName
550                            + ", name=" + name + ", preexisting=" + preexisting);
551                    mWifi = null; // get rid of old copy!
552                    initIWifiIfNecessary();
553                    stopWifi(); // just in case
554                }
555            };
556
557    /**
558     * Failures of IServiceManager are most likely system breaking in any case. Behavior here
559     * will be to WTF and continue.
560     */
561    private void initIServiceManagerIfNecessary() {
562        if (DBG) Log.d(TAG, "initIServiceManagerIfNecessary");
563
564        synchronized (mLock) {
565            if (mServiceManager != null) {
566                return;
567            }
568
569            mServiceManager = getServiceManagerMockable();
570            if (mServiceManager == null) {
571                Log.wtf(TAG, "Failed to get IServiceManager instance");
572            } else {
573                try {
574                    if (!mServiceManager.linkToDeath(
575                            mServiceManagerDeathRecipient, /* don't care */ 0)) {
576                        Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
577                        mServiceManager = null;
578                        return;
579                    }
580
581                    if (!mServiceManager.registerForNotifications(IWifi.kInterfaceName, "",
582                            mServiceNotificationCallback)) {
583                        Log.wtf(TAG, "Failed to register a listener for IWifi service");
584                        mServiceManager = null;
585                    }
586                } catch (RemoteException e) {
587                    Log.wtf(TAG, "Exception while operating on IServiceManager: " + e);
588                    mServiceManager = null;
589                }
590            }
591        }
592    }
593
594    /**
595     * Uses the IServiceManager to query if the vendor HAL is present in the VINTF for the device
596     * or not.
597     * @return true if supported, false otherwise.
598     */
599    private boolean isSupportedInternal() {
600        if (DBG) Log.d(TAG, "isSupportedInternal");
601
602        synchronized (mLock) {
603            if (mServiceManager == null) {
604                Log.wtf(TAG, "isSupported: called but mServiceManager is null!?");
605                return false;
606            }
607            try {
608                return (mServiceManager.getTransport(IWifi.kInterfaceName, HAL_INSTANCE_NAME)
609                        != IServiceManager.Transport.EMPTY);
610            } catch (RemoteException e) {
611                Log.wtf(TAG, "Exception while operating on IServiceManager: " + e);
612                return false;
613            }
614        }
615    }
616
617    private final HwRemoteBinder.DeathRecipient mIWifiDeathRecipient =
618            cookie -> {
619                Log.e(TAG, "IWifi HAL service died! Have a listener for it ... cookie=" + cookie);
620                synchronized (mLock) { // prevents race condition with surrounding method
621                    mWifi = null;
622                    teardownInternal();
623                    // don't restart: wait for registration notification
624                }
625            };
626
627    /**
628     * Initialize IWifi and register death listener and event callback.
629     *
630     * - It is possible that IWifi is not ready - we have a listener on IServiceManager for it.
631     * - It is not expected that any of the registrations will fail. Possible indication that
632     *   service died after we obtained a handle to it.
633     *
634     * Here and elsewhere we assume that death listener will do the right thing!
635    */
636    private void initIWifiIfNecessary() {
637        if (DBG) Log.d(TAG, "initIWifiIfNecessary");
638
639        synchronized (mLock) {
640            if (mWifi != null) {
641                return;
642            }
643
644            try {
645                mWifi = getWifiServiceMockable();
646                if (mWifi == null) {
647                    Log.e(TAG, "IWifi not (yet) available - but have a listener for it ...");
648                    return;
649                }
650
651                if (!mWifi.linkToDeath(mIWifiDeathRecipient, /* don't care */ 0)) {
652                    Log.e(TAG, "Error on linkToDeath on IWifi - will retry later");
653                    return;
654                }
655
656                WifiStatus status = mWifi.registerEventCallback(mWifiEventCallback);
657                if (status.code != WifiStatusCode.SUCCESS) {
658                    Log.e(TAG, "IWifi.registerEventCallback failed: " + statusString(status));
659                    mWifi = null;
660                    return;
661                }
662                managerStatusListenerDispatch();
663            } catch (RemoteException e) {
664                Log.e(TAG, "Exception while operating on IWifi: " + e);
665            }
666        }
667    }
668
669    /**
670     * Registers event listeners on all IWifiChips after a successful start: DEBUG only!
671     *
672     * We don't need the listeners since any callbacks are just confirmation of status codes we
673     * obtain directly from mode changes or interface creation/deletion.
674     *
675     * Relies (to the degree we care) on the service removing all listeners when Wi-Fi is stopped.
676     */
677    private void initIWifiChipDebugListeners() {
678        if (DBG) Log.d(TAG, "initIWifiChipDebugListeners");
679
680        if (!DBG) {
681            return;
682        }
683
684        synchronized (mLock) {
685            try {
686                MutableBoolean statusOk = new MutableBoolean(false);
687                Mutable<ArrayList<Integer>> chipIdsResp = new Mutable<>();
688
689                // get all chip IDs
690                mWifi.getChipIds((WifiStatus status, ArrayList<Integer> chipIds) -> {
691                    statusOk.value = status.code == WifiStatusCode.SUCCESS;
692                    if (statusOk.value) {
693                        chipIdsResp.value = chipIds;
694                    } else {
695                        Log.e(TAG, "getChipIds failed: " + statusString(status));
696                    }
697                });
698                if (!statusOk.value) {
699                    return;
700                }
701
702                if (DBG) Log.d(TAG, "getChipIds=" + chipIdsResp.value);
703                if (chipIdsResp.value.size() == 0) {
704                    Log.e(TAG, "Should have at least 1 chip!");
705                    return;
706                }
707
708                // register a callback for each chip
709                Mutable<IWifiChip> chipResp = new Mutable<>();
710                for (Integer chipId: chipIdsResp.value) {
711                    mWifi.getChip(chipId, (WifiStatus status, IWifiChip chip) -> {
712                        statusOk.value = status.code == WifiStatusCode.SUCCESS;
713                        if (statusOk.value) {
714                            chipResp.value = chip;
715                        } else {
716                            Log.e(TAG, "getChip failed: " + statusString(status));
717                        }
718                    });
719                    if (!statusOk.value) {
720                        continue; // still try next one?
721                    }
722
723                    WifiStatus status = chipResp.value.registerEventCallback(
724                            new IWifiChipEventCallback.Stub() {
725                                @Override
726                                public void onChipReconfigured(int modeId) throws RemoteException {
727                                    Log.d(TAG, "onChipReconfigured: modeId=" + modeId);
728                                }
729
730                                @Override
731                                public void onChipReconfigureFailure(WifiStatus status)
732                                        throws RemoteException {
733                                    Log.d(TAG, "onChipReconfigureFailure: status=" + statusString(
734                                            status));
735                                }
736
737                                @Override
738                                public void onIfaceAdded(int type, String name)
739                                        throws RemoteException {
740                                    Log.d(TAG, "onIfaceAdded: type=" + type + ", name=" + name);
741                                }
742
743                                @Override
744                                public void onIfaceRemoved(int type, String name)
745                                        throws RemoteException {
746                                    Log.d(TAG, "onIfaceRemoved: type=" + type + ", name=" + name);
747                                }
748
749                                @Override
750                                public void onDebugRingBufferDataAvailable(
751                                        WifiDebugRingBufferStatus status,
752                                        ArrayList<Byte> data) throws RemoteException {
753                                    Log.d(TAG, "onDebugRingBufferDataAvailable");
754                                }
755
756                                @Override
757                                public void onDebugErrorAlert(int errorCode,
758                                        ArrayList<Byte> debugData)
759                                        throws RemoteException {
760                                    Log.d(TAG, "onDebugErrorAlert");
761                                }
762                            });
763                    if (status.code != WifiStatusCode.SUCCESS) {
764                        Log.e(TAG, "registerEventCallback failed: " + statusString(status));
765                        continue; // still try next one?
766                    }
767                }
768            } catch (RemoteException e) {
769                Log.e(TAG, "initIWifiChipDebugListeners: exception: " + e);
770                return;
771            }
772        }
773    }
774
775    /**
776     * Get current information about all the chips in the system: modes, current mode (if any), and
777     * any existing interfaces.
778     *
779     * Intended to be called whenever we need to configure the chips - information is NOT cached (to
780     * reduce the likelihood that we get out-of-sync).
781     */
782    private WifiChipInfo[] getAllChipInfo() {
783        if (DBG) Log.d(TAG, "getAllChipInfo");
784
785        synchronized (mLock) {
786            if (mWifi == null) {
787                Log.e(TAG, "getAllChipInfo: called but mWifi is null!?");
788                return null;
789            }
790
791            try {
792                MutableBoolean statusOk = new MutableBoolean(false);
793                Mutable<ArrayList<Integer>> chipIdsResp = new Mutable<>();
794
795                // get all chip IDs
796                mWifi.getChipIds((WifiStatus status, ArrayList<Integer> chipIds) -> {
797                    statusOk.value = status.code == WifiStatusCode.SUCCESS;
798                    if (statusOk.value) {
799                        chipIdsResp.value = chipIds;
800                    } else {
801                        Log.e(TAG, "getChipIds failed: " + statusString(status));
802                    }
803                });
804                if (!statusOk.value) {
805                    return null;
806                }
807
808                if (DBG) Log.d(TAG, "getChipIds=" + chipIdsResp.value);
809                if (chipIdsResp.value.size() == 0) {
810                    Log.e(TAG, "Should have at least 1 chip!");
811                    return null;
812                }
813
814                int chipInfoIndex = 0;
815                WifiChipInfo[] chipsInfo = new WifiChipInfo[chipIdsResp.value.size()];
816
817                Mutable<IWifiChip> chipResp = new Mutable<>();
818                for (Integer chipId: chipIdsResp.value) {
819                    mWifi.getChip(chipId, (WifiStatus status, IWifiChip chip) -> {
820                        statusOk.value = status.code == WifiStatusCode.SUCCESS;
821                        if (statusOk.value) {
822                            chipResp.value = chip;
823                        } else {
824                            Log.e(TAG, "getChip failed: " + statusString(status));
825                        }
826                    });
827                    if (!statusOk.value) {
828                        return null;
829                    }
830
831                    Mutable<ArrayList<IWifiChip.ChipMode>> availableModesResp = new Mutable<>();
832                    chipResp.value.getAvailableModes(
833                            (WifiStatus status, ArrayList<IWifiChip.ChipMode> modes) -> {
834                                statusOk.value = status.code == WifiStatusCode.SUCCESS;
835                                if (statusOk.value) {
836                                    availableModesResp.value = modes;
837                                } else {
838                                    Log.e(TAG, "getAvailableModes failed: " + statusString(status));
839                                }
840                            });
841                    if (!statusOk.value) {
842                        return null;
843                    }
844
845                    MutableBoolean currentModeValidResp = new MutableBoolean(false);
846                    MutableInt currentModeResp = new MutableInt(0);
847                    chipResp.value.getMode((WifiStatus status, int modeId) -> {
848                        statusOk.value = status.code == WifiStatusCode.SUCCESS;
849                        if (statusOk.value) {
850                            currentModeValidResp.value = true;
851                            currentModeResp.value = modeId;
852                        } else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
853                            statusOk.value = true; // valid response
854                        } else {
855                            Log.e(TAG, "getMode failed: " + statusString(status));
856                        }
857                    });
858                    if (!statusOk.value) {
859                        return null;
860                    }
861
862                    Mutable<ArrayList<String>> ifaceNamesResp = new Mutable<>();
863                    MutableInt ifaceIndex = new MutableInt(0);
864
865                    chipResp.value.getStaIfaceNames(
866                            (WifiStatus status, ArrayList<String> ifnames) -> {
867                                statusOk.value = status.code == WifiStatusCode.SUCCESS;
868                                if (statusOk.value) {
869                                    ifaceNamesResp.value = ifnames;
870                                } else {
871                                    Log.e(TAG, "getStaIfaceNames failed: " + statusString(status));
872                                }
873                            });
874                    if (!statusOk.value) {
875                        return null;
876                    }
877
878                    WifiIfaceInfo[] staIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()];
879                    for (String ifaceName: ifaceNamesResp.value) {
880                        chipResp.value.getStaIface(ifaceName,
881                                (WifiStatus status, IWifiStaIface iface) -> {
882                                    statusOk.value = status.code == WifiStatusCode.SUCCESS;
883                                    if (statusOk.value) {
884                                        WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
885                                        ifaceInfo.name = ifaceName;
886                                        ifaceInfo.iface = iface;
887                                        staIfaces[ifaceIndex.value++] = ifaceInfo;
888                                    } else {
889                                        Log.e(TAG, "getStaIface failed: " + statusString(status));
890                                    }
891                                });
892                        if (!statusOk.value) {
893                            return null;
894                        }
895                    }
896
897                    ifaceIndex.value = 0;
898                    chipResp.value.getApIfaceNames(
899                            (WifiStatus status, ArrayList<String> ifnames) -> {
900                                statusOk.value = status.code == WifiStatusCode.SUCCESS;
901                                if (statusOk.value) {
902                                    ifaceNamesResp.value = ifnames;
903                                } else {
904                                    Log.e(TAG, "getApIfaceNames failed: " + statusString(status));
905                                }
906                            });
907                    if (!statusOk.value) {
908                        return null;
909                    }
910
911                    WifiIfaceInfo[] apIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()];
912                    for (String ifaceName: ifaceNamesResp.value) {
913                        chipResp.value.getApIface(ifaceName,
914                                (WifiStatus status, IWifiApIface iface) -> {
915                                    statusOk.value = status.code == WifiStatusCode.SUCCESS;
916                                    if (statusOk.value) {
917                                        WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
918                                        ifaceInfo.name = ifaceName;
919                                        ifaceInfo.iface = iface;
920                                        apIfaces[ifaceIndex.value++] = ifaceInfo;
921                                    } else {
922                                        Log.e(TAG, "getApIface failed: " + statusString(status));
923                                    }
924                                });
925                        if (!statusOk.value) {
926                            return null;
927                        }
928                    }
929
930                    ifaceIndex.value = 0;
931                    chipResp.value.getP2pIfaceNames(
932                            (WifiStatus status, ArrayList<String> ifnames) -> {
933                                statusOk.value = status.code == WifiStatusCode.SUCCESS;
934                                if (statusOk.value) {
935                                    ifaceNamesResp.value = ifnames;
936                                } else {
937                                    Log.e(TAG, "getP2pIfaceNames failed: " + statusString(status));
938                                }
939                            });
940                    if (!statusOk.value) {
941                        return null;
942                    }
943
944                    WifiIfaceInfo[] p2pIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()];
945                    for (String ifaceName: ifaceNamesResp.value) {
946                        chipResp.value.getP2pIface(ifaceName,
947                                (WifiStatus status, IWifiP2pIface iface) -> {
948                                    statusOk.value = status.code == WifiStatusCode.SUCCESS;
949                                    if (statusOk.value) {
950                                        WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
951                                        ifaceInfo.name = ifaceName;
952                                        ifaceInfo.iface = iface;
953                                        p2pIfaces[ifaceIndex.value++] = ifaceInfo;
954                                    } else {
955                                        Log.e(TAG, "getP2pIface failed: " + statusString(status));
956                                    }
957                                });
958                        if (!statusOk.value) {
959                            return null;
960                        }
961                    }
962
963                    ifaceIndex.value = 0;
964                    chipResp.value.getNanIfaceNames(
965                            (WifiStatus status, ArrayList<String> ifnames) -> {
966                                statusOk.value = status.code == WifiStatusCode.SUCCESS;
967                                if (statusOk.value) {
968                                    ifaceNamesResp.value = ifnames;
969                                } else {
970                                    Log.e(TAG, "getNanIfaceNames failed: " + statusString(status));
971                                }
972                            });
973                    if (!statusOk.value) {
974                        return null;
975                    }
976
977                    WifiIfaceInfo[] nanIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()];
978                    for (String ifaceName: ifaceNamesResp.value) {
979                        chipResp.value.getNanIface(ifaceName,
980                                (WifiStatus status, IWifiNanIface iface) -> {
981                                    statusOk.value = status.code == WifiStatusCode.SUCCESS;
982                                    if (statusOk.value) {
983                                        WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
984                                        ifaceInfo.name = ifaceName;
985                                        ifaceInfo.iface = iface;
986                                        nanIfaces[ifaceIndex.value++] = ifaceInfo;
987                                    } else {
988                                        Log.e(TAG, "getNanIface failed: " + statusString(status));
989                                    }
990                                });
991                        if (!statusOk.value) {
992                            return null;
993                        }
994                    }
995
996                    WifiChipInfo chipInfo = new WifiChipInfo();
997                    chipsInfo[chipInfoIndex++] = chipInfo;
998
999                    chipInfo.chip = chipResp.value;
1000                    chipInfo.chipId = chipId;
1001                    chipInfo.availableModes = availableModesResp.value;
1002                    chipInfo.currentModeIdValid = currentModeValidResp.value;
1003                    chipInfo.currentModeId = currentModeResp.value;
1004                    chipInfo.ifaces[IfaceType.STA] = staIfaces;
1005                    chipInfo.ifaces[IfaceType.AP] = apIfaces;
1006                    chipInfo.ifaces[IfaceType.P2P] = p2pIfaces;
1007                    chipInfo.ifaces[IfaceType.NAN] = nanIfaces;
1008                }
1009
1010                return chipsInfo;
1011            } catch (RemoteException e) {
1012                Log.e(TAG, "getAllChipInfoAndValidateCache exception: " + e);
1013            }
1014        }
1015
1016        return null;
1017    }
1018
1019    /**
1020     * Checks the local state of this object (the cached state) against the input 'chipInfos'
1021     * state (which is a live representation of the Wi-Fi firmware status - read through the HAL).
1022     * Returns 'true' if there are no discrepancies - 'false' otherwise.
1023     *
1024     * A discrepancy is if any local state contains references to a chip or interface which are not
1025     * found on the information read from the chip.
1026     */
1027    private boolean validateInterfaceCache(WifiChipInfo[] chipInfos) {
1028        if (DBG) Log.d(TAG, "validateInterfaceCache");
1029
1030        synchronized (mLock) {
1031            for (Map.Entry<IWifiIface, InterfaceCacheEntry> entry: mInterfaceInfoCache.entrySet()) {
1032                // search for chip
1033                WifiChipInfo matchingChipInfo = null;
1034                for (WifiChipInfo ci: chipInfos) {
1035                    if (ci.chipId == entry.getValue().chipId) {
1036                        matchingChipInfo = ci;
1037                        break;
1038                    }
1039                }
1040                if (matchingChipInfo == null) {
1041                    Log.e(TAG, "validateInterfaceCache: no chip found for " + entry.getValue());
1042                    return false;
1043                }
1044
1045                // search for interface
1046                WifiIfaceInfo[] ifaceInfoList = matchingChipInfo.ifaces[entry.getValue().type];
1047                if (ifaceInfoList == null) {
1048                    Log.e(TAG, "validateInterfaceCache: invalid type on entry " + entry.getValue());
1049                    return false;
1050                }
1051
1052                boolean matchFound = false;
1053                for (WifiIfaceInfo ifaceInfo: ifaceInfoList) {
1054                    if (ifaceInfo.name.equals(entry.getValue().name)) {
1055                        matchFound = true;
1056                        break;
1057                    }
1058                }
1059                if (!matchFound) {
1060                    Log.e(TAG, "validateInterfaceCache: no interface found for "
1061                            + entry.getValue());
1062                    return false;
1063                }
1064            }
1065        }
1066
1067        return true;
1068    }
1069
1070    private boolean isWifiStarted() {
1071        if (DBG) Log.d(TAG, "isWifiStart");
1072
1073        synchronized (mLock) {
1074            try {
1075                if (mWifi == null) {
1076                    Log.w(TAG, "isWifiStarted called but mWifi is null!?");
1077                    return false;
1078                } else {
1079                    return mWifi.isStarted();
1080                }
1081            } catch (RemoteException e) {
1082                Log.e(TAG, "isWifiStarted exception: " + e);
1083                return false;
1084            }
1085        }
1086    }
1087
1088    private boolean startWifi() {
1089        if (DBG) Log.d(TAG, "startWifi");
1090
1091        synchronized (mLock) {
1092            try {
1093                if (mWifi == null) {
1094                    Log.w(TAG, "startWifi called but mWifi is null!?");
1095                    return false;
1096                } else {
1097                    int triedCount = 0;
1098                    while (triedCount <= START_HAL_RETRY_TIMES) {
1099                        WifiStatus status = mWifi.start();
1100                        if (status.code == WifiStatusCode.SUCCESS) {
1101                            initIWifiChipDebugListeners();
1102                            managerStatusListenerDispatch();
1103                            if (triedCount != 0) {
1104                                Log.d(TAG, "start IWifi succeeded after trying "
1105                                         + triedCount + " times");
1106                            }
1107                            return true;
1108                        } else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
1109                            // Should retry. Hal might still be stopping.
1110                            Log.e(TAG, "Cannot start IWifi: " + statusString(status)
1111                                    + ", Retrying...");
1112                            try {
1113                                Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
1114                            } catch (InterruptedException ignore) {
1115                                // no-op
1116                            }
1117                            triedCount++;
1118                        } else {
1119                            // Should not retry on other failures.
1120                            Log.e(TAG, "Cannot start IWifi: " + statusString(status));
1121                            return false;
1122                        }
1123                    }
1124                    Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
1125                    return false;
1126                }
1127            } catch (RemoteException e) {
1128                Log.e(TAG, "startWifi exception: " + e);
1129                return false;
1130            }
1131        }
1132    }
1133
1134    private void stopWifi() {
1135        if (DBG) Log.d(TAG, "stopWifi");
1136
1137        synchronized (mLock) {
1138            try {
1139                if (mWifi == null) {
1140                    Log.w(TAG, "stopWifi called but mWifi is null!?");
1141                } else {
1142                    WifiStatus status = mWifi.stop();
1143                    if (status.code != WifiStatusCode.SUCCESS) {
1144                        Log.e(TAG, "Cannot stop IWifi: " + statusString(status));
1145                    }
1146
1147                    // even on failure since WTF??
1148                    teardownInternal();
1149                }
1150            } catch (RemoteException e) {
1151                Log.e(TAG, "stopWifi exception: " + e);
1152            }
1153        }
1154    }
1155
1156    private class WifiEventCallback extends IWifiEventCallback.Stub {
1157        @Override
1158        public void onStart() throws RemoteException {
1159            if (DBG) Log.d(TAG, "IWifiEventCallback.onStart");
1160            // NOP: only happens in reaction to my calls - will handle directly
1161        }
1162
1163        @Override
1164        public void onStop() throws RemoteException {
1165            if (DBG) Log.d(TAG, "IWifiEventCallback.onStop");
1166            // NOP: only happens in reaction to my calls - will handle directly
1167        }
1168
1169        @Override
1170        public void onFailure(WifiStatus status) throws RemoteException {
1171            Log.e(TAG, "IWifiEventCallback.onFailure: " + statusString(status));
1172            teardownInternal();
1173
1174            // No need to do anything else: listeners may (will) re-start Wi-Fi
1175        }
1176    }
1177
1178    private void managerStatusListenerDispatch() {
1179        synchronized (mLock) {
1180            for (ManagerStatusListenerProxy cb : mManagerStatusListeners) {
1181                cb.trigger();
1182            }
1183        }
1184    }
1185
1186    private class ManagerStatusListenerProxy  extends
1187            ListenerProxy<ManagerStatusListener> {
1188        ManagerStatusListenerProxy(ManagerStatusListener statusListener,
1189                Looper looper) {
1190            super(statusListener, looper, "ManagerStatusListenerProxy");
1191        }
1192
1193        @Override
1194        protected void action() {
1195            mListener.onStatusChanged();
1196        }
1197    }
1198
1199    Set<Integer> getSupportedIfaceTypesInternal(IWifiChip chip) {
1200        Set<Integer> results = new HashSet<>();
1201
1202        WifiChipInfo[] chipInfos = getAllChipInfo();
1203        if (chipInfos == null) {
1204            Log.e(TAG, "getSupportedIfaceTypesInternal: no chip info found");
1205            return results;
1206        }
1207
1208        MutableInt chipIdIfProvided = new MutableInt(0); // NOT using 0 as a magic value
1209        if (chip != null) {
1210            MutableBoolean statusOk = new MutableBoolean(false);
1211            try {
1212                chip.getId((WifiStatus status, int id) -> {
1213                    if (status.code == WifiStatusCode.SUCCESS) {
1214                        chipIdIfProvided.value = id;
1215                        statusOk.value = true;
1216                    } else {
1217                        Log.e(TAG, "getSupportedIfaceTypesInternal: IWifiChip.getId() error: "
1218                                + statusString(status));
1219                        statusOk.value = false;
1220                    }
1221                });
1222            } catch (RemoteException e) {
1223                Log.e(TAG, "getSupportedIfaceTypesInternal IWifiChip.getId() exception: " + e);
1224                return results;
1225            }
1226            if (!statusOk.value) {
1227                return results;
1228            }
1229        }
1230
1231        for (WifiChipInfo wci: chipInfos) {
1232            if (chip != null && wci.chipId != chipIdIfProvided.value) {
1233                continue;
1234            }
1235
1236            for (IWifiChip.ChipMode cm: wci.availableModes) {
1237                for (IWifiChip.ChipIfaceCombination cic: cm.availableCombinations) {
1238                    for (IWifiChip.ChipIfaceCombinationLimit cicl: cic.limits) {
1239                        for (int type: cicl.types) {
1240                            results.add(type);
1241                        }
1242                    }
1243                }
1244            }
1245        }
1246
1247        return results;
1248    }
1249
1250    private IWifiIface createIface(int ifaceType, InterfaceDestroyedListener destroyedListener,
1251            Looper looper) {
1252        if (DBG) Log.d(TAG, "createIface: ifaceType=" + ifaceType);
1253
1254        synchronized (mLock) {
1255            WifiChipInfo[] chipInfos = getAllChipInfo();
1256            if (chipInfos == null) {
1257                Log.e(TAG, "createIface: no chip info found");
1258                stopWifi(); // major error: shutting down
1259                return null;
1260            }
1261
1262            if (!validateInterfaceCache(chipInfos)) {
1263                Log.e(TAG, "createIface: local cache is invalid!");
1264                stopWifi(); // major error: shutting down
1265                return null;
1266            }
1267
1268            IWifiIface iface = createIfaceIfPossible(chipInfos, ifaceType, destroyedListener,
1269                    looper);
1270            if (iface != null) { // means that some configuration has changed
1271                if (!dispatchAvailableForRequestListeners()) {
1272                    return null; // catastrophic failure - shut down
1273                }
1274            }
1275
1276            return iface;
1277        }
1278    }
1279
1280    private IWifiIface createIfaceIfPossible(WifiChipInfo[] chipInfos, int ifaceType,
1281            InterfaceDestroyedListener destroyedListener, Looper looper) {
1282        if (DBG) {
1283            Log.d(TAG, "createIfaceIfPossible: chipInfos=" + Arrays.deepToString(chipInfos)
1284                    + ", ifaceType=" + ifaceType);
1285        }
1286        synchronized (mLock) {
1287            IfaceCreationData bestIfaceCreationProposal = null;
1288            for (WifiChipInfo chipInfo: chipInfos) {
1289                for (IWifiChip.ChipMode chipMode: chipInfo.availableModes) {
1290                    for (IWifiChip.ChipIfaceCombination chipIfaceCombo : chipMode
1291                            .availableCombinations) {
1292                        int[][] expandedIfaceCombos = expandIfaceCombos(chipIfaceCombo);
1293                        if (DBG) {
1294                            Log.d(TAG, chipIfaceCombo + " expands to "
1295                                    + Arrays.deepToString(expandedIfaceCombos));
1296                        }
1297
1298                        for (int[] expandedIfaceCombo: expandedIfaceCombos) {
1299                            IfaceCreationData currentProposal = canIfaceComboSupportRequest(
1300                                    chipInfo, chipMode, expandedIfaceCombo, ifaceType);
1301                            if (compareIfaceCreationData(currentProposal,
1302                                    bestIfaceCreationProposal)) {
1303                                if (DBG) Log.d(TAG, "new proposal accepted");
1304                                bestIfaceCreationProposal = currentProposal;
1305                            }
1306                        }
1307                    }
1308                }
1309            }
1310
1311            if (bestIfaceCreationProposal != null) {
1312                IWifiIface iface = executeChipReconfiguration(bestIfaceCreationProposal, ifaceType);
1313                if (iface != null) {
1314                    InterfaceCacheEntry cacheEntry = new InterfaceCacheEntry();
1315
1316                    cacheEntry.chip = bestIfaceCreationProposal.chipInfo.chip;
1317                    cacheEntry.chipId = bestIfaceCreationProposal.chipInfo.chipId;
1318                    cacheEntry.name = getName(iface);
1319                    cacheEntry.type = ifaceType;
1320                    if (destroyedListener != null) {
1321                        cacheEntry.destroyedListeners.add(
1322                                new InterfaceDestroyedListenerProxy(destroyedListener,
1323                                        looper == null ? Looper.myLooper() : looper));
1324                    }
1325
1326                    mInterfaceInfoCache.put(iface, cacheEntry);
1327                    return iface;
1328                }
1329            }
1330        }
1331
1332        return null;
1333    }
1334
1335    // similar to createIfaceIfPossible - but simpler code: not looking for best option just
1336    // for any option (so terminates on first one).
1337    private boolean isItPossibleToCreateIface(WifiChipInfo[] chipInfos, int ifaceType) {
1338        if (DBG) {
1339            Log.d(TAG, "isItPossibleToCreateIface: chipInfos=" + Arrays.deepToString(chipInfos)
1340                    + ", ifaceType=" + ifaceType);
1341        }
1342
1343        for (WifiChipInfo chipInfo: chipInfos) {
1344            for (IWifiChip.ChipMode chipMode: chipInfo.availableModes) {
1345                for (IWifiChip.ChipIfaceCombination chipIfaceCombo : chipMode
1346                        .availableCombinations) {
1347                    int[][] expandedIfaceCombos = expandIfaceCombos(chipIfaceCombo);
1348                    if (DBG) {
1349                        Log.d(TAG, chipIfaceCombo + " expands to "
1350                                + Arrays.deepToString(expandedIfaceCombos));
1351                    }
1352
1353                    for (int[] expandedIfaceCombo: expandedIfaceCombos) {
1354                        if (canIfaceComboSupportRequest(chipInfo, chipMode, expandedIfaceCombo,
1355                                ifaceType) != null) {
1356                            return true;
1357                        }
1358                    }
1359                }
1360            }
1361        }
1362
1363        return false;
1364    }
1365
1366    /**
1367     * Expands (or provides an alternative representation) of the ChipIfaceCombination as all
1368     * possible combinations of interface.
1369     *
1370     * Returns [# of combinations][4 (IfaceType)]
1371     *
1372     * Note: there could be duplicates - allow (inefficient but ...).
1373     * TODO: optimize by using a Set as opposed to a []: will remove duplicates. Will need to
1374     * provide correct hashes.
1375     */
1376    private int[][] expandIfaceCombos(IWifiChip.ChipIfaceCombination chipIfaceCombo) {
1377        int numOfCombos = 1;
1378        for (IWifiChip.ChipIfaceCombinationLimit limit: chipIfaceCombo.limits) {
1379            for (int i = 0; i < limit.maxIfaces; ++i) {
1380                numOfCombos *= limit.types.size();
1381            }
1382        }
1383
1384        int[][] expandedIfaceCombos = new int[numOfCombos][IFACE_TYPES_BY_PRIORITY.length];
1385
1386        int span = numOfCombos; // span of an individual type (or sub-tree size)
1387        for (IWifiChip.ChipIfaceCombinationLimit limit: chipIfaceCombo.limits) {
1388            for (int i = 0; i < limit.maxIfaces; ++i) {
1389                span /= limit.types.size();
1390                for (int k = 0; k < numOfCombos; ++k) {
1391                    expandedIfaceCombos[k][limit.types.get((k / span) % limit.types.size())]++;
1392                }
1393            }
1394        }
1395
1396        return expandedIfaceCombos;
1397    }
1398
1399    private class IfaceCreationData {
1400        public WifiChipInfo chipInfo;
1401        public int chipModeId;
1402        public List<WifiIfaceInfo> interfacesToBeRemovedFirst;
1403
1404        @Override
1405        public String toString() {
1406            StringBuilder sb = new StringBuilder();
1407            sb.append("{chipInfo=").append(chipInfo).append(", chipModeId=").append(chipModeId)
1408                    .append(", interfacesToBeRemovedFirst=").append(interfacesToBeRemovedFirst)
1409                    .append(")");
1410            return sb.toString();
1411        }
1412    }
1413
1414    /**
1415     * Checks whether the input chip-iface-combo can support the requested interface type: if not
1416     * then returns null, if yes then returns information containing the list of interfaces which
1417     * would have to be removed first before the requested interface can be created.
1418     *
1419     * Note: the list of interfaces to be removed is EMPTY if a chip mode change is required - in
1420     * that case ALL the interfaces on the current chip have to be removed first.
1421     *
1422     * Response determined based on:
1423     * - Mode configuration: i.e. could the mode support the interface type in principle
1424     * - Priority information: i.e. are we 'allowed' to remove interfaces in order to create the
1425     *   requested interface
1426     */
1427    private IfaceCreationData canIfaceComboSupportRequest(WifiChipInfo chipInfo,
1428            IWifiChip.ChipMode chipMode, int[] chipIfaceCombo, int ifaceType) {
1429        if (DBG) {
1430            Log.d(TAG, "canIfaceComboSupportRequest: chipInfo=" + chipInfo + ", chipMode="
1431                    + chipMode + ", chipIfaceCombo=" + chipIfaceCombo + ", ifaceType=" + ifaceType);
1432        }
1433
1434        // short-circuit: does the chipIfaceCombo even support the requested type?
1435        if (chipIfaceCombo[ifaceType] == 0) {
1436            if (DBG) Log.d(TAG, "Requested type not supported by combo");
1437            return null;
1438        }
1439
1440        boolean isChipModeChangeProposed =
1441                chipInfo.currentModeIdValid && chipInfo.currentModeId != chipMode.id;
1442
1443        // short-circuit: can't change chip-mode if an existing interface on this chip has a higher
1444        // priority than the requested interface
1445        if (isChipModeChangeProposed) {
1446            for (int type: IFACE_TYPES_BY_PRIORITY) {
1447                if (chipInfo.ifaces[type].length != 0) {
1448                    if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
1449                        if (DBG) {
1450                            Log.d(TAG, "Couldn't delete existing type " + type
1451                                    + " interfaces for requested type");
1452                        }
1453                        return null;
1454                    }
1455                }
1456            }
1457
1458            // but if priority allows the mode change then we're good to go
1459            IfaceCreationData ifaceCreationData = new IfaceCreationData();
1460            ifaceCreationData.chipInfo = chipInfo;
1461            ifaceCreationData.chipModeId = chipMode.id;
1462
1463            return ifaceCreationData;
1464        }
1465
1466        // possibly supported
1467        List<WifiIfaceInfo> interfacesToBeRemovedFirst = new ArrayList<>();
1468
1469        for (int type: IFACE_TYPES_BY_PRIORITY) {
1470            int tooManyInterfaces = chipInfo.ifaces[type].length - chipIfaceCombo[type];
1471
1472            // need to count the requested interface as well
1473            if (type == ifaceType) {
1474                tooManyInterfaces += 1;
1475            }
1476
1477            if (tooManyInterfaces > 0) { // may need to delete some
1478                if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
1479                    if (DBG) {
1480                        Log.d(TAG, "Would need to delete some higher priority interfaces");
1481                    }
1482                    return null;
1483                }
1484
1485                // arbitrarily pick the first interfaces to delete
1486                for (int i = 0; i < tooManyInterfaces; ++i) {
1487                    interfacesToBeRemovedFirst.add(chipInfo.ifaces[type][i]);
1488                }
1489            }
1490        }
1491
1492        IfaceCreationData ifaceCreationData = new IfaceCreationData();
1493        ifaceCreationData.chipInfo = chipInfo;
1494        ifaceCreationData.chipModeId = chipMode.id;
1495        ifaceCreationData.interfacesToBeRemovedFirst = interfacesToBeRemovedFirst;
1496
1497        return ifaceCreationData;
1498    }
1499
1500    /**
1501     * Compares two options to create an interface and determines which is the 'best'. Returns
1502     * true if proposal 1 (val1) is better, other false.
1503     *
1504     * Note: both proposals are 'acceptable' bases on priority criteria.
1505     *
1506     * Criteria:
1507     * - Proposal is better if it means removing fewer high priority interfaces
1508     */
1509    private boolean compareIfaceCreationData(IfaceCreationData val1, IfaceCreationData val2) {
1510        if (DBG) Log.d(TAG, "compareIfaceCreationData: val1=" + val1 + ", val2=" + val2);
1511
1512        // deal with trivial case of one or the other being null
1513        if (val1 == null) {
1514            return false;
1515        } else if (val2 == null) {
1516            return true;
1517        }
1518
1519        for (int type: IFACE_TYPES_BY_PRIORITY) {
1520            // # of interfaces to be deleted: the list or all interfaces of the type if mode change
1521            int numIfacesToDelete1 = 0;
1522            if (val1.chipInfo.currentModeIdValid
1523                    && val1.chipInfo.currentModeId != val1.chipModeId) {
1524                numIfacesToDelete1 = val1.chipInfo.ifaces[type].length;
1525            } else {
1526                numIfacesToDelete1 = val1.interfacesToBeRemovedFirst.size();
1527            }
1528
1529            int numIfacesToDelete2 = 0;
1530            if (val2.chipInfo.currentModeIdValid
1531                    && val2.chipInfo.currentModeId != val2.chipModeId) {
1532                numIfacesToDelete2 = val2.chipInfo.ifaces[type].length;
1533            } else {
1534                numIfacesToDelete2 = val2.interfacesToBeRemovedFirst.size();
1535            }
1536
1537            if (numIfacesToDelete1 < numIfacesToDelete2) {
1538                if (DBG) {
1539                    Log.d(TAG, "decision based on type=" + type + ": " + numIfacesToDelete1
1540                            + " < " + numIfacesToDelete2);
1541                }
1542                return true;
1543            }
1544        }
1545
1546        // arbitrary - flip a coin
1547        if (DBG) Log.d(TAG, "proposals identical - flip a coin");
1548        return false;
1549    }
1550
1551    /**
1552     * Returns true if we're allowed to delete the existing interface type for the requested
1553     * interface type.
1554     *
1555     * Rules:
1556     * 1. Request for AP or STA will destroy any other interface (except see #4)
1557     * 2. Request for P2P will destroy NAN-only
1558     * 3. Request for NAN will not destroy any interface
1559     * --
1560     * 4. No interface will be destroyed for a requested interface of the same type
1561     */
1562    private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
1563            int requestedIfaceType) {
1564        // rule 4
1565        if (existingIfaceType == requestedIfaceType) {
1566            return false;
1567        }
1568
1569        // rule 3
1570        if (requestedIfaceType == IfaceType.NAN) {
1571            return false;
1572        }
1573
1574        // rule 2
1575        if (requestedIfaceType == IfaceType.P2P) {
1576            return existingIfaceType == IfaceType.NAN;
1577        }
1578
1579        // rule 1, the requestIfaceType is either AP or STA
1580        return true;
1581    }
1582
1583    /**
1584     * Performs chip reconfiguration per the input:
1585     * - Removes the specified interfaces
1586     * - Reconfigures the chip to the new chip mode (if necessary)
1587     * - Creates the new interface
1588     *
1589     * Returns the newly created interface or a null on any error.
1590     */
1591    private IWifiIface executeChipReconfiguration(IfaceCreationData ifaceCreationData,
1592            int ifaceType) {
1593        if (DBG) {
1594            Log.d(TAG, "executeChipReconfiguration: ifaceCreationData=" + ifaceCreationData
1595                    + ", ifaceType=" + ifaceType);
1596        }
1597        synchronized (mLock) {
1598            try {
1599                // is this a mode change?
1600                boolean isModeConfigNeeded = !ifaceCreationData.chipInfo.currentModeIdValid
1601                        || ifaceCreationData.chipInfo.currentModeId != ifaceCreationData.chipModeId;
1602                if (DBG) Log.d(TAG, "isModeConfigNeeded=" + isModeConfigNeeded);
1603
1604                // first delete interfaces/change modes
1605                if (isModeConfigNeeded) {
1606                    // remove all interfaces pre mode-change
1607                    // TODO: is this necessary? note that even if we don't want to explicitly
1608                    // remove the interfaces we do need to call the onDeleted callbacks - which
1609                    // this does
1610                    for (WifiIfaceInfo[] ifaceInfos: ifaceCreationData.chipInfo.ifaces) {
1611                        for (WifiIfaceInfo ifaceInfo: ifaceInfos) {
1612                            removeIfaceInternal(ifaceInfo.iface); // ignore return value
1613                        }
1614                    }
1615
1616                    WifiStatus status = ifaceCreationData.chipInfo.chip.configureChip(
1617                            ifaceCreationData.chipModeId);
1618                    if (status.code != WifiStatusCode.SUCCESS) {
1619                        Log.e(TAG, "executeChipReconfiguration: configureChip error: "
1620                                + statusString(status));
1621                        return null;
1622                    }
1623                } else {
1624                    // remove all interfaces on the delete list
1625                    for (WifiIfaceInfo ifaceInfo: ifaceCreationData.interfacesToBeRemovedFirst) {
1626                        removeIfaceInternal(ifaceInfo.iface); // ignore return value
1627                    }
1628                }
1629
1630                // create new interface
1631                Mutable<WifiStatus> statusResp = new Mutable<>();
1632                Mutable<IWifiIface> ifaceResp = new Mutable<>();
1633                switch (ifaceType) {
1634                    case IfaceType.STA:
1635                        ifaceCreationData.chipInfo.chip.createStaIface(
1636                                (WifiStatus status, IWifiStaIface iface) -> {
1637                                    statusResp.value = status;
1638                                    ifaceResp.value = iface;
1639                                });
1640                        break;
1641                    case IfaceType.AP:
1642                        ifaceCreationData.chipInfo.chip.createApIface(
1643                                (WifiStatus status, IWifiApIface iface) -> {
1644                                    statusResp.value = status;
1645                                    ifaceResp.value = iface;
1646                                });
1647                        break;
1648                    case IfaceType.P2P:
1649                        ifaceCreationData.chipInfo.chip.createP2pIface(
1650                                (WifiStatus status, IWifiP2pIface iface) -> {
1651                                    statusResp.value = status;
1652                                    ifaceResp.value = iface;
1653                                });
1654                        break;
1655                    case IfaceType.NAN:
1656                        ifaceCreationData.chipInfo.chip.createNanIface(
1657                                (WifiStatus status, IWifiNanIface iface) -> {
1658                                    statusResp.value = status;
1659                                    ifaceResp.value = iface;
1660                                });
1661                        break;
1662                }
1663
1664                if (statusResp.value.code != WifiStatusCode.SUCCESS) {
1665                    Log.e(TAG, "executeChipReconfiguration: failed to create interface ifaceType="
1666                            + ifaceType + ": " + statusString(statusResp.value));
1667                    return null;
1668                }
1669
1670                return ifaceResp.value;
1671            } catch (RemoteException e) {
1672                Log.e(TAG, "executeChipReconfiguration exception: " + e);
1673                return null;
1674            }
1675        }
1676    }
1677
1678    private boolean removeIfaceInternal(IWifiIface iface) {
1679        if (DBG) Log.d(TAG, "removeIfaceInternal: iface(name)=" + getName(iface));
1680
1681        synchronized (mLock) {
1682            if (mWifi == null) {
1683                Log.e(TAG, "removeIfaceInternal: null IWifi -- iface(name)=" + getName(iface));
1684                return false;
1685            }
1686
1687            IWifiChip chip = getChip(iface);
1688            if (chip == null) {
1689                Log.e(TAG, "removeIfaceInternal: null IWifiChip -- iface(name)=" + getName(iface));
1690                return false;
1691            }
1692
1693            String name = getName(iface);
1694            if (name == null) {
1695                Log.e(TAG, "removeIfaceInternal: can't get name");
1696                return false;
1697            }
1698
1699            int type = getType(iface);
1700            if (type == -1) {
1701                Log.e(TAG, "removeIfaceInternal: can't get type -- iface(name)=" + getName(iface));
1702                return false;
1703            }
1704
1705            WifiStatus status = null;
1706            try {
1707                switch (type) {
1708                    case IfaceType.STA:
1709                        status = chip.removeStaIface(name);
1710                        break;
1711                    case IfaceType.AP:
1712                        status = chip.removeApIface(name);
1713                        break;
1714                    case IfaceType.P2P:
1715                        status = chip.removeP2pIface(name);
1716                        break;
1717                    case IfaceType.NAN:
1718                        status = chip.removeNanIface(name);
1719                        break;
1720                    default:
1721                        Log.wtf(TAG, "removeIfaceInternal: invalid type=" + type);
1722                        return false;
1723                }
1724            } catch (RemoteException e) {
1725                Log.e(TAG, "IWifiChip.removeXxxIface exception: " + e);
1726            }
1727
1728            // dispatch listeners no matter what status
1729            dispatchDestroyedListeners(iface);
1730
1731            if (status != null && status.code == WifiStatusCode.SUCCESS) {
1732                return true;
1733            } else {
1734                Log.e(TAG, "IWifiChip.removeXxxIface failed: " + statusString(status));
1735                return false;
1736            }
1737        }
1738    }
1739
1740    // dispatch all available for request listeners of the specified type AND clean-out the list:
1741    // listeners are called once at most!
1742    private boolean dispatchAvailableForRequestListeners() {
1743        if (DBG) Log.d(TAG, "dispatchAvailableForRequestListeners");
1744
1745        synchronized (mLock) {
1746            WifiChipInfo[] chipInfos = getAllChipInfo();
1747            if (chipInfos == null) {
1748                Log.e(TAG, "dispatchAvailableForRequestListeners: no chip info found");
1749                stopWifi(); // major error: shutting down
1750                return false;
1751            }
1752            if (DBG) {
1753                Log.d(TAG, "dispatchAvailableForRequestListeners: chipInfos="
1754                        + Arrays.deepToString(chipInfos));
1755            }
1756
1757            for (int ifaceType : IFACE_TYPES_BY_PRIORITY) {
1758                dispatchAvailableForRequestListenersForType(ifaceType, chipInfos);
1759            }
1760        }
1761
1762        return true;
1763    }
1764
1765    private void dispatchAvailableForRequestListenersForType(int ifaceType,
1766            WifiChipInfo[] chipInfos) {
1767        if (DBG) Log.d(TAG, "dispatchAvailableForRequestListenersForType: ifaceType=" + ifaceType);
1768
1769        Set<InterfaceAvailableForRequestListenerProxy> listeners =
1770                mInterfaceAvailableForRequestListeners.get(ifaceType);
1771
1772        if (listeners.size() == 0) {
1773            return;
1774        }
1775
1776        if (!isItPossibleToCreateIface(chipInfos, ifaceType)) {
1777            if (DBG) Log.d(TAG, "Creating interface type isn't possible: ifaceType=" + ifaceType);
1778            return;
1779        }
1780
1781        if (DBG) Log.d(TAG, "It is possible to create the interface type: ifaceType=" + ifaceType);
1782        for (InterfaceAvailableForRequestListenerProxy listener : listeners) {
1783            listener.trigger();
1784        }
1785    }
1786
1787    // dispatch all destroyed listeners registered for the specified interface AND remove the
1788    // cache entry
1789    private void dispatchDestroyedListeners(IWifiIface iface) {
1790        if (DBG) Log.d(TAG, "dispatchDestroyedListeners: iface(name)=" + getName(iface));
1791
1792        synchronized (mLock) {
1793            InterfaceCacheEntry entry = mInterfaceInfoCache.get(iface);
1794            if (entry == null) {
1795                Log.e(TAG, "dispatchDestroyedListeners: no cache entry for iface(name)="
1796                        + getName(iface));
1797                return;
1798            }
1799
1800            for (InterfaceDestroyedListenerProxy listener : entry.destroyedListeners) {
1801                listener.trigger();
1802            }
1803            entry.destroyedListeners.clear(); // for insurance (though cache entry is removed)
1804            mInterfaceInfoCache.remove(iface);
1805        }
1806    }
1807
1808    // dispatch all destroyed listeners registered to all interfaces
1809    private void dispatchAllDestroyedListeners() {
1810        if (DBG) Log.d(TAG, "dispatchAllDestroyedListeners");
1811
1812        synchronized (mLock) {
1813            Iterator<Map.Entry<IWifiIface, InterfaceCacheEntry>> it =
1814                    mInterfaceInfoCache.entrySet().iterator();
1815            while (it.hasNext()) {
1816                InterfaceCacheEntry entry = it.next().getValue();
1817                for (InterfaceDestroyedListenerProxy listener : entry.destroyedListeners) {
1818                    listener.trigger();
1819                }
1820                entry.destroyedListeners.clear(); // for insurance (though cache entry is removed)
1821                it.remove();
1822            }
1823        }
1824    }
1825
1826    private abstract class ListenerProxy<LISTENER>  {
1827        private static final int LISTENER_TRIGGERED = 0;
1828
1829        protected LISTENER mListener;
1830        private Handler mHandler;
1831
1832        // override equals & hash to make sure that the container HashSet is unique with respect to
1833        // the contained listener
1834        @Override
1835        public boolean equals(Object obj) {
1836            return mListener == ((ListenerProxy<LISTENER>) obj).mListener;
1837        }
1838
1839        @Override
1840        public int hashCode() {
1841            return mListener.hashCode();
1842        }
1843
1844        void trigger() {
1845            mHandler.sendMessage(mHandler.obtainMessage(LISTENER_TRIGGERED));
1846        }
1847
1848        protected abstract void action();
1849
1850        ListenerProxy(LISTENER listener, Looper looper, String tag) {
1851            mListener = listener;
1852            mHandler = new Handler(looper) {
1853                @Override
1854                public void handleMessage(Message msg) {
1855                    if (DBG) {
1856                        Log.d(tag, "ListenerProxy.handleMessage: what=" + msg.what);
1857                    }
1858                    switch (msg.what) {
1859                        case LISTENER_TRIGGERED:
1860                            action();
1861                            break;
1862                        default:
1863                            Log.e(tag, "ListenerProxy.handleMessage: unknown message what="
1864                                    + msg.what);
1865                    }
1866                }
1867            };
1868        }
1869    }
1870
1871    private class InterfaceDestroyedListenerProxy extends
1872            ListenerProxy<InterfaceDestroyedListener> {
1873        InterfaceDestroyedListenerProxy(InterfaceDestroyedListener destroyedListener,
1874                Looper looper) {
1875            super(destroyedListener, looper, "InterfaceDestroyedListenerProxy");
1876        }
1877
1878        @Override
1879        protected void action() {
1880            mListener.onDestroyed();
1881        }
1882    }
1883
1884    private class InterfaceAvailableForRequestListenerProxy extends
1885            ListenerProxy<InterfaceAvailableForRequestListener> {
1886        InterfaceAvailableForRequestListenerProxy(
1887                InterfaceAvailableForRequestListener destroyedListener, Looper looper) {
1888            super(destroyedListener, looper, "InterfaceAvailableForRequestListenerProxy");
1889        }
1890
1891        @Override
1892        protected void action() {
1893            mListener.onAvailableForRequest();
1894        }
1895    }
1896
1897    // general utilities
1898
1899    private static String statusString(WifiStatus status) {
1900        if (status == null) {
1901            return "status=null";
1902        }
1903        StringBuilder sb = new StringBuilder();
1904        sb.append(status.code).append(" (").append(status.description).append(")");
1905        return sb.toString();
1906    }
1907
1908    // Will return -1 for invalid results! Otherwise will return one of the 4 valid values.
1909    private static int getType(IWifiIface iface) {
1910        MutableInt typeResp = new MutableInt(-1);
1911        try {
1912            iface.getType((WifiStatus status, int type) -> {
1913                if (status.code == WifiStatusCode.SUCCESS) {
1914                    typeResp.value = type;
1915                } else {
1916                    Log.e(TAG, "Error on getType: " + statusString(status));
1917                }
1918            });
1919        } catch (RemoteException e) {
1920            Log.e(TAG, "Exception on getType: " + e);
1921        }
1922
1923        return typeResp.value;
1924    }
1925
1926    private static class Mutable<E> {
1927        public E value;
1928
1929        Mutable() {
1930            value = null;
1931        }
1932
1933        Mutable(E value) {
1934            this.value = value;
1935        }
1936    }
1937
1938    /**
1939     * Dump the internal state of the class.
1940     */
1941    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1942        pw.println("HalDeviceManager:");
1943        pw.println("  mServiceManager: " + mServiceManager);
1944        pw.println("  mWifi: " + mWifi);
1945        pw.println("  mManagerStatusListeners: " + mManagerStatusListeners);
1946        pw.println("  mInterfaceAvailableForRequestListeners: "
1947                + mInterfaceAvailableForRequestListeners);
1948        pw.println("  mInterfaceInfoCache: " + mInterfaceInfoCache);
1949    }
1950}
1951