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