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