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