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