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