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