• 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.Handler;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.os.PersistableBundle;
31 import android.os.PowerManager;
32 import android.os.RemoteCallbackList;
33 import android.os.RemoteException;
34 import android.os.SystemClock;
35 import android.os.Trace;
36 import android.util.ArraySet;
37 import android.util.Log;
38 import android.util.Pair;
39 import android.uwb.IOnUwbActivityEnergyInfoListener;
40 import android.uwb.IUwbAdapterStateCallbacks;
41 import android.uwb.IUwbOemExtensionCallback;
42 import android.uwb.IUwbRangingCallbacks;
43 import android.uwb.IUwbVendorUciCallback;
44 import android.uwb.RangingChangeReason;
45 import android.uwb.SessionHandle;
46 import android.uwb.StateChangeReason;
47 import android.uwb.UwbActivityEnergyInfo;
48 import android.uwb.UwbAddress;
49 import android.uwb.UwbManager.AdapterStateCallback;
50 
51 import androidx.annotation.Nullable;
52 
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.server.uwb.data.UwbUciConstants;
55 import com.android.server.uwb.data.UwbVendorUciResponse;
56 import com.android.server.uwb.info.UwbPowerStats;
57 import com.android.server.uwb.jni.INativeUwbManager;
58 import com.android.server.uwb.jni.NativeUwbManager;
59 
60 import com.google.uwb.support.base.Params;
61 import com.google.uwb.support.ccc.CccOpenRangingParams;
62 import com.google.uwb.support.ccc.CccParams;
63 import com.google.uwb.support.ccc.CccRangingReconfiguredParams;
64 import com.google.uwb.support.ccc.CccStartRangingParams;
65 import com.google.uwb.support.fira.FiraControleeParams;
66 import com.google.uwb.support.fira.FiraOpenSessionParams;
67 import com.google.uwb.support.fira.FiraParams;
68 import com.google.uwb.support.fira.FiraRangingReconfigureParams;
69 import com.google.uwb.support.generic.GenericParams;
70 import com.google.uwb.support.generic.GenericSpecificationParams;
71 import com.google.uwb.support.oemextension.DeviceStatus;
72 import com.google.uwb.support.profile.UuidBundleWrapper;
73 
74 import java.io.FileDescriptor;
75 import java.io.PrintWriter;
76 import java.util.HashMap;
77 import java.util.Map;
78 import java.util.Optional;
79 import java.util.Set;
80 import java.util.concurrent.ExecutionException;
81 import java.util.concurrent.FutureTask;
82 import java.util.concurrent.TimeoutException;
83 
84 /**
85  * Core UWB stack.
86  */
87 public class UwbServiceCore implements INativeUwbManager.DeviceNotification,
88         INativeUwbManager.VendorNotification, UwbCountryCode.CountryCodeChangedListener {
89     private static final String TAG = "UwbServiceCore";
90 
91     @VisibleForTesting
92     public static final int TASK_ENABLE = 1;
93     @VisibleForTesting
94     public static final int TASK_DISABLE = 2;
95     @VisibleForTesting
96     public static final int TASK_RESTART = 3;
97     @VisibleForTesting
98     public static final int TASK_GET_POWER_STATS = 4;
99 
100     @VisibleForTesting
101     public static final int WATCHDOG_MS = 10000;
102     private static final int SEND_VENDOR_CMD_TIMEOUT_MS = 10000;
103 
104     private boolean mIsDiagnosticsEnabled = false;
105     private byte mDiagramsFrameReportsFieldsFlags = 0;
106 
107     private final PowerManager.WakeLock mUwbWakeLock;
108     private final Context mContext;
109     private final RemoteCallbackList<IUwbAdapterStateCallbacks>
110             mAdapterStateCallbacksList = new RemoteCallbackList<>();
111     private final UwbTask mUwbTask;
112 
113     private final UwbSessionManager mSessionManager;
114     private final UwbConfigurationManager mConfigurationManager;
115     private final NativeUwbManager mNativeUwbManager;
116     private final UwbMetrics mUwbMetrics;
117     private final UwbCountryCode mUwbCountryCode;
118     private final UwbInjector mUwbInjector;
119     private final Map<String, /* @UwbManager.AdapterStateCallback.State */ Integer>
120             mChipIdToStateMap;
121     private @StateChangeReason int mLastAdapterStateChangedReason = StateChangeReason.UNKNOWN;
122     private @AdapterStateCallback.State int mLastAdapterStateNotification = -1;
123     private  IUwbVendorUciCallback mCallBack = null;
124     private IUwbOemExtensionCallback mOemExtensionCallback = null;
125     private final Handler mHandler;
126     private GenericSpecificationParams mCachedSpecificationParams;
127     private final Set<InitializationFailureListener> mListeners = new ArraySet<>();
128 
UwbServiceCore(Context uwbApplicationContext, NativeUwbManager nativeUwbManager, UwbMetrics uwbMetrics, UwbCountryCode uwbCountryCode, UwbSessionManager uwbSessionManager, UwbConfigurationManager uwbConfigurationManager, UwbInjector uwbInjector, Looper serviceLooper)129     public UwbServiceCore(Context uwbApplicationContext, NativeUwbManager nativeUwbManager,
130             UwbMetrics uwbMetrics, UwbCountryCode uwbCountryCode,
131             UwbSessionManager uwbSessionManager, UwbConfigurationManager uwbConfigurationManager,
132             UwbInjector uwbInjector, Looper serviceLooper) {
133         mContext = uwbApplicationContext;
134 
135         Log.d(TAG, "Starting Uwb");
136 
137         mUwbWakeLock = mContext.getSystemService(PowerManager.class).newWakeLock(
138                 PowerManager.PARTIAL_WAKE_LOCK, "UwbServiceCore:mUwbWakeLock");
139 
140         mNativeUwbManager = nativeUwbManager;
141 
142         mNativeUwbManager.setDeviceListener(this);
143         mNativeUwbManager.setVendorListener(this);
144         mUwbMetrics = uwbMetrics;
145         mUwbCountryCode = uwbCountryCode;
146         mUwbCountryCode.addListener(this);
147         mSessionManager = uwbSessionManager;
148         mConfigurationManager = uwbConfigurationManager;
149         mUwbInjector = uwbInjector;
150 
151         mChipIdToStateMap = new HashMap<>();
152         mUwbInjector.getMultichipData().setOnInitializedListener(
153                 () -> {
154                     for (String chipId : mUwbInjector.getMultichipData().getChipIds()) {
155                         updateState(AdapterStateCallback.STATE_DISABLED, chipId);
156                     }
157                 });
158 
159         mUwbTask = new UwbTask(serviceLooper);
160         mHandler = new Handler(serviceLooper);
161     }
162 
163     /**
164      * Interface for external classes to listen for any initialization failures.
165      * Added to avoid introducing circular dependency between UwbServiceCore & UwbServiceImpl.
166      */
167     public interface InitializationFailureListener {
onFailure()168         void onFailure();
169     }
170 
addInitializationFailureListener(@onNull InitializationFailureListener listener)171     public void addInitializationFailureListener(@NonNull InitializationFailureListener listener) {
172         mListeners.add(listener);
173     }
removeInitializationFailureListener( @onNull InitializationFailureListener listener)174     public void removeInitializationFailureListener(
175             @NonNull InitializationFailureListener listener) {
176         mListeners.remove(listener);
177     }
178 
getHandler()179     public Handler getHandler() {
180         return mHandler;
181     }
182 
isOemExtensionCbRegistered()183     public boolean isOemExtensionCbRegistered() {
184         return mOemExtensionCallback != null;
185     }
186 
getOemExtensionCallback()187     public IUwbOemExtensionCallback getOemExtensionCallback() {
188         return mOemExtensionCallback;
189     }
190 
updateState(int state, String chipId)191     private void updateState(int state, String chipId) {
192         Log.d(TAG, "updateState(): state=" + state + ", chipId=" + chipId);
193         synchronized (UwbServiceCore.this) {
194             mChipIdToStateMap.put(chipId, state);
195             Log.d(TAG, "chipIdToStateMap = " + mChipIdToStateMap);
196         }
197     }
198 
isUwbEnabled()199     private boolean isUwbEnabled() {
200         synchronized (UwbServiceCore.this) {
201             return getInternalAdapterState() != AdapterStateCallback.STATE_DISABLED;
202         }
203     }
204 
getDeviceStateString(int state)205     String getDeviceStateString(int state) {
206         String ret = "";
207         switch (state) {
208             case UwbUciConstants.DEVICE_STATE_OFF:
209                 ret = "OFF";
210                 break;
211             case UwbUciConstants.DEVICE_STATE_READY:
212                 ret = "READY";
213                 break;
214             case UwbUciConstants.DEVICE_STATE_ACTIVE:
215                 ret = "ACTIVE";
216                 break;
217             case UwbUciConstants.DEVICE_STATE_ERROR:
218                 ret = "ERROR";
219                 break;
220         }
221         return ret;
222     }
223 
224     @Override
onVendorUciNotificationReceived(int gid, int oid, byte[] payload)225     public void onVendorUciNotificationReceived(int gid, int oid, byte[] payload) {
226         Log.i(TAG, "onVendorUciNotificationReceived");
227         if (mCallBack != null) {
228             try {
229                 mCallBack.onVendorNotificationReceived(gid, oid, payload);
230             } catch (RemoteException e) {
231                 Log.e(TAG, "Failed to send vendor notification", e);
232             }
233         }
234     }
235 
236     @Override
onDeviceStatusNotificationReceived(int deviceState, String chipId)237     public void onDeviceStatusNotificationReceived(int deviceState, String chipId) {
238         Log.d(TAG, "onDeviceStatusNotificationReceived(): deviceState = " + deviceState
239                 + ", current country code = " + mUwbCountryCode.getCountryCode());
240 
241         // If error status is received, toggle UWB off to reset stack state.
242         // TODO(b/227488208): Should we try to restart (like wifi) instead?
243         if (!mUwbInjector.getMultichipData().getChipIds().contains(chipId)) {
244             Log.e(TAG, "onDeviceStatusNotificationReceived with invalid chipId " + chipId
245                     + ". Ignoring...");
246             return;
247         }
248 
249         if ((byte) deviceState == UwbUciConstants.DEVICE_STATE_ERROR) {
250             Log.e(TAG, "Error device status received. Restarting...");
251             mUwbMetrics.incrementDeviceStatusErrorCount();
252             takBugReportAfterDeviceError("UWB Bugreport: restarting UWB due to device error");
253             mUwbTask.execute(TASK_RESTART);
254             oemExtensionDeviceStatusUpdate(deviceState, chipId);
255             return;
256         }
257 
258         updateDeviceState(deviceState, chipId);
259 
260         mUwbTask.computeAndNotifyAdapterStateChange(
261                 getReasonFromDeviceState(deviceState),
262                 mUwbCountryCode.getCountryCode(),
263                 Optional.empty());
264     }
265 
updateDeviceState(int deviceState, String chipId)266     void updateDeviceState(int deviceState, String chipId) {
267         Log.i(TAG, "updateDeviceState(): deviceState = " + getDeviceStateString(deviceState)
268                 + ", current internal adapter state = " + getInternalAdapterState());
269 
270         oemExtensionDeviceStatusUpdate(deviceState, chipId);
271         updateState(getAdapterStateFromDeviceState(deviceState), chipId);
272     }
273 
oemExtensionDeviceStatusUpdate(int deviceState, String chipId)274     void oemExtensionDeviceStatusUpdate(int deviceState, String chipId) {
275         if (mOemExtensionCallback != null) {
276             PersistableBundle deviceStateBundle = new DeviceStatus.Builder()
277                     .setDeviceState(deviceState)
278                     .setChipId(chipId)
279                     .build()
280                     .toBundle();
281             try {
282                 mOemExtensionCallback.onDeviceStatusNotificationReceived(deviceStateBundle);
283             } catch (RemoteException e) {
284                 Log.e(TAG, "Failed to send status notification to oem", e);
285             }
286         }
287     }
288 
notifyAdapterState(int adapterState, int reason)289     void notifyAdapterState(int adapterState, int reason) {
290         // Check if the current adapter state is same as the state in the last adapter state
291         // notification, to avoid sending extra onAdapterStateChanged() notifications. For example,
292         // this can happen when UWB is toggled on and a valid country code is already set.
293         if (mLastAdapterStateNotification == adapterState
294                 && mLastAdapterStateChangedReason == reason) {
295             return;
296         }
297         Log.d(TAG, "notifyAdapterState(): adapterState = " + adapterState + ", reason = " + reason);
298 
299         synchronized (mAdapterStateCallbacksList) {
300             if (mAdapterStateCallbacksList.getRegisteredCallbackCount() > 0) {
301                 final int count = mAdapterStateCallbacksList.beginBroadcast();
302                 for (int i = 0; i < count; i++) {
303                     try {
304                         mAdapterStateCallbacksList.getBroadcastItem(i)
305                                 .onAdapterStateChanged(adapterState, reason);
306                     } catch (RemoteException e) {
307                         Log.e(TAG, "onAdapterStateChanged is failed");
308                     }
309                 }
310                 mAdapterStateCallbacksList.finishBroadcast();
311             }
312         }
313 
314         mLastAdapterStateNotification = adapterState;
315         mLastAdapterStateChangedReason = reason;
316     }
317 
getAdapterStateFromDeviceState(int deviceState)318     int getAdapterStateFromDeviceState(int deviceState) {
319         int adapterState = AdapterStateCallback.STATE_DISABLED;
320         if (deviceState == UwbUciConstants.DEVICE_STATE_OFF) {
321             adapterState = AdapterStateCallback.STATE_DISABLED;
322         } else if (deviceState == UwbUciConstants.DEVICE_STATE_READY) {
323             adapterState = AdapterStateCallback.STATE_ENABLED_INACTIVE;
324         } else if (deviceState == UwbUciConstants.DEVICE_STATE_ACTIVE) {
325             adapterState = AdapterStateCallback.STATE_ENABLED_ACTIVE;
326         }
327         return adapterState;
328     }
329 
getReasonFromDeviceState(int deviceState)330     int getReasonFromDeviceState(int deviceState) {
331         int reason = StateChangeReason.UNKNOWN;
332         if (deviceState == UwbUciConstants.DEVICE_STATE_OFF) {
333             reason = StateChangeReason.SYSTEM_POLICY;
334         } else if (deviceState == UwbUciConstants.DEVICE_STATE_READY) {
335             reason = StateChangeReason.SYSTEM_POLICY;
336         } else if (deviceState == UwbUciConstants.DEVICE_STATE_ACTIVE) {
337             reason = StateChangeReason.SESSION_STARTED;
338         }
339         return reason;
340     }
341 
342     @Override
onCoreGenericErrorNotificationReceived(int status, String chipId)343     public void onCoreGenericErrorNotificationReceived(int status, String chipId) {
344         if (!mUwbInjector.getMultichipData().getChipIds().contains(chipId)) {
345             Log.e(TAG, "onCoreGenericErrorNotificationReceived with invalid chipId "
346                     + chipId + ". Ignoring...");
347             return;
348         }
349         Log.e(TAG, "onCoreGenericErrorNotificationReceived status = " + status);
350         mUwbMetrics.incrementUciGenericErrorCount();
351     }
352 
353     @Override
onCountryCodeChanged(@ullable String countryCode)354     public void onCountryCodeChanged(@Nullable String countryCode) {
355         Log.i(TAG, "Received onCountryCodeChanged() with countryCode = " + countryCode);
356 
357         // Notify the current UWB adapter state. For example:
358         // - If UWB was earlier enabled and at that time the country code was not valid (so
359         //   STATE_DISABLED was notified), can now notify STATE_ENABLED_INACTIVE.
360         // - If UWB is in STATE_ENABLED_INACTIVE and country code is no longer valid, should
361         //   notify STATE_DISABLED.
362         mUwbTask.computeAndNotifyAdapterStateChange(
363                 getReasonFromDeviceState(getInternalAdapterState()),
364                 countryCode,
365                 Optional.empty());
366         Log.d(TAG, "Resetting cached specifications");
367         mCachedSpecificationParams = null;
368     }
369 
registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)370     public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
371             throws RemoteException {
372         synchronized (mAdapterStateCallbacksList) {
373             mAdapterStateCallbacksList.register(adapterStateCallbacks);
374         }
375 
376         int adapterState = getAdapterState();
377         Log.d(TAG, "registerAdapterStateCallbacks(): notify adapterState = " + adapterState
378                 + ", reason = " + mLastAdapterStateChangedReason);
379         // We have a new listener being registered (there is no UWB event), so we send the current
380         // adapter state with the last known StateChangeReason.
381         adapterStateCallbacks.onAdapterStateChanged(adapterState, mLastAdapterStateChangedReason);
382     }
383 
unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks callbacks)384     public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks callbacks) {
385         synchronized (mAdapterStateCallbacksList) {
386             mAdapterStateCallbacksList.unregister(callbacks);
387         }
388     }
389 
registerVendorExtensionCallback(IUwbVendorUciCallback callbacks)390     public void registerVendorExtensionCallback(IUwbVendorUciCallback callbacks) {
391         Log.e(TAG, "Register the callback");
392         mCallBack = callbacks;
393     }
394 
unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks)395     public void unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks) {
396         Log.e(TAG, "Unregister the callback");
397         mCallBack = null;
398     }
399 
registerOemExtensionCallback(IUwbOemExtensionCallback callback)400     public void registerOemExtensionCallback(IUwbOemExtensionCallback callback) {
401         if (isOemExtensionCbRegistered()) {
402             Log.w(TAG, "Oem extension callback being re-registered");
403         }
404         Log.e(TAG, "Register Oem Extension callback");
405         mOemExtensionCallback = callback;
406     }
407 
unregisterOemExtensionCallback(IUwbOemExtensionCallback callback)408     public void unregisterOemExtensionCallback(IUwbOemExtensionCallback callback) {
409         Log.e(TAG, "Unregister Oem Extension callback");
410         mOemExtensionCallback = null;
411     }
412 
413     /**
414      * Get cached specification params
415      */
getCachedSpecificationParams(String chipId)416     public GenericSpecificationParams getCachedSpecificationParams(String chipId) {
417         if (mCachedSpecificationParams != null) return mCachedSpecificationParams;
418         // If nothing in cache, populate it.
419         getSpecificationInfo(chipId);
420         return mCachedSpecificationParams;
421     }
422 
423     /**
424      * Get specification info
425      */
getSpecificationInfo(String chipId)426     public PersistableBundle getSpecificationInfo(String chipId) {
427         if (!isUwbEnabled()) {
428             throw new IllegalStateException("Uwb is not enabled");
429         }
430         Trace.beginSection("UWB#getSpecificationInfo");
431         // TODO(b/211445008): Consolidate to a single uwb thread.
432         Pair<Integer, GenericSpecificationParams> specificationParams =
433                 mConfigurationManager.getCapsInfo(
434                         GenericParams.PROTOCOL_NAME, GenericSpecificationParams.class, chipId);
435         Trace.endSection();
436         if (specificationParams.first != UwbUciConstants.STATUS_CODE_OK
437                 || specificationParams.second == null)  {
438             Log.e(TAG, "Failed to retrieve specification params");
439             return new PersistableBundle();
440         }
441         mCachedSpecificationParams = specificationParams.second;
442         return specificationParams.second.toBundle();
443     }
444 
getTimestampResolutionNanos()445     public long getTimestampResolutionNanos() {
446         return mNativeUwbManager.getTimestampResolutionNanos();
447     }
448 
449     /** Set whether diagnostics is enabled and set enabled fields */
enableDiagnostics(boolean enabled, byte flags)450     public void enableDiagnostics(boolean enabled, byte flags) {
451         this.mIsDiagnosticsEnabled = enabled;
452         this.mDiagramsFrameReportsFieldsFlags = flags;
453     }
454 
openRanging( AttributionSource attributionSource, SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks, PersistableBundle params, String chipId)455     public void openRanging(
456             AttributionSource attributionSource,
457             SessionHandle sessionHandle,
458             IUwbRangingCallbacks rangingCallbacks,
459             PersistableBundle params,
460             String chipId) throws RemoteException {
461         if (!isUwbEnabled()) {
462             throw new IllegalStateException("Uwb is not enabled");
463         }
464         int sessionId = 0;
465         int sessionType = 0;
466 
467         if (UuidBundleWrapper.isUuidBundle(params)) {
468             UuidBundleWrapper uuidBundleWrapper = UuidBundleWrapper.fromBundle(params);
469             mUwbInjector.getProfileManager().activateProfile(
470                     attributionSource,
471                     sessionHandle,
472                     uuidBundleWrapper.getServiceInstanceID().get(),
473                     rangingCallbacks,
474                     chipId
475             );
476         } else if (FiraParams.isCorrectProtocol(params)) {
477             FiraOpenSessionParams.Builder builder =
478                     new FiraOpenSessionParams.Builder(FiraOpenSessionParams.fromBundle(params));
479             if (getCachedSpecificationParams(chipId)
480                     .getFiraSpecificationParams().hasRssiReportingSupport()) {
481                 builder.setIsRssiReportingEnabled(true);
482             }
483             if (this.mIsDiagnosticsEnabled && getCachedSpecificationParams(chipId)
484                     .getFiraSpecificationParams().hasDiagnosticsSupport()) {
485                 builder.setIsDiagnosticsEnabled(true);
486                 builder.setDiagramsFrameReportsFieldsFlags(mDiagramsFrameReportsFieldsFlags);
487             }
488             FiraOpenSessionParams firaOpenSessionParams = builder.build();
489             sessionId = firaOpenSessionParams.getSessionId();
490             sessionType = firaOpenSessionParams.getSessionType();
491             mSessionManager.initSession(attributionSource, sessionHandle, sessionId,
492                     (byte) sessionType, firaOpenSessionParams.getProtocolName(),
493                     firaOpenSessionParams, rangingCallbacks, chipId);
494         } else if (CccParams.isCorrectProtocol(params)) {
495             CccOpenRangingParams cccOpenRangingParams = CccOpenRangingParams.fromBundle(params);
496             sessionId = cccOpenRangingParams.getSessionId();
497             sessionType = cccOpenRangingParams.getSessionType();
498             mSessionManager.initSession(attributionSource, sessionHandle, sessionId,
499                     (byte) sessionType, cccOpenRangingParams.getProtocolName(),
500                     cccOpenRangingParams, rangingCallbacks, chipId);
501         } else {
502             Log.e(TAG, "openRanging - Wrong parameters");
503             try {
504                 rangingCallbacks.onRangingOpenFailed(sessionHandle,
505                         RangingChangeReason.BAD_PARAMETERS, new PersistableBundle());
506             } catch (RemoteException e) { }
507         }
508     }
509 
startRanging(SessionHandle sessionHandle, PersistableBundle params)510     public void startRanging(SessionHandle sessionHandle, PersistableBundle params)
511             throws IllegalStateException {
512         if (!isUwbEnabled()) {
513             throw new IllegalStateException("Uwb is not enabled");
514         }
515         Params  startRangingParams = null;
516         if (CccParams.isCorrectProtocol(params)) {
517             startRangingParams = CccStartRangingParams.fromBundle(params);
518         }
519 
520         if (mUwbInjector.getProfileManager().hasSession(sessionHandle)) {
521             mUwbInjector.getProfileManager().startRanging(sessionHandle);
522         } else {
523             mSessionManager.startRanging(sessionHandle, startRangingParams);
524         }
525     }
526 
reconfigureRanging(SessionHandle sessionHandle, PersistableBundle params)527     public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle params) {
528         if (!isUwbEnabled()) {
529             throw new IllegalStateException("Uwb is not enabled");
530         }
531         Params  reconfigureRangingParams = null;
532         if (FiraParams.isCorrectProtocol(params)) {
533             reconfigureRangingParams = FiraRangingReconfigureParams.fromBundle(params);
534         } else if (CccParams.isCorrectProtocol(params)) {
535             reconfigureRangingParams = CccRangingReconfiguredParams.fromBundle(params);
536         }
537         mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams);
538     }
539 
stopRanging(SessionHandle sessionHandle)540     public void stopRanging(SessionHandle sessionHandle) {
541         if (!isUwbEnabled()) {
542             throw new IllegalStateException("Uwb is not enabled");
543         }
544         if (mUwbInjector.getProfileManager().hasSession(sessionHandle)) {
545             mUwbInjector.getProfileManager().stopRanging(sessionHandle);
546         } else {
547             mSessionManager.stopRanging(sessionHandle);
548         }
549     }
550 
closeRanging(SessionHandle sessionHandle)551     public void closeRanging(SessionHandle sessionHandle) {
552         if (!isUwbEnabled()) {
553             throw new IllegalStateException("Uwb is not enabled");
554         }
555         if (mUwbInjector.getProfileManager().hasSession(sessionHandle)) {
556             mUwbInjector.getProfileManager().closeRanging(sessionHandle);
557         } else {
558             mSessionManager.deInitSession(sessionHandle);
559         }
560     }
561 
addControlee(SessionHandle sessionHandle, PersistableBundle params)562     public void addControlee(SessionHandle sessionHandle, PersistableBundle params) {
563         if (!isUwbEnabled()) {
564             throw new IllegalStateException("Uwb is not enabled");
565         }
566         Params  reconfigureRangingParams = null;
567         if (FiraParams.isCorrectProtocol(params)) {
568             FiraControleeParams controleeParams = FiraControleeParams.fromBundle(params);
569             reconfigureRangingParams = new FiraRangingReconfigureParams.Builder()
570                     .setAction(controleeParams.getAction())
571                     .setAddressList(controleeParams.getAddressList())
572                     .setSubSessionIdList(controleeParams.getSubSessionIdList())
573                     .setSubSessionKeyList(controleeParams.getSubSessionKeyList())
574                     .build();
575         }
576         mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams);
577     }
578 
removeControlee(SessionHandle sessionHandle, PersistableBundle params)579     public void removeControlee(SessionHandle sessionHandle, PersistableBundle params) {
580         if (!isUwbEnabled()) {
581             throw new IllegalStateException("Uwb is not enabled");
582         }
583         Params  reconfigureRangingParams = null;
584         if (FiraParams.isCorrectProtocol(params)) {
585             FiraControleeParams controleeParams = FiraControleeParams.fromBundle(params);
586             reconfigureRangingParams = new FiraRangingReconfigureParams.Builder()
587                     .setAction(controleeParams.getAction())
588                     .setAddressList(controleeParams.getAddressList())
589                     .setSubSessionIdList(controleeParams.getSubSessionIdList())
590                     .setSubSessionKeyList(controleeParams.getSubSessionKeyList())
591                     .build();
592         }
593         mSessionManager.reconfigure(sessionHandle, reconfigureRangingParams);
594     }
595 
596     /** Send the payload data to a remote device in the UWB session */
sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, PersistableBundle params, byte[] data)597     public void sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress,
598             PersistableBundle params, byte[] data) throws RemoteException {
599         if (!isUwbEnabled()) {
600             throw new IllegalStateException("Uwb is not enabled");
601         }
602 
603         mSessionManager.sendData(sessionHandle, remoteDeviceAddress, params, data);
604     }
605 
606     /**
607      * Get the UWB Adapter State.
608      */
getAdapterState()609     public /* @UwbManager.AdapterStateCallback.State */ int getAdapterState() {
610         return computeAdapterState(mUwbCountryCode.getCountryCode(), Optional.empty());
611     }
612 
computeAdapterState(String countryCode, Optional<Integer> setCountryCodeStatus)613     private int computeAdapterState(String countryCode, Optional<Integer> setCountryCodeStatus) {
614         // When either the country code is not valid or setting it in UWBS failed with an error,
615         // notify the UWB stack state as DISABLED (even though internally the UWB device state
616         // may be stored as READY), so that applications wait for starting a ranging session.
617         if (!mUwbCountryCode.isValid(countryCode)
618                 || (setCountryCodeStatus.isPresent()
619                 && setCountryCodeStatus.get() != STATUS_CODE_OK)) {
620             return AdapterStateCallback.STATE_DISABLED;
621         }
622         return getInternalAdapterState();
623     }
624 
getInternalAdapterState()625     private /* @UwbManager.AdapterStateCallback.State */ int getInternalAdapterState() {
626         synchronized (UwbServiceCore.this) {
627             if (mChipIdToStateMap.isEmpty()) {
628                 return AdapterStateCallback.STATE_DISABLED;
629             }
630 
631             boolean isActive = false;
632             for (int state : mChipIdToStateMap.values()) {
633                 if (state == AdapterStateCallback.STATE_DISABLED) {
634                     return AdapterStateCallback.STATE_DISABLED;
635                 }
636                 if (state == AdapterStateCallback.STATE_ENABLED_ACTIVE) {
637                     isActive = true;
638                 }
639             }
640             return isActive ? AdapterStateCallback.STATE_ENABLED_ACTIVE
641                     : AdapterStateCallback.STATE_ENABLED_INACTIVE;
642         }
643     }
644 
setEnabled(boolean enabled)645     public synchronized void setEnabled(boolean enabled) {
646         int task = enabled ? TASK_ENABLE : TASK_DISABLE;
647 
648         if (enabled && isUwbEnabled()) {
649             Log.w(TAG, "Uwb is already enabled");
650         } else if (!enabled && !isUwbEnabled()) {
651             Log.w(TAG, "Uwb is already disabled");
652         }
653 
654         mUwbTask.execute(task);
655     }
656 
sendVendorUciResponse(int gid, int oid, byte[] payload)657     private void sendVendorUciResponse(int gid, int oid, byte[] payload) {
658         Log.i(TAG, "onVendorUciResponseReceived");
659         if (mCallBack != null) {
660             try {
661                 mCallBack.onVendorResponseReceived(gid, oid, payload);
662             } catch (RemoteException e) {
663                 Log.e(TAG, "Failed to send vendor response", e);
664             }
665         }
666     }
667 
668     /**
669      * Send vendor UCI message
670      *
671      * @param chipId : Identifier of UWB chip for multi-HAL devices
672      */
sendVendorUciMessage(int mt, int gid, int oid, byte[] payload, String chipId)673     public synchronized int sendVendorUciMessage(int mt, int gid, int oid, byte[] payload,
674             String chipId) {
675         if ((!isUwbEnabled())) {
676             Log.e(TAG, "sendRawVendor : Uwb is not enabled");
677             return UwbUciConstants.STATUS_CODE_FAILED;
678         }
679         // Testing message type is only allowed in version FiRa 2.0 and above.
680         if (mt != MESSAGE_TYPE_COMMAND && getCachedSpecificationParams(chipId)
681                 .getFiraSpecificationParams()
682                 .getMaxMacVersionSupported()
683                 .getMajor() < FIRA_VERSION_MAJOR_2) {
684             Log.e(TAG, "Message Type  " + mt + " not supported in this FiRa version");
685             return  UwbUciConstants.STATUS_CODE_FAILED;
686         }
687         // TODO(b/211445008): Consolidate to a single uwb thread.
688         FutureTask<Integer> sendVendorCmdTask = new FutureTask<>(
689                 () -> {
690                     UwbVendorUciResponse response =
691                             mNativeUwbManager.sendRawVendorCmd(mt, gid, oid, payload, chipId);
692                     if (response.status == UwbUciConstants.STATUS_CODE_OK) {
693                         sendVendorUciResponse(response.gid, response.oid, response.payload);
694                     }
695                     return Integer.valueOf(response.status);
696                 });
697         int status = UwbUciConstants.STATUS_CODE_FAILED;
698         try {
699             status = mUwbInjector.runTaskOnSingleThreadExecutor(sendVendorCmdTask,
700                     SEND_VENDOR_CMD_TIMEOUT_MS);
701         } catch (TimeoutException e) {
702             Log.i(TAG, "Failed to send vendor command - status : TIMEOUT");
703         } catch (InterruptedException e) {
704             e.printStackTrace();
705         } catch (ExecutionException e) {
706             e.printStackTrace();
707         }
708         return status;
709     }
710 
rangingRoundsUpdateDtTag(SessionHandle sessionHandle, PersistableBundle params)711     public void rangingRoundsUpdateDtTag(SessionHandle sessionHandle,
712             PersistableBundle params) throws RemoteException {
713         if (!isUwbEnabled()) {
714             throw new IllegalStateException("Uwb is not enabled");
715         }
716         mSessionManager.rangingRoundsUpdateDtTag(sessionHandle, params);
717     }
718 
719     /**
720      * Query max application data size that can be sent by UWBS in one ranging round.
721      */
queryMaxDataSizeBytes(SessionHandle sessionHandle)722     public int queryMaxDataSizeBytes(SessionHandle sessionHandle) {
723         if (!isUwbEnabled()) {
724             throw new IllegalStateException("Uwb is not enabled");
725         }
726 
727         return mSessionManager.queryMaxDataSizeBytes(sessionHandle);
728     }
729 
730     /**
731      * Update the pose used by the filter engine to distinguish tag position changes from device
732      * position changes.
733      */
updatePose(SessionHandle sessionHandle, PersistableBundle params)734     public void updatePose(SessionHandle sessionHandle, PersistableBundle params) {
735         mSessionManager.updatePose(sessionHandle, params);
736     }
737 
738     private class UwbTask extends Handler {
739 
UwbTask(Looper looper)740         UwbTask(Looper looper) {
741             super(looper);
742         }
743 
744         @Override
handleMessage(Message msg)745         public void handleMessage(Message msg) {
746             int type = msg.what;
747             switch (type) {
748                 case TASK_ENABLE:
749                     handleEnable();
750                     break;
751 
752                 case TASK_DISABLE:
753                     mSessionManager.deinitAllSession();
754                     handleDisable();
755                     break;
756 
757                 case TASK_RESTART:
758                     mSessionManager.deinitAllSession();
759                     handleDisable();
760                     handleEnable();
761                     break;
762 
763                 case TASK_GET_POWER_STATS:
764                     invokeUwbActivityEnergyInfoListener((IOnUwbActivityEnergyInfoListener) msg.obj);
765                     break;
766 
767                 default:
768                     Log.d(TAG, "UwbTask : Undefined Task");
769                     break;
770             }
771         }
772 
execute(int task)773         public void execute(int task) {
774             Message msg = mUwbTask.obtainMessage();
775             msg.what = task;
776             this.sendMessage(msg);
777         }
execute(int task, int arg1, int arg2)778         public void execute(int task, int arg1, int arg2) {
779             Message msg = mUwbTask.obtainMessage();
780             msg.what = task;
781             msg.arg1 = arg1;
782             msg.arg2 = arg2;
783             this.sendMessage(msg);
784         }
785 
execute(int task, Object obj)786         public void execute(int task, Object obj) {
787             Message msg = mUwbTask.obtainMessage();
788             msg.what = task;
789             msg.obj = obj;
790             this.sendMessage(msg);
791         }
792 
executeUnique(int task, int arg1, int arg2)793         private void executeUnique(int task, int arg1, int arg2) {
794             mUwbTask.removeMessages(task);
795             Message msg = mUwbTask.obtainMessage();
796             msg.what = task;
797             msg.arg1 = arg1;
798             msg.arg2 = arg2;
799             this.sendMessage(msg);
800         }
801 
delayedExecute(int task, int arg1, int arg2, int delayMillis)802         private void delayedExecute(int task, int arg1, int arg2, int delayMillis) {
803             Message msg = mUwbTask.obtainMessage();
804             msg.what = task;
805             msg.arg1 = arg1;
806             msg.arg2 = arg2;
807             this.sendMessageDelayed(msg, delayMillis);
808         }
809 
handleEnable()810         private void handleEnable() {
811             if (isUwbEnabled()) {
812                 Log.i(TAG, "UWB service is already enabled");
813                 return;
814             }
815             try {
816                 WatchDogThread watchDog = new WatchDogThread("handleEnable", WATCHDOG_MS);
817                 watchDog.start();
818 
819                 Log.i(TAG, "Initialization start ...");
820                 synchronized (mUwbWakeLock) {
821                     mUwbWakeLock.acquire();
822                 }
823 
824                 try {
825                     if (!mNativeUwbManager.doInitialize()) {
826                         Log.e(TAG, "Error enabling UWB");
827                         mUwbMetrics.incrementDeviceInitFailureCount();
828                         takBugReportAfterDeviceError("UWB Bugreport: error enabling UWB");
829                         for (String chipId : mUwbInjector.getMultichipData().getChipIds()) {
830                             updateState(AdapterStateCallback.STATE_DISABLED, chipId);
831                         }
832                         for (InitializationFailureListener listener : mListeners) {
833                             listener.onFailure();
834                         }
835                     } else {
836                         Log.i(TAG, "Initialization success");
837                         /* TODO : keep it until MW, FW fix b/196943897 */
838                         mUwbMetrics.incrementDeviceInitSuccessCount();
839 
840                         for (String chipId : mUwbInjector.getMultichipData().getChipIds()) {
841                             Log.d(TAG, "enabling chip " + chipId);
842                             updateDeviceState(UwbUciConstants.DEVICE_STATE_READY, chipId);
843                         }
844 
845                         // Set country code on every enable (example: for the scenario when the
846                         // country code was determined/changed while the UWB stack was disabled).
847                         //
848                         // TODO(b/255977441): Handle the case when the countryCode is valid and
849                         // setting the country code returned an error by doing a UWBS reset.
850                         Pair<Integer, String> setCountryCodeResult =
851                                 mUwbCountryCode.setCountryCode(true);
852                         Optional<Integer> setCountryCodeStatus =
853                                 Optional.of(setCountryCodeResult.first);
854                         String countryCode = setCountryCodeResult.second;
855                         Log.i(TAG, "Current country code = " + countryCode);
856                         computeAndNotifyAdapterStateChange(
857                                 getReasonFromDeviceState(UwbUciConstants.DEVICE_STATE_READY),
858                                 countryCode,
859                                 setCountryCodeStatus);
860                     }
861                 } finally {
862                     synchronized (mUwbWakeLock) {
863                         if (mUwbWakeLock.isHeld()) {
864                             mUwbWakeLock.release();
865                         }
866                     }
867                     watchDog.cancel();
868                 }
869             } catch (Exception e) {
870                 e.printStackTrace();
871             }
872         }
873 
handleDisable()874         private void handleDisable() {
875             if (!isUwbEnabled()) {
876                 Log.i(TAG, "UWB service is already disabled");
877                 return;
878             }
879 
880             WatchDogThread watchDog = new WatchDogThread("handleDisable", WATCHDOG_MS);
881             watchDog.start();
882 
883             try {
884                 Log.i(TAG, "Deinitialization start ...");
885                 synchronized (mUwbWakeLock) {
886                     mUwbWakeLock.acquire();
887                 }
888 
889                 if (!mNativeUwbManager.doDeinitialize()) {
890                     Log.w(TAG, "Error disabling UWB");
891                 } else {
892                     Log.i(TAG, "Deinitialization success");
893                 }
894                 /* UWBS_STATUS_OFF is not the valid state. so handle device state directly */
895                 for (String chipId : mUwbInjector.getMultichipData().getChipIds()) {
896                     updateDeviceState(UwbUciConstants.DEVICE_STATE_OFF, chipId);
897                 }
898                 notifyAdapterState(
899                         getAdapterStateFromDeviceState(UwbUciConstants.DEVICE_STATE_OFF),
900                         getReasonFromDeviceState(UwbUciConstants.DEVICE_STATE_OFF));
901             } finally {
902                 synchronized (mUwbWakeLock) {
903                     if (mUwbWakeLock.isHeld()) {
904                         mUwbWakeLock.release();
905                     }
906                 }
907                 watchDog.cancel();
908             }
909         }
910 
computeAndNotifyAdapterStateChange(int reason, String countryCode, Optional<Integer> setCountryCodeStatus)911         private void computeAndNotifyAdapterStateChange(int reason,
912                 String countryCode, Optional<Integer> setCountryCodeStatus) {
913             // When either the country code is not valid or setting it in UWBS failed with the error
914             // STATUS_CODE_ANDROID_REGULATION_UWB_OFF, notify with the reason SYSTEM_REGULATION.
915             if (!mUwbCountryCode.isValid(countryCode)
916                     || (setCountryCodeStatus.isPresent()
917                         && setCountryCodeStatus.get()
918                         == UwbUciConstants.STATUS_CODE_ANDROID_REGULATION_UWB_OFF)) {
919                 reason = StateChangeReason.SYSTEM_REGULATION;
920             }
921 
922             notifyAdapterState(computeAdapterState(countryCode, setCountryCodeStatus), reason);
923         }
924 
925         public class WatchDogThread extends Thread {
926             final Object mCancelWaiter = new Object();
927             final int mTimeout;
928             boolean mCanceled = false;
929 
WatchDogThread(String threadName, int timeout)930             WatchDogThread(String threadName, int timeout) {
931                 super(threadName);
932 
933                 mTimeout = timeout;
934             }
935 
936             @Override
run()937             public void run() {
938                 try {
939                     synchronized (mCancelWaiter) {
940                         mCancelWaiter.wait(mTimeout);
941                         if (mCanceled) {
942                             return;
943                         }
944                     }
945                 } catch (InterruptedException e) {
946                     e.printStackTrace();
947                     interrupt();
948                 }
949 
950                 synchronized (mUwbWakeLock) {
951                     if (mUwbWakeLock.isHeld()) {
952                         mUwbWakeLock.release();
953                     }
954                 }
955             }
956 
cancel()957             public synchronized void cancel() {
958                 synchronized (mCancelWaiter) {
959                     mCanceled = true;
960                     mCancelWaiter.notify();
961                 }
962             }
963         }
964     }
965 
takBugReportAfterDeviceError(String bugTitle)966     private void takBugReportAfterDeviceError(String bugTitle) {
967         if (mUwbInjector.getDeviceConfigFacade().isDeviceErrorBugreportEnabled()) {
968             mUwbInjector.getUwbDiagnostics().takeBugReport(bugTitle);
969         }
970     }
971 
972     /**
973      * Dump the UWB session manager debug info
974      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)975     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
976         pw.println("---- Dump of UwbServiceCore ----");
977         for (String chipId : mUwbInjector.getMultichipData().getChipIds()) {
978             pw.println("Device state = " + getDeviceStateString(mChipIdToStateMap.get(chipId))
979                     + " for chip id = " + chipId);
980         }
981         pw.println("mLastAdapterStateChangedReason = " + mLastAdapterStateChangedReason);
982         pw.println("mLastAdapterStateNotification = " + mLastAdapterStateNotification);
983         pw.println("---- Dump of UwbServiceCore ----");
984     }
985 
986     /**
987      * Report the UWB power stats to the listener
988      */
reportUwbActivityEnergyInfo( IOnUwbActivityEnergyInfoListener listener)989     public synchronized void reportUwbActivityEnergyInfo(
990             IOnUwbActivityEnergyInfoListener listener) {
991         mUwbTask.execute(TASK_GET_POWER_STATS, listener);
992     }
993 
invokeUwbActivityEnergyInfoListener(IOnUwbActivityEnergyInfoListener listener)994     private void invokeUwbActivityEnergyInfoListener(IOnUwbActivityEnergyInfoListener listener) {
995         try {
996             listener.onUwbActivityEnergyInfo(getUwbActivityEnergyInfo());
997         } catch (RemoteException e) {
998             Log.e(TAG, "onUwbActivityEnergyInfo: RemoteException -- ", e);
999         }
1000     }
1001 
getUwbActivityEnergyInfo()1002     private UwbActivityEnergyInfo getUwbActivityEnergyInfo() {
1003         try {
1004             String chipId = mUwbInjector.getMultichipData().getDefaultChipId();
1005             PersistableBundle bundle = getSpecificationInfo(chipId);
1006             GenericSpecificationParams params = GenericSpecificationParams.fromBundle(bundle);
1007             if (!isUwbEnabled() || params == null || !params.hasPowerStatsSupport()) {
1008                 return null;
1009             }
1010             UwbPowerStats stats = mNativeUwbManager.getPowerStats(chipId);
1011             if (stats == null) {
1012                 return null;
1013             }
1014 
1015             Log.d(TAG, " getUwbActivityEnergyInfo: "
1016                     + " tx_time_millis=" + stats.getTxTimeMs()
1017                     + " rx_time_millis=" + stats.getRxTimeMs()
1018                     + " rxIdleTimeMillis=" + stats.getIdleTimeMs()
1019                     + " wake_count=" + stats.getTotalWakeCount());
1020 
1021             return new UwbActivityEnergyInfo.Builder()
1022                     .setTimeSinceBootMillis(SystemClock.elapsedRealtime())
1023                     .setStackState(getInternalAdapterState())
1024                     .setControllerTxDurationMillis(stats.getTxTimeMs())
1025                     .setControllerRxDurationMillis(stats.getRxTimeMs())
1026                     .setControllerIdleDurationMillis(stats.getIdleTimeMs())
1027                     .setControllerWakeCount(stats.getTotalWakeCount())
1028                     .build();
1029         } catch (Exception e) {
1030             e.printStackTrace();
1031             return null;
1032         }
1033     }
1034 }
1035