blob: 9d9f2d40cd411202018e05434b35ad8a69c411a4 [file] [log] [blame]
/*
* 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 + "]");
}
}