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