• 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.V1_0.IWifi;
23 import android.hardware.wifi.V1_0.WifiStatus;
24 import android.hardware.wifi.V1_0.WifiStatusCode;
25 import android.hidl.manager.V1_0.IServiceNotification;
26 import android.hidl.manager.V1_2.IServiceManager;
27 import android.os.IHwBinder;
28 import android.os.RemoteException;
29 import android.util.Log;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.server.wifi.SsidTranslator;
33 import com.android.server.wifi.util.GeneralUtil.Mutable;
34 
35 import java.util.List;
36 import java.util.function.Supplier;
37 
38 /**
39  * HIDL implementation of the IWifiHal interface.
40  */
41 public class WifiHalHidlImpl implements IWifiHal {
42     private static final String TAG = "WifiHalHidlImpl";
43     private IServiceManager mServiceManager;
44     private android.hardware.wifi.V1_0.IWifi mWifi;
45     private Context mContext;
46     private SsidTranslator mSsidTranslator;
47     private android.hardware.wifi.V1_0.IWifiEventCallback mHalCallback10;
48     private android.hardware.wifi.V1_5.IWifiEventCallback mHalCallback15;
49     private WifiHal.Callback mFrameworkCallback;
50     private ServiceManagerDeathRecipient mServiceManagerDeathRecipient;
51     private WifiDeathRecipient mWifiDeathRecipient;
52     private WifiHal.DeathRecipient mFrameworkDeathRecipient;
53     private boolean mIsVendorHalSupported;
54 
55     private final Object mLock = new Object();
56 
WifiHalHidlImpl(@onNull Context context, @NonNull SsidTranslator ssidTranslator)57     public WifiHalHidlImpl(@NonNull Context context, @NonNull SsidTranslator ssidTranslator) {
58         Log.i(TAG, "Creating the Wifi HAL using the HIDL implementation");
59         mContext = context;
60         mSsidTranslator = ssidTranslator;
61         mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient();
62         mWifiDeathRecipient = new WifiDeathRecipient();
63         mHalCallback10 = new WifiEventCallback();
64         mHalCallback15 = new WifiEventCallbackV15();
65     }
66 
67     /**
68      * See comments for {@link IWifiHal#getChip(int)}
69      */
70     @Override
71     @Nullable
getChip(int chipId)72     public WifiChip getChip(int chipId) {
73         synchronized (mLock) {
74             final String methodStr = "getChip";
75             return validateAndCall(methodStr, null,
76                     () -> getChipInternal(methodStr, chipId));
77         }
78     }
79 
80     /**
81      * See comments for {@link IWifiHal#getChipIds()}
82      */
83     @Override
84     @Nullable
getChipIds()85     public List<Integer> getChipIds() {
86         synchronized (mLock) {
87             final String methodStr = "getChipIds";
88             return validateAndCall(methodStr, null,
89                     () -> getChipIdsInternal(methodStr));
90         }
91     }
92 
93     /**
94      * See comments for {@link IWifiHal#registerEventCallback(WifiHal.Callback)}
95      */
96     @Override
registerEventCallback(WifiHal.Callback callback)97     public boolean registerEventCallback(WifiHal.Callback callback) {
98         synchronized (mLock) {
99             final String methodStr = "registerEventCallback";
100             return validateAndCall(methodStr, false,
101                     () -> registerEventCallbackInternal(callback));
102         }
103     }
104 
105     /**
106      * See comments for {@link IWifiHal#isInitializationComplete()}
107      */
108     @Override
isInitializationComplete()109     public boolean isInitializationComplete() {
110         synchronized (mLock) {
111             return mWifi != null;
112         }
113     }
114 
115     /**
116      * See comments for {@link IWifiHal#isSupported()}
117      */
118     @Override
isSupported()119     public boolean isSupported() {
120         synchronized (mLock) {
121             return mIsVendorHalSupported;
122         }
123     }
124 
125     /**
126      * See comments for {@link IWifiHal#start()}
127      */
128     @Override
start()129     public @WifiHal.WifiStatusCode int start() {
130         synchronized (mLock) {
131             final String methodStr = "start";
132             return validateAndCall(methodStr, WifiHal.WIFI_STATUS_ERROR_UNKNOWN,
133                     () -> startInternal(methodStr));
134         }
135     }
136 
137     /**
138      * See comments for {@link IWifiHal#isStarted()}
139      */
140     @Override
isStarted()141     public boolean isStarted() {
142         synchronized (mLock) {
143             final String methodStr = "isStarted";
144             return validateAndCall(methodStr, false,
145                     () -> isStartedInternal(methodStr));
146         }
147     }
148 
149     /**
150      * See comments for {@link IWifiHal#stop()}
151      */
152     @Override
stop()153     public boolean stop() {
154         synchronized (mLock) {
155             final String methodStr = "stop";
156             boolean result = validateAndCall(methodStr, false,
157                     () -> stopInternal(methodStr));
158             return result;
159         }
160     }
161 
162     /**
163      * See comments for {@link IWifiHal#initialize(WifiHal.DeathRecipient)}
164      */
165     @Override
initialize(WifiHal.DeathRecipient deathRecipient)166     public void initialize(WifiHal.DeathRecipient deathRecipient) {
167         synchronized (mLock) {
168             Log.i(TAG, "Initializing the WiFi HAL");
169             mFrameworkDeathRecipient = deathRecipient;
170             initServiceManagerIfNecessaryLocked();
171             if (mIsVendorHalSupported) {
172                 initWifiIfNecessaryLocked();
173             }
174         }
175     }
176 
177     /**
178      * See comments for {@link IWifiHal#invalidate()}
179      */
invalidate()180     public void invalidate() {
181         synchronized (mLock) {
182             mWifi = null;
183         }
184     }
185 
186 
187     // Internal Implementations
188 
getChipInternal(String methodStr, int chipId)189     private WifiChip getChipInternal(String methodStr, int chipId) {
190         Mutable<WifiChip> chipResp = new Mutable<>();
191         try {
192             mWifi.getChip(chipId, (status, chip) -> {
193                 if (isOk(status, methodStr)) {
194                     chipResp.value = new WifiChip(chip, mContext, mSsidTranslator);
195                 }
196             });
197         } catch (RemoteException e) {
198             handleRemoteException(e, methodStr);
199         }
200         return chipResp.value;
201     }
202 
getChipIdsInternal(String methodStr)203     private List<Integer> getChipIdsInternal(String methodStr) {
204         Mutable<List<Integer>> chipIdResp = new Mutable<>();
205         try {
206             mWifi.getChipIds((status, chipIds) -> {
207                 if (isOk(status, methodStr)) {
208                     chipIdResp.value = chipIds;
209                 }
210             });
211         } catch (RemoteException e) {
212             handleRemoteException(e, methodStr);
213         }
214         return chipIdResp.value;
215     }
216 
registerEventCallbackInternal(WifiHal.Callback callback)217     private boolean registerEventCallbackInternal(WifiHal.Callback callback) {
218         if (mFrameworkCallback != null) {
219             Log.e(TAG, "Framework callback is already registered");
220             return false;
221         } else if (callback == null) {
222             Log.e(TAG, "Cannot register a null callback");
223             return false;
224         }
225 
226         if (!registerHalCallback()) return false;
227         mFrameworkCallback = callback;
228         return true;
229     }
230 
registerHalCallback()231     private boolean registerHalCallback() {
232         final String methodStr = "registerHalCallback";
233         try {
234             android.hardware.wifi.V1_5.IWifi wifi15 = getWifiV1_5Mockable();
235             WifiStatus status;
236             if (wifi15 != null) {
237                 status = wifi15.registerEventCallback_1_5(mHalCallback15);
238             } else {
239                 status = mWifi.registerEventCallback(mHalCallback10);
240             }
241 
242             if (!isOk(status, methodStr)) {
243                 Log.e(TAG, "Unable to register HAL callback");
244                 mWifi = null;
245                 return false;
246             }
247             return true;
248         } catch (RemoteException e) {
249             handleRemoteException(e, methodStr);
250             return false;
251         }
252     }
253 
startInternal(String methodStr)254     private @WifiHal.WifiStatusCode int startInternal(String methodStr) {
255         try {
256             WifiStatus status = mWifi.start();
257             return halToFrameworkWifiStatusCode(status.code);
258         } catch (RemoteException e) {
259             handleRemoteException(e, methodStr);
260             return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
261         }
262     }
263 
isStartedInternal(String methodStr)264     private boolean isStartedInternal(String methodStr) {
265         try {
266             return mWifi.isStarted();
267         } catch (RemoteException e) {
268             handleRemoteException(e, methodStr);
269             return false;
270         }
271     }
272 
stopInternal(String methodStr)273     private boolean stopInternal(String methodStr) {
274         try {
275             WifiStatus status = mWifi.stop();
276             return isOk(status, methodStr);
277         } catch (RemoteException e) {
278             handleRemoteException(e, methodStr);
279             return false;
280         }
281     }
282 
283     private class WifiEventCallback extends android.hardware.wifi.V1_0.IWifiEventCallback.Stub {
284         @Override
onStart()285         public void onStart() throws RemoteException {
286             if (mFrameworkCallback == null) return;
287             mFrameworkCallback.onStart();
288         }
289 
290         @Override
onStop()291         public void onStop() throws RemoteException {
292             if (mFrameworkCallback == null) return;
293             mFrameworkCallback.onStop();
294         }
295 
296         @Override
onFailure(WifiStatus status)297         public void onFailure(WifiStatus status) throws RemoteException {
298             synchronized (mLock) {
299                 mWifi = null;
300                 if (mFrameworkCallback == null) return;
301                 mFrameworkCallback.onFailure(halToFrameworkWifiStatusCode(status.code));
302             }
303         }
304     }
305 
306     private class WifiEventCallbackV15 extends android.hardware.wifi.V1_5.IWifiEventCallback.Stub {
307         @Override
onStart()308         public void onStart() throws RemoteException {
309             if (mFrameworkCallback == null) return;
310             mHalCallback10.onStart();
311         }
312 
313         @Override
onStop()314         public void onStop() throws RemoteException {
315             if (mFrameworkCallback == null) return;
316             mHalCallback10.onStop();
317         }
318 
319         @Override
onFailure(WifiStatus status)320         public void onFailure(WifiStatus status) throws RemoteException {
321             if (mFrameworkCallback == null) return;
322             mHalCallback10.onFailure(status);
323         }
324 
325         @Override
onSubsystemRestart(WifiStatus status)326         public void onSubsystemRestart(WifiStatus status) throws RemoteException {
327             if (mFrameworkCallback == null) return;
328             mFrameworkCallback.onSubsystemRestart(halToFrameworkWifiStatusCode(status.code));
329         }
330     }
331 
332     private class ServiceManagerDeathRecipient implements IHwBinder.DeathRecipient {
333         @Override
serviceDied(long cookie)334         public void serviceDied(long cookie) {
335             Log.wtf(TAG, "IServiceManager died: cookie=" + cookie);
336             mServiceManager = null;
337             // theoretically can call initServiceManager again here - but
338             // there's no point since most likely system is going to reboot
339         }
340     }
341 
342     private class WifiDeathRecipient implements IHwBinder.DeathRecipient {
343         @Override
serviceDied(long cookie)344         public void serviceDied(long cookie) {
345             synchronized (mLock) {
346                 Log.e(TAG, "IWifi HAL service died! Have a listener for it ... cookie="
347                         + cookie);
348                 mWifi = null;
349                 if (mFrameworkDeathRecipient != null) {
350                     mFrameworkDeathRecipient.onDeath();
351                 }
352                 // don't restart: wait for registration notification
353             }
354         }
355     }
356 
357     private final IServiceNotification mServiceNotificationCallback =
358             new IServiceNotification.Stub() {
359                 @Override
360                 public void onRegistration(String fqName, String name, boolean preexisting) {
361                     synchronized (mLock) {
362                         Log.d(TAG, "IWifi registration notification: fqName=" + fqName
363                                 + ", name=" + name + ", preexisting=" + preexisting);
364                         initWifiIfNecessaryLocked();
365                     }
366                 }
367             };
368 
369 
370     // Helper Functions
371 
initServiceManagerIfNecessaryLocked()372     private void initServiceManagerIfNecessaryLocked() {
373         if (mServiceManager != null) {
374             Log.i(TAG, "mServiceManager already exists");
375             return;
376         }
377         Log.i(TAG, "initServiceManagerIfNecessaryLocked");
378 
379         // Failures of IServiceManager are most likely system breaking.
380         // Behavior here will be to WTF and continue.
381         mServiceManager = getServiceManagerMockable();
382         if (mServiceManager == null) {
383             Log.wtf(TAG, "Failed to get IServiceManager instance");
384             return;
385         }
386 
387         try {
388             if (!mServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) {
389                 Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
390                 mServiceManager = null;
391                 return;
392             }
393             if (!mServiceManager.registerForNotifications(IWifi.kInterfaceName, "",
394                     mServiceNotificationCallback)) {
395                 Log.wtf(TAG, "Failed to register a listener for IWifi service");
396                 mServiceManager = null;
397             }
398         } catch (RemoteException e) {
399             Log.wtf(TAG, "Exception while operating on IServiceManager: " + e);
400             mServiceManager = null;
401             return;
402         }
403         mIsVendorHalSupported = isSupportedInternal();
404     }
405 
initWifiIfNecessaryLocked()406     private void initWifiIfNecessaryLocked() {
407         if (mWifi != null) {
408             Log.i(TAG, "mWifi already exists");
409             return;
410         }
411         Log.i(TAG, "initWifiIfNecessaryLocked");
412 
413         try {
414             mWifi = getWifiServiceMockable();
415             if (mWifi == null) {
416                 Log.e(TAG, "IWifi not (yet) available - but have a listener for it ...");
417                 return;
418             }
419 
420             if (!mWifi.linkToDeath(mWifiDeathRecipient, /* don't care */ 0)) {
421                 Log.e(TAG, "Error on linkToDeath on IWifi - will retry later");
422                 return;
423             }
424 
425             // Stop wifi just in case. Stop will invalidate the callbacks, so re-register them.
426             stopInternal("stop");
427             registerHalCallback();
428             Log.i(TAG, "mWifi was retrieved. HAL is running version " + getVersion());
429         } catch (RemoteException e) {
430             Log.e(TAG, "Exception while operating on IWifi: " + e);
431         }
432     }
433 
434     /**
435      * Uses the IServiceManager to query if the vendor HAL is present in the VINTF for the device
436      * or not.
437      * @return true if supported, false otherwise.
438      */
isSupportedInternal()439     private boolean isSupportedInternal() {
440         if (mServiceManager == null) {
441             Log.e(TAG, "isSupported: called but mServiceManager is null!?");
442             return false;
443         }
444         try {
445             List<String> wifiServices =
446                     mServiceManager.listManifestByInterface(IWifi.kInterfaceName);
447             return !wifiServices.isEmpty();
448         } catch (RemoteException e) {
449             Log.wtf(TAG, "Exception while operating on IServiceManager: " + e);
450             return false;
451         }
452     }
453 
454     /**
455      * Indicates whether the HIDL service is declared. Uses the IServiceManager to check
456      * if the device is running a version >= V1_0 of the HAL from the VINTF for the device.
457      */
serviceDeclared()458     protected static boolean serviceDeclared() {
459         try {
460             IServiceManager serviceManager = getServiceManager();
461             if (serviceManager == null) {
462                 Log.e(TAG, "Unable to get service manager to check for service.");
463                 return false;
464             }
465             String interfaceName = android.hardware.wifi.V1_0.IWifi.kInterfaceName;
466             if (serviceManager.getTransport(interfaceName, "default")
467                     != IServiceManager.Transport.EMPTY) {
468                 return true;
469             }
470             return false;
471         } catch (RemoteException e) {
472             Log.e(TAG, "Unable to check for existence of HIDL service.");
473             return false;
474         }
475     }
476 
getVersion()477     private String getVersion() {
478         if (checkHalVersionByInterfaceName(
479                 android.hardware.wifi.V1_6.IWifi.kInterfaceName)) {
480             return "1.6";
481         } else if (checkHalVersionByInterfaceName(
482                 android.hardware.wifi.V1_5.IWifi.kInterfaceName)) {
483             return "1.5";
484         } else if (checkHalVersionByInterfaceName(
485                 android.hardware.wifi.V1_4.IWifi.kInterfaceName)) {
486             return "1.4";
487         } else if (checkHalVersionByInterfaceName(
488                 android.hardware.wifi.V1_3.IWifi.kInterfaceName)) {
489             return "1.3";
490         } else if (checkHalVersionByInterfaceName(
491                 android.hardware.wifi.V1_2.IWifi.kInterfaceName)) {
492             return "1.2";
493         } else if (checkHalVersionByInterfaceName(
494                 android.hardware.wifi.V1_1.IWifi.kInterfaceName)) {
495             return "1.1";
496         } else {
497             // Service exists, so at least V1_0 is supported
498             return "1.0";
499         }
500     }
501 
502     /**
503      * Use the IServiceManager to check if the device is running V1_X of the HAL
504      * from the VINTF for the device.
505      *
506      * @return true if HAL version is V1_X, false otherwise.
507      */
checkHalVersionByInterfaceName(String interfaceName)508     private boolean checkHalVersionByInterfaceName(String interfaceName) {
509         if (interfaceName == null) return false;
510         if (mServiceManager == null) {
511             Log.e(TAG, "checkHalVersionByInterfaceName called but mServiceManager is null!?");
512             return false;
513         }
514         try {
515             return (mServiceManager.getTransport(interfaceName, "default")
516                     != IServiceManager.Transport.EMPTY);
517         } catch (RemoteException e) {
518             Log.e(TAG, "Exception while operating on IServiceManager: " + e);
519             handleRemoteException(e, "getTransport");
520             return false;
521         }
522     }
523 
halToFrameworkWifiStatusCode(int code)524     protected static @WifiHal.WifiStatusCode int halToFrameworkWifiStatusCode(int code) {
525         switch (code) {
526             case WifiStatusCode.SUCCESS:
527                 return WifiHal.WIFI_STATUS_SUCCESS;
528             case WifiStatusCode.ERROR_WIFI_CHIP_INVALID:
529                 return WifiHal.WIFI_STATUS_ERROR_WIFI_CHIP_INVALID;
530             case WifiStatusCode.ERROR_WIFI_IFACE_INVALID:
531                 return WifiHal.WIFI_STATUS_ERROR_WIFI_IFACE_INVALID;
532             case WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID:
533                 return WifiHal.WIFI_STATUS_ERROR_WIFI_RTT_CONTROLLER_INVALID;
534             case WifiStatusCode.ERROR_NOT_SUPPORTED:
535                 return WifiHal.WIFI_STATUS_ERROR_NOT_SUPPORTED;
536             case WifiStatusCode.ERROR_NOT_AVAILABLE:
537                 return WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE;
538             case WifiStatusCode.ERROR_NOT_STARTED:
539                 return WifiHal.WIFI_STATUS_ERROR_NOT_STARTED;
540             case WifiStatusCode.ERROR_INVALID_ARGS:
541                 return WifiHal.WIFI_STATUS_ERROR_INVALID_ARGS;
542             case WifiStatusCode.ERROR_BUSY:
543                 return WifiHal.WIFI_STATUS_ERROR_BUSY;
544             case WifiStatusCode.ERROR_UNKNOWN:
545                 return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
546             default:
547                 Log.e(TAG, "Invalid WifiStatusCode received: " + code);
548                 return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
549         }
550     }
551 
getWifiV1_5Mockable()552     protected android.hardware.wifi.V1_5.IWifi getWifiV1_5Mockable() {
553         return android.hardware.wifi.V1_5.IWifi.castFrom(mWifi);
554     }
555 
getServiceManager()556     private static IServiceManager getServiceManager() {
557         try {
558             return IServiceManager.getService();
559         } catch (RemoteException e) {
560             Log.e(TAG, "Exception getting IServiceManager: " + e);
561             return null;
562         }
563     }
564 
565     // Non-static wrapper to allow mocking in the unit tests.
566     @VisibleForTesting
getServiceManagerMockable()567     protected IServiceManager getServiceManagerMockable() {
568         return getServiceManager();
569     }
570 
getWifiServiceMockable()571     protected IWifi getWifiServiceMockable() {
572         try {
573             return IWifi.getService(true /* retry */);
574         } catch (RemoteException e) {
575             Log.e(TAG, "Exception getting IWifi service: " + e);
576             return null;
577         }
578     }
579 
isOk(WifiStatus status, String methodStr)580     private boolean isOk(WifiStatus status, String methodStr) {
581         if (status.code == WifiStatusCode.SUCCESS) return true;
582         Log.e(TAG, methodStr + " failed with status: " + status);
583         return false;
584     }
585 
handleRemoteException(RemoteException e, String methodStr)586     private void handleRemoteException(RemoteException e, String methodStr) {
587         Log.e(TAG, methodStr + " failed with remote exception: " + e);
588         mWifi = null;
589     }
590 
validateAndCall(String methodStr, T defaultVal, @NonNull Supplier<T> supplier)591     private <T> T validateAndCall(String methodStr, T defaultVal, @NonNull Supplier<T> supplier) {
592         if (mWifi == null) {
593             Log.e(TAG, "Cannot call " + methodStr + " because mWifi is null");
594             return defaultVal;
595         }
596         return supplier.get();
597     }
598 }
599