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