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