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 17 package com.android.server.wifi.aware; 18 19 import android.annotation.NonNull; 20 import android.hardware.wifi.V1_0.IWifiNanIface; 21 import android.hardware.wifi.V1_0.WifiStatus; 22 import android.hardware.wifi.V1_0.WifiStatusCode; 23 import android.os.Handler; 24 import android.os.RemoteException; 25 import android.os.WorkSource; 26 import android.util.Log; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.server.wifi.HalDeviceManager; 30 31 import java.io.FileDescriptor; 32 import java.io.PrintWriter; 33 34 /** 35 * Manages the interface to Wi-Fi Aware HIDL (HAL). 36 */ 37 public class WifiAwareNativeManager { 38 private static final String TAG = "WifiAwareNativeManager"; 39 private boolean mDbg = false; 40 41 // to be used for synchronizing access to any of the WifiAwareNative objects 42 private final Object mLock = new Object(); 43 44 private WifiAwareStateManager mWifiAwareStateManager; 45 private HalDeviceManager mHalDeviceManager; 46 private Handler mHandler; 47 private WifiAwareNativeCallback mWifiAwareNativeCallback; 48 private IWifiNanIface mWifiNanIface = null; 49 private InterfaceDestroyedListener mInterfaceDestroyedListener; 50 private int mReferenceCount = 0; 51 WifiAwareNativeManager(WifiAwareStateManager awareStateManager, HalDeviceManager halDeviceManager, WifiAwareNativeCallback wifiAwareNativeCallback)52 WifiAwareNativeManager(WifiAwareStateManager awareStateManager, 53 HalDeviceManager halDeviceManager, 54 WifiAwareNativeCallback wifiAwareNativeCallback) { 55 mWifiAwareStateManager = awareStateManager; 56 mHalDeviceManager = halDeviceManager; 57 mWifiAwareNativeCallback = wifiAwareNativeCallback; 58 } 59 60 /** 61 * Enable verbose logging. 62 */ enableVerboseLogging(boolean verbose)63 public void enableVerboseLogging(boolean verbose) { 64 mDbg = verbose; 65 } 66 67 /** 68 * (HIDL) Cast the input to a 1.2 NAN interface (possibly resulting in a null). 69 * 70 * Separate function so can be mocked in unit tests. 71 */ mockableCastTo_1_2(IWifiNanIface iface)72 public android.hardware.wifi.V1_2.IWifiNanIface mockableCastTo_1_2(IWifiNanIface iface) { 73 return android.hardware.wifi.V1_2.IWifiNanIface.castFrom(iface); 74 } 75 76 /** 77 * (HIDL) Cast the input to a 1.5 NAN interface (possibly resulting in a null). 78 * 79 * Separate function so can be mocked in unit tests. 80 */ mockableCastTo_1_5(IWifiNanIface iface)81 public android.hardware.wifi.V1_5.IWifiNanIface mockableCastTo_1_5(IWifiNanIface iface) { 82 return android.hardware.wifi.V1_5.IWifiNanIface.castFrom(iface); 83 } 84 85 /** 86 * Initialize the class - intended for late initialization. 87 * 88 * @param handler Handler on which to execute interface available callbacks. 89 */ start(Handler handler)90 public void start(Handler handler) { 91 mHandler = handler; 92 mHalDeviceManager.initialize(); 93 mHalDeviceManager.registerStatusListener( 94 new HalDeviceManager.ManagerStatusListener() { 95 @Override 96 public void onStatusChanged() { 97 if (mDbg) Log.v(TAG, "onStatusChanged"); 98 // only care about isStarted (Wi-Fi started) not isReady - since if not 99 // ready then Wi-Fi will also be down. 100 if (mHalDeviceManager.isStarted()) { 101 mWifiAwareStateManager.tryToGetAwareCapability(); 102 } else { 103 awareIsDown(); 104 } 105 } 106 }, mHandler); 107 if (mHalDeviceManager.isStarted()) { 108 mWifiAwareStateManager.tryToGetAwareCapability(); 109 } 110 } 111 112 /** 113 * Returns the native HAL WifiNanIface through which commands to the NAN HAL are dispatched. 114 * Return may be null if not initialized/available. 115 */ 116 @VisibleForTesting getWifiNanIface()117 public IWifiNanIface getWifiNanIface() { 118 synchronized (mLock) { 119 return mWifiNanIface; 120 } 121 } 122 123 /** 124 * Attempt to obtain the HAL NAN interface. 125 */ tryToGetAware(@onNull WorkSource requestorWs)126 public void tryToGetAware(@NonNull WorkSource requestorWs) { 127 synchronized (mLock) { 128 if (mDbg) { 129 Log.d(TAG, "tryToGetAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount=" 130 + mReferenceCount + ", requestorWs=" + requestorWs); 131 } 132 133 if (mWifiNanIface != null) { 134 mReferenceCount++; 135 return; 136 } 137 if (mHalDeviceManager == null) { 138 Log.e(TAG, "tryToGetAware: mHalDeviceManager is null!?"); 139 awareIsDown(); 140 return; 141 } 142 143 mInterfaceDestroyedListener = new InterfaceDestroyedListener(); 144 IWifiNanIface iface = mHalDeviceManager.createNanIface(mInterfaceDestroyedListener, 145 mHandler, requestorWs); 146 if (iface == null) { 147 Log.e(TAG, "Was not able to obtain an IWifiNanIface (even though enabled!?)"); 148 awareIsDown(); 149 } else { 150 if (mDbg) Log.v(TAG, "Obtained an IWifiNanIface"); 151 152 try { 153 android.hardware.wifi.V1_2.IWifiNanIface iface12 = mockableCastTo_1_2(iface); 154 android.hardware.wifi.V1_5.IWifiNanIface iface15 = mockableCastTo_1_5(iface); 155 WifiStatus status; 156 if (iface15 != null) { 157 mWifiAwareNativeCallback.mIsHal12OrLater = true; 158 mWifiAwareNativeCallback.mIsHal15OrLater = true; 159 status = iface15.registerEventCallback_1_5(mWifiAwareNativeCallback); 160 } else if (iface12 != null) { 161 mWifiAwareNativeCallback.mIsHal12OrLater = true; 162 status = iface12.registerEventCallback_1_2(mWifiAwareNativeCallback); 163 } else { 164 status = iface.registerEventCallback(mWifiAwareNativeCallback); 165 } 166 if (status.code != WifiStatusCode.SUCCESS) { 167 Log.e(TAG, "IWifiNanIface.registerEventCallback error: " + statusString( 168 status)); 169 mHalDeviceManager.removeIface(iface); 170 awareIsDown(); 171 return; 172 } 173 } catch (RemoteException e) { 174 Log.e(TAG, "IWifiNanIface.registerEventCallback exception: " + e); 175 awareIsDown(); 176 return; 177 } 178 mWifiNanIface = iface; 179 mReferenceCount = 1; 180 } 181 } 182 } 183 184 /** 185 * Release the HAL NAN interface. 186 */ releaseAware()187 public void releaseAware() { 188 if (mDbg) { 189 Log.d(TAG, "releaseAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount=" 190 + mReferenceCount); 191 } 192 193 if (mWifiNanIface == null) { 194 return; 195 } 196 if (mHalDeviceManager == null) { 197 Log.e(TAG, "releaseAware: mHalDeviceManager is null!?"); 198 return; 199 } 200 201 synchronized (mLock) { 202 mReferenceCount--; 203 if (mReferenceCount != 0) { 204 return; 205 } 206 mInterfaceDestroyedListener.active = false; 207 mInterfaceDestroyedListener = null; 208 mHalDeviceManager.removeIface(mWifiNanIface); 209 mWifiNanIface = null; 210 mWifiAwareNativeCallback.resetChannelInfo(); 211 } 212 } 213 214 /** 215 * Replace requestorWs in-place when iface is already enabled. 216 */ replaceRequestorWs(@onNull WorkSource requestorWs)217 public boolean replaceRequestorWs(@NonNull WorkSource requestorWs) { 218 synchronized (mLock) { 219 if (mDbg) { 220 Log.d(TAG, "replaceRequestorWs: mWifiNanIface=" + mWifiNanIface 221 + ", mReferenceCount=" + mReferenceCount + ", requestorWs=" + requestorWs); 222 } 223 224 if (mWifiNanIface == null) { 225 return false; 226 } 227 if (mHalDeviceManager == null) { 228 Log.e(TAG, "tryToGetAware: mHalDeviceManager is null!?"); 229 awareIsDown(); 230 return false; 231 } 232 233 return mHalDeviceManager.replaceRequestorWs(mWifiNanIface, requestorWs); 234 } 235 } 236 awareIsDown()237 private void awareIsDown() { 238 synchronized (mLock) { 239 if (mDbg) { 240 Log.d(TAG, "awareIsDown: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount =" 241 + mReferenceCount); 242 } 243 mWifiNanIface = null; 244 mReferenceCount = 0; 245 mWifiAwareStateManager.disableUsage(true); 246 } 247 } 248 249 private class InterfaceDestroyedListener implements 250 HalDeviceManager.InterfaceDestroyedListener { 251 public boolean active = true; 252 253 @Override onDestroyed(@onNull String ifaceName)254 public void onDestroyed(@NonNull String ifaceName) { 255 if (mDbg) { 256 Log.d(TAG, "Interface was destroyed: mWifiNanIface=" + mWifiNanIface + ", active=" 257 + active); 258 } 259 if (active && mWifiNanIface != null) { 260 awareIsDown(); 261 } // else: we released it locally so no need to disable usage 262 } 263 } 264 statusString(WifiStatus status)265 private static String statusString(WifiStatus status) { 266 if (status == null) { 267 return "status=null"; 268 } 269 StringBuilder sb = new StringBuilder(); 270 sb.append(status.code).append(" (").append(status.description).append(")"); 271 return sb.toString(); 272 } 273 274 /** 275 * Dump the internal state of the class. 276 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)277 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 278 pw.println("WifiAwareNativeManager:"); 279 pw.println(" mWifiNanIface: " + mWifiNanIface); 280 pw.println(" mReferenceCount: " + mReferenceCount); 281 mWifiAwareNativeCallback.dump(fd, pw, args); 282 } 283 } 284