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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.hardware.wifi.V1_0.IWifi; 22 import android.hardware.wifi.V1_0.IWifiApIface; 23 import android.hardware.wifi.V1_0.IWifiChip; 24 import android.hardware.wifi.V1_0.IWifiChipEventCallback; 25 import android.hardware.wifi.V1_0.IWifiEventCallback; 26 import android.hardware.wifi.V1_0.IWifiIface; 27 import android.hardware.wifi.V1_0.IWifiNanIface; 28 import android.hardware.wifi.V1_0.IWifiP2pIface; 29 import android.hardware.wifi.V1_0.IWifiRttController; 30 import android.hardware.wifi.V1_0.IWifiStaIface; 31 import android.hardware.wifi.V1_0.IfaceType; 32 import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus; 33 import android.hardware.wifi.V1_0.WifiStatus; 34 import android.hardware.wifi.V1_0.WifiStatusCode; 35 import android.hidl.manager.V1_0.IServiceManager; 36 import android.hidl.manager.V1_0.IServiceNotification; 37 import android.os.Handler; 38 import android.os.HidlSupport.Mutable; 39 import android.os.HwRemoteBinder; 40 import android.os.RemoteException; 41 import android.util.Log; 42 import android.util.LongSparseArray; 43 import android.util.MutableBoolean; 44 import android.util.MutableInt; 45 import android.util.Pair; 46 import android.util.SparseArray; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 50 import java.io.FileDescriptor; 51 import java.io.PrintWriter; 52 import java.util.ArrayList; 53 import java.util.Arrays; 54 import java.util.HashMap; 55 import java.util.HashSet; 56 import java.util.Iterator; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.Set; 60 61 /** 62 * Handles device management through the HAL (HIDL) interface. 63 */ 64 public class HalDeviceManager { 65 private static final String TAG = "HalDevMgr"; 66 private static final boolean VDBG = false; 67 private boolean mDbg = false; 68 69 private static final int START_HAL_RETRY_INTERVAL_MS = 20; 70 // Number of attempts a start() is re-tried. A value of 0 means no retries after a single 71 // attempt. 72 @VisibleForTesting 73 public static final int START_HAL_RETRY_TIMES = 3; 74 @VisibleForTesting 75 public static final String HAL_INSTANCE_NAME = "default"; 76 77 private final Clock mClock; 78 79 // public API 80 public HalDeviceManager(Clock clock) { 81 mClock = clock; 82 83 mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashMap<>()); 84 mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashMap<>()); 85 mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashMap<>()); 86 mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashMap<>()); 87 } 88 89 /* package */ void enableVerboseLogging(int verbose) { 90 if (verbose > 0) { 91 mDbg = true; 92 } else { 93 mDbg = false; 94 } 95 if (VDBG) { 96 mDbg = true; // just override 97 } 98 } 99 100 /** 101 * Actually starts the HalDeviceManager: separate from constructor since may want to phase 102 * at a later time. 103 * 104 * TODO: if decide that no need for separating construction from initialization (e.g. both are 105 * done at injector) then move to constructor. 106 */ 107 public void initialize() { 108 initializeInternal(); 109 } 110 111 /** 112 * Register a ManagerStatusListener to get information about the status of the manager. Use the 113 * isReady() and isStarted() methods to check status immediately after registration and when 114 * triggered. 115 * 116 * It is safe to re-register the same callback object - duplicates are detected and only a 117 * single copy kept. 118 * 119 * @param listener ManagerStatusListener listener object. 120 * @param handler Handler on which to dispatch listener. Null implies the listener will be 121 * invoked synchronously from the context of the client which triggered the 122 * state change. 123 */ 124 public void registerStatusListener(@NonNull ManagerStatusListener listener, 125 @Nullable Handler handler) { 126 synchronized (mLock) { 127 if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener, handler))) { 128 Log.w(TAG, "registerStatusListener: duplicate registration ignored"); 129 } 130 } 131 } 132 133 /** 134 * Returns whether the vendor HAL is supported on this device or not. 135 */ 136 public boolean isSupported() { 137 return isSupportedInternal(); 138 } 139 140 /** 141 * Returns the current status of the HalDeviceManager: whether or not it is ready to execute 142 * commands. A return of 'false' indicates that the HAL service (IWifi) is not available. Use 143 * the registerStatusListener() to listener for status changes. 144 */ 145 public boolean isReady() { 146 return mWifi != null; 147 } 148 149 /** 150 * Returns the current status of Wi-Fi: started (true) or stopped (false). 151 * 152 * Note: direct call to HIDL. 153 */ 154 public boolean isStarted() { 155 return isWifiStarted(); 156 } 157 158 /** 159 * Attempts to start Wi-Fi (using HIDL). Returns the success (true) or failure (false) or 160 * the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on 161 * success. 162 * 163 * Note: direct call to HIDL. 164 */ 165 public boolean start() { 166 return startWifi(); 167 } 168 169 /** 170 * Stops Wi-Fi. Will also dispatch any registeredManagerStatusCallback.onStop(). 171 * 172 * Note: direct call to HIDL - failure is not-expected. 173 */ 174 public void stop() { 175 stopWifi(); 176 } 177 178 /** 179 * HAL device manager status change listener. 180 */ 181 public interface ManagerStatusListener { 182 /** 183 * Indicates that the status of the HalDeviceManager has changed. Use isReady() and 184 * isStarted() to obtain status information. 185 */ 186 void onStatusChanged(); 187 } 188 189 /** 190 * Return the set of supported interface types across all Wi-Fi chips on the device. 191 * 192 * @return A set of IfaceTypes constants (possibly empty, e.g. on error). 193 */ 194 public Set<Integer> getSupportedIfaceTypes() { 195 return getSupportedIfaceTypesInternal(null); 196 } 197 198 /** 199 * Return the set of supported interface types for the specified Wi-Fi chip. 200 * 201 * @return A set of IfaceTypes constants (possibly empty, e.g. on error). 202 */ 203 public Set<Integer> getSupportedIfaceTypes(IWifiChip chip) { 204 return getSupportedIfaceTypesInternal(chip); 205 } 206 207 // interface-specific behavior 208 209 /** 210 * Create a STA interface if possible. Changes chip mode and removes conflicting interfaces if 211 * needed and permitted by priority. 212 * 213 * @param lowPrioritySta Indicates whether the requested STA is a low priority STA. The priority 214 * and preemption rules for low priority STA are: 215 * - Do not destroy any interface for it (even another low priority STA) 216 * - Destroy it for any other request 217 * @param destroyedListener Optional (nullable) listener to call when the allocated interface 218 * is removed. Will only be registered and used if an interface is 219 * created successfully. 220 * @param handler Handler on which to dispatch listener. Null implies the listener will be 221 * invoked synchronously from the context of the client which triggered the 222 * iface destruction. 223 * @return A newly created interface - or null if the interface could not be created. 224 */ 225 public IWifiStaIface createStaIface(boolean lowPrioritySta, 226 @Nullable InterfaceDestroyedListener destroyedListener, @Nullable Handler handler) { 227 return (IWifiStaIface) createIface(IfaceType.STA, lowPrioritySta, destroyedListener, 228 handler); 229 } 230 231 /** 232 * Create AP interface if possible (see createStaIface doc). 233 */ 234 public IWifiApIface createApIface(@Nullable InterfaceDestroyedListener destroyedListener, 235 @Nullable Handler handler) { 236 return (IWifiApIface) createIface(IfaceType.AP, false, destroyedListener, handler); 237 } 238 239 /** 240 * Create P2P interface if possible (see createStaIface doc). 241 */ 242 public IWifiP2pIface createP2pIface(@Nullable InterfaceDestroyedListener destroyedListener, 243 @Nullable Handler handler) { 244 return (IWifiP2pIface) createIface(IfaceType.P2P, false, destroyedListener, handler); 245 } 246 247 /** 248 * Create NAN interface if possible (see createStaIface doc). 249 */ 250 public IWifiNanIface createNanIface(@Nullable InterfaceDestroyedListener destroyedListener, 251 @Nullable Handler handler) { 252 return (IWifiNanIface) createIface(IfaceType.NAN, false, destroyedListener, handler); 253 } 254 255 /** 256 * Removes (releases/destroys) the given interface. Will trigger any registered 257 * InterfaceDestroyedListeners and possibly some InterfaceAvailableForRequestListeners if we 258 * can potentially create some other interfaces as a result of removing this interface. 259 */ 260 public boolean removeIface(IWifiIface iface) { 261 boolean success = removeIfaceInternal(iface); 262 dispatchAvailableForRequestListeners(); 263 return success; 264 } 265 266 /** 267 * Returns the IWifiChip corresponding to the specified interface (or null on error). 268 * 269 * Note: clients must not perform chip mode changes or interface management (create/delete) 270 * operations on IWifiChip directly. However, they can use the IWifiChip interface to perform 271 * other functions - e.g. calling the debug/trace methods. 272 */ 273 public IWifiChip getChip(IWifiIface iface) { 274 String name = getName(iface); 275 int type = getType(iface); 276 if (VDBG) Log.d(TAG, "getChip: iface(name)=" + name); 277 278 synchronized (mLock) { 279 InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(Pair.create(name, type)); 280 if (cacheEntry == null) { 281 Log.e(TAG, "getChip: no entry for iface(name)=" + name); 282 return null; 283 } 284 285 return cacheEntry.chip; 286 } 287 } 288 289 /** 290 * Register an InterfaceDestroyedListener to the specified iface - returns true on success 291 * and false on failure. This listener is in addition to the one registered when the interface 292 * was created - allowing non-creators to monitor interface status. 293 * 294 * @param destroyedListener Listener to call when the allocated interface is removed. 295 * Will only be registered and used if an interface is created 296 * successfully. 297 * @param handler Handler on which to dispatch listener. Null implies the listener will be 298 * invoked synchronously from the context of the client which triggered the 299 * iface destruction. 300 */ 301 public boolean registerDestroyedListener(IWifiIface iface, 302 @NonNull InterfaceDestroyedListener destroyedListener, 303 @Nullable Handler handler) { 304 String name = getName(iface); 305 int type = getType(iface); 306 if (VDBG) Log.d(TAG, "registerDestroyedListener: iface(name)=" + name); 307 308 synchronized (mLock) { 309 InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(Pair.create(name, type)); 310 if (cacheEntry == null) { 311 Log.e(TAG, "registerDestroyedListener: no entry for iface(name)=" + name); 312 return false; 313 } 314 315 return cacheEntry.destroyedListeners.add( 316 new InterfaceDestroyedListenerProxy(name, destroyedListener, handler)); 317 } 318 } 319 320 /** 321 * Register a listener to be called when an interface of the specified type could be requested. 322 * No guarantees are provided (some other entity could request it first). The listener is 323 * active from registration until unregistration - using 324 * unregisterInterfaceAvailableForRequestListener(). 325 * 326 * Only a single instance of a listener will be registered (even if the specified looper is 327 * different). 328 * 329 * Note that if it is possible to create the specified interface type at registration time 330 * then the callback will be triggered immediately. 331 * 332 * @param ifaceType The interface type (IfaceType) to be monitored. 333 * @param listener Listener to call when an interface of the requested 334 * type could be created 335 * @param handler Handler on which to dispatch listener. Null implies the listener will be 336 * invoked synchronously from the context of the client which triggered the 337 * mode change. 338 */ 339 public void registerInterfaceAvailableForRequestListener(int ifaceType, 340 @NonNull InterfaceAvailableForRequestListener listener, @Nullable Handler handler) { 341 if (VDBG) { 342 Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType 343 + ", listener=" + listener + ", handler=" + handler); 344 } 345 346 synchronized (mLock) { 347 InterfaceAvailableForRequestListenerProxy proxy = 348 new InterfaceAvailableForRequestListenerProxy(listener, handler); 349 if (mInterfaceAvailableForRequestListeners.get(ifaceType).containsKey(proxy)) { 350 if (VDBG) { 351 Log.d(TAG, 352 "registerInterfaceAvailableForRequestListener: dup listener skipped: " 353 + listener); 354 } 355 return; 356 } 357 mInterfaceAvailableForRequestListeners.get(ifaceType).put(proxy, null); 358 } 359 360 WifiChipInfo[] chipInfos = getAllChipInfo(); 361 if (chipInfos == null) { 362 Log.e(TAG, 363 "registerInterfaceAvailableForRequestListener: no chip info found - but " 364 + "possibly registered pre-started - ignoring"); 365 return; 366 } 367 dispatchAvailableForRequestListenersForType(ifaceType, chipInfos); 368 } 369 370 /** 371 * Unregisters a listener registered with registerInterfaceAvailableForRequestListener(). 372 */ 373 public void unregisterInterfaceAvailableForRequestListener( 374 int ifaceType, 375 InterfaceAvailableForRequestListener listener) { 376 if (VDBG) { 377 Log.d(TAG, "unregisterInterfaceAvailableForRequestListener: ifaceType=" + ifaceType); 378 } 379 380 synchronized (mLock) { 381 mInterfaceAvailableForRequestListeners.get(ifaceType).remove( 382 new InterfaceAvailableForRequestListenerProxy(listener, null)); 383 } 384 } 385 386 /** 387 * Return the name of the input interface or null on error. 388 */ 389 public static String getName(IWifiIface iface) { 390 if (iface == null) { 391 return "<null>"; 392 } 393 394 Mutable<String> nameResp = new Mutable<>(); 395 try { 396 iface.getName((WifiStatus status, String name) -> { 397 if (status.code == WifiStatusCode.SUCCESS) { 398 nameResp.value = name; 399 } else { 400 Log.e(TAG, "Error on getName: " + statusString(status)); 401 } 402 }); 403 } catch (RemoteException e) { 404 Log.e(TAG, "Exception on getName: " + e); 405 } 406 407 return nameResp.value; 408 } 409 410 /** 411 * Called when interface is destroyed. 412 */ 413 public interface InterfaceDestroyedListener { 414 /** 415 * Called for every interface on which registered when destroyed - whether 416 * destroyed by releaseIface() or through chip mode change or through Wi-Fi 417 * going down. 418 * 419 * Can be registered when the interface is requested with createXxxIface() - will 420 * only be valid if the interface creation was successful - i.e. a non-null was returned. 421 * 422 * @param ifaceName Name of the interface that was destroyed. 423 */ 424 void onDestroyed(@NonNull String ifaceName); 425 } 426 427 /** 428 * Called when an interface type availability for creation is changed. 429 */ 430 public interface InterfaceAvailableForRequestListener { 431 /** 432 * Called when an interface type availability for creation is updated. Registered with 433 * registerInterfaceAvailableForRequestListener() and unregistered with 434 * unregisterInterfaceAvailableForRequestListener(). 435 */ 436 void onAvailabilityChanged(boolean isAvailable); 437 } 438 439 /** 440 * Creates a IWifiRttController. A direct match to the IWifiChip.createRttController() method. 441 * 442 * Returns the created IWifiRttController or a null on error. 443 */ 444 public IWifiRttController createRttController() { 445 if (VDBG) Log.d(TAG, "createRttController"); 446 synchronized (mLock) { 447 if (mWifi == null) { 448 Log.e(TAG, "createRttController: null IWifi"); 449 return null; 450 } 451 452 WifiChipInfo[] chipInfos = getAllChipInfo(); 453 if (chipInfos == null) { 454 Log.e(TAG, "createRttController: no chip info found"); 455 stopWifi(); // major error: shutting down 456 return null; 457 } 458 459 for (WifiChipInfo chipInfo : chipInfos) { 460 Mutable<IWifiRttController> rttResp = new Mutable<>(); 461 try { 462 chipInfo.chip.createRttController(null, 463 (WifiStatus status, IWifiRttController rtt) -> { 464 if (status.code == WifiStatusCode.SUCCESS) { 465 rttResp.value = rtt; 466 } else { 467 Log.e(TAG, 468 "IWifiChip.createRttController failed: " + statusString( 469 status)); 470 } 471 }); 472 } catch (RemoteException e) { 473 Log.e(TAG, "IWifiChip.createRttController exception: " + e); 474 } 475 if (rttResp.value != null) { 476 return rttResp.value; 477 } 478 } 479 480 Log.e(TAG, "createRttController: not available from any of the chips"); 481 return null; 482 } 483 } 484 485 // internal state 486 487 /* This "PRIORITY" is not for deciding interface elimination (that is controlled by 488 * allowedToDeleteIfaceTypeForRequestedType. This priority is used for: 489 * - Comparing 2 configuration options 490 * - Order of dispatch of available for request listeners 491 */ 492 private static final int[] IFACE_TYPES_BY_PRIORITY = 493 {IfaceType.AP, IfaceType.STA, IfaceType.P2P, IfaceType.NAN}; 494 495 private final Object mLock = new Object(); 496 497 private IServiceManager mServiceManager; 498 private IWifi mWifi; 499 private final WifiEventCallback mWifiEventCallback = new WifiEventCallback(); 500 private final Set<ManagerStatusListenerProxy> mManagerStatusListeners = new HashSet<>(); 501 private final SparseArray<Map<InterfaceAvailableForRequestListenerProxy, Boolean>> 502 mInterfaceAvailableForRequestListeners = new SparseArray<>(); 503 private final SparseArray<IWifiChipEventCallback.Stub> mDebugCallbacks = new SparseArray<>(); 504 505 /* 506 * This is the only place where we cache HIDL information in this manager. Necessary since 507 * we need to keep a list of registered destroyed listeners. Will be validated regularly 508 * in getAllChipInfoAndValidateCache(). 509 */ 510 private final Map<Pair<String, Integer>, InterfaceCacheEntry> mInterfaceInfoCache = 511 new HashMap<>(); 512 513 private class InterfaceCacheEntry { 514 public IWifiChip chip; 515 public int chipId; 516 public String name; 517 public int type; 518 public Set<InterfaceDestroyedListenerProxy> destroyedListeners = new HashSet<>(); 519 public long creationTime; 520 public boolean isLowPriority; 521 522 @Override 523 public String toString() { 524 StringBuilder sb = new StringBuilder(); 525 sb.append("{name=").append(name).append(", type=").append(type) 526 .append(", destroyedListeners.size()=").append(destroyedListeners.size()) 527 .append(", creationTime=").append(creationTime).append( 528 ", isLowPriority=").append(isLowPriority).append("}"); 529 return sb.toString(); 530 } 531 } 532 533 private class WifiIfaceInfo { 534 public String name; 535 public IWifiIface iface; 536 } 537 538 private class WifiChipInfo { 539 public IWifiChip chip; 540 public int chipId; 541 public ArrayList<IWifiChip.ChipMode> availableModes; 542 public boolean currentModeIdValid; 543 public int currentModeId; 544 public WifiIfaceInfo[][] ifaces = new WifiIfaceInfo[IFACE_TYPES_BY_PRIORITY.length][]; 545 546 @Override 547 public String toString() { 548 StringBuilder sb = new StringBuilder(); 549 sb.append("{chipId=").append(chipId).append(", availableModes=").append(availableModes) 550 .append(", currentModeIdValid=").append(currentModeIdValid) 551 .append(", currentModeId=").append(currentModeId); 552 for (int type: IFACE_TYPES_BY_PRIORITY) { 553 sb.append(", ifaces[" + type + "].length=").append(ifaces[type].length); 554 } 555 sb.append(")"); 556 return sb.toString(); 557 } 558 } 559 560 /** 561 * Wrapper function to access the HIDL services. Created to be mockable in unit-tests. 562 */ 563 protected IWifi getWifiServiceMockable() { 564 try { 565 return IWifi.getService(); 566 } catch (RemoteException e) { 567 Log.e(TAG, "Exception getting IWifi service: " + e); 568 return null; 569 } 570 } 571 572 protected IServiceManager getServiceManagerMockable() { 573 try { 574 return IServiceManager.getService(); 575 } catch (RemoteException e) { 576 Log.e(TAG, "Exception getting IServiceManager: " + e); 577 return null; 578 } 579 } 580 581 // internal implementation 582 583 private void initializeInternal() { 584 initIServiceManagerIfNecessary(); 585 if (isSupportedInternal()) { 586 initIWifiIfNecessary(); 587 } 588 } 589 590 private void teardownInternal() { 591 managerStatusListenerDispatch(); 592 dispatchAllDestroyedListeners(); 593 mInterfaceAvailableForRequestListeners.get(IfaceType.STA).clear(); 594 mInterfaceAvailableForRequestListeners.get(IfaceType.AP).clear(); 595 mInterfaceAvailableForRequestListeners.get(IfaceType.P2P).clear(); 596 mInterfaceAvailableForRequestListeners.get(IfaceType.NAN).clear(); 597 } 598 599 private final HwRemoteBinder.DeathRecipient mServiceManagerDeathRecipient = 600 cookie -> { 601 Log.wtf(TAG, "IServiceManager died: cookie=" + cookie); 602 synchronized (mLock) { 603 mServiceManager = null; 604 // theoretically can call initServiceManager again here - but 605 // there's no point since most likely system is going to reboot 606 } 607 }; 608 609 private final IServiceNotification mServiceNotificationCallback = 610 new IServiceNotification.Stub() { 611 @Override 612 public void onRegistration(String fqName, String name, 613 boolean preexisting) { 614 Log.d(TAG, "IWifi registration notification: fqName=" + fqName 615 + ", name=" + name + ", preexisting=" + preexisting); 616 synchronized (mLock) { 617 initIWifiIfNecessary(); 618 } 619 } 620 }; 621 622 /** 623 * Failures of IServiceManager are most likely system breaking in any case. Behavior here 624 * will be to WTF and continue. 625 */ 626 private void initIServiceManagerIfNecessary() { 627 if (mDbg) Log.d(TAG, "initIServiceManagerIfNecessary"); 628 629 synchronized (mLock) { 630 if (mServiceManager != null) { 631 return; 632 } 633 634 mServiceManager = getServiceManagerMockable(); 635 if (mServiceManager == null) { 636 Log.wtf(TAG, "Failed to get IServiceManager instance"); 637 } else { 638 try { 639 if (!mServiceManager.linkToDeath( 640 mServiceManagerDeathRecipient, /* don't care */ 0)) { 641 Log.wtf(TAG, "Error on linkToDeath on IServiceManager"); 642 mServiceManager = null; 643 return; 644 } 645 646 if (!mServiceManager.registerForNotifications(IWifi.kInterfaceName, "", 647 mServiceNotificationCallback)) { 648 Log.wtf(TAG, "Failed to register a listener for IWifi service"); 649 mServiceManager = null; 650 } 651 } catch (RemoteException e) { 652 Log.wtf(TAG, "Exception while operating on IServiceManager: " + e); 653 mServiceManager = null; 654 } 655 } 656 } 657 } 658 659 /** 660 * Uses the IServiceManager to query if the vendor HAL is present in the VINTF for the device 661 * or not. 662 * @return true if supported, false otherwise. 663 */ 664 private boolean isSupportedInternal() { 665 if (VDBG) Log.d(TAG, "isSupportedInternal"); 666 667 synchronized (mLock) { 668 if (mServiceManager == null) { 669 Log.e(TAG, "isSupported: called but mServiceManager is null!?"); 670 return false; 671 } 672 try { 673 return (mServiceManager.getTransport(IWifi.kInterfaceName, HAL_INSTANCE_NAME) 674 != IServiceManager.Transport.EMPTY); 675 } catch (RemoteException e) { 676 Log.wtf(TAG, "Exception while operating on IServiceManager: " + e); 677 return false; 678 } 679 } 680 } 681 682 private final HwRemoteBinder.DeathRecipient mIWifiDeathRecipient = 683 cookie -> { 684 Log.e(TAG, "IWifi HAL service died! Have a listener for it ... cookie=" + cookie); 685 synchronized (mLock) { // prevents race condition with surrounding method 686 mWifi = null; 687 teardownInternal(); 688 // don't restart: wait for registration notification 689 } 690 }; 691 692 /** 693 * Initialize IWifi and register death listener and event callback. 694 * 695 * - It is possible that IWifi is not ready - we have a listener on IServiceManager for it. 696 * - It is not expected that any of the registrations will fail. Possible indication that 697 * service died after we obtained a handle to it. 698 * 699 * Here and elsewhere we assume that death listener will do the right thing! 700 */ 701 private void initIWifiIfNecessary() { 702 if (mDbg) Log.d(TAG, "initIWifiIfNecessary"); 703 704 synchronized (mLock) { 705 if (mWifi != null) { 706 return; 707 } 708 709 try { 710 mWifi = getWifiServiceMockable(); 711 if (mWifi == null) { 712 Log.e(TAG, "IWifi not (yet) available - but have a listener for it ..."); 713 return; 714 } 715 716 if (!mWifi.linkToDeath(mIWifiDeathRecipient, /* don't care */ 0)) { 717 Log.e(TAG, "Error on linkToDeath on IWifi - will retry later"); 718 return; 719 } 720 721 WifiStatus status = mWifi.registerEventCallback(mWifiEventCallback); 722 if (status.code != WifiStatusCode.SUCCESS) { 723 Log.e(TAG, "IWifi.registerEventCallback failed: " + statusString(status)); 724 mWifi = null; 725 return; 726 } 727 // Stopping wifi just in case. This would also trigger the status callback. 728 stopWifi(); 729 } catch (RemoteException e) { 730 Log.e(TAG, "Exception while operating on IWifi: " + e); 731 } 732 } 733 } 734 735 /** 736 * Registers event listeners on all IWifiChips after a successful start: DEBUG only! 737 * 738 * We don't need the listeners since any callbacks are just confirmation of status codes we 739 * obtain directly from mode changes or interface creation/deletion. 740 * 741 * Relies (to the degree we care) on the service removing all listeners when Wi-Fi is stopped. 742 */ 743 private void initIWifiChipDebugListeners() { 744 if (VDBG) Log.d(TAG, "initIWifiChipDebugListeners"); 745 746 if (!VDBG) { 747 return; 748 } 749 750 synchronized (mLock) { 751 try { 752 MutableBoolean statusOk = new MutableBoolean(false); 753 Mutable<ArrayList<Integer>> chipIdsResp = new Mutable<>(); 754 755 // get all chip IDs 756 mWifi.getChipIds((WifiStatus status, ArrayList<Integer> chipIds) -> { 757 statusOk.value = status.code == WifiStatusCode.SUCCESS; 758 if (statusOk.value) { 759 chipIdsResp.value = chipIds; 760 } else { 761 Log.e(TAG, "getChipIds failed: " + statusString(status)); 762 } 763 }); 764 if (!statusOk.value) { 765 return; 766 } 767 768 Log.d(TAG, "getChipIds=" + chipIdsResp.value); 769 if (chipIdsResp.value.size() == 0) { 770 Log.e(TAG, "Should have at least 1 chip!"); 771 return; 772 } 773 774 // register a callback for each chip 775 Mutable<IWifiChip> chipResp = new Mutable<>(); 776 for (Integer chipId: chipIdsResp.value) { 777 mWifi.getChip(chipId, (WifiStatus status, IWifiChip chip) -> { 778 statusOk.value = status.code == WifiStatusCode.SUCCESS; 779 if (statusOk.value) { 780 chipResp.value = chip; 781 } else { 782 Log.e(TAG, "getChip failed: " + statusString(status)); 783 } 784 }); 785 if (!statusOk.value) { 786 continue; // still try next one? 787 } 788 789 IWifiChipEventCallback.Stub callback = 790 new IWifiChipEventCallback.Stub() { 791 @Override 792 public void onChipReconfigured(int modeId) throws RemoteException { 793 Log.d(TAG, "onChipReconfigured: modeId=" + modeId); 794 } 795 796 @Override 797 public void onChipReconfigureFailure(WifiStatus status) 798 throws RemoteException { 799 Log.d(TAG, "onChipReconfigureFailure: status=" + statusString( 800 status)); 801 } 802 803 @Override 804 public void onIfaceAdded(int type, String name) 805 throws RemoteException { 806 Log.d(TAG, "onIfaceAdded: type=" + type + ", name=" + name); 807 } 808 809 @Override 810 public void onIfaceRemoved(int type, String name) 811 throws RemoteException { 812 Log.d(TAG, "onIfaceRemoved: type=" + type + ", name=" + name); 813 } 814 815 @Override 816 public void onDebugRingBufferDataAvailable( 817 WifiDebugRingBufferStatus status, 818 ArrayList<Byte> data) throws RemoteException { 819 Log.d(TAG, "onDebugRingBufferDataAvailable"); 820 } 821 822 @Override 823 public void onDebugErrorAlert(int errorCode, 824 ArrayList<Byte> debugData) 825 throws RemoteException { 826 Log.d(TAG, "onDebugErrorAlert"); 827 } 828 }; 829 mDebugCallbacks.put(chipId, callback); // store to prevent GC: needed by HIDL 830 WifiStatus status = chipResp.value.registerEventCallback(callback); 831 if (status.code != WifiStatusCode.SUCCESS) { 832 Log.e(TAG, "registerEventCallback failed: " + statusString(status)); 833 continue; // still try next one? 834 } 835 } 836 } catch (RemoteException e) { 837 Log.e(TAG, "initIWifiChipDebugListeners: exception: " + e); 838 return; 839 } 840 } 841 } 842 843 /** 844 * Get current information about all the chips in the system: modes, current mode (if any), and 845 * any existing interfaces. 846 * 847 * Intended to be called whenever we need to configure the chips - information is NOT cached (to 848 * reduce the likelihood that we get out-of-sync). 849 */ 850 private WifiChipInfo[] getAllChipInfo() { 851 if (VDBG) Log.d(TAG, "getAllChipInfo"); 852 853 synchronized (mLock) { 854 if (mWifi == null) { 855 Log.e(TAG, "getAllChipInfo: called but mWifi is null!?"); 856 return null; 857 } 858 859 try { 860 MutableBoolean statusOk = new MutableBoolean(false); 861 Mutable<ArrayList<Integer>> chipIdsResp = new Mutable<>(); 862 863 // get all chip IDs 864 mWifi.getChipIds((WifiStatus status, ArrayList<Integer> chipIds) -> { 865 statusOk.value = status.code == WifiStatusCode.SUCCESS; 866 if (statusOk.value) { 867 chipIdsResp.value = chipIds; 868 } else { 869 Log.e(TAG, "getChipIds failed: " + statusString(status)); 870 } 871 }); 872 if (!statusOk.value) { 873 return null; 874 } 875 876 if (VDBG) Log.d(TAG, "getChipIds=" + chipIdsResp.value); 877 if (chipIdsResp.value.size() == 0) { 878 Log.e(TAG, "Should have at least 1 chip!"); 879 return null; 880 } 881 882 int chipInfoIndex = 0; 883 WifiChipInfo[] chipsInfo = new WifiChipInfo[chipIdsResp.value.size()]; 884 885 Mutable<IWifiChip> chipResp = new Mutable<>(); 886 for (Integer chipId: chipIdsResp.value) { 887 mWifi.getChip(chipId, (WifiStatus status, IWifiChip chip) -> { 888 statusOk.value = status.code == WifiStatusCode.SUCCESS; 889 if (statusOk.value) { 890 chipResp.value = chip; 891 } else { 892 Log.e(TAG, "getChip failed: " + statusString(status)); 893 } 894 }); 895 if (!statusOk.value) { 896 return null; 897 } 898 899 Mutable<ArrayList<IWifiChip.ChipMode>> availableModesResp = new Mutable<>(); 900 chipResp.value.getAvailableModes( 901 (WifiStatus status, ArrayList<IWifiChip.ChipMode> modes) -> { 902 statusOk.value = status.code == WifiStatusCode.SUCCESS; 903 if (statusOk.value) { 904 availableModesResp.value = modes; 905 } else { 906 Log.e(TAG, "getAvailableModes failed: " + statusString(status)); 907 } 908 }); 909 if (!statusOk.value) { 910 return null; 911 } 912 913 MutableBoolean currentModeValidResp = new MutableBoolean(false); 914 MutableInt currentModeResp = new MutableInt(0); 915 chipResp.value.getMode((WifiStatus status, int modeId) -> { 916 statusOk.value = status.code == WifiStatusCode.SUCCESS; 917 if (statusOk.value) { 918 currentModeValidResp.value = true; 919 currentModeResp.value = modeId; 920 } else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) { 921 statusOk.value = true; // valid response 922 } else { 923 Log.e(TAG, "getMode failed: " + statusString(status)); 924 } 925 }); 926 if (!statusOk.value) { 927 return null; 928 } 929 930 Mutable<ArrayList<String>> ifaceNamesResp = new Mutable<>(); 931 MutableInt ifaceIndex = new MutableInt(0); 932 933 chipResp.value.getStaIfaceNames( 934 (WifiStatus status, ArrayList<String> ifnames) -> { 935 statusOk.value = status.code == WifiStatusCode.SUCCESS; 936 if (statusOk.value) { 937 ifaceNamesResp.value = ifnames; 938 } else { 939 Log.e(TAG, "getStaIfaceNames failed: " + statusString(status)); 940 } 941 }); 942 if (!statusOk.value) { 943 return null; 944 } 945 946 WifiIfaceInfo[] staIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()]; 947 for (String ifaceName: ifaceNamesResp.value) { 948 chipResp.value.getStaIface(ifaceName, 949 (WifiStatus status, IWifiStaIface iface) -> { 950 statusOk.value = status.code == WifiStatusCode.SUCCESS; 951 if (statusOk.value) { 952 WifiIfaceInfo ifaceInfo = new WifiIfaceInfo(); 953 ifaceInfo.name = ifaceName; 954 ifaceInfo.iface = iface; 955 staIfaces[ifaceIndex.value++] = ifaceInfo; 956 } else { 957 Log.e(TAG, "getStaIface failed: " + statusString(status)); 958 } 959 }); 960 if (!statusOk.value) { 961 return null; 962 } 963 } 964 965 ifaceIndex.value = 0; 966 chipResp.value.getApIfaceNames( 967 (WifiStatus status, ArrayList<String> ifnames) -> { 968 statusOk.value = status.code == WifiStatusCode.SUCCESS; 969 if (statusOk.value) { 970 ifaceNamesResp.value = ifnames; 971 } else { 972 Log.e(TAG, "getApIfaceNames failed: " + statusString(status)); 973 } 974 }); 975 if (!statusOk.value) { 976 return null; 977 } 978 979 WifiIfaceInfo[] apIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()]; 980 for (String ifaceName: ifaceNamesResp.value) { 981 chipResp.value.getApIface(ifaceName, 982 (WifiStatus status, IWifiApIface iface) -> { 983 statusOk.value = status.code == WifiStatusCode.SUCCESS; 984 if (statusOk.value) { 985 WifiIfaceInfo ifaceInfo = new WifiIfaceInfo(); 986 ifaceInfo.name = ifaceName; 987 ifaceInfo.iface = iface; 988 apIfaces[ifaceIndex.value++] = ifaceInfo; 989 } else { 990 Log.e(TAG, "getApIface failed: " + statusString(status)); 991 } 992 }); 993 if (!statusOk.value) { 994 return null; 995 } 996 } 997 998 ifaceIndex.value = 0; 999 chipResp.value.getP2pIfaceNames( 1000 (WifiStatus status, ArrayList<String> ifnames) -> { 1001 statusOk.value = status.code == WifiStatusCode.SUCCESS; 1002 if (statusOk.value) { 1003 ifaceNamesResp.value = ifnames; 1004 } else { 1005 Log.e(TAG, "getP2pIfaceNames failed: " + statusString(status)); 1006 } 1007 }); 1008 if (!statusOk.value) { 1009 return null; 1010 } 1011 1012 WifiIfaceInfo[] p2pIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()]; 1013 for (String ifaceName: ifaceNamesResp.value) { 1014 chipResp.value.getP2pIface(ifaceName, 1015 (WifiStatus status, IWifiP2pIface iface) -> { 1016 statusOk.value = status.code == WifiStatusCode.SUCCESS; 1017 if (statusOk.value) { 1018 WifiIfaceInfo ifaceInfo = new WifiIfaceInfo(); 1019 ifaceInfo.name = ifaceName; 1020 ifaceInfo.iface = iface; 1021 p2pIfaces[ifaceIndex.value++] = ifaceInfo; 1022 } else { 1023 Log.e(TAG, "getP2pIface failed: " + statusString(status)); 1024 } 1025 }); 1026 if (!statusOk.value) { 1027 return null; 1028 } 1029 } 1030 1031 ifaceIndex.value = 0; 1032 chipResp.value.getNanIfaceNames( 1033 (WifiStatus status, ArrayList<String> ifnames) -> { 1034 statusOk.value = status.code == WifiStatusCode.SUCCESS; 1035 if (statusOk.value) { 1036 ifaceNamesResp.value = ifnames; 1037 } else { 1038 Log.e(TAG, "getNanIfaceNames failed: " + statusString(status)); 1039 } 1040 }); 1041 if (!statusOk.value) { 1042 return null; 1043 } 1044 1045 WifiIfaceInfo[] nanIfaces = new WifiIfaceInfo[ifaceNamesResp.value.size()]; 1046 for (String ifaceName: ifaceNamesResp.value) { 1047 chipResp.value.getNanIface(ifaceName, 1048 (WifiStatus status, IWifiNanIface iface) -> { 1049 statusOk.value = status.code == WifiStatusCode.SUCCESS; 1050 if (statusOk.value) { 1051 WifiIfaceInfo ifaceInfo = new WifiIfaceInfo(); 1052 ifaceInfo.name = ifaceName; 1053 ifaceInfo.iface = iface; 1054 nanIfaces[ifaceIndex.value++] = ifaceInfo; 1055 } else { 1056 Log.e(TAG, "getNanIface failed: " + statusString(status)); 1057 } 1058 }); 1059 if (!statusOk.value) { 1060 return null; 1061 } 1062 } 1063 1064 WifiChipInfo chipInfo = new WifiChipInfo(); 1065 chipsInfo[chipInfoIndex++] = chipInfo; 1066 1067 chipInfo.chip = chipResp.value; 1068 chipInfo.chipId = chipId; 1069 chipInfo.availableModes = availableModesResp.value; 1070 chipInfo.currentModeIdValid = currentModeValidResp.value; 1071 chipInfo.currentModeId = currentModeResp.value; 1072 chipInfo.ifaces[IfaceType.STA] = staIfaces; 1073 chipInfo.ifaces[IfaceType.AP] = apIfaces; 1074 chipInfo.ifaces[IfaceType.P2P] = p2pIfaces; 1075 chipInfo.ifaces[IfaceType.NAN] = nanIfaces; 1076 } 1077 1078 return chipsInfo; 1079 } catch (RemoteException e) { 1080 Log.e(TAG, "getAllChipInfoAndValidateCache exception: " + e); 1081 } 1082 } 1083 1084 return null; 1085 } 1086 1087 /** 1088 * Checks the local state of this object (the cached state) against the input 'chipInfos' 1089 * state (which is a live representation of the Wi-Fi firmware status - read through the HAL). 1090 * Returns 'true' if there are no discrepancies - 'false' otherwise. 1091 * 1092 * A discrepancy is if any local state contains references to a chip or interface which are not 1093 * found on the information read from the chip. 1094 */ 1095 private boolean validateInterfaceCache(WifiChipInfo[] chipInfos) { 1096 if (VDBG) Log.d(TAG, "validateInterfaceCache"); 1097 1098 synchronized (mLock) { 1099 for (InterfaceCacheEntry entry: mInterfaceInfoCache.values()) { 1100 // search for chip 1101 WifiChipInfo matchingChipInfo = null; 1102 for (WifiChipInfo ci: chipInfos) { 1103 if (ci.chipId == entry.chipId) { 1104 matchingChipInfo = ci; 1105 break; 1106 } 1107 } 1108 if (matchingChipInfo == null) { 1109 Log.e(TAG, "validateInterfaceCache: no chip found for " + entry); 1110 return false; 1111 } 1112 1113 // search for interface 1114 WifiIfaceInfo[] ifaceInfoList = matchingChipInfo.ifaces[entry.type]; 1115 if (ifaceInfoList == null) { 1116 Log.e(TAG, "validateInterfaceCache: invalid type on entry " + entry); 1117 return false; 1118 } 1119 1120 boolean matchFound = false; 1121 for (WifiIfaceInfo ifaceInfo: ifaceInfoList) { 1122 if (ifaceInfo.name.equals(entry.name)) { 1123 matchFound = true; 1124 break; 1125 } 1126 } 1127 if (!matchFound) { 1128 Log.e(TAG, "validateInterfaceCache: no interface found for " + entry); 1129 return false; 1130 } 1131 } 1132 } 1133 1134 return true; 1135 } 1136 1137 private boolean isWifiStarted() { 1138 if (VDBG) Log.d(TAG, "isWifiStart"); 1139 1140 synchronized (mLock) { 1141 try { 1142 if (mWifi == null) { 1143 Log.w(TAG, "isWifiStarted called but mWifi is null!?"); 1144 return false; 1145 } else { 1146 return mWifi.isStarted(); 1147 } 1148 } catch (RemoteException e) { 1149 Log.e(TAG, "isWifiStarted exception: " + e); 1150 return false; 1151 } 1152 } 1153 } 1154 1155 private boolean startWifi() { 1156 if (VDBG) Log.d(TAG, "startWifi"); 1157 1158 synchronized (mLock) { 1159 try { 1160 if (mWifi == null) { 1161 Log.w(TAG, "startWifi called but mWifi is null!?"); 1162 return false; 1163 } else { 1164 int triedCount = 0; 1165 while (triedCount <= START_HAL_RETRY_TIMES) { 1166 WifiStatus status = mWifi.start(); 1167 if (status.code == WifiStatusCode.SUCCESS) { 1168 initIWifiChipDebugListeners(); 1169 managerStatusListenerDispatch(); 1170 if (triedCount != 0) { 1171 Log.d(TAG, "start IWifi succeeded after trying " 1172 + triedCount + " times"); 1173 } 1174 return true; 1175 } else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) { 1176 // Should retry. Hal might still be stopping. 1177 Log.e(TAG, "Cannot start IWifi: " + statusString(status) 1178 + ", Retrying..."); 1179 try { 1180 Thread.sleep(START_HAL_RETRY_INTERVAL_MS); 1181 } catch (InterruptedException ignore) { 1182 // no-op 1183 } 1184 triedCount++; 1185 } else { 1186 // Should not retry on other failures. 1187 Log.e(TAG, "Cannot start IWifi: " + statusString(status)); 1188 return false; 1189 } 1190 } 1191 Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times"); 1192 return false; 1193 } 1194 } catch (RemoteException e) { 1195 Log.e(TAG, "startWifi exception: " + e); 1196 return false; 1197 } 1198 } 1199 } 1200 1201 private void stopWifi() { 1202 if (VDBG) Log.d(TAG, "stopWifi"); 1203 1204 synchronized (mLock) { 1205 try { 1206 if (mWifi == null) { 1207 Log.w(TAG, "stopWifi called but mWifi is null!?"); 1208 } else { 1209 WifiStatus status = mWifi.stop(); 1210 if (status.code != WifiStatusCode.SUCCESS) { 1211 Log.e(TAG, "Cannot stop IWifi: " + statusString(status)); 1212 } 1213 1214 // even on failure since WTF?? 1215 teardownInternal(); 1216 } 1217 } catch (RemoteException e) { 1218 Log.e(TAG, "stopWifi exception: " + e); 1219 } 1220 } 1221 } 1222 1223 private class WifiEventCallback extends IWifiEventCallback.Stub { 1224 @Override 1225 public void onStart() throws RemoteException { 1226 if (VDBG) Log.d(TAG, "IWifiEventCallback.onStart"); 1227 // NOP: only happens in reaction to my calls - will handle directly 1228 } 1229 1230 @Override 1231 public void onStop() throws RemoteException { 1232 if (VDBG) Log.d(TAG, "IWifiEventCallback.onStop"); 1233 // NOP: only happens in reaction to my calls - will handle directly 1234 } 1235 1236 @Override 1237 public void onFailure(WifiStatus status) throws RemoteException { 1238 Log.e(TAG, "IWifiEventCallback.onFailure: " + statusString(status)); 1239 teardownInternal(); 1240 1241 // No need to do anything else: listeners may (will) re-start Wi-Fi 1242 } 1243 } 1244 1245 private void managerStatusListenerDispatch() { 1246 synchronized (mLock) { 1247 for (ManagerStatusListenerProxy cb : mManagerStatusListeners) { 1248 cb.trigger(); 1249 } 1250 } 1251 } 1252 1253 private class ManagerStatusListenerProxy extends 1254 ListenerProxy<ManagerStatusListener> { 1255 ManagerStatusListenerProxy(ManagerStatusListener statusListener, Handler handler) { 1256 super(statusListener, handler, "ManagerStatusListenerProxy"); 1257 } 1258 1259 @Override 1260 protected void action() { 1261 mListener.onStatusChanged(); 1262 } 1263 } 1264 1265 Set<Integer> getSupportedIfaceTypesInternal(IWifiChip chip) { 1266 Set<Integer> results = new HashSet<>(); 1267 1268 WifiChipInfo[] chipInfos = getAllChipInfo(); 1269 if (chipInfos == null) { 1270 Log.e(TAG, "getSupportedIfaceTypesInternal: no chip info found"); 1271 return results; 1272 } 1273 1274 MutableInt chipIdIfProvided = new MutableInt(0); // NOT using 0 as a magic value 1275 if (chip != null) { 1276 MutableBoolean statusOk = new MutableBoolean(false); 1277 try { 1278 chip.getId((WifiStatus status, int id) -> { 1279 if (status.code == WifiStatusCode.SUCCESS) { 1280 chipIdIfProvided.value = id; 1281 statusOk.value = true; 1282 } else { 1283 Log.e(TAG, "getSupportedIfaceTypesInternal: IWifiChip.getId() error: " 1284 + statusString(status)); 1285 statusOk.value = false; 1286 } 1287 }); 1288 } catch (RemoteException e) { 1289 Log.e(TAG, "getSupportedIfaceTypesInternal IWifiChip.getId() exception: " + e); 1290 return results; 1291 } 1292 if (!statusOk.value) { 1293 return results; 1294 } 1295 } 1296 1297 for (WifiChipInfo wci: chipInfos) { 1298 if (chip != null && wci.chipId != chipIdIfProvided.value) { 1299 continue; 1300 } 1301 1302 for (IWifiChip.ChipMode cm: wci.availableModes) { 1303 for (IWifiChip.ChipIfaceCombination cic: cm.availableCombinations) { 1304 for (IWifiChip.ChipIfaceCombinationLimit cicl: cic.limits) { 1305 for (int type: cicl.types) { 1306 results.add(type); 1307 } 1308 } 1309 } 1310 } 1311 } 1312 1313 return results; 1314 } 1315 1316 private IWifiIface createIface(int ifaceType, boolean lowPriority, 1317 InterfaceDestroyedListener destroyedListener, Handler handler) { 1318 if (mDbg) { 1319 Log.d(TAG, "createIface: ifaceType=" + ifaceType + ", lowPriority=" + lowPriority); 1320 } 1321 1322 synchronized (mLock) { 1323 WifiChipInfo[] chipInfos = getAllChipInfo(); 1324 if (chipInfos == null) { 1325 Log.e(TAG, "createIface: no chip info found"); 1326 stopWifi(); // major error: shutting down 1327 return null; 1328 } 1329 1330 if (!validateInterfaceCache(chipInfos)) { 1331 Log.e(TAG, "createIface: local cache is invalid!"); 1332 stopWifi(); // major error: shutting down 1333 return null; 1334 } 1335 1336 IWifiIface iface = createIfaceIfPossible(chipInfos, ifaceType, lowPriority, 1337 destroyedListener, handler); 1338 if (iface != null) { // means that some configuration has changed 1339 if (!dispatchAvailableForRequestListeners()) { 1340 return null; // catastrophic failure - shut down 1341 } 1342 } 1343 1344 return iface; 1345 } 1346 } 1347 1348 private IWifiIface createIfaceIfPossible(WifiChipInfo[] chipInfos, int ifaceType, 1349 boolean lowPriority, InterfaceDestroyedListener destroyedListener, Handler handler) { 1350 if (VDBG) { 1351 Log.d(TAG, "createIfaceIfPossible: chipInfos=" + Arrays.deepToString(chipInfos) 1352 + ", ifaceType=" + ifaceType + ", lowPriority=" + lowPriority); 1353 } 1354 synchronized (mLock) { 1355 IfaceCreationData bestIfaceCreationProposal = null; 1356 for (WifiChipInfo chipInfo: chipInfos) { 1357 for (IWifiChip.ChipMode chipMode: chipInfo.availableModes) { 1358 for (IWifiChip.ChipIfaceCombination chipIfaceCombo : chipMode 1359 .availableCombinations) { 1360 int[][] expandedIfaceCombos = expandIfaceCombos(chipIfaceCombo); 1361 if (VDBG) { 1362 Log.d(TAG, chipIfaceCombo + " expands to " 1363 + Arrays.deepToString(expandedIfaceCombos)); 1364 } 1365 1366 for (int[] expandedIfaceCombo: expandedIfaceCombos) { 1367 IfaceCreationData currentProposal = canIfaceComboSupportRequest( 1368 chipInfo, chipMode, expandedIfaceCombo, ifaceType, lowPriority); 1369 if (compareIfaceCreationData(currentProposal, 1370 bestIfaceCreationProposal)) { 1371 if (VDBG) Log.d(TAG, "new proposal accepted"); 1372 bestIfaceCreationProposal = currentProposal; 1373 } 1374 } 1375 } 1376 } 1377 } 1378 1379 if (bestIfaceCreationProposal != null) { 1380 IWifiIface iface = executeChipReconfiguration(bestIfaceCreationProposal, ifaceType); 1381 if (iface != null) { 1382 InterfaceCacheEntry cacheEntry = new InterfaceCacheEntry(); 1383 1384 cacheEntry.chip = bestIfaceCreationProposal.chipInfo.chip; 1385 cacheEntry.chipId = bestIfaceCreationProposal.chipInfo.chipId; 1386 cacheEntry.name = getName(iface); 1387 cacheEntry.type = ifaceType; 1388 if (destroyedListener != null) { 1389 cacheEntry.destroyedListeners.add( 1390 new InterfaceDestroyedListenerProxy( 1391 cacheEntry.name, destroyedListener, handler)); 1392 } 1393 cacheEntry.creationTime = mClock.getUptimeSinceBootMillis(); 1394 cacheEntry.isLowPriority = lowPriority; 1395 1396 if (mDbg) Log.d(TAG, "createIfaceIfPossible: added cacheEntry=" + cacheEntry); 1397 mInterfaceInfoCache.put( 1398 Pair.create(cacheEntry.name, cacheEntry.type), cacheEntry); 1399 return iface; 1400 } 1401 } 1402 } 1403 1404 return null; 1405 } 1406 1407 // similar to createIfaceIfPossible - but simpler code: not looking for best option just 1408 // for any option (so terminates on first one). 1409 private boolean isItPossibleToCreateIface(WifiChipInfo[] chipInfos, int ifaceType) { 1410 if (VDBG) { 1411 Log.d(TAG, "isItPossibleToCreateIface: chipInfos=" + Arrays.deepToString(chipInfos) 1412 + ", ifaceType=" + ifaceType); 1413 } 1414 1415 for (WifiChipInfo chipInfo: chipInfos) { 1416 for (IWifiChip.ChipMode chipMode: chipInfo.availableModes) { 1417 for (IWifiChip.ChipIfaceCombination chipIfaceCombo : chipMode 1418 .availableCombinations) { 1419 int[][] expandedIfaceCombos = expandIfaceCombos(chipIfaceCombo); 1420 if (VDBG) { 1421 Log.d(TAG, chipIfaceCombo + " expands to " 1422 + Arrays.deepToString(expandedIfaceCombos)); 1423 } 1424 1425 for (int[] expandedIfaceCombo: expandedIfaceCombos) { 1426 if (canIfaceComboSupportRequest(chipInfo, chipMode, expandedIfaceCombo, 1427 ifaceType, false) != null) { 1428 return true; 1429 } 1430 } 1431 } 1432 } 1433 } 1434 1435 return false; 1436 } 1437 1438 /** 1439 * Expands (or provides an alternative representation) of the ChipIfaceCombination as all 1440 * possible combinations of interface. 1441 * 1442 * Returns [# of combinations][4 (IfaceType)] 1443 * 1444 * Note: there could be duplicates - allow (inefficient but ...). 1445 * TODO: optimize by using a Set as opposed to a []: will remove duplicates. Will need to 1446 * provide correct hashes. 1447 */ 1448 private int[][] expandIfaceCombos(IWifiChip.ChipIfaceCombination chipIfaceCombo) { 1449 int numOfCombos = 1; 1450 for (IWifiChip.ChipIfaceCombinationLimit limit: chipIfaceCombo.limits) { 1451 for (int i = 0; i < limit.maxIfaces; ++i) { 1452 numOfCombos *= limit.types.size(); 1453 } 1454 } 1455 1456 int[][] expandedIfaceCombos = new int[numOfCombos][IFACE_TYPES_BY_PRIORITY.length]; 1457 1458 int span = numOfCombos; // span of an individual type (or sub-tree size) 1459 for (IWifiChip.ChipIfaceCombinationLimit limit: chipIfaceCombo.limits) { 1460 for (int i = 0; i < limit.maxIfaces; ++i) { 1461 span /= limit.types.size(); 1462 for (int k = 0; k < numOfCombos; ++k) { 1463 expandedIfaceCombos[k][limit.types.get((k / span) % limit.types.size())]++; 1464 } 1465 } 1466 } 1467 1468 return expandedIfaceCombos; 1469 } 1470 1471 private class IfaceCreationData { 1472 public WifiChipInfo chipInfo; 1473 public int chipModeId; 1474 public List<WifiIfaceInfo> interfacesToBeRemovedFirst; 1475 1476 @Override 1477 public String toString() { 1478 StringBuilder sb = new StringBuilder(); 1479 sb.append("{chipInfo=").append(chipInfo).append(", chipModeId=").append(chipModeId) 1480 .append(", interfacesToBeRemovedFirst=").append(interfacesToBeRemovedFirst) 1481 .append(")"); 1482 return sb.toString(); 1483 } 1484 } 1485 1486 /** 1487 * Checks whether the input chip-iface-combo can support the requested interface type: if not 1488 * then returns null, if yes then returns information containing the list of interfaces which 1489 * would have to be removed first before the requested interface can be created. 1490 * 1491 * Note: the list of interfaces to be removed is EMPTY if a chip mode change is required - in 1492 * that case ALL the interfaces on the current chip have to be removed first. 1493 * 1494 * Response determined based on: 1495 * - Mode configuration: i.e. could the mode support the interface type in principle 1496 * - Priority information: i.e. are we 'allowed' to remove interfaces in order to create the 1497 * requested interface 1498 */ 1499 private IfaceCreationData canIfaceComboSupportRequest(WifiChipInfo chipInfo, 1500 IWifiChip.ChipMode chipMode, int[] chipIfaceCombo, int ifaceType, boolean lowPriority) { 1501 if (VDBG) { 1502 Log.d(TAG, "canIfaceComboSupportRequest: chipInfo=" + chipInfo + ", chipMode=" 1503 + chipMode + ", chipIfaceCombo=" + chipIfaceCombo + ", ifaceType=" + ifaceType 1504 + ", lowPriority=" + lowPriority); 1505 } 1506 1507 // short-circuit: does the chipIfaceCombo even support the requested type? 1508 if (chipIfaceCombo[ifaceType] == 0) { 1509 if (VDBG) Log.d(TAG, "Requested type not supported by combo"); 1510 return null; 1511 } 1512 1513 boolean isChipModeChangeProposed = 1514 chipInfo.currentModeIdValid && chipInfo.currentModeId != chipMode.id; 1515 1516 // short-circuit: can't change chip-mode if an existing interface on this chip has a higher 1517 // priority than the requested interface 1518 if (isChipModeChangeProposed) { 1519 for (int type: IFACE_TYPES_BY_PRIORITY) { 1520 if (chipInfo.ifaces[type].length != 0) { 1521 if (lowPriority) { 1522 if (VDBG) { 1523 Log.d(TAG, "Couldn't delete existing type " + type 1524 + " interfaces for a low priority request"); 1525 } 1526 return null; 1527 } 1528 if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType, 1529 chipInfo.ifaces, chipInfo.ifaces[type].length)) { 1530 if (VDBG) { 1531 Log.d(TAG, "Couldn't delete existing type " + type 1532 + " interfaces for requested type"); 1533 } 1534 return null; 1535 } 1536 } 1537 } 1538 1539 // but if priority allows the mode change then we're good to go 1540 IfaceCreationData ifaceCreationData = new IfaceCreationData(); 1541 ifaceCreationData.chipInfo = chipInfo; 1542 ifaceCreationData.chipModeId = chipMode.id; 1543 1544 return ifaceCreationData; 1545 } 1546 1547 // possibly supported 1548 List<WifiIfaceInfo> interfacesToBeRemovedFirst = new ArrayList<>(); 1549 1550 for (int type: IFACE_TYPES_BY_PRIORITY) { 1551 int tooManyInterfaces = chipInfo.ifaces[type].length - chipIfaceCombo[type]; 1552 1553 // need to count the requested interface as well 1554 if (type == ifaceType) { 1555 tooManyInterfaces += 1; 1556 } 1557 1558 if (tooManyInterfaces > 0) { // may need to delete some 1559 if (lowPriority) { 1560 if (VDBG) { 1561 Log.d(TAG, "Couldn't delete existing type " + type 1562 + " interfaces for a low priority request"); 1563 } 1564 return null; 1565 } 1566 1567 if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType, chipInfo.ifaces, 1568 tooManyInterfaces)) { 1569 if (VDBG) { 1570 Log.d(TAG, "Would need to delete some higher priority interfaces"); 1571 } 1572 return null; 1573 } 1574 1575 // delete the most recently created interfaces or LOW priority interfaces 1576 interfacesToBeRemovedFirst = selectInterfacesToDelete(tooManyInterfaces, 1577 chipInfo.ifaces[type]); 1578 } 1579 } 1580 1581 IfaceCreationData ifaceCreationData = new IfaceCreationData(); 1582 ifaceCreationData.chipInfo = chipInfo; 1583 ifaceCreationData.chipModeId = chipMode.id; 1584 ifaceCreationData.interfacesToBeRemovedFirst = interfacesToBeRemovedFirst; 1585 1586 return ifaceCreationData; 1587 } 1588 1589 /** 1590 * Compares two options to create an interface and determines which is the 'best'. Returns 1591 * true if proposal 1 (val1) is better, other false. 1592 * 1593 * Note: both proposals are 'acceptable' bases on priority criteria. 1594 * 1595 * Criteria: 1596 * - Proposal is better if it means removing fewer high priority interfaces 1597 */ 1598 private boolean compareIfaceCreationData(IfaceCreationData val1, IfaceCreationData val2) { 1599 if (VDBG) Log.d(TAG, "compareIfaceCreationData: val1=" + val1 + ", val2=" + val2); 1600 1601 // deal with trivial case of one or the other being null 1602 if (val1 == null) { 1603 return false; 1604 } else if (val2 == null) { 1605 return true; 1606 } 1607 1608 for (int type: IFACE_TYPES_BY_PRIORITY) { 1609 // # of interfaces to be deleted: the list or all interfaces of the type if mode change 1610 int numIfacesToDelete1 = 0; 1611 if (val1.chipInfo.currentModeIdValid 1612 && val1.chipInfo.currentModeId != val1.chipModeId) { 1613 numIfacesToDelete1 = val1.chipInfo.ifaces[type].length; 1614 } else { 1615 numIfacesToDelete1 = val1.interfacesToBeRemovedFirst.size(); 1616 } 1617 1618 int numIfacesToDelete2 = 0; 1619 if (val2.chipInfo.currentModeIdValid 1620 && val2.chipInfo.currentModeId != val2.chipModeId) { 1621 numIfacesToDelete2 = val2.chipInfo.ifaces[type].length; 1622 } else { 1623 numIfacesToDelete2 = val2.interfacesToBeRemovedFirst.size(); 1624 } 1625 1626 if (numIfacesToDelete1 < numIfacesToDelete2) { 1627 if (VDBG) { 1628 Log.d(TAG, "decision based on type=" + type + ": " + numIfacesToDelete1 1629 + " < " + numIfacesToDelete2); 1630 } 1631 return true; 1632 } 1633 } 1634 1635 // arbitrary - flip a coin 1636 if (VDBG) Log.d(TAG, "proposals identical - flip a coin"); 1637 return false; 1638 } 1639 1640 /** 1641 * Returns true if we're allowed to delete the existing interface type for the requested 1642 * interface type. 1643 * 1644 * Rules - applies in order: 1645 * 1646 * General rules: 1647 * 1. No interface will be destroyed for a requested interface of the same type 1648 * 2. No interface will be destroyed if one of the requested interfaces already exists 1649 * 3. If there are >1 interface of an existing type, then it is ok to destroy that type 1650 * interface 1651 * 1652 * Type-specific rules (but note that the general rules are appied first): 1653 * 4. Request for AP or STA will destroy any other interface 1654 * 5. Request for P2P will destroy NAN-only (but will destroy a second STA per #3) 1655 * 6. Request for NAN will not destroy any interface (but will destroy a second STA per #3) 1656 * 1657 * Note: the 'numNecessaryInterfaces' is used to specify how many interfaces would be needed to 1658 * be deleted. This is used to determine whether there are that many low priority interfaces 1659 * of the requested type to delete. 1660 */ 1661 private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType, 1662 int requestedIfaceType, WifiIfaceInfo[][] currentIfaces, int numNecessaryInterfaces) { 1663 // rule 0: check for any low priority interfaces 1664 int numAvailableLowPriorityInterfaces = 0; 1665 for (InterfaceCacheEntry entry : mInterfaceInfoCache.values()) { 1666 if (entry.type == existingIfaceType && entry.isLowPriority) { 1667 numAvailableLowPriorityInterfaces++; 1668 } 1669 } 1670 if (numAvailableLowPriorityInterfaces >= numNecessaryInterfaces) { 1671 return true; 1672 } 1673 1674 // rule 1 1675 if (existingIfaceType == requestedIfaceType) { 1676 return false; 1677 } 1678 1679 // rule 2 1680 if (currentIfaces[requestedIfaceType].length != 0) { 1681 return false; 1682 } 1683 1684 // rule 3 1685 if (currentIfaces[existingIfaceType].length > 1) { 1686 return true; 1687 } 1688 1689 // rule 6 1690 if (requestedIfaceType == IfaceType.NAN) { 1691 return false; 1692 } 1693 1694 // rule 5 1695 if (requestedIfaceType == IfaceType.P2P) { 1696 return existingIfaceType == IfaceType.NAN; 1697 } 1698 1699 // rule 4, the requestIfaceType is either AP or STA 1700 return true; 1701 } 1702 1703 /** 1704 * Selects the interfaces to delete. 1705 * 1706 * Rule: select low priority interfaces and then other interfaces in order of creation time. 1707 * 1708 * @param excessInterfaces Number of interfaces which need to be selected. 1709 * @param interfaces Array of interfaces. 1710 */ 1711 private List<WifiIfaceInfo> selectInterfacesToDelete(int excessInterfaces, 1712 WifiIfaceInfo[] interfaces) { 1713 if (VDBG) { 1714 Log.d(TAG, "selectInterfacesToDelete: excessInterfaces=" + excessInterfaces 1715 + ", interfaces=" + Arrays.toString(interfaces)); 1716 } 1717 1718 boolean lookupError = false; 1719 LongSparseArray<WifiIfaceInfo> orderedListLowPriority = new LongSparseArray<>(); 1720 LongSparseArray<WifiIfaceInfo> orderedList = new LongSparseArray<>(); 1721 for (WifiIfaceInfo info : interfaces) { 1722 InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get( 1723 Pair.create(info.name, getType(info.iface))); 1724 if (cacheEntry == null) { 1725 Log.e(TAG, 1726 "selectInterfacesToDelete: can't find cache entry with name=" + info.name); 1727 lookupError = true; 1728 break; 1729 } 1730 if (cacheEntry.isLowPriority) { 1731 orderedListLowPriority.append(cacheEntry.creationTime, info); 1732 } else { 1733 orderedList.append(cacheEntry.creationTime, info); 1734 } 1735 } 1736 1737 if (lookupError) { 1738 Log.e(TAG, "selectInterfacesToDelete: falling back to arbitrary selection"); 1739 return Arrays.asList(Arrays.copyOf(interfaces, excessInterfaces)); 1740 } else { 1741 List<WifiIfaceInfo> result = new ArrayList<>(excessInterfaces); 1742 for (int i = 0; i < excessInterfaces; ++i) { 1743 int lowPriorityNextIndex = orderedListLowPriority.size() - i - 1; 1744 if (lowPriorityNextIndex >= 0) { 1745 result.add(orderedListLowPriority.valueAt(lowPriorityNextIndex)); 1746 } else { 1747 result.add(orderedList.valueAt( 1748 orderedList.size() - i + orderedListLowPriority.size() - 1)); 1749 } 1750 } 1751 return result; 1752 } 1753 } 1754 1755 /** 1756 * Performs chip reconfiguration per the input: 1757 * - Removes the specified interfaces 1758 * - Reconfigures the chip to the new chip mode (if necessary) 1759 * - Creates the new interface 1760 * 1761 * Returns the newly created interface or a null on any error. 1762 */ 1763 private IWifiIface executeChipReconfiguration(IfaceCreationData ifaceCreationData, 1764 int ifaceType) { 1765 if (mDbg) { 1766 Log.d(TAG, "executeChipReconfiguration: ifaceCreationData=" + ifaceCreationData 1767 + ", ifaceType=" + ifaceType); 1768 } 1769 synchronized (mLock) { 1770 try { 1771 // is this a mode change? 1772 boolean isModeConfigNeeded = !ifaceCreationData.chipInfo.currentModeIdValid 1773 || ifaceCreationData.chipInfo.currentModeId != ifaceCreationData.chipModeId; 1774 if (mDbg) Log.d(TAG, "isModeConfigNeeded=" + isModeConfigNeeded); 1775 1776 // first delete interfaces/change modes 1777 if (isModeConfigNeeded) { 1778 // remove all interfaces pre mode-change 1779 // TODO: is this necessary? note that even if we don't want to explicitly 1780 // remove the interfaces we do need to call the onDeleted callbacks - which 1781 // this does 1782 for (WifiIfaceInfo[] ifaceInfos: ifaceCreationData.chipInfo.ifaces) { 1783 for (WifiIfaceInfo ifaceInfo: ifaceInfos) { 1784 removeIfaceInternal(ifaceInfo.iface); // ignore return value 1785 } 1786 } 1787 1788 WifiStatus status = ifaceCreationData.chipInfo.chip.configureChip( 1789 ifaceCreationData.chipModeId); 1790 if (status.code != WifiStatusCode.SUCCESS) { 1791 Log.e(TAG, "executeChipReconfiguration: configureChip error: " 1792 + statusString(status)); 1793 return null; 1794 } 1795 } else { 1796 // remove all interfaces on the delete list 1797 for (WifiIfaceInfo ifaceInfo: ifaceCreationData.interfacesToBeRemovedFirst) { 1798 removeIfaceInternal(ifaceInfo.iface); // ignore return value 1799 } 1800 } 1801 1802 // create new interface 1803 Mutable<WifiStatus> statusResp = new Mutable<>(); 1804 Mutable<IWifiIface> ifaceResp = new Mutable<>(); 1805 switch (ifaceType) { 1806 case IfaceType.STA: 1807 ifaceCreationData.chipInfo.chip.createStaIface( 1808 (WifiStatus status, IWifiStaIface iface) -> { 1809 statusResp.value = status; 1810 ifaceResp.value = iface; 1811 }); 1812 break; 1813 case IfaceType.AP: 1814 ifaceCreationData.chipInfo.chip.createApIface( 1815 (WifiStatus status, IWifiApIface iface) -> { 1816 statusResp.value = status; 1817 ifaceResp.value = iface; 1818 }); 1819 break; 1820 case IfaceType.P2P: 1821 ifaceCreationData.chipInfo.chip.createP2pIface( 1822 (WifiStatus status, IWifiP2pIface iface) -> { 1823 statusResp.value = status; 1824 ifaceResp.value = iface; 1825 }); 1826 break; 1827 case IfaceType.NAN: 1828 ifaceCreationData.chipInfo.chip.createNanIface( 1829 (WifiStatus status, IWifiNanIface iface) -> { 1830 statusResp.value = status; 1831 ifaceResp.value = iface; 1832 }); 1833 break; 1834 } 1835 1836 if (statusResp.value.code != WifiStatusCode.SUCCESS) { 1837 Log.e(TAG, "executeChipReconfiguration: failed to create interface ifaceType=" 1838 + ifaceType + ": " + statusString(statusResp.value)); 1839 return null; 1840 } 1841 1842 return ifaceResp.value; 1843 } catch (RemoteException e) { 1844 Log.e(TAG, "executeChipReconfiguration exception: " + e); 1845 return null; 1846 } 1847 } 1848 } 1849 1850 private boolean removeIfaceInternal(IWifiIface iface) { 1851 String name = getName(iface); 1852 int type = getType(iface); 1853 if (mDbg) Log.d(TAG, "removeIfaceInternal: iface(name)=" + name + ", type=" + type); 1854 1855 if (type == -1) { 1856 Log.e(TAG, "removeIfaceInternal: can't get type -- iface(name)=" + name); 1857 return false; 1858 } 1859 1860 synchronized (mLock) { 1861 if (mWifi == null) { 1862 Log.e(TAG, "removeIfaceInternal: null IWifi -- iface(name)=" + name); 1863 return false; 1864 } 1865 1866 IWifiChip chip = getChip(iface); 1867 if (chip == null) { 1868 Log.e(TAG, "removeIfaceInternal: null IWifiChip -- iface(name)=" + name); 1869 return false; 1870 } 1871 1872 if (name == null) { 1873 Log.e(TAG, "removeIfaceInternal: can't get name"); 1874 return false; 1875 } 1876 1877 WifiStatus status = null; 1878 try { 1879 switch (type) { 1880 case IfaceType.STA: 1881 status = chip.removeStaIface(name); 1882 break; 1883 case IfaceType.AP: 1884 status = chip.removeApIface(name); 1885 break; 1886 case IfaceType.P2P: 1887 status = chip.removeP2pIface(name); 1888 break; 1889 case IfaceType.NAN: 1890 status = chip.removeNanIface(name); 1891 break; 1892 default: 1893 Log.wtf(TAG, "removeIfaceInternal: invalid type=" + type); 1894 return false; 1895 } 1896 } catch (RemoteException e) { 1897 Log.e(TAG, "IWifiChip.removeXxxIface exception: " + e); 1898 } 1899 1900 // dispatch listeners no matter what status 1901 dispatchDestroyedListeners(name, type); 1902 1903 if (status != null && status.code == WifiStatusCode.SUCCESS) { 1904 return true; 1905 } else { 1906 Log.e(TAG, "IWifiChip.removeXxxIface failed: " + statusString(status)); 1907 return false; 1908 } 1909 } 1910 } 1911 1912 // dispatch all available for request listeners of the specified type AND clean-out the list: 1913 // listeners are called once at most! 1914 private boolean dispatchAvailableForRequestListeners() { 1915 if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListeners"); 1916 1917 synchronized (mLock) { 1918 WifiChipInfo[] chipInfos = getAllChipInfo(); 1919 if (chipInfos == null) { 1920 Log.e(TAG, "dispatchAvailableForRequestListeners: no chip info found"); 1921 stopWifi(); // major error: shutting down 1922 return false; 1923 } 1924 if (VDBG) { 1925 Log.d(TAG, "dispatchAvailableForRequestListeners: chipInfos=" 1926 + Arrays.deepToString(chipInfos)); 1927 } 1928 1929 for (int ifaceType : IFACE_TYPES_BY_PRIORITY) { 1930 dispatchAvailableForRequestListenersForType(ifaceType, chipInfos); 1931 } 1932 } 1933 1934 return true; 1935 } 1936 1937 private void dispatchAvailableForRequestListenersForType(int ifaceType, 1938 WifiChipInfo[] chipInfos) { 1939 if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListenersForType: ifaceType=" + ifaceType); 1940 1941 synchronized (mLock) { 1942 Map<InterfaceAvailableForRequestListenerProxy, Boolean> listeners = 1943 mInterfaceAvailableForRequestListeners.get(ifaceType); 1944 1945 if (listeners.size() == 0) { 1946 return; 1947 } 1948 1949 boolean isAvailable = isItPossibleToCreateIface(chipInfos, ifaceType); 1950 1951 if (VDBG) { 1952 Log.d(TAG, "Interface available for: ifaceType=" + ifaceType + " = " + isAvailable); 1953 } 1954 for (Map.Entry<InterfaceAvailableForRequestListenerProxy, Boolean> listenerEntry : 1955 listeners.entrySet()) { 1956 if (listenerEntry.getValue() == null || listenerEntry.getValue() != isAvailable) { 1957 if (VDBG) { 1958 Log.d(TAG, "Interface available listener dispatched: ifaceType=" + ifaceType 1959 + ", listener=" + listenerEntry.getKey()); 1960 } 1961 listenerEntry.getKey().triggerWithArg(isAvailable); 1962 } 1963 listenerEntry.setValue(isAvailable); 1964 } 1965 } 1966 } 1967 1968 // dispatch all destroyed listeners registered for the specified interface AND remove the 1969 // cache entry 1970 private void dispatchDestroyedListeners(String name, int type) { 1971 if (VDBG) Log.d(TAG, "dispatchDestroyedListeners: iface(name)=" + name); 1972 1973 synchronized (mLock) { 1974 InterfaceCacheEntry entry = mInterfaceInfoCache.get(Pair.create(name, type)); 1975 if (entry == null) { 1976 Log.e(TAG, "dispatchDestroyedListeners: no cache entry for iface(name)=" + name); 1977 return; 1978 } 1979 1980 for (InterfaceDestroyedListenerProxy listener : entry.destroyedListeners) { 1981 listener.trigger(); 1982 } 1983 entry.destroyedListeners.clear(); // for insurance (though cache entry is removed) 1984 mInterfaceInfoCache.remove(Pair.create(name, type)); 1985 } 1986 } 1987 1988 // dispatch all destroyed listeners registered to all interfaces 1989 private void dispatchAllDestroyedListeners() { 1990 if (VDBG) Log.d(TAG, "dispatchAllDestroyedListeners"); 1991 1992 synchronized (mLock) { 1993 Iterator<Map.Entry<Pair<String, Integer>, InterfaceCacheEntry>> it = 1994 mInterfaceInfoCache.entrySet().iterator(); 1995 while (it.hasNext()) { 1996 InterfaceCacheEntry entry = it.next().getValue(); 1997 for (InterfaceDestroyedListenerProxy listener : entry.destroyedListeners) { 1998 listener.trigger(); 1999 } 2000 entry.destroyedListeners.clear(); // for insurance (though cache entry is removed) 2001 it.remove(); 2002 } 2003 } 2004 } 2005 2006 private abstract class ListenerProxy<LISTENER> { 2007 protected LISTENER mListener; 2008 private Handler mHandler; 2009 2010 // override equals & hash to make sure that the container HashSet is unique with respect to 2011 // the contained listener 2012 @Override 2013 public boolean equals(Object obj) { 2014 return mListener == ((ListenerProxy<LISTENER>) obj).mListener; 2015 } 2016 2017 @Override 2018 public int hashCode() { 2019 return mListener.hashCode(); 2020 } 2021 2022 void trigger() { 2023 if (mHandler != null) { 2024 mHandler.post(() -> { 2025 action(); 2026 }); 2027 } else { 2028 action(); 2029 } 2030 } 2031 2032 void triggerWithArg(boolean arg) { 2033 if (mHandler != null) { 2034 mHandler.post(() -> { 2035 actionWithArg(arg); 2036 }); 2037 } else { 2038 actionWithArg(arg); 2039 } 2040 } 2041 2042 protected void action() {} 2043 protected void actionWithArg(boolean arg) {} 2044 2045 ListenerProxy(LISTENER listener, Handler handler, String tag) { 2046 mListener = listener; 2047 mHandler = handler; 2048 } 2049 } 2050 2051 private class InterfaceDestroyedListenerProxy extends 2052 ListenerProxy<InterfaceDestroyedListener> { 2053 private final String mIfaceName; 2054 InterfaceDestroyedListenerProxy(@NonNull String ifaceName, 2055 InterfaceDestroyedListener destroyedListener, 2056 Handler handler) { 2057 super(destroyedListener, handler, "InterfaceDestroyedListenerProxy"); 2058 mIfaceName = ifaceName; 2059 } 2060 2061 @Override 2062 protected void action() { 2063 mListener.onDestroyed(mIfaceName); 2064 } 2065 } 2066 2067 private class InterfaceAvailableForRequestListenerProxy extends 2068 ListenerProxy<InterfaceAvailableForRequestListener> { 2069 InterfaceAvailableForRequestListenerProxy( 2070 InterfaceAvailableForRequestListener destroyedListener, Handler handler) { 2071 super(destroyedListener, handler, "InterfaceAvailableForRequestListenerProxy"); 2072 } 2073 2074 @Override 2075 protected void actionWithArg(boolean isAvailable) { 2076 mListener.onAvailabilityChanged(isAvailable); 2077 } 2078 } 2079 2080 // general utilities 2081 2082 private static String statusString(WifiStatus status) { 2083 if (status == null) { 2084 return "status=null"; 2085 } 2086 StringBuilder sb = new StringBuilder(); 2087 sb.append(status.code).append(" (").append(status.description).append(")"); 2088 return sb.toString(); 2089 } 2090 2091 // Will return -1 for invalid results! Otherwise will return one of the 4 valid values. 2092 private static int getType(IWifiIface iface) { 2093 MutableInt typeResp = new MutableInt(-1); 2094 try { 2095 iface.getType((WifiStatus status, int type) -> { 2096 if (status.code == WifiStatusCode.SUCCESS) { 2097 typeResp.value = type; 2098 } else { 2099 Log.e(TAG, "Error on getType: " + statusString(status)); 2100 } 2101 }); 2102 } catch (RemoteException e) { 2103 Log.e(TAG, "Exception on getType: " + e); 2104 } 2105 2106 return typeResp.value; 2107 } 2108 2109 /** 2110 * Dump the internal state of the class. 2111 */ 2112 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2113 pw.println("HalDeviceManager:"); 2114 pw.println(" mServiceManager: " + mServiceManager); 2115 pw.println(" mWifi: " + mWifi); 2116 pw.println(" mManagerStatusListeners: " + mManagerStatusListeners); 2117 pw.println(" mInterfaceAvailableForRequestListeners: " 2118 + mInterfaceAvailableForRequestListeners); 2119 pw.println(" mInterfaceInfoCache: " + mInterfaceInfoCache); 2120 } 2121 } 2122