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