• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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