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