| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wifi.nan; |
| |
| import android.content.Context; |
| import android.net.wifi.IRttManager; |
| import android.net.wifi.RttManager; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.Messenger; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.util.Log; |
| import android.util.SparseArray; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.util.AsyncChannel; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.util.Arrays; |
| |
| |
| /** |
| * Manages interactions between the NAN and the RTT service. Duplicates some of the functionality |
| * of the RttManager. |
| */ |
| public class WifiNanRttStateManager { |
| private static final String TAG = "WifiNanRttStateManager"; |
| |
| private static final boolean DBG = true; |
| private static final boolean VDBG = true; // STOPSHIP if true |
| |
| private final SparseArray<WifiNanClientState> mPendingOperations = new SparseArray<>(); |
| private AsyncChannel mAsyncChannel; |
| |
| /** |
| * Initializes the connection to the RTT service. |
| */ |
| public void start(Context context, Looper looper) { |
| if (VDBG) Log.v(TAG, "start()"); |
| |
| IBinder b = ServiceManager.getService(Context.WIFI_RTT_SERVICE); |
| IRttManager service = IRttManager.Stub.asInterface(b); |
| if (service == null) { |
| Log.e(TAG, "start(): not able to get WIFI_RTT_SERVICE"); |
| return; |
| } |
| |
| startWithRttService(context, looper, service); |
| } |
| |
| /** |
| * Initializes the connection to the RTT service. |
| */ |
| @VisibleForTesting |
| public void startWithRttService(Context context, Looper looper, IRttManager service) { |
| Messenger messenger; |
| try { |
| messenger = service.getMessenger(); |
| } catch (RemoteException e) { |
| Log.e(TAG, "start(): not able to getMessenger() of WIFI_RTT_SERVICE"); |
| return; |
| } |
| |
| mAsyncChannel = new AsyncChannel(); |
| mAsyncChannel.connect(context, new NanRttHandler(looper), messenger); |
| } |
| |
| private WifiNanClientState getAndRemovePendingOperationClient(int rangingId) { |
| WifiNanClientState client = mPendingOperations.get(rangingId); |
| mPendingOperations.delete(rangingId); |
| return client; |
| } |
| |
| /** |
| * Start a ranging operation for the client + peer MAC. |
| */ |
| public void startRanging(int rangingId, WifiNanClientState client, |
| RttManager.RttParams[] params) { |
| if (VDBG) { |
| Log.v(TAG, "startRanging: rangingId=" + rangingId + ", parms=" |
| + Arrays.toString(params)); |
| } |
| |
| if (mAsyncChannel == null) { |
| Log.d(TAG, "startRanging(): AsyncChannel to RTT service not configured - failing"); |
| client.onRangingFailure(rangingId, RttManager.REASON_NOT_AVAILABLE, |
| "NAN service not able to configure connection to RTT service"); |
| return; |
| } |
| |
| mPendingOperations.put(rangingId, client); |
| RttManager.ParcelableRttParams pparams = new RttManager.ParcelableRttParams(params); |
| mAsyncChannel.sendMessage(RttManager.CMD_OP_START_RANGING, 0, rangingId, pparams); |
| } |
| |
| private class NanRttHandler extends Handler { |
| NanRttHandler(Looper looper) { |
| super(looper); |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| if (VDBG) Log.v(TAG, "handleMessage(): " + msg.what); |
| |
| // channel configuration messages |
| switch (msg.what) { |
| case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: |
| if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { |
| mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); |
| } else { |
| Log.e(TAG, "Failed to set up channel connection to RTT service"); |
| mAsyncChannel = null; |
| } |
| return; |
| case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: |
| /* NOP */ |
| return; |
| case AsyncChannel.CMD_CHANNEL_DISCONNECTED: |
| Log.e(TAG, "Channel connection to RTT service lost"); |
| mAsyncChannel = null; |
| return; |
| } |
| |
| // RTT-specific messages |
| WifiNanClientState client = getAndRemovePendingOperationClient(msg.arg2); |
| if (client == null) { |
| Log.e(TAG, "handleMessage(): RTT message (" + msg.what |
| + ") -- cannot find registered pending operation client for ID " |
| + msg.arg2); |
| return; |
| } |
| |
| switch (msg.what) { |
| case RttManager.CMD_OP_SUCCEEDED: { |
| int rangingId = msg.arg2; |
| RttManager.ParcelableRttResults results = (RttManager.ParcelableRttResults) |
| msg.obj; |
| if (VDBG) { |
| Log.v(TAG, "CMD_OP_SUCCEEDED: rangingId=" + rangingId + ", results=" |
| + results); |
| } |
| for (int i = 0; i < results.mResults.length; ++i) { |
| /* |
| * TODO: store peer ID rather than null in the return result. |
| */ |
| results.mResults[i].bssid = null; |
| } |
| client.onRangingSuccess(rangingId, results); |
| break; |
| } |
| case RttManager.CMD_OP_FAILED: { |
| int rangingId = msg.arg2; |
| int reason = msg.arg1; |
| String description = ((Bundle) msg.obj).getString(RttManager.DESCRIPTION_KEY); |
| if (VDBG) { |
| Log.v(TAG, "CMD_OP_FAILED: rangingId=" + rangingId + ", reason=" + reason |
| + ", description=" + description); |
| } |
| client.onRangingFailure(rangingId, reason, description); |
| break; |
| } |
| case RttManager.CMD_OP_ABORTED: { |
| int rangingId = msg.arg2; |
| if (VDBG) { |
| Log.v(TAG, "CMD_OP_ABORTED: rangingId=" + rangingId); |
| } |
| client.onRangingAborted(rangingId); |
| break; |
| } |
| default: |
| Log.e(TAG, "handleMessage(): ignoring message " + msg.what); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Dump the internal state of the class. |
| */ |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| pw.println("WifiNanRttStateManager:"); |
| pw.println(" mPendingOperations: [" + mPendingOperations + "]"); |
| } |
| } |