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