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