Home | History | Annotate | Download | only in wifi
      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
     74     public HalDeviceManager() {
     75         mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashSet<>());
     76         mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashSet<>());
     77         mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashSet<>());
     78         mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashSet<>());
     79     }
     80 
     81     /**
     82      * Actually starts the HalDeviceManager: separate from constructor since may want to phase
     83      * at a later time.
     84      *
     85      * TODO: if decide that no need for separating construction from initialization (e.g. both are
     86      * done at injector) then move to constructor.
     87      */
     88     public void initialize() {
     89         initializeInternal();
     90     }
     91 
     92     /**
     93      * Register a ManagerStatusListener to get information about the status of the manager. Use the
     94      * isReady() and isStarted() methods to check status immediately after registration and when
     95      * triggered.
     96      *
     97      * It is safe to re-register the same callback object - duplicates are detected and only a
     98      * single copy kept.
     99      *
    100      * @param listener ManagerStatusListener listener object.
    101      * @param looper Looper on which to dispatch listener. Null implies current looper.
    102      */
    103     public void registerStatusListener(ManagerStatusListener listener, Looper looper) {
    104         synchronized (mLock) {
    105             if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener,
    106                     looper == null ? Looper.myLooper() : looper))) {
    107                 Log.w(TAG, "registerStatusListener: duplicate registration ignored");
    108             }
    109         }
    110     }
    111 
    112     /**
    113      * Returns whether the vendor HAL is supported on this device or not.
    114      */
    115     public boolean isSupported() {
    116         return isSupportedInternal();
    117     }
    118 
    119     /**
    120      * Returns the current status of the HalDeviceManager: whether or not it is ready to execute
    121      * commands. A return of 'false' indicates that the HAL service (IWifi) is not available. Use
    122      * the registerStatusListener() to listener for status changes.
    123      */
    124     public boolean isReady() {
    125         return mWifi != null;
    126     }
    127 
    128     /**
    129      * Returns the current status of Wi-Fi: started (true) or stopped (false).
    130      *
    131      * Note: direct call to HIDL.
    132      */
    133     public boolean isStarted() {
    134         return isWifiStarted();
    135     }
    136 
    137     /**
    138      * Attempts to start Wi-Fi (using HIDL). Returns the success (true) or failure (false) or
    139      * the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
    140      * success.
    141      *
    142      * Note: direct call to HIDL.
    143      */
    144     public boolean start() {
    145         return startWifi();
    146     }
    147 
    148     /**
    149      * Stops Wi-Fi. Will also dispatch any registeredManagerStatusCallback.onStop().
    150      *
    151      * Note: direct call to HIDL - failure is not-expected.
    152      */
    153     public void stop() {
    154         stopWifi();
    155     }
    156 
    157     /**
    158      * HAL device manager status change listener.
    159      */
    160     public interface ManagerStatusListener {
    161         /**
    162          * Indicates that the status of the HalDeviceManager has changed. Use isReady() and
    163          * isStarted() to obtain status information.
    164          */
    165         void onStatusChanged();
    166     }
    167 
    168     /**
    169      * Return the set of supported interface types across all Wi-Fi chips on the device.
    170      *
    171      * @return A set of IfaceTypes constants (possibly empty, e.g. on error).
    172      */
    173     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      */
    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      */
    199     public IWifiStaIface createStaIface(InterfaceDestroyedListener destroyedListener,
    200             Looper looper) {
    201         return (IWifiStaIface) createIface(IfaceType.STA, destroyedListener, looper);
    202     }
    203 
    204     /**
    205      * Create AP interface if possible (see createStaIface doc).
    206      */
    207     public IWifiApIface createApIface(InterfaceDestroyedListener destroyedListener,
    208             Looper looper) {
    209         return (IWifiApIface) createIface(IfaceType.AP, destroyedListener, looper);
    210     }
    211 
    212     /**
    213      * Create P2P interface if possible (see createStaIface doc).
    214      */
    215     public IWifiP2pIface createP2pIface(InterfaceDestroyedListener destroyedListener,
    216             Looper looper) {
    217         return (IWifiP2pIface) createIface(IfaceType.P2P, destroyedListener, looper);
    218     }
    219 
    220     /**
    221      * Create NAN interface if possible (see createStaIface doc).
    222      */
    223     public IWifiNanIface createNanIface(InterfaceDestroyedListener destroyedListener,
    224             Looper looper) {
    225         return (IWifiNanIface) createIface(IfaceType.NAN, destroyedListener, looper);
    226     }
    227 
    228     /**
    229      * Removes (releases/destroys) the given interface. Will trigger any registered
    230      * InterfaceDestroyedListeners and possibly some InterfaceAvailableForRequestListeners if we
    231      * can potentially create some other interfaces as a result of removing this interface.
    232      */
    233     public boolean removeIface(IWifiIface iface) {
    234         boolean success = removeIfaceInternal(iface);
    235         dispatchAvailableForRequestListeners();
    236         return success;
    237     }
    238 
    239     /**
    240      * Returns the IWifiChip corresponding to the specified interface (or null on error).
    241      *
    242      * Note: clients must not perform chip mode changes or interface management (create/delete)
    243      * operations on IWifiChip directly. However, they can use the IWifiChip interface to perform
    244      * other functions - e.g. calling the debug/trace methods.
    245      */
    246     public IWifiChip getChip(IWifiIface iface) {
    247         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      */
    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      */
    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      */
    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      */
    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          */
    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          */
    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      */
    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
    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
    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      */
    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 
    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 
    533     private void initializeInternal() {
    534         initIServiceManagerIfNecessary();
    535         if (isSupportedInternal()) {
    536             initIWifiIfNecessary();
    537         }
    538     }
    539 
    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      */
    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      */
    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     */
    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      */
    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      */
    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      */
   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 
   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 
   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 
   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
   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
   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
   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 
   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> {
   1205         ManagerStatusListenerProxy(ManagerStatusListener statusListener,
   1206                 Looper looper) {
   1207             super(statusListener, looper, "ManagerStatusListenerProxy");
   1208         }
   1209 
   1210         @Override
   1211         protected void action() {
   1212             mListener.onStatusChanged();
   1213         }
   1214     }
   1215 
   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 
   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 
   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).
   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      */
   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
   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      */
   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      */
   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      */
   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      */
   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 
   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!
   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 
   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
   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
   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
   1852         public boolean equals(Object obj) {
   1853             return mListener == ((ListenerProxy<LISTENER>) obj).mListener;
   1854         }
   1855 
   1856         @Override
   1857         public int hashCode() {
   1858             return mListener.hashCode();
   1859         }
   1860 
   1861         void trigger() {
   1862             mHandler.sendMessage(mHandler.obtainMessage(LISTENER_TRIGGERED));
   1863         }
   1864 
   1865         protected abstract void action();
   1866 
   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> {
   1890         InterfaceDestroyedListenerProxy(InterfaceDestroyedListener destroyedListener,
   1891                 Looper looper) {
   1892             super(destroyedListener, looper, "InterfaceDestroyedListenerProxy");
   1893         }
   1894 
   1895         @Override
   1896         protected void action() {
   1897             mListener.onDestroyed();
   1898         }
   1899     }
   1900 
   1901     private class InterfaceAvailableForRequestListenerProxy extends
   1902             ListenerProxy<InterfaceAvailableForRequestListener> {
   1903         InterfaceAvailableForRequestListenerProxy(
   1904                 InterfaceAvailableForRequestListener destroyedListener, Looper looper) {
   1905             super(destroyedListener, looper, "InterfaceAvailableForRequestListenerProxy");
   1906         }
   1907 
   1908         @Override
   1909         protected void action() {
   1910             mListener.onAvailableForRequest();
   1911         }
   1912     }
   1913 
   1914     // general utilities
   1915 
   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.
   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 
   1946         Mutable() {
   1947             value = null;
   1948         }
   1949 
   1950         Mutable(E value) {
   1951             this.value = value;
   1952         }
   1953     }
   1954 
   1955     /**
   1956      * Dump the internal state of the class.
   1957      */
   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