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.annotation.Nullable; 20 import android.net.wifi.OuiKeyedData; 21 import android.net.wifi.aware.AwarePairingConfig; 22 import android.net.wifi.aware.IdentityChangedListener; 23 import android.net.wifi.aware.WifiAwareChannelInfo; 24 import android.net.wifi.rtt.RangingResult; 25 import android.util.Log; 26 import android.util.SparseArray; 27 import android.util.SparseIntArray; 28 29 import com.android.modules.utils.BasicShellCommandHandler; 30 import com.android.server.wifi.hal.WifiNanIface; 31 import com.android.server.wifi.hal.WifiNanIface.NanClusterEventType; 32 import com.android.server.wifi.hal.WifiNanIface.NanStatusCode; 33 34 import org.json.JSONArray; 35 import org.json.JSONException; 36 import org.json.JSONObject; 37 38 import java.io.FileDescriptor; 39 import java.io.PrintWriter; 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * Manages the callbacks from Wi-Fi Aware HAL. 45 */ 46 public class WifiAwareNativeCallback implements WifiNanIface.Callback, 47 WifiAwareShellCommand.DelegatedShellCommand { 48 private static final String TAG = "WifiAwareNativeCallback"; 49 private boolean mVerboseLoggingEnabled = false; 50 51 private final WifiAwareStateManager mWifiAwareStateManager; 52 WifiAwareNativeCallback(WifiAwareStateManager wifiAwareStateManager)53 public WifiAwareNativeCallback(WifiAwareStateManager wifiAwareStateManager) { 54 mWifiAwareStateManager = wifiAwareStateManager; 55 } 56 57 /** 58 * Enable/Disable verbose logging. 59 * 60 */ enableVerboseLogging(boolean verboseEnabled)61 public void enableVerboseLogging(boolean verboseEnabled) { 62 mVerboseLoggingEnabled = verboseEnabled; 63 } 64 65 /* 66 * Counts of callbacks from HAL. Retrievable through shell command. 67 */ 68 private static final int CB_EV_CLUSTER = 0; 69 private static final int CB_EV_DISABLED = 1; 70 private static final int CB_EV_PUBLISH_TERMINATED = 2; 71 private static final int CB_EV_SUBSCRIBE_TERMINATED = 3; 72 private static final int CB_EV_MATCH = 4; 73 private static final int CB_EV_MATCH_EXPIRED = 5; 74 private static final int CB_EV_FOLLOWUP_RECEIVED = 6; 75 private static final int CB_EV_TRANSMIT_FOLLOWUP = 7; 76 private static final int CB_EV_DATA_PATH_REQUEST = 8; 77 private static final int CB_EV_DATA_PATH_CONFIRM = 9; 78 private static final int CB_EV_DATA_PATH_TERMINATED = 10; 79 private static final int CB_EV_DATA_PATH_SCHED_UPDATE = 11; 80 81 private final SparseIntArray mCallbackCounter = new SparseIntArray(); 82 private final SparseArray<List<WifiAwareChannelInfo>> mChannelInfoPerNdp = new SparseArray<>(); 83 incrementCbCount(int callbackId)84 private void incrementCbCount(int callbackId) { 85 mCallbackCounter.put(callbackId, mCallbackCounter.get(callbackId) + 1); 86 } 87 88 /** 89 * Interpreter of adb shell command 'adb shell cmd wifiaware native_cb ...'. 90 * 91 * @return -1 if parameter not recognized or invalid value, 0 otherwise. 92 */ 93 @Override onCommand(BasicShellCommandHandler parentShell)94 public int onCommand(BasicShellCommandHandler parentShell) { 95 final PrintWriter pwe = parentShell.getErrPrintWriter(); 96 final PrintWriter pwo = parentShell.getOutPrintWriter(); 97 98 String subCmd = parentShell.getNextArgRequired(); 99 switch (subCmd) { 100 case "get_cb_count": { 101 String option = parentShell.getNextOption(); 102 boolean reset = false; 103 if (option != null) { 104 if ("--reset".equals(option)) { 105 reset = true; 106 } else { 107 pwe.println("Unknown option to 'get_cb_count'"); 108 return -1; 109 } 110 } 111 112 JSONObject j = new JSONObject(); 113 try { 114 for (int i = 0; i < mCallbackCounter.size(); ++i) { 115 j.put(Integer.toString(mCallbackCounter.keyAt(i)), 116 mCallbackCounter.valueAt(i)); 117 } 118 } catch (JSONException e) { 119 Log.e(TAG, "onCommand: get_cb_count e=" + e); 120 } 121 pwo.println(j.toString()); 122 if (reset) { 123 mCallbackCounter.clear(); 124 } 125 return 0; 126 } 127 case "get_channel_info": { 128 String option = parentShell.getNextOption(); 129 if (option != null) { 130 pwe.println("Unknown option to 'get_channel_info'"); 131 return -1; 132 } 133 String channelInfoString = convertChannelInfoToJsonString(); 134 pwo.println(channelInfoString); 135 return 0; 136 } 137 default: 138 pwe.println("Unknown 'wifiaware native_cb <cmd>'"); 139 } 140 141 return -1; 142 } 143 144 @Override onReset()145 public void onReset() { 146 // NOP (onReset is intended for configuration reset - not data reset) 147 } 148 149 @Override onHelp(String command, BasicShellCommandHandler parentShell)150 public void onHelp(String command, BasicShellCommandHandler parentShell) { 151 final PrintWriter pw = parentShell.getOutPrintWriter(); 152 153 pw.println(" " + command); 154 pw.println(" get_cb_count [--reset]: gets the number of callbacks (and optionally reset " 155 + "count)"); 156 pw.println(" get_channel_info: prints out existing NDP channel info as a JSON String"); 157 } 158 159 @Override notifyCapabilitiesResponse(short id, Capabilities capabilities)160 public void notifyCapabilitiesResponse(short id, Capabilities capabilities) { 161 mWifiAwareStateManager.onCapabilitiesUpdateResponse(id, capabilities); 162 } 163 164 @Override notifyRangingResults(ArrayList<RangingResult> rangingResults, byte sessionId)165 public void notifyRangingResults(ArrayList<RangingResult> rangingResults, byte sessionId) { 166 mWifiAwareStateManager.onRangingResults(rangingResults, sessionId); 167 } 168 169 @Override notifyEnableResponse(short id, int status)170 public void notifyEnableResponse(short id, int status) { 171 if (status == NanStatusCode.SUCCESS 172 || status == NanStatusCode.ALREADY_ENABLED) { 173 mWifiAwareStateManager.onConfigSuccessResponse(id); 174 } else { 175 mWifiAwareStateManager.onConfigFailedResponse(id, status); 176 } 177 } 178 179 @Override notifyConfigResponse(short id, int status)180 public void notifyConfigResponse(short id, int status) { 181 if (status == NanStatusCode.SUCCESS) { 182 mWifiAwareStateManager.onConfigSuccessResponse(id); 183 } else { 184 mWifiAwareStateManager.onConfigFailedResponse(id, status); 185 } 186 } 187 188 @Override notifyDisableResponse(short id, int status)189 public void notifyDisableResponse(short id, int status) { 190 mWifiAwareStateManager.onDisableResponse(id, status); 191 } 192 193 @Override notifyStartPublishResponse(short id, int status, byte publishId)194 public void notifyStartPublishResponse(short id, int status, byte publishId) { 195 if (status == NanStatusCode.SUCCESS) { 196 mWifiAwareStateManager.onSessionConfigSuccessResponse(id, true, publishId); 197 } else { 198 mWifiAwareStateManager.onSessionConfigFailResponse(id, true, status); 199 } 200 } 201 202 @Override notifyStartSubscribeResponse(short id, int status, byte subscribeId)203 public void notifyStartSubscribeResponse(short id, int status, byte subscribeId) { 204 if (status == NanStatusCode.SUCCESS) { 205 mWifiAwareStateManager.onSessionConfigSuccessResponse(id, false, subscribeId); 206 } else { 207 mWifiAwareStateManager.onSessionConfigFailResponse(id, false, status); 208 } 209 } 210 211 @Override notifyTransmitFollowupResponse(short id, int status)212 public void notifyTransmitFollowupResponse(short id, int status) { 213 if (status == NanStatusCode.SUCCESS) { 214 mWifiAwareStateManager.onMessageSendQueuedSuccessResponse(id); 215 } else { 216 mWifiAwareStateManager.onMessageSendQueuedFailResponse(id, status); 217 } 218 } 219 220 @Override notifyCreateDataInterfaceResponse(short id, int status)221 public void notifyCreateDataInterfaceResponse(short id, int status) { 222 mWifiAwareStateManager.onCreateDataPathInterfaceResponse(id, 223 status == NanStatusCode.SUCCESS, status); 224 } 225 226 @Override notifyDeleteDataInterfaceResponse(short id, int status)227 public void notifyDeleteDataInterfaceResponse(short id, int status) { 228 mWifiAwareStateManager.onDeleteDataPathInterfaceResponse(id, 229 status == NanStatusCode.SUCCESS, status); 230 } 231 232 @Override notifyInitiateDataPathResponse(short id, int status, int ndpInstanceId)233 public void notifyInitiateDataPathResponse(short id, int status, 234 int ndpInstanceId) { 235 if (status == NanStatusCode.SUCCESS) { 236 mWifiAwareStateManager.onInitiateDataPathResponseSuccess(id, ndpInstanceId); 237 } else { 238 mWifiAwareStateManager.onInitiateDataPathResponseFail(id, status); 239 } 240 } 241 242 @Override notifyRespondToDataPathIndicationResponse(short id, int status)243 public void notifyRespondToDataPathIndicationResponse(short id, int status) { 244 mWifiAwareStateManager.onRespondToDataPathSetupRequestResponse(id, 245 status == NanStatusCode.SUCCESS, status); 246 } 247 248 @Override notifyTerminateDataPathResponse(short id, int status)249 public void notifyTerminateDataPathResponse(short id, int status) { 250 mWifiAwareStateManager.onEndDataPathResponse(id, status == NanStatusCode.SUCCESS, 251 status); 252 } 253 254 @Override notifyInitiatePairingResponse(short id, int status, int pairingInstanceId)255 public void notifyInitiatePairingResponse(short id, int status, 256 int pairingInstanceId) { 257 if (status == NanStatusCode.SUCCESS) { 258 mWifiAwareStateManager.onInitiatePairingResponseSuccess(id, pairingInstanceId); 259 } else { 260 mWifiAwareStateManager.onInitiatePairingResponseFail(id, status); 261 } 262 263 } 264 265 @Override notifyRespondToPairingIndicationResponse(short id, int status)266 public void notifyRespondToPairingIndicationResponse(short id, int status) { 267 if (status == NanStatusCode.SUCCESS) { 268 mWifiAwareStateManager.onRespondToPairingIndicationResponseSuccess(id); 269 } else { 270 mWifiAwareStateManager.onRespondToPairingIndicationResponseFail(id, status); 271 } 272 } 273 274 @Override notifyInitiateBootstrappingResponse(short id, int status, int bootstrappingInstanceId)275 public void notifyInitiateBootstrappingResponse(short id, int status, 276 int bootstrappingInstanceId) { 277 if (status == NanStatusCode.SUCCESS) { 278 mWifiAwareStateManager.onInitiateBootStrappingResponseSuccess(id, 279 bootstrappingInstanceId); 280 } else { 281 mWifiAwareStateManager.onInitiateBootStrappingResponseFail(id, status); 282 } 283 } 284 285 @Override notifyRespondToBootstrappingIndicationResponse(short id, int status)286 public void notifyRespondToBootstrappingIndicationResponse(short id, int status) { 287 if (status == NanStatusCode.SUCCESS) { 288 mWifiAwareStateManager.onRespondToBootstrappingIndicationResponseSuccess(id); 289 } else { 290 mWifiAwareStateManager.onRespondToBootstrappingIndicationResponseFail(id, status); 291 } 292 } 293 294 @Override notifySuspendResponse(short id, int status)295 public void notifySuspendResponse(short id, int status) { 296 mWifiAwareStateManager.onSuspendResponse(id, status); 297 } 298 299 @Override notifyResumeResponse(short id, int status)300 public void notifyResumeResponse(short id, int status) { 301 mWifiAwareStateManager.onResumeResponse(id, status); 302 } 303 304 @Override notifyTerminatePairingResponse(short id, int status)305 public void notifyTerminatePairingResponse(short id, int status) { 306 mWifiAwareStateManager.onEndPairingResponse(id, status == NanStatusCode.SUCCESS, 307 status); 308 } 309 310 @Override eventClusterEvent(int eventType, byte[] addr)311 public void eventClusterEvent(int eventType, byte[] addr) { 312 incrementCbCount(CB_EV_CLUSTER); 313 if (eventType == NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED) { 314 mWifiAwareStateManager.onInterfaceAddressChangeNotification(addr); 315 } else if (eventType == NanClusterEventType.STARTED_CLUSTER) { 316 mWifiAwareStateManager.onClusterChangeNotification( 317 IdentityChangedListener.CLUSTER_CHANGE_EVENT_STARTED, addr); 318 } else if (eventType == NanClusterEventType.JOINED_CLUSTER) { 319 mWifiAwareStateManager.onClusterChangeNotification( 320 IdentityChangedListener.CLUSTER_CHANGE_EVENT_JOINED, addr); 321 } else { 322 Log.e(TAG, "eventClusterEvent: invalid eventType=" + eventType); 323 } 324 } 325 326 @Override eventDisabled(int status)327 public void eventDisabled(int status) { 328 incrementCbCount(CB_EV_DISABLED); 329 mWifiAwareStateManager.onAwareDownNotification(status); 330 } 331 332 @Override eventPublishTerminated(byte sessionId, int status)333 public void eventPublishTerminated(byte sessionId, int status) { 334 incrementCbCount(CB_EV_PUBLISH_TERMINATED); 335 mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status, true); 336 } 337 338 @Override eventSubscribeTerminated(byte sessionId, int status)339 public void eventSubscribeTerminated(byte sessionId, int status) { 340 incrementCbCount(CB_EV_SUBSCRIBE_TERMINATED); 341 mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status, false); 342 } 343 344 @Override eventMatch(byte discoverySessionId, int peerId, byte[] addr, byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndicationType, int rangingMeasurementInMm, byte[] scid, int peerCipherType, byte[] nonce, byte[] tag, AwarePairingConfig pairingConfig, @Nullable List<OuiKeyedData> vendorData)345 public void eventMatch(byte discoverySessionId, int peerId, byte[] addr, 346 byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndicationType, 347 int rangingMeasurementInMm, byte[] scid, int peerCipherType, byte[] nonce, byte[] tag, 348 AwarePairingConfig pairingConfig, @Nullable List<OuiKeyedData> vendorData) { 349 incrementCbCount(CB_EV_MATCH); 350 mWifiAwareStateManager.onMatchNotification(discoverySessionId, peerId, 351 addr, serviceSpecificInfo, matchFilter, rangingIndicationType, 352 rangingMeasurementInMm, scid, peerCipherType, nonce, tag, pairingConfig, 353 vendorData); 354 } 355 356 @Override eventMatchExpired(byte discoverySessionId, int peerId)357 public void eventMatchExpired(byte discoverySessionId, int peerId) { 358 incrementCbCount(CB_EV_MATCH_EXPIRED); 359 mWifiAwareStateManager.onMatchExpiredNotification(discoverySessionId, peerId); 360 } 361 362 @Override eventFollowupReceived(byte discoverySessionId, int peerId, byte[] addr, byte[] serviceSpecificInfo)363 public void eventFollowupReceived(byte discoverySessionId, int peerId, byte[] addr, 364 byte[] serviceSpecificInfo) { 365 incrementCbCount(CB_EV_FOLLOWUP_RECEIVED); 366 mWifiAwareStateManager.onMessageReceivedNotification(discoverySessionId, peerId, 367 addr, serviceSpecificInfo); 368 } 369 370 @Override eventTransmitFollowup(short id, int status)371 public void eventTransmitFollowup(short id, int status) { 372 incrementCbCount(CB_EV_TRANSMIT_FOLLOWUP); 373 if (status == NanStatusCode.SUCCESS) { 374 mWifiAwareStateManager.onMessageSendSuccessNotification(id); 375 } else { 376 mWifiAwareStateManager.onMessageSendFailNotification(id, status); 377 } 378 } 379 380 @Override eventDataPathRequest(byte discoverySessionId, byte[] peerDiscMacAddr, int ndpInstanceId, byte[] appInfo)381 public void eventDataPathRequest(byte discoverySessionId, byte[] peerDiscMacAddr, 382 int ndpInstanceId, byte[] appInfo) { 383 incrementCbCount(CB_EV_DATA_PATH_REQUEST); 384 mWifiAwareStateManager.onDataPathRequestNotification(discoverySessionId, 385 peerDiscMacAddr, ndpInstanceId, appInfo); 386 } 387 388 @Override eventDataPathConfirm(int status, int ndpInstanceId, boolean dataPathSetupSuccess, byte[] peerNdiMacAddr, byte[] appInfo, List<WifiAwareChannelInfo> channelInfos)389 public void eventDataPathConfirm(int status, int ndpInstanceId, boolean dataPathSetupSuccess, 390 byte[] peerNdiMacAddr, byte[] appInfo, 391 List<WifiAwareChannelInfo> channelInfos) { 392 incrementCbCount(CB_EV_DATA_PATH_CONFIRM); 393 if (channelInfos != null) { 394 mChannelInfoPerNdp.put(ndpInstanceId, channelInfos); 395 } 396 mWifiAwareStateManager.onDataPathConfirmNotification(ndpInstanceId, 397 peerNdiMacAddr, dataPathSetupSuccess, status, appInfo, channelInfos); 398 } 399 400 @Override eventDataPathScheduleUpdate(byte[] peerDiscoveryAddress, ArrayList<Integer> ndpInstanceIds, List<WifiAwareChannelInfo> channelInfo)401 public void eventDataPathScheduleUpdate(byte[] peerDiscoveryAddress, 402 ArrayList<Integer> ndpInstanceIds, List<WifiAwareChannelInfo> channelInfo) { 403 incrementCbCount(CB_EV_DATA_PATH_SCHED_UPDATE); 404 for (int ndpInstanceId : ndpInstanceIds) { 405 mChannelInfoPerNdp.put(ndpInstanceId, channelInfo); 406 } 407 mWifiAwareStateManager.onDataPathScheduleUpdateNotification(peerDiscoveryAddress, 408 ndpInstanceIds, channelInfo); 409 } 410 411 @Override eventDataPathTerminated(int ndpInstanceId)412 public void eventDataPathTerminated(int ndpInstanceId) { 413 incrementCbCount(CB_EV_DATA_PATH_TERMINATED); 414 mChannelInfoPerNdp.remove(ndpInstanceId); 415 mWifiAwareStateManager.onDataPathEndNotification(ndpInstanceId); 416 } 417 418 @Override eventPairingRequest(int discoverySessionId, int peerId, byte[] peerDiscMacAddr, int ndpInstanceId, int requestType, boolean enableCache, byte[] nonce, byte[] tag)419 public void eventPairingRequest(int discoverySessionId, int peerId, byte[] peerDiscMacAddr, 420 int ndpInstanceId, int requestType, boolean enableCache, byte[] nonce, byte[] tag) { 421 mWifiAwareStateManager.onPairingRequestNotification(discoverySessionId, peerId, 422 peerDiscMacAddr, ndpInstanceId, requestType, enableCache, nonce, tag); 423 } 424 425 @Override eventPairingConfirm(int pairingId, boolean accept, int reason, int requestType, boolean enableCache, PairingConfigManager.PairingSecurityAssociationInfo npksa)426 public void eventPairingConfirm(int pairingId, boolean accept, int reason, int requestType, 427 boolean enableCache, 428 PairingConfigManager.PairingSecurityAssociationInfo npksa) { 429 mWifiAwareStateManager.onPairingConfirmNotification(pairingId, accept, reason, requestType, 430 enableCache, npksa); 431 } 432 433 @Override eventBootstrappingRequest(int discoverySessionId, int peerId, byte[] peerDiscMacAddr, int bootstrappingInstanceId, int method)434 public void eventBootstrappingRequest(int discoverySessionId, int peerId, 435 byte[] peerDiscMacAddr, int bootstrappingInstanceId, int method) { 436 mWifiAwareStateManager.onBootstrappingRequestNotification(discoverySessionId, peerId, 437 peerDiscMacAddr, bootstrappingInstanceId, method); 438 } 439 440 @Override eventBootstrappingConfirm(int bootstrappingId, int responseCode, int reason, int comebackDelay, byte[] cookie)441 public void eventBootstrappingConfirm(int bootstrappingId, int responseCode, int reason, 442 int comebackDelay, byte[] cookie) { 443 mWifiAwareStateManager.onBootstrappingConfirmNotification(bootstrappingId, responseCode, 444 reason, comebackDelay, cookie); 445 } 446 447 @Override eventSuspensionModeChanged(boolean isSuspended)448 public void eventSuspensionModeChanged(boolean isSuspended) { 449 mWifiAwareStateManager.onSuspensionModeChangedNotification(isSuspended); 450 } 451 452 /** 453 * Reset the channel info when Aware is down. 454 */ resetChannelInfo()455 /* package */ void resetChannelInfo() { 456 mChannelInfoPerNdp.clear(); 457 } 458 459 /** 460 * Dump the internal state of the class. 461 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)462 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 463 pw.println("WifiAwareNativeCallback:"); 464 pw.println(" mCallbackCounter: " + mCallbackCounter); 465 pw.println(" mChannelInfoPerNdp: " + mChannelInfoPerNdp); 466 } 467 468 469 // utilities 470 471 /** 472 * Transfer the channel Info dict into a Json String which can be decoded by Json reader. 473 * The Format is: "{ndpInstanceId: [{"channelFreq": channelFreq, 474 * "channelBandwidth": channelBandwidth, "numSpatialStreams": numSpatialStreams}]}" 475 * @return Json String. 476 */ convertChannelInfoToJsonString()477 private String convertChannelInfoToJsonString() { 478 JSONObject channelInfoJson = new JSONObject(); 479 try { 480 for (int i = 0; i < mChannelInfoPerNdp.size(); i++) { 481 JSONArray infoJsonArray = new JSONArray(); 482 for (WifiAwareChannelInfo info : mChannelInfoPerNdp.valueAt(i)) { 483 JSONObject j = new JSONObject(); 484 j.put("channelFreq", info.getChannelFrequencyMhz()); 485 j.put("channelBandwidth", info.getChannelBandwidth()); 486 j.put("numSpatialStreams", info.getSpatialStreamCount()); 487 infoJsonArray.put(j); 488 } 489 channelInfoJson.put(Integer.toString(mChannelInfoPerNdp.keyAt(i)), infoJsonArray); 490 } 491 } catch (JSONException e) { 492 Log.e(TAG, "onCommand: get_channel_info e=" + e); 493 } 494 return channelInfoJson.toString(); 495 } 496 } 497