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