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