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