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