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