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