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