SupplicantStaIfaceHal.java revision 727ba04029935d4faee3c7fce8a5a0ba6ed0a4ea
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 */ 16package com.android.server.wifi; 17 18import android.hardware.wifi.supplicant.V1_0.ISupplicant; 19import android.hardware.wifi.supplicant.V1_0.ISupplicantIface; 20import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork; 21import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIface; 22import android.hardware.wifi.supplicant.V1_0.ISupplicantStaNetwork; 23import android.hardware.wifi.supplicant.V1_0.IfaceType; 24import android.hardware.wifi.supplicant.V1_0.SupplicantStatus; 25import android.hardware.wifi.supplicant.V1_0.SupplicantStatusCode; 26import android.hidl.manager.V1_0.IServiceManager; 27import android.hidl.manager.V1_0.IServiceNotification; 28import android.net.wifi.WifiConfiguration; 29import android.os.HandlerThread; 30import android.os.RemoteException; 31import android.util.Log; 32import android.util.MutableBoolean; 33 34import com.android.server.wifi.util.NativeUtil; 35 36import java.util.ArrayList; 37 38/** 39 * Hal calls for bring up/shut down of the supplicant daemon and for 40 * sending requests to the supplicant daemon 41 */ 42public class SupplicantStaIfaceHal { 43 /** Invalid Supplicant Iface type */ 44 public static final int INVALID_IFACE_TYPE = -1; 45 private static final boolean DBG = false; 46 private static final String TAG = "SupplicantStaIfaceHal"; 47 private static final String SERVICE_MANAGER_NAME = "manager"; 48 private IServiceManager mIServiceManager = null; 49 // Supplicant HAL interface objects 50 private ISupplicant mISupplicant; 51 private ISupplicantStaIface mISupplicantStaIface; 52 private final Object mLock = new Object(); 53 private final HandlerThread mHandlerThread; 54 public SupplicantStaIfaceHal(HandlerThread handlerThread) { 55 mHandlerThread = handlerThread; 56 } 57 58 /** 59 * Registers a service notification for the ISupplicant service, which triggers intialization of 60 * the ISupplicantStaIface 61 * @return true if the service notification was successfully registered 62 */ 63 public boolean initialize() { 64 if (DBG) Log.i(TAG, "Registering ISupplicant service ready callback."); 65 synchronized (mLock) { 66 mISupplicant = null; 67 mISupplicantStaIface = null; 68 if (mIServiceManager != null) { 69 // Already have an IServiceManager and serviceNotification registered, don't 70 // don't register another. 71 return true; 72 } 73 try { 74 mIServiceManager = getServiceManagerMockable(); 75 if (mIServiceManager == null) { 76 Log.e(TAG, "Failed to get HIDL Service Manager"); 77 return false; 78 } 79 if (!mIServiceManager.linkToDeath(cookie -> { 80 Log.wtf(TAG, "IServiceManager died: cookie=" + cookie); 81 synchronized (mLock) { 82 supplicantServiceDiedHandler(); 83 mIServiceManager = null; // Will need to register a new ServiceNotification 84 } 85 }, 0)) { 86 Log.wtf(TAG, "Error on linkToDeath on IServiceManager"); 87 supplicantServiceDiedHandler(); 88 mIServiceManager = null; // Will need to register a new ServiceNotification 89 return false; 90 } 91 IServiceNotification serviceNotificationCb = new IServiceNotification.Stub() { 92 public void onRegistration(String fqName, String name, boolean preexisting) { 93 synchronized (mLock) { 94 if (DBG) { 95 Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName 96 + ", " + name + " preexisting=" + preexisting); 97 } 98 if (!initSupplicantService() || !initSupplicantStaIface()) { 99 Log.e(TAG, "initalizing ISupplicantIfaces failed."); 100 supplicantServiceDiedHandler(); 101 } else { 102 Log.i(TAG, "Completed initialization of ISupplicant interfaces."); 103 } 104 } 105 } 106 }; 107 /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it 108 exists */ 109 if (!mIServiceManager.registerForNotifications(ISupplicant.kInterfaceName, 110 "", serviceNotificationCb)) { 111 Log.e(TAG, "Failed to register for notifications to " 112 + ISupplicant.kInterfaceName); 113 mIServiceManager = null; // Will need to register a new ServiceNotification 114 return false; 115 } 116 } catch (RemoteException e) { 117 Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: " 118 + e); 119 supplicantServiceDiedHandler(); 120 } 121 return true; 122 } 123 } 124 125 private boolean initSupplicantService() { 126 synchronized (mLock) { 127 try { 128 mISupplicant = getSupplicantMockable(); 129 } catch (RemoteException e) { 130 Log.e(TAG, "ISupplicant.getService exception: " + e); 131 return false; 132 } 133 if (mISupplicant == null) { 134 Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup"); 135 return false; 136 } 137 } 138 return true; 139 } 140 141 private boolean initSupplicantStaIface() { 142 synchronized (mLock) { 143 /** List all supplicant Ifaces */ 144 final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>(); 145 try { 146 mISupplicant.listInterfaces((SupplicantStatus status, 147 ArrayList<ISupplicant.IfaceInfo> ifaces) -> { 148 if (status.code != SupplicantStatusCode.SUCCESS) { 149 Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code); 150 return; 151 } 152 supplicantIfaces.addAll(ifaces); 153 }); 154 } catch (RemoteException e) { 155 Log.e(TAG, "ISupplicant.listInterfaces exception: " + e); 156 return false; 157 } 158 if (supplicantIfaces.size() == 0) { 159 Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup."); 160 return false; 161 } 162 Mutable<ISupplicantIface> supplicantIface = new Mutable<>(); 163 for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) { 164 if (ifaceInfo.type == IfaceType.STA) { 165 try { 166 mISupplicant.getInterface(ifaceInfo, 167 (SupplicantStatus status, ISupplicantIface iface) -> { 168 if (status.code != SupplicantStatusCode.SUCCESS) { 169 Log.e(TAG, "Failed to get ISupplicantIface " + status.code); 170 return; 171 } 172 supplicantIface.value = iface; 173 }); 174 } catch (RemoteException e) { 175 Log.e(TAG, "ISupplicant.getInterface exception: " + e); 176 return false; 177 } 178 break; 179 } 180 } 181 if (supplicantIface.value == null) { 182 Log.e(TAG, "initSupplicantStaIface got null iface"); 183 return false; 184 } 185 mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value); 186 return true; 187 } 188 } 189 190 private void supplicantServiceDiedHandler() { 191 synchronized (mLock) { 192 mISupplicant = null; 193 mISupplicantStaIface = null; 194 } 195 } 196 197 /** 198 * Signals whether Initialization completed successfully. Only necessary for testing, is not 199 * needed to guard calls etc. 200 */ 201 public boolean isInitializationComplete() { 202 return mISupplicantStaIface != null; 203 } 204 205 /** 206 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 207 */ 208 protected IServiceManager getServiceManagerMockable() throws RemoteException { 209 return IServiceManager.getService(SERVICE_MANAGER_NAME); 210 } 211 212 protected ISupplicant getSupplicantMockable() throws RemoteException { 213 return ISupplicant.getService(); 214 } 215 216 protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) { 217 return ISupplicantStaIface.asInterface(iface.asBinder()); 218 } 219 220 /** 221 * Add a network configuration to wpa_supplicant, via HAL 222 * 223 * @param config Config corresponding to the network. 224 * @return SupplicantStaNetwork of the added network in wpa_supplicant. 225 */ 226 private SupplicantStaNetworkHal addNetwork(WifiConfiguration config) { 227 logi("addSupplicantStaNetwork via HIDL"); 228 if (config == null) { 229 loge("Cannot add NULL network!"); 230 return null; 231 } 232 SupplicantStaNetworkHal network = addNetwork(); 233 if (network == null) { 234 loge("Failed to add a network!"); 235 return null; 236 } 237 if (network.saveWifiConfiguration(config)) { 238 return network; 239 } else { 240 loge("Failed to save variables for: " + config.configKey()); 241 return null; 242 } 243 } 244 245 /** 246 * Initiate connection to the provided network. 247 * 248 * @param config Config corresponding to the network. 249 * @param shouldDisconnect Whether to trigger a disconnect first. 250 * @return true if request is sent successfully, false otherwise. 251 */ 252 public boolean connectToNetwork(WifiConfiguration config, boolean shouldDisconnect) { 253 logd("connectToNetwork " + config.configKey() 254 + " (shouldDisconnect " + shouldDisconnect + ")"); 255 if (shouldDisconnect && !disconnect()) { 256 loge("Failed to trigger disconnect"); 257 return false; 258 } 259 if (!removeAllNetworks()) { 260 loge("Failed to remove existing networks"); 261 return false; 262 } 263 SupplicantStaNetworkHal network = addNetwork(config); 264 if (network == null) { 265 loge("Failed to add/save network configuration: " + config.configKey()); 266 return false; 267 } 268 if (!network.select()) { 269 loge("Failed to select network configuration: " + config.configKey()); 270 return false; 271 } 272 return true; 273 } 274 275 /** 276 * Remove all networks from supplicant 277 * TODO(b/34454675) use ISupplicantIface.removeAllNetworks when it exists 278 */ 279 public boolean removeAllNetworks() { 280 synchronized (mLock) { 281 ArrayList<Integer> networks = listNetworks(); 282 if (networks == null) { 283 Log.e(TAG, "removeAllNetworks failed, got null networks"); 284 return false; 285 } 286 for (int id : networks) { 287 if (!removeNetwork(id)) { 288 Log.e(TAG, "removeAllNetworks failed to remove network: " + id); 289 return false; 290 } 291 } 292 } 293 return true; 294 } 295 296 /** 297 * Gets the interface name. 298 * 299 * @return returns the name of Iface or null if the call fails 300 */ 301 private String getName() { 302 synchronized (mLock) { 303 MutableBoolean statusSuccess = new MutableBoolean(false); 304 final String methodStr = "getName"; 305 if (DBG) Log.i(TAG, methodStr); 306 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 307 final StringBuilder builder = new StringBuilder(); 308 try { 309 mISupplicantStaIface.getName((SupplicantStatus status, String name) -> { 310 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 311 if (!statusSuccess.value) { 312 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 313 } else { 314 builder.append(name); 315 } 316 }); 317 } catch (RemoteException e) { 318 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 319 supplicantServiceDiedHandler(); 320 } 321 if (statusSuccess.value) { 322 return builder.toString(); 323 } else { 324 return null; 325 } 326 } 327 } 328 329 /** 330 * Adds a new network. 331 * 332 * @return The ISupplicantNetwork object for the new network, or null if the call fails 333 */ 334 private SupplicantStaNetworkHal addNetwork() { 335 synchronized (mLock) { 336 MutableBoolean statusSuccess = new MutableBoolean(false); 337 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>(); 338 final String methodStr = "addNetwork"; 339 if (DBG) Log.i(TAG, methodStr); 340 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 341 try { 342 mISupplicantStaIface.addNetwork((SupplicantStatus status, 343 ISupplicantNetwork network) -> { 344 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 345 if (!statusSuccess.value) { 346 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 347 } else { 348 newNetwork.value = network; 349 } 350 }); 351 } catch (RemoteException e) { 352 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 353 supplicantServiceDiedHandler(); 354 } 355 if (statusSuccess.value) { 356 return new SupplicantStaNetworkHal(ISupplicantStaNetwork.asInterface( 357 newNetwork.value.asBinder()), mHandlerThread); 358 } else { 359 return null; 360 } 361 } 362 } 363 364 /** 365 * Remove network from supplicant with network Id 366 * 367 * @return true if request is sent successfully, false otherwise. 368 */ 369 private boolean removeNetwork(int id) { 370 synchronized (mLock) { 371 final String methodStr = "removeNetwork"; 372 if (DBG) Log.i(TAG, methodStr); 373 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 374 try { 375 SupplicantStatus status = mISupplicantStaIface.removeNetwork(id); 376 return checkStatusAndLogFailure(status, methodStr); 377 } catch (RemoteException e) { 378 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 379 supplicantServiceDiedHandler(); 380 return false; 381 } 382 } 383 } 384 385 /** 386 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 387 * the call fails 388 */ 389 private SupplicantStaNetworkHal getNetwork(int id) { 390 synchronized (mLock) { 391 MutableBoolean statusSuccess = new MutableBoolean(false); 392 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>(); 393 final String methodStr = "getNetwork"; 394 if (DBG) Log.i(TAG, methodStr); 395 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 396 try { 397 mISupplicantStaIface.getNetwork(id, (SupplicantStatus status, 398 ISupplicantNetwork network) -> { 399 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 400 if (!statusSuccess.value) { 401 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 402 } else { 403 gotNetwork.value = network; 404 } 405 }); 406 } catch (RemoteException e) { 407 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 408 supplicantServiceDiedHandler(); 409 } 410 if (statusSuccess.value) { 411 return new SupplicantStaNetworkHal(ISupplicantStaNetwork.asInterface( 412 gotNetwork.value.asBinder()), mHandlerThread); 413 } else { 414 return null; 415 } 416 } 417 } 418 419 /** 420 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns 421 * null if the call fails 422 */ 423 private java.util.ArrayList<Integer> listNetworks() { 424 synchronized (mLock) { 425 MutableBoolean statusSuccess = new MutableBoolean(false); 426 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>(); 427 final String methodStr = "listNetworks"; 428 if (DBG) Log.i(TAG, methodStr); 429 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 430 try { 431 mISupplicantStaIface.listNetworks((SupplicantStatus status, 432 java.util.ArrayList<Integer> networkIds) -> { 433 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 434 if (!statusSuccess.value) { 435 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 436 } else { 437 networkIdList.value = networkIds; 438 } 439 }); 440 } catch (RemoteException e) { 441 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 442 supplicantServiceDiedHandler(); 443 } 444 if (statusSuccess.value) { 445 return networkIdList.value; 446 } else { 447 return null; 448 } 449 } 450 } 451 452 /** 453 * Trigger a reassociation even if the iface is currently connected. 454 * 455 * @return true if request is sent successfully, false otherwise. 456 */ 457 public boolean reassociate() { 458 synchronized (mLock) { 459 final String methodStr = "reassociate"; 460 if (DBG) Log.i(TAG, methodStr); 461 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 462 try { 463 SupplicantStatus status = mISupplicantStaIface.reassociate(); 464 return checkStatusAndLogFailure(status, methodStr); 465 } catch (RemoteException e) { 466 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 467 supplicantServiceDiedHandler(); 468 return false; 469 } 470 } 471 } 472 473 /** 474 * Trigger a reconnection if the iface is disconnected. 475 * 476 * @return true if request is sent successfully, false otherwise. 477 */ 478 public boolean reconnect() { 479 synchronized (mLock) { 480 final String methodStr = "reconnect"; 481 if (DBG) Log.i(TAG, methodStr); 482 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 483 try { 484 SupplicantStatus status = mISupplicantStaIface.reconnect(); 485 return checkStatusAndLogFailure(status, methodStr); 486 } catch (RemoteException e) { 487 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 488 supplicantServiceDiedHandler(); 489 return false; 490 } 491 } 492 } 493 494 /** 495 * Trigger a disconnection from the currently connected network. 496 * 497 * @return true if request is sent successfully, false otherwise. 498 */ 499 public boolean disconnect() { 500 synchronized (mLock) { 501 final String methodStr = "disconnect"; 502 if (DBG) Log.i(TAG, methodStr); 503 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 504 try { 505 SupplicantStatus status = mISupplicantStaIface.disconnect(); 506 return checkStatusAndLogFailure(status, methodStr); 507 } catch (RemoteException e) { 508 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 509 supplicantServiceDiedHandler(); 510 return false; 511 } 512 } 513 } 514 515 /** 516 * Enable or disable power save mode. 517 * 518 * @param enable true to enable, false to disable. 519 * @return true if request is sent successfully, false otherwise. 520 */ 521 public boolean setPowerSave(boolean enable) { 522 synchronized (mLock) { 523 final String methodStr = "setPowerSave"; 524 if (DBG) Log.i(TAG, methodStr); 525 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 526 try { 527 SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable); 528 return checkStatusAndLogFailure(status, methodStr); 529 } catch (RemoteException e) { 530 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 531 supplicantServiceDiedHandler(); 532 return false; 533 } 534 } 535 } 536 537 /** 538 * Initiate TDLS discover with the specified AP. 539 * 540 * @param macAddress MAC Address of the AP. 541 * @return true if request is sent successfully, false otherwise. 542 */ 543 public boolean initiateTdlsDiscover(String macAddress) { 544 return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress)); 545 } 546 /** See ISupplicantStaIface.hal for documentation */ 547 private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) { 548 synchronized (mLock) { 549 final String methodStr = "initiateTdlsDiscover"; 550 if (DBG) Log.i(TAG, methodStr); 551 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 552 try { 553 SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress); 554 return checkStatusAndLogFailure(status, methodStr); 555 } catch (RemoteException e) { 556 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 557 supplicantServiceDiedHandler(); 558 return false; 559 } 560 } 561 } 562 563 /** 564 * Initiate TDLS setup with the specified AP. 565 * 566 * @param macAddress MAC Address of the AP. 567 * @return true if request is sent successfully, false otherwise. 568 */ 569 public boolean initiateTdlsSetup(String macAddress) { 570 return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress)); 571 } 572 /** See ISupplicantStaIface.hal for documentation */ 573 private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) { 574 synchronized (mLock) { 575 final String methodStr = "initiateTdlsSetup"; 576 if (DBG) Log.i(TAG, methodStr); 577 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 578 try { 579 SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress); 580 return checkStatusAndLogFailure(status, methodStr); 581 } catch (RemoteException e) { 582 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 583 supplicantServiceDiedHandler(); 584 return false; 585 } 586 } 587 } 588 589 /** 590 * Initiate TDLS teardown with the specified AP. 591 * @param macAddress MAC Address of the AP. 592 * @return true if request is sent successfully, false otherwise. 593 */ 594 public boolean initiateTdlsTeardown(String macAddress) { 595 return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress)); 596 } 597 598 /** See ISupplicantStaIface.hal for documentation */ 599 private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) { 600 synchronized (mLock) { 601 final String methodStr = "initiateTdlsTeardown"; 602 if (DBG) Log.i(TAG, methodStr); 603 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 604 try { 605 SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress); 606 return checkStatusAndLogFailure(status, methodStr); 607 } catch (RemoteException e) { 608 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 609 supplicantServiceDiedHandler(); 610 return false; 611 } 612 } 613 } 614 615 /** 616 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 617 * 618 * @param bssid BSSID of the AP 619 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId. 620 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes. 621 * @return true if request is sent successfully, false otherwise. 622 */ 623 public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements, 624 ArrayList<Integer> hs20SubTypes) { 625 return initiateAnqpQuery( 626 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes); 627 } 628 629 /** See ISupplicantStaIface.hal for documentation */ 630 private boolean initiateAnqpQuery(byte[/* 6 */] macAddress, 631 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) { 632 synchronized (mLock) { 633 final String methodStr = "initiateAnqpQuery"; 634 if (DBG) Log.i(TAG, methodStr); 635 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 636 try { 637 SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress, 638 infoElements, subTypes); 639 return checkStatusAndLogFailure(status, methodStr); 640 } catch (RemoteException e) { 641 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 642 supplicantServiceDiedHandler(); 643 return false; 644 } 645 } 646 } 647 648 /** 649 * Request the specified ANQP ICON from the specified AP |bssid|. 650 * 651 * @param bssid BSSID of the AP 652 * @param fileName Name of the file to request. 653 * @return true if request is sent successfully, false otherwise. 654 */ 655 public boolean initiateHs20IconQuery(String bssid, String fileName) { 656 return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName); 657 } 658 659 /** See ISupplicantStaIface.hal for documentation */ 660 private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) { 661 synchronized (mLock) { 662 final String methodStr = "initiateHs20IconQuery"; 663 if (DBG) Log.i(TAG, methodStr); 664 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 665 try { 666 SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress, 667 fileName); 668 return checkStatusAndLogFailure(status, methodStr); 669 } catch (RemoteException e) { 670 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 671 supplicantServiceDiedHandler(); 672 return false; 673 } 674 } 675 } 676 677 /** 678 * Makes a callback to HIDL to getMacAddress from supplicant 679 * 680 * @return string containing the MAC address, or null on a failed call 681 */ 682 public String getMacAddress() { 683 synchronized (mLock) { 684 MutableBoolean statusSuccess = new MutableBoolean(false); 685 final String methodStr = "getMacAddress"; 686 if (DBG) Log.i(TAG, methodStr); 687 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 688 Mutable<String> gotMac = new Mutable<>(); 689 try { 690 mISupplicantStaIface.getMacAddress((SupplicantStatus status, 691 byte[/* 6 */] macAddr) -> { 692 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 693 if (!statusSuccess.value) { 694 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 695 } else { 696 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr); 697 } 698 }); 699 } catch (RemoteException e) { 700 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 701 supplicantServiceDiedHandler(); 702 } 703 if (statusSuccess.value) { 704 return gotMac.value; 705 } else { 706 return null; 707 } 708 } 709 } 710 711 /** 712 * Start using the added RX filters. 713 * 714 * @return true if request is sent successfully, false otherwise. 715 */ 716 public boolean startRxFilter() { 717 synchronized (mLock) { 718 final String methodStr = "startRxFilter"; 719 if (DBG) Log.i(TAG, methodStr); 720 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 721 try { 722 SupplicantStatus status = mISupplicantStaIface.startRxFilter(); 723 return checkStatusAndLogFailure(status, methodStr); 724 } catch (RemoteException e) { 725 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 726 supplicantServiceDiedHandler(); 727 return false; 728 } 729 } 730 } 731 732 /** 733 * Stop using the added RX filters. 734 * 735 * @return true if request is sent successfully, false otherwise. 736 */ 737 public boolean stopRxFilter() { 738 synchronized (mLock) { 739 final String methodStr = "stopRxFilter"; 740 if (DBG) Log.i(TAG, methodStr); 741 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 742 try { 743 SupplicantStatus status = mISupplicantStaIface.stopRxFilter(); 744 return checkStatusAndLogFailure(status, methodStr); 745 } catch (RemoteException e) { 746 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 747 supplicantServiceDiedHandler(); 748 return false; 749 } 750 } 751 } 752 753 public static final byte RX_FILTER_TYPE_V4_MULTICAST = 754 ISupplicantStaIface.RxFilterType.V6_MULTICAST; 755 public static final byte RX_FILTER_TYPE_V6_MULTICAST = 756 ISupplicantStaIface.RxFilterType.V6_MULTICAST; 757 /** 758 * Add an RX filter. 759 * 760 * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or 761 * {@link #RX_FILTER_TYPE_V6_MULTICAST} values. 762 * @return true if request is sent successfully, false otherwise. 763 */ 764 private boolean addRxFilter(byte type) { 765 synchronized (mLock) { 766 final String methodStr = "addRxFilter"; 767 if (DBG) Log.i(TAG, methodStr); 768 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 769 try { 770 SupplicantStatus status = mISupplicantStaIface.addRxFilter(type); 771 return checkStatusAndLogFailure(status, methodStr); 772 } catch (RemoteException e) { 773 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 774 supplicantServiceDiedHandler(); 775 return false; 776 } 777 } 778 } 779 780 /** 781 * Remove an RX filter. 782 * 783 * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or 784 * {@link #RX_FILTER_TYPE_V6_MULTICAST} values. 785 * @return true if request is sent successfully, false otherwise. 786 */ 787 private boolean removeRxFilter(byte type) { 788 synchronized (mLock) { 789 final String methodStr = "removeRxFilter"; 790 if (DBG) Log.i(TAG, methodStr); 791 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 792 try { 793 SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type); 794 return checkStatusAndLogFailure(status, methodStr); 795 } catch (RemoteException e) { 796 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 797 supplicantServiceDiedHandler(); 798 return false; 799 } 800 } 801 } 802 803 public static final byte BT_COEX_MODE_ENABLED = ISupplicantStaIface.BtCoexistenceMode.ENABLED; 804 public static final byte BT_COEX_MODE_DISABLED = ISupplicantStaIface.BtCoexistenceMode.DISABLED; 805 public static final byte BT_COEX_MODE_SENSE = ISupplicantStaIface.BtCoexistenceMode.SENSE; 806 /** 807 * Set Bt co existense mode. 808 * 809 * @param mode one of the above {@link #BT_COEX_MODE_ENABLED}, {@link #BT_COEX_MODE_DISABLED} 810 * or {@link #BT_COEX_MODE_SENSE} values. 811 * @return true if request is sent successfully, false otherwise. 812 */ 813 public boolean setBtCoexistenceMode(byte mode) { 814 synchronized (mLock) { 815 final String methodStr = "setBtCoexistenceMode"; 816 if (DBG) Log.i(TAG, methodStr); 817 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 818 try { 819 SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode); 820 return checkStatusAndLogFailure(status, methodStr); 821 } catch (RemoteException e) { 822 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 823 supplicantServiceDiedHandler(); 824 return false; 825 } 826 } 827 } 828 829 /** Enable or disable BT coexistence mode. 830 * 831 * @param enable true to enable, false to disable. 832 * @return true if request is sent successfully, false otherwise. 833 */ 834 public boolean setBtCoexistenceScanModeEnabled(boolean enable) { 835 synchronized (mLock) { 836 final String methodStr = "setBtCoexistenceScanModeEnabled"; 837 if (DBG) Log.i(TAG, methodStr); 838 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 839 try { 840 SupplicantStatus status = 841 mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable); 842 return checkStatusAndLogFailure(status, methodStr); 843 } catch (RemoteException e) { 844 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 845 supplicantServiceDiedHandler(); 846 return false; 847 } 848 } 849 } 850 851 /** 852 * Enable or disable suspend mode optimizations. 853 * 854 * @param enable true to enable, false otherwise. 855 */ 856 public boolean setSuspendModeEnabled(boolean enable) { 857 synchronized (mLock) { 858 final String methodStr = "setSuspendModeEnabled"; 859 if (DBG) Log.i(TAG, methodStr); 860 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 861 try { 862 SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable); 863 return checkStatusAndLogFailure(status, methodStr); 864 } catch (RemoteException e) { 865 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 866 supplicantServiceDiedHandler(); 867 return false; 868 } 869 } 870 } 871 872 /** 873 * Set country code. 874 * 875 * @param codeStr 2 byte ASCII string. For ex: US, CA. 876 * @return true if request is sent successfully, false otherwise. 877 */ 878 public boolean setCountryCode(String codeStr) { 879 return setCountryCode(NativeUtil.stringToByteArray(codeStr)); 880 } 881 882 /** See ISupplicantStaIface.hal for documentation */ 883 private boolean setCountryCode(byte[/* 2 */] code) { 884 synchronized (mLock) { 885 final String methodStr = "setCountryCode"; 886 if (DBG) Log.i(TAG, methodStr); 887 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 888 try { 889 SupplicantStatus status = mISupplicantStaIface.setCountryCode(code); 890 return checkStatusAndLogFailure(status, methodStr); 891 } catch (RemoteException e) { 892 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 893 supplicantServiceDiedHandler(); 894 return false; 895 } 896 } 897 } 898 899 /** 900 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr 901 */ 902 private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) { 903 if (DBG) Log.i(TAG, methodStr); 904 if (mISupplicantStaIface == null) { 905 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null"); 906 return false; 907 } 908 return true; 909 } 910 911 /** 912 * Returns true if provided status code is SUCCESS, logs debug message and returns false 913 * otherwise 914 */ 915 private static boolean checkStatusAndLogFailure(SupplicantStatus status, 916 final String methodStr) { 917 if (DBG) Log.i(TAG, methodStr); 918 if (status.code != SupplicantStatusCode.SUCCESS) { 919 Log.e(TAG, methodStr + " failed: " + supplicantStatusCodeToString(status.code) + ", " 920 + status.debugMessage); 921 return false; 922 } 923 return true; 924 } 925 926 /** 927 * Converts SupplicantStatus code values to strings for debug logging 928 * TODO(b/34811152) Remove this, or make it more break resistance 929 */ 930 public static String supplicantStatusCodeToString(int code) { 931 switch (code) { 932 case 0: 933 return "SUCCESS"; 934 case 1: 935 return "FAILURE_UNKNOWN"; 936 case 2: 937 return "FAILURE_ARGS_INVALID"; 938 case 3: 939 return "FAILURE_IFACE_INVALID"; 940 case 4: 941 return "FAILURE_IFACE_UNKNOWN"; 942 case 5: 943 return "FAILURE_IFACE_EXISTS"; 944 case 6: 945 return "FAILURE_IFACE_DISABLED"; 946 case 7: 947 return "FAILURE_IFACE_NOT_DISCONNECTED"; 948 case 8: 949 return "FAILURE_NETWORK_INVALID"; 950 case 9: 951 return "FAILURE_NETWORK_UNKNOWN"; 952 default: 953 return "??? UNKNOWN_CODE"; 954 } 955 } 956 957 private static class Mutable<E> { 958 public E value; 959 960 Mutable() { 961 value = null; 962 } 963 964 Mutable(E value) { 965 this.value = value; 966 } 967 } 968 969 private void logd(String s) { 970 Log.d(TAG, s); 971 } 972 973 private void logi(String s) { 974 Log.i(TAG, s); 975 } 976 977 private void loge(String s) { 978 Log.e(TAG, s); 979 } 980} 981