• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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