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