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