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