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