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