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