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.os.Handler; 21 import android.os.WorkSource; 22 import android.util.Log; 23 24 import com.android.internal.annotations.VisibleForTesting; 25 import com.android.server.wifi.HalDeviceManager; 26 import com.android.server.wifi.WifiNative; 27 import com.android.server.wifi.hal.WifiNanIface; 28 import com.android.wifi.flags.FeatureFlags; 29 30 import java.io.FileDescriptor; 31 import java.io.PrintWriter; 32 33 /** 34 * Manages the interface to the Wi-Fi Aware HAL. 35 */ 36 public class WifiAwareNativeManager { 37 private static final String TAG = "WifiAwareNativeManager"; 38 private boolean mVerboseLoggingEnabled = false; 39 40 // to be used for synchronizing access to any of the WifiAwareNative objects 41 private final Object mLock = new Object(); 42 43 private WifiAwareStateManager mWifiAwareStateManager; 44 private HalDeviceManager mHalDeviceManager; 45 private WifiNative mWifiNative; 46 private Handler mHandler; 47 private WifiAwareNativeCallback mWifiAwareNativeCallback; 48 private final FeatureFlags mFeatureFlags; 49 private WifiNanIface mWifiNanIface = null; 50 private WifiNative.Iface mNanIface; 51 private InterfaceDestroyedListener mInterfaceDestroyedListener; 52 private int mReferenceCount = 0; 53 WifiAwareNativeManager(WifiAwareStateManager awareStateManager, HalDeviceManager halDeviceManager, WifiAwareNativeCallback wifiAwareNativeCallback, WifiNative wifiNative, FeatureFlags featureFlags)54 WifiAwareNativeManager(WifiAwareStateManager awareStateManager, 55 HalDeviceManager halDeviceManager, 56 WifiAwareNativeCallback wifiAwareNativeCallback, 57 WifiNative wifiNative, 58 FeatureFlags featureFlags) { 59 mWifiAwareStateManager = awareStateManager; 60 mHalDeviceManager = halDeviceManager; 61 mWifiNative = wifiNative; 62 mFeatureFlags = featureFlags; 63 mWifiAwareNativeCallback = wifiAwareNativeCallback; 64 } 65 66 /** 67 * Enable/Disable verbose logging. 68 */ enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)69 public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) { 70 mVerboseLoggingEnabled = verboseEnabled; 71 if (mWifiNanIface != null) { 72 mWifiNanIface.enableVerboseLogging(halVerboseEnabled); 73 } 74 } 75 76 /** 77 * Initialize the class - intended for late initialization. 78 * 79 * @param handler Handler on which to execute interface available callbacks. 80 */ start(Handler handler)81 public void start(Handler handler) { 82 mHandler = handler; 83 mHalDeviceManager.initialize(); 84 mHalDeviceManager.registerStatusListener( 85 new HalDeviceManager.ManagerStatusListener() { 86 @Override 87 public void onStatusChanged() { 88 if (mVerboseLoggingEnabled) Log.v(TAG, "onStatusChanged"); 89 // only care about isStarted (Wi-Fi started) not isReady - since if not 90 // ready then Wi-Fi will also be down. 91 if (mHalDeviceManager.isStarted()) { 92 mWifiAwareStateManager.tryToGetAwareCapability(); 93 } else { 94 awareIsDown(mWifiAwareStateManager.isD2dAllowedWhenStaDisabled()); 95 } 96 } 97 }, mHandler); 98 if (mHalDeviceManager.isStarted()) { 99 mWifiAwareStateManager.tryToGetAwareCapability(); 100 } 101 } 102 103 /** 104 * Returns the WifiNanIface through which commands to the NAN HAL are dispatched. 105 * Return may be null if not initialized/available. 106 */ 107 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) getWifiNanIface()108 public WifiNanIface getWifiNanIface() { 109 synchronized (mLock) { 110 return mWifiNanIface; 111 } 112 } 113 114 /** 115 * Attempt to obtain the HAL NAN interface. 116 */ tryToGetAware(@onNull WorkSource requestorWs)117 public void tryToGetAware(@NonNull WorkSource requestorWs) { 118 synchronized (mLock) { 119 if (mVerboseLoggingEnabled) { 120 Log.d(TAG, "tryToGetAware: mWifiNanIface=" + mWifiNanIface 121 + ", mReferenceCount=" + mReferenceCount + ", requestorWs=" + requestorWs); 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(mWifiAwareStateManager.isD2dAllowedWhenStaDisabled()); 131 return; 132 } 133 134 mInterfaceDestroyedListener = new InterfaceDestroyedListener(); 135 mNanIface = mWifiNative.createNanIface(mInterfaceDestroyedListener, 136 mHandler, requestorWs); 137 if (mNanIface != null) { 138 mWifiNanIface = (WifiNanIface) mNanIface.iface; 139 } 140 if (mWifiNanIface == null) { 141 Log.e(TAG, "Was not able to obtain a WifiNanIface (even though enabled!?)"); 142 awareIsDown(true); 143 } else { 144 if (mVerboseLoggingEnabled) Log.v(TAG, "Obtained a WifiNanIface"); 145 if (!mWifiNanIface.registerFrameworkCallback(mWifiAwareNativeCallback)) { 146 Log.e(TAG, "Unable to register callback with WifiNanIface"); 147 mHalDeviceManager.removeIface(mWifiNanIface); 148 awareIsDown(mWifiAwareStateManager.isD2dAllowedWhenStaDisabled()); 149 return; 150 } 151 mReferenceCount = 1; 152 mWifiNanIface.enableVerboseLogging(mVerboseLoggingEnabled); 153 } 154 } 155 } 156 157 /** 158 * Release the HAL NAN interface. 159 */ releaseAware()160 public void releaseAware() { 161 if (mVerboseLoggingEnabled) { 162 Log.d(TAG, "releaseAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount=" 163 + mReferenceCount); 164 } 165 166 if (mWifiNanIface == null) { 167 return; 168 } 169 if (mHalDeviceManager == null) { 170 Log.e(TAG, "releaseAware: mHalDeviceManager is null!?"); 171 return; 172 } 173 174 synchronized (mLock) { 175 mReferenceCount--; 176 if (mReferenceCount != 0) { 177 return; 178 } 179 mInterfaceDestroyedListener.active = false; 180 mInterfaceDestroyedListener = null; 181 mHalDeviceManager.removeIface(mWifiNanIface); 182 if (mNanIface != null) { 183 final int nanIfaceId = mNanIface.id; 184 // HAL may be stop when Nan is toredown, 185 // clean mNanIface first to avoid infinite loop in clean up 186 mNanIface = null; 187 mWifiNative.teardownNanIface(nanIfaceId); 188 } 189 mWifiNanIface = null; 190 mWifiAwareNativeCallback.resetChannelInfo(); 191 } 192 } 193 194 /** 195 * Replace requestorWs in-place when iface is already enabled. 196 */ replaceRequestorWs(@onNull WorkSource requestorWs)197 public boolean replaceRequestorWs(@NonNull WorkSource requestorWs) { 198 synchronized (mLock) { 199 if (mVerboseLoggingEnabled) { 200 Log.d(TAG, "replaceRequestorWs: mWifiNanIface=" + mWifiNanIface 201 + ", mReferenceCount=" + mReferenceCount + ", requestorWs=" + requestorWs); 202 } 203 204 if (mWifiNanIface == null) { 205 return false; 206 } 207 if (mHalDeviceManager == null) { 208 Log.e(TAG, "tryToGetAware: mHalDeviceManager is null!?"); 209 awareIsDown(mWifiAwareStateManager.isD2dAllowedWhenStaDisabled()); 210 return false; 211 } 212 213 return mHalDeviceManager.replaceRequestorWsForNanIface(mWifiNanIface, requestorWs); 214 } 215 } 216 awareIsDown(boolean markAsAvailable)217 private void awareIsDown(boolean markAsAvailable) { 218 synchronized (mLock) { 219 if (mVerboseLoggingEnabled) { 220 Log.d(TAG, "awareIsDown: mWifiNanIface=" + mWifiNanIface 221 + ", mReferenceCount =" + mReferenceCount); 222 } 223 if (mNanIface != null) { 224 final int nanIfaceId = mNanIface.id; 225 // HAL may be stop when Nan is toredown, 226 // clean mNanIface first to avoid infinite loop in clean up 227 mNanIface = null; 228 mWifiNative.teardownNanIface(nanIfaceId); 229 } 230 mWifiNanIface = null; 231 mReferenceCount = 0; 232 mWifiAwareStateManager.disableUsage(markAsAvailable); 233 } 234 } 235 236 private class InterfaceDestroyedListener implements 237 HalDeviceManager.InterfaceDestroyedListener { 238 public boolean active = true; 239 240 @Override onDestroyed(@onNull String ifaceName)241 public void onDestroyed(@NonNull String ifaceName) { 242 if (mVerboseLoggingEnabled) { 243 Log.d(TAG, "Interface was destroyed: mWifiNanIface=" + mWifiNanIface 244 + ", active=" + active); 245 } 246 if (active && mWifiNanIface != null) { 247 awareIsDown(true); 248 } // else: we released it locally so no need to disable usage 249 } 250 } 251 252 /** 253 * Dump the internal state of the class. 254 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)255 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 256 pw.println("WifiAwareNativeManager:"); 257 pw.println(" mWifiNanIface: " + mWifiNanIface); 258 pw.println(" mReferenceCount: " + mReferenceCount); 259 mWifiAwareNativeCallback.dump(fd, pw, args); 260 } 261 } 262