1 /* 2 * Copyright (C) 2016 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.aware; 18 19 import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_SUSPEND_INTERNAL_ERROR; 20 21 import static com.android.server.wifi.aware.WifiAwareStateManager.INSTANT_MODE_24GHZ; 22 import static com.android.server.wifi.aware.WifiAwareStateManager.INSTANT_MODE_5GHZ; 23 import static com.android.server.wifi.aware.WifiAwareStateManager.INSTANT_MODE_DISABLED; 24 import static com.android.server.wifi.aware.WifiAwareStateManager.NAN_PAIRING_REQUEST_TYPE_SETUP; 25 import static com.android.server.wifi.aware.WifiAwareStateManager.NAN_PAIRING_REQUEST_TYPE_VERIFICATION; 26 27 import android.annotation.NonNull; 28 import android.net.wifi.OuiKeyedData; 29 import android.net.wifi.WifiScanner; 30 import android.net.wifi.aware.AwarePairingConfig; 31 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 32 import android.net.wifi.aware.PeerHandle; 33 import android.net.wifi.aware.PublishConfig; 34 import android.net.wifi.aware.SubscribeConfig; 35 import android.net.wifi.aware.WifiAwareManager; 36 import android.net.wifi.rtt.RangingResult; 37 import android.net.wifi.util.HexEncoding; 38 import android.os.RemoteException; 39 import android.os.SystemClock; 40 import android.util.Log; 41 import android.util.SparseArray; 42 43 import com.android.server.wifi.hal.WifiNanIface.NanStatusCode; 44 45 import java.io.FileDescriptor; 46 import java.io.PrintWriter; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.List; 50 51 /** 52 * Manages the state of a single Aware discovery session (publish or subscribe). 53 * Primary state consists of a callback through which session callbacks are 54 * executed as well as state related to currently active discovery sessions: 55 * publish/subscribe ID, and MAC address caching (hiding) from clients. 56 */ 57 public class WifiAwareDiscoverySessionState { 58 private static final String TAG = "WifiAwareDiscSessState"; 59 private boolean mDbg = false; 60 61 private static int sNextPeerIdToBeAllocated = 100; // used to create a unique peer ID 62 63 private final WifiAwareNativeApi mWifiAwareNativeApi; 64 private int mSessionId; 65 private byte mPubSubId; 66 private IWifiAwareDiscoverySessionCallback mCallback; 67 private boolean mIsPublishSession; 68 private boolean mIsRangingEnabled; 69 private final long mCreationTime; 70 private long mUpdateTime; 71 private boolean mInstantModeEnabled; 72 private int mInstantModeBand; 73 private AwarePairingConfig mPairingConfig; 74 private boolean mIsSuspendable; 75 private boolean mIsSuspended; 76 77 static class PeerInfo { PeerInfo(int instanceId, byte[] mac)78 PeerInfo(int instanceId, byte[] mac) { 79 mInstanceId = instanceId; 80 mMac = mac; 81 mPeerHandle = new PeerHandle(instanceId); 82 } 83 84 int mInstanceId; 85 byte[] mMac; 86 PeerHandle mPeerHandle; 87 88 @Override toString()89 public String toString() { 90 StringBuilder sb = new StringBuilder("instanceId ["); 91 sb.append(mInstanceId).append(", mac=").append(HexEncoding.encode(mMac)).append("]"); 92 return sb.toString(); 93 } 94 } 95 96 private final SparseArray<PeerInfo> mPeerInfoByRequestorInstanceId = new SparseArray<>(); 97 WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId, byte pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession, boolean isRangingEnabled, long creationTime, boolean instantModeEnabled, int instantModeBand, boolean isSuspendable, AwarePairingConfig pairingConfig)98 public WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId, 99 byte pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession, 100 boolean isRangingEnabled, long creationTime, boolean instantModeEnabled, 101 int instantModeBand, boolean isSuspendable, 102 AwarePairingConfig pairingConfig) { 103 mWifiAwareNativeApi = wifiAwareNativeApi; 104 mSessionId = sessionId; 105 mPubSubId = pubSubId; 106 mCallback = callback; 107 mIsPublishSession = isPublishSession; 108 mIsRangingEnabled = isRangingEnabled; 109 mCreationTime = creationTime; 110 mUpdateTime = creationTime; 111 mInstantModeEnabled = instantModeEnabled; 112 mInstantModeBand = instantModeBand; 113 mIsSuspendable = isSuspendable; 114 mPairingConfig = pairingConfig; 115 } 116 117 /** 118 * Enable verbose logging. 119 */ enableVerboseLogging(boolean verbose)120 public void enableVerboseLogging(boolean verbose) { 121 mDbg = verbose; 122 } 123 getSessionId()124 public int getSessionId() { 125 return mSessionId; 126 } 127 getPubSubId()128 public int getPubSubId() { 129 return mPubSubId; 130 } 131 isPublishSession()132 public boolean isPublishSession() { 133 return mIsPublishSession; 134 } 135 isRangingEnabled()136 public boolean isRangingEnabled() { 137 return mIsRangingEnabled; 138 } 139 setRangingEnabled(boolean enabled)140 public void setRangingEnabled(boolean enabled) { 141 mIsRangingEnabled = enabled; 142 } 143 setInstantModeEnabled(boolean enabled)144 public void setInstantModeEnabled(boolean enabled) { 145 mInstantModeEnabled = enabled; 146 } 147 setInstantModeBand(int band)148 public void setInstantModeBand(int band) { 149 mInstantModeBand = band; 150 } 151 isSuspendable()152 public boolean isSuspendable() { 153 return mIsSuspendable; 154 } 155 isSessionSuspended()156 public boolean isSessionSuspended() { 157 return mIsSuspended; 158 } 159 160 /** 161 * Check if proposed method can be fulfilled by the configure. 162 */ acceptsBootstrappingMethod(int method)163 public boolean acceptsBootstrappingMethod(int method) { 164 if (mPairingConfig == null) { 165 return false; 166 } 167 return (mPairingConfig.getBootstrappingMethods() & method) != 0; 168 } 169 170 /** 171 * Check the instant communication mode of the client. 172 * @param timeout Specify a interval when instant mode config timeout 173 * @return current instant mode one of the {@code INSTANT_MODE_*} 174 */ getInstantMode(long timeout)175 public int getInstantMode(long timeout) { 176 if (SystemClock.elapsedRealtime() - mUpdateTime > timeout || !mInstantModeEnabled) { 177 return INSTANT_MODE_DISABLED; 178 } 179 if (mInstantModeBand == WifiScanner.WIFI_BAND_5_GHZ) { 180 return INSTANT_MODE_5GHZ; 181 } 182 return INSTANT_MODE_24GHZ; 183 } 184 getCreationTime()185 public long getCreationTime() { 186 return mCreationTime; 187 } 188 getCallback()189 public IWifiAwareDiscoverySessionCallback getCallback() { 190 return mCallback; 191 } 192 193 /** 194 * Return the peer information of the specified peer ID - or a null if no such peer ID is 195 * registered. 196 */ getPeerInfo(int peerId)197 public PeerInfo getPeerInfo(int peerId) { 198 return mPeerInfoByRequestorInstanceId.get(peerId); 199 } 200 201 /** 202 * Destroy the current discovery session - stops publishing or subscribing 203 * if currently active. 204 */ terminate()205 public void terminate() { 206 try { 207 mCallback.onSessionTerminated(NanStatusCode.SUCCESS); 208 } catch (RemoteException e) { 209 Log.w(TAG, 210 "onSessionTerminatedLocal onSessionTerminated(): RemoteException (FYI): " + e); 211 } 212 mCallback = null; 213 214 if (mIsPublishSession) { 215 mWifiAwareNativeApi.stopPublish((short) 0, mPubSubId); 216 } else { 217 mWifiAwareNativeApi.stopSubscribe((short) 0, mPubSubId); 218 } 219 } 220 221 /** 222 * Indicates whether the publish/subscribe ID (a HAL ID) corresponds to this 223 * session. 224 * 225 * @param pubSubId The publish/subscribe HAL ID to be tested. 226 * @return true if corresponds to this session, false otherwise. 227 */ isPubSubIdSession(int pubSubId)228 public boolean isPubSubIdSession(int pubSubId) { 229 return mPubSubId == pubSubId; 230 } 231 232 /** 233 * Modify a publish discovery session. 234 * @param transactionId Transaction ID for the transaction - used in the 235 * async callback to match with the original request. 236 * @param config Configuration of the publish session. 237 * @param nik 238 */ updatePublish(short transactionId, PublishConfig config, byte[] nik)239 public boolean updatePublish(short transactionId, PublishConfig config, byte[] nik) { 240 if (!mIsPublishSession) { 241 Log.e(TAG, "A SUBSCRIBE session is being used to publish"); 242 try { 243 mCallback.onSessionConfigFail(NanStatusCode.INTERNAL_FAILURE); 244 } catch (RemoteException e) { 245 Log.e(TAG, "updatePublish: RemoteException=" + e); 246 } 247 return false; 248 } 249 250 mUpdateTime = SystemClock.elapsedRealtime(); 251 boolean success = mWifiAwareNativeApi.publish(transactionId, mPubSubId, config, nik); 252 if (!success) { 253 try { 254 mCallback.onSessionConfigFail(NanStatusCode.INTERNAL_FAILURE); 255 } catch (RemoteException e) { 256 Log.w(TAG, "updatePublish onSessionConfigFail(): RemoteException (FYI): " + e); 257 } 258 } else { 259 mPairingConfig = config.getPairingConfig(); 260 } 261 262 return success; 263 } 264 265 /** 266 * Modify a subscribe discovery session. 267 * @param transactionId Transaction ID for the transaction - used in the 268 * async callback to match with the original request. 269 * @param config Configuration of the subscribe session. 270 * @param nik 271 */ updateSubscribe(short transactionId, SubscribeConfig config, byte[] nik)272 public boolean updateSubscribe(short transactionId, SubscribeConfig config, byte[] nik) { 273 if (mIsPublishSession) { 274 Log.e(TAG, "A PUBLISH session is being used to subscribe"); 275 try { 276 mCallback.onSessionConfigFail(NanStatusCode.INTERNAL_FAILURE); 277 } catch (RemoteException e) { 278 Log.e(TAG, "updateSubscribe: RemoteException=" + e); 279 } 280 return false; 281 } 282 283 mUpdateTime = SystemClock.elapsedRealtime(); 284 boolean success = mWifiAwareNativeApi.subscribe(transactionId, mPubSubId, config, nik); 285 if (!success) { 286 try { 287 mCallback.onSessionConfigFail(NanStatusCode.INTERNAL_FAILURE); 288 } catch (RemoteException e) { 289 Log.w(TAG, "updateSubscribe onSessionConfigFail(): RemoteException (FYI): " + e); 290 } 291 } else { 292 mPairingConfig = config.getPairingConfig(); 293 } 294 295 return success; 296 } 297 298 /** 299 * Send a message to a peer which is part of a discovery session. 300 * 301 * @param transactionId Transaction ID for the transaction - used in the 302 * async callback to match with the original request. 303 * @param peerId ID of the peer. Obtained through previous communication (a 304 * match indication). 305 * @param message Message byte array to send to the peer. 306 * @param messageId A message ID provided by caller to be used in any 307 * callbacks related to the message (success/failure). 308 */ sendMessage(short transactionId, int peerId, byte[] message, int messageId)309 public boolean sendMessage(short transactionId, int peerId, byte[] message, int messageId) { 310 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 311 if (peerInfo == null) { 312 Log.e(TAG, "sendMessage: attempting to send a message to an address which didn't " 313 + "match/contact us"); 314 try { 315 mCallback.onMessageSendFail(messageId, NanStatusCode.INTERNAL_FAILURE); 316 } catch (RemoteException e) { 317 Log.e(TAG, "sendMessage: RemoteException=" + e); 318 } 319 return false; 320 } 321 322 boolean success = mWifiAwareNativeApi.sendMessage(transactionId, mPubSubId, 323 peerInfo.mInstanceId, peerInfo.mMac, message, messageId); 324 if (!success) { 325 try { 326 mCallback.onMessageSendFail(messageId, NanStatusCode.INTERNAL_FAILURE); 327 } catch (RemoteException e) { 328 Log.e(TAG, "sendMessage: RemoteException=" + e); 329 } 330 return false; 331 } 332 333 return success; 334 } 335 336 /** 337 * Request to suspend the current session. 338 * 339 * @param transactionId Transaction ID for the transaction - used in the async callback to match 340 * with the original request. 341 */ suspend(short transactionId)342 public boolean suspend(short transactionId) { 343 if (!mWifiAwareNativeApi.suspendRequest(transactionId, mPubSubId)) { 344 onSuspendFail(WIFI_AWARE_SUSPEND_INTERNAL_ERROR); 345 return false; 346 } 347 return true; 348 } 349 350 /** 351 * Notifies that session suspension has succeeded and updates the session state. 352 */ onSuspendSuccess()353 public void onSuspendSuccess() { 354 mIsSuspended = true; 355 try { 356 mCallback.onSessionSuspendSucceeded(); 357 } catch (RemoteException e) { 358 Log.e(TAG, "onSuspendSuccess: RemoteException=" + e); 359 } 360 } 361 362 /** 363 * Notify the session callback that suspension failed. 364 * @param reason an {@link WifiAwareManager.SessionSuspensionFailedReasonCode} indicating why 365 * the session failed to be suspended. 366 */ onSuspendFail(@ifiAwareManager.SessionSuspensionFailedReasonCode int reason)367 public void onSuspendFail(@WifiAwareManager.SessionSuspensionFailedReasonCode int reason) { 368 try { 369 mCallback.onSessionSuspendFail(reason); 370 } catch (RemoteException e) { 371 Log.e(TAG, "onSuspendFail: RemoteException=" + e); 372 } 373 } 374 375 /** 376 * Request to resume the current (suspended) session. 377 * 378 * @param transactionId Transaction ID for the transaction - used in the async callback to match 379 * with the original request. 380 */ resume(short transactionId)381 public boolean resume(short transactionId) { 382 if (!mWifiAwareNativeApi.resumeRequest(transactionId, mPubSubId)) { 383 onResumeFail(WIFI_AWARE_SUSPEND_INTERNAL_ERROR); 384 return false; 385 } 386 return true; 387 } 388 389 /** 390 * Notifies that has been resumed successfully and updates the session state. 391 */ onResumeSuccess()392 public void onResumeSuccess() { 393 mIsSuspended = false; 394 try { 395 mCallback.onSessionResumeSucceeded(); 396 } catch (RemoteException e) { 397 Log.e(TAG, "onResumeSuccess: RemoteException=" + e); 398 } 399 } 400 401 /** 402 * Notify the session callback that the resumption of the session failed. 403 * @param reason an {@link WifiAwareManager.SessionResumptionFailedReasonCode} indicating why 404 * the session failed to be resumed. 405 */ onResumeFail(@ifiAwareManager.SessionResumptionFailedReasonCode int reason)406 public void onResumeFail(@WifiAwareManager.SessionResumptionFailedReasonCode int reason) { 407 try { 408 mCallback.onSessionResumeFail(reason); 409 } catch (RemoteException e) { 410 Log.e(TAG, "onResumeFail: RemoteException=" + e); 411 } 412 } 413 414 /** 415 * Initiate a NAN pairing request for this publish/subscribe session 416 * @param transactionId Transaction ID for the transaction - used in the 417 * async callback to match with the original request. 418 * @param peerId ID of the peer. Obtained through previous communication (a 419 * match indication). 420 * @param password credential for the pairing setup 421 * @param requestType Setup or verification 422 * @param nik NAN identity key 423 * @param pmk credential for the pairing verification 424 * @param akm Key exchange method is used for pairing 425 * @return True if the request send succeed. 426 */ initiatePairing(short transactionId, int peerId, String password, int requestType, byte[] nik, byte[] pmk, int akm, int cipherSuite)427 public boolean initiatePairing(short transactionId, 428 int peerId, String password, int requestType, byte[] nik, byte[] pmk, int akm, 429 int cipherSuite) { 430 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 431 if (peerInfo == null) { 432 Log.e(TAG, "initiatePairing: attempting to send pairing request to an address which" 433 + "didn't match/contact us"); 434 if (requestType == NAN_PAIRING_REQUEST_TYPE_VERIFICATION) { 435 return false; 436 } 437 try { 438 mCallback.onPairingSetupConfirmed(peerId, false, null); 439 } catch (RemoteException e) { 440 Log.e(TAG, "initiatePairing: RemoteException=" + e); 441 } 442 return false; 443 } 444 445 boolean success = mWifiAwareNativeApi.initiatePairing(transactionId, 446 peerInfo.mInstanceId, peerInfo.mMac, nik, 447 mPairingConfig != null && mPairingConfig.isPairingCacheEnabled(), 448 requestType, pmk, password, akm, cipherSuite); 449 if (!success) { 450 if (requestType == NAN_PAIRING_REQUEST_TYPE_VERIFICATION) { 451 return false; 452 } 453 try { 454 mCallback.onPairingSetupConfirmed(peerId, false, null); 455 } catch (RemoteException e) { 456 Log.e(TAG, "initiatePairing: RemoteException=" + e); 457 } 458 return false; 459 } 460 461 return true; 462 } 463 464 /** 465 * Response to a NAN pairing request for this from this session 466 * @param transactionId Transaction ID for the transaction - used in the 467 * async callback to match with the original request. 468 * @param peerId ID of the peer. Obtained through previous communication (a 469 * match indication). 470 * @param pairingId The id of the current pairing session 471 * @param accept True if accpect, false otherwise 472 * @param password credential for the pairing setup 473 * @param requestType Setup or verification 474 * @param nik NAN identity key 475 * @param pmk credential for the pairing verification 476 * @param akm Key exchange method is used for pairing 477 * @return True if the request send succeed. 478 */ respondToPairingRequest(short transactionId, int peerId, int pairingId, boolean accept, byte[] nik, int requestType, byte[] pmk, String password, int akm, int cipherSuite)479 public boolean respondToPairingRequest(short transactionId, int peerId, int pairingId, 480 boolean accept, byte[] nik, int requestType, byte[] pmk, String password, int akm, 481 int cipherSuite) { 482 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 483 if (peerInfo == null) { 484 Log.e(TAG, "respondToPairingRequest: attempting to response to message to an " 485 + "address which didn't match/contact us"); 486 if (requestType == NAN_PAIRING_REQUEST_TYPE_VERIFICATION) { 487 return false; 488 } 489 try { 490 mCallback.onPairingSetupConfirmed(peerId, false, null); 491 } catch (RemoteException e) { 492 Log.e(TAG, "respondToPairingRequest: RemoteException=" + e); 493 } 494 return false; 495 } 496 497 boolean success = mWifiAwareNativeApi.respondToPairingRequest(transactionId, pairingId, 498 accept, nik, mPairingConfig != null && mPairingConfig.isPairingCacheEnabled(), 499 requestType, pmk, password, akm, cipherSuite); 500 if (!success) { 501 if (requestType == NAN_PAIRING_REQUEST_TYPE_VERIFICATION) { 502 return false; 503 } 504 try { 505 mCallback.onPairingSetupConfirmed(peerId, false, null); 506 } catch (RemoteException e) { 507 Log.e(TAG, "respondToPairingRequest: RemoteException=" + e); 508 } 509 return false; 510 } 511 512 return true; 513 } 514 515 /** 516 * Initiate an Aware bootstrapping request 517 * 518 * @param transactionId Transaction ID for the transaction - used in the 519 * async callback to match with the original request. 520 * @param peerId ID of the peer. Obtained through previous communication (a 521 * match indication). 522 * @param method proposed bootstrapping method 523 * @param isComeBack If the request is for a previous comeback response 524 * @return True if the request send succeed. 525 */ initiateBootstrapping(short transactionId, int peerId, int method, byte[] cookie, boolean isComeBack)526 public boolean initiateBootstrapping(short transactionId, 527 int peerId, int method, byte[] cookie, boolean isComeBack) { 528 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 529 if (peerInfo == null) { 530 Log.e(TAG, "initiateBootstrapping: attempting to send pairing request to an address" 531 + " which didn't match/contact us"); 532 try { 533 mCallback.onBootstrappingVerificationConfirmed(peerId, false, method); 534 } catch (RemoteException e) { 535 Log.e(TAG, "initiateBootstrapping: RemoteException=" + e); 536 } 537 return false; 538 } 539 540 boolean success = mWifiAwareNativeApi.initiateBootstrapping(transactionId, 541 peerInfo.mInstanceId, peerInfo.mMac, method, cookie, mPubSubId, isComeBack); 542 if (!success) { 543 try { 544 mCallback.onBootstrappingVerificationConfirmed(peerId, false, method); 545 } catch (RemoteException e) { 546 Log.e(TAG, "initiateBootstrapping: RemoteException=" + e); 547 } 548 return false; 549 } 550 551 return true; 552 } 553 554 /** 555 * Respond to a bootstrapping request 556 * @param transactionId Transaction ID for the transaction - used in the 557 * async callback to match with the original request. 558 * @param peerId ID of the peer. Obtained through previous communication (a 559 * match indication). 560 * @param bootstrappingId The id of current bootstrapping session 561 * @param accept True if the method proposed by peer is accepted, false otherwise 562 * @param method the accepted method 563 * @return True if the send success 564 */ respondToBootstrapping(short transactionId, int peerId, int bootstrappingId, boolean accept, int method)565 public boolean respondToBootstrapping(short transactionId, 566 int peerId, int bootstrappingId, boolean accept, int method) { 567 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 568 if (peerInfo == null) { 569 Log.e(TAG, "initiateBootstrapping: attempting to send pairing request to" 570 + " an address which didn't match/contact us"); 571 return false; 572 } 573 574 boolean success = mWifiAwareNativeApi.respondToBootstrappingRequest(transactionId, 575 bootstrappingId, accept, mPubSubId); 576 return success; 577 } 578 579 /** 580 * Callback from HAL when a discovery occurs - i.e. when a match to an 581 * active subscription request or to a solicited publish request occurs. 582 * Propagates to client if registered. 583 * @param requestorInstanceId The ID used to identify the peer in this 584 * matched session. 585 * @param peerMac The MAC address of the peer. Never propagated to client 586 * due to privacy concerns. 587 * @param serviceSpecificInfo Information from the discovery advertisement 588 * (usually not used in the match decisions). 589 * @param matchFilter The filter from the discovery advertisement (which was 590 * used in the match decision). 591 * @param rangingIndication Bit mask indicating the type of ranging event triggered. 592 * @param rangeMm The range to the peer in mm (valid if rangingIndication specifies ingress 593 */ onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm, int peerCipherSuite, byte[] scid, String pairingAlias, AwarePairingConfig pairingConfig, @NonNull List<OuiKeyedData> vendorDataList)594 public int onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, 595 byte[] matchFilter, int rangingIndication, int rangeMm, int peerCipherSuite, 596 byte[] scid, String pairingAlias, 597 AwarePairingConfig pairingConfig, @NonNull List<OuiKeyedData> vendorDataList) { 598 int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); 599 OuiKeyedData[] vendorDataArray = null; 600 if (!vendorDataList.isEmpty()) { 601 vendorDataArray = new OuiKeyedData[vendorDataList.size()]; 602 vendorDataList.toArray(vendorDataArray); 603 } 604 605 try { 606 if (rangingIndication == 0) { 607 mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter, peerCipherSuite, scid, 608 pairingAlias, pairingConfig, vendorDataArray); 609 } else { 610 mCallback.onMatchWithDistance(peerId, serviceSpecificInfo, matchFilter, rangeMm, 611 peerCipherSuite, scid, pairingAlias, pairingConfig, vendorDataArray); 612 } 613 } catch (RemoteException e) { 614 Log.w(TAG, "onMatch: RemoteException (FYI): " + e); 615 } 616 return peerId; 617 } 618 619 /** 620 * Callback from HAL when a discovered peer is lost - i.e. when a discovered peer with a matched 621 * session is no longer visible. 622 * 623 * @param requestorInstanceId The ID used to identify the peer in this matched session. 624 */ onMatchExpired(int requestorInstanceId)625 public void onMatchExpired(int requestorInstanceId) { 626 int peerId = 0; 627 for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) { 628 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i); 629 if (peerInfo.mInstanceId == requestorInstanceId) { 630 peerId = mPeerInfoByRequestorInstanceId.keyAt(i); 631 mPeerInfoByRequestorInstanceId.delete(peerId); 632 break; 633 } 634 } 635 if (peerId == 0) { 636 return; 637 } 638 639 try { 640 mCallback.onMatchExpired(peerId); 641 } catch (RemoteException e) { 642 Log.w(TAG, "onMatch: RemoteException (FYI): " + e); 643 } 644 } 645 646 /** 647 * Callback from HAL when a message is received from a peer in a discovery 648 * session. Propagated to client if registered. 649 * 650 * @param requestorInstanceId An ID used to identify the peer. 651 * @param peerMac The MAC address of the peer sending the message. This 652 * information is never propagated to the client due to privacy 653 * concerns. 654 * @param message The received message. 655 */ onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message)656 public void onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message) { 657 int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); 658 659 try { 660 mCallback.onMessageReceived(peerId, message); 661 } catch (RemoteException e) { 662 Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e); 663 } 664 } 665 666 /** 667 * Event that receive the pairing request from the peer 668 */ onPairingRequestReceived(int requestorInstanceId, byte[] peerMac, int pairingId)669 public void onPairingRequestReceived(int requestorInstanceId, byte[] peerMac, 670 int pairingId) { 671 int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); 672 try { 673 mCallback.onPairingSetupRequestReceived(peerId, pairingId); 674 } catch (RemoteException e) { 675 Log.w(TAG, "onPairingRequestReceived: RemoteException (FYI): " + e); 676 } 677 } 678 679 /** 680 * Event that receive the pairing request finished 681 */ onPairingConfirmReceived(int peerId, boolean accept, String alias, int requestType)682 public void onPairingConfirmReceived(int peerId, boolean accept, String alias, 683 int requestType) { 684 try { 685 if (requestType == NAN_PAIRING_REQUEST_TYPE_SETUP) { 686 mCallback.onPairingSetupConfirmed(peerId, accept, alias); 687 } else { 688 mCallback.onPairingVerificationConfirmed(peerId, accept, alias); 689 } 690 } catch (RemoteException e) { 691 Log.w(TAG, "onPairingConfirmReceived: RemoteException (FYI): " + e); 692 } 693 } 694 695 /** 696 * Callback from HAL when ranging results are available 697 */ onRangingResultsReceived(List<RangingResult> rangingResults)698 public void onRangingResultsReceived(List<RangingResult> rangingResults) { 699 List<RangingResult> validResults = new ArrayList<>(); 700 try { 701 for (RangingResult rangingResult : rangingResults) { 702 PeerHandle peerHandle = 703 getPeerHandleFromPeerMac(rangingResult.getMacAddress().toByteArray()); 704 if (peerHandle == null) { 705 Log.e(TAG, "Could not find Peer Handle for the ranging result"); 706 continue; 707 } 708 RangingResult result = new RangingResult.Builder( 709 rangingResult).setPeerHandle(peerHandle).build(); 710 validResults.add(result); 711 } 712 mCallback.onRangingResultsReceived(validResults); 713 } catch (RemoteException e) { 714 Log.w(TAG, "onRangingResultsReceived: RemoteException (FYI): " + e); 715 } 716 } 717 718 /** 719 * Event that receive the bootstrapping request finished 720 */ onBootStrappingConfirmReceived(int peerId, boolean accept, int method)721 public void onBootStrappingConfirmReceived(int peerId, boolean accept, int method) { 722 try { 723 mCallback.onBootstrappingVerificationConfirmed(peerId, accept, method); 724 } catch (RemoteException e) { 725 Log.w(TAG, "onBootStrappingConfirmReceived: RemoteException (FYI): " + e); 726 } 727 } 728 729 730 /** 731 * Get the ID of the peer assign by the framework 732 */ getPeerIdOrAddIfNew(int requestorInstanceId, byte[] peerMac)733 public int getPeerIdOrAddIfNew(int requestorInstanceId, byte[] peerMac) { 734 for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) { 735 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i); 736 if (peerInfo.mInstanceId == requestorInstanceId && Arrays.equals(peerMac, 737 peerInfo.mMac)) { 738 return mPeerInfoByRequestorInstanceId.keyAt(i); 739 } 740 } 741 742 int newPeerId = sNextPeerIdToBeAllocated++; 743 PeerInfo newPeerInfo = new PeerInfo(requestorInstanceId, peerMac); 744 mPeerInfoByRequestorInstanceId.put(newPeerId, newPeerInfo); 745 Log.d(TAG, "New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo); 746 747 return newPeerId; 748 } 749 750 /** 751 * Get the peerHandle assigned by the framework from the peer mac. 752 */ getPeerHandleFromPeerMac(byte[] peerMac)753 public PeerHandle getPeerHandleFromPeerMac(byte[] peerMac) { 754 for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) { 755 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i); 756 if (Arrays.equals(peerMac, peerInfo.mMac)) { 757 return peerInfo.mPeerHandle; 758 } 759 } 760 return null; 761 } 762 763 /** 764 * Dump the internal state of the class. 765 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)766 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 767 pw.println("AwareSessionState:"); 768 pw.println(" mSessionId: " + mSessionId); 769 pw.println(" mIsPublishSession: " + mIsPublishSession); 770 pw.println(" mPubSubId: " + mPubSubId); 771 pw.println(" mPeerInfoByRequestorInstanceId: [" + mPeerInfoByRequestorInstanceId + "]"); 772 } 773 } 774