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