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.net.wifi.WifiScanner; 28 import android.net.wifi.aware.AwarePairingConfig; 29 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 30 import android.net.wifi.aware.PublishConfig; 31 import android.net.wifi.aware.SubscribeConfig; 32 import android.net.wifi.aware.WifiAwareManager; 33 import android.net.wifi.util.HexEncoding; 34 import android.os.RemoteException; 35 import android.os.SystemClock; 36 import android.util.LocalLog; 37 import android.util.Log; 38 import android.util.SparseArray; 39 40 import com.android.server.wifi.hal.WifiNanIface.NanStatusCode; 41 42 import java.io.FileDescriptor; 43 import java.io.PrintWriter; 44 import java.util.Arrays; 45 46 /** 47 * Manages the state of a single Aware discovery session (publish or subscribe). 48 * Primary state consists of a callback through which session callbacks are 49 * executed as well as state related to currently active discovery sessions: 50 * publish/subscribe ID, and MAC address caching (hiding) from clients. 51 */ 52 public class WifiAwareDiscoverySessionState { 53 private static final String TAG = "WifiAwareDiscSessState"; 54 private boolean mDbg = false; 55 56 private static int sNextPeerIdToBeAllocated = 100; // used to create a unique peer ID 57 58 private final WifiAwareNativeApi mWifiAwareNativeApi; 59 private int mSessionId; 60 private byte mPubSubId; 61 private IWifiAwareDiscoverySessionCallback mCallback; 62 private boolean mIsPublishSession; 63 private boolean mIsRangingEnabled; 64 private final long mCreationTime; 65 private long mUpdateTime; 66 private boolean mInstantModeEnabled; 67 private int mInstantModeBand; 68 private final LocalLog mLocalLog; 69 private AwarePairingConfig mPairingConfig; 70 private boolean mIsSuspendable; 71 private boolean mIsSuspended; 72 73 static class PeerInfo { PeerInfo(int instanceId, byte[] mac)74 PeerInfo(int instanceId, byte[] mac) { 75 mInstanceId = instanceId; 76 mMac = mac; 77 } 78 79 int mInstanceId; 80 byte[] mMac; 81 82 @Override toString()83 public String toString() { 84 StringBuilder sb = new StringBuilder("instanceId ["); 85 sb.append(mInstanceId).append(", mac=").append(HexEncoding.encode(mMac)).append("]"); 86 return sb.toString(); 87 } 88 } 89 90 private final SparseArray<PeerInfo> mPeerInfoByRequestorInstanceId = new SparseArray<>(); 91 WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId, byte pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession, boolean isRangingEnabled, long creationTime, boolean instantModeEnabled, int instantModeBand, boolean isSuspendable, LocalLog localLog, AwarePairingConfig pairingConfig)92 public WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId, 93 byte pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession, 94 boolean isRangingEnabled, long creationTime, boolean instantModeEnabled, 95 int instantModeBand, boolean isSuspendable, LocalLog localLog, 96 AwarePairingConfig pairingConfig) { 97 mWifiAwareNativeApi = wifiAwareNativeApi; 98 mSessionId = sessionId; 99 mPubSubId = pubSubId; 100 mCallback = callback; 101 mIsPublishSession = isPublishSession; 102 mIsRangingEnabled = isRangingEnabled; 103 mCreationTime = creationTime; 104 mUpdateTime = creationTime; 105 mInstantModeEnabled = instantModeEnabled; 106 mInstantModeBand = instantModeBand; 107 mIsSuspendable = isSuspendable; 108 mLocalLog = localLog; 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 * @return True if the request send succeed. 519 */ initiateBootstrapping(short transactionId, int peerId, int method, byte[] cookie)520 public boolean initiateBootstrapping(short transactionId, 521 int peerId, int method, byte[] cookie) { 522 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 523 if (peerInfo == null) { 524 Log.e(TAG, "initiateBootstrapping: attempting to send pairing request to an address" 525 + " which didn't match/contact us"); 526 try { 527 mCallback.onBootstrappingVerificationConfirmed(peerId, false, method); 528 } catch (RemoteException e) { 529 Log.e(TAG, "initiateBootstrapping: RemoteException=" + e); 530 } 531 return false; 532 } 533 534 boolean success = mWifiAwareNativeApi.initiateBootstrapping(transactionId, 535 peerInfo.mInstanceId, peerInfo.mMac, method, cookie); 536 if (!success) { 537 try { 538 mCallback.onBootstrappingVerificationConfirmed(peerId, false, method); 539 } catch (RemoteException e) { 540 Log.e(TAG, "initiateBootstrapping: RemoteException=" + e); 541 } 542 return false; 543 } 544 545 return true; 546 } 547 548 /** 549 * Respond to a bootstrapping request 550 * @param transactionId Transaction ID for the transaction - used in the 551 * async callback to match with the original request. 552 * @param peerId ID of the peer. Obtained through previous communication (a 553 * match indication). 554 * @param bootstrappingId The id of current bootstrapping session 555 * @param accept True if the method proposed by peer is accepted, false otherwise 556 * @param method the accepted method 557 * @return True if the send success 558 */ respondToBootstrapping(short transactionId, int peerId, int bootstrappingId, boolean accept, int method)559 public boolean respondToBootstrapping(short transactionId, 560 int peerId, int bootstrappingId, boolean accept, int method) { 561 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId); 562 if (peerInfo == null) { 563 Log.e(TAG, "initiateBootstrapping: attempting to send pairing request to" 564 + " an address which didn't match/contact us"); 565 return false; 566 } 567 568 boolean success = mWifiAwareNativeApi.respondToBootstrappingRequest(transactionId, 569 bootstrappingId, accept); 570 return success; 571 } 572 573 /** 574 * Callback from HAL when a discovery occurs - i.e. when a match to an 575 * active subscription request or to a solicited publish request occurs. 576 * Propagates to client if registered. 577 * @param requestorInstanceId The ID used to identify the peer in this 578 * matched session. 579 * @param peerMac The MAC address of the peer. Never propagated to client 580 * due to privacy concerns. 581 * @param serviceSpecificInfo Information from the discovery advertisement 582 * (usually not used in the match decisions). 583 * @param matchFilter The filter from the discovery advertisement (which was 584 * used in the match decision). 585 * @param rangingIndication Bit mask indicating the type of ranging event triggered. 586 * @param rangeMm The range to the peer in mm (valid if rangingIndication specifies ingress 587 */ onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm, int peerCipherSuite, byte[] scid, String pairingAlias, AwarePairingConfig pairingConfig)588 public int onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, 589 byte[] matchFilter, int rangingIndication, int rangeMm, int peerCipherSuite, 590 byte[] scid, String pairingAlias, 591 AwarePairingConfig pairingConfig) { 592 int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); 593 594 try { 595 if (rangingIndication == 0) { 596 mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter, peerCipherSuite, scid, 597 pairingAlias, pairingConfig); 598 } else { 599 mCallback.onMatchWithDistance(peerId, serviceSpecificInfo, matchFilter, rangeMm, 600 peerCipherSuite, scid, pairingAlias, pairingConfig); 601 } 602 } catch (RemoteException e) { 603 Log.w(TAG, "onMatch: RemoteException (FYI): " + e); 604 } 605 return peerId; 606 } 607 608 /** 609 * Callback from HAL when a discovered peer is lost - i.e. when a discovered peer with a matched 610 * session is no longer visible. 611 * 612 * @param requestorInstanceId The ID used to identify the peer in this matched session. 613 */ onMatchExpired(int requestorInstanceId)614 public void onMatchExpired(int requestorInstanceId) { 615 int peerId = 0; 616 for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) { 617 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i); 618 if (peerInfo.mInstanceId == requestorInstanceId) { 619 peerId = mPeerInfoByRequestorInstanceId.keyAt(i); 620 mPeerInfoByRequestorInstanceId.delete(peerId); 621 break; 622 } 623 } 624 if (peerId == 0) { 625 return; 626 } 627 628 try { 629 mCallback.onMatchExpired(peerId); 630 } catch (RemoteException e) { 631 Log.w(TAG, "onMatch: RemoteException (FYI): " + e); 632 } 633 } 634 635 /** 636 * Callback from HAL when a message is received from a peer in a discovery 637 * session. Propagated to client if registered. 638 * 639 * @param requestorInstanceId An ID used to identify the peer. 640 * @param peerMac The MAC address of the peer sending the message. This 641 * information is never propagated to the client due to privacy 642 * concerns. 643 * @param message The received message. 644 */ onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message)645 public void onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message) { 646 int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); 647 648 try { 649 mCallback.onMessageReceived(peerId, message); 650 } catch (RemoteException e) { 651 Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e); 652 } 653 } 654 655 /** 656 * Event that receive the pairing request from the peer 657 */ onPairingRequestReceived(int requestorInstanceId, byte[] peerMac, int pairingId)658 public void onPairingRequestReceived(int requestorInstanceId, byte[] peerMac, 659 int pairingId) { 660 int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac); 661 try { 662 mCallback.onPairingSetupRequestReceived(peerId, pairingId); 663 } catch (RemoteException e) { 664 Log.w(TAG, "onPairingRequestReceived: RemoteException (FYI): " + e); 665 } 666 } 667 668 /** 669 * Event that receive the pairing request finished 670 */ onPairingConfirmReceived(int peerId, boolean accept, String alias, int requestType)671 public void onPairingConfirmReceived(int peerId, boolean accept, String alias, 672 int requestType) { 673 try { 674 if (requestType == NAN_PAIRING_REQUEST_TYPE_SETUP) { 675 mCallback.onPairingSetupConfirmed(peerId, accept, alias); 676 } else { 677 mCallback.onPairingVerificationConfirmed(peerId, accept, alias); 678 } 679 } catch (RemoteException e) { 680 Log.w(TAG, "onPairingConfirmReceived: RemoteException (FYI): " + e); 681 } 682 } 683 684 /** 685 * Event that receive the bootstrapping request finished 686 */ onBootStrappingConfirmReceived(int peerId, boolean accept, int method)687 public void onBootStrappingConfirmReceived(int peerId, boolean accept, int method) { 688 try { 689 mCallback.onBootstrappingVerificationConfirmed(peerId, accept, method); 690 } catch (RemoteException e) { 691 Log.w(TAG, "onBootStrappingConfirmReceived: RemoteException (FYI): " + e); 692 } 693 } 694 695 696 /** 697 * Get the ID of the peer assign by the framework 698 */ getPeerIdOrAddIfNew(int requestorInstanceId, byte[] peerMac)699 public int getPeerIdOrAddIfNew(int requestorInstanceId, byte[] peerMac) { 700 for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) { 701 PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i); 702 if (peerInfo.mInstanceId == requestorInstanceId && Arrays.equals(peerMac, 703 peerInfo.mMac)) { 704 return mPeerInfoByRequestorInstanceId.keyAt(i); 705 } 706 } 707 708 int newPeerId = sNextPeerIdToBeAllocated++; 709 PeerInfo newPeerInfo = new PeerInfo(requestorInstanceId, peerMac); 710 mPeerInfoByRequestorInstanceId.put(newPeerId, newPeerInfo); 711 Log.d(TAG, "New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo); 712 mLocalLog.log("New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo); 713 714 return newPeerId; 715 } 716 717 /** 718 * Dump the internal state of the class. 719 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)720 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 721 pw.println("AwareSessionState:"); 722 pw.println(" mSessionId: " + mSessionId); 723 pw.println(" mIsPublishSession: " + mIsPublishSession); 724 pw.println(" mPubSubId: " + mPubSubId); 725 pw.println(" mPeerInfoByRequestorInstanceId: [" + mPeerInfoByRequestorInstanceId + "]"); 726 } 727 } 728