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