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