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