1 /* 2 * Copyright (C) 2021 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 17 package com.android.server.wifi.p2p; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.hardware.wifi.supplicant.DebugLevel; 22 import android.hardware.wifi.supplicant.FreqRange; 23 import android.hardware.wifi.supplicant.ISupplicant; 24 import android.hardware.wifi.supplicant.ISupplicantP2pIface; 25 import android.hardware.wifi.supplicant.ISupplicantP2pIfaceCallback; 26 import android.hardware.wifi.supplicant.ISupplicantP2pNetwork; 27 import android.hardware.wifi.supplicant.IfaceInfo; 28 import android.hardware.wifi.supplicant.IfaceType; 29 import android.hardware.wifi.supplicant.MiracastMode; 30 import android.hardware.wifi.supplicant.P2pConnectInfo; 31 import android.hardware.wifi.supplicant.P2pDiscoveryInfo; 32 import android.hardware.wifi.supplicant.P2pExtListenInfo; 33 import android.hardware.wifi.supplicant.P2pFrameTypeMask; 34 import android.hardware.wifi.supplicant.P2pScanType; 35 import android.hardware.wifi.supplicant.WpsConfigMethods; 36 import android.hardware.wifi.supplicant.WpsProvisionMethod; 37 import android.net.wifi.CoexUnsafeChannel; 38 import android.net.wifi.ScanResult; 39 import android.net.wifi.WpsInfo; 40 import android.net.wifi.p2p.WifiP2pConfig; 41 import android.net.wifi.p2p.WifiP2pDevice; 42 import android.net.wifi.p2p.WifiP2pDiscoveryConfig; 43 import android.net.wifi.p2p.WifiP2pExtListenParams; 44 import android.net.wifi.p2p.WifiP2pGroup; 45 import android.net.wifi.p2p.WifiP2pGroupList; 46 import android.net.wifi.p2p.WifiP2pManager; 47 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 48 import android.os.IBinder; 49 import android.os.IBinder.DeathRecipient; 50 import android.os.RemoteException; 51 import android.os.ServiceManager; 52 import android.os.ServiceSpecificException; 53 import android.text.TextUtils; 54 import android.util.Log; 55 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.modules.utils.build.SdkLevel; 58 import com.android.server.wifi.WifiInjector; 59 import com.android.server.wifi.WifiNative; 60 import com.android.server.wifi.WifiSettingsConfigStore; 61 import com.android.server.wifi.util.ArrayUtils; 62 import com.android.server.wifi.util.HalAidlUtil; 63 import com.android.server.wifi.util.NativeUtil; 64 65 import java.io.ByteArrayOutputStream; 66 import java.io.IOException; 67 import java.nio.ByteBuffer; 68 import java.nio.ByteOrder; 69 import java.util.ArrayList; 70 import java.util.List; 71 import java.util.Set; 72 import java.util.concurrent.CountDownLatch; 73 import java.util.concurrent.TimeUnit; 74 import java.util.regex.Matcher; 75 import java.util.regex.Pattern; 76 77 /** 78 * Native calls sending requests to the P2P Hals, and callbacks for receiving P2P events 79 */ 80 public class SupplicantP2pIfaceHalAidlImpl implements ISupplicantP2pIfaceHal { 81 private static final String TAG = "SupplicantP2pIfaceHalAidlImpl"; 82 @VisibleForTesting 83 private static final String HAL_INSTANCE_NAME = ISupplicant.DESCRIPTOR + "/default"; 84 private static boolean sVerboseLoggingEnabled = true; 85 private static boolean sHalVerboseLoggingEnabled = true; 86 private boolean mInitializationStarted = false; 87 private static final int RESULT_NOT_VALID = -1; 88 private static final int DEFAULT_OPERATING_CLASS = 81; 89 public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L; 90 /** 91 * Regex pattern for extracting the wps device type bytes. 92 * Matches a strings like the following: "<categ>-<OUI>-<subcateg>"; 93 */ 94 private static final Pattern WPS_DEVICE_TYPE_PATTERN = 95 Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$"); 96 97 private final Object mLock = new Object(); 98 private CountDownLatch mWaitForDeathLatch; 99 private WifiNative.SupplicantDeathEventHandler mDeathEventHandler; 100 101 // Supplicant HAL AIDL interface objects 102 private ISupplicant mISupplicant = null; 103 private ISupplicantP2pIface mISupplicantP2pIface = null; 104 private final DeathRecipient mSupplicantDeathRecipient = 105 () -> { 106 Log.d(TAG, "ISupplicant/ISupplicantP2pIface died"); 107 synchronized (mLock) { 108 if (mWaitForDeathLatch != null) { 109 mWaitForDeathLatch.countDown(); 110 } 111 supplicantServiceDiedHandler(); 112 } 113 }; 114 private final WifiP2pMonitor mMonitor; 115 private final WifiInjector mWifiInjector; 116 private ISupplicantP2pIfaceCallback mCallback = null; 117 private int mServiceVersion = -1; 118 SupplicantP2pIfaceHalAidlImpl(WifiP2pMonitor monitor, WifiInjector wifiInjector)119 public SupplicantP2pIfaceHalAidlImpl(WifiP2pMonitor monitor, WifiInjector wifiInjector) { 120 mMonitor = monitor; 121 mWifiInjector = wifiInjector; 122 } 123 124 /** 125 * Enable verbose logging for all sub modules. 126 * 127 */ enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)128 public static void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) { 129 sVerboseLoggingEnabled = verboseEnabled; 130 sHalVerboseLoggingEnabled = halVerboseEnabled; 131 SupplicantP2pIfaceCallbackAidlImpl.enableVerboseLogging(verboseEnabled, halVerboseEnabled); 132 } 133 134 /** 135 * Set the debug log level for wpa_supplicant 136 * 137 * @param turnOnVerbose Whether to turn on verbose logging or not. 138 * @param globalShowKeys Whether show keys is true in WifiGlobals. 139 * @return true if request is sent successfully, false otherwise. 140 */ setLogLevel(boolean turnOnVerbose, boolean globalShowKeys)141 public boolean setLogLevel(boolean turnOnVerbose, boolean globalShowKeys) { 142 synchronized (mLock) { 143 int logLevel = turnOnVerbose 144 ? DebugLevel.DEBUG 145 : DebugLevel.INFO; 146 return setDebugParams(logLevel, false, 147 turnOnVerbose && globalShowKeys); 148 } 149 } 150 151 /** See ISupplicant.hal for documentation */ setDebugParams(int level, boolean showTimestamp, boolean showKeys)152 private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) { 153 synchronized (mLock) { 154 String methodStr = "setDebugParams"; 155 if (!checkSupplicantAndLogFailure(methodStr)) { 156 return false; 157 } 158 try { 159 mISupplicant.setDebugParams(level, showTimestamp, showKeys); 160 return true; 161 } catch (RemoteException e) { 162 handleRemoteException(e, methodStr); 163 } catch (ServiceSpecificException e) { 164 handleServiceSpecificException(e, methodStr); 165 } 166 return false; 167 } 168 } 169 170 /** 171 * Retrieve the ISupplicant service and link to service death. 172 * @return true if successful, false otherwise 173 */ initialize()174 public boolean initialize() { 175 synchronized (mLock) { 176 final String methodStr = "initialize"; 177 if (mISupplicant != null) { 178 Log.i(TAG, "Service is already initialized."); 179 return true; 180 } 181 mInitializationStarted = true; 182 mISupplicantP2pIface = null; 183 mISupplicant = getSupplicantMockable(); 184 if (mISupplicant == null) { 185 Log.e(TAG, "Unable to obtain ISupplicant binder."); 186 return false; 187 } 188 Log.i(TAG, "Obtained ISupplicant binder."); 189 190 try { 191 IBinder serviceBinder = getServiceBinderMockable(); 192 if (serviceBinder == null) { 193 return false; 194 } 195 serviceBinder.linkToDeath(mSupplicantDeathRecipient, /* flags= */ 0); 196 return true; 197 } catch (RemoteException e) { 198 handleRemoteException(e, methodStr); 199 return false; 200 } 201 } 202 } 203 204 /** 205 * Setup the P2P iface. 206 * 207 * @param ifaceName Name of the interface. 208 * @return true on success, false otherwise. 209 */ setupIface(@onNull String ifaceName)210 public boolean setupIface(@NonNull String ifaceName) { 211 synchronized (mLock) { 212 if (mISupplicantP2pIface != null) { 213 // P2P iface already exists 214 return false; 215 } 216 ISupplicantP2pIface iface = addIface(ifaceName); 217 if (iface == null) { 218 Log.e(TAG, "Unable to add iface " + ifaceName); 219 return false; 220 } 221 mISupplicantP2pIface = iface; 222 223 if (mMonitor != null) { 224 ISupplicantP2pIfaceCallback callback = 225 new SupplicantP2pIfaceCallbackAidlImpl(ifaceName, mMonitor, 226 getCachedServiceVersion()); 227 if (!registerCallback(callback)) { 228 Log.e(TAG, "Unable to register callback for iface " + ifaceName); 229 return false; 230 } 231 mCallback = callback; 232 } 233 return true; 234 } 235 } 236 addIface(@onNull String ifaceName)237 private ISupplicantP2pIface addIface(@NonNull String ifaceName) { 238 synchronized (mLock) { 239 String methodStr = "addIface"; 240 if (!checkSupplicantAndLogFailure(methodStr)) { 241 return null; 242 } 243 try { 244 return mISupplicant.addP2pInterface(ifaceName); 245 } catch (RemoteException e) { 246 handleRemoteException(e, methodStr); 247 } catch (ServiceSpecificException e) { 248 handleServiceSpecificException(e, methodStr); 249 } 250 return null; 251 } 252 } 253 254 /** 255 * Teardown the P2P interface. 256 * 257 * @param ifaceName Name of the interface. 258 * @return true on success, false otherwise. 259 */ teardownIface(@onNull String ifaceName)260 public boolean teardownIface(@NonNull String ifaceName) { 261 synchronized (mLock) { 262 final String methodStr = "teardownIface"; 263 if (!checkSupplicantAndLogFailure(methodStr)) { 264 return false; 265 } else if (!checkP2pIfaceAndLogFailure(methodStr)) { 266 return false; 267 } 268 269 try { 270 IfaceInfo ifaceInfo = new IfaceInfo(); 271 ifaceInfo.name = ifaceName; 272 ifaceInfo.type = IfaceType.P2P; 273 mISupplicant.removeInterface(ifaceInfo); 274 mISupplicantP2pIface = null; 275 mCallback = null; 276 return true; 277 } catch (RemoteException e) { 278 handleRemoteException(e, methodStr); 279 } catch (ServiceSpecificException e) { 280 handleServiceSpecificException(e, methodStr); 281 } 282 return false; 283 } 284 } 285 supplicantServiceDiedHandler()286 private void supplicantServiceDiedHandler() { 287 synchronized (mLock) { 288 mISupplicant = null; 289 mISupplicantP2pIface = null; 290 mInitializationStarted = false; 291 if (mDeathEventHandler != null) { 292 mDeathEventHandler.onDeath(); 293 } 294 } 295 } 296 297 /** 298 * Signals whether initialization started successfully. 299 */ isInitializationStarted()300 public boolean isInitializationStarted() { 301 synchronized (mLock) { 302 return mInitializationStarted; 303 } 304 } 305 306 /** 307 * Signals whether initialization completed successfully. 308 */ isInitializationComplete()309 public boolean isInitializationComplete() { 310 synchronized (mLock) { 311 return mISupplicant != null; 312 } 313 } 314 315 /** 316 * Indicates whether the AIDL service is declared 317 */ serviceDeclared()318 public static boolean serviceDeclared() { 319 // Service Manager API ServiceManager#isDeclared supported after T. 320 if (!SdkLevel.isAtLeastT()) { 321 return false; 322 } 323 return ServiceManager.isDeclared(HAL_INSTANCE_NAME); 324 } 325 326 /** 327 * Wrapper functions to access static HAL methods, created to be mockable in unit tests 328 */ 329 @VisibleForTesting getSupplicantMockable()330 protected ISupplicant getSupplicantMockable() { 331 synchronized (mLock) { 332 try { 333 if (SdkLevel.isAtLeastT()) { 334 return ISupplicant.Stub.asInterface( 335 ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME)); 336 } else { 337 return null; 338 } 339 } catch (Exception e) { 340 Log.e(TAG, "Unable to get ISupplicant service, " + e); 341 return null; 342 } 343 } 344 } 345 346 @VisibleForTesting getServiceBinderMockable()347 protected IBinder getServiceBinderMockable() { 348 synchronized (mLock) { 349 if (mISupplicant == null) { 350 return null; 351 } 352 return mISupplicant.asBinder(); 353 } 354 } 355 356 /** 357 * Returns false if mISupplicant is null and logs failure message 358 */ checkSupplicantAndLogFailure(String methodStr)359 private boolean checkSupplicantAndLogFailure(String methodStr) { 360 synchronized (mLock) { 361 if (mISupplicant == null) { 362 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null"); 363 return false; 364 } 365 return true; 366 } 367 } 368 369 /** 370 * Returns false if SupplicantP2pIface is null, and logs failure to call methodStr 371 */ checkP2pIfaceAndLogFailure(String methodStr)372 private boolean checkP2pIfaceAndLogFailure(String methodStr) { 373 synchronized (mLock) { 374 if (mISupplicantP2pIface == null) { 375 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantP2pIface is null"); 376 return false; 377 } 378 return true; 379 } 380 } 381 handleRemoteException(RemoteException e, String methodStr)382 private void handleRemoteException(RemoteException e, String methodStr) { 383 synchronized (mLock) { 384 supplicantServiceDiedHandler(); 385 Log.e(TAG, 386 "ISupplicantP2pIface." + methodStr + " failed with remote exception: ", e); 387 } 388 } 389 handleServiceSpecificException(ServiceSpecificException e, String methodStr)390 private void handleServiceSpecificException(ServiceSpecificException e, String methodStr) { 391 synchronized (mLock) { 392 Log.e(TAG, "ISupplicantP2pIface." + methodStr + " failed with " 393 + "service specific exception: ", e); 394 } 395 } 396 wpsInfoToConfigMethod(int info)397 private int wpsInfoToConfigMethod(int info) { 398 switch (info) { 399 case WpsInfo.PBC: 400 return WpsProvisionMethod.PBC; 401 case WpsInfo.DISPLAY: 402 return WpsProvisionMethod.DISPLAY; 403 case WpsInfo.KEYPAD: 404 case WpsInfo.LABEL: 405 return WpsProvisionMethod.KEYPAD; 406 default: 407 Log.e(TAG, "Unsupported WPS provision method: " + info); 408 return RESULT_NOT_VALID; 409 } 410 } 411 412 /** 413 * Retrieves the name of the network interface. 414 * 415 * @return name Name of the network interface, e.g., wlan0 416 */ getName()417 public String getName() { 418 synchronized (mLock) { 419 String methodStr = "getName"; 420 if (!checkP2pIfaceAndLogFailure(methodStr)) { 421 return null; 422 } 423 try { 424 return mISupplicantP2pIface.getName(); 425 } catch (RemoteException e) { 426 handleRemoteException(e, methodStr); 427 } catch (ServiceSpecificException e) { 428 handleServiceSpecificException(e, methodStr); 429 } 430 return null; 431 } 432 } 433 434 /** 435 * Register for callbacks from this interface. 436 * 437 * These callbacks are invoked for events that are specific to this interface. 438 * Registration of multiple callback objects is supported. These objects must 439 * be automatically deleted when the corresponding client process is dead or 440 * if this interface is removed. 441 * 442 * @param callback An instance of the |ISupplicantP2pIfaceCallback| AIDL 443 * interface object. 444 * @return boolean value indicating whether operation was successful. 445 */ registerCallback(ISupplicantP2pIfaceCallback callback)446 public boolean registerCallback(ISupplicantP2pIfaceCallback callback) { 447 synchronized (mLock) { 448 String methodStr = "registerCallback"; 449 if (!checkP2pIfaceAndLogFailure(methodStr)) { 450 return false; 451 } 452 try { 453 mISupplicantP2pIface.registerCallback(callback); 454 return true; 455 } catch (RemoteException e) { 456 handleRemoteException(e, methodStr); 457 } catch (ServiceSpecificException e) { 458 handleServiceSpecificException(e, methodStr); 459 } 460 return false; 461 } 462 } 463 464 /** 465 * Initiate a P2P service discovery with a (optional) timeout. 466 * 467 * @param timeout Max time to be spent is performing discovery. 468 * Set to 0 to indefinitely continue discovery until an explicit 469 * |stopFind| is sent. 470 * @return boolean value indicating whether operation was successful. 471 */ find(int timeout)472 public boolean find(int timeout) { 473 return find( 474 WifiP2pManager.WIFI_P2P_SCAN_FULL, 475 WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED, timeout); 476 } 477 478 /** 479 * Initiate a P2P device discovery with a scan type, a (optional) frequency, and a (optional) 480 * timeout. 481 * 482 * @param type indicates what channels to scan. 483 * Valid values are {@link WifiP2pManager#WIFI_P2P_SCAN_FULL} for doing full P2P scan, 484 * {@link WifiP2pManager#WIFI_P2P_SCAN_SOCIAL} for scanning social channels, 485 * {@link WifiP2pManager#WIFI_P2P_SCAN_SINGLE_FREQ} for scanning a specified frequency. 486 * @param freq is the frequency to be scanned. 487 * The possible values are: 488 * <ul> 489 * <li> A valid frequency for {@link WifiP2pManager#WIFI_P2P_SCAN_SINGLE_FREQ}</li> 490 * <li> {@link WifiP2pManager#WIFI_P2P_SCAN_FREQ_UNSPECIFIED} for 491 * {@link WifiP2pManager#WIFI_P2P_SCAN_FULL} and 492 * {@link WifiP2pManager#WIFI_P2P_SCAN_SOCIAL}</li> 493 * </ul> 494 * @param timeout Max time to be spent is performing discovery. 495 * Set to 0 to indefinitely continue discovery until an explicit 496 * |stopFind| is sent. 497 * @return boolean value indicating whether operation was successful. 498 */ find(@ifiP2pManager.WifiP2pScanType int type, int freq, int timeout)499 public boolean find(@WifiP2pManager.WifiP2pScanType int type, int freq, int timeout) { 500 synchronized (mLock) { 501 String methodStr = "find"; 502 if (!checkP2pIfaceAndLogFailure(methodStr)) { 503 return false; 504 } 505 if (timeout < 0) { 506 Log.e(TAG, "Invalid timeout value: " + timeout); 507 return false; 508 } 509 if (freq < 0) { 510 Log.e(TAG, "Invalid freq value: " + freq); 511 return false; 512 } 513 if (freq != WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED 514 && type != WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ) { 515 Log.e(TAG, "Specified freq for scan type:" + type); 516 return false; 517 } 518 try { 519 switch (type) { 520 case WifiP2pManager.WIFI_P2P_SCAN_FULL: 521 mISupplicantP2pIface.find(timeout); 522 break; 523 case WifiP2pManager.WIFI_P2P_SCAN_SOCIAL: 524 mISupplicantP2pIface.findOnSocialChannels(timeout); 525 break; 526 case WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ: 527 if (freq == WifiP2pManager.WIFI_P2P_SCAN_FREQ_UNSPECIFIED) { 528 Log.e(TAG, "Unspecified freq for WIFI_P2P_SCAN_SINGLE_FREQ"); 529 return false; 530 } 531 mISupplicantP2pIface.findOnSpecificFrequency(freq, timeout); 532 break; 533 default: 534 Log.e(TAG, "Invalid scan type: " + type); 535 return false; 536 } 537 return true; 538 } catch (RemoteException e) { 539 handleRemoteException(e, methodStr); 540 } catch (ServiceSpecificException e) { 541 handleServiceSpecificException(e, methodStr); 542 } 543 return false; 544 } 545 } 546 frameworkToHalScanType(@ifiP2pManager.WifiP2pScanType int scanType)547 private static int frameworkToHalScanType(@WifiP2pManager.WifiP2pScanType int scanType) { 548 switch (scanType) { 549 case WifiP2pManager.WIFI_P2P_SCAN_FULL: 550 return P2pScanType.FULL; 551 case WifiP2pManager.WIFI_P2P_SCAN_SOCIAL: 552 return P2pScanType.SOCIAL; 553 case WifiP2pManager.WIFI_P2P_SCAN_SINGLE_FREQ: 554 return P2pScanType.SPECIFIC_FREQ; 555 default: 556 Log.e(TAG, "Invalid discovery scan type: " + scanType); 557 return -1; 558 } 559 } 560 561 /** 562 * Initiate P2P device discovery with config params. 563 * 564 * See comments for {@link ISupplicantP2pIfaceHal#findWithParams(WifiP2pDiscoveryConfig, int)}. 565 */ findWithParams(WifiP2pDiscoveryConfig config, int timeout)566 public boolean findWithParams(WifiP2pDiscoveryConfig config, int timeout) { 567 synchronized (mLock) { 568 String methodStr = "findWithParams"; 569 if (!checkP2pIfaceAndLogFailure(methodStr)) { 570 return false; 571 } 572 if (getCachedServiceVersion() < 3) { 573 // HAL does not support findWithParams before V3. 574 return find(config.getScanType(), config.getFrequencyMhz(), timeout); 575 } 576 577 P2pDiscoveryInfo halInfo = new P2pDiscoveryInfo(); 578 halInfo.scanType = frameworkToHalScanType(config.getScanType()); 579 halInfo.timeoutInSec = timeout; 580 halInfo.frequencyMhz = config.getFrequencyMhz(); 581 if (halInfo.scanType == -1) { 582 return false; 583 } 584 if (halInfo.frequencyMhz < 0) { 585 Log.e(TAG, "Invalid freq value: " + halInfo.frequencyMhz); 586 return false; 587 } 588 589 if (!config.getVendorData().isEmpty()) { 590 halInfo.vendorData = 591 HalAidlUtil.frameworkToHalOuiKeyedDataList(config.getVendorData()); 592 } 593 594 try { 595 mISupplicantP2pIface.findWithParams(halInfo); 596 return true; 597 } catch (RemoteException e) { 598 handleRemoteException(e, methodStr); 599 } catch (ServiceSpecificException e) { 600 handleServiceSpecificException(e, methodStr); 601 } 602 return false; 603 } 604 } 605 606 /** 607 * Stop an ongoing P2P service discovery. 608 * 609 * @return boolean value indicating whether operation was successful. 610 */ stopFind()611 public boolean stopFind() { 612 synchronized (mLock) { 613 String methodStr = "stopFind"; 614 if (!checkP2pIfaceAndLogFailure(methodStr)) { 615 return false; 616 } 617 try { 618 mISupplicantP2pIface.stopFind(); 619 return true; 620 } catch (RemoteException e) { 621 handleRemoteException(e, methodStr); 622 } catch (ServiceSpecificException e) { 623 handleServiceSpecificException(e, methodStr); 624 } 625 return false; 626 } 627 } 628 629 /** 630 * Flush P2P peer table and state. 631 * 632 * @return boolean value indicating whether operation was successful. 633 */ flush()634 public boolean flush() { 635 synchronized (mLock) { 636 String methodStr = "flush"; 637 if (!checkP2pIfaceAndLogFailure(methodStr)) { 638 return false; 639 } 640 try { 641 mISupplicantP2pIface.flush(); 642 return true; 643 } catch (RemoteException e) { 644 handleRemoteException(e, methodStr); 645 } catch (ServiceSpecificException e) { 646 handleServiceSpecificException(e, methodStr); 647 } 648 return false; 649 } 650 } 651 652 /** 653 * This command can be used to flush all services from the 654 * device. 655 * 656 * @return boolean value indicating whether operation was successful. 657 */ serviceFlush()658 public boolean serviceFlush() { 659 synchronized (mLock) { 660 String methodStr = "serviceFlush"; 661 if (!checkP2pIfaceAndLogFailure(methodStr)) { 662 return false; 663 } 664 try { 665 mISupplicantP2pIface.flushServices(); 666 return true; 667 } catch (RemoteException e) { 668 handleRemoteException(e, methodStr); 669 } catch (ServiceSpecificException e) { 670 handleServiceSpecificException(e, methodStr); 671 } 672 return false; 673 } 674 } 675 676 /** 677 * Turn on/off power save mode for the interface. 678 * 679 * @param groupIfName Group interface name to use. 680 * @param enable Indicate if power save is to be turned on/off. 681 * 682 * @return boolean value indicating whether operation was successful. 683 */ setPowerSave(String groupIfName, boolean enable)684 public boolean setPowerSave(String groupIfName, boolean enable) { 685 synchronized (mLock) { 686 String methodStr = "setPowerSave"; 687 if (!checkP2pIfaceAndLogFailure(methodStr)) { 688 return false; 689 } 690 try { 691 mISupplicantP2pIface.setPowerSave(groupIfName, enable); 692 return true; 693 } catch (RemoteException e) { 694 handleRemoteException(e, methodStr); 695 } catch (ServiceSpecificException e) { 696 handleServiceSpecificException(e, methodStr); 697 } 698 return false; 699 } 700 } 701 702 /** 703 * Set the Maximum idle time in seconds for P2P groups. 704 * This value controls how long a P2P group is maintained after there 705 * is no other members in the group. As a group owner, this means no 706 * associated stations in the group. As a P2P client, this means no 707 * group owner seen in scan results. 708 * 709 * @param groupIfName Group interface name to use. 710 * @param timeoutInSec Timeout value in seconds. 711 * 712 * @return boolean value indicating whether operation was successful. 713 */ setGroupIdle(String groupIfName, int timeoutInSec)714 public boolean setGroupIdle(String groupIfName, int timeoutInSec) { 715 synchronized (mLock) { 716 String methodStr = "setGroupIdle"; 717 if (!checkP2pIfaceAndLogFailure(methodStr)) { 718 return false; 719 } 720 // Basic checking here. Leave actual parameter validation to supplicant. 721 if (timeoutInSec < 0) { 722 Log.e(TAG, "Invalid group timeout value " + timeoutInSec); 723 return false; 724 } 725 if (groupIfName == null) { 726 Log.e(TAG, "Group interface name cannot be null."); 727 return false; 728 } 729 730 try { 731 mISupplicantP2pIface.setGroupIdle(groupIfName, timeoutInSec); 732 return true; 733 } catch (RemoteException e) { 734 handleRemoteException(e, methodStr); 735 } catch (ServiceSpecificException e) { 736 handleServiceSpecificException(e, methodStr); 737 } 738 return false; 739 } 740 } 741 742 /** 743 * Set the postfix to be used for P2P SSID's. 744 * 745 * @param postfix String to be appended to SSID. 746 * 747 * @return boolean value indicating whether operation was successful. 748 */ setSsidPostfix(String postfix)749 public boolean setSsidPostfix(String postfix) { 750 synchronized (mLock) { 751 String methodStr = "setSsidPostfix"; 752 if (!checkP2pIfaceAndLogFailure(methodStr)) { 753 return false; 754 } 755 // Basic checking here. Leave actual parameter validation to supplicant. 756 if (postfix == null) { 757 Log.e(TAG, "Invalid SSID postfix value (null)."); 758 return false; 759 } 760 761 try { 762 mISupplicantP2pIface.setSsidPostfix( 763 NativeUtil.byteArrayFromArrayList( 764 NativeUtil.decodeSsid("\"" + postfix + "\""))); 765 return true; 766 } catch (RemoteException e) { 767 handleRemoteException(e, methodStr); 768 } catch (ServiceSpecificException e) { 769 handleServiceSpecificException(e, methodStr); 770 } catch (IllegalArgumentException e) { 771 Log.e(TAG, "Could not decode SSID.", e); 772 } 773 return false; 774 } 775 } 776 connectWithParams(boolean joinExistingGroup, byte[] peerAddress, int provisionMethod, String preSelectedPin, boolean persistent, int groupOwnerIntent, WifiP2pConfig config)777 private String connectWithParams(boolean joinExistingGroup, byte[] peerAddress, 778 int provisionMethod, String preSelectedPin, boolean persistent, int groupOwnerIntent, 779 WifiP2pConfig config) { 780 synchronized (mLock) { 781 String methodStr = "connectWithParams"; 782 783 // Parameters should be pre-validated. 784 P2pConnectInfo info = new P2pConnectInfo(); 785 info.joinExistingGroup = joinExistingGroup; 786 info.peerAddress = peerAddress; 787 info.provisionMethod = provisionMethod; 788 info.preSelectedPin = preSelectedPin; 789 info.persistent = persistent; 790 info.goIntent = groupOwnerIntent; 791 792 if (SdkLevel.isAtLeastV() && config.getVendorData() != null 793 && !config.getVendorData().isEmpty()) { 794 info.vendorData = 795 HalAidlUtil.frameworkToHalOuiKeyedDataList(config.getVendorData()); 796 } 797 798 try { 799 return mISupplicantP2pIface.connectWithParams(info); 800 } catch (RemoteException e) { 801 handleRemoteException(e, methodStr); 802 } catch (ServiceSpecificException e) { 803 handleServiceSpecificException(e, methodStr); 804 } 805 return null; 806 } 807 } 808 809 /** 810 * Start P2P group formation with a discovered P2P peer. This includes 811 * optional group owner negotiation, group interface setup, provisioning, 812 * and establishing data connection. 813 * 814 * @param config Configuration to use to connect to remote device. 815 * @param joinExistingGroup Indicates that this is a command to join an 816 * existing group as a client. It skips the group owner negotiation 817 * part. This must send a Provision Discovery Request message to the 818 * target group owner before associating for WPS provisioning. 819 * 820 * @return String containing generated pin, if selected provision method 821 * uses PIN. 822 */ connect(WifiP2pConfig config, boolean joinExistingGroup)823 public String connect(WifiP2pConfig config, boolean joinExistingGroup) { 824 synchronized (mLock) { 825 String methodStr = "connect"; 826 827 if (!checkP2pIfaceAndLogFailure(methodStr)) { 828 return null; 829 } 830 if (config == null) { 831 Log.e(TAG, "Could not connect because config is null."); 832 return null; 833 } 834 if (config.deviceAddress == null) { 835 Log.e(TAG, "Could not parse null mac address."); 836 return null; 837 } 838 if (config.wps.setup == WpsInfo.PBC && !TextUtils.isEmpty(config.wps.pin)) { 839 Log.e(TAG, "Expected empty pin for PBC."); 840 return null; 841 } 842 843 byte[] peerAddress = null; 844 try { 845 peerAddress = NativeUtil.macAddressToByteArray(config.deviceAddress); 846 } catch (IllegalArgumentException e) { 847 Log.e(TAG, "Could not parse peer mac address.", e); 848 return null; 849 } 850 851 int provisionMethod = wpsInfoToConfigMethod(config.wps.setup); 852 if (provisionMethod == RESULT_NOT_VALID) { 853 Log.e(TAG, "Invalid WPS config method: " + config.wps.setup); 854 return null; 855 } 856 // NOTE: preSelectedPin cannot be null, otherwise hal would crash. 857 String preSelectedPin = TextUtils.isEmpty(config.wps.pin) ? "" : config.wps.pin; 858 boolean persistent = (config.netId == WifiP2pGroup.NETWORK_ID_PERSISTENT); 859 860 if (config.groupOwnerIntent < 0 || config.groupOwnerIntent > 15) { 861 Log.e(TAG, "Invalid group owner intent: " + config.groupOwnerIntent); 862 return null; 863 } 864 865 if (getCachedServiceVersion() >= 3) { 866 return connectWithParams(joinExistingGroup, peerAddress, provisionMethod, 867 preSelectedPin, persistent, config.groupOwnerIntent, config); 868 } 869 870 try { 871 return mISupplicantP2pIface.connect( 872 peerAddress, provisionMethod, preSelectedPin, joinExistingGroup, 873 persistent, config.groupOwnerIntent); 874 } catch (RemoteException e) { 875 handleRemoteException(e, methodStr); 876 } catch (ServiceSpecificException e) { 877 handleServiceSpecificException(e, methodStr); 878 } 879 return null; 880 } 881 } 882 883 /** 884 * Cancel an ongoing P2P group formation and joining-a-group related 885 * operation. This operation unauthorizes the specific peer device (if any 886 * had been authorized to start group formation), stops P2P find (if in 887 * progress), stops pending operations for join-a-group, and removes the 888 * P2P group interface (if one was used) that is in the WPS provisioning 889 * step. If the WPS provisioning step has been completed, the group is not 890 * terminated. 891 * 892 * @return boolean value indicating whether operation was successful. 893 */ cancelConnect()894 public boolean cancelConnect() { 895 synchronized (mLock) { 896 String methodStr = "cancelConnect"; 897 if (!checkP2pIfaceAndLogFailure(methodStr)) { 898 return false; 899 } 900 try { 901 mISupplicantP2pIface.cancelConnect(); 902 return true; 903 } catch (RemoteException e) { 904 handleRemoteException(e, methodStr); 905 } catch (ServiceSpecificException e) { 906 handleServiceSpecificException(e, methodStr); 907 } 908 return false; 909 } 910 } 911 912 /** 913 * Send P2P provision discovery request to the specified peer. The 914 * parameters for this command are the P2P device address of the peer and the 915 * desired configuration method. 916 * 917 * @param config Config class describing peer setup. 918 * 919 * @return boolean value indicating whether operation was successful. 920 */ provisionDiscovery(WifiP2pConfig config)921 public boolean provisionDiscovery(WifiP2pConfig config) { 922 synchronized (mLock) { 923 String methodStr = "provisionDiscovery"; 924 if (!checkP2pIfaceAndLogFailure("provisionDiscovery")) { 925 return false; 926 } 927 if (config == null) { 928 return false; 929 } 930 931 int targetMethod = wpsInfoToConfigMethod(config.wps.setup); 932 if (targetMethod == RESULT_NOT_VALID) { 933 Log.e(TAG, "Unrecognized WPS configuration method: " + config.wps.setup); 934 return false; 935 } 936 if (targetMethod == WpsProvisionMethod.DISPLAY) { 937 // We are doing display, so provision discovery is keypad. 938 targetMethod = WpsProvisionMethod.KEYPAD; 939 } else if (targetMethod == WpsProvisionMethod.KEYPAD) { 940 // We are doing keypad, so provision discovery is display. 941 targetMethod = WpsProvisionMethod.DISPLAY; 942 } 943 944 if (config.deviceAddress == null) { 945 Log.e(TAG, "Cannot parse null mac address."); 946 return false; 947 } 948 byte[] macAddress = null; 949 try { 950 macAddress = NativeUtil.macAddressToByteArray(config.deviceAddress); 951 } catch (IllegalArgumentException e) { 952 Log.e(TAG, "Could not parse peer mac address.", e); 953 return false; 954 } 955 956 try { 957 mISupplicantP2pIface.provisionDiscovery(macAddress, targetMethod); 958 return true; 959 } catch (RemoteException e) { 960 handleRemoteException(e, methodStr); 961 } catch (ServiceSpecificException e) { 962 handleServiceSpecificException(e, methodStr); 963 } 964 return false; 965 } 966 } 967 968 /** 969 * Invite a device to a persistent group. 970 * If the peer device is the group owner of the persistent group, the peer 971 * parameter is not needed. Otherwise it is used to specify which 972 * device to invite. |goDeviceAddress| parameter may be used to override 973 * the group owner device address for Invitation Request should it not be 974 * known for some reason (this should not be needed in most cases). 975 * 976 * @param group Group object to use. 977 * @param peerAddress MAC address of the device to invite. 978 * 979 * @return boolean value indicating whether operation was successful. 980 */ invite(WifiP2pGroup group, String peerAddress)981 public boolean invite(WifiP2pGroup group, String peerAddress) { 982 synchronized (mLock) { 983 String methodStr = "invite"; 984 if (!checkP2pIfaceAndLogFailure(methodStr)) { 985 return false; 986 } 987 if (TextUtils.isEmpty(peerAddress)) { 988 Log.e(TAG, "Peer mac address is empty."); 989 return false; 990 } 991 if (group == null) { 992 Log.e(TAG, "Cannot invite to null group."); 993 return false; 994 } 995 if (group.getOwner() == null) { 996 Log.e(TAG, "Cannot invite to group with null owner."); 997 return false; 998 } 999 if (group.getOwner().deviceAddress == null) { 1000 Log.e(TAG, "Group owner has no mac address."); 1001 return false; 1002 } 1003 1004 byte[] ownerMacAddress = null; 1005 try { 1006 ownerMacAddress = NativeUtil.macAddressToByteArray(group.getOwner().deviceAddress); 1007 } catch (IllegalArgumentException e) { 1008 Log.e(TAG, "Group owner mac address parse error.", e); 1009 return false; 1010 } 1011 1012 byte[] peerMacAddress; 1013 try { 1014 peerMacAddress = NativeUtil.macAddressToByteArray(peerAddress); 1015 } catch (IllegalArgumentException e) { 1016 Log.e(TAG, "Peer mac address parse error.", e); 1017 return false; 1018 } 1019 1020 try { 1021 mISupplicantP2pIface.invite( 1022 group.getInterface(), ownerMacAddress, peerMacAddress); 1023 return true; 1024 } catch (RemoteException e) { 1025 handleRemoteException(e, methodStr); 1026 } catch (ServiceSpecificException e) { 1027 handleServiceSpecificException(e, methodStr); 1028 } 1029 return false; 1030 } 1031 } 1032 1033 /** 1034 * Reject connection attempt from a peer (specified with a device 1035 * address). This is a mechanism to reject a pending group owner negotiation 1036 * with a peer and request to automatically block any further connection or 1037 * discovery of the peer. 1038 * 1039 * @param peerAddress MAC address of the device to reject. 1040 * 1041 * @return boolean value indicating whether operation was successful. 1042 */ reject(String peerAddress)1043 public boolean reject(String peerAddress) { 1044 synchronized (mLock) { 1045 String methodStr = "reject"; 1046 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1047 return false; 1048 } 1049 1050 if (peerAddress == null) { 1051 Log.e(TAG, "Rejected peer's mac address is null."); 1052 return false; 1053 } 1054 byte[] macAddress = null; 1055 try { 1056 macAddress = NativeUtil.macAddressToByteArray(peerAddress); 1057 } catch (IllegalArgumentException e) { 1058 Log.e(TAG, "Could not parse peer mac address.", e); 1059 return false; 1060 } 1061 1062 try { 1063 mISupplicantP2pIface.reject(macAddress); 1064 return true; 1065 } catch (RemoteException e) { 1066 handleRemoteException(e, methodStr); 1067 } catch (ServiceSpecificException e) { 1068 handleServiceSpecificException(e, methodStr); 1069 } 1070 return false; 1071 } 1072 } 1073 1074 /** 1075 * Gets the MAC address of the device. 1076 * 1077 * @return MAC address of the device. 1078 */ getDeviceAddress()1079 public String getDeviceAddress() { 1080 synchronized (mLock) { 1081 String methodStr = "getDeviceAddress"; 1082 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1083 return null; 1084 } 1085 try { 1086 byte[] address = mISupplicantP2pIface.getDeviceAddress(); 1087 return NativeUtil.macAddressFromByteArray(address); 1088 } catch (RemoteException e) { 1089 handleRemoteException(e, methodStr); 1090 } catch (ServiceSpecificException e) { 1091 handleServiceSpecificException(e, methodStr); 1092 } catch (IllegalArgumentException e) { 1093 Log.e(TAG, "Received invalid MAC address", e); 1094 } 1095 return null; 1096 } 1097 } 1098 1099 /** 1100 * Gets the operational SSID of the device. 1101 * 1102 * @param address MAC address of the peer. 1103 * 1104 * @return SSID of the device. 1105 */ getSsid(String address)1106 public String getSsid(String address) { 1107 synchronized (mLock) { 1108 String methodStr = "getSsid"; 1109 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1110 return null; 1111 } 1112 1113 if (address == null) { 1114 Log.e(TAG, "Cannot parse null peer mac address."); 1115 return null; 1116 } 1117 byte[] macAddress = null; 1118 try { 1119 macAddress = NativeUtil.macAddressToByteArray(address); 1120 } catch (IllegalArgumentException e) { 1121 Log.e(TAG, "Could not parse mac address.", e); 1122 return null; 1123 } 1124 1125 try { 1126 byte[] ssid = mISupplicantP2pIface.getSsid(macAddress); 1127 if (ssid == null) { 1128 return null; 1129 } 1130 return NativeUtil.removeEnclosingQuotes( 1131 NativeUtil.encodeSsid( 1132 NativeUtil.byteArrayToArrayList(ssid))); 1133 } catch (RemoteException e) { 1134 handleRemoteException(e, methodStr); 1135 } catch (ServiceSpecificException e) { 1136 handleServiceSpecificException(e, methodStr); 1137 } catch (IllegalArgumentException e) { 1138 Log.e(TAG, "Unable to parse SSID: ", e); 1139 } 1140 return null; 1141 } 1142 } 1143 1144 /** 1145 * Reinvoke a device from a persistent group. 1146 * 1147 * @param networkId Used to specify the persistent group. 1148 * @param peerAddress MAC address of the device to reinvoke. 1149 * 1150 * @return true, if operation was successful. 1151 */ reinvoke(int networkId, String peerAddress)1152 public boolean reinvoke(int networkId, String peerAddress) { 1153 synchronized (mLock) { 1154 String methodStr = "reinvoke"; 1155 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1156 return false; 1157 } 1158 if (TextUtils.isEmpty(peerAddress) || networkId < 0) { 1159 return false; 1160 } 1161 byte[] macAddress = null; 1162 try { 1163 macAddress = NativeUtil.macAddressToByteArray(peerAddress); 1164 } catch (IllegalArgumentException e) { 1165 Log.e(TAG, "Could not parse mac address.", e); 1166 return false; 1167 } 1168 1169 try { 1170 mISupplicantP2pIface.reinvoke(networkId, macAddress); 1171 return true; 1172 } catch (RemoteException e) { 1173 handleRemoteException(e, methodStr); 1174 } catch (ServiceSpecificException e) { 1175 handleServiceSpecificException(e, methodStr); 1176 } 1177 return false; 1178 } 1179 } 1180 1181 /** 1182 * Set up a P2P group owner manually (i.e., without group owner 1183 * negotiation with a specific peer). This is also known as autonomous 1184 * group owner. 1185 * 1186 * @param networkId Used to specify the restart of a persistent group. 1187 * @param isPersistent Used to request a persistent group to be formed. 1188 * 1189 * @return true, if operation was successful. 1190 */ groupAdd(int networkId, boolean isPersistent)1191 public boolean groupAdd(int networkId, boolean isPersistent) { 1192 synchronized (mLock) { 1193 String methodStr = "groupAdd"; 1194 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1195 return false; 1196 } 1197 try { 1198 mISupplicantP2pIface.addGroup(isPersistent, networkId); 1199 return true; 1200 } catch (RemoteException e) { 1201 handleRemoteException(e, methodStr); 1202 } catch (ServiceSpecificException e) { 1203 handleServiceSpecificException(e, methodStr); 1204 } 1205 return false; 1206 } 1207 } 1208 1209 /** 1210 * Set up a P2P group as Group Owner or join a group with a configuration. 1211 * 1212 * @param networkName SSID of the group to be formed 1213 * @param passphrase passphrase of the group to be formed 1214 * @param isPersistent Used to request a persistent group to be formed. 1215 * @param freq preferred frequency or band of the group to be formed 1216 * @param peerAddress peerAddress Group Owner MAC address, only applied for Group Client. 1217 * If the MAC is "00:00:00:00:00:00", the device will try to find a peer 1218 * whose SSID matches ssid. 1219 * @param join join a group or create a group 1220 * 1221 * @return true, if operation was successful. 1222 */ groupAdd(String networkName, String passphrase, boolean isPersistent, int freq, String peerAddress, boolean join)1223 public boolean groupAdd(String networkName, String passphrase, 1224 boolean isPersistent, int freq, String peerAddress, boolean join) { 1225 synchronized (mLock) { 1226 String methodStr = "groupAdd"; 1227 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1228 return false; 1229 } 1230 1231 byte[] macAddress = null; 1232 try { 1233 macAddress = NativeUtil.macAddressToByteArray(peerAddress); 1234 } catch (IllegalArgumentException e) { 1235 Log.e(TAG, "Could not parse mac address.", e); 1236 return false; 1237 } 1238 1239 byte[] ssid = null; 1240 try { 1241 ssid = NativeUtil.byteArrayFromArrayList( 1242 NativeUtil.decodeSsid("\"" + networkName + "\"")); 1243 } catch (Exception e) { 1244 Log.e(TAG, "Could not parse ssid.", e); 1245 return false; 1246 } 1247 1248 try { 1249 mISupplicantP2pIface.addGroupWithConfig( 1250 ssid, passphrase, isPersistent, freq, macAddress, join); 1251 return true; 1252 } catch (RemoteException e) { 1253 handleRemoteException(e, methodStr); 1254 } catch (ServiceSpecificException e) { 1255 handleServiceSpecificException(e, methodStr); 1256 } 1257 return false; 1258 } 1259 } 1260 1261 /** 1262 * Terminate a P2P group. If a new virtual network interface was used for 1263 * the group, it must also be removed. The network interface name of the 1264 * group interface is used as a parameter for this command. 1265 * 1266 * @param groupName Group interface name to use. 1267 * 1268 * @return true, if operation was successful. 1269 */ groupRemove(String groupName)1270 public boolean groupRemove(String groupName) { 1271 synchronized (mLock) { 1272 String methodStr = "groupRemove"; 1273 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1274 return false; 1275 } 1276 if (TextUtils.isEmpty(groupName)) { 1277 return false; 1278 } 1279 try { 1280 mISupplicantP2pIface.removeGroup(groupName); 1281 return true; 1282 } catch (RemoteException e) { 1283 handleRemoteException(e, methodStr); 1284 } catch (ServiceSpecificException e) { 1285 handleServiceSpecificException(e, methodStr); 1286 } 1287 return false; 1288 } 1289 } 1290 1291 /** 1292 * Gets the capability of the group which the device is a 1293 * member of. 1294 * 1295 * @param peerAddress MAC address of the peer. 1296 * 1297 * @return combination of |GroupCapabilityMask| values. 1298 */ getGroupCapability(String peerAddress)1299 public int getGroupCapability(String peerAddress) { 1300 synchronized (mLock) { 1301 String methodStr = "getGroupCapability"; 1302 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1303 return RESULT_NOT_VALID; 1304 } 1305 if (peerAddress == null) { 1306 Log.e(TAG, "Cannot parse null peer mac address."); 1307 return RESULT_NOT_VALID; 1308 } 1309 1310 byte[] macAddress = null; 1311 try { 1312 macAddress = NativeUtil.macAddressToByteArray(peerAddress); 1313 } catch (IllegalArgumentException e) { 1314 Log.e(TAG, "Could not parse mac address.", e); 1315 return RESULT_NOT_VALID; 1316 } 1317 1318 try { 1319 return mISupplicantP2pIface.getGroupCapability(macAddress); 1320 } catch (RemoteException e) { 1321 handleRemoteException(e, methodStr); 1322 } catch (ServiceSpecificException e) { 1323 handleServiceSpecificException(e, methodStr); 1324 } 1325 return RESULT_NOT_VALID; 1326 } 1327 } 1328 1329 /** 1330 * Configure Extended Listen Timing. See comments for 1331 * {@link ISupplicantP2pIfaceHal#configureExtListen(boolean, int, int, WifiP2pExtListenParams)} 1332 * 1333 * @return true, if operation was successful. 1334 */ configureExtListen(boolean enable, int periodInMillis, int intervalInMillis, @Nullable WifiP2pExtListenParams extListenParams)1335 public boolean configureExtListen(boolean enable, int periodInMillis, int intervalInMillis, 1336 @Nullable WifiP2pExtListenParams extListenParams) { 1337 synchronized (mLock) { 1338 String methodStr = "configureExtListen"; 1339 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1340 return false; 1341 } 1342 if (enable && intervalInMillis < periodInMillis) { 1343 return false; 1344 } 1345 1346 // If listening is disabled, wpa supplicant expects zeroes. 1347 if (!enable) { 1348 periodInMillis = 0; 1349 intervalInMillis = 0; 1350 } 1351 1352 // Verify that the integers are not negative. Leave actual parameter validation to 1353 // supplicant. 1354 if (periodInMillis < 0 || intervalInMillis < 0) { 1355 Log.e(TAG, "Invalid parameters supplied to configureExtListen: " + periodInMillis 1356 + ", " + intervalInMillis); 1357 return false; 1358 } 1359 1360 if (getCachedServiceVersion() >= 3) { 1361 return configureExtListenWithParams( 1362 periodInMillis, intervalInMillis, extListenParams); 1363 } 1364 1365 try { 1366 mISupplicantP2pIface.configureExtListen(periodInMillis, intervalInMillis); 1367 return true; 1368 } catch (RemoteException e) { 1369 handleRemoteException(e, methodStr); 1370 } catch (ServiceSpecificException e) { 1371 handleServiceSpecificException(e, methodStr); 1372 } 1373 return false; 1374 } 1375 } 1376 configureExtListenWithParams(int periodInMillis, int intervalInMillis, @Nullable WifiP2pExtListenParams extListenParams)1377 private boolean configureExtListenWithParams(int periodInMillis, int intervalInMillis, 1378 @Nullable WifiP2pExtListenParams extListenParams) { 1379 String methodStr = "configureExtListenWithParams"; 1380 1381 // Expect that these parameters are already validated. 1382 P2pExtListenInfo extListenInfo = new P2pExtListenInfo(); 1383 extListenInfo.periodMs = periodInMillis; 1384 extListenInfo.intervalMs = intervalInMillis; 1385 1386 if (SdkLevel.isAtLeastV() && extListenParams != null 1387 && extListenParams.getVendorData() != null) { 1388 extListenInfo.vendorData = 1389 HalAidlUtil.frameworkToHalOuiKeyedDataList(extListenParams.getVendorData()); 1390 } 1391 1392 try { 1393 mISupplicantP2pIface.configureExtListenWithParams(extListenInfo); 1394 return true; 1395 } catch (RemoteException e) { 1396 handleRemoteException(e, methodStr); 1397 } catch (ServiceSpecificException e) { 1398 handleServiceSpecificException(e, methodStr); 1399 } 1400 return false; 1401 } 1402 1403 /** 1404 * Set P2P Listen channel. 1405 * 1406 * @param listenChannel Wifi channel. eg, 1, 6, 11. 1407 * 1408 * @return true, if operation was successful. 1409 */ setListenChannel(int listenChannel)1410 public boolean setListenChannel(int listenChannel) { 1411 synchronized (mLock) { 1412 String methodStr = "setListenChannel"; 1413 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1414 return false; 1415 } 1416 1417 // There is no original channel recorded in supplicant, so just return true. 1418 if (listenChannel == 0) { 1419 return true; 1420 } 1421 1422 // Using channels other than 1, 6, and 11 would result in a discovery issue. 1423 if (listenChannel != 1 && listenChannel != 6 && listenChannel != 11) { 1424 return false; 1425 } 1426 1427 try { 1428 mISupplicantP2pIface.setListenChannel(listenChannel, DEFAULT_OPERATING_CLASS); 1429 return true; 1430 } catch (RemoteException e) { 1431 handleRemoteException(e, methodStr); 1432 } catch (ServiceSpecificException e) { 1433 handleServiceSpecificException(e, methodStr); 1434 } 1435 return false; 1436 } 1437 } 1438 1439 /** 1440 * Set P2P operating channel. 1441 * 1442 * @param operatingChannel the desired operating channel. 1443 * @param unsafeChannels channels which p2p cannot use. 1444 * 1445 * @return true, if operation was successful. 1446 */ setOperatingChannel(int operatingChannel, @NonNull List<CoexUnsafeChannel> unsafeChannels)1447 public boolean setOperatingChannel(int operatingChannel, 1448 @NonNull List<CoexUnsafeChannel> unsafeChannels) { 1449 synchronized (mLock) { 1450 String methodStr = "setOperatingChannel"; 1451 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1452 return false; 1453 } 1454 if (unsafeChannels == null) { 1455 return false; 1456 } 1457 1458 ArrayList<FreqRange> ranges = new ArrayList<>(); 1459 if (operatingChannel >= 1 && operatingChannel <= 165) { 1460 int freq = (operatingChannel <= 14 ? 2407 : 5000) + operatingChannel * 5; 1461 FreqRange range1 = new FreqRange(); 1462 range1.min = 1000; 1463 range1.max = freq - 5; 1464 FreqRange range2 = new FreqRange(); 1465 range2.min = freq + 5; 1466 range2.max = 6000; 1467 ranges.add(range1); 1468 ranges.add(range2); 1469 } 1470 if (SdkLevel.isAtLeastS()) { 1471 for (CoexUnsafeChannel cuc: unsafeChannels) { 1472 int centerFreq = ScanResult.convertChannelToFrequencyMhzIfSupported( 1473 cuc.getChannel(), cuc.getBand()); 1474 FreqRange range = new FreqRange(); 1475 // The range boundaries are inclusive in native frequency inclusion check. 1476 // Subtract one to avoid affecting neighbors. 1477 range.min = centerFreq - 5 - 1; 1478 range.max = centerFreq + 5 - 1; 1479 ranges.add(range); 1480 } 1481 } 1482 1483 FreqRange[] rangeArr = new FreqRange[ranges.size()]; 1484 for (int i = 0; i < ranges.size(); i++) { 1485 rangeArr[i] = ranges.get(i); 1486 } 1487 1488 try { 1489 mISupplicantP2pIface.setDisallowedFrequencies(rangeArr); 1490 return true; 1491 } catch (RemoteException e) { 1492 handleRemoteException(e, methodStr); 1493 } catch (ServiceSpecificException e) { 1494 handleServiceSpecificException(e, methodStr); 1495 } 1496 return false; 1497 } 1498 } 1499 1500 /** 1501 * This command can be used to add a upnp/bonjour service. 1502 * 1503 * @param servInfo List of service queries. 1504 * 1505 * @return true, if operation was successful. 1506 */ serviceAdd(WifiP2pServiceInfo servInfo)1507 public boolean serviceAdd(WifiP2pServiceInfo servInfo) { 1508 synchronized (mLock) { 1509 String methodStr = "serviceAdd"; 1510 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1511 return false; 1512 } 1513 1514 if (servInfo == null) { 1515 Log.e(TAG, "Null service info passed."); 1516 return false; 1517 } 1518 1519 for (String s : servInfo.getSupplicantQueryList()) { 1520 if (s == null) { 1521 Log.e(TAG, "Invalid service description (null)."); 1522 return false; 1523 } 1524 1525 String[] data = s.split(" "); 1526 if (data.length < 3) { 1527 Log.e(TAG, "Service specification invalid: " + s); 1528 return false; 1529 } 1530 1531 try { 1532 if ("upnp".equals(data[0])) { 1533 int version = 0; 1534 try { 1535 version = Integer.parseInt(data[1], 16); 1536 } catch (NumberFormatException e) { 1537 Log.e(TAG, "UPnP Service specification invalid: " + s, e); 1538 return false; 1539 } 1540 mISupplicantP2pIface.addUpnpService(version, data[2]); 1541 } else if ("bonjour".equals(data[0])) { 1542 if (data[1] != null && data[2] != null) { 1543 byte[] request = null; 1544 byte[] response = null; 1545 try { 1546 request = NativeUtil.hexStringToByteArray(data[1]); 1547 response = NativeUtil.hexStringToByteArray(data[2]); 1548 } catch (IllegalArgumentException e) { 1549 Log.e(TAG, "Invalid bonjour service description."); 1550 return false; 1551 } 1552 mISupplicantP2pIface.addBonjourService(request, response); 1553 } 1554 } else { 1555 Log.e(TAG, "Unknown / unsupported P2P service requested: " + data[0]); 1556 return false; 1557 } 1558 } catch (RemoteException e) { 1559 handleRemoteException(e, methodStr); 1560 return false; 1561 } catch (ServiceSpecificException e) { 1562 handleServiceSpecificException(e, methodStr); 1563 return false; 1564 } 1565 } 1566 1567 return true; 1568 } 1569 } 1570 1571 /** 1572 * This command can be used to remove a upnp/bonjour service. 1573 * 1574 * @param servInfo List of service queries. 1575 * 1576 * @return true, if operation was successful. 1577 */ serviceRemove(WifiP2pServiceInfo servInfo)1578 public boolean serviceRemove(WifiP2pServiceInfo servInfo) { 1579 synchronized (mLock) { 1580 String methodStr = "serviceRemove"; 1581 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1582 return false; 1583 } 1584 1585 if (servInfo == null) { 1586 Log.e(TAG, "Null service info passed."); 1587 return false; 1588 } 1589 1590 for (String s : servInfo.getSupplicantQueryList()) { 1591 if (s == null) { 1592 Log.e(TAG, "Invalid service description (null)."); 1593 return false; 1594 } 1595 1596 String[] data = s.split(" "); 1597 if (data.length < 3) { 1598 Log.e(TAG, "Service specification invalid: " + s); 1599 return false; 1600 } 1601 1602 try { 1603 if ("upnp".equals(data[0])) { 1604 int version = 0; 1605 try { 1606 version = Integer.parseInt(data[1], 16); 1607 } catch (NumberFormatException e) { 1608 Log.e(TAG, "UPnP Service specification invalid: " + s, e); 1609 return false; 1610 } 1611 mISupplicantP2pIface.removeUpnpService(version, data[2]); 1612 } else if ("bonjour".equals(data[0])) { 1613 if (data[1] != null) { 1614 byte[] request = null; 1615 try { 1616 request = NativeUtil.hexStringToByteArray(data[1]); 1617 } catch (IllegalArgumentException e) { 1618 Log.e(TAG, "Invalid bonjour service description."); 1619 return false; 1620 } 1621 mISupplicantP2pIface.removeBonjourService(request); 1622 } 1623 } else { 1624 Log.e(TAG, "Unknown / unsupported P2P service requested: " + data[0]); 1625 return false; 1626 } 1627 } catch (RemoteException e) { 1628 handleRemoteException(e, methodStr); 1629 return false; 1630 } catch (ServiceSpecificException e) { 1631 handleServiceSpecificException(e, methodStr); 1632 return false; 1633 } 1634 } 1635 1636 return true; 1637 } 1638 } 1639 1640 /** 1641 * Schedule a P2P service discovery request. The parameters for this command 1642 * are the device address of the peer device (or 00:00:00:00:00:00 for 1643 * wildcard query that is sent to every discovered P2P peer that supports 1644 * service discovery) and P2P Service Query TLV(s) as hexdump. 1645 * 1646 * @param peerAddress MAC address of the device to discover. 1647 * @param query Hex dump of the query data. 1648 * @return identifier Identifier for the request. Can be used to cancel the 1649 * request. 1650 */ requestServiceDiscovery(String peerAddress, String query)1651 public String requestServiceDiscovery(String peerAddress, String query) { 1652 synchronized (mLock) { 1653 String methodStr = "requestServiceDiscovery"; 1654 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1655 return null; 1656 } 1657 1658 if (peerAddress == null) { 1659 Log.e(TAG, "Cannot parse null peer mac address."); 1660 return null; 1661 } 1662 1663 byte[] macAddress = null; 1664 try { 1665 macAddress = NativeUtil.macAddressToByteArray(peerAddress); 1666 } catch (IllegalArgumentException e) { 1667 Log.e(TAG, "Could not process peer MAC address.", e); 1668 return null; 1669 } 1670 1671 if (query == null) { 1672 Log.e(TAG, "Cannot parse null service discovery query."); 1673 return null; 1674 } 1675 byte[] binQuery = null; 1676 try { 1677 binQuery = NativeUtil.hexStringToByteArray(query); 1678 } catch (Exception e) { 1679 Log.e(TAG, "Could not parse service query.", e); 1680 return null; 1681 } 1682 1683 try { 1684 long result = mISupplicantP2pIface.requestServiceDiscovery(macAddress, binQuery); 1685 return Long.toString(result); 1686 } catch (RemoteException e) { 1687 handleRemoteException(e, methodStr); 1688 } catch (ServiceSpecificException e) { 1689 handleServiceSpecificException(e, methodStr); 1690 } 1691 return null; 1692 } 1693 } 1694 1695 /** 1696 * Cancel a previous service discovery request. 1697 * 1698 * @param identifier Identifier for the request to cancel. 1699 * @return true, if operation was successful. 1700 */ cancelServiceDiscovery(String identifier)1701 public boolean cancelServiceDiscovery(String identifier) { 1702 synchronized (mLock) { 1703 String methodStr = "cancelServiceDiscovery"; 1704 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1705 return false; 1706 } 1707 if (identifier == null) { 1708 Log.e(TAG, "Received a null service discovery identifier."); 1709 return false; 1710 } 1711 1712 long id = 0; 1713 try { 1714 id = Long.parseLong(identifier); 1715 } catch (NumberFormatException e) { 1716 Log.e(TAG, "Service discovery identifier invalid: " + identifier, e); 1717 return false; 1718 } 1719 1720 try { 1721 mISupplicantP2pIface.cancelServiceDiscovery(id); 1722 return true; 1723 } catch (RemoteException e) { 1724 handleRemoteException(e, methodStr); 1725 } catch (ServiceSpecificException e) { 1726 handleServiceSpecificException(e, methodStr); 1727 } 1728 return false; 1729 } 1730 } 1731 1732 /** 1733 * Send driver command to set Miracast mode. 1734 * 1735 * @param mode Mode of Miracast. 1736 * @return true, if operation was successful. 1737 */ setMiracastMode(int mode)1738 public boolean setMiracastMode(int mode) { 1739 synchronized (mLock) { 1740 String methodStr = "setMiracastMode"; 1741 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1742 return false; 1743 } 1744 1745 byte targetMode = MiracastMode.DISABLED; 1746 switch (mode) { 1747 case WifiP2pManager.MIRACAST_SOURCE: 1748 targetMode = MiracastMode.SOURCE; 1749 break; 1750 case WifiP2pManager.MIRACAST_SINK: 1751 targetMode = MiracastMode.SINK; 1752 break; 1753 } 1754 1755 try { 1756 mISupplicantP2pIface.setMiracastMode(targetMode); 1757 return true; 1758 } catch (RemoteException e) { 1759 handleRemoteException(e, methodStr); 1760 } catch (ServiceSpecificException e) { 1761 handleServiceSpecificException(e, methodStr); 1762 } 1763 return false; 1764 } 1765 } 1766 1767 /** 1768 * Initiate WPS Push Button setup. 1769 * The PBC operation requires that a button is also pressed at the 1770 * AP/Registrar at about the same time (2 minute window). 1771 * 1772 * @param groupIfName Group interface name to use. 1773 * @param bssid BSSID of the AP. Use empty bssid to indicate wildcard. 1774 * @return true, if operation was successful. 1775 */ startWpsPbc(String groupIfName, String bssid)1776 public boolean startWpsPbc(String groupIfName, String bssid) { 1777 synchronized (mLock) { 1778 String methodStr = "startWpsPbc"; 1779 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1780 return false; 1781 } 1782 if (TextUtils.isEmpty(groupIfName)) { 1783 Log.e(TAG, "Group name required when requesting WPS PBC. Got empty string."); 1784 return false; 1785 } 1786 1787 // Null values should be fine, since bssid can be empty. 1788 byte[] macAddress = null; 1789 try { 1790 macAddress = NativeUtil.macAddressToByteArray(bssid); 1791 } catch (IllegalArgumentException e) { 1792 Log.e(TAG, "Could not parse BSSID.", e); 1793 return false; 1794 } 1795 1796 try { 1797 mISupplicantP2pIface.startWpsPbc(groupIfName, macAddress); 1798 return true; 1799 } catch (RemoteException e) { 1800 handleRemoteException(e, methodStr); 1801 } catch (ServiceSpecificException e) { 1802 handleServiceSpecificException(e, methodStr); 1803 } 1804 return false; 1805 } 1806 } 1807 1808 /** 1809 * Initiate WPS Pin Keypad setup. 1810 * 1811 * @param groupIfName Group interface name to use. 1812 * @param pin 8 digit pin to be used. 1813 * @return true, if operation was successful. 1814 */ startWpsPinKeypad(String groupIfName, String pin)1815 public boolean startWpsPinKeypad(String groupIfName, String pin) { 1816 synchronized (mLock) { 1817 String methodStr = "startWpsPinKeypad"; 1818 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1819 return false; 1820 } 1821 if (TextUtils.isEmpty(groupIfName)) { 1822 Log.e(TAG, "Group name required when requesting WPS KEYPAD."); 1823 return false; 1824 } 1825 if (TextUtils.isEmpty(pin)) { 1826 Log.e(TAG, "PIN required when requesting WPS KEYPAD."); 1827 return false; 1828 } 1829 1830 try { 1831 mISupplicantP2pIface.startWpsPinKeypad(groupIfName, pin); 1832 return true; 1833 } catch (RemoteException e) { 1834 handleRemoteException(e, methodStr); 1835 } catch (ServiceSpecificException e) { 1836 handleServiceSpecificException(e, methodStr); 1837 } 1838 return false; 1839 } 1840 } 1841 1842 /** 1843 * Initiate WPS Pin Display setup. 1844 * 1845 * @param groupIfName Group interface name to use. 1846 * @param bssid BSSID of the AP. Use empty bssid to indicate wildcard. 1847 * @return generated pin if operation was successful, null otherwise. 1848 */ startWpsPinDisplay(String groupIfName, String bssid)1849 public String startWpsPinDisplay(String groupIfName, String bssid) { 1850 synchronized (mLock) { 1851 String methodStr = "startWpsPinDisplay"; 1852 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1853 return null; 1854 } 1855 if (TextUtils.isEmpty(groupIfName)) { 1856 Log.e(TAG, "Group name required when requesting WPS KEYPAD."); 1857 return null; 1858 } 1859 1860 // Null values should be fine, since bssid can be empty. 1861 byte[] macAddress = null; 1862 try { 1863 macAddress = NativeUtil.macAddressToByteArray(bssid); 1864 } catch (IllegalArgumentException e) { 1865 Log.e(TAG, "Could not parse BSSID.", e); 1866 return null; 1867 } 1868 1869 try { 1870 return mISupplicantP2pIface.startWpsPinDisplay(groupIfName, macAddress); 1871 } catch (RemoteException e) { 1872 handleRemoteException(e, methodStr); 1873 } catch (ServiceSpecificException e) { 1874 handleServiceSpecificException(e, methodStr); 1875 } 1876 return null; 1877 } 1878 } 1879 1880 /** 1881 * Cancel any ongoing WPS operations. 1882 * 1883 * @param groupIfName Group interface name to use. 1884 * @return true, if operation was successful. 1885 */ cancelWps(String groupIfName)1886 public boolean cancelWps(String groupIfName) { 1887 synchronized (mLock) { 1888 String methodStr = "cancelWps"; 1889 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1890 return false; 1891 } 1892 if (groupIfName == null) { 1893 Log.e(TAG, "Group name required when requesting WPS KEYPAD."); 1894 return false; 1895 } 1896 1897 try { 1898 mISupplicantP2pIface.cancelWps(groupIfName); 1899 return true; 1900 } catch (RemoteException e) { 1901 handleRemoteException(e, methodStr); 1902 } catch (ServiceSpecificException e) { 1903 handleServiceSpecificException(e, methodStr); 1904 } 1905 return false; 1906 } 1907 } 1908 1909 /** 1910 * Enable/Disable Wifi Display. 1911 * 1912 * @param enable true to enable, false to disable. 1913 * @return true, if operation was successful. 1914 */ enableWfd(boolean enable)1915 public boolean enableWfd(boolean enable) { 1916 synchronized (mLock) { 1917 String methodStr = "enableWfd"; 1918 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1919 return false; 1920 } 1921 try { 1922 mISupplicantP2pIface.enableWfd(enable); 1923 return true; 1924 } catch (RemoteException e) { 1925 handleRemoteException(e, methodStr); 1926 } catch (ServiceSpecificException e) { 1927 handleServiceSpecificException(e, methodStr); 1928 } 1929 return false; 1930 } 1931 } 1932 1933 1934 /** 1935 * Set Wifi Display device info. 1936 * 1937 * @param info WFD device info as described in section 5.1.2 of WFD technical 1938 * specification v1.0.0. 1939 * @return true, if operation was successful. 1940 */ setWfdDeviceInfo(String info)1941 public boolean setWfdDeviceInfo(String info) { 1942 synchronized (mLock) { 1943 String methodStr = "setWfdDeviceInfo"; 1944 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1945 return false; 1946 } 1947 if (info == null) { 1948 Log.e(TAG, "Cannot parse null WFD info string."); 1949 return false; 1950 } 1951 1952 byte[] wfdInfo = null; 1953 try { 1954 wfdInfo = NativeUtil.hexStringToByteArray(info); 1955 } catch (IllegalArgumentException e) { 1956 Log.e(TAG, "Could not parse WFD Device Info string."); 1957 return false; 1958 } 1959 1960 try { 1961 mISupplicantP2pIface.setWfdDeviceInfo(wfdInfo); 1962 return true; 1963 } catch (RemoteException e) { 1964 handleRemoteException(e, methodStr); 1965 } catch (ServiceSpecificException e) { 1966 handleServiceSpecificException(e, methodStr); 1967 } 1968 return false; 1969 } 1970 } 1971 1972 /** 1973 * Remove network with provided id. 1974 * 1975 * @param networkId Id of the network to lookup. 1976 * @return true, if operation was successful. 1977 */ removeNetwork(int networkId)1978 public boolean removeNetwork(int networkId) { 1979 synchronized (mLock) { 1980 String methodStr = "removeNetwork"; 1981 if (!checkP2pIfaceAndLogFailure(methodStr)) { 1982 return false; 1983 } 1984 try { 1985 mISupplicantP2pIface.removeNetwork(networkId); 1986 return true; 1987 } catch (RemoteException e) { 1988 handleRemoteException(e, methodStr); 1989 } catch (ServiceSpecificException e) { 1990 handleServiceSpecificException(e, methodStr); 1991 } 1992 return false; 1993 } 1994 } 1995 1996 /** 1997 * List the networks saved in wpa_supplicant. 1998 * 1999 * @return List of network ids. 2000 */ listNetworks()2001 private int[] listNetworks() { 2002 synchronized (mLock) { 2003 String methodStr = "listNetworks"; 2004 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2005 return null; 2006 } 2007 try { 2008 return mISupplicantP2pIface.listNetworks(); 2009 } catch (RemoteException e) { 2010 handleRemoteException(e, methodStr); 2011 } catch (ServiceSpecificException e) { 2012 handleServiceSpecificException(e, methodStr); 2013 } 2014 return null; 2015 } 2016 } 2017 2018 /** 2019 * Get the supplicant P2p network object for the specified network ID. 2020 * 2021 * @param networkId Id of the network to lookup. 2022 * @return ISupplicantP2pNetwork instance on success, null on failure. 2023 */ getNetwork(int networkId)2024 private ISupplicantP2pNetwork getNetwork(int networkId) { 2025 synchronized (mLock) { 2026 String methodStr = "getNetwork"; 2027 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2028 return null; 2029 } 2030 try { 2031 return mISupplicantP2pIface.getNetwork(networkId); 2032 } catch (RemoteException e) { 2033 handleRemoteException(e, methodStr); 2034 } catch (ServiceSpecificException e) { 2035 handleServiceSpecificException(e, methodStr); 2036 } 2037 return null; 2038 } 2039 } 2040 2041 /** 2042 * Get the persistent group list from wpa_supplicant's p2p mgmt interface 2043 * 2044 * @param groups WifiP2pGroupList to store persistent groups in 2045 * @return true, if list has been modified. 2046 */ loadGroups(WifiP2pGroupList groups)2047 public boolean loadGroups(WifiP2pGroupList groups) { 2048 synchronized (mLock) { 2049 String methodStr = "loadGroups"; 2050 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2051 return false; 2052 } 2053 int[] networkIds = listNetworks(); 2054 if (networkIds == null || networkIds.length == 0) { 2055 return false; 2056 } 2057 for (int networkId : networkIds) { 2058 ISupplicantP2pNetwork network = getNetwork(networkId); 2059 if (network == null) { 2060 Log.e(TAG, "Failed to retrieve network object for " + networkId); 2061 continue; 2062 } 2063 2064 boolean gotResult = false; 2065 boolean isCurrent = false; 2066 try { 2067 isCurrent = network.isCurrent(); 2068 gotResult = true; 2069 } catch (RemoteException e) { 2070 handleRemoteException(e, methodStr); 2071 } catch (ServiceSpecificException e) { 2072 handleServiceSpecificException(e, methodStr); 2073 } 2074 2075 /** Skip the current network, if we're somehow getting networks from the p2p GO 2076 interface, instead of p2p mgmt interface*/ 2077 if (!gotResult || isCurrent) { 2078 Log.i(TAG, "Skipping current network"); 2079 continue; 2080 } 2081 2082 WifiP2pGroup group = new WifiP2pGroup(); 2083 group.setNetworkId(networkId); 2084 2085 // Now get the ssid, bssid and other flags for this network. 2086 byte[] ssid = null; 2087 gotResult = false; 2088 try { 2089 ssid = network.getSsid(); 2090 gotResult = true; 2091 } catch (RemoteException e) { 2092 handleRemoteException(e, methodStr); 2093 } catch (ServiceSpecificException e) { 2094 handleServiceSpecificException(e, methodStr); 2095 } 2096 if (gotResult && !ArrayUtils.isEmpty(ssid)) { 2097 group.setNetworkName(NativeUtil.removeEnclosingQuotes( 2098 NativeUtil.encodeSsid( 2099 NativeUtil.byteArrayToArrayList(ssid)))); 2100 } 2101 2102 byte[] bssid = null; 2103 gotResult = false; 2104 try { 2105 bssid = network.getBssid(); 2106 gotResult = true; 2107 } catch (RemoteException e) { 2108 handleRemoteException(e, methodStr); 2109 } catch (ServiceSpecificException e) { 2110 handleServiceSpecificException(e, methodStr); 2111 } 2112 if (gotResult && !ArrayUtils.isEmpty(bssid)) { 2113 WifiP2pDevice device = new WifiP2pDevice(); 2114 device.deviceAddress = NativeUtil.macAddressFromByteArray(bssid); 2115 group.setOwner(device); 2116 } 2117 2118 boolean isGroupOwner = false; 2119 gotResult = false; 2120 try { 2121 isGroupOwner = network.isGroupOwner(); 2122 gotResult = true; 2123 } catch (RemoteException e) { 2124 handleRemoteException(e, methodStr); 2125 } catch (ServiceSpecificException e) { 2126 handleServiceSpecificException(e, methodStr); 2127 } 2128 if (gotResult) { 2129 group.setIsGroupOwner(isGroupOwner); 2130 } 2131 groups.add(group); 2132 } 2133 } 2134 return true; 2135 } 2136 2137 /** 2138 * Set WPS device name. 2139 * 2140 * @param name String to be set. 2141 * @return true if request is sent successfully, false otherwise. 2142 */ setWpsDeviceName(String name)2143 public boolean setWpsDeviceName(String name) { 2144 synchronized (mLock) { 2145 String methodStr = "setWpsDeviceName"; 2146 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2147 return false; 2148 } 2149 if (name == null) { 2150 return false; 2151 } 2152 try { 2153 mISupplicantP2pIface.setWpsDeviceName(name); 2154 return true; 2155 } catch (RemoteException e) { 2156 handleRemoteException(e, methodStr); 2157 } catch (ServiceSpecificException e) { 2158 handleServiceSpecificException(e, methodStr); 2159 } 2160 return false; 2161 } 2162 } 2163 2164 /** 2165 * Set WPS device type. 2166 * 2167 * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg> 2168 * @return true if request is sent successfully, false otherwise. 2169 */ setWpsDeviceType(String typeStr)2170 public boolean setWpsDeviceType(String typeStr) { 2171 try { 2172 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr); 2173 if (!match.find() || match.groupCount() != 3) { 2174 Log.e(TAG, "Malformed WPS device type " + typeStr); 2175 return false; 2176 } 2177 short categ = Short.parseShort(match.group(1)); 2178 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2)); 2179 short subCateg = Short.parseShort(match.group(3)); 2180 2181 byte[] bytes = new byte[8]; 2182 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); 2183 byteBuffer.putShort(categ); 2184 byteBuffer.put(oui); 2185 byteBuffer.putShort(subCateg); 2186 synchronized (mLock) { 2187 String methodStr = "setWpsDeviceType"; 2188 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2189 return false; 2190 } 2191 try { 2192 mISupplicantP2pIface.setWpsDeviceType(bytes); 2193 return true; 2194 } catch (RemoteException e) { 2195 handleRemoteException(e, methodStr); 2196 } catch (ServiceSpecificException e) { 2197 handleServiceSpecificException(e, methodStr); 2198 } 2199 } 2200 } catch (IllegalArgumentException e) { 2201 Log.e(TAG, "Illegal argument " + typeStr, e); 2202 } 2203 return false; 2204 } 2205 2206 /** 2207 * Set WPS config methods 2208 * 2209 * @param configMethodsStr List of config methods. 2210 * @return true if request is sent successfully, false otherwise. 2211 */ setWpsConfigMethods(String configMethodsStr)2212 public boolean setWpsConfigMethods(String configMethodsStr) { 2213 synchronized (mLock) { 2214 String methodStr = "setWpsConfigMethods"; 2215 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2216 return false; 2217 } 2218 2219 short configMethodsMask = 0; 2220 String[] configMethodsStrArr = configMethodsStr.split("\\s+"); 2221 for (int i = 0; i < configMethodsStrArr.length; i++) { 2222 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]); 2223 } 2224 2225 try { 2226 mISupplicantP2pIface.setWpsConfigMethods(configMethodsMask); 2227 return true; 2228 } catch (RemoteException e) { 2229 handleRemoteException(e, methodStr); 2230 } catch (ServiceSpecificException e) { 2231 handleServiceSpecificException(e, methodStr); 2232 } 2233 return false; 2234 } 2235 } 2236 2237 /** 2238 * Get NFC handover request message. 2239 * 2240 * @return select message if created successfully, null otherwise. 2241 */ getNfcHandoverRequest()2242 public String getNfcHandoverRequest() { 2243 synchronized (mLock) { 2244 String methodStr = "getNfcHandoverRequest"; 2245 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2246 return null; 2247 } 2248 try { 2249 byte[] message = mISupplicantP2pIface.createNfcHandoverRequestMessage(); 2250 return NativeUtil.hexStringFromByteArray(message); 2251 } catch (RemoteException e) { 2252 handleRemoteException(e, methodStr); 2253 } catch (ServiceSpecificException e) { 2254 handleServiceSpecificException(e, methodStr); 2255 } catch (IllegalArgumentException e) { 2256 Log.e(TAG, "Invalid message received ", e); 2257 } 2258 return null; 2259 } 2260 } 2261 2262 /** 2263 * Get NFC handover select message. 2264 * 2265 * @return select message if created successfully, null otherwise. 2266 */ getNfcHandoverSelect()2267 public String getNfcHandoverSelect() { 2268 synchronized (mLock) { 2269 String methodStr = "getNfcHandoverSelect"; 2270 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2271 return null; 2272 } 2273 try { 2274 byte[] message = mISupplicantP2pIface.createNfcHandoverSelectMessage(); 2275 return NativeUtil.hexStringFromByteArray(message); 2276 } catch (RemoteException e) { 2277 handleRemoteException(e, methodStr); 2278 } catch (ServiceSpecificException e) { 2279 handleServiceSpecificException(e, methodStr); 2280 } catch (IllegalArgumentException e) { 2281 Log.e(TAG, "Invalid message received ", e); 2282 } 2283 return null; 2284 } 2285 } 2286 2287 /** 2288 * Report NFC handover select message. 2289 * 2290 * @return true if reported successfully, false otherwise. 2291 */ initiatorReportNfcHandover(String selectMessage)2292 public boolean initiatorReportNfcHandover(String selectMessage) { 2293 synchronized (mLock) { 2294 String methodStr = "initiatorReportNfcHandover"; 2295 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2296 return false; 2297 } 2298 if (selectMessage == null) { 2299 return false; 2300 } 2301 try { 2302 mISupplicantP2pIface.reportNfcHandoverInitiation( 2303 NativeUtil.hexStringToByteArray(selectMessage)); 2304 return true; 2305 } catch (RemoteException e) { 2306 handleRemoteException(e, methodStr); 2307 } catch (ServiceSpecificException e) { 2308 handleServiceSpecificException(e, methodStr); 2309 } catch (IllegalArgumentException e) { 2310 Log.e(TAG, "Illegal argument " + selectMessage, e); 2311 } 2312 return false; 2313 } 2314 } 2315 2316 /** 2317 * Report NFC handover request message. 2318 * 2319 * @return true if reported successfully, false otherwise. 2320 */ responderReportNfcHandover(String requestMessage)2321 public boolean responderReportNfcHandover(String requestMessage) { 2322 synchronized (mLock) { 2323 String methodStr = "responderReportNfcHandover"; 2324 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2325 return false; 2326 } 2327 if (requestMessage == null) { 2328 return false; 2329 } 2330 try { 2331 mISupplicantP2pIface.reportNfcHandoverResponse( 2332 NativeUtil.hexStringToByteArray(requestMessage)); 2333 return true; 2334 } catch (RemoteException e) { 2335 handleRemoteException(e, methodStr); 2336 } catch (ServiceSpecificException e) { 2337 handleServiceSpecificException(e, methodStr); 2338 } catch (IllegalArgumentException e) { 2339 Log.e(TAG, "Illegal argument " + requestMessage, e); 2340 } 2341 return false; 2342 } 2343 } 2344 2345 /** 2346 * Set the client list for the provided network. 2347 * 2348 * @param networkId Id of the network. 2349 * @param clientListStr Space separated list of clients. 2350 * @return true, if operation was successful. 2351 */ setClientList(int networkId, String clientListStr)2352 public boolean setClientList(int networkId, String clientListStr) { 2353 synchronized (mLock) { 2354 String methodStr = "setClientList"; 2355 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2356 return false; 2357 } 2358 if (TextUtils.isEmpty(clientListStr)) { 2359 Log.e(TAG, "Invalid client list"); 2360 return false; 2361 } 2362 ISupplicantP2pNetwork network = getNetwork(networkId); 2363 if (network == null) { 2364 Log.e(TAG, "Invalid network id "); 2365 return false; 2366 } 2367 2368 try { 2369 String[] clientListArr = clientListStr.split("\\s+"); 2370 android.hardware.wifi.supplicant.MacAddress[] clients = 2371 new android.hardware.wifi.supplicant.MacAddress[clientListArr.length]; 2372 for (int i = 0; i < clientListArr.length; i++) { 2373 android.hardware.wifi.supplicant.MacAddress client = 2374 new android.hardware.wifi.supplicant.MacAddress(); 2375 client.data = NativeUtil.macAddressToByteArray(clientListArr[i]); 2376 clients[i] = client; 2377 } 2378 network.setClientList(clients); 2379 return true; 2380 } catch (RemoteException e) { 2381 handleRemoteException(e, methodStr); 2382 } catch (ServiceSpecificException e) { 2383 handleServiceSpecificException(e, methodStr); 2384 } catch (IllegalArgumentException e) { 2385 Log.e(TAG, "Illegal argument " + clientListStr, e); 2386 } 2387 return false; 2388 } 2389 } 2390 2391 /** 2392 * Set the client list for the provided network. 2393 * 2394 * @param networkId Id of the network. 2395 * @return Space separated list of clients if successful, null otherwise. 2396 */ getClientList(int networkId)2397 public String getClientList(int networkId) { 2398 synchronized (mLock) { 2399 String methodStr = "getClientList"; 2400 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2401 return null; 2402 } 2403 ISupplicantP2pNetwork network = getNetwork(networkId); 2404 if (network == null) { 2405 Log.e(TAG, "Invalid network id "); 2406 return null; 2407 } 2408 try { 2409 android.hardware.wifi.supplicant.MacAddress[] clients = network.getClientList(); 2410 String[] macStrings = new String[clients.length]; 2411 for (int i = 0; i < clients.length; i++) { 2412 try { 2413 macStrings[i] = NativeUtil.macAddressFromByteArray(clients[i].data); 2414 } catch (Exception e) { 2415 Log.e(TAG, "Invalid MAC address received ", e); 2416 return null; 2417 } 2418 } 2419 return String.join(" ", macStrings); 2420 } catch (RemoteException e) { 2421 handleRemoteException(e, methodStr); 2422 } catch (ServiceSpecificException e) { 2423 handleServiceSpecificException(e, methodStr); 2424 } 2425 return null; 2426 2427 } 2428 } 2429 2430 /** 2431 * Persist the current configurations to disk. 2432 * 2433 * @return true, if operation was successful. 2434 */ saveConfig()2435 public boolean saveConfig() { 2436 synchronized (mLock) { 2437 String methodStr = "saveConfig"; 2438 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2439 return false; 2440 } 2441 try { 2442 mISupplicantP2pIface.saveConfig(); 2443 return true; 2444 } catch (RemoteException e) { 2445 handleRemoteException(e, methodStr); 2446 } catch (ServiceSpecificException e) { 2447 handleServiceSpecificException(e, methodStr); 2448 } 2449 return false; 2450 } 2451 } 2452 2453 2454 /** 2455 * Enable/Disable P2P MAC randomization. 2456 * 2457 * @param enable true to enable, false to disable. 2458 * @return true, if operation was successful. 2459 */ setMacRandomization(boolean enable)2460 public boolean setMacRandomization(boolean enable) { 2461 synchronized (mLock) { 2462 String methodStr = "setMacRandomization"; 2463 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2464 return false; 2465 } 2466 try { 2467 mISupplicantP2pIface.setMacRandomization(enable); 2468 return true; 2469 } catch (RemoteException e) { 2470 handleRemoteException(e, methodStr); 2471 } catch (ServiceSpecificException e) { 2472 handleServiceSpecificException(e, methodStr); 2473 } 2474 return false; 2475 } 2476 } 2477 2478 /** 2479 * Set Wifi Display R2 device info. 2480 * 2481 * @param info WFD R2 device info as described in section 5.1.12 of WFD technical 2482 * specification v2.1. 2483 * @return true, if operation was successful. 2484 */ setWfdR2DeviceInfo(String info)2485 public boolean setWfdR2DeviceInfo(String info) { 2486 synchronized (mLock) { 2487 String methodStr = "setWfdR2DeviceInfo"; 2488 if (info == null) { 2489 Log.e(TAG, "Cannot parse null WFD info string."); 2490 return false; 2491 } 2492 2493 byte[] wfdR2Info = null; 2494 try { 2495 wfdR2Info = NativeUtil.hexStringToByteArray(info); 2496 } catch (IllegalArgumentException e) { 2497 Log.e(TAG, "Could not parse WFD R2 Device Info string."); 2498 return false; 2499 } 2500 2501 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2502 return false; 2503 } 2504 try { 2505 mISupplicantP2pIface.setWfdR2DeviceInfo(wfdR2Info); 2506 return true; 2507 } catch (RemoteException e) { 2508 handleRemoteException(e, methodStr); 2509 } catch (ServiceSpecificException e) { 2510 handleServiceSpecificException(e, methodStr); 2511 } 2512 return false; 2513 } 2514 } 2515 2516 /** 2517 * Remove the client with the MAC address from the group. 2518 * 2519 * @param peerAddress Mac address of the client. 2520 * @param isLegacyClient Indicate if client is a legacy client or not. 2521 * @return true if success 2522 */ removeClient(String peerAddress, boolean isLegacyClient)2523 public boolean removeClient(String peerAddress, boolean isLegacyClient) { 2524 synchronized (mLock) { 2525 String methodStr = "removeClient"; 2526 2527 if (peerAddress == null) { 2528 Log.e(TAG, "Cannot parse null peer mac address."); 2529 return false; 2530 } 2531 2532 byte[] peerMacAddress; 2533 try { 2534 peerMacAddress = NativeUtil.macAddressToByteArray(peerAddress); 2535 } catch (IllegalArgumentException e) { 2536 Log.e(TAG, "Peer mac address parse error.", e); 2537 return false; 2538 } 2539 2540 2541 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2542 return false; 2543 } 2544 try { 2545 mISupplicantP2pIface.removeClient(peerMacAddress, isLegacyClient); 2546 return true; 2547 } catch (RemoteException e) { 2548 handleRemoteException(e, methodStr); 2549 } catch (ServiceSpecificException e) { 2550 handleServiceSpecificException(e, methodStr); 2551 } 2552 return false; 2553 } 2554 } 2555 2556 /** 2557 * Set vendor-specific information elements to wpa_supplicant. 2558 * 2559 * @param vendorElements The list of vendor-specific information elements. 2560 * 2561 * @return boolean The value indicating whether operation was successful. 2562 */ setVendorElements(Set<ScanResult.InformationElement> vendorElements)2563 public boolean setVendorElements(Set<ScanResult.InformationElement> vendorElements) { 2564 synchronized (mLock) { 2565 String methodStr = "setVendorElements"; 2566 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2567 return false; 2568 } 2569 if (vendorElements == null) { 2570 return false; 2571 } 2572 byte[] vendorElemBytes = convertInformationElementSetToBytes( 2573 vendorElements); 2574 if (null == vendorElemBytes) { 2575 Log.w(TAG, "Cannot convert vendor elements to bytes."); 2576 return false; 2577 } 2578 try { 2579 mISupplicantP2pIface.setVendorElements( 2580 P2pFrameTypeMask.P2P_FRAME_PROBE_RESP_P2P, vendorElemBytes); 2581 return true; 2582 } catch (RemoteException e) { 2583 handleRemoteException(e, methodStr); 2584 } catch (ServiceSpecificException e) { 2585 handleServiceSpecificException(e, methodStr); 2586 } 2587 return false; 2588 } 2589 } 2590 getCachedServiceVersion()2591 private int getCachedServiceVersion() { 2592 if (mServiceVersion == -1) { 2593 mServiceVersion = mWifiInjector.getSettingsConfigStore().get( 2594 WifiSettingsConfigStore.SUPPLICANT_HAL_AIDL_SERVICE_VERSION); 2595 } 2596 return mServiceVersion; 2597 } 2598 2599 /** 2600 * Get the supported features. 2601 * 2602 * @return bitmask defined by WifiP2pManager.FEATURE_* 2603 */ getSupportedFeatures()2604 public long getSupportedFeatures() { 2605 // First AIDL version supports these three features. 2606 long result = WifiP2pManager.FEATURE_SET_VENDOR_ELEMENTS 2607 | WifiP2pManager.FEATURE_FLEXIBLE_DISCOVERY 2608 | WifiP2pManager.FEATURE_GROUP_CLIENT_REMOVAL; 2609 if (getCachedServiceVersion() >= 2) { 2610 result |= WifiP2pManager.FEATURE_GROUP_OWNER_IPV6_LINK_LOCAL_ADDRESS_PROVIDED; 2611 } 2612 return result; 2613 } 2614 2615 /** 2616 * Configure the IP addresses in supplicant for P2P GO to provide the IP address to 2617 * client in EAPOL handshake. Refer Wi-Fi P2P Technical Specification v1.7 - Section 4.2.8 2618 * IP Address Allocation in EAPOL-Key Frames (4-Way Handshake) for more details. 2619 * The IP addresses are IPV4 addresses and higher-order address bytes are in the 2620 * lower-order int bytes (e.g. 1.2.3.4 is represented as 0x04030201) 2621 * 2622 * @param ipAddressGo The P2P Group Owner IP address. 2623 * @param ipAddressMask The P2P Group owner subnet mask. 2624 * @param ipAddressStart The starting address in the IP address pool. 2625 * @param ipAddressEnd The ending address in the IP address pool. 2626 * @return boolean value indicating whether operation was successful. 2627 */ configureEapolIpAddressAllocationParams(int ipAddressGo, int ipAddressMask, int ipAddressStart, int ipAddressEnd)2628 public boolean configureEapolIpAddressAllocationParams(int ipAddressGo, int ipAddressMask, 2629 int ipAddressStart, int ipAddressEnd) { 2630 synchronized (mLock) { 2631 String methodStr = "configureEapolIpAddressAllocationParams"; 2632 if (!checkP2pIfaceAndLogFailure(methodStr)) { 2633 return false; 2634 } 2635 try { 2636 mISupplicantP2pIface.configureEapolIpAddressAllocationParams(ipAddressGo, 2637 ipAddressMask, ipAddressStart, ipAddressEnd); 2638 return true; 2639 } catch (RemoteException e) { 2640 handleRemoteException(e, methodStr); 2641 } catch (ServiceSpecificException e) { 2642 handleServiceSpecificException(e, methodStr); 2643 } 2644 return false; 2645 } 2646 } 2647 convertInformationElementSetToBytes( Set<ScanResult.InformationElement> ies)2648 private byte[] convertInformationElementSetToBytes( 2649 Set<ScanResult.InformationElement> ies) { 2650 try { 2651 ByteArrayOutputStream os = new ByteArrayOutputStream(); 2652 for (ScanResult.InformationElement ie: ies) { 2653 os.write((byte) ie.id); 2654 os.write((byte) (ie.bytes.length)); 2655 os.write(ie.bytes); 2656 } 2657 return os.toByteArray(); 2658 } catch (IOException ex) { 2659 return null; 2660 } catch (Exception ex) { 2661 return null; 2662 } 2663 } 2664 2665 /** 2666 * Converts the Wps config method string to the equivalent enum value. 2667 */ stringToWpsConfigMethod(String configMethod)2668 private static short stringToWpsConfigMethod(String configMethod) { 2669 switch (configMethod) { 2670 case "usba": 2671 return WpsConfigMethods.USBA; 2672 case "ethernet": 2673 return WpsConfigMethods.ETHERNET; 2674 case "label": 2675 return WpsConfigMethods.LABEL; 2676 case "display": 2677 return WpsConfigMethods.DISPLAY; 2678 case "int_nfc_token": 2679 return WpsConfigMethods.INT_NFC_TOKEN; 2680 case "ext_nfc_token": 2681 return WpsConfigMethods.EXT_NFC_TOKEN; 2682 case "nfc_interface": 2683 return WpsConfigMethods.NFC_INTERFACE; 2684 case "push_button": 2685 return WpsConfigMethods.PUSHBUTTON; 2686 case "keypad": 2687 return WpsConfigMethods.KEYPAD; 2688 case "virtual_push_button": 2689 return WpsConfigMethods.VIRT_PUSHBUTTON; 2690 case "physical_push_button": 2691 return WpsConfigMethods.PHY_PUSHBUTTON; 2692 case "p2ps": 2693 return WpsConfigMethods.P2PS; 2694 case "virtual_display": 2695 return WpsConfigMethods.VIRT_DISPLAY; 2696 case "physical_display": 2697 return WpsConfigMethods.PHY_DISPLAY; 2698 default: 2699 throw new IllegalArgumentException( 2700 "Invalid WPS config method: " + configMethod); 2701 } 2702 } 2703 2704 /** 2705 * Terminate the supplicant daemon & wait for its death. 2706 */ terminate()2707 public void terminate() { 2708 synchronized (mLock) { 2709 final String methodStr = "terminate"; 2710 if (!checkSupplicantAndLogFailure(methodStr)) { 2711 return; 2712 } 2713 Log.i(TAG, "Terminate supplicant service"); 2714 try { 2715 mWaitForDeathLatch = new CountDownLatch(1); 2716 mISupplicant.terminate(); 2717 } catch (RemoteException e) { 2718 handleRemoteException(e, methodStr); 2719 } 2720 } 2721 2722 // Wait for death recipient to confirm the service death. 2723 try { 2724 if (!mWaitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 2725 Log.w(TAG, "Timed out waiting for confirmation of supplicant death"); 2726 supplicantServiceDiedHandler(); 2727 } else { 2728 Log.d(TAG, "Got service death confirmation"); 2729 } 2730 } catch (InterruptedException e) { 2731 Log.w(TAG, "Failed to wait for supplicant death"); 2732 } 2733 } 2734 2735 /** 2736 * Registers a death notification for supplicant. 2737 * @return Returns true on success. 2738 */ registerDeathHandler(@onNull WifiNative.SupplicantDeathEventHandler handler)2739 public boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) { 2740 synchronized (mLock) { 2741 if (mDeathEventHandler != null) { 2742 Log.e(TAG, "Death handler already present"); 2743 } 2744 mDeathEventHandler = handler; 2745 return true; 2746 } 2747 } 2748 2749 /** 2750 * Deregisters a death notification for supplicant. 2751 * @return Returns true on success. 2752 */ deregisterDeathHandler()2753 public boolean deregisterDeathHandler() { 2754 synchronized (mLock) { 2755 if (mDeathEventHandler == null) { 2756 Log.e(TAG, "No Death handler present"); 2757 } 2758 mDeathEventHandler = null; 2759 return true; 2760 } 2761 } 2762 2763 } 2764