• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static com.android.server.wifi.HalDeviceManagerUtil.jsonToStaticChipInfo;
20 import static com.android.server.wifi.HalDeviceManagerUtil.staticChipInfoToJson;
21 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STATIC_CHIP_INFO;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.res.Resources;
31 import android.net.NetworkInfo;
32 import android.net.wifi.WifiContext;
33 import android.net.wifi.WifiScanner;
34 import android.net.wifi.p2p.WifiP2pManager;
35 import android.os.Handler;
36 import android.os.WorkSource;
37 import android.text.TextUtils;
38 import android.util.ArrayMap;
39 import android.util.ArraySet;
40 import android.util.Log;
41 import android.util.Pair;
42 import android.util.SparseArray;
43 import android.util.SparseIntArray;
44 
45 import com.android.internal.annotations.VisibleForTesting;
46 import com.android.modules.utils.build.SdkLevel;
47 import com.android.server.wifi.HalDeviceManagerUtil.StaticChipInfo;
48 import com.android.server.wifi.hal.WifiApIface;
49 import com.android.server.wifi.hal.WifiChip;
50 import com.android.server.wifi.hal.WifiHal;
51 import com.android.server.wifi.hal.WifiNanIface;
52 import com.android.server.wifi.hal.WifiP2pIface;
53 import com.android.server.wifi.hal.WifiRttController;
54 import com.android.server.wifi.hal.WifiStaIface;
55 import com.android.server.wifi.util.WorkSourceHelper;
56 import com.android.wifi.resources.R;
57 
58 import org.json.JSONArray;
59 import org.json.JSONException;
60 
61 import java.io.FileDescriptor;
62 import java.io.PrintWriter;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.Collections;
66 import java.util.HashMap;
67 import java.util.HashSet;
68 import java.util.Iterator;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.Set;
72 import java.util.stream.Collectors;
73 
74 /**
75  * Handles device management through the HAL interface.
76  */
77 public class HalDeviceManager {
78     private static final String TAG = "HalDevMgr";
79     private static final boolean VDBG = false;
80     private boolean mDbg = false;
81 
82     public static final long CHIP_CAPABILITY_ANY = 0L;
83     private static final long CHIP_CAPABILITY_UNINITIALIZED = -1L;
84 
85     private static final int DBS_24G_5G_MASK =
86             WifiScanner.WIFI_BAND_24_GHZ | WifiScanner.WIFI_BAND_5_GHZ;
87     private static final int DBS_5G_6G_MASK =
88             WifiScanner.WIFI_BAND_5_GHZ | WifiScanner.WIFI_BAND_6_GHZ;
89 
90     private static final int START_HAL_RETRY_INTERVAL_MS = 20;
91     // Number of attempts a start() is re-tried. A value of 0 means no retries after a single
92     // attempt.
93     @VisibleForTesting
94     public static final int START_HAL_RETRY_TIMES = 3;
95 
96     private final WifiContext mContext;
97     private final Clock mClock;
98     private final WifiInjector mWifiInjector;
99     private final Handler mEventHandler;
100     private WifiHal mWifiHal;
101     private WifiDeathRecipient mIWifiDeathRecipient;
102     private boolean mIsConcurrencyComboLoadedFromDriver;
103     private boolean mWaitForDestroyedListeners;
104     // Map of Interface name to their associated ConcreteClientModeManager
105     private final Map<String, ConcreteClientModeManager> mClientModeManagers = new ArrayMap<>();
106     // Map of Interface name to their associated SoftApManager
107     private final Map<String, SoftApManager> mSoftApManagers = new ArrayMap<>();
108     private boolean mIsP2pConnected = false;
109 
110     /**
111      * Public API for querying interfaces from the HalDeviceManager.
112      *
113      * TODO (b/256648410): Consider replacing these values with WifiChip.IFACE_TYPE_
114      *                     to avoid duplication.
115      */
116     public static final int HDM_CREATE_IFACE_STA = 0;
117     public static final int HDM_CREATE_IFACE_AP = 1;
118     public static final int HDM_CREATE_IFACE_AP_BRIDGE = 2;
119     public static final int HDM_CREATE_IFACE_P2P = 3;
120     public static final int HDM_CREATE_IFACE_NAN = 4;
121 
122     @IntDef(flag = false, prefix = { "HDM_CREATE_IFACE_TYPE_" }, value = {
123             HDM_CREATE_IFACE_STA,
124             HDM_CREATE_IFACE_AP,
125             HDM_CREATE_IFACE_AP_BRIDGE,
126             HDM_CREATE_IFACE_P2P,
127             HDM_CREATE_IFACE_NAN,
128     })
129     public @interface HdmIfaceTypeForCreation {};
130 
131     public static final SparseIntArray HAL_IFACE_MAP = new SparseIntArray() {{
132             put(HDM_CREATE_IFACE_STA, WifiChip.IFACE_TYPE_STA);
133             put(HDM_CREATE_IFACE_AP, WifiChip.IFACE_TYPE_AP);
134             put(HDM_CREATE_IFACE_AP_BRIDGE, WifiChip.IFACE_TYPE_AP);
135             put(HDM_CREATE_IFACE_P2P, WifiChip.IFACE_TYPE_P2P);
136             put(HDM_CREATE_IFACE_NAN, WifiChip.IFACE_TYPE_NAN);
137         }};
138 
139     public static final SparseIntArray CONCURRENCY_TYPE_TO_CREATE_TYPE_MAP = new SparseIntArray() {{
140             put(WifiChip.IFACE_CONCURRENCY_TYPE_STA, HDM_CREATE_IFACE_STA);
141             put(WifiChip.IFACE_CONCURRENCY_TYPE_AP, HDM_CREATE_IFACE_AP);
142             put(WifiChip.IFACE_CONCURRENCY_TYPE_AP_BRIDGED, HDM_CREATE_IFACE_AP_BRIDGE);
143             put(WifiChip.IFACE_CONCURRENCY_TYPE_P2P, HDM_CREATE_IFACE_P2P);
144             put(WifiChip.IFACE_CONCURRENCY_TYPE_NAN, HDM_CREATE_IFACE_NAN);
145         }};
146 
147 
148     // public API
HalDeviceManager(WifiContext context, Clock clock, WifiInjector wifiInjector, Handler handler)149     public HalDeviceManager(WifiContext context, Clock clock, WifiInjector wifiInjector,
150             Handler handler) {
151         mContext = context;
152         mClock = clock;
153         mWifiInjector = wifiInjector;
154         mEventHandler = handler;
155         mIWifiDeathRecipient = new WifiDeathRecipient();
156         mWifiHal = getWifiHalMockable(context, wifiInjector);
157         // Monitor P2P connection to treat disconnected P2P as low priority.
158         IntentFilter intentFilter = new IntentFilter();
159         intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
160         mContext.registerReceiver(new BroadcastReceiver() {
161             @Override
162             public void onReceive(Context context, Intent intent) {
163                 if (!intent.getAction().equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
164                     return;
165                 }
166                 NetworkInfo networkInfo =
167                         intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
168                 mIsP2pConnected = networkInfo != null
169                         && networkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED;
170             }
171         }, intentFilter, null, mEventHandler);
172     }
173 
174     @VisibleForTesting
getWifiHalMockable(WifiContext context, WifiInjector wifiInjector)175     protected WifiHal getWifiHalMockable(WifiContext context, WifiInjector wifiInjector) {
176         return new WifiHal(context, wifiInjector.getSsidTranslator());
177     }
178 
179     /**
180      * Enables verbose logging.
181      */
enableVerboseLogging(boolean verboseEnabled)182     public void enableVerboseLogging(boolean verboseEnabled) {
183         mDbg = verboseEnabled;
184 
185         if (VDBG) {
186             mDbg = true; // just override
187         }
188     }
189 
190     /**
191      * Actually starts the HalDeviceManager: separate from constructor since may want to phase
192      * at a later time.
193      *
194      * TODO: if decide that no need for separating construction from initialization (e.g. both are
195      * done at injector) then move to constructor.
196      */
initialize()197     public void initialize() {
198         initializeInternal();
199         registerWifiHalEventCallback();
200     }
201 
202     /**
203      * Register a ManagerStatusListener to get information about the status of the manager. Use the
204      * isReady() and isStarted() methods to check status immediately after registration and when
205      * triggered.
206      *
207      * It is safe to re-register the same callback object - duplicates are detected and only a
208      * single copy kept.
209      *
210      * @param listener ManagerStatusListener listener object.
211      * @param handler Handler on which to dispatch listener. Null implies the listener will be
212      *                invoked synchronously from the context of the client which triggered the
213      *                state change.
214      */
registerStatusListener(@onNull ManagerStatusListener listener, @Nullable Handler handler)215     public void registerStatusListener(@NonNull ManagerStatusListener listener,
216             @Nullable Handler handler) {
217         synchronized (mLock) {
218             if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener, handler))) {
219                 Log.w(TAG, "registerStatusListener: duplicate registration ignored");
220             }
221         }
222     }
223 
224     /**
225      * Returns whether the vendor HAL is supported on this device or not.
226      */
isSupported()227     public boolean isSupported() {
228         return mWifiHal.isSupported();
229     }
230 
231     /**
232      * Returns the current status of the HalDeviceManager: whether or not it is ready to execute
233      * commands. A return of 'false' indicates that the HAL service (IWifi) is not available. Use
234      * the registerStatusListener() to listener for status changes.
235      */
isReady()236     public boolean isReady() {
237         return mWifiHal.isInitializationComplete();
238     }
239 
240     /**
241      * Returns the current status of Wi-Fi: started (true) or stopped (false).
242      */
isStarted()243     public boolean isStarted() {
244         return isWifiStarted();
245     }
246 
247     /**
248      * Attempts to start Wi-Fi. Returns the success (true) or failure (false) or
249      * the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
250      * success.
251      */
start()252     public boolean start() {
253         return startWifi();
254     }
255 
256     /**
257      * Stops Wi-Fi. Will also dispatch any registeredManagerStatusCallback.onStop().
258      */
stop()259     public void stop() {
260         stopWifi();
261         mWifiHal.invalidate();
262     }
263 
264     /**
265      * HAL device manager status change listener.
266      */
267     public interface ManagerStatusListener {
268         /**
269          * Indicates that the status of the HalDeviceManager has changed. Use isReady() and
270          * isStarted() to obtain status information.
271          */
onStatusChanged()272         void onStatusChanged();
273     }
274 
275     /**
276      * Return the set of supported interface types across all Wi-Fi chips on the device.
277      *
278      * @return A set of IfaceTypes constants (possibly empty, e.g. on error).
279      */
getSupportedIfaceTypes()280     public Set<Integer> getSupportedIfaceTypes() {
281         return getSupportedIfaceTypesInternal(null);
282     }
283 
284     /**
285      * Return the set of supported interface types for the specified Wi-Fi chip.
286      *
287      * @return A set of IfaceTypes constants  (possibly empty, e.g. on error).
288      */
getSupportedIfaceTypes(WifiChip chip)289     public Set<Integer> getSupportedIfaceTypes(WifiChip chip) {
290         return getSupportedIfaceTypesInternal(chip);
291     }
292 
293     // interface-specific behavior
294 
295     /**
296      * Create a STA interface if possible. Changes chip mode and removes conflicting interfaces if
297      * needed and permitted by priority.
298      *
299      * @param requiredChipCapabilities The bitmask of Capabilities which are required.
300      *                                 See IWifiChip.hal for documentation.
301      * @param destroyedListener Optional (nullable) listener to call when the allocated interface
302      *                          is removed. Will only be registered and used if an interface is
303      *                          created successfully.
304      * @param handler Handler on which to dispatch listener. Must be non Null if destroyedListener
305      *                is set. If the this handler is running on the same thread as the client which
306      *                triggered the iface destruction, the listener will be invoked synchronously
307      *                from that context of the client.
308      * @param requestorWs Requestor worksource. This will be used to determine priority of this
309      *                    interface using rules based on the requestor app's context.
310      * @param concreteClientModeManager ConcreteClientModeManager requesting the interface.
311      * @return A newly created interface - or null if the interface could not be created.
312      */
createStaIface( long requiredChipCapabilities, @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler, @NonNull WorkSource requestorWs, @NonNull ConcreteClientModeManager concreteClientModeManager)313     public WifiStaIface createStaIface(
314             long requiredChipCapabilities,
315             @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler,
316             @NonNull WorkSource requestorWs,
317             @NonNull ConcreteClientModeManager concreteClientModeManager) {
318         if (concreteClientModeManager == null) {
319             Log.wtf(TAG, "Cannot create STA Iface with null ConcreteClientModeManager");
320             return null;
321         }
322         WifiStaIface staIface = (WifiStaIface) createIface(HDM_CREATE_IFACE_STA,
323                 requiredChipCapabilities, destroyedListener, handler, requestorWs);
324         if (staIface != null) {
325             mClientModeManagers.put(getName(staIface), concreteClientModeManager);
326         }
327         return staIface;
328     }
329 
330     /**
331      * Create a STA interface if possible. Changes chip mode and removes conflicting interfaces if
332      * needed and permitted by priority.
333      *
334      * @param destroyedListener Optional (nullable) listener to call when the allocated interface
335      *                          is removed. Will only be registered and used if an interface is
336      *                          created successfully.
337      * @param handler Handler on which to dispatch listener. Must be non Null if destroyedListener
338      *                is set. If the handler is running on the same thread as the client which
339      *                triggered the iface destruction, the listener will be invoked synchronously
340      *                from that context of the client.
341      * @param requestorWs Requestor worksource. This will be used to determine priority of this
342      *                    interface using rules based on the requestor app's context.
343      * @param concreteClientModeManager ConcreteClientModeManager requesting the interface.
344      * @return A newly created interface - or null if the interface could not be created.
345      */
createStaIface( @ullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler, @NonNull WorkSource requestorWs, @NonNull ConcreteClientModeManager concreteClientModeManager)346     public WifiStaIface createStaIface(
347             @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler,
348             @NonNull WorkSource requestorWs,
349             @NonNull ConcreteClientModeManager concreteClientModeManager) {
350         return createStaIface(CHIP_CAPABILITY_ANY, destroyedListener, handler, requestorWs,
351                 concreteClientModeManager);
352     }
353 
354     /**
355      * Create AP interface if possible (see createStaIface doc).
356      */
createApIface( long requiredChipCapabilities, @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler, @NonNull WorkSource requestorWs, boolean isBridged, @NonNull SoftApManager softApManager)357     public WifiApIface createApIface(
358             long requiredChipCapabilities,
359             @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler,
360             @NonNull WorkSource requestorWs, boolean isBridged,
361             @NonNull SoftApManager softApManager) {
362         if (softApManager == null) {
363             Log.e(TAG, "Cannot create AP Iface with null SoftApManager");
364             return null;
365         }
366         WifiApIface apIface = (WifiApIface) createIface(isBridged ? HDM_CREATE_IFACE_AP_BRIDGE
367                 : HDM_CREATE_IFACE_AP, requiredChipCapabilities, destroyedListener,
368                 handler, requestorWs);
369         if (apIface != null) {
370             mSoftApManagers.put(getName(apIface), softApManager);
371         }
372         return apIface;
373     }
374 
375     /**
376      * Create P2P interface if possible (see createStaIface doc).
377      */
createP2pIface( long requiredChipCapabilities, @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler, @NonNull WorkSource requestorWs)378     public String createP2pIface(
379             long requiredChipCapabilities,
380             @Nullable InterfaceDestroyedListener destroyedListener,
381             @Nullable Handler handler, @NonNull WorkSource requestorWs) {
382         WifiP2pIface iface = (WifiP2pIface) createIface(HDM_CREATE_IFACE_P2P,
383                 requiredChipCapabilities, destroyedListener, handler, requestorWs);
384         if (iface == null) {
385             return null;
386         }
387         String ifaceName = getName(iface);
388         if (TextUtils.isEmpty(ifaceName)) {
389             removeIface(iface);
390             return null;
391         }
392         mWifiP2pIfaces.put(ifaceName, iface);
393         return ifaceName;
394     }
395 
396     /**
397      * Create P2P interface if possible (see createStaIface doc).
398      */
createP2pIface(@ullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler, @NonNull WorkSource requestorWs)399     public String createP2pIface(@Nullable InterfaceDestroyedListener destroyedListener,
400             @Nullable Handler handler, @NonNull WorkSource requestorWs) {
401         return createP2pIface(CHIP_CAPABILITY_ANY, destroyedListener, handler, requestorWs);
402     }
403 
404     /**
405      * Create NAN interface if possible (see createStaIface doc).
406      */
createNanIface(@ullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler, @NonNull WorkSource requestorWs)407     public WifiNanIface createNanIface(@Nullable InterfaceDestroyedListener destroyedListener,
408             @Nullable Handler handler, @NonNull WorkSource requestorWs) {
409         return (WifiNanIface) createIface(HDM_CREATE_IFACE_NAN, CHIP_CAPABILITY_ANY,
410                 destroyedListener, handler, requestorWs);
411     }
412 
413     /**
414      * Removes (releases/destroys) the given interface. Will trigger any registered
415      * InterfaceDestroyedListeners.
416      */
removeIface(WifiHal.WifiInterface iface)417     public boolean removeIface(WifiHal.WifiInterface iface) {
418         boolean success = removeIfaceInternal(iface, /* validateRttController */true);
419         return success;
420     }
421 
422     /**
423      * Wrapper around {@link #removeIface(WifiHal.WifiInterface)} for P2P ifaces.
424      */
removeP2pIface(String ifaceName)425     public boolean removeP2pIface(String ifaceName) {
426         WifiP2pIface iface = mWifiP2pIfaces.get(ifaceName);
427         if (iface == null) return false;
428         if (!removeIface(iface)) {
429             Log.e(TAG, "Unable to remove p2p iface " + ifaceName);
430             return false;
431         }
432         mWifiP2pIfaces.remove(ifaceName);
433         return true;
434     }
435 
getInterfaceCacheEntry(WifiHal.WifiInterface iface)436     private InterfaceCacheEntry getInterfaceCacheEntry(WifiHal.WifiInterface iface) {
437         String name = getName(iface);
438         int type = getType(iface);
439         if (VDBG) Log.d(TAG, "getInterfaceCacheEntry: iface(name)=" + name);
440 
441         synchronized (mLock) {
442             InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(Pair.create(name, type));
443             if (cacheEntry == null) {
444                 Log.e(TAG, "getInterfaceCacheEntry: no entry for iface(name)=" + name);
445                 return null;
446             }
447 
448             return cacheEntry;
449         }
450     }
451 
452     /**
453      * Returns the WifiChip corresponding to the specified interface (or null on error).
454      *
455      * Note: clients must not perform chip mode changes or interface management (create/delete)
456      * operations on WifiChip directly. However, they can use the WifiChip interface to perform
457      * other functions - e.g. calling the debug/trace methods.
458      */
getChip(WifiHal.WifiInterface iface)459     public WifiChip getChip(WifiHal.WifiInterface iface) {
460         synchronized (mLock) {
461             InterfaceCacheEntry cacheEntry = getInterfaceCacheEntry(iface);
462             return (cacheEntry == null) ? null : cacheEntry.chip;
463         }
464     }
465 
getChipInfo(WifiHal.WifiInterface iface)466     private WifiChipInfo getChipInfo(WifiHal.WifiInterface iface) {
467         synchronized (mLock) {
468             InterfaceCacheEntry cacheEntry = getInterfaceCacheEntry(iface);
469             if (cacheEntry == null) return null;
470 
471             WifiChipInfo[] chipInfos = getAllChipInfoCached();
472             if (chipInfos == null) return null;
473 
474             for (WifiChipInfo info: chipInfos) {
475                 if (info.chipId == cacheEntry.chipId) {
476                     return info;
477                 }
478             }
479             return null;
480         }
481     }
482 
483     /**
484      * See {@link WifiNative#getSupportedBandCombinations(String)}.
485      */
getSupportedBandCombinations(WifiHal.WifiInterface iface)486     public Set<List<Integer>> getSupportedBandCombinations(WifiHal.WifiInterface iface) {
487         synchronized (mLock) {
488             Set<List<Integer>> combinations = getCachedSupportedBandCombinations(iface);
489             if (combinations == null) return null;
490             return Collections.unmodifiableSet(combinations);
491         }
492     }
493 
getCachedSupportedBandCombinations( WifiHal.WifiInterface iface)494     private Set<List<Integer>> getCachedSupportedBandCombinations(
495             WifiHal.WifiInterface iface) {
496         WifiChipInfo info = getChipInfo(iface);
497         if (info == null) return null;
498         // If there is no band combination information, cache it.
499         if (info.bandCombinations == null) {
500             if (info.radioCombinations == null) {
501                 WifiChip chip = getChip(iface);
502                 if (chip == null) return null;
503                 info.radioCombinations = getChipSupportedRadioCombinations(chip);
504             }
505             info.bandCombinations = getChipSupportedBandCombinations(info.radioCombinations);
506             if (mDbg) {
507                 Log.d(TAG, "radioCombinations=" + info.radioCombinations
508                         + " bandCombinations=" + info.bandCombinations);
509             }
510         }
511         return info.bandCombinations;
512     }
513 
514     /**
515      * See {@link WifiNative#isBandCombinationSupported(String, List)}.
516      */
isBandCombinationSupported(WifiHal.WifiInterface iface, @NonNull List<Integer> bands)517     public boolean isBandCombinationSupported(WifiHal.WifiInterface iface,
518             @NonNull List<Integer> bands) {
519         synchronized (mLock) {
520             Set<List<Integer>> combinations = getCachedSupportedBandCombinations(iface);
521             if (combinations == null) return false;
522             // Lookup depends on the order of the bands. So sort it.
523             return combinations.contains(bands.stream().sorted().collect(Collectors.toList()));
524         }
525     }
526 
527     /**
528      * Indicate whether 2.4GHz/5GHz DBS is supported.
529      *
530      * @param iface The interface on the chip.
531      * @return true if supported; false, otherwise;
532      */
is24g5gDbsSupported(WifiHal.WifiInterface iface)533     public boolean is24g5gDbsSupported(WifiHal.WifiInterface iface) {
534         return isBandCombinationSupported(iface,
535                 Arrays.asList(WifiScanner.WIFI_BAND_24_GHZ, WifiScanner.WIFI_BAND_5_GHZ));
536     }
537 
538     /**
539      * Wrapper around {@link #is24g5gDbsSupported(WifiHal.WifiInterface)} for P2P ifaces.
540      */
is24g5gDbsSupportedOnP2pIface(String ifaceName)541     public boolean is24g5gDbsSupportedOnP2pIface(String ifaceName) {
542         WifiP2pIface iface = mWifiP2pIfaces.get(ifaceName);
543         if (iface == null) return false;
544         return is24g5gDbsSupported(iface);
545     }
546 
547     /**
548      * Indicate whether 5GHz/6GHz DBS is supported.
549      *
550      * @param iface The interface on the chip.
551      * @return true if supported; false, otherwise;
552      */
is5g6gDbsSupported(WifiHal.WifiInterface iface)553     public boolean is5g6gDbsSupported(WifiHal.WifiInterface iface) {
554         return isBandCombinationSupported(iface,
555                 Arrays.asList(WifiScanner.WIFI_BAND_5_GHZ, WifiScanner.WIFI_BAND_6_GHZ));
556     }
557 
558     /**
559      * Wrapper around {@link #is5g6gDbsSupported(WifiHal.WifiInterface)} for P2P ifaces.
560      */
is5g6gDbsSupportedOnP2pIface(String ifaceName)561     public boolean is5g6gDbsSupportedOnP2pIface(String ifaceName) {
562         WifiP2pIface iface = mWifiP2pIfaces.get(ifaceName);
563         if (iface == null) return false;
564         return is5g6gDbsSupported(iface);
565     }
566 
567     /**
568      * Replace the requestorWs info for the associated info.
569      *
570      * When a new iface is requested via
571      * {@link #createIface(int, long, InterfaceDestroyedListener, Handler, WorkSource, ConcreteClientModeManager)}, the clients
572      * pass in a worksource which includes all the apps that triggered the iface creation. However,
573      * this list of apps can change during the lifetime of the iface (as new apps request the same
574      * iface or existing apps release their request for the iface). This API can be invoked multiple
575      * times to replace the entire requestor info for the provided iface.
576      *
577      * Note: This is a wholesale replacement of the requestor info. The corresponding client is
578      * responsible for individual add/remove of apps in the WorkSource passed in.
579      */
replaceRequestorWs(@onNull WifiHal.WifiInterface iface, @NonNull WorkSource newRequestorWs)580     public boolean replaceRequestorWs(@NonNull WifiHal.WifiInterface iface,
581             @NonNull WorkSource newRequestorWs) {
582         String name = getName(iface);
583         int type = getType(iface);
584         if (VDBG) {
585             Log.d(TAG, "replaceRequestorWs: iface(name)=" + name + ", newRequestorWs="
586                     + newRequestorWs);
587         }
588 
589         synchronized (mLock) {
590             InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(Pair.create(name, type));
591             if (cacheEntry == null) {
592                 Log.e(TAG, "replaceRequestorWs: no entry for iface(name)=" + name);
593                 return false;
594             }
595             cacheEntry.requestorWsHelper = mWifiInjector.makeWsHelper(newRequestorWs);
596             return true;
597         }
598     }
599 
600     /**
601      * Wrapper around {@link #replaceRequestorWs(WifiHal.WifiInterface, WorkSource)} for P2P ifaces.
602      */
replaceRequestorWsForP2pIface(String ifaceName, @NonNull WorkSource newRequestorWs)603     public boolean replaceRequestorWsForP2pIface(String ifaceName,
604             @NonNull WorkSource newRequestorWs) {
605         WifiP2pIface iface = mWifiP2pIfaces.get(ifaceName);
606         if (iface == null) return false;
607         return replaceRequestorWs(iface, newRequestorWs);
608     }
609 
610     /**
611      * Wrapper around {@link #replaceRequestorWs(WifiHal.WifiInterface, WorkSource)} for NAN ifaces.
612      */
replaceRequestorWsForNanIface(@onNull WifiNanIface iface, @NonNull WorkSource newRequestorWs)613     public boolean replaceRequestorWsForNanIface(@NonNull WifiNanIface iface,
614             @NonNull WorkSource newRequestorWs) {
615         return replaceRequestorWs(iface, newRequestorWs);
616     }
617 
618     /**
619      * Register a SubsystemRestartListener to listen to the subsystem restart event from HAL.
620      * Use the action() to forward the event to SelfRecovery when receiving the event from HAL.
621      *
622      * @param listener SubsystemRestartListener listener object.
623      * @param handler Handler on which to dispatch listener. Null implies the listener will be
624      *                invoked synchronously from the context of the client which triggered the
625      *                state change.
626      */
registerSubsystemRestartListener(@onNull SubsystemRestartListener listener, @Nullable Handler handler)627     public void registerSubsystemRestartListener(@NonNull SubsystemRestartListener listener,
628             @Nullable Handler handler) {
629         if (listener == null) {
630             Log.wtf(TAG, "registerSubsystemRestartListener with nulls!? listener=" + listener);
631             return;
632         }
633         if (!mSubsystemRestartListener.add(new SubsystemRestartListenerProxy(listener, handler))) {
634             Log.w(TAG, "registerSubsystemRestartListener: duplicate registration ignored");
635         }
636     }
637 
638     /**
639      * Register a callback object for RTT life-cycle events. The callback object registration
640      * indicates that an RTT controller should be created whenever possible. The callback object
641      * will be called with a new RTT controller whenever it is created (or at registration time
642      * if an RTT controller already exists). The callback object will also be triggered whenever
643      * an existing RTT controller is destroyed (the previous copies must be discarded by the
644      * recipient).
645      *
646      * Each listener should maintain a single callback object to register here. The callback can
647      * be registered upon the listener's initialization, and re-registered on HDM status changes, if
648      * {@link #isStarted} is true.
649      *
650      * @param callback InterfaceRttControllerLifecycleCallback object.
651      * @param handler Handler on which to dispatch callback
652      */
registerRttControllerLifecycleCallback( @onNull InterfaceRttControllerLifecycleCallback callback, @NonNull Handler handler)653     public void registerRttControllerLifecycleCallback(
654             @NonNull InterfaceRttControllerLifecycleCallback callback, @NonNull Handler handler) {
655         if (VDBG) {
656             Log.d(TAG, "registerRttControllerLifecycleCallback: callback=" + callback + ", handler="
657                     + handler);
658         }
659 
660         if (callback == null || handler == null) {
661             Log.wtf(TAG, "registerRttControllerLifecycleCallback with nulls!? callback=" + callback
662                     + ", handler=" + handler);
663             return;
664         }
665 
666         synchronized (mLock) {
667             InterfaceRttControllerLifecycleCallbackProxy proxy =
668                     new InterfaceRttControllerLifecycleCallbackProxy(callback, handler);
669             if (!mRttControllerLifecycleCallbacks.add(proxy)) {
670                 Log.d(TAG,
671                         "registerRttControllerLifecycleCallback: registering an existing callback="
672                                 + callback);
673                 return;
674             }
675 
676             if (mWifiRttController == null) {
677                 mWifiRttController = createRttControllerIfPossible();
678             }
679             if (mWifiRttController != null) {
680                 proxy.onNewRttController(mWifiRttController);
681             }
682         }
683     }
684 
685     /**
686      * Return the name of the input interface or null on error.
687      */
getName(WifiHal.WifiInterface iface)688     public String getName(WifiHal.WifiInterface iface) {
689         if (iface == null) {
690             return "<null>";
691         }
692         return iface.getName();
693     }
694 
695     /**
696      * Called when subsystem restart
697      */
698     public interface SubsystemRestartListener {
699         /**
700          * Called for subsystem restart event from the HAL.
701          * It will trigger recovery mechanism in framework.
702          */
onSubsystemRestart()703         void onSubsystemRestart();
704     }
705 
706     /**
707      * Called when interface is destroyed.
708      */
709     public interface InterfaceDestroyedListener {
710         /**
711          * Called for every interface on which registered when destroyed - whether
712          * destroyed by releaseIface() or through chip mode change or through Wi-Fi
713          * going down.
714          *
715          * Can be registered when the interface is requested with createXxxIface() - will
716          * only be valid if the interface creation was successful - i.e. a non-null was returned.
717          *
718          * @param ifaceName Name of the interface that was destroyed.
719          */
onDestroyed(@onNull String ifaceName)720         void onDestroyed(@NonNull String ifaceName);
721     }
722 
723     /**
724      * Called on RTT controller lifecycle events. RTT controller is a singleton which will be
725      * created when possible (after first lifecycle registration) and destroyed if necessary.
726      *
727      * Determination of availability is determined by the HAL. Creation attempts (if requested
728      * by registration of interface) will be done on any mode changes.
729      */
730     public interface InterfaceRttControllerLifecycleCallback {
731         /**
732          * Called when an RTT controller was created (or for newly registered listeners - if it
733          * was already available). The controller provided by this callback may be destroyed by
734          * the HAL at which point the {@link #onRttControllerDestroyed()} will be called.
735          *
736          * Note: this callback can be triggered to replace an existing controller (instead of
737          * calling the Destroyed callback in between).
738          *
739          * @param controller The RTT controller object.
740          */
onNewRttController(@onNull WifiRttController controller)741         void onNewRttController(@NonNull WifiRttController controller);
742 
743         /**
744          * Called when the previously provided RTT controller is destroyed. Clients must discard
745          * their copy. A new copy may be provided later by
746          * {@link #onNewRttController(WifiRttController)}.
747          */
onRttControllerDestroyed()748         void onRttControllerDestroyed();
749     }
750 
751     /**
752      * Returns whether the provided @HdmIfaceTypeForCreation combo can be supported by the device.
753      * Note: This only returns an answer based on the create type combination exposed by the HAL.
754      * The actual iface creation/deletion rules depend on the iface priorities set in
755      * {@link #allowedToDelete(int, int, int, int)}
756      *
757      * @param createTypeCombo SparseArray keyed in by @HdmIfaceTypeForCreation to number of ifaces
758      *                         needed.
759      * @return true if the device supports the provided combo, false otherwise.
760      */
canDeviceSupportCreateTypeCombo(SparseArray<Integer> createTypeCombo)761     public boolean canDeviceSupportCreateTypeCombo(SparseArray<Integer> createTypeCombo) {
762         if (VDBG) {
763             Log.d(TAG, "canDeviceSupportCreateTypeCombo: createTypeCombo=" + createTypeCombo);
764         }
765 
766         synchronized (mLock) {
767             int[] requestedCombo = new int[CREATE_TYPES_BY_PRIORITY.length];
768             for (int createType : CREATE_TYPES_BY_PRIORITY) {
769                 requestedCombo[createType] = createTypeCombo.get(createType, 0);
770             }
771             for (StaticChipInfo staticChipInfo : getStaticChipInfos()) {
772                 SparseArray<List<int[][]>> expandedCreateTypeCombosPerChipModeId =
773                         getExpandedCreateTypeCombosPerChipModeId(
774                                 staticChipInfo.getAvailableModes());
775                 for (int i = 0; i < expandedCreateTypeCombosPerChipModeId.size(); i++) {
776                     int chipModeId = expandedCreateTypeCombosPerChipModeId.keyAt(i);
777                     for (int[][] expandedCreateTypeCombo
778                             : expandedCreateTypeCombosPerChipModeId.get(chipModeId)) {
779                         for (int[] supportedCombo : expandedCreateTypeCombo) {
780                             if (canCreateTypeComboSupportRequestedCreateTypeCombo(
781                                     supportedCombo, requestedCombo)) {
782                                 if (VDBG) {
783                                     Log.d(TAG, "Device can support createTypeCombo="
784                                             + createTypeCombo);
785                                 }
786                                 return true;
787                             }
788                         }
789                     }
790                 }
791             }
792             if (VDBG) {
793                 Log.d(TAG, "Device cannot support createTypeCombo=" + createTypeCombo);
794             }
795             return false;
796         }
797     }
798 
799     /**
800      * Returns whether the provided Iface can be requested by specifier requestor.
801      *
802      * @param createIfaceType Type of iface requested.
803      * @param requiredChipCapabilities The bitmask of Capabilities which are required.
804      *                                 See the HAL for documentation.
805      * @param requestorWs Requestor worksource. This will be used to determine priority of this
806      *                    interface using rules based on the requestor app's context.
807      * @return true if the device supports the provided combo, false otherwise.
808      */
isItPossibleToCreateIface(@dmIfaceTypeForCreation int createIfaceType, long requiredChipCapabilities, WorkSource requestorWs)809     public boolean isItPossibleToCreateIface(@HdmIfaceTypeForCreation int createIfaceType,
810             long requiredChipCapabilities, WorkSource requestorWs) {
811         if (VDBG) {
812             Log.d(TAG, "isItPossibleToCreateIface: createIfaceType=" + createIfaceType
813                     + ", requiredChipCapabilities=" + requiredChipCapabilities);
814         }
815         return reportImpactToCreateIface(createIfaceType, true, requiredChipCapabilities,
816                 requestorWs) != null;
817     }
818 
819     /**
820      * Returns whether the provided Iface can be requested by specifier requestor.
821      *
822      * @param createIfaceType Type of iface requested.
823      * @param requestorWs Requestor worksource. This will be used to determine priority of this
824      *                    interface using rules based on the requestor app's context.
825      * @return true if the device supports the provided combo, false otherwise.
826      */
isItPossibleToCreateIface( @dmIfaceTypeForCreation int createIfaceType, WorkSource requestorWs)827     public boolean isItPossibleToCreateIface(
828             @HdmIfaceTypeForCreation int createIfaceType, WorkSource requestorWs) {
829         return isItPossibleToCreateIface(
830                 createIfaceType, CHIP_CAPABILITY_ANY, requestorWs);
831     }
832 
833     /**
834      * Returns the details of what it would take to create the provided Iface requested by the
835      * specified requestor. The details are the list of other interfaces which would have to be
836      * destroyed.
837      *
838      * Return types imply:
839      * - null: interface cannot be created
840      * - empty list: interface can be crated w/o destroying any other interfaces
841      * - otherwise: a list of interfaces to be destroyed
842      *
843      * @param createIfaceType Type of iface requested.
844      * @param queryForNewInterface True: request another interface of the specified type, False: if
845      *                             there's already an interface of the specified type then no need
846      *                             for further operation.
847      * @param requiredChipCapabilities The bitmask of Capabilities which are required.
848      *                                 See the HAL for documentation.
849      * @param requestorWs Requestor worksource. This will be used to determine priority of this
850      *                    interface using rules based on the requestor app's context.
851      * @return the list of interfaces that would have to be destroyed and their worksource. The
852      * interface type is described using @HdmIfaceTypeForCreation.
853      */
reportImpactToCreateIface( @dmIfaceTypeForCreation int createIfaceType, boolean queryForNewInterface, long requiredChipCapabilities, WorkSource requestorWs)854     public List<Pair<Integer, WorkSource>> reportImpactToCreateIface(
855             @HdmIfaceTypeForCreation int createIfaceType, boolean queryForNewInterface,
856             long requiredChipCapabilities, WorkSource requestorWs) {
857         if (VDBG) {
858             Log.d(TAG, "reportImpactToCreateIface: ifaceType=" + createIfaceType
859                     + ", requiredChipCapabilities=" + requiredChipCapabilities
860                     + ", requestorWs=" + requestorWs);
861         }
862 
863         IfaceCreationData creationData;
864         synchronized (mLock) {
865             if (!mWifiHal.isInitializationComplete()) {
866                 Log.e(TAG, "reportImpactToCreateIface: Wifi Hal is not available");
867                 return null;
868             }
869             WifiChipInfo[] chipInfos = getAllChipInfo();
870             if (chipInfos == null) {
871                 Log.e(TAG, "createIface: no chip info found");
872                 stopWifi(); // major error: shutting down
873                 return null;
874             }
875 
876             if (!validateInterfaceCacheAndRetrieveRequestorWs(chipInfos)) {
877                 Log.e(TAG, "createIface: local cache is invalid!");
878                 stopWifi(); // major error: shutting down
879                 return null;
880             }
881 
882             if (!queryForNewInterface) {
883                 for (WifiChipInfo chipInfo: chipInfos) {
884                     if (chipInfo.ifaces[createIfaceType].length != 0) {
885                         return Collections.emptyList(); // approve w/o deleting any interfaces
886                     }
887                 }
888             }
889 
890             creationData = getBestIfaceCreationProposal(chipInfos, createIfaceType,
891                     requiredChipCapabilities, requestorWs);
892         }
893 
894         if (creationData == null) {
895             return null; // impossible to create requested interface
896         }
897 
898         List<Pair<Integer, WorkSource>> details = new ArrayList<>();
899         boolean isModeConfigNeeded = !creationData.chipInfo.currentModeIdValid
900                 || creationData.chipInfo.currentModeId != creationData.chipModeId;
901         if (!isModeConfigNeeded && (creationData.interfacesToBeRemovedFirst == null
902                 || creationData.interfacesToBeRemovedFirst.isEmpty())) {
903             // can create interface w/o deleting any other interfaces
904             return details;
905         }
906 
907         if (isModeConfigNeeded) {
908             if (VDBG) {
909                 Log.d(TAG, "isItPossibleToCreateIfaceDetails: mode change from - "
910                         + creationData.chipInfo.currentModeId + ", to - "
911                         + creationData.chipModeId);
912             }
913             for (WifiIfaceInfo[] ifaceInfos: creationData.chipInfo.ifaces) {
914                 for (WifiIfaceInfo ifaceInfo : ifaceInfos) {
915                     details.add(Pair.create(ifaceInfo.createType,
916                             ifaceInfo.requestorWsHelper.getWorkSource()));
917                 }
918             }
919         } else {
920             for (WifiIfaceInfo ifaceInfo : creationData.interfacesToBeRemovedFirst) {
921                 details.add(Pair.create(ifaceInfo.createType,
922                         ifaceInfo.requestorWsHelper.getWorkSource()));
923             }
924         }
925 
926         return details;
927     }
928 
929     /**
930      * See {@link #reportImpactToCreateIface(int, boolean, long, WorkSource)}.
931      *
932      * @param ifaceType Type of iface requested.
933      * @param queryForNewInterface True: request another interface of the specified type, False: if
934      *                             there's already an interface of the specified type then no need
935      *                             for further operation.
936      * @param requestorWs Requestor worksource. This will be used to determine priority of this
937      *                    interface using rules based on the requestor app's context.
938      * @return the list of interfaces that would have to be destroyed and their worksource.
939      */
reportImpactToCreateIface( @dmIfaceTypeForCreation int ifaceType, boolean queryForNewInterface, WorkSource requestorWs)940     public List<Pair<Integer, WorkSource>> reportImpactToCreateIface(
941             @HdmIfaceTypeForCreation int ifaceType, boolean queryForNewInterface,
942             WorkSource requestorWs) {
943         return reportImpactToCreateIface(ifaceType, queryForNewInterface, CHIP_CAPABILITY_ANY,
944                 requestorWs);
945     }
946 
947     /**
948      * Helper method to return true if the given iface request will result in deleting an iface
949      * requested by a privileged worksource.
950      */
creatingIfaceWillDeletePrivilegedIface( @dmIfaceTypeForCreation int ifaceType, WorkSource requestorWs)951     public boolean creatingIfaceWillDeletePrivilegedIface(
952             @HdmIfaceTypeForCreation int ifaceType, WorkSource requestorWs) {
953         List<Pair<Integer, WorkSource>> impact =
954                 reportImpactToCreateIface(ifaceType, true, requestorWs);
955         if (impact == null) {
956             return false;
957         }
958         for (Pair<Integer, WorkSource> pair : impact) {
959             if (mWifiInjector.makeWsHelper(pair.second).getRequestorWsPriority()
960                     == WorkSourceHelper.PRIORITY_PRIVILEGED) {
961                 return true;
962             }
963         }
964         return false;
965     }
966 
967     // internal state
968 
969     /* This "PRIORITY" is not for deciding interface elimination (that is controlled by
970      * allowedToDeleteIfaceTypeForRequestedType. This priority is used for:
971      * - Comparing 2 configuration options
972      * - Order of dispatch of available for request listeners
973      */
974     private static final int[] IFACE_TYPES_BY_PRIORITY =
975             {WifiChip.IFACE_TYPE_AP, WifiChip.IFACE_TYPE_STA, WifiChip.IFACE_TYPE_P2P,
976                     WifiChip.IFACE_TYPE_NAN};
977     private static final int[] CREATE_TYPES_BY_PRIORITY =
978             {HDM_CREATE_IFACE_AP, HDM_CREATE_IFACE_AP_BRIDGE, HDM_CREATE_IFACE_STA,
979                     HDM_CREATE_IFACE_P2P, HDM_CREATE_IFACE_NAN};
980 
981     private final Object mLock = new Object();
982 
983     private WifiRttController mWifiRttController;
984     private HashMap<String, WifiP2pIface> mWifiP2pIfaces = new HashMap<>();
985     private final WifiHal.Callback mWifiEventCallback = new WifiEventCallback();
986     private final Set<ManagerStatusListenerProxy> mManagerStatusListeners = new HashSet<>();
987     private final Set<InterfaceRttControllerLifecycleCallbackProxy>
988             mRttControllerLifecycleCallbacks = new HashSet<>();
989     private final Set<SubsystemRestartListenerProxy> mSubsystemRestartListener = new HashSet<>();
990 
991     /*
992      * This is the only place where we cache HAL information in this manager. Necessary since
993      * we need to keep a list of registered destroyed listeners. Will be validated regularly
994      * in getAllChipInfoAndValidateCache().
995      */
996     private final Map<Pair<String, Integer>, InterfaceCacheEntry> mInterfaceInfoCache =
997             new HashMap<>();
998 
999     private class InterfaceCacheEntry {
1000         public WifiChip chip;
1001         public int chipId;
1002         public String name;
1003         public int type;
1004         public Set<InterfaceDestroyedListenerProxy> destroyedListeners = new HashSet<>();
1005         public long creationTime;
1006         public WorkSourceHelper requestorWsHelper;
1007 
1008         @Override
toString()1009         public String toString() {
1010             StringBuilder sb = new StringBuilder();
1011             sb.append("{name=").append(name).append(", type=").append(type)
1012                     .append(", destroyedListeners.size()=").append(destroyedListeners.size())
1013                     .append(", RequestorWs=").append(requestorWsHelper)
1014                     .append(", creationTime=").append(creationTime).append("}");
1015             return sb.toString();
1016         }
1017     }
1018 
1019     private class WifiIfaceInfo {
1020         public String name;
1021         public WifiHal.WifiInterface iface;
1022         public @HdmIfaceTypeForCreation int createType;
1023         public WorkSourceHelper requestorWsHelper;
1024 
1025         @Override
toString()1026         public String toString() {
1027             return "{name=" + name + ", iface=" + iface + ", requestorWs=" + requestorWsHelper
1028                     + " }";
1029         }
1030     }
1031 
1032     private class WifiChipInfo {
1033         public WifiChip chip;
1034         public int chipId = -1;
1035         public ArrayList<WifiChip.ChipMode> availableModes;
1036         public boolean currentModeIdValid = false;
1037         public int currentModeId = -1;
1038         // Arrays of WifiIfaceInfo indexed by @HdmIfaceTypeForCreation, in order of creation as
1039         // returned by WifiChip.getXxxIfaceNames.
1040         public WifiIfaceInfo[][] ifaces = new WifiIfaceInfo[CREATE_TYPES_BY_PRIORITY.length][];
1041         public long chipCapabilities;
1042         public List<WifiChip.WifiRadioCombination> radioCombinations = null;
1043         // A data structure for the faster band combination lookup.
1044         public Set<List<Integer>> bandCombinations = null;
1045 
1046         @Override
toString()1047         public String toString() {
1048             StringBuilder sb = new StringBuilder();
1049             sb.append("{chipId=").append(chipId).append(", availableModes=").append(availableModes)
1050                     .append(", currentModeIdValid=").append(currentModeIdValid)
1051                     .append(", currentModeId=").append(currentModeId)
1052                     .append(", chipCapabilities=").append(chipCapabilities)
1053                     .append(", radioCombinations=").append(radioCombinations)
1054                     .append(", bandCombinations=").append(bandCombinations);
1055             for (int type: IFACE_TYPES_BY_PRIORITY) {
1056                 sb.append(", ifaces[" + type + "].length=").append(ifaces[type].length);
1057             }
1058             sb.append("}");
1059             return sb.toString();
1060         }
1061     }
1062 
isWaitForDestroyedListenersMockable()1063     protected boolean isWaitForDestroyedListenersMockable() {
1064         return mWaitForDestroyedListeners;
1065     }
1066 
1067     // internal implementation
1068 
initializeInternal()1069     private void initializeInternal() {
1070         mWifiHal.initialize(mIWifiDeathRecipient);
1071     }
1072 
getIfaceTypeToString(@dmIfaceTypeForCreation int type)1073     private static String getIfaceTypeToString(@HdmIfaceTypeForCreation int type) {
1074         switch (type) {
1075             case HDM_CREATE_IFACE_STA:
1076                 return "STA";
1077             case HDM_CREATE_IFACE_AP:
1078                 return "AP";
1079             case HDM_CREATE_IFACE_AP_BRIDGE:
1080                 return "AP_BRIDGE";
1081             case HDM_CREATE_IFACE_P2P:
1082                 return "P2P";
1083             case HDM_CREATE_IFACE_NAN:
1084                 return "NAN";
1085             default:
1086                 return "UNKNOWN " + type;
1087         }
1088     }
1089 
teardownInternal()1090     private void teardownInternal() {
1091         managerStatusListenerDispatch();
1092         dispatchAllDestroyedListeners();
1093 
1094         mWifiRttController = null;
1095         dispatchRttControllerLifecycleOnDestroyed();
1096         mRttControllerLifecycleCallbacks.clear();
1097         mWifiP2pIfaces.clear();
1098     }
1099 
1100     private class WifiDeathRecipient implements WifiHal.DeathRecipient {
1101         @Override
onDeath()1102         public void onDeath() {
1103             mEventHandler.post(() -> {
1104                 synchronized (mLock) { // prevents race condition with surrounding method
1105                     teardownInternal();
1106                 }
1107             });
1108         }
1109     }
1110 
1111     /**
1112      * Register the wifi HAL event callback. Reset the Wifi HAL interface when it fails.
1113      * @return true if success.
1114      */
registerWifiHalEventCallback()1115     private boolean registerWifiHalEventCallback() {
1116         return mWifiHal.registerEventCallback(mWifiEventCallback);
1117     }
1118 
1119     @Nullable
1120     private WifiChipInfo[] mCachedWifiChipInfos = null;
1121 
1122     /**
1123      * Get current information about all the chips in the system: modes, current mode (if any), and
1124      * any existing interfaces.
1125      *
1126      * Intended to be called for any external iface support related queries. This information is
1127      * cached to reduce performance overhead (unlike {@link #getAllChipInfo()}).
1128      */
getAllChipInfoCached()1129     private WifiChipInfo[] getAllChipInfoCached() {
1130         if (mCachedWifiChipInfos == null) {
1131             mCachedWifiChipInfos = getAllChipInfo();
1132         }
1133         return mCachedWifiChipInfos;
1134     }
1135 
1136     /**
1137      * Get current information about all the chips in the system: modes, current mode (if any), and
1138      * any existing interfaces.
1139      *
1140      * Intended to be called whenever we need to configure the chips - information is NOT cached (to
1141      * reduce the likelihood that we get out-of-sync).
1142      */
getAllChipInfo()1143     private WifiChipInfo[] getAllChipInfo() {
1144         if (VDBG) Log.d(TAG, "getAllChipInfo");
1145 
1146         synchronized (mLock) {
1147             if (!isWifiStarted()) {
1148                 return null;
1149             }
1150 
1151             // get all chip IDs
1152             List<Integer> chipIds = mWifiHal.getChipIds();
1153             if (chipIds == null) {
1154                 return null;
1155             }
1156 
1157             if (VDBG) Log.d(TAG, "getChipIds=" + Arrays.toString(chipIds.toArray()));
1158             if (chipIds.size() == 0) {
1159                 Log.e(TAG, "Should have at least 1 chip!");
1160                 return null;
1161             }
1162 
1163             SparseArray<StaticChipInfo> staticChipInfoPerId = new SparseArray<>();
1164             for (StaticChipInfo staticChipInfo : getStaticChipInfos()) {
1165                 staticChipInfoPerId.put(staticChipInfo.getChipId(), staticChipInfo);
1166             }
1167 
1168             int chipInfoIndex = 0;
1169             WifiChipInfo[] chipsInfo = new WifiChipInfo[chipIds.size()];
1170 
1171             for (Integer chipId : chipIds) {
1172                 WifiChip chip = mWifiHal.getChip(chipId);
1173                 if (chip == null) {
1174                     return null;
1175                 }
1176 
1177                 StaticChipInfo staticChipInfo = staticChipInfoPerId.get(chipId);
1178                 List<WifiChip.ChipMode> chipModes = null;
1179                 if (staticChipInfo == null) {
1180                     chipModes = chip.getAvailableModes();
1181                     if (chipModes == null) {
1182                         return null;
1183                     }
1184                 }
1185 
1186                 WifiChip.Response<Integer> currentMode = chip.getMode();
1187                 if (currentMode.getStatusCode() != WifiHal.WIFI_STATUS_SUCCESS
1188                         && currentMode.getStatusCode() != WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE) {
1189                     return null;
1190                 }
1191 
1192                 long chipCapabilities = getChipCapabilities(chip);
1193 
1194                 List<String> ifaceNames = chip.getStaIfaceNames();
1195                 if (ifaceNames == null) {
1196                     return null;
1197                 }
1198 
1199                 int ifaceIndex = 0;
1200                 WifiIfaceInfo[] staIfaces = new WifiIfaceInfo[ifaceNames.size()];
1201                 for (String ifaceName: ifaceNames) {
1202                     WifiHal.WifiInterface iface = chip.getStaIface(ifaceName);
1203                     if (iface == null) {
1204                         return null;
1205                     }
1206                     WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
1207                     ifaceInfo.name = ifaceName;
1208                     ifaceInfo.iface = iface;
1209                     ifaceInfo.createType = HDM_CREATE_IFACE_STA;
1210                     staIfaces[ifaceIndex++] = ifaceInfo;
1211                 }
1212 
1213                 ifaceIndex = 0;
1214                 ifaceNames = chip.getApIfaceNames();
1215                 if (ifaceNames == null) {
1216                     return null;
1217                 }
1218 
1219                 WifiIfaceInfo[] apIfaces = new WifiIfaceInfo[ifaceNames.size()];
1220                 for (String ifaceName : ifaceNames) {
1221                     WifiHal.WifiInterface iface = chip.getApIface(ifaceName);
1222                     if (iface == null) {
1223                         return null;
1224                     }
1225                     WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
1226                     ifaceInfo.name = ifaceName;
1227                     ifaceInfo.iface = iface;
1228                     ifaceInfo.createType = HDM_CREATE_IFACE_AP;
1229                     apIfaces[ifaceIndex++] = ifaceInfo;
1230                 }
1231 
1232                 int numBridgedAps = 0;
1233                 for (WifiIfaceInfo apIfaceInfo : apIfaces) {
1234                     List<String> bridgedInstances = ((WifiApIface) apIfaceInfo.iface)
1235                             .getBridgedInstances();
1236                     // Only count bridged APs with more than 1 instance as a bridged
1237                     // AP; 1 instance bridged APs will be counted as single AP.
1238                     if (bridgedInstances != null && bridgedInstances.size() > 1) {
1239                         apIfaceInfo.createType = HDM_CREATE_IFACE_AP_BRIDGE;
1240                         numBridgedAps++;
1241                     }
1242                 }
1243 
1244                 WifiIfaceInfo[] singleApIfaces = new WifiIfaceInfo[apIfaces.length - numBridgedAps];
1245                 WifiIfaceInfo[] bridgedApIfaces = new WifiIfaceInfo[numBridgedAps];
1246                 int singleApIndex = 0;
1247                 int bridgedApIndex = 0;
1248                 for (WifiIfaceInfo apIfaceInfo : apIfaces) {
1249                     if (apIfaceInfo.createType == HDM_CREATE_IFACE_AP_BRIDGE) {
1250                         bridgedApIfaces[bridgedApIndex++] = apIfaceInfo;
1251                     } else {
1252                         singleApIfaces[singleApIndex++] = apIfaceInfo;
1253                     }
1254                 }
1255 
1256                 ifaceIndex = 0;
1257                 ifaceNames = chip.getP2pIfaceNames();
1258                 if (ifaceNames == null) {
1259                     return null;
1260                 }
1261 
1262                 WifiIfaceInfo[] p2pIfaces = new WifiIfaceInfo[ifaceNames.size()];
1263                 for (String ifaceName : ifaceNames) {
1264                     WifiHal.WifiInterface iface = chip.getP2pIface(ifaceName);
1265                     if (iface == null) {
1266                         return null;
1267                     }
1268                     WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
1269                     ifaceInfo.name = ifaceName;
1270                     ifaceInfo.iface = iface;
1271                     ifaceInfo.createType = HDM_CREATE_IFACE_P2P;
1272                     p2pIfaces[ifaceIndex++] = ifaceInfo;
1273                 }
1274 
1275                 ifaceIndex = 0;
1276                 ifaceNames = chip.getNanIfaceNames();
1277                 if (ifaceNames == null) {
1278                     return null;
1279                 }
1280 
1281                 WifiIfaceInfo[] nanIfaces = new WifiIfaceInfo[ifaceNames.size()];
1282                 for (String ifaceName : ifaceNames) {
1283                     WifiHal.WifiInterface iface = chip.getNanIface(ifaceName);
1284                     if (iface == null) {
1285                         return null;
1286                     }
1287                     WifiIfaceInfo ifaceInfo = new WifiIfaceInfo();
1288                     ifaceInfo.name = ifaceName;
1289                     ifaceInfo.iface = iface;
1290                     ifaceInfo.createType = HDM_CREATE_IFACE_NAN;
1291                     nanIfaces[ifaceIndex++] = ifaceInfo;
1292                 }
1293 
1294                 WifiChipInfo chipInfo = new WifiChipInfo();
1295                 chipsInfo[chipInfoIndex++] = chipInfo;
1296 
1297                 chipInfo.chip = chip;
1298                 chipInfo.chipId = chipId;
1299                 if (staticChipInfo != null) {
1300                     chipInfo.availableModes = staticChipInfo.getAvailableModes();
1301                 } else {
1302                     chipInfo.availableModes = new ArrayList<>(chipModes);
1303                 }
1304                 chipInfo.currentModeIdValid =
1305                         currentMode.getStatusCode() == WifiHal.WIFI_STATUS_SUCCESS;
1306                 chipInfo.currentModeId = currentMode.getValue();
1307                 chipInfo.chipCapabilities = chipCapabilities;
1308                 chipInfo.ifaces[HDM_CREATE_IFACE_STA] = staIfaces;
1309                 chipInfo.ifaces[HDM_CREATE_IFACE_AP] = singleApIfaces;
1310                 chipInfo.ifaces[HDM_CREATE_IFACE_AP_BRIDGE] = bridgedApIfaces;
1311                 chipInfo.ifaces[HDM_CREATE_IFACE_P2P] = p2pIfaces;
1312                 chipInfo.ifaces[HDM_CREATE_IFACE_NAN] = nanIfaces;
1313             }
1314             return chipsInfo;
1315         }
1316     }
1317 
1318     @Nullable
1319     private StaticChipInfo[] mCachedStaticChipInfos = null;
1320 
1321     @NonNull
getStaticChipInfos()1322     private StaticChipInfo[] getStaticChipInfos() {
1323         if (mCachedStaticChipInfos == null) {
1324             mCachedStaticChipInfos = loadStaticChipInfoFromStore();
1325         }
1326         return mCachedStaticChipInfos;
1327     }
1328 
saveStaticChipInfoToStore(StaticChipInfo[] staticChipInfos)1329     private void saveStaticChipInfoToStore(StaticChipInfo[] staticChipInfos) {
1330         try {
1331             JSONArray staticChipInfosJson = new JSONArray();
1332             for (StaticChipInfo staticChipInfo : staticChipInfos) {
1333                 staticChipInfosJson.put(staticChipInfoToJson(staticChipInfo));
1334             }
1335             mWifiInjector.getSettingsConfigStore().put(WIFI_STATIC_CHIP_INFO,
1336                     staticChipInfosJson.toString());
1337         } catch (JSONException e) {
1338             Log.e(TAG, "JSONException while converting StaticChipInfo to JSON: " + e);
1339         }
1340     }
1341 
loadStaticChipInfoFromStore()1342     private StaticChipInfo[] loadStaticChipInfoFromStore() {
1343         StaticChipInfo[] staticChipInfos = new StaticChipInfo[0];
1344         String configString = mWifiInjector.getSettingsConfigStore().get(WIFI_STATIC_CHIP_INFO);
1345         if (TextUtils.isEmpty(configString)) {
1346             return staticChipInfos;
1347         }
1348         try {
1349             JSONArray staticChipInfosJson = new JSONArray(
1350                     mWifiInjector.getSettingsConfigStore().get(WIFI_STATIC_CHIP_INFO));
1351             staticChipInfos = new StaticChipInfo[staticChipInfosJson.length()];
1352             for (int i = 0; i < staticChipInfosJson.length(); i++) {
1353                 staticChipInfos[i] = jsonToStaticChipInfo(staticChipInfosJson.getJSONObject(i));
1354             }
1355         } catch (JSONException e) {
1356             Log.e(TAG, "Failed to load static chip info from store: " + e);
1357         }
1358         return staticChipInfos;
1359     }
1360 
1361     @NonNull
convertWifiChipInfoToStaticChipInfos( @onNull WifiChipInfo[] chipInfos)1362     private StaticChipInfo[] convertWifiChipInfoToStaticChipInfos(
1363             @NonNull WifiChipInfo[] chipInfos) {
1364         StaticChipInfo[] staticChipInfos = new StaticChipInfo[chipInfos.length];
1365         for (int i = 0; i < chipInfos.length; i++) {
1366             WifiChipInfo chipInfo = chipInfos[i];
1367             staticChipInfos[i] = new StaticChipInfo(
1368                     chipInfo.chipId,
1369                     chipInfo.chipCapabilities,
1370                     chipInfo.availableModes);
1371         }
1372         return staticChipInfos;
1373     }
1374 
1375     /**
1376      * Checks the local state of this object (the cached state) against the input 'chipInfos'
1377      * state (which is a live representation of the Wi-Fi firmware status - read through the HAL).
1378      * Returns 'true' if there are no discrepancies - 'false' otherwise.
1379      *
1380      * A discrepancy is if any local state contains references to a chip or interface which are not
1381      * found on the information read from the chip.
1382      *
1383      * Also, fills in the |requestorWs| corresponding to each active iface in |WifiChipInfo|.
1384      */
validateInterfaceCacheAndRetrieveRequestorWs(WifiChipInfo[] chipInfos)1385     private boolean validateInterfaceCacheAndRetrieveRequestorWs(WifiChipInfo[] chipInfos) {
1386         if (VDBG) Log.d(TAG, "validateInterfaceCache");
1387 
1388         synchronized (mLock) {
1389             for (InterfaceCacheEntry entry: mInterfaceInfoCache.values()) {
1390                 // search for chip
1391                 WifiChipInfo matchingChipInfo = null;
1392                 for (WifiChipInfo ci: chipInfos) {
1393                     if (ci.chipId == entry.chipId) {
1394                         matchingChipInfo = ci;
1395                         break;
1396                     }
1397                 }
1398                 if (matchingChipInfo == null) {
1399                     Log.e(TAG, "validateInterfaceCache: no chip found for " + entry);
1400                     return false;
1401                 }
1402 
1403                 // search for matching interface cache entry by iterating through the corresponding
1404                 // HdmIfaceTypeForCreation values.
1405                 boolean matchFound = false;
1406                 for (int createType : CREATE_TYPES_BY_PRIORITY) {
1407                     if (HAL_IFACE_MAP.get(createType) != entry.type) {
1408                         continue;
1409                     }
1410                     WifiIfaceInfo[] ifaceInfoList = matchingChipInfo.ifaces[createType];
1411                     if (ifaceInfoList == null) {
1412                         Log.e(TAG, "validateInterfaceCache: invalid type on entry " + entry);
1413                         return false;
1414                     }
1415                     for (WifiIfaceInfo ifaceInfo : ifaceInfoList) {
1416                         if (ifaceInfo.name.equals(entry.name)) {
1417                             ifaceInfo.requestorWsHelper = entry.requestorWsHelper;
1418                             matchFound = true;
1419                             break;
1420                         }
1421                     }
1422                 }
1423                 if (!matchFound) {
1424                     Log.e(TAG, "validateInterfaceCache: no interface found for " + entry);
1425                     return false;
1426                 }
1427             }
1428         }
1429 
1430         return true;
1431     }
1432 
isWifiStarted()1433     private boolean isWifiStarted() {
1434         if (VDBG) Log.d(TAG, "isWifiStart");
1435         synchronized (mLock) {
1436             return mWifiHal.isStarted();
1437         }
1438     }
1439 
startWifi()1440     private boolean startWifi() {
1441         if (VDBG) Log.d(TAG, "startWifi");
1442         initializeInternal();
1443         synchronized (mLock) {
1444             int triedCount = 0;
1445             while (triedCount <= START_HAL_RETRY_TIMES) {
1446                 int status = mWifiHal.start();
1447                 if (status == WifiHal.WIFI_STATUS_SUCCESS) {
1448                     managerStatusListenerDispatch();
1449                     if (triedCount != 0) {
1450                         Log.d(TAG, "start IWifi succeeded after trying "
1451                                  + triedCount + " times");
1452                     }
1453                     WifiChipInfo[] wifiChipInfos = getAllChipInfo();
1454                     if (wifiChipInfos == null) {
1455                         Log.e(TAG, "Started wifi but could not get current chip info.");
1456                     }
1457                     return true;
1458                 } else if (status == WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE) {
1459                     // Should retry. Hal might still be stopping. the registered event
1460                     // callback will not be cleared.
1461                     Log.e(TAG, "Cannot start wifi because unavailable. Retrying...");
1462                     try {
1463                         Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
1464                     } catch (InterruptedException ignore) {
1465                         // no-op
1466                     }
1467                     triedCount++;
1468                 } else {
1469                     // Should not retry on other failures.
1470                     // Will be handled in the onFailure event.
1471                     Log.e(TAG, "Cannot start IWifi. Status: " + status);
1472                     return false;
1473                 }
1474             }
1475             Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
1476             return false;
1477         }
1478     }
1479 
stopWifi()1480     private void stopWifi() {
1481         if (VDBG) Log.d(TAG, "stopWifi");
1482         synchronized (mLock) {
1483             if (!mWifiHal.isInitializationComplete()) {
1484                 Log.w(TAG, "stopWifi was called, but Wifi Hal is not initialized");
1485                 return;
1486             }
1487             if (!mWifiHal.stop()) {
1488                 Log.e(TAG, "Cannot stop IWifi");
1489             }
1490             // even on failure since WTF??
1491             teardownInternal();
1492         }
1493     }
1494 
1495     private class WifiEventCallback implements WifiHal.Callback {
1496         @Override
onStart()1497         public void onStart() {
1498             mEventHandler.post(() -> {
1499                 if (VDBG) Log.d(TAG, "IWifiEventCallback.onStart");
1500                 // NOP: only happens in reaction to my calls - will handle directly
1501             });
1502         }
1503 
1504         @Override
onStop()1505         public void onStop() {
1506             mEventHandler.post(() -> {
1507                 if (VDBG) Log.d(TAG, "IWifiEventCallback.onStop");
1508                 // NOP: only happens in reaction to my calls - will handle directly
1509             });
1510         }
1511 
1512         @Override
onFailure(int status)1513         public void onFailure(int status) {
1514             mEventHandler.post(() -> {
1515                 Log.e(TAG, "IWifiEventCallback.onFailure. Status: " + status);
1516                 synchronized (mLock) {
1517                     teardownInternal();
1518                 }
1519             });
1520         }
1521 
1522         @Override
onSubsystemRestart(int status)1523         public void onSubsystemRestart(int status) {
1524             Log.i(TAG, "onSubsystemRestart");
1525             mEventHandler.post(() -> {
1526                 Log.i(TAG, "IWifiEventCallback.onSubsystemRestart. Status: " + status);
1527                 synchronized (mLock) {
1528                     Log.i(TAG, "Attempting to invoke mSubsystemRestartListener");
1529                     for (SubsystemRestartListenerProxy cb : mSubsystemRestartListener) {
1530                         Log.i(TAG, "Invoking mSubsystemRestartListener");
1531                         cb.action();
1532                     }
1533                 }
1534             });
1535         }
1536     }
1537 
managerStatusListenerDispatch()1538     private void managerStatusListenerDispatch() {
1539         synchronized (mLock) {
1540             for (ManagerStatusListenerProxy cb : mManagerStatusListeners) {
1541                 cb.trigger(false);
1542             }
1543         }
1544     }
1545 
1546     private class ManagerStatusListenerProxy  extends
1547             ListenerProxy<ManagerStatusListener> {
ManagerStatusListenerProxy(ManagerStatusListener statusListener, Handler handler)1548         ManagerStatusListenerProxy(ManagerStatusListener statusListener, Handler handler) {
1549             super(statusListener, handler, "ManagerStatusListenerProxy");
1550         }
1551 
1552         @Override
action()1553         protected void action() {
1554             mListener.onStatusChanged();
1555         }
1556     }
1557 
getSupportedIfaceTypesInternal(WifiChip chip)1558     private Set<Integer> getSupportedIfaceTypesInternal(WifiChip chip) {
1559         Set<Integer> results = new HashSet<>();
1560 
1561         WifiChipInfo[] chipInfos = getAllChipInfoCached();
1562         if (chipInfos == null) {
1563             Log.e(TAG, "getSupportedIfaceTypesInternal: no chip info found");
1564             return results;
1565         }
1566 
1567         int chipIdIfProvided = 0; // NOT using 0 as a magic value
1568         if (chip != null) {
1569             chipIdIfProvided = chip.getId();
1570             if (chipIdIfProvided == -1) {
1571                 return results;
1572             }
1573         }
1574 
1575         for (WifiChipInfo wci: chipInfos) {
1576             if (chip != null && wci.chipId != chipIdIfProvided) {
1577                 continue;
1578             }
1579             // Map the IfaceConcurrencyTypes to the corresponding IfaceType.
1580             for (WifiChip.ChipMode cm : wci.availableModes) {
1581                 for (WifiChip.ChipConcurrencyCombination cic : cm.availableCombinations) {
1582                     for (WifiChip.ChipConcurrencyCombinationLimit cicl : cic.limits) {
1583                         for (int concurrencyType: cicl.types) {
1584                             results.add(HAL_IFACE_MAP.get(
1585                                     CONCURRENCY_TYPE_TO_CREATE_TYPE_MAP.get(concurrencyType)));
1586                         }
1587                     }
1588                 }
1589             }
1590         }
1591         return results;
1592     }
1593 
createIface(@dmIfaceTypeForCreation int createIfaceType, long requiredChipCapabilities, InterfaceDestroyedListener destroyedListener, Handler handler, WorkSource requestorWs)1594     private WifiHal.WifiInterface createIface(@HdmIfaceTypeForCreation int createIfaceType,
1595             long requiredChipCapabilities, InterfaceDestroyedListener destroyedListener,
1596             Handler handler, WorkSource requestorWs) {
1597         if (mDbg) {
1598             Log.d(TAG, "createIface: createIfaceType=" + createIfaceType
1599                     + ", requiredChipCapabilities=" + requiredChipCapabilities
1600                     + ", requestorWs=" + requestorWs);
1601         }
1602         if (destroyedListener != null && handler == null) {
1603             Log.wtf(TAG, "createIface: createIfaceType=" + createIfaceType
1604                     + "with NonNull destroyedListener but Null handler");
1605             return null;
1606         }
1607 
1608         synchronized (mLock) {
1609             WifiChipInfo[] chipInfos = getAllChipInfo();
1610             if (chipInfos == null) {
1611                 Log.e(TAG, "createIface: no chip info found");
1612                 stopWifi(); // major error: shutting down
1613                 // Event callback has been invalidated in HAL stop, register it again.
1614                 registerWifiHalEventCallback();
1615                 return null;
1616             }
1617 
1618             if (!validateInterfaceCacheAndRetrieveRequestorWs(chipInfos)) {
1619                 Log.e(TAG, "createIface: local cache is invalid!");
1620                 stopWifi(); // major error: shutting down
1621                 // Event callback has been invalidated in HAL stop, register it again.
1622                 registerWifiHalEventCallback();
1623                 return null;
1624             }
1625 
1626             return createIfaceIfPossible(
1627                     chipInfos, createIfaceType, requiredChipCapabilities,
1628                     destroyedListener, handler, requestorWs);
1629         }
1630     }
1631 
isChipCapabilitiesSupported(long currentChipCapabilities, long requiredChipCapabilities)1632     private static boolean isChipCapabilitiesSupported(long currentChipCapabilities,
1633             long requiredChipCapabilities) {
1634         if (requiredChipCapabilities == CHIP_CAPABILITY_ANY) return true;
1635 
1636         if (CHIP_CAPABILITY_UNINITIALIZED == currentChipCapabilities) return true;
1637 
1638         return (currentChipCapabilities & requiredChipCapabilities)
1639                 == requiredChipCapabilities;
1640     }
1641 
getBestIfaceCreationProposal( WifiChipInfo[] chipInfos, @HdmIfaceTypeForCreation int createIfaceType, long requiredChipCapabilities, WorkSource requestorWs)1642     private IfaceCreationData getBestIfaceCreationProposal(
1643             WifiChipInfo[] chipInfos, @HdmIfaceTypeForCreation int createIfaceType,
1644             long requiredChipCapabilities, WorkSource requestorWs) {
1645         int targetHalIfaceType = HAL_IFACE_MAP.get(createIfaceType);
1646         if (VDBG) {
1647             Log.d(TAG, "getBestIfaceCreationProposal: chipInfos=" + Arrays.deepToString(chipInfos)
1648                     + ", createIfaceType=" + createIfaceType
1649                     + ", targetHalIfaceType=" + targetHalIfaceType
1650                     + ", requiredChipCapabilities=" + requiredChipCapabilities
1651                     + ", requestorWs=" + requestorWs);
1652         }
1653         synchronized (mLock) {
1654             IfaceCreationData bestIfaceCreationProposal = null;
1655             for (WifiChipInfo chipInfo : chipInfos) {
1656                 if (!isChipCapabilitiesSupported(
1657                         chipInfo.chipCapabilities, requiredChipCapabilities)) {
1658                     continue;
1659                 }
1660 
1661                 SparseArray<List<int[][]>> expandedCreateTypeCombosPerChipModeId =
1662                         getExpandedCreateTypeCombosPerChipModeId(chipInfo.availableModes);
1663                 for (int i = 0; i < expandedCreateTypeCombosPerChipModeId.size(); i++) {
1664                     int chipModeId = expandedCreateTypeCombosPerChipModeId.keyAt(i);
1665                     for (int[][] expandedCreateTypeCombo :
1666                             expandedCreateTypeCombosPerChipModeId.get(chipModeId)) {
1667                         for (int[] createTypeCombo : expandedCreateTypeCombo) {
1668                             IfaceCreationData currentProposal = canCreateTypeComboSupportRequest(
1669                                     chipInfo, chipModeId, createTypeCombo, createIfaceType,
1670                                     requestorWs);
1671                             if (compareIfaceCreationData(currentProposal,
1672                                     bestIfaceCreationProposal)) {
1673                                 if (VDBG) Log.d(TAG, "new proposal accepted");
1674                                 bestIfaceCreationProposal = currentProposal;
1675                             }
1676                         }
1677                     }
1678                 }
1679             }
1680             return bestIfaceCreationProposal;
1681         }
1682     }
1683 
1684     /**
1685      * Returns a SparseArray indexed by ChipModeId, containing Lists of expanded create type combos
1686      * supported by that id.
1687      */
getExpandedCreateTypeCombosPerChipModeId( ArrayList<WifiChip.ChipMode> chipModes)1688     private SparseArray<List<int[][]>> getExpandedCreateTypeCombosPerChipModeId(
1689             ArrayList<WifiChip.ChipMode> chipModes) {
1690         SparseArray<List<int[][]>> combosPerChipModeId = new SparseArray<>();
1691         for (WifiChip.ChipMode chipMode : chipModes) {
1692             List<int[][]> expandedCreateTypeCombos = new ArrayList<>();
1693             for (WifiChip.ChipConcurrencyCombination chipConcurrencyCombo
1694                     : chipMode.availableCombinations) {
1695                 expandedCreateTypeCombos.add(expandCreateTypeCombo(chipConcurrencyCombo));
1696             }
1697             combosPerChipModeId.put(chipMode.id, expandedCreateTypeCombos);
1698         }
1699         return combosPerChipModeId;
1700     }
1701 
createIfaceIfPossible( WifiChipInfo[] chipInfos, @HdmIfaceTypeForCreation int createIfaceType, long requiredChipCapabilities, InterfaceDestroyedListener destroyedListener, Handler handler, WorkSource requestorWs)1702     private WifiHal.WifiInterface createIfaceIfPossible(
1703             WifiChipInfo[] chipInfos, @HdmIfaceTypeForCreation int createIfaceType,
1704             long requiredChipCapabilities, InterfaceDestroyedListener destroyedListener,
1705             Handler handler, WorkSource requestorWs) {
1706         int targetHalIfaceType = HAL_IFACE_MAP.get(createIfaceType);
1707         if (VDBG) {
1708             Log.d(TAG, "createIfaceIfPossible: chipInfos=" + Arrays.deepToString(chipInfos)
1709                     + ", createIfaceType=" + createIfaceType
1710                     + ", targetHalIfaceType=" + targetHalIfaceType
1711                     + ", requiredChipCapabilities=" + requiredChipCapabilities
1712                     + ", requestorWs=" + requestorWs);
1713         }
1714         synchronized (mLock) {
1715             IfaceCreationData bestIfaceCreationProposal = getBestIfaceCreationProposal(chipInfos,
1716                     createIfaceType, requiredChipCapabilities, requestorWs);
1717 
1718             if (bestIfaceCreationProposal != null) {
1719                 WifiHal.WifiInterface iface = executeChipReconfiguration(bestIfaceCreationProposal,
1720                         createIfaceType);
1721                 if (iface == null) {
1722                     // If the chip reconfiguration failed, we'll need to clean up internal state.
1723                     Log.e(TAG, "Teardown Wifi internal state");
1724                     mWifiHal.invalidate();
1725                     teardownInternal();
1726                 } else {
1727                     InterfaceCacheEntry cacheEntry = new InterfaceCacheEntry();
1728 
1729                     cacheEntry.chip = bestIfaceCreationProposal.chipInfo.chip;
1730                     cacheEntry.chipId = bestIfaceCreationProposal.chipInfo.chipId;
1731                     cacheEntry.name = getName(iface);
1732                     cacheEntry.type = targetHalIfaceType;
1733                     cacheEntry.requestorWsHelper = mWifiInjector.makeWsHelper(requestorWs);
1734                     if (destroyedListener != null) {
1735                         cacheEntry.destroyedListeners.add(
1736                                 new InterfaceDestroyedListenerProxy(
1737                                         cacheEntry.name, destroyedListener, handler));
1738                     }
1739                     cacheEntry.creationTime = mClock.getElapsedSinceBootMillis();
1740 
1741                     if (mDbg) Log.d(TAG, "createIfaceIfPossible: added cacheEntry=" + cacheEntry);
1742                     mInterfaceInfoCache.put(
1743                             Pair.create(cacheEntry.name, cacheEntry.type), cacheEntry);
1744                     return iface;
1745                 }
1746             } else {
1747                 List<String> createIfaceInfoString = new ArrayList<String>();
1748                 for (WifiChipInfo chipInfo : chipInfos) {
1749                     for (int existingCreateType : CREATE_TYPES_BY_PRIORITY) {
1750                         WifiIfaceInfo[] createTypeIfaces = chipInfo.ifaces[existingCreateType];
1751                         for (WifiIfaceInfo intfInfo : createTypeIfaces) {
1752                             if (intfInfo != null) {
1753                                 createIfaceInfoString.add(
1754                                         "name=" + intfInfo.name + " type=" + getIfaceTypeToString(
1755                                                 intfInfo.createType));
1756                             }
1757                         }
1758                     }
1759                 }
1760                 Log.i(TAG, "bestIfaceCreationProposal is null," + " requestIface="
1761                         + getIfaceTypeToString(createIfaceType) + ", existingIface="
1762                         + createIfaceInfoString);
1763             }
1764         }
1765 
1766         Log.e(TAG, "createIfaceIfPossible: Failed to create iface for ifaceType=" + createIfaceType
1767                 + ", requestorWs=" + requestorWs);
1768         return null;
1769     }
1770 
1771     /**
1772      * Expands (or provides an alternative representation) of the ChipConcurrencyCombination as all
1773      * possible combinations of @HdmIfaceTypeForCreation.
1774      *
1775      * Returns [# of combinations][4 (@HdmIfaceTypeForCreation)]
1776      *
1777      * Note: there could be duplicates - allow (inefficient but ...).
1778      * TODO: optimize by using a Set as opposed to a []: will remove duplicates. Will need to
1779      * provide correct hashes.
1780      */
expandCreateTypeCombo( WifiChip.ChipConcurrencyCombination chipConcurrencyCombo)1781     private int[][] expandCreateTypeCombo(
1782             WifiChip.ChipConcurrencyCombination chipConcurrencyCombo) {
1783         int numOfCombos = 1;
1784         for (WifiChip.ChipConcurrencyCombinationLimit limit : chipConcurrencyCombo.limits) {
1785             for (int i = 0; i < limit.maxIfaces; ++i) {
1786                 numOfCombos *= limit.types.size();
1787             }
1788         }
1789 
1790         int[][] expandedCreateTypeCombo =
1791                 new int[numOfCombos][CREATE_TYPES_BY_PRIORITY.length];
1792 
1793         int span = numOfCombos; // span of an individual type (or sub-tree size)
1794         for (WifiChip.ChipConcurrencyCombinationLimit limit : chipConcurrencyCombo.limits) {
1795             for (int i = 0; i < limit.maxIfaces; ++i) {
1796                 span /= limit.types.size();
1797                 for (int k = 0; k < numOfCombos; ++k) {
1798                     expandedCreateTypeCombo[k][CONCURRENCY_TYPE_TO_CREATE_TYPE_MAP.get(
1799                             limit.types.get((k / span) % limit.types.size()))]++;
1800                 }
1801             }
1802         }
1803         if (VDBG) {
1804             Log.d(TAG, "ChipConcurrencyCombo " + chipConcurrencyCombo
1805                     + " expands to HdmIfaceTypeForCreation combo "
1806                     + Arrays.deepToString(expandedCreateTypeCombo));
1807         }
1808         return expandedCreateTypeCombo;
1809     }
1810 
1811     private class IfaceCreationData {
1812         public WifiChipInfo chipInfo;
1813         public int chipModeId;
1814         public @NonNull List<WifiIfaceInfo> interfacesToBeRemovedFirst = new ArrayList<>();
1815         public @NonNull List<WifiIfaceInfo> interfacesToBeDowngraded = new ArrayList<>();
1816 
1817         @Override
toString()1818         public String toString() {
1819             StringBuilder sb = new StringBuilder();
1820             sb.append("{chipInfo=").append(chipInfo).append(", chipModeId=").append(chipModeId)
1821                     .append(", interfacesToBeRemovedFirst=").append(interfacesToBeRemovedFirst)
1822                     .append(", interfacesToBeDowngraded=").append(interfacesToBeDowngraded)
1823                     .append(")");
1824             return sb.toString();
1825         }
1826     }
1827 
1828     /**
1829      * Checks whether the input chip-create-type-combo can support the requested create type:
1830      * if not then returns null, if yes then returns information containing the list of interfaces
1831      * which would have to be removed first before an interface of the given create type can be
1832      * created.
1833      *
1834      * Note: the list of interfaces to be removed is EMPTY if a chip mode change is required - in
1835      * that case ALL the interfaces on the current chip have to be removed first.
1836      *
1837      * Response determined based on:
1838      * - Mode configuration: i.e. could the mode support the interface type in principle
1839      */
canCreateTypeComboSupportRequest( WifiChipInfo chipInfo, int chipModeId, int[] chipCreateTypeCombo, @HdmIfaceTypeForCreation int requestedCreateType, WorkSource requestorWs)1840     private IfaceCreationData canCreateTypeComboSupportRequest(
1841             WifiChipInfo chipInfo,
1842             int chipModeId,
1843             int[] chipCreateTypeCombo,
1844             @HdmIfaceTypeForCreation int requestedCreateType,
1845             WorkSource requestorWs) {
1846         if (VDBG) {
1847             Log.d(TAG, "canCreateTypeComboSupportRequest: chipInfo=" + chipInfo
1848                     + ", chipModeId=" + chipModeId
1849                     + ", chipCreateTypeCombo=" + Arrays.toString(chipCreateTypeCombo)
1850                     + ", requestedCreateType=" + requestedCreateType
1851                     + ", requestorWs=" + requestorWs);
1852         }
1853 
1854         // short-circuit: does the combo even support the requested type?
1855         if (chipCreateTypeCombo[requestedCreateType] == 0) {
1856             if (VDBG) Log.d(TAG, "Requested create type not supported by combo");
1857             return null;
1858         }
1859 
1860         IfaceCreationData ifaceCreationData = new IfaceCreationData();
1861         ifaceCreationData.chipInfo = chipInfo;
1862         ifaceCreationData.chipModeId = chipModeId;
1863 
1864         boolean isChipModeChangeProposed =
1865                 chipInfo.currentModeIdValid && chipInfo.currentModeId != chipModeId;
1866 
1867         // short-circuit: can't change chip-mode if an existing interface on this chip has a higher
1868         // priority than the requested interface
1869         if (isChipModeChangeProposed) {
1870             for (int existingCreateType : CREATE_TYPES_BY_PRIORITY) {
1871                 WifiIfaceInfo[] createTypeIfaces = chipInfo.ifaces[existingCreateType];
1872                 if (selectInterfacesToDelete(createTypeIfaces.length, requestedCreateType,
1873                         requestorWs, existingCreateType, createTypeIfaces) == null) {
1874                     if (VDBG) {
1875                         Log.d(TAG, "Couldn't delete existing create type "
1876                                 + existingCreateType + " interfaces for requested type");
1877                     }
1878                     return null;
1879                 }
1880             }
1881 
1882             // but if priority allows the mode change then we're good to go
1883             return ifaceCreationData;
1884         }
1885 
1886         // possibly supported
1887         for (int existingCreateType : CREATE_TYPES_BY_PRIORITY) {
1888             WifiIfaceInfo[] createTypeIfaces = chipInfo.ifaces[existingCreateType];
1889             int numExcessIfaces = createTypeIfaces.length - chipCreateTypeCombo[existingCreateType];
1890             // need to count the requested create type as well
1891             if (existingCreateType == requestedCreateType) {
1892                 numExcessIfaces += 1;
1893             }
1894             if (numExcessIfaces > 0) { // may need to delete some
1895                 // Try downgrading bridged APs before we consider deleting them.
1896                 if (existingCreateType == HDM_CREATE_IFACE_AP_BRIDGE) {
1897                     int availableSingleApCapacity = chipCreateTypeCombo[HDM_CREATE_IFACE_AP]
1898                             - chipInfo.ifaces[HDM_CREATE_IFACE_AP].length;
1899                     if (requestedCreateType == HDM_CREATE_IFACE_AP) {
1900                         availableSingleApCapacity -= 1;
1901                     }
1902                     if (availableSingleApCapacity >= numExcessIfaces) {
1903                         List<WifiIfaceInfo> interfacesToBeDowngraded =
1904                                 selectBridgedApInterfacesToDowngrade(
1905                                         numExcessIfaces, createTypeIfaces);
1906                         if (interfacesToBeDowngraded != null) {
1907                             ifaceCreationData.interfacesToBeDowngraded.addAll(
1908                                     interfacesToBeDowngraded);
1909                             continue;
1910                         }
1911                         // Can't downgrade enough bridged APs, fall through to delete them.
1912                         if (VDBG) {
1913                             Log.d(TAG, "Could not downgrade enough bridged APs for request.");
1914                         }
1915                     }
1916                 }
1917                 List<WifiIfaceInfo> selectedIfacesToDelete =
1918                         selectInterfacesToDelete(numExcessIfaces, requestedCreateType, requestorWs,
1919                                 existingCreateType, createTypeIfaces);
1920                 if (selectedIfacesToDelete == null) {
1921                     if (VDBG) {
1922                         Log.d(TAG, "Would need to delete some higher priority interfaces");
1923                     }
1924                     return null;
1925                 }
1926                 ifaceCreationData.interfacesToBeRemovedFirst.addAll(selectedIfacesToDelete);
1927             }
1928         }
1929         return ifaceCreationData;
1930     }
1931 
1932     /**
1933      * Compares two options to create an interface and determines which is the 'best'. Returns
1934      * true if proposal 1 (val1) is better, other false.
1935      *
1936      * Note: both proposals are 'acceptable' bases on priority criteria.
1937      *
1938      * Criteria:
1939      * - Proposal is better if it means removing fewer high priority interfaces, or downgrades the
1940      *   fewest interfaces.
1941      */
compareIfaceCreationData(IfaceCreationData val1, IfaceCreationData val2)1942     private boolean compareIfaceCreationData(IfaceCreationData val1, IfaceCreationData val2) {
1943         if (VDBG) Log.d(TAG, "compareIfaceCreationData: val1=" + val1 + ", val2=" + val2);
1944 
1945         // deal with trivial case of one or the other being null
1946         if (val1 == null) {
1947             return false;
1948         } else if (val2 == null) {
1949             return true;
1950         }
1951 
1952         int[] val1NumIfacesToBeRemoved = new int[CREATE_TYPES_BY_PRIORITY.length];
1953         if (val1.chipInfo.currentModeIdValid
1954                 && val1.chipInfo.currentModeId != val1.chipModeId) {
1955             for (int createType : CREATE_TYPES_BY_PRIORITY) {
1956                 val1NumIfacesToBeRemoved[createType] = val1.chipInfo.ifaces[createType].length;
1957             }
1958         } else {
1959             for (WifiIfaceInfo ifaceToRemove : val1.interfacesToBeRemovedFirst) {
1960                 val1NumIfacesToBeRemoved[ifaceToRemove.createType]++;
1961             }
1962         }
1963         int[] val2NumIfacesToBeRemoved = new int[CREATE_TYPES_BY_PRIORITY.length];
1964         if (val2.chipInfo.currentModeIdValid
1965                 && val2.chipInfo.currentModeId != val2.chipModeId) {
1966             for (int createType : CREATE_TYPES_BY_PRIORITY) {
1967                 val2NumIfacesToBeRemoved[createType] = val2.chipInfo.ifaces[createType].length;
1968             }
1969         } else {
1970             for (WifiIfaceInfo ifaceToRemove : val2.interfacesToBeRemovedFirst) {
1971                 val2NumIfacesToBeRemoved[ifaceToRemove.createType]++;
1972             }
1973         }
1974 
1975         for (int createType: CREATE_TYPES_BY_PRIORITY) {
1976             if (val1NumIfacesToBeRemoved[createType] != val2NumIfacesToBeRemoved[createType]) {
1977                 if (VDBG) {
1978                     Log.d(TAG, "decision based on num ifaces to be removed, createType="
1979                             + createType + ", new proposal will remove "
1980                             + val1NumIfacesToBeRemoved[createType] + " iface, and old proposal"
1981                             + "will remove " + val2NumIfacesToBeRemoved[createType] + " iface");
1982                 }
1983                 return val1NumIfacesToBeRemoved[createType] < val2NumIfacesToBeRemoved[createType];
1984             }
1985         }
1986 
1987         int val1NumIFacesToBeDowngraded = val1.interfacesToBeDowngraded.size();
1988         int val2NumIFacesToBeDowngraded = val2.interfacesToBeDowngraded.size();
1989         if (val1NumIFacesToBeDowngraded != val2NumIFacesToBeDowngraded) {
1990             return val1NumIFacesToBeDowngraded < val2NumIFacesToBeDowngraded;
1991         }
1992 
1993         // arbitrary - flip a coin
1994         if (VDBG) Log.d(TAG, "proposals identical - flip a coin");
1995         return false;
1996     }
1997 
1998     /**
1999      * Returns whether interface request from |newRequestorWsPriority| is allowed to delete an
2000      * interface request from |existingRequestorWsPriority|.
2001      *
2002      * Rule:
2003      *  - If |newRequestorWsPriority| > |existingRequestorWsPriority|, then YES.
2004      *  - If they are at the same priority level, then
2005      *      - If both are privileged and not for the same interface type, then YES.
2006      *      - Else, NO.
2007      */
allowedToDelete( @dmIfaceTypeForCreation int requestedCreateType, @NonNull WorkSourceHelper newRequestorWs, @NonNull WifiIfaceInfo existingIfaceInfo)2008     private boolean allowedToDelete(
2009             @HdmIfaceTypeForCreation int requestedCreateType,
2010             @NonNull WorkSourceHelper newRequestorWs, @NonNull WifiIfaceInfo existingIfaceInfo) {
2011         int existingCreateType = existingIfaceInfo.createType;
2012         WorkSourceHelper existingRequestorWs = existingIfaceInfo.requestorWsHelper;
2013         @WorkSourceHelper.RequestorWsPriority int newRequestorWsPriority =
2014                 newRequestorWs.getRequestorWsPriority();
2015         @WorkSourceHelper.RequestorWsPriority int existingRequestorWsPriority =
2016                 existingRequestorWs.getRequestorWsPriority();
2017         if (!SdkLevel.isAtLeastS()) {
2018             return allowedToDeleteForR(requestedCreateType, existingCreateType);
2019         }
2020 
2021         // Special case to let other requesters delete secondary internet STAs
2022         if (existingCreateType == HDM_CREATE_IFACE_STA
2023                 && newRequestorWsPriority > WorkSourceHelper.PRIORITY_BG) {
2024             ConcreteClientModeManager cmm = mClientModeManagers.get(existingIfaceInfo.name);
2025             if (cmm != null && cmm.isSecondaryInternet()) {
2026                 if (mDbg) {
2027                     Log.i(TAG, "Requested create type " + requestedCreateType + " from "
2028                             + newRequestorWs + " can delete secondary internet STA from "
2029                             + existingRequestorWs);
2030                 }
2031                 return true;
2032             }
2033         }
2034 
2035         // Allow FG apps to delete any disconnected P2P iface if they are older than
2036         // config_disconnectedP2pIfaceLowPriorityTimeoutMs.
2037         int unusedP2pTimeoutMs = mContext.getResources().getInteger(
2038                 R.integer.config_disconnectedP2pIfaceLowPriorityTimeoutMs);
2039         if (newRequestorWsPriority > WorkSourceHelper.PRIORITY_BG
2040                 && existingCreateType == HDM_CREATE_IFACE_P2P
2041                 && !mIsP2pConnected
2042                 && unusedP2pTimeoutMs >= 0) {
2043             InterfaceCacheEntry ifaceCacheEntry = mInterfaceInfoCache.get(
2044                     Pair.create(existingIfaceInfo.name, getType(existingIfaceInfo.iface)));
2045             if (ifaceCacheEntry != null && mClock.getElapsedSinceBootMillis()
2046                     >= ifaceCacheEntry.creationTime + unusedP2pTimeoutMs) {
2047                 if (mDbg) {
2048                     Log.i(TAG, "Allowed to delete disconnected P2P iface: " + ifaceCacheEntry);
2049                 }
2050                 return true;
2051             }
2052         }
2053 
2054         // Defer deletion decision to the InterfaceConflictManager dialog.
2055         if (mWifiInjector.getInterfaceConflictManager().needsUserApprovalToDelete(
2056                         requestedCreateType, newRequestorWs,
2057                         existingCreateType, existingRequestorWs)) {
2058             return true;
2059         }
2060 
2061         // If the new request is higher priority than existing priority, then the new requestor
2062         // wins. This is because at all other priority levels (except privileged), existing caller
2063         // wins if both the requests are at the same priority level.
2064         if (newRequestorWsPriority > existingRequestorWsPriority) {
2065             return true;
2066         }
2067         if (newRequestorWsPriority == existingRequestorWsPriority) {
2068             // If both the requests are same priority for the same iface type, the existing
2069             // requestor wins.
2070             if (requestedCreateType == existingCreateType) {
2071                 return false;
2072             }
2073             // If both the requests are privileged, the new requestor wins. The exception is for
2074             // backwards compatibility with P2P Settings, prefer SoftAP over P2P for when the user
2075             // enables SoftAP with P2P Settings open.
2076             if (newRequestorWsPriority == WorkSourceHelper.PRIORITY_PRIVILEGED) {
2077                 if (requestedCreateType == HDM_CREATE_IFACE_P2P
2078                         && (existingCreateType == HDM_CREATE_IFACE_AP
2079                         || existingCreateType == HDM_CREATE_IFACE_AP_BRIDGE)) {
2080                     return false;
2081                 }
2082                 return true;
2083             }
2084         }
2085 
2086         // Allow LOHS to beat Settings STA if there's no STA+AP concurrency (legacy behavior)
2087         if (allowedToDeleteForNoStaApConcurrencyLohs(
2088                 requestedCreateType, newRequestorWsPriority,
2089                 existingCreateType, existingRequestorWsPriority)) {
2090             return true;
2091         }
2092 
2093         return false;
2094     }
2095 
2096     /**
2097      * Returns true if the requested iface is a LOHS trying to delete a Settings STA on a device
2098      * that doesn't support STA + AP concurrency, false otherwise.
2099      */
allowedToDeleteForNoStaApConcurrencyLohs( @dmIfaceTypeForCreation int requestedCreateType, @WorkSourceHelper.RequestorWsPriority int newRequestorWsPriority, @HdmIfaceTypeForCreation int existingCreateType, @WorkSourceHelper.RequestorWsPriority int existingRequestorWsPriority)2100     private boolean allowedToDeleteForNoStaApConcurrencyLohs(
2101             @HdmIfaceTypeForCreation int requestedCreateType,
2102             @WorkSourceHelper.RequestorWsPriority int newRequestorWsPriority,
2103             @HdmIfaceTypeForCreation int existingCreateType,
2104             @WorkSourceHelper.RequestorWsPriority int existingRequestorWsPriority) {
2105         return !canDeviceSupportCreateTypeCombo(
2106                 new SparseArray<Integer>() {{
2107                     put(HDM_CREATE_IFACE_STA, 1);
2108                     put(HDM_CREATE_IFACE_AP, 1);
2109                 }})
2110                 && (requestedCreateType == HDM_CREATE_IFACE_AP
2111                 || requestedCreateType == HDM_CREATE_IFACE_AP_BRIDGE)
2112                 && newRequestorWsPriority != WorkSourceHelper.PRIORITY_INTERNAL
2113                 && newRequestorWsPriority != WorkSourceHelper.PRIORITY_PRIVILEGED
2114                 && existingCreateType == HDM_CREATE_IFACE_STA
2115                 && existingRequestorWsPriority == WorkSourceHelper.PRIORITY_PRIVILEGED;
2116     }
2117 
2118     /**
2119      * Returns true if we're allowed to delete the existing interface type for the requested
2120      * interface type.
2121      *
2122      * Rules - applies in order:
2123      *
2124      * General rules:
2125      * 1. No interface will be destroyed for a requested interface of the same type
2126      *
2127      * Type-specific rules (but note that the general rules are applied first):
2128      * 2. Request for AP or STA will destroy any other interface
2129      * 3. Request for P2P will destroy NAN-only
2130      * 4. Request for NAN will destroy P2P-only
2131      */
2132     private static boolean allowedToDeleteForR(
2133             @HdmIfaceTypeForCreation int requestedCreateType,
2134             @HdmIfaceTypeForCreation int existingCreateType) {
2135         // rule 1
2136         if (existingCreateType == requestedCreateType) {
2137             return false;
2138         }
2139 
2140         // rule 2
2141         if (requestedCreateType == HDM_CREATE_IFACE_P2P) {
2142             return existingCreateType == HDM_CREATE_IFACE_NAN;
2143         }
2144 
2145         // rule 3
2146         if (requestedCreateType == HDM_CREATE_IFACE_NAN) {
2147             return existingCreateType == HDM_CREATE_IFACE_P2P;
2148         }
2149 
2150         // rule 4, the requestedCreateType is either AP/AP_BRIDGED or STA
2151         return true;
2152     }
2153 
2154     /**
2155      * Selects the interfaces of a given type and quantity to delete for a requested interface.
2156      * If the specified quantity of interfaces cannot be deleted, returns null.
2157      *
2158      * Only interfaces with lower priority than the requestor will be selected, in ascending order
2159      * of priority. Priority is determined by the following rules:
2160      * 1. Requests for interfaces have the following priority which are based on corresponding
2161      * requesting  app's context. Priorities in decreasing order (i.e (i) has the highest priority,
2162      * (v) has the lowest priority).
2163      *  - (i) Requests from privileged apps (i.e settings, setup wizard, connectivity stack, etc)
2164      *  - (ii) Requests from system apps.
2165      *  - (iii) Requests from foreground apps.
2166      *  - (iv) Requests from foreground services.
2167      *  - (v) Requests from everything else (lumped together as "background").
2168      * Note: If there are more than 1 app requesting for a particular interface, then we consider
2169      * the priority of the highest priority app among them.
2170      * For ex: If there is a system app and a foreground requesting for NAN iface, then we use the
2171      * system app to determine the priority of the interface request.
2172      * 2. If there are 2 conflicting interface requests from apps with the same priority, then
2173      *    - (i) If both the apps are privileged and not for the same interface type, the new request
2174      *          wins (last caller wins).
2175      *    - (ii) Else, the existing request wins (first caller wins).
2176      * Note: Privileged apps are the ones that the user is directly interacting with, hence we use
2177      * last caller wins to decide among those, for all other apps we try to minimize disruption to
2178      * existing requests.
2179      * For ex: User turns on wifi, then hotspot on legacy devices which do not support STA + AP, we
2180      * want the last request from the user (i.e hotspot) to be honored.
2181      *
2182      * @param requestedQuantity Number of interfaces which need to be selected.
2183      * @param requestedCreateType Requested iface type.
2184      * @param requestorWs Requestor worksource.
2185      * @param existingCreateType Existing iface type.
2186      * @param existingInterfaces Array of interfaces to be selected from in order of creation.
2187      */
2188     private List<WifiIfaceInfo> selectInterfacesToDelete(int requestedQuantity,
2189             @HdmIfaceTypeForCreation int requestedCreateType, @NonNull WorkSource requestorWs,
2190             @HdmIfaceTypeForCreation int existingCreateType,
2191             @NonNull WifiIfaceInfo[] existingInterfaces) {
2192         if (VDBG) {
2193             Log.d(TAG, "selectInterfacesToDelete: requestedQuantity=" + requestedQuantity
2194                     + ", requestedCreateType=" + requestedCreateType
2195                     + ", requestorWs=" + requestorWs
2196                     + ", existingCreateType=" + existingCreateType
2197                     + ", existingInterfaces=" + Arrays.toString(existingInterfaces));
2198         }
2199         WorkSourceHelper newRequestorWsHelper = mWifiInjector.makeWsHelper(requestorWs);
2200 
2201         boolean lookupError = false;
2202         // Map of priority levels to ifaces to delete.
2203         Map<Integer, List<WifiIfaceInfo>> ifacesToDeleteMap = new HashMap<>();
2204         // Reverse order to make sure later created interfaces deleted firstly
2205         for (int i = existingInterfaces.length - 1; i >= 0; i--) {
2206             WifiIfaceInfo info = existingInterfaces[i];
2207             InterfaceCacheEntry cacheEntry;
2208             synchronized (mLock) {
2209                 cacheEntry = mInterfaceInfoCache.get(Pair.create(info.name, getType(info.iface)));
2210             }
2211             if (cacheEntry == null) {
2212                 Log.e(TAG,
2213                         "selectInterfacesToDelete: can't find cache entry with name=" + info.name);
2214                 lookupError = true;
2215                 break;
2216             }
2217             int newRequestorWsPriority = newRequestorWsHelper.getRequestorWsPriority();
2218             int existingRequestorWsPriority = cacheEntry.requestorWsHelper.getRequestorWsPriority();
2219             boolean isAllowedToDelete = allowedToDelete(requestedCreateType, newRequestorWsHelper,
2220                     info);
2221             if (VDBG) {
2222                 Log.d(TAG, "info=" + info + ":  allowedToDelete=" + isAllowedToDelete
2223                         + " (requestedCreateType=" + requestedCreateType
2224                         + ", newRequestorWsPriority=" + newRequestorWsPriority
2225                         + ", existingCreateType=" + existingCreateType
2226                         + ", existingRequestorWsPriority=" + existingRequestorWsPriority + ")");
2227             }
2228             if (isAllowedToDelete) {
2229                 ifacesToDeleteMap.computeIfAbsent(
2230                         existingRequestorWsPriority, v -> new ArrayList<>()).add(info);
2231             }
2232         }
2233 
2234         List<WifiIfaceInfo> ifacesToDelete;
2235         if (lookupError) {
2236             Log.e(TAG, "selectInterfacesToDelete: falling back to arbitrary selection");
2237             ifacesToDelete = Arrays.asList(Arrays.copyOf(existingInterfaces, requestedQuantity));
2238         } else {
2239             int numIfacesToDelete = 0;
2240             ifacesToDelete = new ArrayList<>(requestedQuantity);
2241             // Iterate from lowest priority to highest priority ifaces.
2242             for (int i = WorkSourceHelper.PRIORITY_MIN; i <= WorkSourceHelper.PRIORITY_MAX; i++) {
2243                 List<WifiIfaceInfo> ifacesToDeleteListWithinPriority =
2244                         ifacesToDeleteMap.getOrDefault(i, new ArrayList<>());
2245                 int numIfacesToDeleteWithinPriority =
2246                         Math.min(requestedQuantity - numIfacesToDelete,
2247                                 ifacesToDeleteListWithinPriority.size());
2248                 ifacesToDelete.addAll(
2249                         ifacesToDeleteListWithinPriority.subList(
2250                                 0, numIfacesToDeleteWithinPriority));
2251                 numIfacesToDelete += numIfacesToDeleteWithinPriority;
2252                 if (numIfacesToDelete == requestedQuantity) {
2253                     break;
2254                 }
2255             }
2256         }
2257         if (ifacesToDelete.size() < requestedQuantity) {
2258             return null;
2259         }
2260         return ifacesToDelete;
2261     }
2262 
2263     /**
2264      * Selects the requested quantity of bridged AP ifaces available for downgrade in order of
2265      * creation, or returns null if the requested quantity cannot be satisfied.
2266      *
2267      * @param requestedQuantity Number of interfaces which need to be selected
2268      * @param bridgedApIfaces Array of bridged AP interfaces in order of creation
2269      */
2270     private List<WifiIfaceInfo> selectBridgedApInterfacesToDowngrade(int requestedQuantity,
2271             WifiIfaceInfo[] bridgedApIfaces) {
2272         List<WifiIfaceInfo> ifacesToDowngrade = new ArrayList<>();
2273         for (WifiIfaceInfo ifaceInfo : bridgedApIfaces) {
2274             String name = getName(ifaceInfo.iface);
2275             if (name == null) {
2276                 continue;
2277             }
2278             SoftApManager softApManager = mSoftApManagers.get(name);
2279             if (softApManager == null) {
2280                 Log.e(TAG, "selectBridgedApInterfacesToDowngrade: Could not find SoftApManager for"
2281                         + " iface: " + ifaceInfo.iface);
2282                 continue;
2283             }
2284             String instanceForRemoval =
2285                     softApManager.getBridgedApDowngradeIfaceInstanceForRemoval();
2286             if (instanceForRemoval == null) {
2287                 continue;
2288             }
2289             ifacesToDowngrade.add(ifaceInfo);
2290             if (ifacesToDowngrade.size() >= requestedQuantity) {
2291                 break;
2292             }
2293         }
2294         if (ifacesToDowngrade.size() < requestedQuantity) {
2295             return null;
2296         }
2297         if (VDBG) {
2298             Log.i(TAG, "selectBridgedApInterfacesToDowngrade: ifaces to downgrade "
2299                     + ifacesToDowngrade);
2300         }
2301         return ifacesToDowngrade;
2302     }
2303 
2304     /**
2305      * Checks whether the expanded @HdmIfaceTypeForCreation combo can support the requested combo.
2306      */
2307     private boolean canCreateTypeComboSupportRequestedCreateTypeCombo(
2308             int[] chipCombo, int[] requestedCombo) {
2309         if (VDBG) {
2310             Log.d(TAG, "canCreateTypeComboSupportRequestedCreateTypeCombo: "
2311                     + "chipCombo=" + Arrays.toString(chipCombo)
2312                     + ", requestedCombo=" + Arrays.toString(requestedCombo));
2313         }
2314         for (int createType : CREATE_TYPES_BY_PRIORITY) {
2315             if (chipCombo[createType]
2316                     < requestedCombo[createType]) {
2317                 if (VDBG) Log.d(TAG, "Requested type not supported by combo");
2318                 return false;
2319             }
2320         }
2321         return true;
2322     }
2323 
2324     /**
2325      * Performs chip reconfiguration per the input:
2326      * - Removes the specified interfaces
2327      * - Reconfigures the chip to the new chip mode (if necessary)
2328      * - Creates the new interface
2329      *
2330      * Returns the newly created interface or a null on any error.
2331      */
2332     private WifiHal.WifiInterface executeChipReconfiguration(IfaceCreationData ifaceCreationData,
2333             @HdmIfaceTypeForCreation int createIfaceType) {
2334         if (mDbg) {
2335             Log.d(TAG, "executeChipReconfiguration: ifaceCreationData=" + ifaceCreationData
2336                     + ", createIfaceType=" + createIfaceType);
2337         }
2338         synchronized (mLock) {
2339             // is this a mode change?
2340             boolean isModeConfigNeeded = !ifaceCreationData.chipInfo.currentModeIdValid
2341                     || ifaceCreationData.chipInfo.currentModeId != ifaceCreationData.chipModeId;
2342             if (mDbg) Log.d(TAG, "isModeConfigNeeded=" + isModeConfigNeeded);
2343             Log.i(TAG, "currentModeId=" + ifaceCreationData.chipInfo.currentModeId
2344                     + ", requestModeId=" + ifaceCreationData.chipModeId
2345                     + ", currentModeIdValid=" + ifaceCreationData.chipInfo.currentModeIdValid);
2346 
2347             // first delete interfaces/change modes
2348             if (isModeConfigNeeded) {
2349                 // remove all interfaces pre mode-change
2350                 // TODO: is this necessary? note that even if we don't want to explicitly
2351                 // remove the interfaces we do need to call the onDeleted callbacks - which
2352                 // this does
2353                 for (WifiIfaceInfo[] ifaceInfos : ifaceCreationData.chipInfo.ifaces) {
2354                     for (WifiIfaceInfo ifaceInfo : ifaceInfos) {
2355                         removeIfaceInternal(ifaceInfo.iface,
2356                                 /* validateRttController */false); // ignore return value
2357                     }
2358                 }
2359 
2360                 boolean success = ifaceCreationData.chipInfo.chip.configureChip(
2361                         ifaceCreationData.chipModeId);
2362                 if (!success) {
2363                     Log.e(TAG, "executeChipReconfiguration: configureChip error");
2364                     return null;
2365                 }
2366                 if (!mIsConcurrencyComboLoadedFromDriver) {
2367                     WifiChipInfo[] wifiChipInfos = getAllChipInfo();
2368                     if (wifiChipInfos != null) {
2369                         mCachedStaticChipInfos =
2370                                 convertWifiChipInfoToStaticChipInfos(wifiChipInfos);
2371                         saveStaticChipInfoToStore(mCachedStaticChipInfos);
2372                         mIsConcurrencyComboLoadedFromDriver = true;
2373                     } else {
2374                         Log.e(TAG, "Configured chip but could not get current chip info.");
2375                     }
2376                 }
2377             } else {
2378                 // remove all interfaces on the delete list
2379                 for (WifiIfaceInfo ifaceInfo : ifaceCreationData.interfacesToBeRemovedFirst) {
2380                     removeIfaceInternal(ifaceInfo.iface,
2381                             /* validateRttController */false); // ignore return value
2382                 }
2383                 // downgrade all interfaces on the downgrade list
2384                 for (WifiIfaceInfo ifaceInfo : ifaceCreationData.interfacesToBeDowngraded) {
2385                     if (ifaceInfo.createType == HDM_CREATE_IFACE_AP_BRIDGE) {
2386                         if (!downgradeBridgedApIface(ifaceInfo)) {
2387                             Log.e(TAG, "executeChipReconfiguration: failed to downgrade bridged"
2388                                     + " AP: " + ifaceInfo);
2389                             return null;
2390                         }
2391                     }
2392                 }
2393             }
2394 
2395             // create new interface
2396             WifiHal.WifiInterface iface = null;
2397             switch (createIfaceType) {
2398                 case HDM_CREATE_IFACE_STA:
2399                     iface = ifaceCreationData.chipInfo.chip.createStaIface();
2400                     break;
2401                 case HDM_CREATE_IFACE_AP_BRIDGE:
2402                     iface = ifaceCreationData.chipInfo.chip.createBridgedApIface();
2403                     break;
2404                 case HDM_CREATE_IFACE_AP:
2405                     iface = ifaceCreationData.chipInfo.chip.createApIface();
2406                     break;
2407                 case HDM_CREATE_IFACE_P2P:
2408                     iface = ifaceCreationData.chipInfo.chip.createP2pIface();
2409                     break;
2410                 case HDM_CREATE_IFACE_NAN:
2411                     iface = ifaceCreationData.chipInfo.chip.createNanIface();
2412                     break;
2413             }
2414 
2415             updateRttControllerWhenInterfaceChanges();
2416 
2417             if (iface == null) {
2418                 Log.e(TAG, "executeChipReconfiguration: failed to create interface"
2419                         + " createIfaceType=" + createIfaceType);
2420                 return null;
2421             }
2422 
2423             return iface;
2424         }
2425     }
2426 
2427     /**
2428      * Remove a Iface from IWifiChip.
2429      * @param iface the interface need to be removed
2430      * @param validateRttController if RttController validation is required. If any iface creation
2431      *                              is guaranteed after removing iface, this can be false. Otherwise
2432      *                              this must be true.
2433      * @return True if removal succeed, otherwise false.
2434      */
2435     private boolean removeIfaceInternal(WifiHal.WifiInterface iface,
2436             boolean validateRttController) {
2437         String name = getName(iface);
2438         int type = getType(iface);
2439         if (mDbg) Log.d(TAG, "removeIfaceInternal: iface(name)=" + name + ", type=" + type);
2440 
2441         if (type == -1) {
2442             Log.e(TAG, "removeIfaceInternal: can't get type -- iface(name)=" + name);
2443             return false;
2444         }
2445 
2446         synchronized (mLock) {
2447             WifiChip chip = getChip(iface);
2448             if (chip == null) {
2449                 Log.e(TAG, "removeIfaceInternal: null IWifiChip -- iface(name)=" + name);
2450                 return false;
2451             }
2452 
2453             if (name == null) {
2454                 Log.e(TAG, "removeIfaceInternal: can't get name");
2455                 return false;
2456             }
2457 
2458             // dispatch listeners on other threads to prevent race conditions in case the HAL is
2459             // blocking and they get notification about destruction from HAL before cleaning up
2460             // status.
2461             dispatchDestroyedListeners(name, type, true);
2462 
2463             boolean success = false;
2464             switch (type) {
2465                 case WifiChip.IFACE_TYPE_STA:
2466                     mClientModeManagers.remove(name);
2467                     success = chip.removeStaIface(name);
2468                     break;
2469                 case WifiChip.IFACE_TYPE_AP:
2470                     success = chip.removeApIface(name);
2471                     break;
2472                 case WifiChip.IFACE_TYPE_P2P:
2473                     success = chip.removeP2pIface(name);
2474                     break;
2475                 case WifiChip.IFACE_TYPE_NAN:
2476                     success = chip.removeNanIface(name);
2477                     break;
2478                 default:
2479                     Log.wtf(TAG, "removeIfaceInternal: invalid type=" + type);
2480                     return false;
2481             }
2482 
2483             // dispatch listeners no matter what status
2484             dispatchDestroyedListeners(name, type, false);
2485             if (validateRttController) {
2486                 // Try to update the RttController
2487                 updateRttControllerWhenInterfaceChanges();
2488             }
2489 
2490             if (success) {
2491                 return true;
2492             } else {
2493                 Log.e(TAG, "IWifiChip.removeXxxIface failed, name=" + name + ", type=" + type);
2494                 return false;
2495             }
2496         }
2497     }
2498 
2499     // dispatch all destroyed listeners registered for the specified interface AND remove the
2500     // cache entries for the called listeners
2501     // onlyOnOtherThreads = true: only call listeners on other threads
2502     // onlyOnOtherThreads = false: call all listeners
2503     private void dispatchDestroyedListeners(String name, int type, boolean onlyOnOtherThreads) {
2504         if (VDBG) Log.d(TAG, "dispatchDestroyedListeners: iface(name)=" + name);
2505 
2506         List<InterfaceDestroyedListenerProxy> triggerList = new ArrayList<>();
2507         synchronized (mLock) {
2508             InterfaceCacheEntry entry = mInterfaceInfoCache.get(Pair.create(name, type));
2509             if (entry == null) {
2510                 Log.e(TAG, "dispatchDestroyedListeners: no cache entry for iface(name)=" + name);
2511                 return;
2512             }
2513 
2514             Iterator<InterfaceDestroyedListenerProxy> iterator =
2515                     entry.destroyedListeners.iterator();
2516             while (iterator.hasNext()) {
2517                 InterfaceDestroyedListenerProxy listener = iterator.next();
2518                 if (!onlyOnOtherThreads || !listener.requestedToRunInCurrentThread()) {
2519                     triggerList.add(listener);
2520                     iterator.remove();
2521                 }
2522             }
2523             if (!onlyOnOtherThreads) { // leave entry until final call to *all* callbacks
2524                 mInterfaceInfoCache.remove(Pair.create(name, type));
2525             }
2526         }
2527 
2528         for (InterfaceDestroyedListenerProxy listener : triggerList) {
2529             listener.trigger(isWaitForDestroyedListenersMockable());
2530         }
2531     }
2532 
2533     // dispatch all destroyed listeners registered to all interfaces
2534     private void dispatchAllDestroyedListeners() {
2535         if (VDBG) Log.d(TAG, "dispatchAllDestroyedListeners");
2536 
2537         List<InterfaceDestroyedListenerProxy> triggerList = new ArrayList<>();
2538         synchronized (mLock) {
2539             for (InterfaceCacheEntry cacheEntry: mInterfaceInfoCache.values()) {
2540                 for (InterfaceDestroyedListenerProxy listener : cacheEntry.destroyedListeners) {
2541                     triggerList.add(listener);
2542                 }
2543                 cacheEntry.destroyedListeners.clear(); // for insurance
2544             }
2545             mInterfaceInfoCache.clear();
2546         }
2547 
2548         for (InterfaceDestroyedListenerProxy listener : triggerList) {
2549             listener.trigger(false);
2550         }
2551     }
2552 
2553     private boolean downgradeBridgedApIface(WifiIfaceInfo bridgedApIfaceInfo) {
2554         String name = getName(bridgedApIfaceInfo.iface);
2555         if (name == null) {
2556             return false;
2557         }
2558         SoftApManager bridgedSoftApManager = mSoftApManagers.get(name);
2559         if (bridgedSoftApManager == null) {
2560             Log.e(TAG, "Could not find SoftApManager for bridged AP iface " + name);
2561             return false;
2562         }
2563         WifiChip chip = getChip(bridgedApIfaceInfo.iface);
2564         if (chip == null) {
2565             return false;
2566         }
2567         String instanceForRemoval =
2568                 bridgedSoftApManager.getBridgedApDowngradeIfaceInstanceForRemoval();
2569         return chip.removeIfaceInstanceFromBridgedApIface(name, instanceForRemoval);
2570     }
2571 
2572     private abstract class ListenerProxy<LISTENER>  {
2573         protected LISTENER mListener;
2574         private Handler mHandler;
2575 
2576         // override equals & hash to make sure that the container HashSet is unique with respect to
2577         // the contained listener
2578         @Override
2579         public boolean equals(Object obj) {
2580             return mListener == ((ListenerProxy<LISTENER>) obj).mListener;
2581         }
2582 
2583         @Override
2584         public int hashCode() {
2585             return mListener.hashCode();
2586         }
2587 
2588         public boolean requestedToRunInCurrentThread() {
2589             if (mHandler == null) return true;
2590             long currentTid = mWifiInjector.getCurrentThreadId();
2591             long handlerTid = mHandler.getLooper().getThread().getId();
2592             return currentTid == handlerTid;
2593         }
2594 
2595         void trigger(boolean isRunAtFront) {
2596             // TODO(b/199792691): The thread check is needed to preserve the existing
2597             //  assumptions of synchronous execution of the "onDestroyed" callback as much as
2598             //  possible. This is needed to prevent regressions caused by posting to the handler
2599             //  thread changing the code execution order.
2600             //  When all wifi services (ie. WifiAware, WifiP2p) get moved to the wifi handler
2601             //  thread, remove this thread check and the Handler#post() and simply always
2602             //  invoke the callback directly.
2603             if (requestedToRunInCurrentThread()) {
2604                 // Already running on the same handler thread. Trigger listener synchronously.
2605                 action();
2606             } else if (isRunAtFront) {
2607                 // Current thread is not the thread the listener should be invoked on.
2608                 // Post action to the intended thread and run synchronously.
2609                 new WifiThreadRunner(mHandler).runAtFront(() -> {
2610                     action();
2611                 });
2612             } else {
2613                 // Current thread is not the thread the listener should be invoked on.
2614                 // Post action to the intended thread.
2615                 if (mHandler instanceof RunnerHandler) {
2616                     RunnerHandler rh = (RunnerHandler) mHandler;
2617                     rh.postToFront(() -> action());
2618                 } else {
2619                     mHandler.postAtFrontOfQueue(() -> action());
2620                 }
2621             }
2622         }
2623 
2624         protected void action() {}
2625 
2626         ListenerProxy(LISTENER listener, Handler handler, String tag) {
2627             mListener = listener;
2628             mHandler = handler;
2629         }
2630     }
2631 
2632     private class SubsystemRestartListenerProxy extends
2633             ListenerProxy<SubsystemRestartListener> {
2634         SubsystemRestartListenerProxy(@NonNull SubsystemRestartListener subsystemRestartListener,
2635                                         Handler handler) {
2636             super(subsystemRestartListener, handler, "SubsystemRestartListenerProxy");
2637         }
2638 
2639         @Override
2640         protected void action() {
2641             mListener.onSubsystemRestart();
2642         }
2643     }
2644 
2645     private class InterfaceDestroyedListenerProxy extends
2646             ListenerProxy<InterfaceDestroyedListener> {
2647         private final String mIfaceName;
2648         InterfaceDestroyedListenerProxy(@NonNull String ifaceName,
2649                                         @NonNull InterfaceDestroyedListener destroyedListener,
2650                                         @NonNull Handler handler) {
2651             super(destroyedListener, handler, "InterfaceDestroyedListenerProxy");
2652             mIfaceName = ifaceName;
2653         }
2654 
2655         @Override
2656         protected void action() {
2657             mListener.onDestroyed(mIfaceName);
2658         }
2659     }
2660 
2661     private class InterfaceRttControllerLifecycleCallbackProxy implements
2662             InterfaceRttControllerLifecycleCallback {
2663         private InterfaceRttControllerLifecycleCallback mCallback;
2664         private Handler mHandler;
2665 
2666         InterfaceRttControllerLifecycleCallbackProxy(
2667                 InterfaceRttControllerLifecycleCallback callback, Handler handler) {
2668             mCallback = callback;
2669             mHandler = handler;
2670         }
2671 
2672         // override equals & hash to make sure that the container HashSet is unique with respect to
2673         // the contained listener
2674         @Override
2675         public boolean equals(Object obj) {
2676             return mCallback == ((InterfaceRttControllerLifecycleCallbackProxy) obj).mCallback;
2677         }
2678 
2679         @Override
2680         public int hashCode() {
2681             return mCallback.hashCode();
2682         }
2683 
2684         @Override
2685         public void onNewRttController(WifiRttController controller) {
2686             mHandler.post(() -> mCallback.onNewRttController(controller));
2687         }
2688 
2689         @Override
2690         public void onRttControllerDestroyed() {
2691             mHandler.post(() -> mCallback.onRttControllerDestroyed());
2692         }
2693     }
2694 
2695     private void dispatchRttControllerLifecycleOnNew() {
2696         if (VDBG) {
2697             Log.v(TAG, "dispatchRttControllerLifecycleOnNew: # cbs="
2698                     + mRttControllerLifecycleCallbacks.size());
2699         }
2700         for (InterfaceRttControllerLifecycleCallbackProxy cbp : mRttControllerLifecycleCallbacks) {
2701             cbp.onNewRttController(mWifiRttController);
2702         }
2703     }
2704 
2705     private void dispatchRttControllerLifecycleOnDestroyed() {
2706         for (InterfaceRttControllerLifecycleCallbackProxy cbp : mRttControllerLifecycleCallbacks) {
2707             cbp.onRttControllerDestroyed();
2708         }
2709     }
2710 
2711     /**
2712      * Updates the RttController when the interface changes:
2713      * - Handles callbacks to registered listeners
2714      * - Handles creation of new RttController
2715      */
2716     private void updateRttControllerWhenInterfaceChanges() {
2717         synchronized (mLock) {
2718             if (mWifiRttController != null && mWifiRttController.validate()) {
2719                 if (mDbg) {
2720                     Log.d(TAG, "Current RttController is valid, Don't try to create a new one");
2721                 }
2722                 return;
2723             }
2724             boolean controllerDestroyed = mWifiRttController != null;
2725             mWifiRttController = null;
2726             if (mRttControllerLifecycleCallbacks.size() == 0) {
2727                 Log.d(TAG, "updateRttController: no one is interested in RTT controllers");
2728                 return;
2729             }
2730 
2731             WifiRttController newRttController = createRttControllerIfPossible();
2732             if (newRttController == null) {
2733                 if (controllerDestroyed) {
2734                     dispatchRttControllerLifecycleOnDestroyed();
2735                 }
2736             } else {
2737                 mWifiRttController = newRttController;
2738                 dispatchRttControllerLifecycleOnNew();
2739             }
2740         }
2741     }
2742 
2743     /**
2744      * Try to create and set up a new RttController.
2745      *
2746      * @return The new RttController - or null on failure.
2747      */
2748     private WifiRttController createRttControllerIfPossible() {
2749         synchronized (mLock) {
2750             if (!isWifiStarted()) {
2751                 Log.d(TAG, "createRttControllerIfPossible: Wifi is not started");
2752                 return null;
2753             }
2754 
2755             WifiChipInfo[] chipInfos = getAllChipInfo();
2756             if (chipInfos == null) {
2757                 Log.d(TAG, "createRttControllerIfPossible: no chip info found - most likely chip "
2758                         + "not up yet");
2759                 return null;
2760             }
2761 
2762             for (WifiChipInfo chipInfo : chipInfos) {
2763                 if (!chipInfo.currentModeIdValid) {
2764                     if (VDBG) {
2765                         Log.d(TAG, "createRttControllerIfPossible: chip not configured yet: "
2766                                 + chipInfo);
2767                     }
2768                     continue;
2769                 }
2770 
2771                 WifiRttController rttController = chipInfo.chip.createRttController();
2772                 if (rttController != null) {
2773                     if (!rttController.setup()) {
2774                         return null;
2775                     }
2776                     rttController.enableVerboseLogging(mDbg);
2777                     return rttController;
2778                 }
2779             }
2780         }
2781 
2782         Log.w(TAG, "createRttControllerIfPossible: not available from any of the chips");
2783         return null;
2784     }
2785 
2786     // general utilities
2787 
2788     // Will return -1 for invalid results! Otherwise will return one of the 4 valid values.
2789     @VisibleForTesting
2790     protected static int getType(WifiHal.WifiInterface iface) {
2791         if (iface instanceof WifiStaIface) {
2792             return WifiChip.IFACE_TYPE_STA;
2793         } else if (iface instanceof WifiApIface) {
2794             return WifiChip.IFACE_TYPE_AP;
2795         } else if (iface instanceof WifiP2pIface) {
2796             return WifiChip.IFACE_TYPE_P2P;
2797         } else if (iface instanceof WifiNanIface) {
2798             return WifiChip.IFACE_TYPE_NAN;
2799         }
2800         return -1;
2801     }
2802 
2803     private static Set<List<Integer>> getChipSupportedBandCombinations(
2804             List<WifiChip.WifiRadioCombination> combinations) {
2805         Set<List<Integer>> lookupTable = new ArraySet<>();
2806         if (combinations == null) return lookupTable;
2807         // Add radio combinations to the lookup table.
2808         for (WifiChip.WifiRadioCombination combination : combinations) {
2809             // Build list of bands.
2810             List<Integer> bands = new ArrayList<>();
2811             for (WifiChip.WifiRadioConfiguration config : combination.radioConfigurations) {
2812                 bands.add(config.bandInfo);
2813             }
2814             // Sort the list of bands as hash code depends on the order and content of the list.
2815             Collections.sort(bands);
2816             lookupTable.add(Collections.unmodifiableList(bands));
2817         }
2818         return lookupTable;
2819     }
2820 
2821     /**
2822      * Get the chip capabilities.
2823      *
2824      * @param wifiChip WifiChip to get the features for.
2825      * @return Bitset of WifiManager.WIFI_FEATURE_* values.
2826      */
2827     public long getChipCapabilities(@NonNull WifiChip wifiChip) {
2828         if (wifiChip == null) return 0;
2829 
2830         WifiChip.Response<Long> capsResp = wifiChip.getCapabilitiesBeforeIfacesExist();
2831         if (capsResp.getStatusCode() == WifiHal.WIFI_STATUS_SUCCESS) {
2832             return capsResp.getValue();
2833         } else if (capsResp.getStatusCode() != WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION) {
2834             // Non-remote exception here is likely because HIDL HAL < v1.5
2835             // does not support getting capabilities before creating an interface.
2836             return CHIP_CAPABILITY_UNINITIALIZED;
2837         } else { // remote exception
2838             return 0;
2839         }
2840     }
2841 
2842     /**
2843      * Get the supported radio combinations.
2844      *
2845      * This is called after creating an interface and need at least v1.6 HAL.
2846      *
2847      * @param wifiChip WifiChip
2848      * @return List of supported Wifi radio combinations
2849      */
2850     private List<WifiChip.WifiRadioCombination> getChipSupportedRadioCombinations(
2851             @NonNull WifiChip wifiChip) {
2852         synchronized (mLock) {
2853             if (wifiChip == null) return null;
2854             return wifiChip.getSupportedRadioCombinations();
2855         }
2856     }
2857 
2858     /**
2859      * Initialization after boot completes to get boot-dependent resources.
2860      */
2861     public void handleBootCompleted() {
2862         Resources res = mContext.getResources();
2863         mWaitForDestroyedListeners = res.getBoolean(R.bool.config_wifiWaitForDestroyedListeners);
2864     }
2865 
2866     /**
2867      * Dump the internal state of the class.
2868      */
2869     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2870         pw.println("Dump of HalDeviceManager:");
2871         pw.println("  mManagerStatusListeners: " + mManagerStatusListeners);
2872         pw.println("  mInterfaceInfoCache: " + mInterfaceInfoCache);
2873         pw.println("  mDebugChipsInfo: " + Arrays.toString(getAllChipInfo()));
2874     }
2875 }
2876