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