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