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