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