1 /* 2 * Copyright (C) 2016 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.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.hardware.wifi.V1_0.NanStatusType; 24 import android.net.wifi.RttManager; 25 import android.net.wifi.aware.Characteristics; 26 import android.net.wifi.aware.ConfigRequest; 27 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 28 import android.net.wifi.aware.IWifiAwareEventCallback; 29 import android.net.wifi.aware.PublishConfig; 30 import android.net.wifi.aware.SubscribeConfig; 31 import android.net.wifi.aware.WifiAwareManager; 32 import android.net.wifi.aware.WifiAwareNetworkSpecifier; 33 import android.os.Bundle; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.PowerManager; 37 import android.os.RemoteException; 38 import android.os.ShellCommand; 39 import android.os.SystemClock; 40 import android.os.UserHandle; 41 import android.util.ArrayMap; 42 import android.util.Log; 43 import android.util.Pair; 44 import android.util.SparseArray; 45 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.util.MessageUtils; 48 import com.android.internal.util.State; 49 import com.android.internal.util.StateMachine; 50 import com.android.internal.util.WakeupMessage; 51 import com.android.server.wifi.util.NativeUtil; 52 import com.android.server.wifi.util.WifiPermissionsWrapper; 53 54 import libcore.util.HexEncoding; 55 56 import org.json.JSONException; 57 import org.json.JSONObject; 58 59 import java.io.FileDescriptor; 60 import java.io.PrintWriter; 61 import java.util.Arrays; 62 import java.util.HashMap; 63 import java.util.Iterator; 64 import java.util.LinkedHashMap; 65 import java.util.Map; 66 67 /** 68 * Manages the state of the Wi-Fi Aware system service. 69 */ 70 public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShellCommand { 71 private static final String TAG = "WifiAwareStateManager"; 72 private static final boolean DBG = false; 73 private static final boolean VDBG = false; // STOPSHIP if true 74 75 @VisibleForTesting 76 public static final String HAL_COMMAND_TIMEOUT_TAG = TAG + " HAL Command Timeout"; 77 78 @VisibleForTesting 79 public static final String HAL_SEND_MESSAGE_TIMEOUT_TAG = TAG + " HAL Send Message Timeout"; 80 81 @VisibleForTesting 82 public static final String HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG = 83 TAG + " HAL Data Path Confirm Timeout"; 84 85 /* 86 * State machine message types. There are sub-types for the messages (except for TIMEOUTs). 87 * Format: 88 * - Message.arg1: contains message sub-type 89 * - Message.arg2: contains transaction ID for RESPONSE & RESPONSE_TIMEOUT 90 */ 91 private static final int MESSAGE_TYPE_COMMAND = 1; 92 private static final int MESSAGE_TYPE_RESPONSE = 2; 93 private static final int MESSAGE_TYPE_NOTIFICATION = 3; 94 private static final int MESSAGE_TYPE_RESPONSE_TIMEOUT = 4; 95 private static final int MESSAGE_TYPE_SEND_MESSAGE_TIMEOUT = 5; 96 private static final int MESSAGE_TYPE_DATA_PATH_TIMEOUT = 6; 97 98 /* 99 * Message sub-types: 100 */ 101 private static final int COMMAND_TYPE_CONNECT = 100; 102 private static final int COMMAND_TYPE_DISCONNECT = 101; 103 private static final int COMMAND_TYPE_TERMINATE_SESSION = 102; 104 private static final int COMMAND_TYPE_PUBLISH = 103; 105 private static final int COMMAND_TYPE_UPDATE_PUBLISH = 104; 106 private static final int COMMAND_TYPE_SUBSCRIBE = 105; 107 private static final int COMMAND_TYPE_UPDATE_SUBSCRIBE = 106; 108 private static final int COMMAND_TYPE_ENQUEUE_SEND_MESSAGE = 107; 109 private static final int COMMAND_TYPE_ENABLE_USAGE = 108; 110 private static final int COMMAND_TYPE_DISABLE_USAGE = 109; 111 private static final int COMMAND_TYPE_START_RANGING = 110; 112 private static final int COMMAND_TYPE_GET_CAPABILITIES = 111; 113 private static final int COMMAND_TYPE_CREATE_ALL_DATA_PATH_INTERFACES = 112; 114 private static final int COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES = 113; 115 private static final int COMMAND_TYPE_CREATE_DATA_PATH_INTERFACE = 114; 116 private static final int COMMAND_TYPE_DELETE_DATA_PATH_INTERFACE = 115; 117 private static final int COMMAND_TYPE_INITIATE_DATA_PATH_SETUP = 116; 118 private static final int COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST = 117; 119 private static final int COMMAND_TYPE_END_DATA_PATH = 118; 120 private static final int COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE = 119; 121 private static final int COMMAND_TYPE_RECONFIGURE = 120; 122 private static final int COMMAND_TYPE_DELAYED_INITIALIZATION = 121; 123 124 private static final int RESPONSE_TYPE_ON_CONFIG_SUCCESS = 200; 125 private static final int RESPONSE_TYPE_ON_CONFIG_FAIL = 201; 126 private static final int RESPONSE_TYPE_ON_SESSION_CONFIG_SUCCESS = 202; 127 private static final int RESPONSE_TYPE_ON_SESSION_CONFIG_FAIL = 203; 128 private static final int RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_SUCCESS = 204; 129 private static final int RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_FAIL = 205; 130 private static final int RESPONSE_TYPE_ON_CAPABILITIES_UPDATED = 206; 131 private static final int RESPONSE_TYPE_ON_CREATE_INTERFACE = 207; 132 private static final int RESPONSE_TYPE_ON_DELETE_INTERFACE = 208; 133 private static final int RESPONSE_TYPE_ON_INITIATE_DATA_PATH_SUCCESS = 209; 134 private static final int RESPONSE_TYPE_ON_INITIATE_DATA_PATH_FAIL = 210; 135 private static final int RESPONSE_TYPE_ON_RESPOND_TO_DATA_PATH_SETUP_REQUEST = 211; 136 private static final int RESPONSE_TYPE_ON_END_DATA_PATH = 212; 137 private static final int RESPONSE_TYPE_ON_DISABLE = 213; 138 139 private static final int NOTIFICATION_TYPE_INTERFACE_CHANGE = 301; 140 private static final int NOTIFICATION_TYPE_CLUSTER_CHANGE = 302; 141 private static final int NOTIFICATION_TYPE_MATCH = 303; 142 private static final int NOTIFICATION_TYPE_SESSION_TERMINATED = 304; 143 private static final int NOTIFICATION_TYPE_MESSAGE_RECEIVED = 305; 144 private static final int NOTIFICATION_TYPE_AWARE_DOWN = 306; 145 private static final int NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS = 307; 146 private static final int NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL = 308; 147 private static final int NOTIFICATION_TYPE_ON_DATA_PATH_REQUEST = 309; 148 private static final int NOTIFICATION_TYPE_ON_DATA_PATH_CONFIRM = 310; 149 private static final int NOTIFICATION_TYPE_ON_DATA_PATH_END = 311; 150 151 private static final SparseArray<String> sSmToString = MessageUtils.findMessageNames( 152 new Class[]{WifiAwareStateManager.class}, 153 new String[]{"MESSAGE_TYPE", "COMMAND_TYPE", "RESPONSE_TYPE", "NOTIFICATION_TYPE"}); 154 155 /* 156 * Keys used when passing (some) arguments to the Handler thread (too many 157 * arguments to pass in the short-cut Message members). 158 */ 159 private static final String MESSAGE_BUNDLE_KEY_SESSION_TYPE = "session_type"; 160 private static final String MESSAGE_BUNDLE_KEY_SESSION_ID = "session_id"; 161 private static final String MESSAGE_BUNDLE_KEY_CONFIG = "config"; 162 private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; 163 private static final String MESSAGE_BUNDLE_KEY_MESSAGE_PEER_ID = "message_peer_id"; 164 private static final String MESSAGE_BUNDLE_KEY_MESSAGE_ID = "message_id"; 165 private static final String MESSAGE_BUNDLE_KEY_SSI_DATA = "ssi_data"; 166 private static final String MESSAGE_BUNDLE_KEY_FILTER_DATA = "filter_data"; 167 private static final String MESSAGE_BUNDLE_KEY_MAC_ADDRESS = "mac_address"; 168 private static final String MESSAGE_BUNDLE_KEY_MESSAGE_DATA = "message_data"; 169 private static final String MESSAGE_BUNDLE_KEY_REQ_INSTANCE_ID = "req_instance_id"; 170 private static final String MESSAGE_BUNDLE_KEY_RANGING_ID = "ranging_id"; 171 private static final String MESSAGE_BUNDLE_KEY_SEND_MESSAGE_ENQUEUE_TIME = "message_queue_time"; 172 private static final String MESSAGE_BUNDLE_KEY_RETRY_COUNT = "retry_count"; 173 private static final String MESSAGE_BUNDLE_KEY_SUCCESS_FLAG = "success_flag"; 174 private static final String MESSAGE_BUNDLE_KEY_STATUS_CODE = "status_code"; 175 private static final String MESSAGE_BUNDLE_KEY_INTERFACE_NAME = "interface_name"; 176 private static final String MESSAGE_BUNDLE_KEY_CHANNEL_REQ_TYPE = "channel_request_type"; 177 private static final String MESSAGE_BUNDLE_KEY_CHANNEL = "channel"; 178 private static final String MESSAGE_BUNDLE_KEY_PEER_ID = "peer_id"; 179 private static final String MESSAGE_BUNDLE_KEY_UID = "uid"; 180 private static final String MESSAGE_BUNDLE_KEY_PID = "pid"; 181 private static final String MESSAGE_BUNDLE_KEY_CALLING_PACKAGE = "calling_package"; 182 private static final String MESSAGE_BUNDLE_KEY_SENT_MESSAGE = "send_message"; 183 private static final String MESSAGE_BUNDLE_KEY_MESSAGE_ARRIVAL_SEQ = "message_arrival_seq"; 184 private static final String MESSAGE_BUNDLE_KEY_NOTIFY_IDENTITY_CHANGE = "notify_identity_chg"; 185 private static final String MESSAGE_BUNDLE_KEY_PMK = "pmk"; 186 private static final String MESSAGE_BUNDLE_KEY_PASSPHRASE = "passphrase"; 187 private static final String MESSAGE_BUNDLE_KEY_OOB = "out_of_band"; 188 189 private WifiAwareNativeApi mWifiAwareNativeApi; 190 private WifiAwareNativeManager mWifiAwareNativeManager; 191 192 /* 193 * Asynchronous access with no lock 194 */ 195 private volatile boolean mUsageEnabled = false; 196 197 /* 198 * Synchronous access: state is only accessed through the state machine 199 * handler thread: no need to use a lock. 200 */ 201 private Context mContext; 202 private WifiAwareMetrics mAwareMetrics; 203 private volatile Capabilities mCapabilities; 204 private volatile Characteristics mCharacteristics = null; 205 private WifiAwareStateMachine mSm; 206 private WifiAwareRttStateManager mRtt; 207 public WifiAwareDataPathStateManager mDataPathMgr; 208 private PowerManager mPowerManager; 209 210 private final SparseArray<WifiAwareClientState> mClients = new SparseArray<>(); 211 private ConfigRequest mCurrentAwareConfiguration = null; 212 private boolean mCurrentIdentityNotification = false; 213 214 private static final byte[] ALL_ZERO_MAC = new byte[] {0, 0, 0, 0, 0, 0}; 215 private byte[] mCurrentDiscoveryInterfaceMac = ALL_ZERO_MAC; 216 217 public WifiAwareStateManager() { 218 onReset(); 219 } 220 221 /** 222 * Inject references to other manager objects. Needed to resolve 223 * circular dependencies and to allow mocking. 224 */ 225 public void setNative(WifiAwareNativeManager wifiAwareNativeManager, 226 WifiAwareNativeApi wifiAwareNativeApi) { 227 mWifiAwareNativeManager = wifiAwareNativeManager; 228 mWifiAwareNativeApi = wifiAwareNativeApi; 229 } 230 231 /* 232 * parameters settable through shell command 233 */ 234 public static final String PARAM_ON_IDLE_DISABLE_AWARE = "on_idle_disable_aware"; 235 public static final int PARAM_ON_IDLE_DISABLE_AWARE_DEFAULT = 1; // 0 = false, 1 = true 236 237 private Map<String, Integer> mSettableParameters = new HashMap<>(); 238 239 /** 240 * Interpreter of adb shell command 'adb shell wifiaware native_api ...'. 241 * 242 * @return -1 if parameter not recognized or invalid value, 0 otherwise. 243 */ 244 @Override 245 public int onCommand(ShellCommand parentShell) { 246 final PrintWriter pw_err = parentShell.getErrPrintWriter(); 247 final PrintWriter pw_out = parentShell.getOutPrintWriter(); 248 249 String subCmd = parentShell.getNextArgRequired(); 250 if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'"); 251 switch (subCmd) { 252 case "set": { 253 String name = parentShell.getNextArgRequired(); 254 if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'"); 255 if (!mSettableParameters.containsKey(name)) { 256 pw_err.println("Unknown parameter name -- '" + name + "'"); 257 return -1; 258 } 259 260 String valueStr = parentShell.getNextArgRequired(); 261 if (VDBG) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'"); 262 int value; 263 try { 264 value = Integer.valueOf(valueStr); 265 } catch (NumberFormatException e) { 266 pw_err.println("Can't convert value to integer -- '" + valueStr + "'"); 267 return -1; 268 } 269 mSettableParameters.put(name, value); 270 return 0; 271 } 272 case "get": { 273 String name = parentShell.getNextArgRequired(); 274 if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'"); 275 if (!mSettableParameters.containsKey(name)) { 276 pw_err.println("Unknown parameter name -- '" + name + "'"); 277 return -1; 278 } 279 280 pw_out.println((int) mSettableParameters.get(name)); 281 return 0; 282 } 283 case "get_capabilities": { 284 JSONObject j = new JSONObject(); 285 if (mCapabilities != null) { 286 try { 287 j.put("maxConcurrentAwareClusters", 288 mCapabilities.maxConcurrentAwareClusters); 289 j.put("maxPublishes", mCapabilities.maxPublishes); 290 j.put("maxSubscribes", mCapabilities.maxSubscribes); 291 j.put("maxServiceNameLen", mCapabilities.maxServiceNameLen); 292 j.put("maxMatchFilterLen", mCapabilities.maxMatchFilterLen); 293 j.put("maxTotalMatchFilterLen", mCapabilities.maxTotalMatchFilterLen); 294 j.put("maxServiceSpecificInfoLen", mCapabilities.maxServiceSpecificInfoLen); 295 j.put("maxExtendedServiceSpecificInfoLen", 296 mCapabilities.maxExtendedServiceSpecificInfoLen); 297 j.put("maxNdiInterfaces", mCapabilities.maxNdiInterfaces); 298 j.put("maxNdpSessions", mCapabilities.maxNdpSessions); 299 j.put("maxAppInfoLen", mCapabilities.maxAppInfoLen); 300 j.put("maxQueuedTransmitMessages", mCapabilities.maxQueuedTransmitMessages); 301 j.put("maxSubscribeInterfaceAddresses", 302 mCapabilities.maxSubscribeInterfaceAddresses); 303 j.put("supportedCipherSuites", mCapabilities.supportedCipherSuites); 304 } catch (JSONException e) { 305 Log.e(TAG, "onCommand: get_capabilities e=" + e); 306 } 307 } 308 pw_out.println(j.toString()); 309 return 0; 310 } 311 default: 312 pw_err.println("Unknown 'wifiaware state_mgr <cmd>'"); 313 } 314 315 return -1; 316 } 317 318 @Override 319 public void onReset() { 320 mSettableParameters.put(PARAM_ON_IDLE_DISABLE_AWARE, PARAM_ON_IDLE_DISABLE_AWARE_DEFAULT); 321 } 322 323 @Override 324 public void onHelp(String command, ShellCommand parentShell) { 325 final PrintWriter pw = parentShell.getOutPrintWriter(); 326 327 pw.println(" " + command); 328 pw.println(" set <name> <value>: sets named parameter to value. Names: " 329 + mSettableParameters.keySet()); 330 pw.println(" get <name>: gets named parameter value. Names: " 331 + mSettableParameters.keySet()); 332 pw.println(" get_capabilities: prints out the capabilities as a JSON string"); 333 } 334 335 /** 336 * Initialize the handler of the state manager with the specified thread 337 * looper. 338 * 339 * @param looper Thread looper on which to run the handler. 340 */ 341 public void start(Context context, Looper looper, WifiAwareMetrics awareMetrics, 342 WifiPermissionsWrapper permissionsWrapper) { 343 Log.i(TAG, "start()"); 344 345 mContext = context; 346 mAwareMetrics = awareMetrics; 347 mSm = new WifiAwareStateMachine(TAG, looper); 348 mSm.setDbg(DBG); 349 mSm.start(); 350 351 mRtt = new WifiAwareRttStateManager(); 352 mDataPathMgr = new WifiAwareDataPathStateManager(this); 353 mDataPathMgr.start(mContext, mSm.getHandler().getLooper(), awareMetrics, 354 permissionsWrapper); 355 356 mPowerManager = mContext.getSystemService(PowerManager.class); 357 358 IntentFilter intentFilter = new IntentFilter(); 359 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 360 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 361 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 362 mContext.registerReceiver(new BroadcastReceiver() { 363 @Override 364 public void onReceive(Context context, Intent intent) { 365 String action = intent.getAction(); 366 if (VDBG) Log.v(TAG, "BroadcastReceiver: action=" + action); 367 if (action.equals(Intent.ACTION_SCREEN_ON) 368 || action.equals(Intent.ACTION_SCREEN_OFF)) { 369 reconfigure(); 370 } 371 372 if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) { 373 if (mSettableParameters.get(PARAM_ON_IDLE_DISABLE_AWARE) != 0) { 374 if (mPowerManager.isDeviceIdleMode()) { 375 disableUsage(); 376 } else { 377 enableUsage(); 378 } 379 } else { 380 reconfigure(); 381 } 382 } 383 } 384 }, intentFilter); 385 } 386 387 /** 388 * Initialize the late-initialization sub-services: depend on other services already existing. 389 */ 390 public void startLate() { 391 delayedInitialization(); 392 } 393 394 /** 395 * Get the client state for the specified ID (or null if none exists). 396 */ 397 /* package */ WifiAwareClientState getClient(int clientId) { 398 return mClients.get(clientId); 399 } 400 401 /** 402 * Get the capabilities. 403 */ 404 public Capabilities getCapabilities() { 405 return mCapabilities; 406 } 407 408 /** 409 * Get the public characteristics derived from the capabilities. Use lazy initialization. 410 */ 411 public Characteristics getCharacteristics() { 412 if (mCharacteristics == null && mCapabilities != null) { 413 mCharacteristics = mCapabilities.toPublicCharacteristics(); 414 } 415 416 return mCharacteristics; 417 } 418 419 /* 420 * COMMANDS 421 */ 422 423 /** 424 * Place a request for delayed start operation on the state machine queue. 425 */ 426 public void delayedInitialization() { 427 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 428 msg.arg1 = COMMAND_TYPE_DELAYED_INITIALIZATION; 429 mSm.sendMessage(msg); 430 } 431 432 /** 433 * Place a request for a new client connection on the state machine queue. 434 */ 435 public void connect(int clientId, int uid, int pid, String callingPackage, 436 IWifiAwareEventCallback callback, ConfigRequest configRequest, 437 boolean notifyOnIdentityChanged) { 438 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 439 msg.arg1 = COMMAND_TYPE_CONNECT; 440 msg.arg2 = clientId; 441 msg.obj = callback; 442 msg.getData().putParcelable(MESSAGE_BUNDLE_KEY_CONFIG, configRequest); 443 msg.getData().putInt(MESSAGE_BUNDLE_KEY_UID, uid); 444 msg.getData().putInt(MESSAGE_BUNDLE_KEY_PID, pid); 445 msg.getData().putString(MESSAGE_BUNDLE_KEY_CALLING_PACKAGE, callingPackage); 446 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_NOTIFY_IDENTITY_CHANGE, 447 notifyOnIdentityChanged); 448 mSm.sendMessage(msg); 449 } 450 451 /** 452 * Place a request to disconnect (destroy) an existing client on the state 453 * machine queue. 454 */ 455 public void disconnect(int clientId) { 456 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 457 msg.arg1 = COMMAND_TYPE_DISCONNECT; 458 msg.arg2 = clientId; 459 mSm.sendMessage(msg); 460 } 461 462 /** 463 * Place a request to reconfigure Aware. No additional input - intended to use current 464 * power settings when executed. Thus possibly entering or exiting power saving mode if 465 * needed (or do nothing if Aware is not active). 466 */ 467 public void reconfigure() { 468 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 469 msg.arg1 = COMMAND_TYPE_RECONFIGURE; 470 mSm.sendMessage(msg); 471 } 472 473 /** 474 * Place a request to stop a discovery session on the state machine queue. 475 */ 476 public void terminateSession(int clientId, int sessionId) { 477 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 478 msg.arg1 = COMMAND_TYPE_TERMINATE_SESSION; 479 msg.arg2 = clientId; 480 msg.obj = sessionId; 481 mSm.sendMessage(msg); 482 } 483 484 /** 485 * Place a request to start a new publish discovery session on the state 486 * machine queue. 487 */ 488 public void publish(int clientId, PublishConfig publishConfig, 489 IWifiAwareDiscoverySessionCallback callback) { 490 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 491 msg.arg1 = COMMAND_TYPE_PUBLISH; 492 msg.arg2 = clientId; 493 msg.obj = callback; 494 msg.getData().putParcelable(MESSAGE_BUNDLE_KEY_CONFIG, publishConfig); 495 mSm.sendMessage(msg); 496 } 497 498 /** 499 * Place a request to modify an existing publish discovery session on the 500 * state machine queue. 501 */ 502 public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) { 503 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 504 msg.arg1 = COMMAND_TYPE_UPDATE_PUBLISH; 505 msg.arg2 = clientId; 506 msg.obj = publishConfig; 507 msg.getData().putInt(MESSAGE_BUNDLE_KEY_SESSION_ID, sessionId); 508 mSm.sendMessage(msg); 509 } 510 511 /** 512 * Place a request to start a new subscribe discovery session on the state 513 * machine queue. 514 */ 515 public void subscribe(int clientId, SubscribeConfig subscribeConfig, 516 IWifiAwareDiscoverySessionCallback callback) { 517 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 518 msg.arg1 = COMMAND_TYPE_SUBSCRIBE; 519 msg.arg2 = clientId; 520 msg.obj = callback; 521 msg.getData().putParcelable(MESSAGE_BUNDLE_KEY_CONFIG, subscribeConfig); 522 mSm.sendMessage(msg); 523 } 524 525 /** 526 * Place a request to modify an existing subscribe discovery session on the 527 * state machine queue. 528 */ 529 public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) { 530 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 531 msg.arg1 = COMMAND_TYPE_UPDATE_SUBSCRIBE; 532 msg.arg2 = clientId; 533 msg.obj = subscribeConfig; 534 msg.getData().putInt(MESSAGE_BUNDLE_KEY_SESSION_ID, sessionId); 535 mSm.sendMessage(msg); 536 } 537 538 /** 539 * Place a request to send a message on a discovery session on the state 540 * machine queue. 541 */ 542 public void sendMessage(int clientId, int sessionId, int peerId, byte[] message, int messageId, 543 int retryCount) { 544 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 545 msg.arg1 = COMMAND_TYPE_ENQUEUE_SEND_MESSAGE; 546 msg.arg2 = clientId; 547 msg.getData().putInt(MESSAGE_BUNDLE_KEY_SESSION_ID, sessionId); 548 msg.getData().putInt(MESSAGE_BUNDLE_KEY_MESSAGE_PEER_ID, peerId); 549 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message); 550 msg.getData().putInt(MESSAGE_BUNDLE_KEY_MESSAGE_ID, messageId); 551 msg.getData().putInt(MESSAGE_BUNDLE_KEY_RETRY_COUNT, retryCount); 552 mSm.sendMessage(msg); 553 } 554 555 /** 556 * Place a request to range a peer on the discovery session on the state machine queue. 557 */ 558 public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params, 559 int rangingId) { 560 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 561 msg.arg1 = COMMAND_TYPE_START_RANGING; 562 msg.arg2 = clientId; 563 msg.obj = params; 564 msg.getData().putInt(MESSAGE_BUNDLE_KEY_SESSION_ID, sessionId); 565 msg.getData().putInt(MESSAGE_BUNDLE_KEY_RANGING_ID, rangingId); 566 mSm.sendMessage(msg); 567 } 568 569 /** 570 * Enable usage of Aware. Doesn't actually turn on Aware (form clusters) - that 571 * only happens when a connection is created. 572 */ 573 public void enableUsage() { 574 if (mSettableParameters.get(PARAM_ON_IDLE_DISABLE_AWARE) != 0 575 && mPowerManager.isDeviceIdleMode()) { 576 Log.d(TAG, "enableUsage(): while device is in IDLE mode - ignoring"); 577 return; 578 } 579 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 580 msg.arg1 = COMMAND_TYPE_ENABLE_USAGE; 581 mSm.sendMessage(msg); 582 } 583 584 /** 585 * Disable usage of Aware. Terminates all existing clients with onAwareDown(). 586 */ 587 public void disableUsage() { 588 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 589 msg.arg1 = COMMAND_TYPE_DISABLE_USAGE; 590 mSm.sendMessage(msg); 591 } 592 593 /** 594 * Checks whether Aware usage is enabled (not necessarily that Aware is up right 595 * now) or disabled. 596 * 597 * @return A boolean indicating whether Aware usage is enabled (true) or 598 * disabled (false). 599 */ 600 public boolean isUsageEnabled() { 601 return mUsageEnabled; 602 } 603 604 /** 605 * Get the capabilities of the current Aware firmware. 606 */ 607 public void queryCapabilities() { 608 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 609 msg.arg1 = COMMAND_TYPE_GET_CAPABILITIES; 610 mSm.sendMessage(msg); 611 } 612 613 /** 614 * Create all Aware data path interfaces which are supported by the firmware capabilities. 615 */ 616 public void createAllDataPathInterfaces() { 617 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 618 msg.arg1 = COMMAND_TYPE_CREATE_ALL_DATA_PATH_INTERFACES; 619 mSm.sendMessage(msg); 620 } 621 622 /** 623 * delete all Aware data path interfaces. 624 */ 625 public void deleteAllDataPathInterfaces() { 626 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 627 msg.arg1 = COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES; 628 mSm.sendMessage(msg); 629 } 630 631 /** 632 * Create the specified data-path interface. Doesn't actually creates a data-path. 633 */ 634 public void createDataPathInterface(String interfaceName) { 635 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 636 msg.arg1 = COMMAND_TYPE_CREATE_DATA_PATH_INTERFACE; 637 msg.obj = interfaceName; 638 mSm.sendMessage(msg); 639 } 640 641 /** 642 * Deletes the specified data-path interface. 643 */ 644 public void deleteDataPathInterface(String interfaceName) { 645 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 646 msg.arg1 = COMMAND_TYPE_DELETE_DATA_PATH_INTERFACE; 647 msg.obj = interfaceName; 648 mSm.sendMessage(msg); 649 } 650 651 /** 652 * Command to initiate a data-path (executed by the initiator). 653 */ 654 public void initiateDataPathSetup(WifiAwareNetworkSpecifier networkSpecifier, int peerId, 655 int channelRequestType, int channel, byte[] peer, String interfaceName, byte[] pmk, 656 String passphrase, boolean isOutOfBand) { 657 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 658 msg.arg1 = COMMAND_TYPE_INITIATE_DATA_PATH_SETUP; 659 msg.obj = networkSpecifier; 660 msg.getData().putInt(MESSAGE_BUNDLE_KEY_PEER_ID, peerId); 661 msg.getData().putInt(MESSAGE_BUNDLE_KEY_CHANNEL_REQ_TYPE, channelRequestType); 662 msg.getData().putInt(MESSAGE_BUNDLE_KEY_CHANNEL, channel); 663 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS, peer); 664 msg.getData().putString(MESSAGE_BUNDLE_KEY_INTERFACE_NAME, interfaceName); 665 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_PMK, pmk); 666 msg.getData().putString(MESSAGE_BUNDLE_KEY_PASSPHRASE, passphrase); 667 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_OOB, isOutOfBand); 668 mSm.sendMessage(msg); 669 } 670 671 /** 672 * Command to respond to the data-path request (executed by the responder). 673 */ 674 public void respondToDataPathRequest(boolean accept, int ndpId, String interfaceName, 675 byte[] pmk, String passphrase, boolean isOutOfBand) { 676 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 677 msg.arg1 = COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST; 678 msg.arg2 = ndpId; 679 msg.obj = accept; 680 msg.getData().putString(MESSAGE_BUNDLE_KEY_INTERFACE_NAME, interfaceName); 681 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_PMK, pmk); 682 msg.getData().putString(MESSAGE_BUNDLE_KEY_PASSPHRASE, passphrase); 683 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_OOB, isOutOfBand); 684 mSm.sendMessage(msg); 685 } 686 687 /** 688 * Command to terminate the specified data-path. 689 */ 690 public void endDataPath(int ndpId) { 691 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 692 msg.arg1 = COMMAND_TYPE_END_DATA_PATH; 693 msg.arg2 = ndpId; 694 mSm.sendMessage(msg); 695 } 696 697 /** 698 * Aware follow-on messages (L2 messages) are queued by the firmware for transmission 699 * on-the-air. The firmware has limited queue depth. The host queues all messages and doles 700 * them out to the firmware when possible. This command removes the next messages for 701 * transmission from the host queue and attempts to send it through the firmware. The queues 702 * are inspected when the command is executed - not when the command is placed on the handler 703 * (i.e. not evaluated here). 704 */ 705 private void transmitNextMessage() { 706 Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); 707 msg.arg1 = COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE; 708 mSm.sendMessage(msg); 709 } 710 711 /* 712 * RESPONSES 713 */ 714 715 /** 716 * Place a callback request on the state machine queue: configuration 717 * request completed (successfully). 718 */ 719 public void onConfigSuccessResponse(short transactionId) { 720 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 721 msg.arg1 = RESPONSE_TYPE_ON_CONFIG_SUCCESS; 722 msg.arg2 = transactionId; 723 mSm.sendMessage(msg); 724 } 725 726 /** 727 * Place a callback request on the state machine queue: configuration 728 * request failed. 729 */ 730 public void onConfigFailedResponse(short transactionId, int reason) { 731 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 732 msg.arg1 = RESPONSE_TYPE_ON_CONFIG_FAIL; 733 msg.arg2 = transactionId; 734 msg.obj = reason; 735 mSm.sendMessage(msg); 736 } 737 738 /** 739 * Place a callback request on the stage machine queue: disable request finished 740 * (with the provided reason code). 741 */ 742 public void onDisableResponse(short transactionId, int reason) { 743 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 744 msg.arg1 = RESPONSE_TYPE_ON_DISABLE; 745 msg.arg2 = transactionId; 746 msg.obj = reason; 747 mSm.sendMessage(msg); 748 } 749 750 /** 751 * Place a callback request on the state machine queue: session 752 * configuration (new or update) request succeeded. 753 */ 754 public void onSessionConfigSuccessResponse(short transactionId, boolean isPublish, 755 byte pubSubId) { 756 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 757 msg.arg1 = RESPONSE_TYPE_ON_SESSION_CONFIG_SUCCESS; 758 msg.arg2 = transactionId; 759 msg.obj = pubSubId; 760 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SESSION_TYPE, isPublish); 761 mSm.sendMessage(msg); 762 } 763 764 /** 765 * Place a callback request on the state machine queue: session 766 * configuration (new or update) request failed. 767 */ 768 public void onSessionConfigFailResponse(short transactionId, boolean isPublish, int reason) { 769 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 770 msg.arg1 = RESPONSE_TYPE_ON_SESSION_CONFIG_FAIL; 771 msg.arg2 = transactionId; 772 msg.obj = reason; 773 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SESSION_TYPE, isPublish); 774 mSm.sendMessage(msg); 775 } 776 777 /** 778 * Place a callback request on the state machine queue: message has been queued successfully. 779 */ 780 public void onMessageSendQueuedSuccessResponse(short transactionId) { 781 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 782 msg.arg1 = RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_SUCCESS; 783 msg.arg2 = transactionId; 784 mSm.sendMessage(msg); 785 } 786 787 /** 788 * Place a callback request on the state machine queue: attempt to queue the message failed. 789 */ 790 public void onMessageSendQueuedFailResponse(short transactionId, int reason) { 791 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 792 msg.arg1 = RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_FAIL; 793 msg.arg2 = transactionId; 794 msg.obj = reason; 795 mSm.sendMessage(msg); 796 } 797 798 /** 799 * Place a callback request on the state machine queue: update vendor 800 * capabilities of the Aware stack. 801 */ 802 public void onCapabilitiesUpdateResponse(short transactionId, 803 Capabilities capabilities) { 804 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 805 msg.arg1 = RESPONSE_TYPE_ON_CAPABILITIES_UPDATED; 806 msg.arg2 = transactionId; 807 msg.obj = capabilities; 808 mSm.sendMessage(msg); 809 } 810 811 /** 812 * Places a callback request on the state machine queue: data-path interface creation command 813 * completed. 814 */ 815 public void onCreateDataPathInterfaceResponse(short transactionId, boolean success, 816 int reasonOnFailure) { 817 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 818 msg.arg1 = RESPONSE_TYPE_ON_CREATE_INTERFACE; 819 msg.arg2 = transactionId; 820 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG, success); 821 msg.getData().putInt(MESSAGE_BUNDLE_KEY_STATUS_CODE, reasonOnFailure); 822 mSm.sendMessage(msg); 823 } 824 825 /** 826 * Places a callback request on the state machine queue: data-path interface deletion command 827 * completed. 828 */ 829 public void onDeleteDataPathInterfaceResponse(short transactionId, boolean success, 830 int reasonOnFailure) { 831 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 832 msg.arg1 = RESPONSE_TYPE_ON_DELETE_INTERFACE; 833 msg.arg2 = transactionId; 834 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG, success); 835 msg.getData().putInt(MESSAGE_BUNDLE_KEY_STATUS_CODE, reasonOnFailure); 836 mSm.sendMessage(msg); 837 } 838 839 /** 840 * Response from firmware to initiateDataPathSetup(...). Indicates that command has started 841 * succesfully (not completed!). 842 */ 843 public void onInitiateDataPathResponseSuccess(short transactionId, int ndpId) { 844 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 845 msg.arg1 = RESPONSE_TYPE_ON_INITIATE_DATA_PATH_SUCCESS; 846 msg.arg2 = transactionId; 847 msg.obj = ndpId; 848 mSm.sendMessage(msg); 849 } 850 851 /** 852 * Response from firmware to initiateDataPathSetup(...). 853 * Indicates that command has failed. 854 */ 855 public void onInitiateDataPathResponseFail(short transactionId, int reason) { 856 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 857 msg.arg1 = RESPONSE_TYPE_ON_INITIATE_DATA_PATH_FAIL; 858 msg.arg2 = transactionId; 859 msg.obj = reason; 860 mSm.sendMessage(msg); 861 } 862 863 /** 864 * Response from firmware to 865 * {@link #respondToDataPathRequest(boolean, int, String, byte[], String, boolean)} 866 */ 867 public void onRespondToDataPathSetupRequestResponse(short transactionId, boolean success, 868 int reasonOnFailure) { 869 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 870 msg.arg1 = RESPONSE_TYPE_ON_RESPOND_TO_DATA_PATH_SETUP_REQUEST; 871 msg.arg2 = transactionId; 872 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG, success); 873 msg.getData().putInt(MESSAGE_BUNDLE_KEY_STATUS_CODE, reasonOnFailure); 874 mSm.sendMessage(msg); 875 } 876 877 /** 878 * Response from firmware to {@link #endDataPath(int)}. 879 */ 880 public void onEndDataPathResponse(short transactionId, boolean success, int reasonOnFailure) { 881 Message msg = mSm.obtainMessage(MESSAGE_TYPE_RESPONSE); 882 msg.arg1 = RESPONSE_TYPE_ON_END_DATA_PATH; 883 msg.arg2 = transactionId; 884 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG, success); 885 msg.getData().putInt(MESSAGE_BUNDLE_KEY_STATUS_CODE, reasonOnFailure); 886 mSm.sendMessage(msg); 887 } 888 889 /* 890 * NOTIFICATIONS 891 */ 892 893 /** 894 * Place a callback request on the state machine queue: the discovery 895 * interface has changed. 896 */ 897 public void onInterfaceAddressChangeNotification(byte[] mac) { 898 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 899 msg.arg1 = NOTIFICATION_TYPE_INTERFACE_CHANGE; 900 msg.obj = mac; 901 mSm.sendMessage(msg); 902 } 903 904 /** 905 * Place a callback request on the state machine queue: the cluster 906 * membership has changed (e.g. due to starting a new cluster or joining 907 * another cluster). 908 */ 909 public void onClusterChangeNotification(int flag, byte[] clusterId) { 910 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 911 msg.arg1 = NOTIFICATION_TYPE_CLUSTER_CHANGE; 912 msg.arg2 = flag; 913 msg.obj = clusterId; 914 mSm.sendMessage(msg); 915 } 916 917 /** 918 * Place a callback request on the state machine queue: a discovery match 919 * has occurred - e.g. our subscription discovered someone else publishing a 920 * matching service (to the one we were looking for). 921 */ 922 public void onMatchNotification(int pubSubId, int requestorInstanceId, byte[] peerMac, 923 byte[] serviceSpecificInfo, byte[] matchFilter) { 924 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 925 msg.arg1 = NOTIFICATION_TYPE_MATCH; 926 msg.arg2 = pubSubId; 927 msg.getData().putInt(MESSAGE_BUNDLE_KEY_REQ_INSTANCE_ID, requestorInstanceId); 928 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS, peerMac); 929 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_SSI_DATA, serviceSpecificInfo); 930 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_FILTER_DATA, matchFilter); 931 mSm.sendMessage(msg); 932 } 933 934 /** 935 * Place a callback request on the state machine queue: a session (publish 936 * or subscribe) has terminated (per plan or due to an error). 937 */ 938 public void onSessionTerminatedNotification(int pubSubId, int reason, boolean isPublish) { 939 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 940 msg.arg1 = NOTIFICATION_TYPE_SESSION_TERMINATED; 941 msg.arg2 = pubSubId; 942 msg.obj = reason; 943 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SESSION_TYPE, isPublish); 944 mSm.sendMessage(msg); 945 } 946 947 /** 948 * Place a callback request on the state machine queue: a message has been 949 * received as part of a discovery session. 950 */ 951 public void onMessageReceivedNotification(int pubSubId, int requestorInstanceId, byte[] peerMac, 952 byte[] message) { 953 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 954 msg.arg1 = NOTIFICATION_TYPE_MESSAGE_RECEIVED; 955 msg.arg2 = pubSubId; 956 msg.obj = requestorInstanceId; 957 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS, peerMac); 958 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE_DATA, message); 959 mSm.sendMessage(msg); 960 } 961 962 /** 963 * Place a callback request on the state machine queue: Aware is going down. 964 */ 965 public void onAwareDownNotification(int reason) { 966 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 967 msg.arg1 = NOTIFICATION_TYPE_AWARE_DOWN; 968 msg.arg2 = reason; 969 mSm.sendMessage(msg); 970 } 971 972 /** 973 * Notification that a message has been sent successfully (i.e. an ACK has been received). 974 */ 975 public void onMessageSendSuccessNotification(short transactionId) { 976 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 977 msg.arg1 = NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS; 978 msg.arg2 = transactionId; 979 mSm.sendMessage(msg); 980 } 981 982 /** 983 * Notification that a message transmission has failed due to the indicated reason - e.g. no ACK 984 * was received. 985 */ 986 public void onMessageSendFailNotification(short transactionId, int reason) { 987 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 988 msg.arg1 = NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL; 989 msg.arg2 = transactionId; 990 msg.obj = reason; 991 mSm.sendMessage(msg); 992 } 993 994 /** 995 * Place a callback request on the state machine queue: data-path request (from peer) received. 996 */ 997 public void onDataPathRequestNotification(int pubSubId, byte[] mac, int ndpId) { 998 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 999 msg.arg1 = NOTIFICATION_TYPE_ON_DATA_PATH_REQUEST; 1000 msg.arg2 = pubSubId; 1001 msg.obj = ndpId; 1002 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS, mac); 1003 mSm.sendMessage(msg); 1004 } 1005 1006 /** 1007 * Place a callback request on the state machine queue: data-path confirmation received - i.e. 1008 * data-path is now up. 1009 */ 1010 public void onDataPathConfirmNotification(int ndpId, byte[] mac, boolean accept, int reason, 1011 byte[] message) { 1012 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 1013 msg.arg1 = NOTIFICATION_TYPE_ON_DATA_PATH_CONFIRM; 1014 msg.arg2 = ndpId; 1015 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS, mac); 1016 msg.getData().putBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG, accept); 1017 msg.getData().putInt(MESSAGE_BUNDLE_KEY_STATUS_CODE, reason); 1018 msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE_DATA, message); 1019 mSm.sendMessage(msg); 1020 } 1021 1022 /** 1023 * Place a callback request on the state machine queue: the specified data-path has been 1024 * terminated. 1025 */ 1026 public void onDataPathEndNotification(int ndpId) { 1027 Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION); 1028 msg.arg1 = NOTIFICATION_TYPE_ON_DATA_PATH_END; 1029 msg.arg2 = ndpId; 1030 mSm.sendMessage(msg); 1031 } 1032 1033 /** 1034 * State machine. 1035 */ 1036 @VisibleForTesting 1037 class WifiAwareStateMachine extends StateMachine { 1038 private static final int TRANSACTION_ID_IGNORE = 0; 1039 1040 private DefaultState mDefaultState = new DefaultState(); 1041 private WaitState mWaitState = new WaitState(); 1042 private WaitForResponseState mWaitForResponseState = new WaitForResponseState(); 1043 1044 private short mNextTransactionId = 1; 1045 public int mNextSessionId = 1; 1046 1047 private Message mCurrentCommand; 1048 private short mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1049 1050 private static final long AWARE_SEND_MESSAGE_TIMEOUT = 10_000; 1051 private int mSendArrivalSequenceCounter = 0; 1052 private boolean mSendQueueBlocked = false; 1053 private final SparseArray<Message> mHostQueuedSendMessages = new SparseArray<>(); 1054 private final Map<Short, Message> mFwQueuedSendMessages = new LinkedHashMap<>(); 1055 private WakeupMessage mSendMessageTimeoutMessage = new WakeupMessage(mContext, getHandler(), 1056 HAL_SEND_MESSAGE_TIMEOUT_TAG, MESSAGE_TYPE_SEND_MESSAGE_TIMEOUT); 1057 1058 private static final long AWARE_WAIT_FOR_DP_CONFIRM_TIMEOUT = 20_000; 1059 private final Map<WifiAwareNetworkSpecifier, WakeupMessage> 1060 mDataPathConfirmTimeoutMessages = new ArrayMap<>(); 1061 1062 WifiAwareStateMachine(String name, Looper looper) { 1063 super(name, looper); 1064 1065 addState(mDefaultState); 1066 /* --> */ addState(mWaitState, mDefaultState); 1067 /* --> */ addState(mWaitForResponseState, mDefaultState); 1068 1069 setInitialState(mWaitState); 1070 } 1071 1072 public void onAwareDownCleanupSendQueueState() { 1073 mSendQueueBlocked = false; 1074 mHostQueuedSendMessages.clear(); 1075 mFwQueuedSendMessages.clear(); 1076 } 1077 1078 private class DefaultState extends State { 1079 @Override 1080 public boolean processMessage(Message msg) { 1081 if (VDBG) { 1082 Log.v(TAG, getName() + msg.toString()); 1083 } 1084 1085 switch (msg.what) { 1086 case MESSAGE_TYPE_NOTIFICATION: 1087 processNotification(msg); 1088 return HANDLED; 1089 case MESSAGE_TYPE_SEND_MESSAGE_TIMEOUT: 1090 processSendMessageTimeout(); 1091 return HANDLED; 1092 case MESSAGE_TYPE_DATA_PATH_TIMEOUT: { 1093 WifiAwareNetworkSpecifier networkSpecifier = 1094 (WifiAwareNetworkSpecifier) msg.obj; 1095 1096 if (VDBG) { 1097 Log.v(TAG, "MESSAGE_TYPE_DATA_PATH_TIMEOUT: networkSpecifier=" 1098 + networkSpecifier); 1099 } 1100 1101 mDataPathMgr.handleDataPathTimeout(networkSpecifier); 1102 mDataPathConfirmTimeoutMessages.remove(networkSpecifier); 1103 return HANDLED; 1104 } 1105 default: 1106 /* fall-through */ 1107 } 1108 1109 Log.wtf(TAG, 1110 "DefaultState: should not get non-NOTIFICATION in this state: msg=" + msg); 1111 return NOT_HANDLED; 1112 } 1113 } 1114 1115 private class WaitState extends State { 1116 @Override 1117 public boolean processMessage(Message msg) { 1118 if (VDBG) { 1119 Log.v(TAG, getName() + msg.toString()); 1120 } 1121 1122 switch (msg.what) { 1123 case MESSAGE_TYPE_COMMAND: 1124 if (processCommand(msg)) { 1125 transitionTo(mWaitForResponseState); 1126 } 1127 return HANDLED; 1128 case MESSAGE_TYPE_RESPONSE: 1129 /* fall-through */ 1130 case MESSAGE_TYPE_RESPONSE_TIMEOUT: 1131 /* 1132 * remnants/delayed/out-of-sync messages - but let 1133 * WaitForResponseState deal with them (identified as 1134 * out-of-date by transaction ID). 1135 */ 1136 deferMessage(msg); 1137 return HANDLED; 1138 default: 1139 /* fall-through */ 1140 } 1141 1142 return NOT_HANDLED; 1143 } 1144 } 1145 1146 private class WaitForResponseState extends State { 1147 private static final long AWARE_COMMAND_TIMEOUT = 5_000; 1148 private WakeupMessage mTimeoutMessage; 1149 1150 @Override 1151 public void enter() { 1152 mTimeoutMessage = new WakeupMessage(mContext, getHandler(), HAL_COMMAND_TIMEOUT_TAG, 1153 MESSAGE_TYPE_RESPONSE_TIMEOUT, mCurrentCommand.arg1, mCurrentTransactionId); 1154 mTimeoutMessage.schedule(SystemClock.elapsedRealtime() + AWARE_COMMAND_TIMEOUT); 1155 } 1156 1157 @Override 1158 public void exit() { 1159 mTimeoutMessage.cancel(); 1160 } 1161 1162 @Override 1163 public boolean processMessage(Message msg) { 1164 if (VDBG) { 1165 Log.v(TAG, getName() + msg.toString()); 1166 } 1167 1168 switch (msg.what) { 1169 case MESSAGE_TYPE_COMMAND: 1170 /* 1171 * don't want COMMANDs in this state - defer until back 1172 * in WaitState 1173 */ 1174 deferMessage(msg); 1175 return HANDLED; 1176 case MESSAGE_TYPE_RESPONSE: 1177 if (msg.arg2 == mCurrentTransactionId) { 1178 processResponse(msg); 1179 transitionTo(mWaitState); 1180 } else { 1181 Log.w(TAG, 1182 "WaitForResponseState: processMessage: non-matching " 1183 + "transaction ID on RESPONSE (a very late " 1184 + "response) -- msg=" + msg); 1185 /* no transition */ 1186 } 1187 return HANDLED; 1188 case MESSAGE_TYPE_RESPONSE_TIMEOUT: 1189 if (msg.arg2 == mCurrentTransactionId) { 1190 processTimeout(msg); 1191 transitionTo(mWaitState); 1192 } else { 1193 Log.w(TAG, "WaitForResponseState: processMessage: non-matching " 1194 + "transaction ID on RESPONSE_TIMEOUT (either a non-cancelled " 1195 + "timeout or a race condition with cancel) -- msg=" + msg); 1196 /* no transition */ 1197 } 1198 return HANDLED; 1199 default: 1200 /* fall-through */ 1201 } 1202 1203 return NOT_HANDLED; 1204 } 1205 } 1206 1207 private void processNotification(Message msg) { 1208 if (VDBG) { 1209 Log.v(TAG, "processNotification: msg=" + msg); 1210 } 1211 1212 switch (msg.arg1) { 1213 case NOTIFICATION_TYPE_INTERFACE_CHANGE: { 1214 byte[] mac = (byte[]) msg.obj; 1215 1216 onInterfaceAddressChangeLocal(mac); 1217 break; 1218 } 1219 case NOTIFICATION_TYPE_CLUSTER_CHANGE: { 1220 int flag = msg.arg2; 1221 byte[] clusterId = (byte[]) msg.obj; 1222 1223 onClusterChangeLocal(flag, clusterId); 1224 break; 1225 } 1226 case NOTIFICATION_TYPE_MATCH: { 1227 int pubSubId = msg.arg2; 1228 int requestorInstanceId = msg.getData() 1229 .getInt(MESSAGE_BUNDLE_KEY_REQ_INSTANCE_ID); 1230 byte[] peerMac = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS); 1231 byte[] serviceSpecificInfo = msg.getData() 1232 .getByteArray(MESSAGE_BUNDLE_KEY_SSI_DATA); 1233 byte[] matchFilter = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_FILTER_DATA); 1234 1235 onMatchLocal(pubSubId, requestorInstanceId, peerMac, serviceSpecificInfo, 1236 matchFilter); 1237 break; 1238 } 1239 case NOTIFICATION_TYPE_SESSION_TERMINATED: { 1240 int pubSubId = msg.arg2; 1241 int reason = (Integer) msg.obj; 1242 boolean isPublish = msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SESSION_TYPE); 1243 1244 onSessionTerminatedLocal(pubSubId, isPublish, reason); 1245 break; 1246 } 1247 case NOTIFICATION_TYPE_MESSAGE_RECEIVED: { 1248 int pubSubId = msg.arg2; 1249 int requestorInstanceId = (Integer) msg.obj; 1250 byte[] peerMac = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS); 1251 byte[] message = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE_DATA); 1252 1253 onMessageReceivedLocal(pubSubId, requestorInstanceId, peerMac, message); 1254 break; 1255 } 1256 case NOTIFICATION_TYPE_AWARE_DOWN: { 1257 int reason = msg.arg2; 1258 1259 /* 1260 * TODO: b/28615938. Use reason code to determine whether or not need clean-up 1261 * local state (only needed if AWARE_DOWN is due to internal firmware reason, 1262 * e.g. concurrency, rather than due to a requested shutdown). 1263 */ 1264 1265 onAwareDownLocal(); 1266 1267 break; 1268 } 1269 case NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS: { 1270 short transactionId = (short) msg.arg2; 1271 Message queuedSendCommand = mFwQueuedSendMessages.get(transactionId); 1272 if (VDBG) { 1273 Log.v(TAG, "NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS: queuedSendCommand=" 1274 + queuedSendCommand); 1275 } 1276 if (queuedSendCommand == null) { 1277 Log.w(TAG, 1278 "processNotification: NOTIFICATION_TYPE_ON_MESSAGE_SEND_SUCCESS:" 1279 + " transactionId=" + transactionId 1280 + " - no such queued send command (timed-out?)"); 1281 } else { 1282 mFwQueuedSendMessages.remove(transactionId); 1283 updateSendMessageTimeout(); 1284 onMessageSendSuccessLocal(queuedSendCommand); 1285 } 1286 mSendQueueBlocked = false; 1287 transmitNextMessage(); 1288 1289 break; 1290 } 1291 case NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL: { 1292 short transactionId = (short) msg.arg2; 1293 int reason = (Integer) msg.obj; 1294 Message sentMessage = mFwQueuedSendMessages.get(transactionId); 1295 if (VDBG) { 1296 Log.v(TAG, "NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL: sentMessage=" 1297 + sentMessage); 1298 } 1299 if (sentMessage == null) { 1300 Log.w(TAG, 1301 "processNotification: NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL:" 1302 + " transactionId=" + transactionId 1303 + " - no such queued send command (timed-out?)"); 1304 } else { 1305 mFwQueuedSendMessages.remove(transactionId); 1306 updateSendMessageTimeout(); 1307 1308 int retryCount = sentMessage.getData() 1309 .getInt(MESSAGE_BUNDLE_KEY_RETRY_COUNT); 1310 if (retryCount > 0 && reason == NanStatusType.NO_OTA_ACK) { 1311 if (DBG) { 1312 Log.d(TAG, 1313 "NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL: transactionId=" 1314 + transactionId + ", reason=" + reason 1315 + ": retransmitting - retryCount=" + retryCount); 1316 } 1317 sentMessage.getData().putInt(MESSAGE_BUNDLE_KEY_RETRY_COUNT, 1318 retryCount - 1); 1319 1320 int arrivalSeq = sentMessage.getData().getInt( 1321 MESSAGE_BUNDLE_KEY_MESSAGE_ARRIVAL_SEQ); 1322 mHostQueuedSendMessages.put(arrivalSeq, sentMessage); 1323 } else { 1324 onMessageSendFailLocal(sentMessage, reason); 1325 } 1326 mSendQueueBlocked = false; 1327 transmitNextMessage(); 1328 } 1329 break; 1330 } 1331 case NOTIFICATION_TYPE_ON_DATA_PATH_REQUEST: { 1332 WifiAwareNetworkSpecifier networkSpecifier = mDataPathMgr.onDataPathRequest( 1333 msg.arg2, msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS), 1334 (int) msg.obj); 1335 1336 if (networkSpecifier != null) { 1337 WakeupMessage timeout = new WakeupMessage(mContext, getHandler(), 1338 HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG, MESSAGE_TYPE_DATA_PATH_TIMEOUT, 1339 0, 0, networkSpecifier); 1340 mDataPathConfirmTimeoutMessages.put(networkSpecifier, timeout); 1341 timeout.schedule( 1342 SystemClock.elapsedRealtime() + AWARE_WAIT_FOR_DP_CONFIRM_TIMEOUT); 1343 } 1344 1345 break; 1346 } 1347 case NOTIFICATION_TYPE_ON_DATA_PATH_CONFIRM: { 1348 WifiAwareNetworkSpecifier networkSpecifier = mDataPathMgr.onDataPathConfirm( 1349 msg.arg2, msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS), 1350 msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG), 1351 msg.getData().getInt(MESSAGE_BUNDLE_KEY_STATUS_CODE), 1352 msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE_DATA)); 1353 1354 if (networkSpecifier != null) { 1355 WakeupMessage timeout = mDataPathConfirmTimeoutMessages.remove( 1356 networkSpecifier); 1357 if (timeout != null) { 1358 timeout.cancel(); 1359 } 1360 } 1361 1362 break; 1363 } 1364 case NOTIFICATION_TYPE_ON_DATA_PATH_END: 1365 mDataPathMgr.onDataPathEnd(msg.arg2); 1366 break; 1367 default: 1368 Log.wtf(TAG, "processNotification: this isn't a NOTIFICATION -- msg=" + msg); 1369 return; 1370 } 1371 } 1372 1373 /** 1374 * Execute the command specified by the input Message. Returns a true if 1375 * need to wait for a RESPONSE, otherwise a false. We may not have to 1376 * wait for a RESPONSE if there was an error in the state (so no command 1377 * is sent to HAL) OR if we choose not to wait for response - e.g. for 1378 * disconnected/terminate commands failure is not possible. 1379 */ 1380 private boolean processCommand(Message msg) { 1381 if (VDBG) { 1382 Log.v(TAG, "processCommand: msg=" + msg); 1383 } 1384 1385 if (mCurrentCommand != null) { 1386 Log.wtf(TAG, 1387 "processCommand: receiving a command (msg=" + msg 1388 + ") but current (previous) command isn't null (prev_msg=" 1389 + mCurrentCommand + ")"); 1390 mCurrentCommand = null; 1391 } 1392 1393 mCurrentTransactionId = mNextTransactionId++; 1394 1395 boolean waitForResponse = true; 1396 1397 switch (msg.arg1) { 1398 case COMMAND_TYPE_CONNECT: { 1399 int clientId = msg.arg2; 1400 IWifiAwareEventCallback callback = (IWifiAwareEventCallback) msg.obj; 1401 ConfigRequest configRequest = (ConfigRequest) msg.getData() 1402 .getParcelable(MESSAGE_BUNDLE_KEY_CONFIG); 1403 int uid = msg.getData().getInt(MESSAGE_BUNDLE_KEY_UID); 1404 int pid = msg.getData().getInt(MESSAGE_BUNDLE_KEY_PID); 1405 String callingPackage = msg.getData().getString( 1406 MESSAGE_BUNDLE_KEY_CALLING_PACKAGE); 1407 boolean notifyIdentityChange = msg.getData().getBoolean( 1408 MESSAGE_BUNDLE_KEY_NOTIFY_IDENTITY_CHANGE); 1409 1410 waitForResponse = connectLocal(mCurrentTransactionId, clientId, uid, pid, 1411 callingPackage, callback, configRequest, notifyIdentityChange); 1412 break; 1413 } 1414 case COMMAND_TYPE_DISCONNECT: { 1415 int clientId = msg.arg2; 1416 1417 waitForResponse = disconnectLocal(mCurrentTransactionId, clientId); 1418 break; 1419 } 1420 case COMMAND_TYPE_RECONFIGURE: 1421 waitForResponse = reconfigureLocal(mCurrentTransactionId); 1422 break; 1423 case COMMAND_TYPE_TERMINATE_SESSION: { 1424 int clientId = msg.arg2; 1425 int sessionId = (Integer) msg.obj; 1426 1427 terminateSessionLocal(clientId, sessionId); 1428 waitForResponse = false; 1429 break; 1430 } 1431 case COMMAND_TYPE_PUBLISH: { 1432 int clientId = msg.arg2; 1433 IWifiAwareDiscoverySessionCallback callback = 1434 (IWifiAwareDiscoverySessionCallback) msg.obj; 1435 PublishConfig publishConfig = (PublishConfig) msg.getData() 1436 .getParcelable(MESSAGE_BUNDLE_KEY_CONFIG); 1437 1438 waitForResponse = publishLocal(mCurrentTransactionId, clientId, publishConfig, 1439 callback); 1440 break; 1441 } 1442 case COMMAND_TYPE_UPDATE_PUBLISH: { 1443 int clientId = msg.arg2; 1444 int sessionId = msg.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 1445 PublishConfig publishConfig = (PublishConfig) msg.obj; 1446 1447 waitForResponse = updatePublishLocal(mCurrentTransactionId, clientId, sessionId, 1448 publishConfig); 1449 break; 1450 } 1451 case COMMAND_TYPE_SUBSCRIBE: { 1452 int clientId = msg.arg2; 1453 IWifiAwareDiscoverySessionCallback callback = 1454 (IWifiAwareDiscoverySessionCallback) msg.obj; 1455 SubscribeConfig subscribeConfig = (SubscribeConfig) msg.getData() 1456 .getParcelable(MESSAGE_BUNDLE_KEY_CONFIG); 1457 1458 waitForResponse = subscribeLocal(mCurrentTransactionId, clientId, 1459 subscribeConfig, callback); 1460 break; 1461 } 1462 case COMMAND_TYPE_UPDATE_SUBSCRIBE: { 1463 int clientId = msg.arg2; 1464 int sessionId = msg.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 1465 SubscribeConfig subscribeConfig = (SubscribeConfig) msg.obj; 1466 1467 waitForResponse = updateSubscribeLocal(mCurrentTransactionId, clientId, 1468 sessionId, subscribeConfig); 1469 break; 1470 } 1471 case COMMAND_TYPE_ENQUEUE_SEND_MESSAGE: { 1472 if (VDBG) { 1473 Log.v(TAG, "processCommand: ENQUEUE_SEND_MESSAGE - messageId=" 1474 + msg.getData().getInt(MESSAGE_BUNDLE_KEY_MESSAGE_ID) 1475 + ", mSendArrivalSequenceCounter=" + mSendArrivalSequenceCounter); 1476 } 1477 Message sendMsg = obtainMessage(msg.what); 1478 sendMsg.copyFrom(msg); 1479 sendMsg.getData().putInt(MESSAGE_BUNDLE_KEY_MESSAGE_ARRIVAL_SEQ, 1480 mSendArrivalSequenceCounter); 1481 mHostQueuedSendMessages.put(mSendArrivalSequenceCounter, sendMsg); 1482 mSendArrivalSequenceCounter++; 1483 waitForResponse = false; 1484 1485 if (!mSendQueueBlocked) { 1486 transmitNextMessage(); 1487 } 1488 1489 break; 1490 } 1491 case COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE: { 1492 if (mSendQueueBlocked || mHostQueuedSendMessages.size() == 0) { 1493 if (VDBG) { 1494 Log.v(TAG, "processCommand: SEND_TOP_OF_QUEUE_MESSAGE - blocked or " 1495 + "empty host queue"); 1496 } 1497 waitForResponse = false; 1498 } else { 1499 if (VDBG) { 1500 Log.v(TAG, "processCommand: SEND_TOP_OF_QUEUE_MESSAGE - " 1501 + "sendArrivalSequenceCounter=" 1502 + mHostQueuedSendMessages.keyAt(0)); 1503 } 1504 Message sendMessage = mHostQueuedSendMessages.valueAt(0); 1505 mHostQueuedSendMessages.removeAt(0); 1506 1507 Bundle data = sendMessage.getData(); 1508 int clientId = sendMessage.arg2; 1509 int sessionId = sendMessage.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 1510 int peerId = data.getInt(MESSAGE_BUNDLE_KEY_MESSAGE_PEER_ID); 1511 byte[] message = data.getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE); 1512 int messageId = data.getInt(MESSAGE_BUNDLE_KEY_MESSAGE_ID); 1513 1514 msg.getData().putParcelable(MESSAGE_BUNDLE_KEY_SENT_MESSAGE, sendMessage); 1515 1516 waitForResponse = sendFollowonMessageLocal(mCurrentTransactionId, clientId, 1517 sessionId, peerId, message, messageId); 1518 } 1519 break; 1520 } 1521 case COMMAND_TYPE_ENABLE_USAGE: 1522 enableUsageLocal(); 1523 waitForResponse = false; 1524 break; 1525 case COMMAND_TYPE_DISABLE_USAGE: 1526 waitForResponse = disableUsageLocal(mCurrentTransactionId); 1527 break; 1528 case COMMAND_TYPE_START_RANGING: { 1529 Bundle data = msg.getData(); 1530 1531 int clientId = msg.arg2; 1532 RttManager.RttParams[] params = (RttManager.RttParams[]) msg.obj; 1533 int sessionId = data.getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 1534 int rangingId = data.getInt(MESSAGE_BUNDLE_KEY_RANGING_ID); 1535 1536 startRangingLocal(clientId, sessionId, params, rangingId); 1537 waitForResponse = false; 1538 break; 1539 } 1540 case COMMAND_TYPE_GET_CAPABILITIES: 1541 if (mCapabilities == null) { 1542 waitForResponse = mWifiAwareNativeApi.getCapabilities( 1543 mCurrentTransactionId); 1544 } else { 1545 if (VDBG) { 1546 Log.v(TAG, "COMMAND_TYPE_GET_CAPABILITIES: already have capabilities - " 1547 + "skipping"); 1548 } 1549 waitForResponse = false; 1550 } 1551 break; 1552 case COMMAND_TYPE_CREATE_ALL_DATA_PATH_INTERFACES: 1553 mDataPathMgr.createAllInterfaces(); 1554 waitForResponse = false; 1555 break; 1556 case COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES: 1557 mDataPathMgr.deleteAllInterfaces(); 1558 waitForResponse = false; 1559 break; 1560 case COMMAND_TYPE_CREATE_DATA_PATH_INTERFACE: 1561 waitForResponse = mWifiAwareNativeApi.createAwareNetworkInterface( 1562 mCurrentTransactionId, (String) msg.obj); 1563 break; 1564 case COMMAND_TYPE_DELETE_DATA_PATH_INTERFACE: 1565 waitForResponse = mWifiAwareNativeApi.deleteAwareNetworkInterface( 1566 mCurrentTransactionId, (String) msg.obj); 1567 break; 1568 case COMMAND_TYPE_INITIATE_DATA_PATH_SETUP: { 1569 Bundle data = msg.getData(); 1570 1571 WifiAwareNetworkSpecifier networkSpecifier = 1572 (WifiAwareNetworkSpecifier) msg.obj; 1573 1574 int peerId = data.getInt(MESSAGE_BUNDLE_KEY_PEER_ID); 1575 int channelRequestType = data.getInt(MESSAGE_BUNDLE_KEY_CHANNEL_REQ_TYPE); 1576 int channel = data.getInt(MESSAGE_BUNDLE_KEY_CHANNEL); 1577 byte[] peer = data.getByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS); 1578 String interfaceName = data.getString(MESSAGE_BUNDLE_KEY_INTERFACE_NAME); 1579 byte[] pmk = data.getByteArray(MESSAGE_BUNDLE_KEY_PMK); 1580 String passphrase = data.getString(MESSAGE_BUNDLE_KEY_PASSPHRASE); 1581 boolean isOutOfBand = data.getBoolean(MESSAGE_BUNDLE_KEY_OOB); 1582 1583 waitForResponse = initiateDataPathSetupLocal(mCurrentTransactionId, 1584 networkSpecifier, peerId, channelRequestType, channel, peer, 1585 interfaceName, pmk, passphrase, isOutOfBand); 1586 1587 if (waitForResponse) { 1588 WakeupMessage timeout = new WakeupMessage(mContext, getHandler(), 1589 HAL_DATA_PATH_CONFIRM_TIMEOUT_TAG, MESSAGE_TYPE_DATA_PATH_TIMEOUT, 1590 0, 0, networkSpecifier); 1591 mDataPathConfirmTimeoutMessages.put(networkSpecifier, timeout); 1592 timeout.schedule( 1593 SystemClock.elapsedRealtime() + AWARE_WAIT_FOR_DP_CONFIRM_TIMEOUT); 1594 } 1595 break; 1596 } 1597 case COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST: { 1598 Bundle data = msg.getData(); 1599 1600 int ndpId = msg.arg2; 1601 boolean accept = (boolean) msg.obj; 1602 String interfaceName = data.getString(MESSAGE_BUNDLE_KEY_INTERFACE_NAME); 1603 byte[] pmk = data.getByteArray(MESSAGE_BUNDLE_KEY_PMK); 1604 String passphrase = data.getString(MESSAGE_BUNDLE_KEY_PASSPHRASE); 1605 boolean isOutOfBand = data.getBoolean(MESSAGE_BUNDLE_KEY_OOB); 1606 1607 waitForResponse = respondToDataPathRequestLocal(mCurrentTransactionId, accept, 1608 ndpId, interfaceName, pmk, passphrase, isOutOfBand); 1609 1610 break; 1611 } 1612 case COMMAND_TYPE_END_DATA_PATH: 1613 waitForResponse = endDataPathLocal(mCurrentTransactionId, msg.arg2); 1614 break; 1615 case COMMAND_TYPE_DELAYED_INITIALIZATION: 1616 mWifiAwareNativeManager.start(); 1617 mRtt.start(mContext, mSm.getHandler().getLooper()); 1618 waitForResponse = false; 1619 break; 1620 default: 1621 waitForResponse = false; 1622 Log.wtf(TAG, "processCommand: this isn't a COMMAND -- msg=" + msg); 1623 /* fall-through */ 1624 } 1625 1626 if (!waitForResponse) { 1627 mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1628 } else { 1629 mCurrentCommand = obtainMessage(msg.what); 1630 mCurrentCommand.copyFrom(msg); 1631 } 1632 1633 return waitForResponse; 1634 } 1635 1636 private void processResponse(Message msg) { 1637 if (VDBG) { 1638 Log.v(TAG, "processResponse: msg=" + msg); 1639 } 1640 1641 if (mCurrentCommand == null) { 1642 Log.wtf(TAG, "processResponse: no existing command stored!? msg=" + msg); 1643 mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1644 return; 1645 } 1646 1647 switch (msg.arg1) { 1648 case RESPONSE_TYPE_ON_CONFIG_SUCCESS: 1649 onConfigCompletedLocal(mCurrentCommand); 1650 break; 1651 case RESPONSE_TYPE_ON_CONFIG_FAIL: { 1652 int reason = (Integer) msg.obj; 1653 1654 onConfigFailedLocal(mCurrentCommand, reason); 1655 break; 1656 } 1657 case RESPONSE_TYPE_ON_SESSION_CONFIG_SUCCESS: { 1658 byte pubSubId = (Byte) msg.obj; 1659 boolean isPublish = msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SESSION_TYPE); 1660 1661 onSessionConfigSuccessLocal(mCurrentCommand, pubSubId, isPublish); 1662 break; 1663 } 1664 case RESPONSE_TYPE_ON_SESSION_CONFIG_FAIL: { 1665 int reason = (Integer) msg.obj; 1666 boolean isPublish = msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SESSION_TYPE); 1667 1668 onSessionConfigFailLocal(mCurrentCommand, isPublish, reason); 1669 break; 1670 } 1671 case RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_SUCCESS: { 1672 Message sentMessage = mCurrentCommand.getData().getParcelable( 1673 MESSAGE_BUNDLE_KEY_SENT_MESSAGE); 1674 sentMessage.getData().putLong(MESSAGE_BUNDLE_KEY_SEND_MESSAGE_ENQUEUE_TIME, 1675 SystemClock.elapsedRealtime()); 1676 mFwQueuedSendMessages.put(mCurrentTransactionId, sentMessage); 1677 updateSendMessageTimeout(); 1678 if (!mSendQueueBlocked) { 1679 transmitNextMessage(); 1680 } 1681 1682 if (VDBG) { 1683 Log.v(TAG, "processResponse: ON_MESSAGE_SEND_QUEUED_SUCCESS - arrivalSeq=" 1684 + sentMessage.getData().getInt( 1685 MESSAGE_BUNDLE_KEY_MESSAGE_ARRIVAL_SEQ)); 1686 } 1687 break; 1688 } 1689 case RESPONSE_TYPE_ON_MESSAGE_SEND_QUEUED_FAIL: { 1690 if (VDBG) { 1691 Log.v(TAG, "processResponse: ON_MESSAGE_SEND_QUEUED_FAIL - blocking!"); 1692 } 1693 int reason = (Integer) msg.obj; 1694 if (reason == NanStatusType.FOLLOWUP_TX_QUEUE_FULL) { 1695 Message sentMessage = mCurrentCommand.getData().getParcelable( 1696 MESSAGE_BUNDLE_KEY_SENT_MESSAGE); 1697 int arrivalSeq = sentMessage.getData().getInt( 1698 MESSAGE_BUNDLE_KEY_MESSAGE_ARRIVAL_SEQ); 1699 mHostQueuedSendMessages.put(arrivalSeq, sentMessage); 1700 mSendQueueBlocked = true; 1701 1702 if (VDBG) { 1703 Log.v(TAG, "processResponse: ON_MESSAGE_SEND_QUEUED_FAIL - arrivalSeq=" 1704 + arrivalSeq + " -- blocking"); 1705 } 1706 } else { 1707 Message sentMessage = mCurrentCommand.getData().getParcelable( 1708 MESSAGE_BUNDLE_KEY_SENT_MESSAGE); 1709 onMessageSendFailLocal(sentMessage, NanStatusType.INTERNAL_FAILURE); 1710 if (!mSendQueueBlocked) { 1711 transmitNextMessage(); 1712 } 1713 } 1714 break; 1715 } 1716 case RESPONSE_TYPE_ON_CAPABILITIES_UPDATED: { 1717 onCapabilitiesUpdatedResponseLocal((Capabilities) msg.obj); 1718 break; 1719 } 1720 case RESPONSE_TYPE_ON_CREATE_INTERFACE: 1721 onCreateDataPathInterfaceResponseLocal(mCurrentCommand, 1722 msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG), 1723 msg.getData().getInt(MESSAGE_BUNDLE_KEY_STATUS_CODE)); 1724 break; 1725 case RESPONSE_TYPE_ON_DELETE_INTERFACE: 1726 onDeleteDataPathInterfaceResponseLocal(mCurrentCommand, 1727 msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG), 1728 msg.getData().getInt(MESSAGE_BUNDLE_KEY_STATUS_CODE)); 1729 break; 1730 case RESPONSE_TYPE_ON_INITIATE_DATA_PATH_SUCCESS: 1731 onInitiateDataPathResponseSuccessLocal(mCurrentCommand, (int) msg.obj); 1732 break; 1733 case RESPONSE_TYPE_ON_INITIATE_DATA_PATH_FAIL: 1734 onInitiateDataPathResponseFailLocal(mCurrentCommand, (int) msg.obj); 1735 break; 1736 case RESPONSE_TYPE_ON_RESPOND_TO_DATA_PATH_SETUP_REQUEST: 1737 onRespondToDataPathSetupRequestResponseLocal(mCurrentCommand, 1738 msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG), 1739 msg.getData().getInt(MESSAGE_BUNDLE_KEY_STATUS_CODE)); 1740 break; 1741 case RESPONSE_TYPE_ON_END_DATA_PATH: 1742 onEndPathEndResponseLocal(mCurrentCommand, 1743 msg.getData().getBoolean(MESSAGE_BUNDLE_KEY_SUCCESS_FLAG), 1744 msg.getData().getInt(MESSAGE_BUNDLE_KEY_STATUS_CODE)); 1745 break; 1746 case RESPONSE_TYPE_ON_DISABLE: 1747 onDisableResponseLocal(mCurrentCommand, (Integer) msg.obj); 1748 break; 1749 default: 1750 Log.wtf(TAG, "processResponse: this isn't a RESPONSE -- msg=" + msg); 1751 mCurrentCommand = null; 1752 mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1753 return; 1754 } 1755 1756 mCurrentCommand = null; 1757 mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1758 } 1759 1760 private void processTimeout(Message msg) { 1761 if (VDBG) { 1762 Log.v(TAG, "processTimeout: msg=" + msg); 1763 } 1764 1765 if (mCurrentCommand == null) { 1766 Log.wtf(TAG, "processTimeout: no existing command stored!? msg=" + msg); 1767 mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1768 return; 1769 } 1770 1771 /* 1772 * Only have to handle those COMMANDs which wait for a response. 1773 */ 1774 switch (msg.arg1) { 1775 case COMMAND_TYPE_CONNECT: { 1776 onConfigFailedLocal(mCurrentCommand, NanStatusType.INTERNAL_FAILURE); 1777 break; 1778 } 1779 case COMMAND_TYPE_DISCONNECT: { 1780 onConfigFailedLocal(mCurrentCommand, NanStatusType.INTERNAL_FAILURE); 1781 break; 1782 } 1783 case COMMAND_TYPE_RECONFIGURE: 1784 /* 1785 * Reconfigure timed-out. There is nothing to do but log the issue - which 1786 * will be done in the callback. 1787 */ 1788 onConfigFailedLocal(mCurrentCommand, NanStatusType.INTERNAL_FAILURE); 1789 break; 1790 case COMMAND_TYPE_TERMINATE_SESSION: { 1791 Log.wtf(TAG, "processTimeout: TERMINATE_SESSION - shouldn't be waiting!"); 1792 break; 1793 } 1794 case COMMAND_TYPE_PUBLISH: { 1795 onSessionConfigFailLocal(mCurrentCommand, true, NanStatusType.INTERNAL_FAILURE); 1796 break; 1797 } 1798 case COMMAND_TYPE_UPDATE_PUBLISH: { 1799 onSessionConfigFailLocal(mCurrentCommand, true, NanStatusType.INTERNAL_FAILURE); 1800 break; 1801 } 1802 case COMMAND_TYPE_SUBSCRIBE: { 1803 onSessionConfigFailLocal(mCurrentCommand, false, 1804 NanStatusType.INTERNAL_FAILURE); 1805 break; 1806 } 1807 case COMMAND_TYPE_UPDATE_SUBSCRIBE: { 1808 onSessionConfigFailLocal(mCurrentCommand, false, 1809 NanStatusType.INTERNAL_FAILURE); 1810 break; 1811 } 1812 case COMMAND_TYPE_ENQUEUE_SEND_MESSAGE: { 1813 Log.wtf(TAG, "processTimeout: ENQUEUE_SEND_MESSAGE - shouldn't be waiting!"); 1814 break; 1815 } 1816 case COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE: { 1817 Message sentMessage = mCurrentCommand.getData().getParcelable( 1818 MESSAGE_BUNDLE_KEY_SENT_MESSAGE); 1819 onMessageSendFailLocal(sentMessage, NanStatusType.INTERNAL_FAILURE); 1820 mSendQueueBlocked = false; 1821 transmitNextMessage(); 1822 break; 1823 } 1824 case COMMAND_TYPE_ENABLE_USAGE: 1825 Log.wtf(TAG, "processTimeout: ENABLE_USAGE - shouldn't be waiting!"); 1826 break; 1827 case COMMAND_TYPE_DISABLE_USAGE: 1828 Log.wtf(TAG, "processTimeout: DISABLE_USAGE - shouldn't be waiting!"); 1829 break; 1830 case COMMAND_TYPE_START_RANGING: 1831 Log.wtf(TAG, "processTimeout: START_RANGING - shouldn't be waiting!"); 1832 break; 1833 case COMMAND_TYPE_GET_CAPABILITIES: 1834 Log.e(TAG, 1835 "processTimeout: GET_CAPABILITIES timed-out - strange, will try again" 1836 + " when next enabled!?"); 1837 break; 1838 case COMMAND_TYPE_CREATE_ALL_DATA_PATH_INTERFACES: 1839 Log.wtf(TAG, 1840 "processTimeout: CREATE_ALL_DATA_PATH_INTERFACES - shouldn't be " 1841 + "waiting!"); 1842 break; 1843 case COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES: 1844 Log.wtf(TAG, 1845 "processTimeout: DELETE_ALL_DATA_PATH_INTERFACES - shouldn't be " 1846 + "waiting!"); 1847 break; 1848 case COMMAND_TYPE_CREATE_DATA_PATH_INTERFACE: 1849 // TODO: fix status: timeout 1850 onCreateDataPathInterfaceResponseLocal(mCurrentCommand, false, 0); 1851 break; 1852 case COMMAND_TYPE_DELETE_DATA_PATH_INTERFACE: 1853 // TODO: fix status: timeout 1854 onDeleteDataPathInterfaceResponseLocal(mCurrentCommand, false, 0); 1855 break; 1856 case COMMAND_TYPE_INITIATE_DATA_PATH_SETUP: 1857 // TODO: fix status: timeout 1858 onInitiateDataPathResponseFailLocal(mCurrentCommand, 0); 1859 break; 1860 case COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST: 1861 // TODO: fix status: timeout 1862 onRespondToDataPathSetupRequestResponseLocal(mCurrentCommand, false, 0); 1863 break; 1864 case COMMAND_TYPE_END_DATA_PATH: 1865 // TODO: fix status: timeout 1866 onEndPathEndResponseLocal(mCurrentCommand, false, 0); 1867 break; 1868 case COMMAND_TYPE_DELAYED_INITIALIZATION: 1869 Log.wtf(TAG, 1870 "processTimeout: COMMAND_TYPE_DELAYED_INITIALIZATION - shouldn't be " 1871 + "waiting!"); 1872 break; 1873 default: 1874 Log.wtf(TAG, "processTimeout: this isn't a COMMAND -- msg=" + msg); 1875 /* fall-through */ 1876 } 1877 1878 mCurrentCommand = null; 1879 mCurrentTransactionId = TRANSACTION_ID_IGNORE; 1880 } 1881 1882 private void updateSendMessageTimeout() { 1883 if (VDBG) { 1884 Log.v(TAG, "updateSendMessageTimeout: mHostQueuedSendMessages.size()=" 1885 + mHostQueuedSendMessages.size() + ", mFwQueuedSendMessages.size()=" 1886 + mFwQueuedSendMessages.size() + ", mSendQueueBlocked=" 1887 + mSendQueueBlocked); 1888 } 1889 Iterator<Message> it = mFwQueuedSendMessages.values().iterator(); 1890 if (it.hasNext()) { 1891 /* 1892 * Schedule timeout based on the first message in the queue (which is the earliest 1893 * submitted message). Timeout = queuing time + timeout constant. 1894 */ 1895 Message msg = it.next(); 1896 mSendMessageTimeoutMessage.schedule( 1897 msg.getData().getLong(MESSAGE_BUNDLE_KEY_SEND_MESSAGE_ENQUEUE_TIME) 1898 + AWARE_SEND_MESSAGE_TIMEOUT); 1899 } else { 1900 mSendMessageTimeoutMessage.cancel(); 1901 } 1902 } 1903 1904 private void processSendMessageTimeout() { 1905 if (VDBG) { 1906 Log.v(TAG, "processSendMessageTimeout: mHostQueuedSendMessages.size()=" 1907 + mHostQueuedSendMessages.size() + ", mFwQueuedSendMessages.size()=" 1908 + mFwQueuedSendMessages.size() + ", mSendQueueBlocked=" 1909 + mSendQueueBlocked); 1910 1911 } 1912 /* 1913 * Note: using 'first' to always time-out (remove) at least 1 notification (partially) 1914 * due to test code needs: there's no way to mock elapsedRealtime(). TODO: replace with 1915 * injected getClock() once moved off of mmwd. 1916 */ 1917 boolean first = true; 1918 long currentTime = SystemClock.elapsedRealtime(); 1919 Iterator<Map.Entry<Short, Message>> it = mFwQueuedSendMessages.entrySet().iterator(); 1920 while (it.hasNext()) { 1921 Map.Entry<Short, Message> entry = it.next(); 1922 short transactionId = entry.getKey(); 1923 Message message = entry.getValue(); 1924 long messageEnqueueTime = message.getData().getLong( 1925 MESSAGE_BUNDLE_KEY_SEND_MESSAGE_ENQUEUE_TIME); 1926 if (first || messageEnqueueTime + AWARE_SEND_MESSAGE_TIMEOUT <= currentTime) { 1927 if (VDBG) { 1928 Log.v(TAG, "processSendMessageTimeout: expiring - transactionId=" 1929 + transactionId + ", message=" + message 1930 + ", due to messageEnqueueTime=" + messageEnqueueTime 1931 + ", currentTime=" + currentTime); 1932 } 1933 onMessageSendFailLocal(message, NanStatusType.INTERNAL_FAILURE); 1934 it.remove(); 1935 first = false; 1936 } else { 1937 break; 1938 } 1939 } 1940 updateSendMessageTimeout(); 1941 mSendQueueBlocked = false; 1942 transmitNextMessage(); 1943 } 1944 1945 @Override 1946 protected String getLogRecString(Message msg) { 1947 StringBuilder sb = new StringBuilder(WifiAwareStateManager.messageToString(msg)); 1948 1949 if (msg.what == MESSAGE_TYPE_COMMAND 1950 && mCurrentTransactionId != TRANSACTION_ID_IGNORE) { 1951 sb.append(" (Transaction ID=").append(mCurrentTransactionId).append(")"); 1952 } 1953 1954 return sb.toString(); 1955 } 1956 1957 @Override 1958 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1959 pw.println("WifiAwareStateMachine:"); 1960 pw.println(" mNextTransactionId: " + mNextTransactionId); 1961 pw.println(" mNextSessionId: " + mNextSessionId); 1962 pw.println(" mCurrentCommand: " + mCurrentCommand); 1963 pw.println(" mCurrentTransaction: " + mCurrentTransactionId); 1964 pw.println(" mSendQueueBlocked: " + mSendQueueBlocked); 1965 pw.println(" mSendArrivalSequenceCounter: " + mSendArrivalSequenceCounter); 1966 pw.println(" mHostQueuedSendMessages: [" + mHostQueuedSendMessages + "]"); 1967 pw.println(" mFwQueuedSendMessages: [" + mFwQueuedSendMessages + "]"); 1968 super.dump(fd, pw, args); 1969 } 1970 } 1971 1972 private void sendAwareStateChangedBroadcast(boolean enabled) { 1973 if (VDBG) { 1974 Log.v(TAG, "sendAwareStateChangedBroadcast: enabled=" + enabled); 1975 } 1976 final Intent intent = new Intent(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); 1977 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1978 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1979 } 1980 1981 /* 1982 * COMMANDS 1983 */ 1984 1985 private boolean connectLocal(short transactionId, int clientId, int uid, int pid, 1986 String callingPackage, IWifiAwareEventCallback callback, ConfigRequest configRequest, 1987 boolean notifyIdentityChange) { 1988 if (VDBG) { 1989 Log.v(TAG, "connectLocal(): transactionId=" + transactionId + ", clientId=" + clientId 1990 + ", uid=" + uid + ", pid=" + pid + ", callingPackage=" + callingPackage 1991 + ", callback=" + callback + ", configRequest=" + configRequest 1992 + ", notifyIdentityChange=" + notifyIdentityChange); 1993 } 1994 1995 if (!mUsageEnabled) { 1996 Log.w(TAG, "connect(): called with mUsageEnabled=false"); 1997 try { 1998 callback.onConnectFail(NanStatusType.INTERNAL_FAILURE); 1999 mAwareMetrics.recordAttachStatus(NanStatusType.INTERNAL_FAILURE); 2000 } catch (RemoteException e) { 2001 Log.w(TAG, "connectLocal onConnectFail(): RemoteException (FYI): " + e); 2002 } 2003 return false; 2004 } 2005 2006 if (mClients.get(clientId) != null) { 2007 Log.e(TAG, "connectLocal: entry already exists for clientId=" + clientId); 2008 } 2009 2010 if (VDBG) { 2011 Log.v(TAG, "mCurrentAwareConfiguration=" + mCurrentAwareConfiguration 2012 + ", mCurrentIdentityNotification=" + mCurrentIdentityNotification); 2013 } 2014 2015 ConfigRequest merged = mergeConfigRequests(configRequest); 2016 if (merged == null) { 2017 Log.e(TAG, "connectLocal: requested configRequest=" + configRequest 2018 + ", incompatible with current configurations"); 2019 try { 2020 callback.onConnectFail(NanStatusType.INTERNAL_FAILURE); 2021 mAwareMetrics.recordAttachStatus(NanStatusType.INTERNAL_FAILURE); 2022 } catch (RemoteException e) { 2023 Log.w(TAG, "connectLocal onConnectFail(): RemoteException (FYI): " + e); 2024 } 2025 return false; 2026 } else if (VDBG) { 2027 Log.v(TAG, "connectLocal: merged=" + merged); 2028 } 2029 2030 if (mCurrentAwareConfiguration != null && mCurrentAwareConfiguration.equals(merged) 2031 && (mCurrentIdentityNotification || !notifyIdentityChange)) { 2032 try { 2033 callback.onConnectSuccess(clientId); 2034 } catch (RemoteException e) { 2035 Log.w(TAG, "connectLocal onConnectSuccess(): RemoteException (FYI): " + e); 2036 } 2037 WifiAwareClientState client = new WifiAwareClientState(mContext, clientId, uid, pid, 2038 callingPackage, callback, configRequest, notifyIdentityChange, 2039 SystemClock.elapsedRealtime()); 2040 client.onInterfaceAddressChange(mCurrentDiscoveryInterfaceMac); 2041 mClients.append(clientId, client); 2042 mAwareMetrics.recordAttachSession(uid, notifyIdentityChange, mClients); 2043 return false; 2044 } 2045 boolean notificationRequired = 2046 doesAnyClientNeedIdentityChangeNotifications() || notifyIdentityChange; 2047 2048 boolean success = mWifiAwareNativeApi.enableAndConfigure(transactionId, merged, 2049 notificationRequired, mCurrentAwareConfiguration == null, 2050 mPowerManager.isInteractive(), mPowerManager.isDeviceIdleMode()); 2051 if (!success) { 2052 try { 2053 callback.onConnectFail(NanStatusType.INTERNAL_FAILURE); 2054 mAwareMetrics.recordAttachStatus(NanStatusType.INTERNAL_FAILURE); 2055 } catch (RemoteException e) { 2056 Log.w(TAG, "connectLocal onConnectFail(): RemoteException (FYI): " + e); 2057 } 2058 } 2059 2060 return success; 2061 } 2062 2063 private boolean disconnectLocal(short transactionId, int clientId) { 2064 if (VDBG) { 2065 Log.v(TAG, 2066 "disconnectLocal(): transactionId=" + transactionId + ", clientId=" + clientId); 2067 } 2068 2069 WifiAwareClientState client = mClients.get(clientId); 2070 if (client == null) { 2071 Log.e(TAG, "disconnectLocal: no entry for clientId=" + clientId); 2072 return false; 2073 } 2074 mClients.delete(clientId); 2075 mAwareMetrics.recordAttachSessionDuration(client.getCreationTime()); 2076 SparseArray<WifiAwareDiscoverySessionState> sessions = client.getSessions(); 2077 for (int i = 0; i < sessions.size(); ++i) { 2078 mAwareMetrics.recordDiscoverySessionDuration(sessions.valueAt(i).getCreationTime(), 2079 sessions.valueAt(i).isPublishSession()); 2080 } 2081 client.destroy(); 2082 2083 if (mClients.size() == 0) { 2084 mCurrentAwareConfiguration = null; 2085 deleteAllDataPathInterfaces(); 2086 return mWifiAwareNativeApi.disable(transactionId); 2087 } 2088 2089 ConfigRequest merged = mergeConfigRequests(null); 2090 if (merged == null) { 2091 Log.wtf(TAG, "disconnectLocal: got an incompatible merge on remaining configs!?"); 2092 return false; 2093 } 2094 boolean notificationReqs = doesAnyClientNeedIdentityChangeNotifications(); 2095 if (merged.equals(mCurrentAwareConfiguration) 2096 && mCurrentIdentityNotification == notificationReqs) { 2097 return false; 2098 } 2099 2100 return mWifiAwareNativeApi.enableAndConfigure(transactionId, merged, notificationReqs, 2101 false, mPowerManager.isInteractive(), mPowerManager.isDeviceIdleMode()); 2102 } 2103 2104 private boolean reconfigureLocal(short transactionId) { 2105 if (VDBG) Log.v(TAG, "reconfigureLocal(): transactionId=" + transactionId); 2106 2107 if (mClients.size() == 0) { 2108 // no clients - Aware is not enabled, nothing to reconfigure 2109 return false; 2110 } 2111 2112 boolean notificationReqs = doesAnyClientNeedIdentityChangeNotifications(); 2113 2114 return mWifiAwareNativeApi.enableAndConfigure(transactionId, mCurrentAwareConfiguration, 2115 notificationReqs, false, mPowerManager.isInteractive(), 2116 mPowerManager.isDeviceIdleMode()); 2117 } 2118 2119 private void terminateSessionLocal(int clientId, int sessionId) { 2120 if (VDBG) { 2121 Log.v(TAG, 2122 "terminateSessionLocal(): clientId=" + clientId + ", sessionId=" + sessionId); 2123 } 2124 2125 WifiAwareClientState client = mClients.get(clientId); 2126 if (client == null) { 2127 Log.e(TAG, "terminateSession: no client exists for clientId=" + clientId); 2128 return; 2129 } 2130 2131 WifiAwareDiscoverySessionState session = client.terminateSession(sessionId); 2132 if (session != null) { 2133 mAwareMetrics.recordDiscoverySessionDuration(session.getCreationTime(), 2134 session.isPublishSession()); 2135 } 2136 } 2137 2138 private boolean publishLocal(short transactionId, int clientId, PublishConfig publishConfig, 2139 IWifiAwareDiscoverySessionCallback callback) { 2140 if (VDBG) { 2141 Log.v(TAG, "publishLocal(): transactionId=" + transactionId + ", clientId=" + clientId 2142 + ", publishConfig=" + publishConfig + ", callback=" + callback); 2143 } 2144 2145 WifiAwareClientState client = mClients.get(clientId); 2146 if (client == null) { 2147 Log.e(TAG, "publishLocal: no client exists for clientId=" + clientId); 2148 return false; 2149 } 2150 2151 boolean success = mWifiAwareNativeApi.publish(transactionId, (byte) 0, publishConfig); 2152 if (!success) { 2153 try { 2154 callback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 2155 } catch (RemoteException e) { 2156 Log.w(TAG, "publishLocal onSessionConfigFail(): RemoteException (FYI): " + e); 2157 } 2158 mAwareMetrics.recordDiscoveryStatus(client.getUid(), NanStatusType.INTERNAL_FAILURE, 2159 true); 2160 } 2161 2162 return success; 2163 } 2164 2165 private boolean updatePublishLocal(short transactionId, int clientId, int sessionId, 2166 PublishConfig publishConfig) { 2167 if (VDBG) { 2168 Log.v(TAG, "updatePublishLocal(): transactionId=" + transactionId + ", clientId=" 2169 + clientId + ", sessionId=" + sessionId + ", publishConfig=" + publishConfig); 2170 } 2171 2172 WifiAwareClientState client = mClients.get(clientId); 2173 if (client == null) { 2174 Log.e(TAG, "updatePublishLocal: no client exists for clientId=" + clientId); 2175 return false; 2176 } 2177 2178 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2179 if (session == null) { 2180 Log.e(TAG, "updatePublishLocal: no session exists for clientId=" + clientId 2181 + ", sessionId=" + sessionId); 2182 return false; 2183 } 2184 2185 boolean status = session.updatePublish(transactionId, publishConfig); 2186 if (!status) { 2187 mAwareMetrics.recordDiscoveryStatus(client.getUid(), NanStatusType.INTERNAL_FAILURE, 2188 true); 2189 } 2190 return status; 2191 } 2192 2193 private boolean subscribeLocal(short transactionId, int clientId, 2194 SubscribeConfig subscribeConfig, IWifiAwareDiscoverySessionCallback callback) { 2195 if (VDBG) { 2196 Log.v(TAG, "subscribeLocal(): transactionId=" + transactionId + ", clientId=" + clientId 2197 + ", subscribeConfig=" + subscribeConfig + ", callback=" + callback); 2198 } 2199 2200 WifiAwareClientState client = mClients.get(clientId); 2201 if (client == null) { 2202 Log.e(TAG, "subscribeLocal: no client exists for clientId=" + clientId); 2203 return false; 2204 } 2205 2206 boolean success = mWifiAwareNativeApi.subscribe(transactionId, (byte) 0, subscribeConfig); 2207 if (!success) { 2208 try { 2209 callback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); 2210 } catch (RemoteException e) { 2211 Log.w(TAG, "subscribeLocal onSessionConfigFail(): RemoteException (FYI): " + e); 2212 } 2213 mAwareMetrics.recordDiscoveryStatus(client.getUid(), NanStatusType.INTERNAL_FAILURE, 2214 false); 2215 } 2216 2217 return success; 2218 } 2219 2220 private boolean updateSubscribeLocal(short transactionId, int clientId, int sessionId, 2221 SubscribeConfig subscribeConfig) { 2222 if (VDBG) { 2223 Log.v(TAG, 2224 "updateSubscribeLocal(): transactionId=" + transactionId + ", clientId=" 2225 + clientId + ", sessionId=" + sessionId + ", subscribeConfig=" 2226 + subscribeConfig); 2227 } 2228 2229 WifiAwareClientState client = mClients.get(clientId); 2230 if (client == null) { 2231 Log.e(TAG, "updateSubscribeLocal: no client exists for clientId=" + clientId); 2232 return false; 2233 } 2234 2235 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2236 if (session == null) { 2237 Log.e(TAG, "updateSubscribeLocal: no session exists for clientId=" + clientId 2238 + ", sessionId=" + sessionId); 2239 return false; 2240 } 2241 2242 boolean status = session.updateSubscribe(transactionId, subscribeConfig); 2243 if (!status) { 2244 mAwareMetrics.recordDiscoveryStatus(client.getUid(), NanStatusType.INTERNAL_FAILURE, 2245 false); 2246 } 2247 return status; 2248 } 2249 2250 private boolean sendFollowonMessageLocal(short transactionId, int clientId, int sessionId, 2251 int peerId, byte[] message, int messageId) { 2252 if (VDBG) { 2253 Log.v(TAG, 2254 "sendFollowonMessageLocal(): transactionId=" + transactionId + ", clientId=" 2255 + clientId + ", sessionId=" + sessionId + ", peerId=" + peerId 2256 + ", messageId=" + messageId); 2257 } 2258 2259 WifiAwareClientState client = mClients.get(clientId); 2260 if (client == null) { 2261 Log.e(TAG, "sendFollowonMessageLocal: no client exists for clientId=" + clientId); 2262 return false; 2263 } 2264 2265 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2266 if (session == null) { 2267 Log.e(TAG, "sendFollowonMessageLocal: no session exists for clientId=" + clientId 2268 + ", sessionId=" + sessionId); 2269 return false; 2270 } 2271 2272 return session.sendMessage(transactionId, peerId, message, messageId); 2273 } 2274 2275 private void enableUsageLocal() { 2276 if (VDBG) Log.v(TAG, "enableUsageLocal: mUsageEnabled=" + mUsageEnabled); 2277 2278 if (mUsageEnabled) { 2279 return; 2280 } 2281 2282 mUsageEnabled = true; 2283 queryCapabilities(); 2284 sendAwareStateChangedBroadcast(true); 2285 2286 mAwareMetrics.recordEnableUsage(); 2287 } 2288 2289 private boolean disableUsageLocal(short transactionId) { 2290 if (VDBG) { 2291 Log.v(TAG, "disableUsageLocal: transactionId=" + transactionId + ", mUsageEnabled=" 2292 + mUsageEnabled); 2293 } 2294 2295 if (!mUsageEnabled) { 2296 return false; 2297 } 2298 2299 onAwareDownLocal(); 2300 2301 mUsageEnabled = false; 2302 boolean callDispatched = mWifiAwareNativeApi.disable(transactionId); 2303 2304 sendAwareStateChangedBroadcast(false); 2305 2306 mAwareMetrics.recordDisableUsage(); 2307 2308 return callDispatched; 2309 } 2310 2311 private void startRangingLocal(int clientId, int sessionId, RttManager.RttParams[] params, 2312 int rangingId) { 2313 if (VDBG) { 2314 Log.v(TAG, "startRangingLocal: clientId=" + clientId + ", sessionId=" + sessionId 2315 + ", parms=" + Arrays.toString(params) + ", rangingId=" + rangingId); 2316 } 2317 2318 WifiAwareClientState client = mClients.get(clientId); 2319 if (client == null) { 2320 Log.e(TAG, "startRangingLocal: no client exists for clientId=" + clientId); 2321 return; 2322 } 2323 2324 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2325 if (session == null) { 2326 Log.e(TAG, "startRangingLocal: no session exists for clientId=" + clientId 2327 + ", sessionId=" + sessionId); 2328 client.onRangingFailure(rangingId, RttManager.REASON_INVALID_REQUEST, 2329 "Invalid session ID"); 2330 return; 2331 } 2332 2333 for (RttManager.RttParams param : params) { 2334 String peerIdStr = param.bssid; 2335 try { 2336 WifiAwareDiscoverySessionState.PeerInfo peerInfo = session.getPeerInfo( 2337 Integer.parseInt(peerIdStr)); 2338 if (peerInfo == null || peerInfo.mMac == null) { 2339 Log.d(TAG, "startRangingLocal: no MAC address for peer ID=" + peerIdStr); 2340 param.bssid = ""; 2341 } else { 2342 param.bssid = NativeUtil.macAddressFromByteArray(peerInfo.mMac); 2343 } 2344 } catch (NumberFormatException e) { 2345 Log.e(TAG, "startRangingLocal: invalid peer ID specification (in bssid field): '" 2346 + peerIdStr + "'"); 2347 param.bssid = ""; 2348 } 2349 } 2350 2351 mRtt.startRanging(rangingId, client, params); 2352 } 2353 2354 private boolean initiateDataPathSetupLocal(short transactionId, 2355 WifiAwareNetworkSpecifier networkSpecifier, int peerId, int channelRequestType, 2356 int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase, 2357 boolean isOutOfBand) { 2358 if (VDBG) { 2359 Log.v(TAG, "initiateDataPathSetupLocal(): transactionId=" + transactionId 2360 + ", networkSpecifier=" + networkSpecifier + ", peerId=" + peerId 2361 + ", channelRequestType=" + channelRequestType + ", channel=" + channel 2362 + ", peer=" 2363 + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName=" + interfaceName 2364 + ", pmk=" + ((pmk == null) ? "" : "*") + ", passphrase=" + ( 2365 (passphrase == null) ? "" : "*") + ", isOutOfBand=" 2366 + isOutOfBand); 2367 } 2368 2369 boolean success = mWifiAwareNativeApi.initiateDataPath(transactionId, peerId, 2370 channelRequestType, channel, peer, interfaceName, pmk, passphrase, isOutOfBand, 2371 mCapabilities); 2372 if (!success) { 2373 mDataPathMgr.onDataPathInitiateFail(networkSpecifier, NanStatusType.INTERNAL_FAILURE); 2374 } 2375 2376 return success; 2377 } 2378 2379 private boolean respondToDataPathRequestLocal(short transactionId, boolean accept, 2380 int ndpId, String interfaceName, byte[] pmk, String passphrase, boolean isOutOfBand) { 2381 if (VDBG) { 2382 Log.v(TAG, 2383 "respondToDataPathRequestLocal(): transactionId=" + transactionId + ", accept=" 2384 + accept + ", ndpId=" + ndpId + ", interfaceName=" + interfaceName 2385 + ", pmk=" + ((pmk == null) ? "" : "*") + ", passphrase=" 2386 + ((passphrase == null) ? "" : "*") + ", isOutOfBand=" 2387 + isOutOfBand); 2388 } 2389 boolean success = mWifiAwareNativeApi.respondToDataPathRequest(transactionId, accept, ndpId, 2390 interfaceName, pmk, passphrase, isOutOfBand, mCapabilities); 2391 if (!success) { 2392 mDataPathMgr.onRespondToDataPathRequest(ndpId, false, NanStatusType.INTERNAL_FAILURE); 2393 } 2394 return success; 2395 } 2396 2397 private boolean endDataPathLocal(short transactionId, int ndpId) { 2398 if (VDBG) { 2399 Log.v(TAG, 2400 "endDataPathLocal: transactionId=" + transactionId + ", ndpId=" + ndpId); 2401 } 2402 2403 return mWifiAwareNativeApi.endDataPath(transactionId, ndpId); 2404 } 2405 2406 /* 2407 * RESPONSES 2408 */ 2409 2410 private void onConfigCompletedLocal(Message completedCommand) { 2411 if (VDBG) { 2412 Log.v(TAG, "onConfigCompleted: completedCommand=" + completedCommand); 2413 } 2414 2415 if (completedCommand.arg1 == COMMAND_TYPE_CONNECT) { 2416 Bundle data = completedCommand.getData(); 2417 2418 int clientId = completedCommand.arg2; 2419 IWifiAwareEventCallback callback = (IWifiAwareEventCallback) completedCommand.obj; 2420 ConfigRequest configRequest = (ConfigRequest) data 2421 .getParcelable(MESSAGE_BUNDLE_KEY_CONFIG); 2422 int uid = data.getInt(MESSAGE_BUNDLE_KEY_UID); 2423 int pid = data.getInt(MESSAGE_BUNDLE_KEY_PID); 2424 boolean notifyIdentityChange = data.getBoolean( 2425 MESSAGE_BUNDLE_KEY_NOTIFY_IDENTITY_CHANGE); 2426 String callingPackage = data.getString(MESSAGE_BUNDLE_KEY_CALLING_PACKAGE); 2427 2428 WifiAwareClientState client = new WifiAwareClientState(mContext, clientId, uid, pid, 2429 callingPackage, callback, configRequest, notifyIdentityChange, 2430 SystemClock.elapsedRealtime()); 2431 mClients.put(clientId, client); 2432 mAwareMetrics.recordAttachSession(uid, notifyIdentityChange, mClients); 2433 try { 2434 callback.onConnectSuccess(clientId); 2435 } catch (RemoteException e) { 2436 Log.w(TAG, 2437 "onConfigCompletedLocal onConnectSuccess(): RemoteException (FYI): " + e); 2438 } 2439 client.onInterfaceAddressChange(mCurrentDiscoveryInterfaceMac); 2440 } else if (completedCommand.arg1 == COMMAND_TYPE_DISCONNECT) { 2441 /* 2442 * NOP (i.e. updated configuration after disconnecting a client) 2443 */ 2444 } else if (completedCommand.arg1 == COMMAND_TYPE_RECONFIGURE) { 2445 /* 2446 * NOP (i.e. updated configuration at power saving event) 2447 */ 2448 } else { 2449 Log.wtf(TAG, "onConfigCompletedLocal: unexpected completedCommand=" + completedCommand); 2450 return; 2451 } 2452 2453 if (mCurrentAwareConfiguration == null) { // enabled (as opposed to re-configured) 2454 createAllDataPathInterfaces(); 2455 } 2456 mCurrentAwareConfiguration = mergeConfigRequests(null); 2457 if (mCurrentAwareConfiguration == null) { 2458 Log.wtf(TAG, "onConfigCompletedLocal: got a null merged configuration after config!?"); 2459 } 2460 mCurrentIdentityNotification = doesAnyClientNeedIdentityChangeNotifications(); 2461 } 2462 2463 private void onConfigFailedLocal(Message failedCommand, int reason) { 2464 if (VDBG) { 2465 Log.v(TAG, 2466 "onConfigFailedLocal: failedCommand=" + failedCommand + ", reason=" + reason); 2467 } 2468 2469 if (failedCommand.arg1 == COMMAND_TYPE_CONNECT) { 2470 IWifiAwareEventCallback callback = (IWifiAwareEventCallback) failedCommand.obj; 2471 2472 try { 2473 callback.onConnectFail(reason); 2474 mAwareMetrics.recordAttachStatus(reason); 2475 } catch (RemoteException e) { 2476 Log.w(TAG, "onConfigFailedLocal onConnectFail(): RemoteException (FYI): " + e); 2477 } 2478 } else if (failedCommand.arg1 == COMMAND_TYPE_DISCONNECT) { 2479 /* 2480 * NOP (tried updating configuration after disconnecting a client - 2481 * shouldn't fail but there's nothing to do - the old configuration 2482 * is still up-and-running). 2483 * 2484 * OR: timed-out getting a response to a disable. Either way a NOP. 2485 */ 2486 } else if (failedCommand.arg1 == COMMAND_TYPE_RECONFIGURE) { 2487 /* 2488 * NOP (configuration change as part of possibly power saving event - should not 2489 * fail but there's nothing to do). 2490 */ 2491 } else { 2492 Log.wtf(TAG, "onConfigFailedLocal: unexpected failedCommand=" + failedCommand); 2493 return; 2494 } 2495 } 2496 2497 private void onDisableResponseLocal(Message command, int reason) { 2498 if (VDBG) { 2499 Log.v(TAG, "onDisableResponseLocal: command=" + command + ", reason=" + reason); 2500 } 2501 2502 /* 2503 * do nothing: 2504 * - success: was waiting so that don't enable while disabling 2505 * - fail: shouldn't happen (though can if already disabled for instance) 2506 */ 2507 if (reason != NanStatusType.SUCCESS) { 2508 Log.e(TAG, "onDisableResponseLocal: FAILED!? command=" + command + ", reason=" 2509 + reason); 2510 } 2511 2512 mAwareMetrics.recordDisableAware(); 2513 } 2514 2515 private void onSessionConfigSuccessLocal(Message completedCommand, byte pubSubId, 2516 boolean isPublish) { 2517 if (VDBG) { 2518 Log.v(TAG, "onSessionConfigSuccessLocal: completedCommand=" + completedCommand 2519 + ", pubSubId=" + pubSubId + ", isPublish=" + isPublish); 2520 } 2521 2522 if (completedCommand.arg1 == COMMAND_TYPE_PUBLISH 2523 || completedCommand.arg1 == COMMAND_TYPE_SUBSCRIBE) { 2524 int clientId = completedCommand.arg2; 2525 IWifiAwareDiscoverySessionCallback callback = 2526 (IWifiAwareDiscoverySessionCallback) completedCommand.obj; 2527 2528 WifiAwareClientState client = mClients.get(clientId); 2529 if (client == null) { 2530 Log.e(TAG, 2531 "onSessionConfigSuccessLocal: no client exists for clientId=" + clientId); 2532 return; 2533 } 2534 2535 int sessionId = mSm.mNextSessionId++; 2536 try { 2537 callback.onSessionStarted(sessionId); 2538 } catch (RemoteException e) { 2539 Log.e(TAG, "onSessionConfigSuccessLocal: onSessionStarted() RemoteException=" + e); 2540 return; 2541 } 2542 2543 WifiAwareDiscoverySessionState session = new WifiAwareDiscoverySessionState( 2544 mWifiAwareNativeApi, sessionId, pubSubId, callback, isPublish, 2545 SystemClock.elapsedRealtime()); 2546 client.addSession(session); 2547 2548 mAwareMetrics.recordDiscoverySession(client.getUid(), 2549 completedCommand.arg1 == COMMAND_TYPE_PUBLISH, mClients); 2550 mAwareMetrics.recordDiscoveryStatus(client.getUid(), NanStatusType.SUCCESS, 2551 completedCommand.arg1 == COMMAND_TYPE_PUBLISH); 2552 2553 } else if (completedCommand.arg1 == COMMAND_TYPE_UPDATE_PUBLISH 2554 || completedCommand.arg1 == COMMAND_TYPE_UPDATE_SUBSCRIBE) { 2555 int clientId = completedCommand.arg2; 2556 int sessionId = completedCommand.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 2557 2558 WifiAwareClientState client = mClients.get(clientId); 2559 if (client == null) { 2560 Log.e(TAG, 2561 "onSessionConfigSuccessLocal: no client exists for clientId=" + clientId); 2562 return; 2563 } 2564 2565 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2566 if (session == null) { 2567 Log.e(TAG, "onSessionConfigSuccessLocal: no session exists for clientId=" + clientId 2568 + ", sessionId=" + sessionId); 2569 return; 2570 } 2571 2572 try { 2573 session.getCallback().onSessionConfigSuccess(); 2574 } catch (RemoteException e) { 2575 Log.e(TAG, "onSessionConfigSuccessLocal: onSessionConfigSuccess() RemoteException=" 2576 + e); 2577 } 2578 mAwareMetrics.recordDiscoveryStatus(client.getUid(), NanStatusType.SUCCESS, 2579 completedCommand.arg1 == COMMAND_TYPE_UPDATE_PUBLISH); 2580 } else { 2581 Log.wtf(TAG, 2582 "onSessionConfigSuccessLocal: unexpected completedCommand=" + completedCommand); 2583 } 2584 } 2585 2586 private void onSessionConfigFailLocal(Message failedCommand, boolean isPublish, int reason) { 2587 if (VDBG) { 2588 Log.v(TAG, "onSessionConfigFailLocal: failedCommand=" + failedCommand + ", isPublish=" 2589 + isPublish + ", reason=" + reason); 2590 } 2591 2592 if (failedCommand.arg1 == COMMAND_TYPE_PUBLISH 2593 || failedCommand.arg1 == COMMAND_TYPE_SUBSCRIBE) { 2594 int clientId = failedCommand.arg2; 2595 IWifiAwareDiscoverySessionCallback callback = 2596 (IWifiAwareDiscoverySessionCallback) failedCommand.obj; 2597 2598 WifiAwareClientState client = mClients.get(clientId); 2599 if (client == null) { 2600 Log.e(TAG, "onSessionConfigFailLocal: no client exists for clientId=" + clientId); 2601 return; 2602 } 2603 2604 try { 2605 callback.onSessionConfigFail(reason); 2606 } catch (RemoteException e) { 2607 Log.w(TAG, "onSessionConfigFailLocal onSessionConfigFail(): RemoteException (FYI): " 2608 + e); 2609 } 2610 mAwareMetrics.recordDiscoveryStatus(client.getUid(), reason, 2611 failedCommand.arg1 == COMMAND_TYPE_PUBLISH); 2612 } else if (failedCommand.arg1 == COMMAND_TYPE_UPDATE_PUBLISH 2613 || failedCommand.arg1 == COMMAND_TYPE_UPDATE_SUBSCRIBE) { 2614 int clientId = failedCommand.arg2; 2615 int sessionId = failedCommand.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 2616 2617 WifiAwareClientState client = mClients.get(clientId); 2618 if (client == null) { 2619 Log.e(TAG, "onSessionConfigFailLocal: no client exists for clientId=" + clientId); 2620 return; 2621 } 2622 2623 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2624 if (session == null) { 2625 Log.e(TAG, "onSessionConfigFailLocal: no session exists for clientId=" + clientId 2626 + ", sessionId=" + sessionId); 2627 return; 2628 } 2629 2630 try { 2631 session.getCallback().onSessionConfigFail(reason); 2632 } catch (RemoteException e) { 2633 Log.e(TAG, "onSessionConfigFailLocal: onSessionConfigFail() RemoteException=" + e); 2634 } 2635 mAwareMetrics.recordDiscoveryStatus(client.getUid(), reason, 2636 failedCommand.arg1 == COMMAND_TYPE_UPDATE_PUBLISH); 2637 2638 if (reason == NanStatusType.INVALID_SESSION_ID) { 2639 client.removeSession(sessionId); 2640 } 2641 } else { 2642 Log.wtf(TAG, "onSessionConfigFailLocal: unexpected failedCommand=" + failedCommand); 2643 } 2644 } 2645 2646 private void onMessageSendSuccessLocal(Message completedCommand) { 2647 if (VDBG) { 2648 Log.v(TAG, "onMessageSendSuccess: completedCommand=" + completedCommand); 2649 } 2650 2651 int clientId = completedCommand.arg2; 2652 int sessionId = completedCommand.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 2653 int messageId = completedCommand.getData().getInt(MESSAGE_BUNDLE_KEY_MESSAGE_ID); 2654 2655 WifiAwareClientState client = mClients.get(clientId); 2656 if (client == null) { 2657 Log.e(TAG, "onMessageSendSuccessLocal: no client exists for clientId=" + clientId); 2658 return; 2659 } 2660 2661 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2662 if (session == null) { 2663 Log.e(TAG, "onMessageSendSuccessLocal: no session exists for clientId=" + clientId 2664 + ", sessionId=" + sessionId); 2665 return; 2666 } 2667 2668 try { 2669 session.getCallback().onMessageSendSuccess(messageId); 2670 } catch (RemoteException e) { 2671 Log.w(TAG, "onMessageSendSuccessLocal: RemoteException (FYI): " + e); 2672 } 2673 } 2674 2675 private void onMessageSendFailLocal(Message failedCommand, int reason) { 2676 if (VDBG) { 2677 Log.v(TAG, "onMessageSendFail: failedCommand=" + failedCommand + ", reason=" + reason); 2678 } 2679 2680 int clientId = failedCommand.arg2; 2681 int sessionId = failedCommand.getData().getInt(MESSAGE_BUNDLE_KEY_SESSION_ID); 2682 int messageId = failedCommand.getData().getInt(MESSAGE_BUNDLE_KEY_MESSAGE_ID); 2683 2684 WifiAwareClientState client = mClients.get(clientId); 2685 if (client == null) { 2686 Log.e(TAG, "onMessageSendFailLocal: no client exists for clientId=" + clientId); 2687 return; 2688 } 2689 2690 WifiAwareDiscoverySessionState session = client.getSession(sessionId); 2691 if (session == null) { 2692 Log.e(TAG, "onMessageSendFailLocal: no session exists for clientId=" + clientId 2693 + ", sessionId=" + sessionId); 2694 return; 2695 } 2696 2697 try { 2698 session.getCallback().onMessageSendFail(messageId, reason); 2699 } catch (RemoteException e) { 2700 Log.e(TAG, "onMessageSendFailLocal: onMessageSendFail RemoteException=" + e); 2701 } 2702 } 2703 2704 private void onCapabilitiesUpdatedResponseLocal(Capabilities capabilities) { 2705 if (VDBG) { 2706 Log.v(TAG, "onCapabilitiesUpdatedResponseLocal: capabilites=" + capabilities); 2707 } 2708 2709 mCapabilities = capabilities; 2710 mCharacteristics = null; 2711 } 2712 2713 private void onCreateDataPathInterfaceResponseLocal(Message command, boolean success, 2714 int reasonOnFailure) { 2715 if (VDBG) { 2716 Log.v(TAG, "onCreateDataPathInterfaceResponseLocal: command=" + command + ", success=" 2717 + success + ", reasonOnFailure=" + reasonOnFailure); 2718 } 2719 2720 if (success) { 2721 if (DBG) { 2722 Log.d(TAG, "onCreateDataPathInterfaceResponseLocal: successfully created interface " 2723 + command.obj); 2724 } 2725 mDataPathMgr.onInterfaceCreated((String) command.obj); 2726 } else { 2727 Log.e(TAG, 2728 "onCreateDataPathInterfaceResponseLocal: failed when trying to create " 2729 + "interface " 2730 + command.obj + ". Reason code=" + reasonOnFailure); 2731 } 2732 } 2733 2734 private void onDeleteDataPathInterfaceResponseLocal(Message command, boolean success, 2735 int reasonOnFailure) { 2736 if (VDBG) { 2737 Log.v(TAG, "onDeleteDataPathInterfaceResponseLocal: command=" + command + ", success=" 2738 + success + ", reasonOnFailure=" + reasonOnFailure); 2739 } 2740 2741 if (success) { 2742 if (DBG) { 2743 Log.d(TAG, "onDeleteDataPathInterfaceResponseLocal: successfully deleted interface " 2744 + command.obj); 2745 } 2746 mDataPathMgr.onInterfaceDeleted((String) command.obj); 2747 } else { 2748 Log.e(TAG, 2749 "onDeleteDataPathInterfaceResponseLocal: failed when trying to delete " 2750 + "interface " 2751 + command.obj + ". Reason code=" + reasonOnFailure); 2752 } 2753 } 2754 2755 private void onInitiateDataPathResponseSuccessLocal(Message command, int ndpId) { 2756 if (VDBG) { 2757 Log.v(TAG, "onInitiateDataPathResponseSuccessLocal: command=" + command + ", ndpId=" 2758 + ndpId); 2759 } 2760 2761 mDataPathMgr.onDataPathInitiateSuccess((WifiAwareNetworkSpecifier) command.obj, ndpId); 2762 } 2763 2764 private void onInitiateDataPathResponseFailLocal(Message command, int reason) { 2765 if (VDBG) { 2766 Log.v(TAG, "onInitiateDataPathResponseFailLocal: command=" + command + ", reason=" 2767 + reason); 2768 } 2769 2770 mDataPathMgr.onDataPathInitiateFail((WifiAwareNetworkSpecifier) command.obj, reason); 2771 } 2772 2773 private void onRespondToDataPathSetupRequestResponseLocal(Message command, boolean success, 2774 int reasonOnFailure) { 2775 if (VDBG) { 2776 Log.v(TAG, "onRespondToDataPathSetupRequestResponseLocal: command=" + command 2777 + ", success=" + success + ", reasonOnFailure=" + reasonOnFailure); 2778 } 2779 2780 mDataPathMgr.onRespondToDataPathRequest(command.arg2, success, reasonOnFailure); 2781 } 2782 2783 private void onEndPathEndResponseLocal(Message command, boolean success, int reasonOnFailure) { 2784 if (VDBG) { 2785 Log.v(TAG, "onEndPathEndResponseLocal: command=" + command 2786 + ", success=" + success + ", reasonOnFailure=" + reasonOnFailure); 2787 } 2788 2789 // TODO: do something with this 2790 } 2791 2792 /* 2793 * NOTIFICATIONS 2794 */ 2795 2796 private void onInterfaceAddressChangeLocal(byte[] mac) { 2797 if (VDBG) { 2798 Log.v(TAG, "onInterfaceAddressChange: mac=" + String.valueOf(HexEncoding.encode(mac))); 2799 } 2800 2801 mCurrentDiscoveryInterfaceMac = mac; 2802 2803 for (int i = 0; i < mClients.size(); ++i) { 2804 WifiAwareClientState client = mClients.valueAt(i); 2805 client.onInterfaceAddressChange(mac); 2806 } 2807 2808 mAwareMetrics.recordEnableAware(); 2809 } 2810 2811 private void onClusterChangeLocal(int flag, byte[] clusterId) { 2812 if (VDBG) { 2813 Log.v(TAG, "onClusterChange: flag=" + flag + ", clusterId=" 2814 + String.valueOf(HexEncoding.encode(clusterId))); 2815 } 2816 2817 for (int i = 0; i < mClients.size(); ++i) { 2818 WifiAwareClientState client = mClients.valueAt(i); 2819 client.onClusterChange(flag, clusterId, mCurrentDiscoveryInterfaceMac); 2820 } 2821 2822 mAwareMetrics.recordEnableAware(); 2823 } 2824 2825 private void onMatchLocal(int pubSubId, int requestorInstanceId, byte[] peerMac, 2826 byte[] serviceSpecificInfo, byte[] matchFilter) { 2827 if (VDBG) { 2828 Log.v(TAG, 2829 "onMatch: pubSubId=" + pubSubId + ", requestorInstanceId=" + requestorInstanceId 2830 + ", peerDiscoveryMac=" + String.valueOf(HexEncoding.encode(peerMac)) 2831 + ", serviceSpecificInfo=" + Arrays.toString(serviceSpecificInfo) 2832 + ", matchFilter=" + Arrays.toString(matchFilter)); 2833 } 2834 2835 Pair<WifiAwareClientState, WifiAwareDiscoverySessionState> data = 2836 getClientSessionForPubSubId(pubSubId); 2837 if (data == null) { 2838 Log.e(TAG, "onMatch: no session found for pubSubId=" + pubSubId); 2839 return; 2840 } 2841 2842 data.second.onMatch(requestorInstanceId, peerMac, serviceSpecificInfo, matchFilter); 2843 } 2844 2845 private void onSessionTerminatedLocal(int pubSubId, boolean isPublish, int reason) { 2846 if (VDBG) { 2847 Log.v(TAG, "onSessionTerminatedLocal: pubSubId=" + pubSubId + ", isPublish=" + isPublish 2848 + ", reason=" + reason); 2849 } 2850 2851 Pair<WifiAwareClientState, WifiAwareDiscoverySessionState> data = 2852 getClientSessionForPubSubId(pubSubId); 2853 if (data == null) { 2854 Log.e(TAG, "onSessionTerminatedLocal: no session found for pubSubId=" + pubSubId); 2855 return; 2856 } 2857 2858 try { 2859 data.second.getCallback().onSessionTerminated(reason); 2860 } catch (RemoteException e) { 2861 Log.w(TAG, 2862 "onSessionTerminatedLocal onSessionTerminated(): RemoteException (FYI): " + e); 2863 } 2864 data.first.removeSession(data.second.getSessionId()); 2865 mAwareMetrics.recordDiscoverySessionDuration(data.second.getCreationTime(), 2866 data.second.isPublishSession()); 2867 } 2868 2869 private void onMessageReceivedLocal(int pubSubId, int requestorInstanceId, byte[] peerMac, 2870 byte[] message) { 2871 if (VDBG) { 2872 Log.v(TAG, 2873 "onMessageReceivedLocal: pubSubId=" + pubSubId + ", requestorInstanceId=" 2874 + requestorInstanceId + ", peerDiscoveryMac=" 2875 + String.valueOf(HexEncoding.encode(peerMac))); 2876 } 2877 2878 Pair<WifiAwareClientState, WifiAwareDiscoverySessionState> data = 2879 getClientSessionForPubSubId(pubSubId); 2880 if (data == null) { 2881 Log.e(TAG, "onMessageReceivedLocal: no session found for pubSubId=" + pubSubId); 2882 return; 2883 } 2884 2885 data.second.onMessageReceived(requestorInstanceId, peerMac, message); 2886 } 2887 2888 private void onAwareDownLocal() { 2889 if (VDBG) { 2890 Log.v(TAG, "onAwareDown"); 2891 } 2892 2893 for (int i = 0; i < mClients.size(); ++i) { 2894 mAwareMetrics.recordAttachSessionDuration(mClients.valueAt(i).getCreationTime()); 2895 SparseArray<WifiAwareDiscoverySessionState> sessions = mClients.valueAt( 2896 i).getSessions(); 2897 for (int j = 0; j < sessions.size(); ++j) { 2898 mAwareMetrics.recordDiscoverySessionDuration(sessions.valueAt(i).getCreationTime(), 2899 sessions.valueAt(i).isPublishSession()); 2900 } 2901 } 2902 mAwareMetrics.recordDisableAware(); 2903 2904 mClients.clear(); 2905 mCurrentAwareConfiguration = null; 2906 mSm.onAwareDownCleanupSendQueueState(); 2907 mDataPathMgr.onAwareDownCleanupDataPaths(); 2908 mCurrentDiscoveryInterfaceMac = ALL_ZERO_MAC; 2909 deleteAllDataPathInterfaces(); 2910 } 2911 2912 /* 2913 * Utilities 2914 */ 2915 2916 private Pair<WifiAwareClientState, WifiAwareDiscoverySessionState> getClientSessionForPubSubId( 2917 int pubSubId) { 2918 for (int i = 0; i < mClients.size(); ++i) { 2919 WifiAwareClientState client = mClients.valueAt(i); 2920 WifiAwareDiscoverySessionState session = client.getAwareSessionStateForPubSubId( 2921 pubSubId); 2922 if (session != null) { 2923 return new Pair<>(client, session); 2924 } 2925 } 2926 2927 return null; 2928 } 2929 2930 /** 2931 * Merge all the existing client configurations with the (optional) input configuration request. 2932 * If the configurations are "incompatible" (rules in comment below) return a null. 2933 */ 2934 private ConfigRequest mergeConfigRequests(ConfigRequest configRequest) { 2935 if (VDBG) { 2936 Log.v(TAG, "mergeConfigRequests(): mClients=[" + mClients + "], configRequest=" 2937 + configRequest); 2938 } 2939 2940 if (mClients.size() == 0 && configRequest == null) { 2941 Log.e(TAG, "mergeConfigRequests: invalid state - called with 0 clients registered!"); 2942 return null; 2943 } 2944 2945 // TODO: continue working on merge algorithm: 2946 // - if any request 5g: enable 2947 // - maximal master preference 2948 // - cluster range: must be identical 2949 // - if any request identity change: enable 2950 // - discovery window: minimum value if specified, 0 (disable) is considered an infinity 2951 boolean support5gBand = false; 2952 int masterPreference = 0; 2953 boolean clusterIdValid = false; 2954 int clusterLow = 0; 2955 int clusterHigh = ConfigRequest.CLUSTER_ID_MAX; 2956 int[] discoveryWindowInterval = 2957 {ConfigRequest.DW_INTERVAL_NOT_INIT, ConfigRequest.DW_INTERVAL_NOT_INIT}; 2958 if (configRequest != null) { 2959 support5gBand = configRequest.mSupport5gBand; 2960 masterPreference = configRequest.mMasterPreference; 2961 clusterIdValid = true; 2962 clusterLow = configRequest.mClusterLow; 2963 clusterHigh = configRequest.mClusterHigh; 2964 discoveryWindowInterval = configRequest.mDiscoveryWindowInterval; 2965 } 2966 for (int i = 0; i < mClients.size(); ++i) { 2967 ConfigRequest cr = mClients.valueAt(i).getConfigRequest(); 2968 2969 // any request turns on 5G 2970 if (cr.mSupport5gBand) { 2971 support5gBand = true; 2972 } 2973 2974 // maximal master preference 2975 masterPreference = Math.max(masterPreference, cr.mMasterPreference); 2976 2977 // cluster range must be the same across all config requests 2978 if (!clusterIdValid) { 2979 clusterIdValid = true; 2980 clusterLow = cr.mClusterLow; 2981 clusterHigh = cr.mClusterHigh; 2982 } else { 2983 if (clusterLow != cr.mClusterLow) return null; 2984 if (clusterHigh != cr.mClusterHigh) return null; 2985 } 2986 2987 for (int band = ConfigRequest.NAN_BAND_24GHZ; band <= ConfigRequest.NAN_BAND_5GHZ; 2988 ++band) { 2989 if (discoveryWindowInterval[band] == ConfigRequest.DW_INTERVAL_NOT_INIT) { 2990 discoveryWindowInterval[band] = cr.mDiscoveryWindowInterval[band]; 2991 } else if (cr.mDiscoveryWindowInterval[band] 2992 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 2993 // do nothing: keep my values 2994 } else if (discoveryWindowInterval[band] == ConfigRequest.DW_DISABLE) { 2995 discoveryWindowInterval[band] = cr.mDiscoveryWindowInterval[band]; 2996 } else if (cr.mDiscoveryWindowInterval[band] == ConfigRequest.DW_DISABLE) { 2997 // do nothing: keep my values 2998 } else { 2999 discoveryWindowInterval[band] = Math.min(discoveryWindowInterval[band], 3000 cr.mDiscoveryWindowInterval[band]); 3001 } 3002 } 3003 } 3004 ConfigRequest.Builder builder = new ConfigRequest.Builder().setSupport5gBand(support5gBand) 3005 .setMasterPreference(masterPreference).setClusterLow(clusterLow) 3006 .setClusterHigh(clusterHigh); 3007 for (int band = ConfigRequest.NAN_BAND_24GHZ; band <= ConfigRequest.NAN_BAND_5GHZ; ++band) { 3008 if (discoveryWindowInterval[band] != ConfigRequest.DW_INTERVAL_NOT_INIT) { 3009 builder.setDiscoveryWindowInterval(band, discoveryWindowInterval[band]); 3010 } 3011 } 3012 return builder.build(); 3013 } 3014 3015 private boolean doesAnyClientNeedIdentityChangeNotifications() { 3016 for (int i = 0; i < mClients.size(); ++i) { 3017 if (mClients.valueAt(i).getNotifyIdentityChange()) { 3018 return true; 3019 } 3020 } 3021 return false; 3022 } 3023 3024 private static String messageToString(Message msg) { 3025 StringBuilder sb = new StringBuilder(); 3026 3027 String s = sSmToString.get(msg.what); 3028 if (s == null) { 3029 s = "<unknown>"; 3030 } 3031 sb.append(s).append("/"); 3032 3033 if (msg.what == MESSAGE_TYPE_NOTIFICATION || msg.what == MESSAGE_TYPE_COMMAND 3034 || msg.what == MESSAGE_TYPE_RESPONSE) { 3035 s = sSmToString.get(msg.arg1); 3036 if (s == null) { 3037 s = "<unknown>"; 3038 } 3039 sb.append(s); 3040 } 3041 3042 if (msg.what == MESSAGE_TYPE_RESPONSE || msg.what == MESSAGE_TYPE_RESPONSE_TIMEOUT) { 3043 sb.append(" (Transaction ID=").append(msg.arg2).append(")"); 3044 } 3045 3046 return sb.toString(); 3047 } 3048 3049 /** 3050 * Dump the internal state of the class. 3051 */ 3052 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3053 pw.println("AwareStateManager:"); 3054 pw.println(" mClients: [" + mClients + "]"); 3055 pw.println(" mUsageEnabled: " + mUsageEnabled); 3056 pw.println(" mCapabilities: [" + mCapabilities + "]"); 3057 pw.println(" mCurrentAwareConfiguration: " + mCurrentAwareConfiguration); 3058 pw.println(" mCurrentIdentityNotification: " + mCurrentIdentityNotification); 3059 for (int i = 0; i < mClients.size(); ++i) { 3060 mClients.valueAt(i).dump(fd, pw, args); 3061 } 3062 pw.println(" mSettableParameters: " + mSettableParameters); 3063 mSm.dump(fd, pw, args); 3064 mRtt.dump(fd, pw, args); 3065 mDataPathMgr.dump(fd, pw, args); 3066 mWifiAwareNativeApi.dump(fd, pw, args); 3067 } 3068 } 3069