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