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