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