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