WifiAwareRttStateManager.java revision f4274d887c5a26679849fd0e665207899e8bbad9
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
17package com.android.server.wifi.aware;
18
19import android.content.Context;
20import android.net.wifi.IRttManager;
21import android.net.wifi.RttManager;
22import android.os.Bundle;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.Looper;
26import android.os.Message;
27import android.os.Messenger;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.util.Log;
31import android.util.SparseArray;
32
33import com.android.internal.annotations.VisibleForTesting;
34import com.android.internal.util.AsyncChannel;
35
36import java.io.FileDescriptor;
37import java.io.PrintWriter;
38import java.util.Arrays;
39
40
41/**
42 * Manages interactions between the Aware and the RTT service. Duplicates some of the functionality
43 * of the RttManager.
44 */
45public class WifiAwareRttStateManager {
46    private static final String TAG = "WifiAwareRttStateMgr";
47
48    private static final boolean DBG = false;
49    private static final boolean VDBG = false; // STOPSHIP if true
50
51    private final SparseArray<WifiAwareClientState> mPendingOperations = new SparseArray<>();
52    private AsyncChannel mAsyncChannel;
53    private Context mContext;
54
55    /**
56     * Initializes the connection to the RTT service.
57     */
58    public void start(Context context, Looper looper) {
59        if (VDBG) Log.v(TAG, "start()");
60
61        IBinder b = ServiceManager.getService(Context.WIFI_RTT_SERVICE);
62        IRttManager service = IRttManager.Stub.asInterface(b);
63        if (service == null) {
64            Log.e(TAG, "start(): not able to get WIFI_RTT_SERVICE");
65            return;
66        }
67
68        startWithRttService(context, looper, service);
69    }
70
71    /**
72     * Initializes the connection to the RTT service.
73     */
74    @VisibleForTesting
75    public void startWithRttService(Context context, Looper looper, IRttManager service) {
76        Messenger messenger;
77        try {
78            messenger = service.getMessenger(null, new int[1]);
79        } catch (RemoteException e) {
80            Log.e(TAG, "start(): not able to getMessenger() of WIFI_RTT_SERVICE");
81            return;
82        }
83
84        mAsyncChannel = new AsyncChannel();
85        mAsyncChannel.connect(context, new AwareRttHandler(looper), messenger);
86        mContext = context;
87    }
88
89    private WifiAwareClientState getAndRemovePendingOperationClient(int rangingId) {
90        WifiAwareClientState client = mPendingOperations.get(rangingId);
91        mPendingOperations.delete(rangingId);
92        return client;
93    }
94
95    /**
96     * Start a ranging operation for the client + peer MAC.
97     */
98    public void startRanging(int rangingId, WifiAwareClientState client,
99                             RttManager.RttParams[] params) {
100        if (VDBG) {
101            Log.v(TAG, "startRanging: rangingId=" + rangingId + ", parms="
102                    + Arrays.toString(params));
103        }
104
105        if (mAsyncChannel == null) {
106            Log.d(TAG, "startRanging(): AsyncChannel to RTT service not configured - failing");
107            client.onRangingFailure(rangingId, RttManager.REASON_NOT_AVAILABLE,
108                    "Aware service not able to configure connection to RTT service");
109            return;
110        }
111
112        mPendingOperations.put(rangingId, client);
113        RttManager.ParcelableRttParams pparams = new RttManager.ParcelableRttParams(params);
114        mAsyncChannel.sendMessage(RttManager.CMD_OP_START_RANGING, 0, rangingId, pparams);
115    }
116
117    private class AwareRttHandler extends Handler {
118        AwareRttHandler(Looper looper) {
119            super(looper);
120        }
121
122        @Override
123        public void handleMessage(Message msg) {
124            if (VDBG) Log.v(TAG, "handleMessage(): " + msg.what);
125
126            // channel configuration messages
127            switch (msg.what) {
128                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
129                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
130                        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION,
131                                new RttManager.RttClient(mContext.getPackageName()));
132                    } else {
133                        Log.e(TAG, "Failed to set up channel connection to RTT service");
134                        mAsyncChannel = null;
135                    }
136                    return;
137                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
138                    /* NOP */
139                    return;
140                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
141                    Log.e(TAG, "Channel connection to RTT service lost");
142                    mAsyncChannel = null;
143                    return;
144            }
145
146            // RTT-specific messages
147            WifiAwareClientState client = getAndRemovePendingOperationClient(msg.arg2);
148            if (client == null) {
149                Log.e(TAG, "handleMessage(): RTT message (" + msg.what
150                        + ") -- cannot find registered pending operation client for ID "
151                        + msg.arg2);
152                return;
153            }
154
155            switch (msg.what) {
156                case RttManager.CMD_OP_SUCCEEDED: {
157                    int rangingId = msg.arg2;
158                    RttManager.ParcelableRttResults results = (RttManager.ParcelableRttResults)
159                            msg.obj;
160                    if (VDBG) {
161                        Log.v(TAG, "CMD_OP_SUCCEEDED: rangingId=" + rangingId + ", results="
162                                + results);
163                    }
164                    for (int i = 0; i < results.mResults.length; ++i) {
165                        /*
166                         * TODO: store peer ID rather than null in the return result.
167                         */
168                        results.mResults[i].bssid = null;
169                    }
170                    client.onRangingSuccess(rangingId, results);
171                    break;
172                }
173                case RttManager.CMD_OP_FAILED: {
174                    int rangingId = msg.arg2;
175                    int reason = msg.arg1;
176                    String description = ((Bundle) msg.obj).getString(RttManager.DESCRIPTION_KEY);
177                    if (VDBG) {
178                        Log.v(TAG, "CMD_OP_FAILED: rangingId=" + rangingId + ", reason=" + reason
179                                + ", description=" + description);
180                    }
181                    client.onRangingFailure(rangingId, reason, description);
182                    break;
183                }
184                case RttManager.CMD_OP_ABORTED: {
185                    int rangingId = msg.arg2;
186                    if (VDBG) {
187                        Log.v(TAG, "CMD_OP_ABORTED: rangingId=" + rangingId);
188                    }
189                    client.onRangingAborted(rangingId);
190                    break;
191                }
192                default:
193                    Log.e(TAG, "handleMessage(): ignoring message " + msg.what);
194                    break;
195            }
196        }
197    }
198
199    /**
200     * Dump the internal state of the class.
201     */
202    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
203        pw.println("WifiAwareRttStateManager:");
204        pw.println("  mPendingOperations: [" + mPendingOperations + "]");
205    }
206}
207