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