RttService.java revision 435236f48f94a8373fa71251a3223e642f446e77
1package com.android.server.wifi;
2
3import android.Manifest;
4import android.content.BroadcastReceiver;
5import android.content.Context;
6import android.content.Intent;
7import android.content.IntentFilter;
8import android.content.pm.PackageManager;
9import android.net.wifi.IApInterface;
10import android.net.wifi.IClientInterface;
11import android.net.wifi.IInterfaceEventCallback;
12import android.net.wifi.IRttManager;
13import android.net.wifi.IWificond;
14import android.net.wifi.RttManager;
15import android.net.wifi.RttManager.ResponderConfig;
16import android.net.wifi.WifiManager;
17import android.os.Binder;
18import android.os.Bundle;
19import android.os.Handler;
20import android.os.HandlerThread;
21import android.os.IBinder;
22import android.os.Looper;
23import android.os.Message;
24import android.os.Messenger;
25import android.os.RemoteException;
26import android.util.ArrayMap;
27import android.util.Log;
28import android.util.Slog;
29
30import com.android.internal.annotations.GuardedBy;
31import com.android.internal.util.AsyncChannel;
32import com.android.internal.util.IState;
33import com.android.internal.util.Protocol;
34import com.android.internal.util.State;
35import com.android.internal.util.StateMachine;
36import com.android.server.SystemService;
37
38import java.io.FileDescriptor;
39import java.io.PrintWriter;
40import java.util.HashSet;
41import java.util.Iterator;
42import java.util.LinkedList;
43import java.util.List;
44import java.util.Queue;
45import java.util.Set;
46
47public 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 = WifiNative.getWlanNativeInterface();
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