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