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