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