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