1 /*
2  * Copyright (C) 2017 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 android.hardware.wifi.V1_0.NanCapabilities;
20 import android.hardware.wifi.V1_0.NanClusterEventInd;
21 import android.hardware.wifi.V1_0.NanClusterEventType;
22 import android.hardware.wifi.V1_0.NanDataPathConfirmInd;
23 import android.hardware.wifi.V1_0.NanDataPathRequestInd;
24 import android.hardware.wifi.V1_0.NanFollowupReceivedInd;
25 import android.hardware.wifi.V1_0.NanMatchInd;
26 import android.hardware.wifi.V1_0.NanStatusType;
27 import android.hardware.wifi.V1_0.WifiNanStatus;
28 import android.hardware.wifi.V1_2.IWifiNanIfaceEventCallback;
29 import android.hardware.wifi.V1_2.NanDataPathScheduleUpdateInd;
30 import android.os.ShellCommand;
31 import android.util.Log;
32 import android.util.SparseIntArray;
33 
34 import libcore.util.HexEncoding;
35 
36 import org.json.JSONException;
37 import org.json.JSONObject;
38 
39 import java.io.FileDescriptor;
40 import java.io.PrintWriter;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 
44 /**
45  * Manages the callbacks from Wi-Fi Aware HIDL (HAL).
46  */
47 public class WifiAwareNativeCallback extends IWifiNanIfaceEventCallback.Stub implements
48         WifiAwareShellCommand.DelegatedShellCommand {
49     private static final String TAG = "WifiAwareNativeCallback";
50     private static final boolean VDBG = false;
51     /* package */ boolean mDbg = false;
52 
53     /* package */ boolean mIsHal12OrLater = false;
54 
55     private final WifiAwareStateManager mWifiAwareStateManager;
56 
WifiAwareNativeCallback(WifiAwareStateManager wifiAwareStateManager)57     public WifiAwareNativeCallback(WifiAwareStateManager wifiAwareStateManager) {
58         mWifiAwareStateManager = wifiAwareStateManager;
59     }
60 
61     /*
62      * Counts of callbacks from HAL. Retrievable through shell command.
63      */
64     private static final int CB_EV_CLUSTER = 0;
65     private static final int CB_EV_DISABLED = 1;
66     private static final int CB_EV_PUBLISH_TERMINATED = 2;
67     private static final int CB_EV_SUBSCRIBE_TERMINATED = 3;
68     private static final int CB_EV_MATCH = 4;
69     private static final int CB_EV_MATCH_EXPIRED = 5;
70     private static final int CB_EV_FOLLOWUP_RECEIVED = 6;
71     private static final int CB_EV_TRANSMIT_FOLLOWUP = 7;
72     private static final int CB_EV_DATA_PATH_REQUEST = 8;
73     private static final int CB_EV_DATA_PATH_CONFIRM = 9;
74     private static final int CB_EV_DATA_PATH_TERMINATED = 10;
75     private static final int CB_EV_DATA_PATH_SCHED_UPDATE = 11;
76 
77     private SparseIntArray mCallbackCounter = new SparseIntArray();
78 
incrementCbCount(int callbackId)79     private void incrementCbCount(int callbackId) {
80         mCallbackCounter.put(callbackId, mCallbackCounter.get(callbackId) + 1);
81     }
82 
83     /**
84      * Interpreter of adb shell command 'adb shell wifiaware native_cb ...'.
85      *
86      * @return -1 if parameter not recognized or invalid value, 0 otherwise.
87      */
88     @Override
onCommand(ShellCommand parentShell)89     public int onCommand(ShellCommand parentShell) {
90         final PrintWriter pwe = parentShell.getErrPrintWriter();
91         final PrintWriter pwo = parentShell.getOutPrintWriter();
92 
93         String subCmd = parentShell.getNextArgRequired();
94         if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'");
95         switch (subCmd) {
96             case "get_cb_count": {
97                 String option = parentShell.getNextOption();
98                 if (VDBG) Log.v(TAG, "option='" + option + "'");
99                 boolean reset = false;
100                 if (option != null) {
101                     if ("--reset".equals(option)) {
102                         reset = true;
103                     } else {
104                         pwe.println("Unknown option to 'get_cb_count'");
105                         return -1;
106                     }
107                 }
108 
109                 JSONObject j = new JSONObject();
110                 try {
111                     for (int i = 0; i < mCallbackCounter.size(); ++i) {
112                         j.put(Integer.toString(mCallbackCounter.keyAt(i)),
113                                 mCallbackCounter.valueAt(i));
114                     }
115                 } catch (JSONException e) {
116                     Log.e(TAG, "onCommand: get_cb_count e=" + e);
117                 }
118                 pwo.println(j.toString());
119                 if (reset) {
120                     mCallbackCounter.clear();
121                 }
122                 return 0;
123             }
124             default:
125                 pwe.println("Unknown 'wifiaware native_cb <cmd>'");
126         }
127 
128         return -1;
129     }
130 
131     @Override
onReset()132     public void onReset() {
133         // NOP (onReset is intended for configuration reset - not data reset)
134     }
135 
136     @Override
onHelp(String command, ShellCommand parentShell)137     public void onHelp(String command, ShellCommand parentShell) {
138         final PrintWriter pw = parentShell.getOutPrintWriter();
139 
140         pw.println("  " + command);
141         pw.println("    get_cb_count [--reset]: gets the number of callbacks (and optionally reset "
142                 + "count)");
143     }
144 
145     @Override
notifyCapabilitiesResponse(short id, WifiNanStatus status, NanCapabilities capabilities)146     public void notifyCapabilitiesResponse(short id, WifiNanStatus status,
147             NanCapabilities capabilities) {
148         if (mDbg) {
149             Log.v(TAG, "notifyCapabilitiesResponse: id=" + id + ", status=" + statusString(status)
150                     + ", capabilities=" + capabilities);
151         }
152 
153         if (status.status == NanStatusType.SUCCESS) {
154             Capabilities frameworkCapabilities = new Capabilities();
155             frameworkCapabilities.maxConcurrentAwareClusters = capabilities.maxConcurrentClusters;
156             frameworkCapabilities.maxPublishes = capabilities.maxPublishes;
157             frameworkCapabilities.maxSubscribes = capabilities.maxSubscribes;
158             frameworkCapabilities.maxServiceNameLen = capabilities.maxServiceNameLen;
159             frameworkCapabilities.maxMatchFilterLen = capabilities.maxMatchFilterLen;
160             frameworkCapabilities.maxTotalMatchFilterLen = capabilities.maxTotalMatchFilterLen;
161             frameworkCapabilities.maxServiceSpecificInfoLen =
162                     capabilities.maxServiceSpecificInfoLen;
163             frameworkCapabilities.maxExtendedServiceSpecificInfoLen =
164                     capabilities.maxExtendedServiceSpecificInfoLen;
165             frameworkCapabilities.maxNdiInterfaces = capabilities.maxNdiInterfaces;
166             frameworkCapabilities.maxNdpSessions = capabilities.maxNdpSessions;
167             frameworkCapabilities.maxAppInfoLen = capabilities.maxAppInfoLen;
168             frameworkCapabilities.maxQueuedTransmitMessages =
169                     capabilities.maxQueuedTransmitFollowupMsgs;
170             frameworkCapabilities.maxSubscribeInterfaceAddresses =
171                     capabilities.maxSubscribeInterfaceAddresses;
172             frameworkCapabilities.supportedCipherSuites = capabilities.supportedCipherSuites;
173 
174             mWifiAwareStateManager.onCapabilitiesUpdateResponse(id, frameworkCapabilities);
175         } else {
176             Log.e(TAG, "notifyCapabilitiesResponse: error code=" + status.status + " ("
177                     + status.description + ")");
178         }
179     }
180 
181     @Override
notifyEnableResponse(short id, WifiNanStatus status)182     public void notifyEnableResponse(short id, WifiNanStatus status) {
183         if (mDbg) Log.v(TAG, "notifyEnableResponse: id=" + id + ", status=" + statusString(status));
184 
185         if (status.status == NanStatusType.ALREADY_ENABLED) {
186             Log.wtf(TAG, "notifyEnableResponse: id=" + id + ", already enabled!?");
187         }
188 
189         if (status.status == NanStatusType.SUCCESS
190                 || status.status == NanStatusType.ALREADY_ENABLED) {
191             mWifiAwareStateManager.onConfigSuccessResponse(id);
192         } else {
193             mWifiAwareStateManager.onConfigFailedResponse(id, status.status);
194         }
195     }
196 
197     @Override
notifyConfigResponse(short id, WifiNanStatus status)198     public void notifyConfigResponse(short id, WifiNanStatus status) {
199         if (mDbg) Log.v(TAG, "notifyConfigResponse: id=" + id + ", status=" + statusString(status));
200 
201         if (status.status == NanStatusType.SUCCESS) {
202             mWifiAwareStateManager.onConfigSuccessResponse(id);
203         } else {
204             mWifiAwareStateManager.onConfigFailedResponse(id, status.status);
205         }
206     }
207 
208     @Override
notifyDisableResponse(short id, WifiNanStatus status)209     public void notifyDisableResponse(short id, WifiNanStatus status) {
210         if (mDbg) {
211             Log.v(TAG, "notifyDisableResponse: id=" + id + ", status=" + statusString(status));
212         }
213 
214         if (status.status != NanStatusType.SUCCESS) {
215             Log.e(TAG, "notifyDisableResponse: failure - code=" + status.status + " ("
216                     + status.description + ")");
217         }
218         mWifiAwareStateManager.onDisableResponse(id, status.status);
219     }
220 
221     @Override
notifyStartPublishResponse(short id, WifiNanStatus status, byte publishId)222     public void notifyStartPublishResponse(short id, WifiNanStatus status, byte publishId) {
223         if (mDbg) {
224             Log.v(TAG, "notifyStartPublishResponse: id=" + id + ", status=" + statusString(status)
225                     + ", publishId=" + publishId);
226         }
227 
228         if (status.status == NanStatusType.SUCCESS) {
229             mWifiAwareStateManager.onSessionConfigSuccessResponse(id, true, publishId);
230         } else {
231             mWifiAwareStateManager.onSessionConfigFailResponse(id, true, status.status);
232         }
233     }
234 
235     @Override
notifyStopPublishResponse(short id, WifiNanStatus status)236     public void notifyStopPublishResponse(short id, WifiNanStatus status) {
237         if (mDbg) {
238             Log.v(TAG, "notifyStopPublishResponse: id=" + id + ", status=" + statusString(status));
239         }
240 
241         if (status.status == NanStatusType.SUCCESS) {
242             // NOP
243         } else {
244             Log.e(TAG, "notifyStopPublishResponse: failure - code=" + status.status + " ("
245                     + status.description + ")");
246         }
247     }
248 
249     @Override
notifyStartSubscribeResponse(short id, WifiNanStatus status, byte subscribeId)250     public void notifyStartSubscribeResponse(short id, WifiNanStatus status, byte subscribeId) {
251         if (mDbg) {
252             Log.v(TAG, "notifyStartSubscribeResponse: id=" + id + ", status=" + statusString(status)
253                     + ", subscribeId=" + subscribeId);
254         }
255 
256         if (status.status == NanStatusType.SUCCESS) {
257             mWifiAwareStateManager.onSessionConfigSuccessResponse(id, false, subscribeId);
258         } else {
259             mWifiAwareStateManager.onSessionConfigFailResponse(id, false, status.status);
260         }
261     }
262 
263     @Override
notifyStopSubscribeResponse(short id, WifiNanStatus status)264     public void notifyStopSubscribeResponse(short id, WifiNanStatus status) {
265         if (mDbg) {
266             Log.v(TAG, "notifyStopSubscribeResponse: id=" + id + ", status="
267                     + statusString(status));
268         }
269 
270         if (status.status == NanStatusType.SUCCESS) {
271             // NOP
272         } else {
273             Log.e(TAG, "notifyStopSubscribeResponse: failure - code=" + status.status + " ("
274                     + status.description + ")");
275         }
276     }
277 
278     @Override
notifyTransmitFollowupResponse(short id, WifiNanStatus status)279     public void notifyTransmitFollowupResponse(short id, WifiNanStatus status) {
280         if (mDbg) {
281             Log.v(TAG, "notifyTransmitFollowupResponse: id=" + id + ", status="
282                     + statusString(status));
283         }
284 
285         if (status.status == NanStatusType.SUCCESS) {
286             mWifiAwareStateManager.onMessageSendQueuedSuccessResponse(id);
287         } else {
288             mWifiAwareStateManager.onMessageSendQueuedFailResponse(id, status.status);
289         }
290     }
291 
292     @Override
notifyCreateDataInterfaceResponse(short id, WifiNanStatus status)293     public void notifyCreateDataInterfaceResponse(short id, WifiNanStatus status) {
294         if (mDbg) {
295             Log.v(TAG, "notifyCreateDataInterfaceResponse: id=" + id + ", status="
296                     + statusString(status));
297         }
298 
299         mWifiAwareStateManager.onCreateDataPathInterfaceResponse(id,
300                 status.status == NanStatusType.SUCCESS, status.status);
301     }
302 
303     @Override
notifyDeleteDataInterfaceResponse(short id, WifiNanStatus status)304     public void notifyDeleteDataInterfaceResponse(short id, WifiNanStatus status) {
305         if (mDbg) {
306             Log.v(TAG, "notifyDeleteDataInterfaceResponse: id=" + id + ", status="
307                     + statusString(status));
308         }
309 
310         mWifiAwareStateManager.onDeleteDataPathInterfaceResponse(id,
311                 status.status == NanStatusType.SUCCESS, status.status);
312     }
313 
314     @Override
notifyInitiateDataPathResponse(short id, WifiNanStatus status, int ndpInstanceId)315     public void notifyInitiateDataPathResponse(short id, WifiNanStatus status,
316             int ndpInstanceId) {
317         if (mDbg) {
318             Log.v(TAG, "notifyInitiateDataPathResponse: id=" + id + ", status="
319                     + statusString(status) + ", ndpInstanceId=" + ndpInstanceId);
320         }
321 
322         if (status.status == NanStatusType.SUCCESS) {
323             mWifiAwareStateManager.onInitiateDataPathResponseSuccess(id, ndpInstanceId);
324         } else {
325             mWifiAwareStateManager.onInitiateDataPathResponseFail(id, status.status);
326         }
327     }
328 
329     @Override
notifyRespondToDataPathIndicationResponse(short id, WifiNanStatus status)330     public void notifyRespondToDataPathIndicationResponse(short id, WifiNanStatus status) {
331         if (mDbg) {
332             Log.v(TAG, "notifyRespondToDataPathIndicationResponse: id=" + id
333                     + ", status=" + statusString(status));
334         }
335 
336         mWifiAwareStateManager.onRespondToDataPathSetupRequestResponse(id,
337                 status.status == NanStatusType.SUCCESS, status.status);
338     }
339 
340     @Override
notifyTerminateDataPathResponse(short id, WifiNanStatus status)341     public void notifyTerminateDataPathResponse(short id, WifiNanStatus status) {
342         if (mDbg) {
343             Log.v(TAG, "notifyTerminateDataPathResponse: id=" + id + ", status="
344                     + statusString(status));
345         }
346 
347         mWifiAwareStateManager.onEndDataPathResponse(id, status.status == NanStatusType.SUCCESS,
348                 status.status);
349     }
350 
351     @Override
eventClusterEvent(NanClusterEventInd event)352     public void eventClusterEvent(NanClusterEventInd event) {
353         if (mDbg) {
354             Log.v(TAG, "eventClusterEvent: eventType=" + event.eventType + ", addr="
355                     + String.valueOf(HexEncoding.encode(event.addr)));
356         }
357         incrementCbCount(CB_EV_CLUSTER);
358 
359         if (event.eventType == NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED) {
360             mWifiAwareStateManager.onInterfaceAddressChangeNotification(event.addr);
361         } else if (event.eventType == NanClusterEventType.STARTED_CLUSTER) {
362             mWifiAwareStateManager.onClusterChangeNotification(
363                     WifiAwareClientState.CLUSTER_CHANGE_EVENT_STARTED, event.addr);
364         } else if (event.eventType == NanClusterEventType.JOINED_CLUSTER) {
365             mWifiAwareStateManager.onClusterChangeNotification(
366                     WifiAwareClientState.CLUSTER_CHANGE_EVENT_JOINED, event.addr);
367         } else {
368             Log.e(TAG, "eventClusterEvent: invalid eventType=" + event.eventType);
369         }
370     }
371 
372     @Override
eventDisabled(WifiNanStatus status)373     public void eventDisabled(WifiNanStatus status) {
374         if (mDbg) Log.v(TAG, "eventDisabled: status=" + statusString(status));
375         incrementCbCount(CB_EV_DISABLED);
376 
377         mWifiAwareStateManager.onAwareDownNotification(status.status);
378     }
379 
380     @Override
eventPublishTerminated(byte sessionId, WifiNanStatus status)381     public void eventPublishTerminated(byte sessionId, WifiNanStatus status) {
382         if (mDbg) {
383             Log.v(TAG, "eventPublishTerminated: sessionId=" + sessionId + ", status="
384                     + statusString(status));
385         }
386         incrementCbCount(CB_EV_PUBLISH_TERMINATED);
387 
388         mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status.status, true);
389     }
390 
391     @Override
eventSubscribeTerminated(byte sessionId, WifiNanStatus status)392     public void eventSubscribeTerminated(byte sessionId, WifiNanStatus status) {
393         if (mDbg) {
394             Log.v(TAG, "eventSubscribeTerminated: sessionId=" + sessionId + ", status="
395                     + statusString(status));
396         }
397         incrementCbCount(CB_EV_SUBSCRIBE_TERMINATED);
398 
399         mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status.status, false);
400     }
401 
402     @Override
eventMatch(NanMatchInd event)403     public void eventMatch(NanMatchInd event) {
404         if (mDbg) {
405             Log.v(TAG, "eventMatch: discoverySessionId=" + event.discoverySessionId + ", peerId="
406                     + event.peerId + ", addr=" + String.valueOf(HexEncoding.encode(event.addr))
407                     + ", serviceSpecificInfo=" + Arrays.toString(
408                     convertArrayListToNativeByteArray(event.serviceSpecificInfo)) + ", ssi.size()="
409                     + (event.serviceSpecificInfo == null ? 0 : event.serviceSpecificInfo.size())
410                     + ", matchFilter=" + Arrays.toString(
411                     convertArrayListToNativeByteArray(event.matchFilter)) + ", mf.size()=" + (
412                     event.matchFilter == null ? 0 : event.matchFilter.size())
413                     + ", rangingIndicationType=" + event.rangingIndicationType
414                     + ", rangingMeasurementInCm=" + event.rangingMeasurementInCm);
415         }
416         incrementCbCount(CB_EV_MATCH);
417 
418         // TODO: b/69428593 get rid of conversion once HAL moves from CM to MM
419         mWifiAwareStateManager.onMatchNotification(event.discoverySessionId, event.peerId,
420                 event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo),
421                 convertArrayListToNativeByteArray(event.matchFilter), event.rangingIndicationType,
422                 event.rangingMeasurementInCm * 10);
423     }
424 
425     @Override
eventMatchExpired(byte discoverySessionId, int peerId)426     public void eventMatchExpired(byte discoverySessionId, int peerId) {
427         if (mDbg) {
428             Log.v(TAG, "eventMatchExpired: discoverySessionId=" + discoverySessionId
429                     + ", peerId=" + peerId);
430         }
431         incrementCbCount(CB_EV_MATCH_EXPIRED);
432 
433         // NOP
434     }
435 
436     @Override
eventFollowupReceived(NanFollowupReceivedInd event)437     public void eventFollowupReceived(NanFollowupReceivedInd event) {
438         if (mDbg) {
439             Log.v(TAG, "eventFollowupReceived: discoverySessionId=" + event.discoverySessionId
440                     + ", peerId=" + event.peerId + ", addr=" + String.valueOf(
441                     HexEncoding.encode(event.addr)) + ", serviceSpecificInfo=" + Arrays.toString(
442                     convertArrayListToNativeByteArray(event.serviceSpecificInfo)) + ", ssi.size()="
443                     + (event.serviceSpecificInfo == null ? 0 : event.serviceSpecificInfo.size()));
444         }
445         incrementCbCount(CB_EV_FOLLOWUP_RECEIVED);
446 
447         mWifiAwareStateManager.onMessageReceivedNotification(event.discoverySessionId, event.peerId,
448                 event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo));
449     }
450 
451     @Override
eventTransmitFollowup(short id, WifiNanStatus status)452     public void eventTransmitFollowup(short id, WifiNanStatus status) {
453         if (mDbg) {
454             Log.v(TAG, "eventTransmitFollowup: id=" + id + ", status=" + statusString(status));
455         }
456         incrementCbCount(CB_EV_TRANSMIT_FOLLOWUP);
457 
458         if (status.status == NanStatusType.SUCCESS) {
459             mWifiAwareStateManager.onMessageSendSuccessNotification(id);
460         } else {
461             mWifiAwareStateManager.onMessageSendFailNotification(id, status.status);
462         }
463     }
464 
465     @Override
eventDataPathRequest(NanDataPathRequestInd event)466     public void eventDataPathRequest(NanDataPathRequestInd event) {
467         if (mDbg) {
468             Log.v(TAG, "eventDataPathRequest: discoverySessionId=" + event.discoverySessionId
469                     + ", peerDiscMacAddr=" + String.valueOf(
470                     HexEncoding.encode(event.peerDiscMacAddr)) + ", ndpInstanceId="
471                     + event.ndpInstanceId + ", appInfo.size()=" + event.appInfo.size());
472         }
473         incrementCbCount(CB_EV_DATA_PATH_REQUEST);
474 
475         mWifiAwareStateManager.onDataPathRequestNotification(event.discoverySessionId,
476                 event.peerDiscMacAddr, event.ndpInstanceId,
477                 convertArrayListToNativeByteArray(event.appInfo));
478     }
479 
480     @Override
eventDataPathConfirm(NanDataPathConfirmInd event)481     public void eventDataPathConfirm(NanDataPathConfirmInd event) {
482         if (mDbg) {
483             Log.v(TAG, "onDataPathConfirm: ndpInstanceId=" + event.ndpInstanceId
484                     + ", peerNdiMacAddr=" + String.valueOf(HexEncoding.encode(event.peerNdiMacAddr))
485                     + ", dataPathSetupSuccess=" + event.dataPathSetupSuccess + ", reason="
486                     + event.status.status + ", appInfo.size()=" + event.appInfo.size());
487         }
488         if (mIsHal12OrLater) {
489             Log.wtf(TAG, "eventDataPathConfirm should not be called by a >=1.2 HAL!");
490         }
491         incrementCbCount(CB_EV_DATA_PATH_CONFIRM);
492 
493         mWifiAwareStateManager.onDataPathConfirmNotification(event.ndpInstanceId,
494                 event.peerNdiMacAddr, event.dataPathSetupSuccess, event.status.status,
495                 convertArrayListToNativeByteArray(event.appInfo), null);
496     }
497 
498     @Override
eventDataPathConfirm_1_2(android.hardware.wifi.V1_2.NanDataPathConfirmInd event)499     public void eventDataPathConfirm_1_2(android.hardware.wifi.V1_2.NanDataPathConfirmInd event) {
500         if (mDbg) {
501             Log.v(TAG, "eventDataPathConfirm_1_2: ndpInstanceId=" + event.V1_0.ndpInstanceId
502                     + ", peerNdiMacAddr=" + String.valueOf(
503                     HexEncoding.encode(event.V1_0.peerNdiMacAddr)) + ", dataPathSetupSuccess="
504                     + event.V1_0.dataPathSetupSuccess + ", reason=" + event.V1_0.status.status
505                     + ", appInfo.size()=" + event.V1_0.appInfo.size());
506         }
507         if (!mIsHal12OrLater) {
508             Log.wtf(TAG, "eventDataPathConfirm_1_2 should not be called by a <1.2 HAL!");
509             return;
510         }
511         incrementCbCount(CB_EV_DATA_PATH_CONFIRM);
512 
513         mWifiAwareStateManager.onDataPathConfirmNotification(event.V1_0.ndpInstanceId,
514                 event.V1_0.peerNdiMacAddr, event.V1_0.dataPathSetupSuccess,
515                 event.V1_0.status.status, convertArrayListToNativeByteArray(event.V1_0.appInfo),
516                 event.channelInfo);
517     }
518 
519     @Override
eventDataPathScheduleUpdate(NanDataPathScheduleUpdateInd event)520     public void eventDataPathScheduleUpdate(NanDataPathScheduleUpdateInd event) {
521         if (mDbg) {
522             Log.v(TAG, "eventDataPathScheduleUpdate");
523         }
524         if (!mIsHal12OrLater) {
525             Log.wtf(TAG, "eventDataPathScheduleUpdate should not be called by a <1.2 HAL!");
526             return;
527         }
528         incrementCbCount(CB_EV_DATA_PATH_SCHED_UPDATE);
529 
530         mWifiAwareStateManager.onDataPathScheduleUpdateNotification(event.peerDiscoveryAddress,
531                 event.ndpInstanceIds, event.channelInfo);
532     }
533 
534     @Override
eventDataPathTerminated(int ndpInstanceId)535     public void eventDataPathTerminated(int ndpInstanceId) {
536         if (mDbg) Log.v(TAG, "eventDataPathTerminated: ndpInstanceId=" + ndpInstanceId);
537         incrementCbCount(CB_EV_DATA_PATH_TERMINATED);
538 
539         mWifiAwareStateManager.onDataPathEndNotification(ndpInstanceId);
540     }
541 
542     /**
543      * Dump the internal state of the class.
544      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)545     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
546         pw.println("WifiAwareNativeCallback:");
547         pw.println("  mCallbackCounter: " + mCallbackCounter);
548     }
549 
550 
551     // utilities
552 
553     /**
554      * Converts an ArrayList<Byte> to a byte[].
555      *
556      * @param from The input ArrayList<Byte></Byte> to convert from.
557      *
558      * @return A newly allocated byte[].
559      */
convertArrayListToNativeByteArray(ArrayList<Byte> from)560     private byte[] convertArrayListToNativeByteArray(ArrayList<Byte> from) {
561         if (from == null) {
562             return null;
563         }
564 
565         byte[] to = new byte[from.size()];
566         for (int i = 0; i < from.size(); ++i) {
567             to[i] = from.get(i);
568         }
569         return to;
570     }
571 
statusString(WifiNanStatus status)572     private static String statusString(WifiNanStatus status) {
573         if (status == null) {
574             return "status=null";
575         }
576         StringBuilder sb = new StringBuilder();
577         sb.append(status.status).append(" (").append(status.description).append(")");
578         return sb.toString();
579     }
580 }
581