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