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