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