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