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