Home | History | Annotate | Download | only in wifi
      1 package com.android.server.wifi;
      2 
      3 import android.Manifest;
      4 import android.content.BroadcastReceiver;
      5 import android.content.Context;
      6 import android.content.Intent;
      7 import android.content.IntentFilter;
      8 import android.content.pm.PackageManager;
      9 import android.net.wifi.IApInterface;
     10 import android.net.wifi.IClientInterface;
     11 import android.net.wifi.IInterfaceEventCallback;
     12 import android.net.wifi.IRttManager;
     13 import android.net.wifi.IWificond;
     14 import android.net.wifi.RttManager;
     15 import android.net.wifi.RttManager.ResponderConfig;
     16 import android.net.wifi.WifiManager;
     17 import android.os.Binder;
     18 import android.os.Bundle;
     19 import android.os.Handler;
     20 import android.os.HandlerThread;
     21 import android.os.IBinder;
     22 import android.os.Looper;
     23 import android.os.Message;
     24 import android.os.Messenger;
     25 import android.os.RemoteException;
     26 import android.util.ArrayMap;
     27 import android.util.Log;
     28 import android.util.Slog;
     29 
     30 import com.android.internal.annotations.GuardedBy;
     31 import com.android.internal.util.AsyncChannel;
     32 import com.android.internal.util.IState;
     33 import com.android.internal.util.Protocol;
     34 import com.android.internal.util.State;
     35 import com.android.internal.util.StateMachine;
     36 import com.android.server.SystemService;
     37 
     38 import java.io.FileDescriptor;
     39 import java.io.PrintWriter;
     40 import java.util.HashSet;
     41 import java.util.Iterator;
     42 import java.util.LinkedList;
     43 import java.util.List;
     44 import java.util.Queue;
     45 import java.util.Set;
     46 
     47 public final class RttService extends SystemService {
     48 
     49     public static final boolean DBG = true;
     50     private static final String WIFICOND_SERVICE_NAME = "wificond";
     51 
     52     static class RttServiceImpl extends IRttManager.Stub {
     53 
     54         @Override
     55         public Messenger getMessenger() {
     56             return new Messenger(mClientHandler);
     57         }
     58 
     59         private class ClientHandler extends Handler {
     60 
     61             ClientHandler(android.os.Looper looper) {
     62                 super(looper);
     63             }
     64 
     65             @Override
     66             public void handleMessage(Message msg) {
     67 
     68                 if (DBG) {
     69                     Log.d(TAG, "ClientHandler got" + msg + " what = " + getDescription(msg.what));
     70                 }
     71 
     72                 switch (msg.what) {
     73 
     74                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
     75                         if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
     76                             Slog.e(TAG, "Send failed, client connection lost");
     77                         } else {
     78                             if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
     79                         }
     80                         if (DBG) Slog.d(TAG, "closing client " + msg.replyTo);
     81                         synchronized (mLock) {
     82                             ClientInfo ci = mClients.remove(msg.replyTo);
     83                             if (ci != null) ci.cleanup();
     84                         }
     85                         return;
     86                     case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
     87                         AsyncChannel ac = new AsyncChannel();
     88                         ac.connected(mContext, this, msg.replyTo);
     89                         ClientInfo client = new ClientInfo(ac, msg.sendingUid);
     90                         synchronized (mLock) {
     91                             mClients.put(msg.replyTo, client);
     92                         }
     93                         ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
     94                                 AsyncChannel.STATUS_SUCCESSFUL);
     95                         return;
     96                 }
     97 
     98                 ClientInfo ci;
     99                 synchronized (mLock) {
    100                     ci = mClients.get(msg.replyTo);
    101                 }
    102                 if (ci == null) {
    103                     Slog.e(TAG, "Could not find client info for message " + msg.replyTo);
    104                     replyFailed(msg, RttManager.REASON_INVALID_LISTENER, "Could not find listener");
    105                     return;
    106                 }
    107                 if (!enforcePermissionCheck(msg)) {
    108                     replyFailed(msg, RttManager.REASON_PERMISSION_DENIED,
    109                             "Client doesn't have LOCATION_HARDWARE permission");
    110                     return;
    111                 }
    112                 final int validCommands[] = {
    113                         RttManager.CMD_OP_START_RANGING,
    114                         RttManager.CMD_OP_STOP_RANGING,
    115                         RttManager.CMD_OP_ENABLE_RESPONDER,
    116                         RttManager.CMD_OP_DISABLE_RESPONDER,
    117                         };
    118 
    119                 for (int cmd : validCommands) {
    120                     if (cmd == msg.what) {
    121                         mStateMachine.sendMessage(Message.obtain(msg));
    122                         return;
    123                     }
    124                 }
    125 
    126                 replyFailed(msg, RttManager.REASON_INVALID_REQUEST, "Invalid request");
    127             }
    128 
    129             private String getDescription(int what) {
    130                 switch(what) {
    131                     case RttManager.CMD_OP_ENABLE_RESPONDER:
    132                         return "CMD_OP_ENABLE_RESPONDER";
    133                     case RttManager.CMD_OP_DISABLE_RESPONDER:
    134                         return "CMD_OP_DISABLE_RESPONDER";
    135                     default:
    136                         return "CMD_UNKNOWN";
    137                 }
    138             }
    139         }
    140 
    141         private final WifiNative mWifiNative;
    142         private final Context mContext;
    143         private final Looper mLooper;
    144         private RttStateMachine mStateMachine;
    145         private ClientHandler mClientHandler;
    146         private WifiInjector mWifiInjector;
    147 
    148         RttServiceImpl(Context context, Looper looper, WifiInjector wifiInjector) {
    149             mContext = context;
    150             mWifiNative = wifiInjector.getWifiNative();
    151             mLooper = looper;
    152             mWifiInjector = wifiInjector;
    153         }
    154 
    155         public void startService() {
    156             mClientHandler = new ClientHandler(mLooper);
    157             mStateMachine = new RttStateMachine(mLooper);
    158             mContext.registerReceiver(
    159                     new BroadcastReceiver() {
    160                         @Override
    161                         public void onReceive(Context context, Intent intent) {
    162                             int state = intent.getIntExtra(
    163                                     WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
    164                             if (DBG) Log.d(TAG, "SCAN_AVAILABLE : " + state);
    165                             if (state == WifiManager.WIFI_STATE_ENABLED) {
    166                                 mStateMachine.sendMessage(CMD_DRIVER_LOADED);
    167                             } else if (state == WifiManager.WIFI_STATE_DISABLED) {
    168                                 mStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
    169                             }
    170                         }
    171                     }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));
    172 
    173             mStateMachine.start();
    174         }
    175 
    176         private class RttRequest {
    177             Integer key;
    178             ClientInfo ci;
    179             RttManager.RttParams[] params;
    180 
    181             @Override
    182             public String toString() {
    183                 String str = getClass().getName() + "@" + Integer.toHexString(hashCode());
    184                 if(this.key != null) {
    185                     return str + " key: " + this.key;
    186                 } else {
    187                     return str + " key: " + " , null";
    188                 }
    189             }
    190         }
    191 
    192         private class ClientInfo {
    193             private final AsyncChannel mChannel;
    194             private final int mUid;
    195 
    196             ArrayMap<Integer, RttRequest> mRequests = new ArrayMap<>();
    197             // Client keys of all outstanding responders.
    198             Set<Integer> mResponderRequests = new HashSet<>();
    199 
    200             ClientInfo(AsyncChannel channel, int uid) {
    201                 mChannel = channel;
    202                 mUid = uid;
    203             }
    204 
    205             void addResponderRequest(int key) {
    206                 mResponderRequests.add(key);
    207             }
    208 
    209             void removeResponderRequest(int key) {
    210                 mResponderRequests.remove(key);
    211             }
    212 
    213             boolean addRttRequest(int key, RttManager.ParcelableRttParams parcelableParams) {
    214                 if (parcelableParams == null) {
    215                     return false;
    216                 }
    217 
    218                 RttManager.RttParams params[] = parcelableParams.mParams;
    219 
    220                 RttRequest request = new RttRequest();
    221                 request.key = key;
    222                 request.ci = this;
    223                 request.params = params;
    224                 mRequests.put(key, request);
    225                 mRequestQueue.add(request);
    226                 return true;
    227             }
    228 
    229             void removeRttRequest(int key) {
    230                 mRequests.remove(key);
    231             }
    232 
    233             void reportResponderEnableSucceed(int key, ResponderConfig config) {
    234                 mChannel.sendMessage(RttManager.CMD_OP_ENALBE_RESPONDER_SUCCEEDED, 0, key, config);
    235             }
    236 
    237             void reportResponderEnableFailed(int key, int reason) {
    238                 mChannel.sendMessage(RttManager.CMD_OP_ENALBE_RESPONDER_FAILED, reason, key);
    239                 removeResponderRequest(key);
    240             }
    241 
    242             void reportResult(RttRequest request, RttManager.RttResult[] results) {
    243                 RttManager.ParcelableRttResults parcelableResults =
    244                         new RttManager.ParcelableRttResults(results);
    245 
    246                 mChannel.sendMessage(RttManager.CMD_OP_SUCCEEDED,
    247                         0, request.key, parcelableResults);
    248                 removeRttRequest(request.key);
    249             }
    250 
    251             void reportFailed(RttRequest request, int reason, String description) {
    252                 reportFailed(request.key, reason, description);
    253             }
    254 
    255             void reportFailed(int key, int reason, String description) {
    256                 Bundle bundle = new Bundle();
    257                 bundle.putString(RttManager.DESCRIPTION_KEY, description);
    258                 mChannel.sendMessage(RttManager.CMD_OP_FAILED, key, reason, bundle);
    259                 removeRttRequest(key);
    260             }
    261 
    262             void reportAborted(int key) {
    263                 mChannel.sendMessage(RttManager.CMD_OP_ABORTED, 0, key);
    264                 //All Queued RTT request will be cleaned
    265                 cleanup();
    266             }
    267 
    268             void cleanup() {
    269                 mRequests.clear();
    270                 mRequestQueue.clear();
    271                 // When client is lost, clean up responder requests and send disable responder
    272                 // message to RttStateMachine.
    273                 mResponderRequests.clear();
    274                 mStateMachine.sendMessage(RttManager.CMD_OP_DISABLE_RESPONDER);
    275             }
    276 
    277             @Override
    278             public String toString() {
    279                 return "ClientInfo [uid=" + mUid + ", channel=" + mChannel + "]";
    280             }
    281         }
    282 
    283         private Queue<RttRequest> mRequestQueue = new LinkedList<>();
    284 
    285         @GuardedBy("mLock")
    286         private ArrayMap<Messenger, ClientInfo> mClients = new ArrayMap<>();
    287         // Lock for mClients.
    288         private final Object mLock = new Object();
    289 
    290         private static final int BASE = Protocol.BASE_WIFI_RTT_SERVICE;
    291 
    292         private static final int CMD_DRIVER_LOADED                       = BASE + 0;
    293         private static final int CMD_DRIVER_UNLOADED                     = BASE + 1;
    294         private static final int CMD_ISSUE_NEXT_REQUEST                  = BASE + 2;
    295         private static final int CMD_RTT_RESPONSE                        = BASE + 3;
    296         private static final int CMD_CLIENT_INTERFACE_READY              = BASE + 4;
    297         private static final int CMD_CLIENT_INTERFACE_DOWN               = BASE + 5;
    298 
    299         // Maximum duration for responder role.
    300         private static final int MAX_RESPONDER_DURATION_SECONDS = 60 * 10;
    301 
    302         private static class InterfaceEventHandler extends IInterfaceEventCallback.Stub {
    303             InterfaceEventHandler(RttStateMachine rttStateMachine) {
    304                 mRttStateMachine = rttStateMachine;
    305             }
    306             @Override
    307             public void OnClientTorndownEvent(IClientInterface networkInterface) {
    308                 mRttStateMachine.sendMessage(CMD_CLIENT_INTERFACE_DOWN, networkInterface);
    309             }
    310             @Override
    311             public void OnClientInterfaceReady(IClientInterface networkInterface) {
    312                 mRttStateMachine.sendMessage(CMD_CLIENT_INTERFACE_READY, networkInterface);
    313             }
    314             @Override
    315             public void OnApTorndownEvent(IApInterface networkInterface) { }
    316             @Override
    317             public void OnApInterfaceReady(IApInterface networkInterface) { }
    318 
    319             private RttStateMachine mRttStateMachine;
    320         }
    321 
    322         class RttStateMachine extends StateMachine {
    323             private IWificond mWificond;
    324             private InterfaceEventHandler mInterfaceEventHandler;
    325             private IClientInterface mClientInterface;
    326 
    327             DefaultState mDefaultState = new DefaultState();
    328             EnabledState mEnabledState = new EnabledState();
    329             InitiatorEnabledState mInitiatorEnabledState = new InitiatorEnabledState();
    330             ResponderEnabledState mResponderEnabledState = new ResponderEnabledState();
    331             ResponderConfig mResponderConfig;
    332 
    333             RttStateMachine(Looper looper) {
    334                 super("RttStateMachine", looper);
    335 
    336                 // CHECKSTYLE:OFF IndentationCheck
    337                 addState(mDefaultState);
    338                 addState(mEnabledState);
    339                     addState(mInitiatorEnabledState, mEnabledState);
    340                     addState(mResponderEnabledState, mEnabledState);
    341                 // CHECKSTYLE:ON IndentationCheck
    342 
    343                 setInitialState(mDefaultState);
    344             }
    345 
    346             class DefaultState extends State {
    347                 @Override
    348                 public boolean processMessage(Message msg) {
    349                     if (DBG) Log.d(TAG, "DefaultState got" + msg);
    350                     switch (msg.what) {
    351                         case CMD_DRIVER_LOADED:
    352                             transitionTo(mEnabledState);
    353                             break;
    354                         case CMD_ISSUE_NEXT_REQUEST:
    355                             deferMessage(msg);
    356                             break;
    357                         case RttManager.CMD_OP_START_RANGING:
    358                             replyFailed(msg, RttManager.REASON_NOT_AVAILABLE, "Try later");
    359                             break;
    360                         case RttManager.CMD_OP_STOP_RANGING:
    361                             return HANDLED;
    362                         case RttManager.CMD_OP_ENABLE_RESPONDER:
    363 
    364                             ClientInfo client;
    365                             synchronized (mLock) {
    366                                 client = mClients.get(msg.replyTo);
    367                             }
    368                             if (client == null) {
    369                                 Log.e(TAG, "client not connected yet!");
    370                                 break;
    371                             }
    372                             int key = msg.arg2;
    373                             client.reportResponderEnableFailed(key,
    374                                     RttManager.REASON_NOT_AVAILABLE);
    375                             break;
    376                         case RttManager.CMD_OP_DISABLE_RESPONDER:
    377                             return HANDLED;
    378                         default:
    379                             return NOT_HANDLED;
    380                     }
    381                     return HANDLED;
    382                 }
    383             }
    384 
    385             class EnabledState extends State {
    386                 @Override
    387                 public void enter() {
    388                     // This allows us to tolerate wificond restarts.
    389                     // When wificond restarts WifiStateMachine is supposed to go
    390                     // back to initial state and restart.
    391                     // 1) RttService watches for WIFI_STATE_ENABLED broadcasts
    392                     // 2) WifiStateMachine sends these broadcasts in the SupplicantStarted state
    393                     // 3) Since WSM will only be in SupplicantStarted for as long as wificond is
    394                     // alive, we refresh our wificond handler here and we don't subscribe to
    395                     // wificond's death explicitly.
    396                     mWificond = mWifiInjector.makeWificond();
    397                     if (mWificond == null) {
    398                         Log.w(TAG, "Failed to get wificond binder handler");
    399                         transitionTo(mDefaultState);
    400                     }
    401                     mInterfaceEventHandler = new InterfaceEventHandler(mStateMachine);
    402                     try {
    403                         mWificond.RegisterCallback(mInterfaceEventHandler);
    404                         // Get the current client interface, assuming there is at most
    405                         // one client interface for now.
    406                         List<IBinder> interfaces = mWificond.GetClientInterfaces();
    407                         if (interfaces.size() > 0) {
    408                             mStateMachine.sendMessage(
    409                                     CMD_CLIENT_INTERFACE_READY,
    410                                     IClientInterface.Stub.asInterface(interfaces.get(0)));
    411                         }
    412                     } catch (RemoteException e1) { }
    413 
    414                 }
    415                 @Override
    416                 public void exit() {
    417                     try {
    418                         mWificond.UnregisterCallback(mInterfaceEventHandler);
    419                     } catch (RemoteException e1) { }
    420                     mInterfaceEventHandler = null;
    421                 }
    422                 @Override
    423                 public boolean processMessage(Message msg) {
    424                     if (DBG) Log.d(TAG, "EnabledState got" + msg);
    425                     ClientInfo ci;
    426                     synchronized (mLock) {
    427                         ci = mClients.get(msg.replyTo);
    428                     }
    429 
    430                     switch (msg.what) {
    431                         case CMD_DRIVER_UNLOADED:
    432                             transitionTo(mDefaultState);
    433                             break;
    434                         case CMD_ISSUE_NEXT_REQUEST:
    435                             deferMessage(msg);
    436                             transitionTo(mInitiatorEnabledState);
    437                             break;
    438                         case RttManager.CMD_OP_START_RANGING: {
    439                             RttManager.ParcelableRttParams params =
    440                                     (RttManager.ParcelableRttParams)msg.obj;
    441                             if (params == null || params.mParams == null
    442                                     || params.mParams.length == 0) {
    443                                 replyFailed(msg,
    444                                         RttManager.REASON_INVALID_REQUEST, "No params");
    445                             } else if (ci.addRttRequest(msg.arg2, params) == false) {
    446                                 replyFailed(msg,
    447                                         RttManager.REASON_INVALID_REQUEST, "Unspecified");
    448                             } else {
    449                                 sendMessage(CMD_ISSUE_NEXT_REQUEST);
    450                             }
    451                         }
    452                             break;
    453                         case RttManager.CMD_OP_STOP_RANGING:
    454                             for (Iterator<RttRequest> it = mRequestQueue.iterator();
    455                                     it.hasNext(); ) {
    456                                 RttRequest request = it.next();
    457                                 if (request.key == msg.arg2) {
    458                                     if (DBG) Log.d(TAG, "Cancelling not-yet-scheduled RTT");
    459                                     mRequestQueue.remove(request);
    460                                     request.ci.reportAborted(request.key);
    461                                     break;
    462                                 }
    463                             }
    464                             break;
    465                         case RttManager.CMD_OP_ENABLE_RESPONDER:
    466                             int key = msg.arg2;
    467                             mResponderConfig =
    468                                     mWifiNative.enableRttResponder(MAX_RESPONDER_DURATION_SECONDS);
    469                             if (DBG) Log.d(TAG, "mWifiNative.enableRttResponder called");
    470 
    471                             if (mResponderConfig != null) {
    472                                 // TODO: remove once mac address is added when enabling responder.
    473                                 mResponderConfig.macAddress = mWifiNative.getMacAddress();
    474                                 ci.addResponderRequest(key);
    475                                 ci.reportResponderEnableSucceed(key, mResponderConfig);
    476                                 transitionTo(mResponderEnabledState);
    477                             } else {
    478                                 Log.e(TAG, "enable responder failed");
    479                                 ci.reportResponderEnableFailed(key, RttManager.REASON_UNSPECIFIED);
    480                             }
    481                             break;
    482                         case RttManager.CMD_OP_DISABLE_RESPONDER:
    483                             break;
    484                         case CMD_CLIENT_INTERFACE_DOWN:
    485                             if (mClientInterface == (IClientInterface) msg.obj) {
    486                                 mClientInterface = null;
    487                             }
    488                             break;
    489                         case CMD_CLIENT_INTERFACE_READY:
    490                             mClientInterface = (IClientInterface) msg.obj;
    491                             break;
    492                         default:
    493                             return NOT_HANDLED;
    494                     }
    495                     return HANDLED;
    496                 }
    497             }
    498 
    499             class InitiatorEnabledState extends State {
    500                 RttRequest mOutstandingRequest;
    501                 @Override
    502                 public boolean processMessage(Message msg) {
    503                     if (DBG) Log.d(TAG, "RequestPendingState got" + msg);
    504                     switch (msg.what) {
    505                         case CMD_DRIVER_UNLOADED:
    506                             if (mOutstandingRequest != null) {
    507                                 mWifiNative.cancelRtt(mOutstandingRequest.params);
    508                                 if (DBG) Log.d(TAG, "abort key: " + mOutstandingRequest.key);
    509                                 mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key);
    510                                 mOutstandingRequest = null;
    511                             }
    512                             transitionTo(mDefaultState);
    513                             break;
    514                         case CMD_ISSUE_NEXT_REQUEST:
    515                             if (mOutstandingRequest == null) {
    516                                 mOutstandingRequest = issueNextRequest();
    517                                 if (mOutstandingRequest == null) {
    518                                     transitionTo(mEnabledState);
    519                                 }
    520                                 if(mOutstandingRequest != null) {
    521                                     if (DBG) Log.d(TAG, "new mOutstandingRequest.key is: " +
    522                                             mOutstandingRequest.key);
    523                                 } else {
    524                                     if (DBG) Log.d(TAG,
    525                                             "CMD_ISSUE_NEXT_REQUEST: mOutstandingRequest =null ");
    526                                 }
    527                             } else {
    528                                 /* just wait; we'll issue next request after
    529                                  * current one is finished */
    530                                  if (DBG) Log.d(TAG, "Current mOutstandingRequest.key is: " +
    531                                          mOutstandingRequest.key);
    532                                  if (DBG) Log.d(TAG, "Ignoring CMD_ISSUE_NEXT_REQUEST");
    533                             }
    534                             break;
    535                         case CMD_RTT_RESPONSE:
    536                             if (DBG) Log.d(TAG, "Received an RTT response from: " + msg.arg2);
    537                             mOutstandingRequest.ci.reportResult(
    538                                     mOutstandingRequest, (RttManager.RttResult[])msg.obj);
    539                             mOutstandingRequest = null;
    540                             sendMessage(CMD_ISSUE_NEXT_REQUEST);
    541                             break;
    542                         case RttManager.CMD_OP_STOP_RANGING:
    543                             if (mOutstandingRequest != null
    544                                     && msg.arg2 == mOutstandingRequest.key) {
    545                                 if (DBG) Log.d(TAG, "Cancelling ongoing RTT of: " + msg.arg2);
    546                                 mWifiNative.cancelRtt(mOutstandingRequest.params);
    547                                 mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key);
    548                                 mOutstandingRequest = null;
    549                                 sendMessage(CMD_ISSUE_NEXT_REQUEST);
    550                             } else {
    551                                 /* Let EnabledState handle this */
    552                                 return NOT_HANDLED;
    553                             }
    554                             break;
    555                         default:
    556                             return NOT_HANDLED;
    557                     }
    558                     return HANDLED;
    559                 }
    560             }
    561 
    562             // Check if there are still outstanding responder requests from any client.
    563             private boolean hasOutstandingReponderRequests() {
    564                 synchronized (mLock) {
    565                     for (ClientInfo client : mClients.values()) {
    566                         if (!client.mResponderRequests.isEmpty()) {
    567                             return true;
    568                         }
    569                     }
    570                 }
    571                 return false;
    572             }
    573 
    574             /**
    575              * Representing an outstanding RTT responder state.
    576              */
    577             class ResponderEnabledState extends State {
    578                 @Override
    579                 public boolean processMessage(Message msg) {
    580                     if (DBG) Log.d(TAG, "ResponderEnabledState got " + msg);
    581                     ClientInfo ci;
    582                     synchronized (mLock) {
    583                         ci = mClients.get(msg.replyTo);
    584                     }
    585                     int key = msg.arg2;
    586                     switch(msg.what) {
    587                         case RttManager.CMD_OP_ENABLE_RESPONDER:
    588                             // Responder already enabled, simply return the responder config.
    589                             ci.addResponderRequest(key);
    590                             ci.reportResponderEnableSucceed(key, mResponderConfig);
    591                             return HANDLED;
    592                         case RttManager.CMD_OP_DISABLE_RESPONDER:
    593                             if (ci != null) {
    594                                 ci.removeResponderRequest(key);
    595                             }
    596                             // Only disable responder when there are no outstanding clients.
    597                             if (!hasOutstandingReponderRequests()) {
    598                                 if (!mWifiNative.disableRttResponder()) {
    599                                     Log.e(TAG, "disable responder failed");
    600                                 }
    601                                 if (DBG) Log.d(TAG, "mWifiNative.disableRttResponder called");
    602                                 transitionTo(mEnabledState);
    603                             }
    604                             return HANDLED;
    605                         case RttManager.CMD_OP_START_RANGING:
    606                         case RttManager.CMD_OP_STOP_RANGING:  // fall through
    607                             // Concurrent initiator and responder role is not supported.
    608                             replyFailed(msg,
    609                                     RttManager.REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON,
    610                                     "Initiator not allowed when responder is turned on");
    611                             return HANDLED;
    612                         default:
    613                             return NOT_HANDLED;
    614                     }
    615                 }
    616             }
    617 
    618             /**
    619              * Returns name of current state.
    620              */
    621             String currentState() {
    622                 IState state = getCurrentState();
    623                 return state == null ? "null" : state.getName();
    624             }
    625         }
    626 
    627         void replySucceeded(Message msg, Object obj) {
    628             if (msg.replyTo != null) {
    629                 Message reply = Message.obtain();
    630                 reply.what = RttManager.CMD_OP_SUCCEEDED;
    631                 reply.arg2 = msg.arg2;
    632                 reply.obj = obj;
    633                 try {
    634                     msg.replyTo.send(reply);
    635                 } catch (RemoteException e) {
    636                     // There's not much we can do if reply can't be sent!
    637                 }
    638             } else {
    639                 // locally generated message; doesn't need a reply!
    640             }
    641         }
    642 
    643         void replyFailed(Message msg, int reason, String description) {
    644             Message reply = Message.obtain();
    645             reply.what = RttManager.CMD_OP_FAILED;
    646             reply.arg1 = reason;
    647             reply.arg2 = msg.arg2;
    648 
    649             Bundle bundle = new Bundle();
    650             bundle.putString(RttManager.DESCRIPTION_KEY, description);
    651             reply.obj = bundle;
    652 
    653             try {
    654                 if (msg.replyTo != null) {
    655                     msg.replyTo.send(reply);
    656                 }
    657             } catch (RemoteException e) {
    658                 // There's not much we can do if reply can't be sent!
    659             }
    660         }
    661 
    662         boolean enforcePermissionCheck(Message msg) {
    663             try {
    664                 mContext.enforcePermission(Manifest.permission.LOCATION_HARDWARE,
    665                          -1, msg.sendingUid, "LocationRTT");
    666             } catch (SecurityException e) {
    667                 Log.e(TAG, "UID: " + msg.sendingUid + " has no LOCATION_HARDWARE Permission");
    668                 return false;
    669             }
    670             return true;
    671         }
    672 
    673         @Override
    674         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    675             if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
    676                     != PackageManager.PERMISSION_GRANTED) {
    677                 pw.println("Permission Denial: can't dump RttService from from pid="
    678                         + Binder.getCallingPid()
    679                         + ", uid=" + Binder.getCallingUid()
    680                         + " without permission "
    681                         + android.Manifest.permission.DUMP);
    682                 return;
    683             }
    684             pw.println("current state: " + mStateMachine.currentState());
    685             pw.println("clients:");
    686             synchronized (mLock) {
    687                 for (ClientInfo client : mClients.values()) {
    688                     pw.println("  " + client);
    689                 }
    690             }
    691         }
    692 
    693         private WifiNative.RttEventHandler mEventHandler = new WifiNative.RttEventHandler() {
    694             @Override
    695             public void onRttResults(RttManager.RttResult[] result) {
    696                 mStateMachine.sendMessage(CMD_RTT_RESPONSE, result);
    697             }
    698         };
    699 
    700         RttRequest issueNextRequest() {
    701             RttRequest request = null;
    702             while (mRequestQueue.isEmpty() == false) {
    703                 request = mRequestQueue.remove();
    704                 if(request !=  null) {
    705                     if (mWifiNative.requestRtt(request.params, mEventHandler)) {
    706                         if (DBG) Log.d(TAG, "Issued next RTT request with key: " + request.key);
    707                         return request;
    708                     } else {
    709                         Log.e(TAG, "Fail to issue key at native layer");
    710                         request.ci.reportFailed(request,
    711                                 RttManager.REASON_UNSPECIFIED, "Failed to start");
    712                     }
    713                 }
    714             }
    715 
    716             /* all requests exhausted */
    717             if (DBG) Log.d(TAG, "No more requests left");
    718             return null;
    719         }
    720         @Override
    721         public RttManager.RttCapabilities getRttCapabilities() {
    722             return mWifiNative.getRttCapabilities();
    723         }
    724     }
    725 
    726     private static final String TAG = "RttService";
    727     RttServiceImpl mImpl;
    728     private final HandlerThread mHandlerThread;
    729 
    730     public RttService(Context context) {
    731         super(context);
    732         mHandlerThread = new HandlerThread("WifiRttService");
    733         mHandlerThread.start();
    734         Log.i(TAG, "Creating " + Context.WIFI_RTT_SERVICE);
    735     }
    736 
    737     @Override
    738     public void onStart() {
    739         mImpl = new RttServiceImpl(getContext(),
    740                 mHandlerThread.getLooper(), WifiInjector.getInstance());
    741 
    742         Log.i(TAG, "Starting " + Context.WIFI_RTT_SERVICE);
    743         publishBinderService(Context.WIFI_RTT_SERVICE, mImpl);
    744     }
    745 
    746     @Override
    747     public void onBootPhase(int phase) {
    748         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
    749             Log.i(TAG, "Registering " + Context.WIFI_RTT_SERVICE);
    750             if (mImpl == null) {
    751                 mImpl = new RttServiceImpl(getContext(),
    752                         mHandlerThread.getLooper(),  WifiInjector.getInstance());
    753             }
    754             mImpl.startService();
    755         }
    756     }
    757 
    758 
    759 }
    760