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