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