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