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