• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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