1 /* 2 * Copyright (C) 2021 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.uwb; 18 19 import static android.uwb.UwbManager.MESSAGE_TYPE_COMMAND; 20 21 import static com.android.server.uwb.data.UwbUciConstants.FIRA_VERSION_MAJOR_2; 22 import static com.android.server.uwb.data.UwbUciConstants.STATUS_CODE_OK; 23 24 import android.annotation.NonNull; 25 import android.content.AttributionSource; 26 import android.content.Context; 27 import android.os.Binder; 28 import android.os.Handler; 29 import android.os.IBinder; 30 import android.os.Looper; 31 import android.os.Message; 32 import android.os.PersistableBundle; 33 import android.os.PowerManager; 34 import android.os.RemoteCallbackList; 35 import android.os.RemoteException; 36 import android.os.SystemClock; 37 import android.os.Trace; 38 import android.util.ArraySet; 39 import android.util.Log; 40 import android.util.Pair; 41 import android.uwb.IOnUwbActivityEnergyInfoListener; 42 import android.uwb.IUwbAdapterStateCallbacks; 43 import android.uwb.IUwbOemExtensionCallback; 44 import android.uwb.IUwbRangingCallbacks; 45 import android.uwb.IUwbVendorUciCallback; 46 import android.uwb.RangingChangeReason; 47 import android.uwb.SessionHandle; 48 import android.uwb.StateChangeReason; 49 import android.uwb.UwbActivityEnergyInfo; 50 import android.uwb.UwbAddress; 51 import android.uwb.UwbManager.AdapterStateCallback; 52 53 import androidx.annotation.Nullable; 54 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.server.uwb.data.UwbDeviceInfoResponse; 57 import com.android.server.uwb.data.UwbUciConstants; 58 import com.android.server.uwb.data.UwbVendorUciResponse; 59 import com.android.server.uwb.info.UwbPowerStats; 60 import com.android.server.uwb.jni.INativeUwbManager; 61 import com.android.server.uwb.jni.NativeUwbManager; 62 63 import com.google.uwb.support.aliro.AliroOpenRangingParams; 64 import com.google.uwb.support.aliro.AliroParams; 65 import com.google.uwb.support.aliro.AliroRangingReconfiguredParams; 66 import com.google.uwb.support.aliro.AliroStartRangingParams; 67 import com.google.uwb.support.base.Params; 68 import com.google.uwb.support.ccc.CccOpenRangingParams; 69 import com.google.uwb.support.ccc.CccParams; 70 import com.google.uwb.support.ccc.CccRangingReconfiguredParams; 71 import com.google.uwb.support.ccc.CccStartRangingParams; 72 import com.google.uwb.support.fira.FiraControleeParams; 73 import com.google.uwb.support.fira.FiraOpenSessionParams; 74 import com.google.uwb.support.fira.FiraParams; 75 import com.google.uwb.support.fira.FiraRangingReconfigureParams; 76 import com.google.uwb.support.fira.FiraSpecificationParams; 77 import com.google.uwb.support.fira.FiraSuspendRangingParams; 78 import com.google.uwb.support.generic.GenericParams; 79 import com.google.uwb.support.generic.GenericSpecificationParams; 80 import com.google.uwb.support.oemextension.DeviceStatus; 81 import com.google.uwb.support.profile.UuidBundleWrapper; 82 import com.google.uwb.support.radar.RadarOpenSessionParams; 83 import com.google.uwb.support.radar.RadarParams; 84 import com.google.uwb.support.rftest.RfTestOpenSessionParams; 85 import com.google.uwb.support.rftest.RfTestParams; 86 import com.google.uwb.support.rftest.RfTestStartSessionParams; 87 88 import java.io.FileDescriptor; 89 import java.io.PrintWriter; 90 import java.util.HashMap; 91 import java.util.Map; 92 import java.util.NoSuchElementException; 93 import java.util.Objects; 94 import java.util.Optional; 95 import java.util.Random; 96 import java.util.Set; 97 import java.util.concurrent.ExecutionException; 98 import java.util.concurrent.FutureTask; 99 import java.util.concurrent.TimeoutException; 100 101 /** 102 * Core UWB stack. 103 */ 104 public class UwbServiceCore implements INativeUwbManager.DeviceNotification, 105 INativeUwbManager.VendorNotification, UwbCountryCode.CountryCodeChangedListener { 106 private static final String TAG = "UwbServiceCore"; 107 108 @VisibleForTesting 109 public static final int TASK_ENABLE = 1; 110 @VisibleForTesting 111 public static final int TASK_DISABLE = 2; 112 @VisibleForTesting 113 public static final int TASK_RESTART = 3; 114 @VisibleForTesting 115 public static final int TASK_GET_POWER_STATS = 4; 116 @VisibleForTesting 117 public static final int TASK_HW_ENABLE = 5; 118 @VisibleForTesting 119 public static final int TASK_HW_DISABLE = 6; 120 121 @VisibleForTesting 122 public static final int WATCHDOG_MS = 10000; 123 private static final int SEND_VENDOR_CMD_TIMEOUT_MS = 10000; 124 125 private boolean mIsDiagnosticsEnabled = false; 126 private byte mDiagramsFrameReportsFieldsFlags = 0; 127 128 private final PowerManager.WakeLock mUwbWakeLock; 129 private final Context mContext; 130 private final RemoteCallbackList<IUwbAdapterStateCallbacks> 131 mAdapterStateCallbacksList = new RemoteCallbackList<>(); 132 private final UwbTask mUwbTask; 133 134 private final UwbSessionManager mSessionManager; 135 private final UwbConfigurationManager mConfigurationManager; 136 private final NativeUwbManager mNativeUwbManager; 137 private final UwbMetrics mUwbMetrics; 138 private final UwbCountryCode mUwbCountryCode; 139 private final UwbInjector mUwbInjector; 140 private final Map<String, /* @UwbManager.AdapterStateCallback.State */ Integer> 141 mChipIdToStateMap; 142 143 private final UwbClientHwState mUwbClientHwState = new UwbClientHwState(); 144 private Map<String, UwbDeviceInfoResponse> mChipIdToDeviceInfoResponseMap = new HashMap<>(); 145 private @StateChangeReason int mLastAdapterStateChangedReason = StateChangeReason.UNKNOWN; 146 private @AdapterStateCallback.State int mLastAdapterStateNotification = -1; 147 private IUwbVendorUciCallback mCallBack = null; 148 private IUwbOemExtensionCallback mOemExtensionCallback = null; 149 private final Handler mHandler; 150 private GenericSpecificationParams mCachedSpecificationParams; 151 private boolean mNeedCachedSpecParamsUpdate = true; 152 private boolean mSetEnabled = false; 153 private final Set<InitializationFailureListener> mListeners = new ArraySet<>(); 154 155 /** 156 * Wrapper class to hold {@link AttributionSource} and override it's equals 157 * to remove the check for token since we want to uniquely identify client (not different binder 158 * tokens* from the same client). 159 */ 160 private class AttributionSourceHolder implements IBinder.DeathRecipient { 161 private final AttributionSource mAttributionSource; 162 private final IBinder mBinder; 163 AttributionSourceHolder(AttributionSource attributionSource, IBinder binder)164 AttributionSourceHolder(AttributionSource attributionSource, IBinder binder) { 165 mAttributionSource = attributionSource; 166 mBinder = binder; 167 } 168 getAttributionSource()169 public AttributionSource getAttributionSource() { 170 return mAttributionSource; 171 } 172 linkToDeath()173 public void linkToDeath() { 174 try { 175 mBinder.linkToDeath(this, 0); 176 } catch (RemoteException e) { 177 Log.e(TAG, "Failed to register for death recipient for " 178 + mAttributionSource); 179 } 180 } 181 unlinkToDeath()182 public void unlinkToDeath() { 183 try { 184 mBinder.unlinkToDeath(this, 0); 185 } catch (NoSuchElementException e) { } 186 } 187 188 @Override equals(@ullable Object o)189 public boolean equals(@Nullable Object o) { 190 if (this == o) return true; 191 if (o == null || getClass() != o.getClass()) return false; 192 AttributionSourceHolder that = (AttributionSourceHolder) o; 193 return mAttributionSource.getUid() == that.mAttributionSource.getUid() 194 && Objects.equals(mAttributionSource.getPackageName(), 195 that.mAttributionSource.getPackageName()) 196 && Objects.equals(mAttributionSource.getAttributionTag(), 197 that.mAttributionSource.getAttributionTag()) 198 && Objects.equals(mAttributionSource.getNext(), that.mAttributionSource.getNext()); 199 } 200 201 @Override hashCode()202 public int hashCode() { 203 return Objects.hash(mAttributionSource.getUid(), mAttributionSource.getPackageName(), 204 mAttributionSource.getAttributionTag(), mAttributionSource.getNext()); 205 } 206 207 @Override toString()208 public String toString() { 209 return mAttributionSource.toString(); 210 } 211 212 @Override binderDied()213 public void binderDied() { 214 Log.i(TAG, "binderDied : reset hw enable for " + this); 215 requestHwEnabled(false, mAttributionSource, mBinder); 216 } 217 } 218 219 /** 220 * Storing a map of {@link AttributionSource} to enable/disable state of each client. 221 */ 222 private class UwbClientHwState { 223 private final Map<AttributionSourceHolder, Boolean> mMap = new HashMap<>(); 224 setEnabled(AttributionSourceHolder attributionSourceHolder, boolean enable)225 public void setEnabled(AttributionSourceHolder attributionSourceHolder, boolean enable) { 226 Boolean prevValue = mMap.put(attributionSourceHolder, Boolean.valueOf(enable)); 227 if (prevValue == null) prevValue = false; 228 // If enabling, add link to death. 229 if (!prevValue && enable) { 230 attributionSourceHolder.linkToDeath(); 231 } 232 // If disabling, remove link to death. 233 if (prevValue && !enable) { 234 attributionSourceHolder.unlinkToDeath(); 235 } 236 } 237 238 /** 239 * We use AttributionSourceHolder to linkToDeath, so avoid creating duplicate objects in the 240 * map for the same client. 241 */ getOrCreate( AttributionSource attributionSource, IBinder binder)242 public AttributionSourceHolder getOrCreate( 243 AttributionSource attributionSource, IBinder binder) { 244 // Check if attribution source is chained and has a 3p app in it, if so then 245 // use that attribution source to check for hw enable state. 246 AttributionSource nonPrivilegedAppAttrSource = 247 mUwbInjector.getAnyNonPrivilegedAppInAttributionSource(attributionSource); 248 if (nonPrivilegedAppAttrSource != null) attributionSource = nonPrivilegedAppAttrSource; 249 for (AttributionSourceHolder k : mMap.keySet()) { 250 if (Objects.equals(k.getAttributionSource(), attributionSource)) { 251 return k; 252 } 253 } 254 return new AttributionSourceHolder(attributionSource, binder); 255 } 256 isEnabled(AttributionSourceHolder attributionSourceHolder)257 public boolean isEnabled(AttributionSourceHolder attributionSourceHolder) { 258 return mMap.getOrDefault(attributionSourceHolder, false); 259 } 260 261 /** 262 * Check all the client states to figure out if we should enable the hardware. 263 * 264 * <li> If feature {@link DeviceConfigFacade#isHwIdleTurnOffEnabled()} is disabled -> true 265 * </li> 266 * <li> If there is at least 1 client vote to enable -> true </li> 267 * <li> Else -> false </li> 268 * 269 * @return 270 */ shouldHwBeEnabled()271 public boolean shouldHwBeEnabled() { 272 // If the feature is disabled, always return true. 273 if (!mUwbInjector.getDeviceConfigFacade().isHwIdleTurnOffEnabled()) return true; 274 // Unless all clients vote to disable the hardware, enable it. 275 return mMap.values().stream().filter(v -> v).findAny().orElse(false); 276 } 277 278 @Override toString()279 public String toString() { 280 return "UwbClientHwState [" + mMap + "]"; 281 } 282 } 283 UwbServiceCore(Context uwbApplicationContext, NativeUwbManager nativeUwbManager, UwbMetrics uwbMetrics, UwbCountryCode uwbCountryCode, UwbSessionManager uwbSessionManager, UwbConfigurationManager uwbConfigurationManager, UwbInjector uwbInjector, Looper serviceLooper)284 public UwbServiceCore(Context uwbApplicationContext, NativeUwbManager nativeUwbManager, 285 UwbMetrics uwbMetrics, UwbCountryCode uwbCountryCode, 286 UwbSessionManager uwbSessionManager, UwbConfigurationManager uwbConfigurationManager, 287 UwbInjector uwbInjector, Looper serviceLooper) { 288 mContext = uwbApplicationContext; 289 290 Log.d(TAG, "Starting Uwb"); 291 292 mUwbWakeLock = mContext.getSystemService(PowerManager.class).newWakeLock( 293 PowerManager.PARTIAL_WAKE_LOCK, "UwbServiceCore:mUwbWakeLock"); 294 295 mNativeUwbManager = nativeUwbManager; 296 297 mNativeUwbManager.setDeviceListener(this); 298 mNativeUwbManager.setVendorListener(this); 299 mUwbMetrics = uwbMetrics; 300 mUwbCountryCode = uwbCountryCode; 301 mUwbCountryCode.addListener(this); 302 mSessionManager = uwbSessionManager; 303 mConfigurationManager = uwbConfigurationManager; 304 mUwbInjector = uwbInjector; 305 306 mChipIdToStateMap = new HashMap<>(); 307 mUwbInjector.getMultichipData().setOnInitializedListener( 308 () -> { 309 for (String chipId : mUwbInjector.getMultichipData().getChipIds()) { 310 updateState(AdapterStateCallback.STATE_DISABLED, chipId); 311 } 312 }); 313 314 mUwbTask = new UwbTask(serviceLooper); 315 mHandler = new Handler(serviceLooper); 316 } 317 318 /** 319 * Interface for external classes to listen for any initialization failures. 320 * Added to avoid introducing circular dependency between UwbServiceCore & UwbServiceImpl. 321 */ 322 public interface InitializationFailureListener { onFailure()323 void onFailure(); 324 } 325 addInitializationFailureListener(@onNull InitializationFailureListener listener)326 public void addInitializationFailureListener(@NonNull InitializationFailureListener listener) { 327 mListeners.add(listener); 328 } removeInitializationFailureListener( @onNull InitializationFailureListener listener)329 public void removeInitializationFailureListener( 330 @NonNull InitializationFailureListener listener) { 331 mListeners.remove(listener); 332 } 333 getHandler()334 public Handler getHandler() { 335 return mHandler; 336 } 337 isOemExtensionCbRegistered()338 public synchronized boolean isOemExtensionCbRegistered() { 339 return mOemExtensionCallback != null; 340 } 341 getOemExtensionCallback()342 public synchronized IUwbOemExtensionCallback getOemExtensionCallback() { 343 return mOemExtensionCallback; 344 } 345 updateState(int state, String chipId)346 private void updateState(int state, String chipId) { 347 Log.d(TAG, "updateState(): state=" + state + ", chipId=" + chipId); 348 synchronized (UwbServiceCore.this) { 349 mChipIdToStateMap.put(chipId, state); 350 Log.d(TAG, "chipIdToStateMap = " + mChipIdToStateMap); 351 } 352 } 353 isUwbEnabled()354 private boolean isUwbEnabled() { 355 return getAdapterState() != AdapterStateCallback.STATE_DISABLED; 356 } 357 isUwbEnabledInternal()358 private boolean isUwbEnabledInternal() { 359 synchronized (UwbServiceCore.this) { 360 return getInternalAdapterState() != AdapterStateCallback.STATE_DISABLED; 361 } 362 } 363 getDeviceStateString(int state)364 String getDeviceStateString(int state) { 365 String ret = ""; 366 switch (state) { 367 case UwbUciConstants.DEVICE_STATE_OFF: 368 ret = "OFF"; 369 break; 370 case UwbUciConstants.DEVICE_STATE_READY: 371 ret = "READY"; 372 break; 373 case UwbUciConstants.DEVICE_STATE_ACTIVE: 374 ret = "ACTIVE"; 375 break; 376 case UwbUciConstants.DEVICE_STATE_ERROR: 377 case UwbUciConstants.DEVICE_STATE_INIT_ERROR: 378 ret = "ERROR"; 379 break; 380 } 381 return ret; 382 } 383 384 @Override onVendorUciNotificationReceived(int gid, int oid, byte[] payload)385 public void onVendorUciNotificationReceived(int gid, int oid, byte[] payload) { 386 Log.i(TAG, "onVendorUciNotificationReceived"); 387 if (mCallBack != null) { 388 try { 389 mCallBack.onVendorNotificationReceived(gid, oid, payload); 390 } catch (RemoteException e) { 391 Log.e(TAG, "Failed to send vendor notification", e); 392 } 393 } 394 } 395 396 @Override onDeviceStatusNotificationReceived(int deviceState, String chipId)397 public void onDeviceStatusNotificationReceived(int deviceState, String chipId) { 398 try { 399 Log.d(TAG, "onDeviceStatusNotificationReceived(): deviceState = " + deviceState 400 + ", current country code = " + mUwbCountryCode.getCountryCode()); 401 402 // If error status is received, toggle UWB off to reset stack state. 403 // TODO(b/227488208): Should we try to restart (like wifi) instead? 404 if (!mUwbInjector.getMultichipData().getChipIds().contains(chipId)) { 405 Log.e(TAG, "onDeviceStatusNotificationReceived with invalid chipId " + chipId 406 + ". Ignoring..."); 407 return; 408 } 409 410 if ((byte) deviceState == UwbUciConstants.DEVICE_STATE_ERROR) { 411 Log.wtf(TAG, "Error device status received. Restarting..."); 412 mUwbMetrics.incrementDeviceStatusErrorCount(); 413 takBugReportAfterDeviceError("UWB Bugreport: restarting UWB due to device error"); 414 mUwbTask.execute(TASK_RESTART); 415 oemExtensionDeviceStatusUpdate(deviceState, chipId); 416 return; 417 } 418 419 updateDeviceState(deviceState, chipId); 420 421 mUwbTask.computeAndNotifyAdapterStateChange( 422 getReasonFromDeviceState(deviceState), 423 mUwbCountryCode.getCountryCode(), 424 mUwbCountryCode.getCountryCodeStatus()); 425 } catch (Exception e) { 426 Log.e(TAG, "Exception in onDeviceStatusNotificationReceived"); 427 } 428 } 429 updateDeviceState(int deviceState, String chipId)430 void updateDeviceState(int deviceState, String chipId) { 431 Log.i(TAG, "updateDeviceState(): deviceState = " + getDeviceStateString(deviceState) 432 + ", current internal adapter state = " + getInternalAdapterState()); 433 434 updateState(getAdapterStateFromDeviceState(deviceState), chipId); 435 oemExtensionDeviceStatusUpdate(deviceState, chipId); 436 } 437 oemExtensionDeviceStatusUpdate(int deviceState, String chipId)438 void oemExtensionDeviceStatusUpdate(int deviceState, String chipId) { 439 IUwbOemExtensionCallback oemExtensionCallback = getOemExtensionCallback(); 440 if (oemExtensionCallback != null) { 441 PersistableBundle deviceStateBundle = new DeviceStatus.Builder() 442 .setDeviceState(deviceState) 443 .setChipId(chipId) 444 .build() 445 .toBundle(); 446 try { 447 oemExtensionCallback.onDeviceStatusNotificationReceived(deviceStateBundle); 448 } catch (RemoteException e) { 449 Log.e(TAG, "Failed to send status notification to oem", e); 450 } 451 } 452 } 453 notifyAdapterState(int adapterState, int reason)454 void notifyAdapterState(int adapterState, int reason) { 455 Log.d(TAG, "notifyAdapterState(): adapterState = " + adapterState + ", reason = " + reason); 456 457 synchronized (mAdapterStateCallbacksList) { 458 if (mAdapterStateCallbacksList.getRegisteredCallbackCount() > 0) { 459 final int count = mAdapterStateCallbacksList.beginBroadcast(); 460 for (int i = 0; i < count; i++) { 461 try { 462 mAdapterStateCallbacksList.getBroadcastItem(i) 463 .onAdapterStateChanged(adapterState, reason); 464 } catch (RemoteException e) { 465 Log.e(TAG, "onAdapterStateChanged is failed"); 466 } 467 } 468 mAdapterStateCallbacksList.finishBroadcast(); 469 } 470 } 471 472 mLastAdapterStateNotification = adapterState; 473 mLastAdapterStateChangedReason = reason; 474 } 475 getAdapterStateFromDeviceState(int deviceState)476 int getAdapterStateFromDeviceState(int deviceState) { 477 int adapterState = AdapterStateCallback.STATE_DISABLED; 478 if (deviceState == UwbUciConstants.DEVICE_STATE_OFF) { 479 adapterState = AdapterStateCallback.STATE_DISABLED; 480 } else if (deviceState == UwbUciConstants.DEVICE_STATE_READY) { 481 adapterState = AdapterStateCallback.STATE_ENABLED_INACTIVE; 482 } else if (deviceState == UwbUciConstants.DEVICE_STATE_ACTIVE) { 483 adapterState = AdapterStateCallback.STATE_ENABLED_ACTIVE; 484 } 485 return adapterState; 486 } 487 getReasonFromDeviceState(int deviceState)488 int getReasonFromDeviceState(int deviceState) { 489 int reason = StateChangeReason.UNKNOWN; 490 if (deviceState == UwbUciConstants.DEVICE_STATE_OFF) { 491 reason = StateChangeReason.SYSTEM_POLICY; 492 } else if (deviceState == UwbUciConstants.DEVICE_STATE_READY) { 493 reason = StateChangeReason.SYSTEM_POLICY; 494 } else if (deviceState == UwbUciConstants.DEVICE_STATE_ACTIVE) { 495 reason = StateChangeReason.SESSION_STARTED; 496 } 497 return reason; 498 } 499 500 @Override onCoreGenericErrorNotificationReceived(int status, String chipId)501 public void onCoreGenericErrorNotificationReceived(int status, String chipId) { 502 if (!mUwbInjector.getMultichipData().getChipIds().contains(chipId)) { 503 Log.e(TAG, "onCoreGenericErrorNotificationReceived with invalid chipId " 504 + chipId + ". Ignoring..."); 505 return; 506 } 507 Log.e(TAG, "onCoreGenericErrorNotificationReceived status = " + status); 508 mUwbMetrics.incrementUciGenericErrorCount(); 509 } 510 511 @Override onCountryCodeChanged(int setCountryCodeStatus, @Nullable String countryCode)512 public void onCountryCodeChanged(int setCountryCodeStatus, @Nullable String countryCode) { 513 Log.i(TAG, "Received onCountryCodeChanged() with countryCode = " + countryCode); 514 515 // Notify the current UWB adapter state. For example: 516 // - If UWB was earlier enabled and at that time the country code was not valid (so 517 // STATE_DISABLED was notified), can now notify STATE_ENABLED_INACTIVE. 518 // - If UWB is in STATE_ENABLED_INACTIVE and country code is no longer valid, should 519 // notify STATE_DISABLED. 520 mUwbTask.computeAndNotifyAdapterStateChange( 521 getReasonFromDeviceState(getInternalAdapterState()), 522 countryCode, 523 Optional.of(setCountryCodeStatus)); 524 Log.d(TAG, "Resetting cached specifications"); 525 mNeedCachedSpecParamsUpdate = true; 526 } 527 registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)528 public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks) 529 throws RemoteException { 530 synchronized (mAdapterStateCallbacksList) { 531 mAdapterStateCallbacksList.register(adapterStateCallbacks); 532 } 533 534 int adapterState = getAdapterState(); 535 Log.d(TAG, "registerAdapterStateCallbacks(): notify adapterState = " + adapterState 536 + ", reason = " + mLastAdapterStateChangedReason); 537 // We have a new listener being registered (there is no UWB event), so we send the current 538 // adapter state with the last known StateChangeReason. 539 adapterStateCallbacks.onAdapterStateChanged(adapterState, mLastAdapterStateChangedReason); 540 } 541 unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks callbacks)542 public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks callbacks) { 543 synchronized (mAdapterStateCallbacksList) { 544 mAdapterStateCallbacksList.unregister(callbacks); 545 } 546 } 547 registerVendorExtensionCallback(IUwbVendorUciCallback callbacks)548 public void registerVendorExtensionCallback(IUwbVendorUciCallback callbacks) { 549 Log.e(TAG, "Register the callback"); 550 mCallBack = callbacks; 551 } 552 unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks)553 public void unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks) { 554 Log.e(TAG, "Unregister the callback"); 555 mCallBack = null; 556 } 557 registerOemExtensionCallback(IUwbOemExtensionCallback callback)558 public synchronized void registerOemExtensionCallback(IUwbOemExtensionCallback callback) { 559 if (isOemExtensionCbRegistered()) { 560 Log.w(TAG, "Oem extension callback being re-registered"); 561 } 562 Log.e(TAG, "Register Oem Extension callback"); 563 mOemExtensionCallback = callback; 564 } 565 unregisterOemExtensionCallback(IUwbOemExtensionCallback callback)566 public synchronized void unregisterOemExtensionCallback(IUwbOemExtensionCallback callback) { 567 Log.e(TAG, "Unregister Oem Extension callback"); 568 mOemExtensionCallback = null; 569 } 570 571 /** 572 * Get cached specification params 573 */ getCachedSpecificationParams(String chipId)574 public GenericSpecificationParams getCachedSpecificationParams(String chipId) { 575 if (mCachedSpecificationParams != null && !mNeedCachedSpecParamsUpdate) { 576 return mCachedSpecificationParams; 577 } 578 // If nothing in cache, populate it. 579 getSpecificationInfo(chipId); 580 mNeedCachedSpecParamsUpdate = false; 581 return mCachedSpecificationParams; 582 } 583 584 /** 585 * Get cached CORE_GET_DEVICE_INFO response, for the given Uwb ChipId. 586 */ 587 @Nullable getCachedDeviceInfoResponse(String chipId)588 public UwbDeviceInfoResponse getCachedDeviceInfoResponse(String chipId) { 589 return mChipIdToDeviceInfoResponseMap.get(chipId); 590 } 591 592 /** 593 * Get specification info 594 */ getSpecificationInfo(String chipId)595 public PersistableBundle getSpecificationInfo(String chipId) { 596 if (!isUwbEnabled()) { 597 throw new IllegalStateException("Uwb is not enabled"); 598 } 599 Trace.beginSection("UWB#getSpecificationInfo"); 600 // TODO(b/211445008): Consolidate to a single uwb thread. 601 Pair<Integer, GenericSpecificationParams> specificationParams = 602 mConfigurationManager.getCapsInfo( 603 GenericParams.PROTOCOL_NAME, GenericSpecificationParams.class, chipId, 604 mSessionManager.getUwbsFiraProtocolVersion(chipId)); 605 Trace.endSection(); 606 if (specificationParams.first != UwbUciConstants.STATUS_CODE_OK 607 || specificationParams.second == null) { 608 Log.e(TAG, "Failed to retrieve specification params"); 609 return new PersistableBundle(); 610 } 611 if (specificationParams.second.getFiraSpecificationParams() != null) { 612 int uciVersion = Objects.requireNonNull(getCachedDeviceInfoResponse( 613 mUwbInjector.getMultichipData().getDefaultChipId())).mUciVersion; 614 FiraSpecificationParams firaSpecificationParams = 615 new FiraSpecificationParams.Builder( 616 specificationParams.second.getFiraSpecificationParams()) 617 .setBackgroundRangingSupport(mUwbInjector.getDeviceConfigFacade() 618 .isBackgroundRangingEnabled()) 619 .setUciVersionSupported(uciVersion > 100 ? 1 : uciVersion) 620 .setCountryCode(mUwbCountryCode.getCountryCode()) 621 .build(); 622 specificationParams.second.setFiraSpecificationParams(firaSpecificationParams); 623 } 624 mCachedSpecificationParams = specificationParams.second; 625 return specificationParams.second.toBundle(); 626 } 627 628 /** 629 * Get the UWBS time 630 */ queryUwbsTimestampMicros()631 public long queryUwbsTimestampMicros() { 632 String chipId = mUwbInjector.getMultichipData().getDefaultChipId(); 633 return mNativeUwbManager.queryUwbsTimestamp(chipId); 634 } 635 getTimestampResolutionNanos()636 public long getTimestampResolutionNanos() { 637 return mNativeUwbManager.getTimestampResolutionNanos(); 638 } 639 640 /** Set whether diagnostics is enabled and set enabled fields */ enableDiagnostics(boolean enabled, byte flags)641 public void enableDiagnostics(boolean enabled, byte flags) { 642 this.mIsDiagnosticsEnabled = enabled; 643 this.mDiagramsFrameReportsFieldsFlags = flags; 644 } 645 openRanging( AttributionSource attributionSource, SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks, PersistableBundle params, String chipId)646 public void openRanging( 647 AttributionSource attributionSource, 648 SessionHandle sessionHandle, 649 IUwbRangingCallbacks rangingCallbacks, 650 PersistableBundle params, 651 String chipId) throws RemoteException { 652 if (!isUwbEnabled()) { 653 throw new IllegalStateException("Uwb is not enabled"); 654 } 655 int sessionId = 0; 656 int sessionType = 0; 657 658 if (UuidBundleWrapper.isUuidBundle(params)) { 659 UuidBundleWrapper uuidBundleWrapper = UuidBundleWrapper.fromBundle(params); 660 mUwbInjector.getProfileManager().activateProfile( 661 attributionSource, 662 sessionHandle, 663 uuidBundleWrapper.getServiceInstanceID().get(), 664 rangingCallbacks, 665 chipId 666 ); 667 } else if (FiraParams.isCorrectProtocol(params)) { 668 FiraOpenSessionParams.Builder builder = 669 new FiraOpenSessionParams.Builder(FiraOpenSessionParams.fromBundle(params)); 670 UwbDeviceInfoResponse deviceInfo = getCachedDeviceInfoResponse(chipId); 671 if ((deviceInfo != null && deviceInfo.mUciVersion >= 2) 672 || getCachedSpecificationParams(chipId) 673 .getFiraSpecificationParams().hasRssiReportingSupport()) { 674 builder.setIsRssiReportingEnabled(true); 675 } 676 if (this.mIsDiagnosticsEnabled && getCachedSpecificationParams(chipId) 677 .getFiraSpecificationParams().hasDiagnosticsSupport()) { 678 builder.setIsDiagnosticsEnabled(true); 679 builder.setDiagramsFrameReportsFieldsFlags(mDiagramsFrameReportsFieldsFlags); 680 } 681 FiraOpenSessionParams firaOpenSessionParams = builder.build(); 682 sessionId = firaOpenSessionParams.getSessionId(); 683 sessionType = firaOpenSessionParams.getSessionType(); 684 mSessionManager.initSession(attributionSource, sessionHandle, sessionId, 685 (byte) sessionType, firaOpenSessionParams.getProtocolName(), 686 firaOpenSessionParams, rangingCallbacks, chipId); 687 } else if (CccParams.isCorrectProtocol(params)) { 688 CccOpenRangingParams cccOpenRangingParams = CccOpenRangingParams.fromBundle(params); 689 CccOpenRangingParams.Builder builder = 690 new CccOpenRangingParams.Builder(CccOpenRangingParams.fromBundle(params)); 691 if (mUwbInjector.getDeviceConfigFacade().isRandomHopmodekeySupported() 692 && cccOpenRangingParams.getHoppingConfigMode() 693 != CccParams.HOPPING_CONFIG_MODE_NONE 694 && cccOpenRangingParams.getHopModeKey() == CccParams.HOP_MODE_KEY_UNSET) { 695 builder.setHopModeKey(new Random().nextInt()); 696 } 697 cccOpenRangingParams = builder.build(); 698 sessionId = cccOpenRangingParams.getSessionId(); 699 sessionType = cccOpenRangingParams.getSessionType(); 700 mSessionManager.initSession(attributionSource, sessionHandle, sessionId, 701 (byte) sessionType, cccOpenRangingParams.getProtocolName(), 702 cccOpenRangingParams, rangingCallbacks, chipId); 703 } else if (AliroParams.isCorrectProtocol(params)) { 704 AliroOpenRangingParams aliroOpenRangingParams = 705 AliroOpenRangingParams.fromBundle(params); 706 AliroOpenRangingParams.Builder builder = 707 new AliroOpenRangingParams.Builder(AliroOpenRangingParams.fromBundle(params)); 708 if (mUwbInjector.getDeviceConfigFacade().isRandomHopmodekeySupported() 709 && aliroOpenRangingParams.getHoppingConfigMode() 710 != CccParams.HOPPING_CONFIG_MODE_NONE 711 && aliroOpenRangingParams.getHopModeKey() == CccParams.HOP_MODE_KEY_UNSET) { 712 builder.setHopModeKey(new Random().nextInt()); 713 } 714 aliroOpenRangingParams = builder.build(); 715 sessionId = aliroOpenRangingParams.getSessionId(); 716 sessionType = aliroOpenRangingParams.getSessionType(); 717 mSessionManager.initSession(attributionSource, sessionHandle, sessionId, 718 (byte) sessionType, aliroOpenRangingParams.getProtocolName(), 719 aliroOpenRangingParams, rangingCallbacks, chipId); 720 } else if (RadarParams.isCorrectProtocol(params)) { 721 RadarOpenSessionParams radarOpenSessionParams = 722 RadarOpenSessionParams.fromBundle(params); 723 sessionId = radarOpenSessionParams.getSessionId(); 724 sessionType = radarOpenSessionParams.getSessionType(); 725 mSessionManager.initSession(attributionSource, sessionHandle, sessionId, 726 (byte) sessionType, radarOpenSessionParams.getProtocolName(), 727 radarOpenSessionParams, rangingCallbacks, chipId); 728 } else if (RfTestParams.isCorrectProtocol(params)) { 729 RfTestOpenSessionParams rfTestOpenSessionParams = 730 RfTestOpenSessionParams.fromBundle(params); 731 sessionId = rfTestOpenSessionParams.getSessionId(); 732 sessionType = rfTestOpenSessionParams.getSessionType(); 733 mSessionManager.initSession(attributionSource, sessionHandle, sessionId, 734 (byte) sessionType, rfTestOpenSessionParams.getProtocolName(), 735 rfTestOpenSessionParams, rangingCallbacks, chipId); 736 } else { 737 Log.e(TAG, "openRanging - Wrong parameters"); 738 try { 739 rangingCallbacks.onRangingOpenFailed(sessionHandle, 740 RangingChangeReason.BAD_PARAMETERS, new PersistableBundle()); 741 } catch (RemoteException e) { } 742 } 743 } 744 startRanging(SessionHandle sessionHandle, PersistableBundle params)745 public void startRanging(SessionHandle sessionHandle, PersistableBundle params) 746 throws IllegalStateException { 747 if (!isUwbEnabled()) { 748 throw new IllegalStateException("Uwb is not enabled"); 749 } 750 Params startRangingParams = null; 751 if (CccParams.isCorrectProtocol(params)) { 752 startRangingParams = CccStartRangingParams.fromBundle(params); 753 } else if (AliroParams.isCorrectProtocol(params)) { 754 startRangingParams = AliroStartRangingParams.fromBundle(params); 755 } else if (RfTestParams.isCorrectProtocol(params)) { 756 startRangingParams = RfTestStartSessionParams.fromBundle(params); 757 } 758 759 if (mUwbInjector.getProfileManager().hasSession(sessionHandle)) { 760 mUwbInjector.getProfileManager().startRanging(sessionHandle); 761 } else { 762 mSessionManager.startRanging(sessionHandle, startRangingParams); 763 } 764 } 765 reconfigureRanging(SessionHandle sessionHandle, PersistableBundle params)766 public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle params) { 767 if (!isUwbEnabled()) { 768 throw new IllegalStateException("Uwb is not enabled"); 769 } 770 Params reconfigureRangingParams = null; 771 if (FiraParams.isCorrectProtocol(params)) { 772 reconfigureRangingParams = FiraRangingReconfigureParams.fromBundle(params); 773 } else if (CccParams.isCorrectProtocol(params)) { 774 reconfigureRangingParams = CccRangingReconfiguredParams.fromBundle(params); 775 } else if (AliroParams.isCorrectProtocol(params)) { 776 reconfigureRangingParams = AliroRangingReconfiguredParams.fromBundle(params); 777 } 778 779 mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams); 780 } 781 stopRanging(SessionHandle sessionHandle)782 public void stopRanging(SessionHandle sessionHandle) { 783 if (!isUwbEnabled()) { 784 throw new IllegalStateException("Uwb is not enabled"); 785 } 786 if (mUwbInjector.getProfileManager().hasSession(sessionHandle)) { 787 mUwbInjector.getProfileManager().stopRanging(sessionHandle); 788 } else { 789 mSessionManager.stopRanging(sessionHandle); 790 } 791 } 792 closeRanging(SessionHandle sessionHandle)793 public void closeRanging(SessionHandle sessionHandle) { 794 if (!isUwbEnabled()) { 795 throw new IllegalStateException("Uwb is not enabled"); 796 } 797 if (mUwbInjector.getProfileManager().hasSession(sessionHandle)) { 798 mUwbInjector.getProfileManager().closeRanging(sessionHandle); 799 } else { 800 mSessionManager.deInitSession(sessionHandle); 801 } 802 } 803 addControlee(SessionHandle sessionHandle, PersistableBundle params)804 public void addControlee(SessionHandle sessionHandle, PersistableBundle params) { 805 if (!isUwbEnabled()) { 806 throw new IllegalStateException("Uwb is not enabled"); 807 } 808 Params reconfigureRangingParams = null; 809 if (FiraParams.isCorrectProtocol(params)) { 810 FiraControleeParams controleeParams = FiraControleeParams.fromBundle(params); 811 reconfigureRangingParams = new FiraRangingReconfigureParams.Builder() 812 .setAction(controleeParams.getAction()) 813 .setAddressList(controleeParams.getAddressList()) 814 .setSubSessionIdList(controleeParams.getSubSessionIdList()) 815 .setSubSessionKeyList(controleeParams.getSubSessionKeyList()) 816 .build(); 817 } 818 mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams); 819 } 820 removeControlee(SessionHandle sessionHandle, PersistableBundle params)821 public void removeControlee(SessionHandle sessionHandle, PersistableBundle params) { 822 if (!isUwbEnabled()) { 823 throw new IllegalStateException("Uwb is not enabled"); 824 } 825 Params reconfigureRangingParams = null; 826 if (FiraParams.isCorrectProtocol(params)) { 827 FiraControleeParams controleeParams = FiraControleeParams.fromBundle(params); 828 reconfigureRangingParams = new FiraRangingReconfigureParams.Builder() 829 .setAction(controleeParams.getAction()) 830 .setAddressList(controleeParams.getAddressList()) 831 .setSubSessionIdList(controleeParams.getSubSessionIdList()) 832 .setSubSessionKeyList(controleeParams.getSubSessionKeyList()) 833 .build(); 834 } 835 mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams); 836 } 837 checkPauseOrResumeParams( PersistableBundle params, int expectedSuspendRangingRoundsValue)838 private void checkPauseOrResumeParams( 839 PersistableBundle params, int expectedSuspendRangingRoundsValue) { 840 if (!FiraParams.isCorrectProtocol(params)) { 841 throw new IllegalStateException("Incorrect protocol type in given params"); 842 } 843 FiraSuspendRangingParams suspendRangingParams = 844 FiraSuspendRangingParams.fromBundle(params); 845 if (suspendRangingParams.getSuspendRangingRounds() != expectedSuspendRangingRoundsValue) { 846 throw new IllegalStateException( 847 "Incorrect SuspendRangingRound value " 848 + suspendRangingParams.getSuspendRangingRounds() 849 + ", expected value = " + expectedSuspendRangingRoundsValue); 850 } 851 } 852 pause(SessionHandle sessionHandle, PersistableBundle params)853 public void pause(SessionHandle sessionHandle, PersistableBundle params) { 854 checkPauseOrResumeParams(params, FiraParams.SUSPEND_RANGING_ENABLED); 855 pauseOrResumeSession(sessionHandle, params); 856 } 857 resume(SessionHandle sessionHandle, PersistableBundle params)858 public void resume(SessionHandle sessionHandle, PersistableBundle params) { 859 checkPauseOrResumeParams(params, FiraParams.SUSPEND_RANGING_DISABLED); 860 pauseOrResumeSession(sessionHandle, params); 861 } 862 pauseOrResumeSession(SessionHandle sessionHandle, PersistableBundle params)863 private void pauseOrResumeSession(SessionHandle sessionHandle, PersistableBundle params) { 864 if (!isUwbEnabled()) { 865 throw new IllegalStateException("Uwb is not enabled"); 866 } 867 Params reconfigureRangingParams = null; 868 if (FiraParams.isCorrectProtocol(params)) { 869 FiraSuspendRangingParams suspendRangingParams = 870 FiraSuspendRangingParams.fromBundle(params); 871 reconfigureRangingParams = new FiraRangingReconfigureParams.Builder() 872 .setSuspendRangingRounds(suspendRangingParams.getSuspendRangingRounds()) 873 .build(); 874 } 875 mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams); 876 } 877 878 /** Send the payload data to a remote device in the UWB session */ sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, PersistableBundle params, byte[] data)879 public void sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, 880 PersistableBundle params, byte[] data) throws RemoteException { 881 if (!isUwbEnabled()) { 882 throw new IllegalStateException("Uwb is not enabled"); 883 } 884 885 mSessionManager.sendData(sessionHandle, remoteDeviceAddress, params, data); 886 } 887 888 /** 889 * Configure's data transfer session 890 */ setDataTransferPhaseConfig(SessionHandle sessionHandle, PersistableBundle params)891 public void setDataTransferPhaseConfig(SessionHandle sessionHandle, 892 PersistableBundle params) throws RemoteException { 893 if (!isUwbEnabled()) { 894 throw new IllegalStateException("Uwb is not enabled"); 895 } 896 897 mSessionManager.setDataTransferPhaseConfig(sessionHandle, params); 898 } 899 900 /** 901 * Get the UWB Adapter State. 902 */ getAdapterState()903 public /* @UwbManager.AdapterStateCallback.State */ int getAdapterState() { 904 return computeAdapterState( 905 mUwbCountryCode.getCountryCode(), mUwbCountryCode.getCountryCodeStatus()); 906 } 907 computeAdapterState(String countryCode, Optional<Integer> setCountryCodeStatus)908 private int computeAdapterState(String countryCode, Optional<Integer> setCountryCodeStatus) { 909 int internalAdapterState = getInternalAdapterState(); 910 if (internalAdapterState == AdapterStateCallback.STATE_DISABLED && mSetEnabled 911 && !mUwbClientHwState.shouldHwBeEnabled()) { 912 // If the UWB chip was disabled due to lack of vote for uwb hardware, then 913 // send corresponding state. 914 return AdapterStateCallback.STATE_ENABLED_HW_IDLE; 915 } 916 // When either the country code is not valid or setting it in UWBS failed with an error, 917 // notify the UWB stack state as DISABLED (even though internally the UWB device state 918 // may be stored as READY), so that applications wait for starting a ranging session. 919 if (!UwbCountryCode.isValid(countryCode) 920 || (setCountryCodeStatus.isPresent() 921 && setCountryCodeStatus.get() != STATUS_CODE_OK)) { 922 return AdapterStateCallback.STATE_DISABLED; 923 } 924 return internalAdapterState; 925 } 926 927 /** 928 * Configure a Hybrid session controller. 929 */ setHybridSessionControllerConfiguration(SessionHandle sessionHandle, PersistableBundle params)930 public void setHybridSessionControllerConfiguration(SessionHandle sessionHandle, 931 PersistableBundle params) { 932 if (!isUwbEnabled()) { 933 throw new IllegalStateException("Uwb is not enabled"); 934 } 935 936 mSessionManager.setHybridSessionControllerConfiguration(sessionHandle, params); 937 } 938 939 /** 940 * Configure a Hybrid session controlee. 941 */ setHybridSessionControleeConfiguration(SessionHandle sessionHandle, PersistableBundle params)942 public void setHybridSessionControleeConfiguration(SessionHandle sessionHandle, 943 PersistableBundle params) { 944 if (!isUwbEnabled()) { 945 throw new IllegalStateException("Uwb is not enabled"); 946 } 947 948 mSessionManager.setHybridSessionControleeConfiguration(sessionHandle, params); 949 } 950 getInternalAdapterState()951 private /* @UwbManager.AdapterStateCallback.State */ int getInternalAdapterState() { 952 synchronized (UwbServiceCore.this) { 953 if (mChipIdToStateMap.isEmpty()) { 954 return AdapterStateCallback.STATE_DISABLED; 955 } 956 957 boolean isActive = false; 958 for (int state : mChipIdToStateMap.values()) { 959 if (state == AdapterStateCallback.STATE_DISABLED) { 960 return AdapterStateCallback.STATE_DISABLED; 961 } 962 if (state == AdapterStateCallback.STATE_ENABLED_ACTIVE) { 963 isActive = true; 964 } 965 } 966 return isActive ? AdapterStateCallback.STATE_ENABLED_ACTIVE 967 : AdapterStateCallback.STATE_ENABLED_INACTIVE; 968 } 969 } 970 setEnabled(boolean enabled)971 public synchronized void setEnabled(boolean enabled) { 972 int task = enabled ? TASK_ENABLE : TASK_DISABLE; 973 Log.d(TAG, "setEnabled: " + enabled + "callingUid: " + Binder.getCallingUid()); 974 if (enabled && isUwbEnabledInternal()) { 975 Log.w(TAG, "Uwb is already enabled"); 976 } else if (!enabled && !isUwbEnabledInternal()) { 977 Log.w(TAG, "Uwb is already disabled"); 978 } 979 980 mUwbTask.execute(task); 981 } 982 requestHwEnabled( boolean enabled, AttributionSource attributionSource, IBinder binder)983 public synchronized void requestHwEnabled( 984 boolean enabled, AttributionSource attributionSource, IBinder binder) { 985 int task = enabled ? TASK_HW_ENABLE : TASK_HW_DISABLE; 986 AttributionSourceHolder attributionSourceHolder = 987 mUwbClientHwState.getOrCreate(attributionSource, binder); 988 Log.d(TAG, "requestHwEnabled: " + enabled + ", source: " + attributionSource); 989 if (enabled && mUwbClientHwState.isEnabled(attributionSourceHolder)) { 990 Log.w(TAG, "Uwb hardware is already enabled by " + attributionSource); 991 } else if (!enabled && !mUwbClientHwState.isEnabled(attributionSourceHolder)) { 992 Log.w(TAG, "Uwb hardware is already disabled by " + attributionSource); 993 } 994 mUwbTask.execute(task, attributionSourceHolder); 995 } 996 updateHwState(AttributionSourceHolder attributionSourceHolder, boolean enable)997 private void updateHwState(AttributionSourceHolder attributionSourceHolder, boolean enable) { 998 Log.d(TAG, "updateHwState(): state=" + enable 999 + ", attributionSource=" + attributionSourceHolder); 1000 synchronized (UwbServiceCore.this) { 1001 mUwbClientHwState.setEnabled(attributionSourceHolder, enable); 1002 Log.d(TAG, "mUwbClientHwState= " + mUwbClientHwState); 1003 } 1004 } 1005 isHwEnableRequested(AttributionSource attributionSource)1006 public boolean isHwEnableRequested(AttributionSource attributionSource) { 1007 synchronized (UwbServiceCore.this) { 1008 AttributionSourceHolder attributionSourceHolder = 1009 mUwbClientHwState.getOrCreate(attributionSource, null); 1010 return mUwbClientHwState.isEnabled(attributionSourceHolder); 1011 } 1012 } 1013 sendVendorUciResponse(int gid, int oid, byte[] payload)1014 private void sendVendorUciResponse(int gid, int oid, byte[] payload) { 1015 Log.i(TAG, "onVendorUciResponseReceived"); 1016 if (mCallBack != null) { 1017 try { 1018 mCallBack.onVendorResponseReceived(gid, oid, payload); 1019 } catch (RemoteException e) { 1020 Log.e(TAG, "Failed to send vendor response", e); 1021 } 1022 } 1023 } 1024 1025 /** 1026 * Send vendor UCI message 1027 * 1028 * @param chipId : Identifier of UWB chip for multi-HAL devices 1029 */ sendVendorUciMessage(int mt, int gid, int oid, byte[] payload, String chipId)1030 public synchronized int sendVendorUciMessage(int mt, int gid, int oid, byte[] payload, 1031 String chipId) { 1032 if ((!isUwbEnabledInternal())) { 1033 Log.e(TAG, "sendRawVendor : Uwb is not enabled"); 1034 return UwbUciConstants.STATUS_CODE_FAILED; 1035 } 1036 // Testing message type is only allowed in version FiRa 2.0 and above. 1037 if (mt != MESSAGE_TYPE_COMMAND && getCachedSpecificationParams(chipId) 1038 .getFiraSpecificationParams() 1039 .getMaxMacVersionSupported() 1040 .getMajor() < FIRA_VERSION_MAJOR_2) { 1041 Log.e(TAG, "Message Type " + mt + " not supported in this FiRa version"); 1042 return UwbUciConstants.STATUS_CODE_FAILED; 1043 } 1044 // TODO(b/211445008): Consolidate to a single uwb thread. 1045 FutureTask<Integer> sendVendorCmdTask = new FutureTask<>( 1046 () -> { 1047 UwbVendorUciResponse response = 1048 mNativeUwbManager.sendRawVendorCmd(mt, gid, oid, payload, chipId); 1049 if (response.status == UwbUciConstants.STATUS_CODE_OK) { 1050 sendVendorUciResponse(response.gid, response.oid, response.payload); 1051 } 1052 return Integer.valueOf(response.status); 1053 }); 1054 int status = UwbUciConstants.STATUS_CODE_FAILED; 1055 try { 1056 status = mUwbInjector.runTaskOnSingleThreadExecutor(sendVendorCmdTask, 1057 SEND_VENDOR_CMD_TIMEOUT_MS); 1058 } catch (TimeoutException e) { 1059 Log.i(TAG, "Failed to send vendor command - status : TIMEOUT"); 1060 } catch (InterruptedException e) { 1061 e.printStackTrace(); 1062 } catch (ExecutionException e) { 1063 e.printStackTrace(); 1064 } 1065 return status; 1066 } 1067 rangingRoundsUpdateDtTag(SessionHandle sessionHandle, PersistableBundle params)1068 public void rangingRoundsUpdateDtTag(SessionHandle sessionHandle, 1069 PersistableBundle params) throws RemoteException { 1070 if (!isUwbEnabled()) { 1071 throw new IllegalStateException("Uwb is not enabled"); 1072 } 1073 mSessionManager.rangingRoundsUpdateDtTag(sessionHandle, params); 1074 } 1075 1076 /** 1077 * Query max application data size that can be sent by UWBS in one ranging round. 1078 */ queryMaxDataSizeBytes(SessionHandle sessionHandle)1079 public int queryMaxDataSizeBytes(SessionHandle sessionHandle) { 1080 if (!isUwbEnabled()) { 1081 throw new IllegalStateException("Uwb is not enabled"); 1082 } 1083 1084 return mSessionManager.queryMaxDataSizeBytes(sessionHandle); 1085 } 1086 1087 /** 1088 * Update the pose used by the filter engine to distinguish tag position changes from device 1089 * position changes. 1090 */ updatePose(SessionHandle sessionHandle, PersistableBundle params)1091 public void updatePose(SessionHandle sessionHandle, PersistableBundle params) { 1092 mSessionManager.updatePose(sessionHandle, params); 1093 } 1094 1095 private class UwbTask extends Handler { 1096 UwbTask(Looper looper)1097 UwbTask(Looper looper) { 1098 super(looper); 1099 } 1100 1101 @Override handleMessage(Message msg)1102 public void handleMessage(Message msg) { 1103 int type = msg.what; 1104 switch (type) { 1105 case TASK_ENABLE: 1106 handleEnable(); 1107 break; 1108 1109 case TASK_DISABLE: 1110 handleDisable(); 1111 break; 1112 1113 case TASK_HW_ENABLE: 1114 handleHwEnable((AttributionSourceHolder) msg.obj); 1115 break; 1116 1117 case TASK_HW_DISABLE: 1118 handleHwDisable((AttributionSourceHolder) msg.obj); 1119 break; 1120 1121 case TASK_RESTART: 1122 handleDisable(); 1123 handleEnable(); 1124 break; 1125 1126 case TASK_GET_POWER_STATS: 1127 invokeUwbActivityEnergyInfoListener((IOnUwbActivityEnergyInfoListener) msg.obj); 1128 break; 1129 1130 default: 1131 Log.d(TAG, "UwbTask : Undefined Task"); 1132 break; 1133 } 1134 } 1135 execute(int task)1136 public void execute(int task) { 1137 Message msg = mUwbTask.obtainMessage(); 1138 msg.what = task; 1139 this.sendMessage(msg); 1140 } execute(int task, int arg1, int arg2)1141 public void execute(int task, int arg1, int arg2) { 1142 Message msg = mUwbTask.obtainMessage(); 1143 msg.what = task; 1144 msg.arg1 = arg1; 1145 msg.arg2 = arg2; 1146 this.sendMessage(msg); 1147 } 1148 execute(int task, Object obj)1149 public void execute(int task, Object obj) { 1150 Message msg = mUwbTask.obtainMessage(); 1151 msg.what = task; 1152 msg.obj = obj; 1153 this.sendMessage(msg); 1154 } 1155 executeUnique(int task, int arg1, int arg2)1156 private void executeUnique(int task, int arg1, int arg2) { 1157 mUwbTask.removeMessages(task); 1158 Message msg = mUwbTask.obtainMessage(); 1159 msg.what = task; 1160 msg.arg1 = arg1; 1161 msg.arg2 = arg2; 1162 this.sendMessage(msg); 1163 } 1164 delayedExecute(int task, int arg1, int arg2, int delayMillis)1165 private void delayedExecute(int task, int arg1, int arg2, int delayMillis) { 1166 Message msg = mUwbTask.obtainMessage(); 1167 msg.what = task; 1168 msg.arg1 = arg1; 1169 msg.arg2 = arg2; 1170 this.sendMessageDelayed(msg, delayMillis); 1171 } 1172 initializeHw()1173 private void initializeHw() { 1174 try { 1175 WatchDogThread watchDog = new WatchDogThread("handleEnable", WATCHDOG_MS); 1176 watchDog.start(); 1177 1178 Log.i(TAG, "Initialization start ..."); 1179 synchronized (mUwbWakeLock) { 1180 mUwbWakeLock.acquire(); 1181 } 1182 try { 1183 Map<String, UwbDeviceInfoResponse> result = mNativeUwbManager.doInitialize(); 1184 if (result == null) { 1185 Log.e(TAG, "Error enabling UWB"); 1186 1187 // Capture a bug report only if the Listener list is empty. This acts as a 1188 // proxy for this being the second initialization attempt, since currently 1189 // there is only one listener (UwbServiceImpl), which is removed after the 1190 // first retry attempt. 1191 mUwbMetrics.logUwbStateChangeEvent(true, false, mListeners.isEmpty()); 1192 if (mListeners.isEmpty()) { 1193 takBugReportAfterDeviceError("UWB Bugreport: error enabling UWB"); 1194 } 1195 for (String chipId : mUwbInjector.getMultichipData().getChipIds()) { 1196 updateDeviceState(UwbUciConstants.DEVICE_STATE_INIT_ERROR, chipId); 1197 } 1198 for (InitializationFailureListener listener : mListeners) { 1199 listener.onFailure(); 1200 } 1201 } else { 1202 mChipIdToDeviceInfoResponseMap = result; 1203 1204 Log.i(TAG, "Initialization success"); 1205 /* TODO : keep it until MW, FW fix b/196943897 */ 1206 mUwbMetrics.logUwbStateChangeEvent(true, true, false); 1207 1208 for (String chipId : mUwbInjector.getMultichipData().getChipIds()) { 1209 Log.d(TAG, "enabling chip " + chipId); 1210 updateDeviceState(UwbUciConstants.DEVICE_STATE_READY, chipId); 1211 } 1212 1213 // Set country code on every enable (example: for the scenario when the 1214 // country code was determined/changed while the UWB stack was disabled). 1215 // 1216 // TODO(b/255977441): Handle the case when the countryCode is valid and 1217 // setting the country code returned an error by doing a UWBS reset. 1218 Pair<Integer, String> setCountryCodeResult = 1219 mUwbCountryCode.setCountryCode(true); 1220 Optional<Integer> setCountryCodeStatus = 1221 Optional.of(setCountryCodeResult.first); 1222 String countryCode = setCountryCodeResult.second; 1223 Log.i(TAG, "Current country code = " + countryCode); 1224 computeAndNotifyAdapterStateChange( 1225 getReasonFromDeviceState(UwbUciConstants.DEVICE_STATE_READY), 1226 countryCode, 1227 setCountryCodeStatus); 1228 } 1229 } finally { 1230 synchronized (mUwbWakeLock) { 1231 if (mUwbWakeLock.isHeld()) { 1232 mUwbWakeLock.release(); 1233 } 1234 } 1235 watchDog.cancel(); 1236 } 1237 } catch (Exception e) { 1238 e.printStackTrace(); 1239 } 1240 } 1241 deInitializeHw()1242 private void deInitializeHw() { 1243 WatchDogThread watchDog = new WatchDogThread("handleDisable", WATCHDOG_MS); 1244 watchDog.start(); 1245 1246 try { 1247 Log.i(TAG, "Deinitialization start ..."); 1248 synchronized (mUwbWakeLock) { 1249 mUwbWakeLock.acquire(); 1250 } 1251 mSessionManager.deInitAllSession(); 1252 if (!mNativeUwbManager.doDeinitialize()) { 1253 Log.w(TAG, "Error disabling UWB"); 1254 mUwbMetrics.logUwbStateChangeEvent(false, false, false); 1255 } else { 1256 Log.i(TAG, "Deinitialization success"); 1257 mUwbMetrics.logUwbStateChangeEvent(false, true, false); 1258 } 1259 /* UWBS_STATUS_OFF is not the valid state. so handle device state directly */ 1260 for (String chipId : mUwbInjector.getMultichipData().getChipIds()) { 1261 updateDeviceState(UwbUciConstants.DEVICE_STATE_OFF, chipId); 1262 } 1263 int adapterState = getAdapterStateFromDeviceState(UwbUciConstants.DEVICE_STATE_OFF); 1264 int adapterReason = getReasonFromDeviceState(UwbUciConstants.DEVICE_STATE_OFF); 1265 if (!mUwbClientHwState.shouldHwBeEnabled()) { 1266 // If the UWB chip was disabled due to lack of vote for uwb hardware, then 1267 // send corresponding state. 1268 adapterState = AdapterStateCallback.STATE_ENABLED_HW_IDLE; 1269 adapterReason = StateChangeReason.SYSTEM_POLICY; 1270 } 1271 notifyAdapterState(adapterState, adapterReason); 1272 } finally { 1273 synchronized (mUwbWakeLock) { 1274 if (mUwbWakeLock.isHeld()) { 1275 mUwbWakeLock.release(); 1276 } 1277 } 1278 watchDog.cancel(); 1279 } 1280 } 1281 1282 handleEnable()1283 private void handleEnable() { 1284 mSetEnabled = true; 1285 if (isUwbEnabledInternal()) { 1286 Log.i(TAG, "UWB chip is already enabled, notify adapter state = " 1287 + getAdapterState()); 1288 return; 1289 } 1290 if (mUwbClientHwState.shouldHwBeEnabled()) { 1291 initializeHw(); 1292 } else { 1293 Log.i(TAG, "UWB Hw not requested, not enabling"); 1294 // If no clients have voted to enable hardware, just send notification to external 1295 // clients with corresponding reason. 1296 notifyAdapterState( 1297 AdapterStateCallback.STATE_ENABLED_HW_IDLE, 1298 StateChangeReason.SYSTEM_POLICY); 1299 } 1300 } 1301 handleDisable()1302 private void handleDisable() { 1303 mSetEnabled = false; 1304 if (!isUwbEnabledInternal()) { 1305 Log.i(TAG, "UWB chip is already disabled, notify adapter state = " 1306 + getAdapterState()); 1307 return; 1308 } 1309 deInitializeHw(); 1310 } 1311 handleHwEnable(AttributionSourceHolder attributionSourceHolder)1312 private void handleHwEnable(AttributionSourceHolder attributionSourceHolder) { 1313 if (mUwbClientHwState.isEnabled(attributionSourceHolder)) { 1314 Log.i(TAG, "UWB hardware is already enabled by " + attributionSourceHolder); 1315 return; 1316 } 1317 boolean prevShouldHwBeEnabled = mUwbClientHwState.shouldHwBeEnabled(); 1318 updateHwState(attributionSourceHolder, true); 1319 if (mSetEnabled && !prevShouldHwBeEnabled && mUwbClientHwState.shouldHwBeEnabled()) { 1320 Log.i(TAG, "UWB Hw requested, enabling"); 1321 initializeHw(); 1322 } 1323 } 1324 handleHwDisable(AttributionSourceHolder attributionSourceHolder)1325 private void handleHwDisable(AttributionSourceHolder attributionSourceHolder) { 1326 if (!mUwbClientHwState.isEnabled(attributionSourceHolder)) { 1327 Log.i(TAG, "UWB hardware is already disabled by " + attributionSourceHolder); 1328 return; 1329 } 1330 boolean prevShouldHwBeEnabled = mUwbClientHwState.shouldHwBeEnabled(); 1331 updateHwState(attributionSourceHolder, false); 1332 if (prevShouldHwBeEnabled && !mUwbClientHwState.shouldHwBeEnabled()) { 1333 Log.i(TAG, "UWB Hw not requested, disabling"); 1334 deInitializeHw(); 1335 } 1336 } 1337 computeAndNotifyAdapterStateChange(int reason, String countryCode, Optional<Integer> setCountryCodeStatus)1338 private void computeAndNotifyAdapterStateChange(int reason, 1339 String countryCode, Optional<Integer> setCountryCodeStatus) { 1340 // When either the country code is not valid or setting it in UWBS failed with the error 1341 // STATUS_CODE_ANDROID_REGULATION_UWB_OFF, notify with the reason SYSTEM_REGULATION. 1342 if (!UwbCountryCode.isValid(countryCode) 1343 || (setCountryCodeStatus.isPresent() 1344 && setCountryCodeStatus.get() 1345 == UwbUciConstants.STATUS_CODE_ANDROID_REGULATION_UWB_OFF)) { 1346 reason = StateChangeReason.SYSTEM_REGULATION; 1347 } 1348 1349 notifyAdapterState(computeAdapterState(countryCode, setCountryCodeStatus), reason); 1350 } 1351 1352 public class WatchDogThread extends Thread { 1353 final Object mCancelWaiter = new Object(); 1354 final int mTimeout; 1355 boolean mCanceled = false; 1356 WatchDogThread(String threadName, int timeout)1357 WatchDogThread(String threadName, int timeout) { 1358 super(threadName); 1359 1360 mTimeout = timeout; 1361 } 1362 1363 @Override run()1364 public void run() { 1365 try { 1366 synchronized (mCancelWaiter) { 1367 mCancelWaiter.wait(mTimeout); 1368 if (mCanceled) { 1369 return; 1370 } 1371 } 1372 } catch (InterruptedException e) { 1373 e.printStackTrace(); 1374 interrupt(); 1375 } 1376 1377 synchronized (mUwbWakeLock) { 1378 if (mUwbWakeLock.isHeld()) { 1379 mUwbWakeLock.release(); 1380 } 1381 } 1382 } 1383 cancel()1384 public synchronized void cancel() { 1385 synchronized (mCancelWaiter) { 1386 mCanceled = true; 1387 mCancelWaiter.notify(); 1388 } 1389 } 1390 } 1391 } 1392 takBugReportAfterDeviceError(String bugTitle)1393 private void takBugReportAfterDeviceError(String bugTitle) { 1394 if (mUwbInjector.getDeviceConfigFacade().isDeviceErrorBugreportEnabled()) { 1395 mUwbInjector.getUwbDiagnostics().takeBugReport(bugTitle); 1396 } 1397 } 1398 1399 /** 1400 * Dump the UWB session manager debug info 1401 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)1402 public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1403 pw.println("---- Dump of UwbServiceCore ----"); 1404 for (String chipId : mUwbInjector.getMultichipData().getChipIds()) { 1405 pw.println("Device state = " + getDeviceStateString(mChipIdToStateMap.get(chipId)) 1406 + " for chip id = " + chipId); 1407 } 1408 pw.println("mSetEnabled = " + mSetEnabled); 1409 pw.println("mUwbClientHwState = " + mUwbClientHwState); 1410 pw.println("mLastAdapterStateChangedReason = " + mLastAdapterStateChangedReason); 1411 pw.println("mLastAdapterStateNotification = " + mLastAdapterStateNotification); 1412 pw.println("---- Dump of UwbServiceCore ----"); 1413 } 1414 1415 /** 1416 * Report the UWB power stats to the listener 1417 */ reportUwbActivityEnergyInfo( IOnUwbActivityEnergyInfoListener listener)1418 public synchronized void reportUwbActivityEnergyInfo( 1419 IOnUwbActivityEnergyInfoListener listener) { 1420 mUwbTask.execute(TASK_GET_POWER_STATS, listener); 1421 } 1422 invokeUwbActivityEnergyInfoListener(IOnUwbActivityEnergyInfoListener listener)1423 private void invokeUwbActivityEnergyInfoListener(IOnUwbActivityEnergyInfoListener listener) { 1424 try { 1425 listener.onUwbActivityEnergyInfo(getUwbActivityEnergyInfo()); 1426 } catch (RemoteException e) { 1427 Log.e(TAG, "onUwbActivityEnergyInfo: RemoteException -- ", e); 1428 } 1429 } 1430 getUwbActivityEnergyInfo()1431 private UwbActivityEnergyInfo getUwbActivityEnergyInfo() { 1432 try { 1433 String chipId = mUwbInjector.getMultichipData().getDefaultChipId(); 1434 PersistableBundle bundle = getSpecificationInfo(chipId); 1435 GenericSpecificationParams params = GenericSpecificationParams.fromBundle(bundle); 1436 if (!isUwbEnabled() || params == null || !params.hasPowerStatsSupport()) { 1437 return null; 1438 } 1439 UwbPowerStats stats = mNativeUwbManager.getPowerStats(chipId); 1440 if (stats == null) { 1441 return null; 1442 } 1443 1444 Log.d(TAG, " getUwbActivityEnergyInfo: " 1445 + " tx_time_millis=" + stats.getTxTimeMs() 1446 + " rx_time_millis=" + stats.getRxTimeMs() 1447 + " rxIdleTimeMillis=" + stats.getIdleTimeMs() 1448 + " wake_count=" + stats.getTotalWakeCount()); 1449 1450 return new UwbActivityEnergyInfo.Builder() 1451 .setTimeSinceBootMillis(SystemClock.elapsedRealtime()) 1452 .setStackState(getInternalAdapterState()) 1453 .setControllerTxDurationMillis(stats.getTxTimeMs()) 1454 .setControllerRxDurationMillis(stats.getRxTimeMs()) 1455 .setControllerIdleDurationMillis(stats.getIdleTimeMs()) 1456 .setControllerWakeCount(stats.getTotalWakeCount()) 1457 .build(); 1458 } catch (Exception e) { 1459 e.printStackTrace(); 1460 return null; 1461 } 1462 } 1463 } 1464