SupplicantStaIfaceHal.java revision d95fa596d07855b70ff18a50a48e773155a919f5
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.getId()) { 269 loge("Failed to get network id for configuration: " + config.configKey()); 270 return false; 271 } 272 if (!network.select()) { 273 loge("Failed to select network configuration: " + config.configKey()); 274 return false; 275 } 276 return true; 277 } 278 279 /** 280 * Remove all networks from supplicant 281 * TODO(b/34454675) use ISupplicantIface.removeAllNetworks when it exists 282 */ 283 public boolean removeAllNetworks() { 284 synchronized (mLock) { 285 ArrayList<Integer> networks = listNetworks(); 286 if (networks == null) { 287 Log.e(TAG, "removeAllNetworks failed, got null networks"); 288 return false; 289 } 290 for (int id : networks) { 291 if (!removeNetwork(id)) { 292 Log.e(TAG, "removeAllNetworks failed to remove network: " + id); 293 return false; 294 } 295 } 296 } 297 return true; 298 } 299 300 /** 301 * Gets the interface name. 302 * 303 * @return returns the name of Iface or null if the call fails 304 */ 305 private String getName() { 306 synchronized (mLock) { 307 MutableBoolean statusSuccess = new MutableBoolean(false); 308 final String methodStr = "getName"; 309 if (DBG) Log.i(TAG, methodStr); 310 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 311 final StringBuilder builder = new StringBuilder(); 312 try { 313 mISupplicantStaIface.getName((SupplicantStatus status, String name) -> { 314 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 315 if (!statusSuccess.value) { 316 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 317 } else { 318 builder.append(name); 319 } 320 }); 321 } catch (RemoteException e) { 322 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 323 supplicantServiceDiedHandler(); 324 } 325 if (statusSuccess.value) { 326 return builder.toString(); 327 } else { 328 return null; 329 } 330 } 331 } 332 333 /** 334 * Adds a new network. 335 * 336 * @return The ISupplicantNetwork object for the new network, or null if the call fails 337 */ 338 private SupplicantStaNetworkHal addNetwork() { 339 synchronized (mLock) { 340 MutableBoolean statusSuccess = new MutableBoolean(false); 341 Mutable<ISupplicantNetwork> newNetwork = new Mutable<>(); 342 final String methodStr = "addNetwork"; 343 if (DBG) Log.i(TAG, methodStr); 344 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 345 try { 346 mISupplicantStaIface.addNetwork((SupplicantStatus status, 347 ISupplicantNetwork network) -> { 348 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 349 if (!statusSuccess.value) { 350 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 351 } else { 352 newNetwork.value = network; 353 } 354 }); 355 } catch (RemoteException e) { 356 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 357 supplicantServiceDiedHandler(); 358 } 359 if (statusSuccess.value) { 360 return new SupplicantStaNetworkHal(ISupplicantStaNetwork.asInterface( 361 newNetwork.value.asBinder()), mHandlerThread); 362 } else { 363 return null; 364 } 365 } 366 } 367 368 /** 369 * Remove network from supplicant with network Id 370 * 371 * @return true if request is sent successfully, false otherwise. 372 */ 373 private boolean removeNetwork(int id) { 374 synchronized (mLock) { 375 final String methodStr = "removeNetwork"; 376 if (DBG) Log.i(TAG, methodStr); 377 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 378 try { 379 SupplicantStatus status = mISupplicantStaIface.removeNetwork(id); 380 return checkStatusAndLogFailure(status, methodStr); 381 } catch (RemoteException e) { 382 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 383 supplicantServiceDiedHandler(); 384 return false; 385 } 386 } 387 } 388 389 /** 390 * @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if 391 * the call fails 392 */ 393 private SupplicantStaNetworkHal getNetwork(int id) { 394 synchronized (mLock) { 395 MutableBoolean statusSuccess = new MutableBoolean(false); 396 Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>(); 397 final String methodStr = "getNetwork"; 398 if (DBG) Log.i(TAG, methodStr); 399 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 400 try { 401 mISupplicantStaIface.getNetwork(id, (SupplicantStatus status, 402 ISupplicantNetwork network) -> { 403 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 404 if (!statusSuccess.value) { 405 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 406 } else { 407 gotNetwork.value = network; 408 } 409 }); 410 } catch (RemoteException e) { 411 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 412 supplicantServiceDiedHandler(); 413 } 414 if (statusSuccess.value) { 415 return new SupplicantStaNetworkHal(ISupplicantStaNetwork.asInterface( 416 gotNetwork.value.asBinder()), mHandlerThread); 417 } else { 418 return null; 419 } 420 } 421 } 422 423 /** 424 * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns 425 * null if the call fails 426 */ 427 private java.util.ArrayList<Integer> listNetworks() { 428 synchronized (mLock) { 429 MutableBoolean statusSuccess = new MutableBoolean(false); 430 Mutable<ArrayList<Integer>> networkIdList = new Mutable<>(); 431 final String methodStr = "listNetworks"; 432 if (DBG) Log.i(TAG, methodStr); 433 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 434 try { 435 mISupplicantStaIface.listNetworks((SupplicantStatus status, 436 java.util.ArrayList<Integer> networkIds) -> { 437 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 438 if (!statusSuccess.value) { 439 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 440 } else { 441 networkIdList.value = networkIds; 442 } 443 }); 444 } catch (RemoteException e) { 445 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 446 supplicantServiceDiedHandler(); 447 } 448 if (statusSuccess.value) { 449 return networkIdList.value; 450 } else { 451 return null; 452 } 453 } 454 } 455 456 /** 457 * Trigger a reassociation even if the iface is currently connected. 458 * 459 * @return true if request is sent successfully, false otherwise. 460 */ 461 public boolean reassociate() { 462 synchronized (mLock) { 463 final String methodStr = "reassociate"; 464 if (DBG) Log.i(TAG, methodStr); 465 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 466 try { 467 SupplicantStatus status = mISupplicantStaIface.reassociate(); 468 return checkStatusAndLogFailure(status, methodStr); 469 } catch (RemoteException e) { 470 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 471 supplicantServiceDiedHandler(); 472 return false; 473 } 474 } 475 } 476 477 /** 478 * Trigger a reconnection if the iface is disconnected. 479 * 480 * @return true if request is sent successfully, false otherwise. 481 */ 482 public boolean reconnect() { 483 synchronized (mLock) { 484 final String methodStr = "reconnect"; 485 if (DBG) Log.i(TAG, methodStr); 486 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 487 try { 488 SupplicantStatus status = mISupplicantStaIface.reconnect(); 489 return checkStatusAndLogFailure(status, methodStr); 490 } catch (RemoteException e) { 491 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 492 supplicantServiceDiedHandler(); 493 return false; 494 } 495 } 496 } 497 498 /** 499 * Trigger a disconnection from the currently connected network. 500 * 501 * @return true if request is sent successfully, false otherwise. 502 */ 503 public boolean disconnect() { 504 synchronized (mLock) { 505 final String methodStr = "disconnect"; 506 if (DBG) Log.i(TAG, methodStr); 507 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 508 try { 509 SupplicantStatus status = mISupplicantStaIface.disconnect(); 510 return checkStatusAndLogFailure(status, methodStr); 511 } catch (RemoteException e) { 512 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 513 supplicantServiceDiedHandler(); 514 return false; 515 } 516 } 517 } 518 519 /** 520 * Enable or disable power save mode. 521 * 522 * @param enable true to enable, false to disable. 523 * @return true if request is sent successfully, false otherwise. 524 */ 525 public boolean setPowerSave(boolean enable) { 526 synchronized (mLock) { 527 final String methodStr = "setPowerSave"; 528 if (DBG) Log.i(TAG, methodStr); 529 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 530 try { 531 SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable); 532 return checkStatusAndLogFailure(status, methodStr); 533 } catch (RemoteException e) { 534 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 535 supplicantServiceDiedHandler(); 536 return false; 537 } 538 } 539 } 540 541 /** 542 * Initiate TDLS discover with the specified AP. 543 * 544 * @param macAddress MAC Address of the AP. 545 * @return true if request is sent successfully, false otherwise. 546 */ 547 public boolean initiateTdlsDiscover(String macAddress) { 548 return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress)); 549 } 550 /** See ISupplicantStaIface.hal for documentation */ 551 private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) { 552 synchronized (mLock) { 553 final String methodStr = "initiateTdlsDiscover"; 554 if (DBG) Log.i(TAG, methodStr); 555 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 556 try { 557 SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress); 558 return checkStatusAndLogFailure(status, methodStr); 559 } catch (RemoteException e) { 560 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 561 supplicantServiceDiedHandler(); 562 return false; 563 } 564 } 565 } 566 567 /** 568 * Initiate TDLS setup with the specified AP. 569 * 570 * @param macAddress MAC Address of the AP. 571 * @return true if request is sent successfully, false otherwise. 572 */ 573 public boolean initiateTdlsSetup(String macAddress) { 574 return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress)); 575 } 576 /** See ISupplicantStaIface.hal for documentation */ 577 private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) { 578 synchronized (mLock) { 579 final String methodStr = "initiateTdlsSetup"; 580 if (DBG) Log.i(TAG, methodStr); 581 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 582 try { 583 SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress); 584 return checkStatusAndLogFailure(status, methodStr); 585 } catch (RemoteException e) { 586 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 587 supplicantServiceDiedHandler(); 588 return false; 589 } 590 } 591 } 592 593 /** 594 * Initiate TDLS teardown with the specified AP. 595 * @param macAddress MAC Address of the AP. 596 * @return true if request is sent successfully, false otherwise. 597 */ 598 public boolean initiateTdlsTeardown(String macAddress) { 599 return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress)); 600 } 601 602 /** See ISupplicantStaIface.hal for documentation */ 603 private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) { 604 synchronized (mLock) { 605 final String methodStr = "initiateTdlsTeardown"; 606 if (DBG) Log.i(TAG, methodStr); 607 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 608 try { 609 SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress); 610 return checkStatusAndLogFailure(status, methodStr); 611 } catch (RemoteException e) { 612 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 613 supplicantServiceDiedHandler(); 614 return false; 615 } 616 } 617 } 618 619 /** 620 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 621 * 622 * @param bssid BSSID of the AP 623 * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId. 624 * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes. 625 * @return true if request is sent successfully, false otherwise. 626 */ 627 public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements, 628 ArrayList<Integer> hs20SubTypes) { 629 return initiateAnqpQuery( 630 NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes); 631 } 632 633 /** See ISupplicantStaIface.hal for documentation */ 634 private boolean initiateAnqpQuery(byte[/* 6 */] macAddress, 635 java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) { 636 synchronized (mLock) { 637 final String methodStr = "initiateAnqpQuery"; 638 if (DBG) Log.i(TAG, methodStr); 639 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 640 try { 641 SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress, 642 infoElements, subTypes); 643 return checkStatusAndLogFailure(status, methodStr); 644 } catch (RemoteException e) { 645 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 646 supplicantServiceDiedHandler(); 647 return false; 648 } 649 } 650 } 651 652 /** 653 * Request the specified ANQP ICON from the specified AP |bssid|. 654 * 655 * @param bssid BSSID of the AP 656 * @param fileName Name of the file to request. 657 * @return true if request is sent successfully, false otherwise. 658 */ 659 public boolean initiateHs20IconQuery(String bssid, String fileName) { 660 return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName); 661 } 662 663 /** See ISupplicantStaIface.hal for documentation */ 664 private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) { 665 synchronized (mLock) { 666 final String methodStr = "initiateHs20IconQuery"; 667 if (DBG) Log.i(TAG, methodStr); 668 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 669 try { 670 SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress, 671 fileName); 672 return checkStatusAndLogFailure(status, methodStr); 673 } catch (RemoteException e) { 674 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 675 supplicantServiceDiedHandler(); 676 return false; 677 } 678 } 679 } 680 681 /** 682 * Makes a callback to HIDL to getMacAddress from supplicant 683 * 684 * @return string containing the MAC address, or null on a failed call 685 */ 686 public String getMacAddress() { 687 synchronized (mLock) { 688 MutableBoolean statusSuccess = new MutableBoolean(false); 689 final String methodStr = "getMacAddress"; 690 if (DBG) Log.i(TAG, methodStr); 691 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null; 692 Mutable<String> gotMac = new Mutable<>(); 693 try { 694 mISupplicantStaIface.getMacAddress((SupplicantStatus status, 695 byte[/* 6 */] macAddr) -> { 696 statusSuccess.value = status.code == SupplicantStatusCode.SUCCESS; 697 if (!statusSuccess.value) { 698 Log.e(TAG, methodStr + " failed: " + status.debugMessage); 699 } else { 700 gotMac.value = NativeUtil.macAddressFromByteArray(macAddr); 701 } 702 }); 703 } catch (RemoteException e) { 704 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception: " + e); 705 supplicantServiceDiedHandler(); 706 } 707 if (statusSuccess.value) { 708 return gotMac.value; 709 } else { 710 return null; 711 } 712 } 713 } 714 715 /** 716 * Start using the added RX filters. 717 * 718 * @return true if request is sent successfully, false otherwise. 719 */ 720 public boolean startRxFilter() { 721 synchronized (mLock) { 722 final String methodStr = "startRxFilter"; 723 if (DBG) Log.i(TAG, methodStr); 724 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 725 try { 726 SupplicantStatus status = mISupplicantStaIface.startRxFilter(); 727 return checkStatusAndLogFailure(status, methodStr); 728 } catch (RemoteException e) { 729 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 730 supplicantServiceDiedHandler(); 731 return false; 732 } 733 } 734 } 735 736 /** 737 * Stop using the added RX filters. 738 * 739 * @return true if request is sent successfully, false otherwise. 740 */ 741 public boolean stopRxFilter() { 742 synchronized (mLock) { 743 final String methodStr = "stopRxFilter"; 744 if (DBG) Log.i(TAG, methodStr); 745 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 746 try { 747 SupplicantStatus status = mISupplicantStaIface.stopRxFilter(); 748 return checkStatusAndLogFailure(status, methodStr); 749 } catch (RemoteException e) { 750 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 751 supplicantServiceDiedHandler(); 752 return false; 753 } 754 } 755 } 756 757 public static final byte RX_FILTER_TYPE_V4_MULTICAST = 758 ISupplicantStaIface.RxFilterType.V6_MULTICAST; 759 public static final byte RX_FILTER_TYPE_V6_MULTICAST = 760 ISupplicantStaIface.RxFilterType.V6_MULTICAST; 761 /** 762 * Add an RX filter. 763 * 764 * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or 765 * {@link #RX_FILTER_TYPE_V6_MULTICAST} values. 766 * @return true if request is sent successfully, false otherwise. 767 */ 768 private boolean addRxFilter(byte type) { 769 synchronized (mLock) { 770 final String methodStr = "addRxFilter"; 771 if (DBG) Log.i(TAG, methodStr); 772 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 773 try { 774 SupplicantStatus status = mISupplicantStaIface.addRxFilter(type); 775 return checkStatusAndLogFailure(status, methodStr); 776 } catch (RemoteException e) { 777 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 778 supplicantServiceDiedHandler(); 779 return false; 780 } 781 } 782 } 783 784 /** 785 * Remove an RX filter. 786 * 787 * @param type one of {@link #RX_FILTER_TYPE_V4_MULTICAST} or 788 * {@link #RX_FILTER_TYPE_V6_MULTICAST} values. 789 * @return true if request is sent successfully, false otherwise. 790 */ 791 private boolean removeRxFilter(byte type) { 792 synchronized (mLock) { 793 final String methodStr = "removeRxFilter"; 794 if (DBG) Log.i(TAG, methodStr); 795 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 796 try { 797 SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type); 798 return checkStatusAndLogFailure(status, methodStr); 799 } catch (RemoteException e) { 800 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 801 supplicantServiceDiedHandler(); 802 return false; 803 } 804 } 805 } 806 807 public static final byte BT_COEX_MODE_ENABLED = ISupplicantStaIface.BtCoexistenceMode.ENABLED; 808 public static final byte BT_COEX_MODE_DISABLED = ISupplicantStaIface.BtCoexistenceMode.DISABLED; 809 public static final byte BT_COEX_MODE_SENSE = ISupplicantStaIface.BtCoexistenceMode.SENSE; 810 /** 811 * Set Bt co existense mode. 812 * 813 * @param mode one of the above {@link #BT_COEX_MODE_ENABLED}, {@link #BT_COEX_MODE_DISABLED} 814 * or {@link #BT_COEX_MODE_SENSE} values. 815 * @return true if request is sent successfully, false otherwise. 816 */ 817 public boolean setBtCoexistenceMode(byte mode) { 818 synchronized (mLock) { 819 final String methodStr = "setBtCoexistenceMode"; 820 if (DBG) Log.i(TAG, methodStr); 821 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 822 try { 823 SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode); 824 return checkStatusAndLogFailure(status, methodStr); 825 } catch (RemoteException e) { 826 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 827 supplicantServiceDiedHandler(); 828 return false; 829 } 830 } 831 } 832 833 /** Enable or disable BT coexistence mode. 834 * 835 * @param enable true to enable, false to disable. 836 * @return true if request is sent successfully, false otherwise. 837 */ 838 public boolean setBtCoexistenceScanModeEnabled(boolean enable) { 839 synchronized (mLock) { 840 final String methodStr = "setBtCoexistenceScanModeEnabled"; 841 if (DBG) Log.i(TAG, methodStr); 842 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 843 try { 844 SupplicantStatus status = 845 mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable); 846 return checkStatusAndLogFailure(status, methodStr); 847 } catch (RemoteException e) { 848 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 849 supplicantServiceDiedHandler(); 850 return false; 851 } 852 } 853 } 854 855 /** 856 * Enable or disable suspend mode optimizations. 857 * 858 * @param enable true to enable, false otherwise. 859 */ 860 public boolean setSuspendModeEnabled(boolean enable) { 861 synchronized (mLock) { 862 final String methodStr = "setSuspendModeEnabled"; 863 if (DBG) Log.i(TAG, methodStr); 864 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 865 try { 866 SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable); 867 return checkStatusAndLogFailure(status, methodStr); 868 } catch (RemoteException e) { 869 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 870 supplicantServiceDiedHandler(); 871 return false; 872 } 873 } 874 } 875 876 /** 877 * Set country code. 878 * 879 * @param codeStr 2 byte ASCII string. For ex: US, CA. 880 * @return true if request is sent successfully, false otherwise. 881 */ 882 public boolean setCountryCode(String codeStr) { 883 return setCountryCode(NativeUtil.stringToByteArray(codeStr)); 884 } 885 886 /** See ISupplicantStaIface.hal for documentation */ 887 private boolean setCountryCode(byte[/* 2 */] code) { 888 synchronized (mLock) { 889 final String methodStr = "setCountryCode"; 890 if (DBG) Log.i(TAG, methodStr); 891 if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false; 892 try { 893 SupplicantStatus status = mISupplicantStaIface.setCountryCode(code); 894 return checkStatusAndLogFailure(status, methodStr); 895 } catch (RemoteException e) { 896 Log.e(TAG, "ISupplicantStaIface." + methodStr + ": exception:" + e); 897 supplicantServiceDiedHandler(); 898 return false; 899 } 900 } 901 } 902 903 /** 904 * Returns false if SupplicantStaIface is null, and logs failure to call methodStr 905 */ 906 private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) { 907 if (DBG) Log.i(TAG, methodStr); 908 if (mISupplicantStaIface == null) { 909 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null"); 910 return false; 911 } 912 return true; 913 } 914 915 /** 916 * Returns true if provided status code is SUCCESS, logs debug message and returns false 917 * otherwise 918 */ 919 private static boolean checkStatusAndLogFailure(SupplicantStatus status, 920 final String methodStr) { 921 if (DBG) Log.i(TAG, methodStr); 922 if (status.code != SupplicantStatusCode.SUCCESS) { 923 Log.e(TAG, methodStr + " failed: " + supplicantStatusCodeToString(status.code) + ", " 924 + status.debugMessage); 925 return false; 926 } 927 return true; 928 } 929 930 /** 931 * Converts SupplicantStatus code values to strings for debug logging 932 * TODO(b/34811152) Remove this, or make it more break resistance 933 */ 934 public static String supplicantStatusCodeToString(int code) { 935 switch (code) { 936 case 0: 937 return "SUCCESS"; 938 case 1: 939 return "FAILURE_UNKNOWN"; 940 case 2: 941 return "FAILURE_ARGS_INVALID"; 942 case 3: 943 return "FAILURE_IFACE_INVALID"; 944 case 4: 945 return "FAILURE_IFACE_UNKNOWN"; 946 case 5: 947 return "FAILURE_IFACE_EXISTS"; 948 case 6: 949 return "FAILURE_IFACE_DISABLED"; 950 case 7: 951 return "FAILURE_IFACE_NOT_DISCONNECTED"; 952 case 8: 953 return "FAILURE_NETWORK_INVALID"; 954 case 9: 955 return "FAILURE_NETWORK_UNKNOWN"; 956 default: 957 return "??? UNKNOWN_CODE"; 958 } 959 } 960 961 private static class Mutable<E> { 962 public E value; 963 964 Mutable() { 965 value = null; 966 } 967 968 Mutable(E value) { 969 this.value = value; 970 } 971 } 972 973 private void logd(String s) { 974 Log.d(TAG, s); 975 } 976 977 private void logi(String s) { 978 Log.i(TAG, s); 979 } 980 981 private void loge(String s) { 982 Log.e(TAG, s); 983 } 984} 985