• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.hal;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.hardware.wifi.IWifiChip;
23 import android.hardware.wifi.IWifiEventCallback;
24 import android.hardware.wifi.WifiStatusCode;
25 import android.os.IBinder;
26 import android.os.IBinder.DeathRecipient;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.os.ServiceSpecificException;
30 import android.util.Log;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.modules.utils.build.SdkLevel;
34 import com.android.server.wifi.SsidTranslator;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 
39 /**
40  * AIDL implementation of the IWifiHal interface.
41  */
42 public class WifiHalAidlImpl implements IWifiHal {
43     private static final String TAG = "WifiHalAidlImpl";
44     private static final String HAL_INSTANCE_NAME =
45             android.hardware.wifi.IWifi.DESCRIPTOR + "/default";
46 
47     private android.hardware.wifi.IWifi mWifi;
48     private Context mContext;
49     private SsidTranslator mSsidTranslator;
50     private IWifiEventCallback mHalCallback;
51     private WifiHal.Callback mFrameworkCallback;
52     private DeathRecipient mServiceDeathRecipient;
53     private WifiHal.DeathRecipient mFrameworkDeathRecipient;
54     private final Object mLock = new Object();
55     private static int sServiceVersion;
56 
WifiHalAidlImpl(@onNull Context context, @NonNull SsidTranslator ssidTranslator)57     public WifiHalAidlImpl(@NonNull Context context, @NonNull SsidTranslator ssidTranslator) {
58         Log.i(TAG, "Creating the Wifi HAL using the AIDL implementation");
59         mContext = context;
60         mSsidTranslator = ssidTranslator;
61         mServiceDeathRecipient = new WifiDeathRecipient();
62         mHalCallback = new WifiEventCallback();
63     }
64 
65     /**
66      * See comments for {@link IWifiHal#getChip(int)}
67      */
68     @Override
69     @Nullable
getChip(int chipId)70     public WifiChip getChip(int chipId) {
71         final String methodStr = "getChip";
72         synchronized (mLock) {
73             try {
74                 if (!checkWifiAndLogFailure(methodStr)) return null;
75                 IWifiChip chip = mWifi.getChip(chipId);
76                 return new WifiChip(chip, mContext, mSsidTranslator);
77             } catch (RemoteException e) {
78                 handleRemoteException(e, methodStr);
79             } catch (ServiceSpecificException e) {
80                 handleServiceSpecificException(e, methodStr);
81             }
82             return null;
83         }
84     }
85 
86     /**
87      * See comments for {@link IWifiHal#getChipIds()}
88      */
89     @Override
90     @Nullable
getChipIds()91     public List<Integer> getChipIds() {
92         final String methodStr = "getChipIds";
93         synchronized (mLock) {
94             try {
95                 if (!checkWifiAndLogFailure(methodStr)) return null;
96                 int[] chipIdArray = mWifi.getChipIds();
97                 List<Integer> chipIdList = new ArrayList<>();
98                 for (int id : chipIdArray) {
99                     chipIdList.add(id);
100                 }
101                 return chipIdList;
102             } catch (RemoteException e) {
103                 handleRemoteException(e, methodStr);
104             } catch (ServiceSpecificException e) {
105                 handleServiceSpecificException(e, methodStr);
106             }
107             return null;
108         }
109     }
110 
111     /**
112      * See comments for {@link IWifiHal#registerEventCallback(WifiHal.Callback)}
113      */
114     @Override
registerEventCallback(WifiHal.Callback callback)115     public boolean registerEventCallback(WifiHal.Callback callback) {
116         synchronized (mLock) {
117             if (mFrameworkCallback != null) {
118                 Log.e(TAG, "Framework callback is already registered");
119                 return false;
120             } else if (callback == null) {
121                 Log.e(TAG, "Cannot register a null callback");
122                 return false;
123             }
124             if (!registerHalCallback()) return false;
125             mFrameworkCallback = callback;
126             return true;
127         }
128     }
129 
registerHalCallback()130     private boolean registerHalCallback() {
131         final String methodStr = "registerHalCallback";
132         try {
133             if (!checkWifiAndLogFailure(methodStr)) return false;
134             mWifi.registerEventCallback(mHalCallback);
135             return true;
136         } catch (RemoteException e) {
137             handleRemoteException(e, methodStr);
138         } catch (ServiceSpecificException e) {
139             handleServiceSpecificException(e, methodStr);
140         }
141         return false;
142     }
143 
144     /**
145      * See comments for {@link IWifiHal#isInitializationComplete()}
146      */
147     @Override
isInitializationComplete()148     public boolean isInitializationComplete() {
149         synchronized (mLock) {
150             return mWifi != null;
151         }
152     }
153 
154     /**
155      * See comments for {@link IWifiHal#isSupported()}
156      */
157     @Override
isSupported()158     public boolean isSupported() {
159         return serviceDeclared();
160     }
161 
162     /**
163      * Indicates whether the AIDL service is declared.
164      */
serviceDeclared()165     protected static boolean serviceDeclared() {
166         // Service Manager API ServiceManager#isDeclared is supported after U.
167         return SdkLevel.isAtLeastU() ? ServiceManager.isDeclared(HAL_INSTANCE_NAME) : false;
168     }
169 
170     /**
171      * See comments for {@link IWifiHal#start()}
172      */
173     @Override
start()174     public @WifiHal.WifiStatusCode int start() {
175         final String methodStr = "start";
176         synchronized (mLock) {
177             try {
178                 if (!checkWifiAndLogFailure(methodStr)) return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
179                 mWifi.start();
180                 return WifiHal.WIFI_STATUS_SUCCESS;
181             } catch (RemoteException e) {
182                 handleRemoteException(e, methodStr);
183                 return WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION;
184             } catch (ServiceSpecificException e) {
185                 handleServiceSpecificException(e, methodStr);
186                 return halToFrameworkWifiStatusCode(e.errorCode);
187             }
188         }
189     }
190 
191     /**
192      * See comments for {@link IWifiHal#isStarted()}
193      */
194     @Override
isStarted()195     public boolean isStarted() {
196         final String methodStr = "isStarted";
197         synchronized (mLock) {
198             try {
199                 if (!checkWifiAndLogFailure(methodStr)) return false;
200                 return mWifi.isStarted();
201             } catch (RemoteException e) {
202                 handleRemoteException(e, methodStr);
203             } catch (ServiceSpecificException e) {
204                 handleServiceSpecificException(e, methodStr);
205             }
206             return false;
207         }
208     }
209 
210     /**
211      * See comments for {@link IWifiHal#stop()}
212      */
213     @Override
stop()214     public boolean stop() {
215         synchronized (mLock) {
216             if (!checkWifiAndLogFailure("stop")) return false;
217             boolean result = stopInternal();
218             return result;
219         }
220     }
221 
stopInternal()222     private boolean stopInternal() {
223         final String methodStr = "stopInternal";
224         try {
225             mWifi.stop();
226             return true;
227         } catch (RemoteException e) {
228             handleRemoteException(e, methodStr);
229         } catch (ServiceSpecificException e) {
230             handleServiceSpecificException(e, methodStr);
231         }
232         return false;
233     }
234 
235     /**
236      * See comments for {@link IWifiHal#initialize(WifiHal.DeathRecipient)}
237      */
238     @Override
initialize(WifiHal.DeathRecipient deathRecipient)239     public void initialize(WifiHal.DeathRecipient deathRecipient) {
240         final String methodStr = "initialize";
241         synchronized (mLock) {
242             if (mWifi != null) {
243                 Log.i(TAG, "Service is already initialized");
244                 return;
245             }
246 
247             mWifi = getWifiServiceMockable();
248             if (mWifi == null) {
249                 Log.e(TAG, "Unable to obtain the IWifi binder");
250                 return;
251             }
252             Log.i(TAG, "Obtained the IWifi binder. Local Version: "
253                     + android.hardware.wifi.IWifi.VERSION);
254 
255             try {
256                 sServiceVersion = mWifi.getInterfaceVersion();
257                 Log.i(TAG, "Remote Version: " + sServiceVersion);
258                 IBinder serviceBinder = getServiceBinderMockable();
259                 if (serviceBinder == null) {
260                     Log.e(TAG, "Unable to obtain the service binder");
261                     return;
262                 }
263                 serviceBinder.linkToDeath(mServiceDeathRecipient, /* flags= */  0);
264                 mFrameworkDeathRecipient = deathRecipient;
265 
266                 // Stop wifi just in case. Stop will invalidate the callbacks, so re-register them.
267                 stopInternal();
268                 registerHalCallback();
269                 Log.i(TAG, "Initialization is complete");
270             } catch (RemoteException e) {
271                 handleRemoteException(e, methodStr);
272             }
273         }
274     }
275 
276     /**
277      * See comments for {@link IWifiHal#invalidate()}
278      */
invalidate()279     public void invalidate() {
280         synchronized (mLock) {
281             mWifi = null;
282         }
283     }
284 
285     private class WifiEventCallback extends IWifiEventCallback.Stub {
286         @Override
onStart()287         public void onStart() throws RemoteException {
288             if (mFrameworkCallback == null) return;
289             mFrameworkCallback.onStart();
290         }
291 
292         @Override
onStop()293         public void onStop() throws RemoteException {
294             if (mFrameworkCallback == null) return;
295             mFrameworkCallback.onStop();
296         }
297 
298         @Override
onFailure(int statusCode)299         public void onFailure(int statusCode) throws RemoteException {
300             synchronized (mLock) {
301                 mWifi = null;
302             }
303             if (mFrameworkCallback == null) return;
304             mFrameworkCallback.onFailure(halToFrameworkWifiStatusCode(statusCode));
305         }
306 
307         @Override
onSubsystemRestart(int statusCode)308         public void onSubsystemRestart(int statusCode) throws RemoteException {
309             if (mFrameworkCallback == null) return;
310             mFrameworkCallback.onSubsystemRestart(halToFrameworkWifiStatusCode(statusCode));
311         }
312 
313         @Override
getInterfaceHash()314         public String getInterfaceHash() {
315             return IWifiEventCallback.HASH;
316         }
317 
318         @Override
getInterfaceVersion()319         public int getInterfaceVersion() {
320             return IWifiEventCallback.VERSION;
321         }
322     }
323 
324     private class WifiDeathRecipient implements DeathRecipient {
325         @Override
binderDied()326         public void binderDied() {
327             synchronized (mLock) {
328                 Log.w(TAG, "IWifi binder died.");
329                 mWifi = null;
330                 if (mFrameworkDeathRecipient != null) {
331                     mFrameworkDeathRecipient.onDeath();
332                 }
333             }
334         }
335     }
336 
337 
338     // Utilities
339 
halToFrameworkWifiStatusCode(int code)340     protected static @WifiHal.WifiStatusCode int halToFrameworkWifiStatusCode(int code) {
341         switch (code) {
342             case WifiStatusCode.SUCCESS:
343                 return WifiHal.WIFI_STATUS_SUCCESS;
344             case WifiStatusCode.ERROR_WIFI_CHIP_INVALID:
345                 return WifiHal.WIFI_STATUS_ERROR_WIFI_CHIP_INVALID;
346             case WifiStatusCode.ERROR_WIFI_IFACE_INVALID:
347                 return WifiHal.WIFI_STATUS_ERROR_WIFI_IFACE_INVALID;
348             case WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID:
349                 return WifiHal.WIFI_STATUS_ERROR_WIFI_RTT_CONTROLLER_INVALID;
350             case WifiStatusCode.ERROR_NOT_SUPPORTED:
351                 return WifiHal.WIFI_STATUS_ERROR_NOT_SUPPORTED;
352             case WifiStatusCode.ERROR_NOT_AVAILABLE:
353                 return WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE;
354             case WifiStatusCode.ERROR_NOT_STARTED:
355                 return WifiHal.WIFI_STATUS_ERROR_NOT_STARTED;
356             case WifiStatusCode.ERROR_INVALID_ARGS:
357                 return WifiHal.WIFI_STATUS_ERROR_INVALID_ARGS;
358             case WifiStatusCode.ERROR_BUSY:
359                 return WifiHal.WIFI_STATUS_ERROR_BUSY;
360             case WifiStatusCode.ERROR_UNKNOWN:
361                 return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
362             default:
363                 Log.e(TAG, "Invalid WifiStatusCode received: " + code);
364                 return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
365         }
366     }
367 
368     @VisibleForTesting
getWifiServiceMockable()369     protected android.hardware.wifi.IWifi getWifiServiceMockable() {
370         try {
371             if (SdkLevel.isAtLeastU()) {
372                 return android.hardware.wifi.IWifi.Stub.asInterface(
373                         ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME));
374             } else {
375                 return null;
376             }
377         } catch (Exception e) {
378             Log.e(TAG, "Unable to get IWifi service, " + e);
379             return null;
380         }
381     }
382 
383     @VisibleForTesting
getServiceBinderMockable()384     protected IBinder getServiceBinderMockable() {
385         if (mWifi == null) return null;
386         return mWifi.asBinder();
387     }
388 
389     /**
390      * Check that the service is running at least the expected version. Method is protected
391      * in order to allow calls from the WifiXxxIface classes.
392      */
isServiceVersionAtLeast(int expectedVersion)393     protected static boolean isServiceVersionAtLeast(int expectedVersion) {
394         return expectedVersion <= sServiceVersion;
395     }
396 
checkWifiAndLogFailure(String methodStr)397     private boolean checkWifiAndLogFailure(String methodStr) {
398         if (mWifi == null) {
399             Log.e(TAG, "Unable to call " + methodStr + " because IWifi is null.");
400             return false;
401         }
402         return true;
403     }
404 
handleRemoteException(RemoteException e, String methodStr)405     private void handleRemoteException(RemoteException e, String methodStr) {
406         mWifi = null;
407         Log.e(TAG, methodStr + " failed with remote exception: " + e);
408     }
409 
handleServiceSpecificException(ServiceSpecificException e, String methodStr)410     private void handleServiceSpecificException(ServiceSpecificException e, String methodStr) {
411         Log.e(TAG, methodStr + " failed with service-specific exception: " + e);
412     }
413 }
414