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.content.pm.PackageManager.PERMISSION_GRANTED;
20 
21 import android.annotation.NonNull;
22 import android.content.AttributionSource;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.database.ContentObserver;
28 import android.net.Uri;
29 import android.os.Binder;
30 import android.os.IBinder;
31 import android.os.ParcelFileDescriptor;
32 import android.os.PersistableBundle;
33 import android.os.Process;
34 import android.os.RemoteException;
35 import android.os.UserManager;
36 import android.provider.Settings;
37 import android.util.Log;
38 import android.uwb.IOnUwbActivityEnergyInfoListener;
39 import android.uwb.IUwbAdapter;
40 import android.uwb.IUwbAdapterStateCallbacks;
41 import android.uwb.IUwbAdfProvisionStateCallbacks;
42 import android.uwb.IUwbOemExtensionCallback;
43 import android.uwb.IUwbRangingCallbacks;
44 import android.uwb.IUwbVendorUciCallback;
45 import android.uwb.SessionHandle;
46 import android.uwb.UwbAddress;
47 
48 import com.android.internal.annotations.VisibleForTesting;
49 import com.android.modules.utils.build.SdkLevel;
50 import com.android.server.uwb.data.UwbUciConstants;
51 
52 import com.google.uwb.support.generic.GenericSpecificationParams;
53 import com.google.uwb.support.multichip.ChipInfoParams;
54 import com.google.uwb.support.profile.ServiceProfile;
55 import com.google.uwb.support.profile.UuidBundleWrapper;
56 
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.Optional;
62 import java.util.UUID;
63 
64 /**
65  * Implementation of {@link android.uwb.IUwbAdapter} binder service.
66  */
67 public class UwbServiceImpl extends IUwbAdapter.Stub {
68     private static final String TAG = "UwbServiceImpl";
69 
70     /**
71      * @hide constant copied from {@link Settings.Global}
72      * TODO(b/274636414): Migrate to official API in Android V.
73      */
74     private static final String SETTINGS_RADIO_UWB = "uwb";
75     /**
76      * @hide constant copied from {@link Settings.Global}
77      * TODO(b/274636414): Migrate to official API in Android V.
78      */
79     @VisibleForTesting
80     public static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios";
81     /**
82      * @hide constant copied from {@link Settings.Global}
83      * TODO(b/274636414): Migrate to official API in Android V.
84      */
85     @VisibleForTesting
86     public static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled";
87     @VisibleForTesting
88     public static final int INITIALIZATION_RETRY_TIMEOUT_MS = 10_000;
89 
90     private final Context mContext;
91     private final UwbInjector mUwbInjector;
92     private final UwbSettingsStore mUwbSettingsStore;
93     private final UwbServiceCore mUwbServiceCore;
94 
95     private boolean mUwbUserRestricted;
96 
97     private UwbServiceCore.InitializationFailureListener mInitializationFailureListener;
98 
UwbServiceImpl(@onNull Context context, @NonNull UwbInjector uwbInjector)99     UwbServiceImpl(@NonNull Context context, @NonNull UwbInjector uwbInjector) {
100         mContext = context;
101         mUwbInjector = uwbInjector;
102         mUwbSettingsStore = uwbInjector.getUwbSettingsStore();
103         mUwbServiceCore = uwbInjector.getUwbServiceCore();
104         mInitializationFailureListener = () -> {
105             Log.i(TAG, "Initialization failed, retry initialization after "
106                     + INITIALIZATION_RETRY_TIMEOUT_MS + "ms");
107             mUwbServiceCore.getHandler().postDelayed(() -> {
108                 try {
109                     mUwbServiceCore.setEnabled(isUwbEnabled());
110                 } catch (Exception e) {
111                     Log.e(TAG, "Unable to set UWB Adapter state.", e);
112                 }
113             }, INITIALIZATION_RETRY_TIMEOUT_MS);
114             // Remove initialization failure listener after first retry attempt to avoid
115             // continuously retrying.
116             mUwbServiceCore.removeInitializationFailureListener(mInitializationFailureListener);
117         };
118         mUwbServiceCore.addInitializationFailureListener(mInitializationFailureListener);
119         registerAirplaneModeReceiver();
120         registerSatelliteModeReceiver();
121         mUwbUserRestricted = isUwbUserRestricted();
122         registerUserRestrictionsReceiver();
123     }
124 
125     /**
126      * Initialize the stack after boot completed.
127      */
initialize()128     public void initialize() {
129         mUwbSettingsStore.initialize();
130         mUwbInjector.getMultichipData().initialize();
131         mUwbInjector.getUwbCountryCode().initialize();
132         mUwbInjector.getUciLogModeStore().initialize();
133         // Initialize the UCI stack at bootup.
134         boolean enabled = isUwbEnabled();
135         if (enabled && mUwbInjector.getDeviceConfigFacade().isUwbDisabledUntilFirstToggle()
136                 && !isUwbFirstToggleDone()) {
137             // Disable uwb on first boot until the user explicitly toggles UWB on for the
138             // first time.
139             enabled = false;
140         }
141         mUwbServiceCore.setEnabled(enabled);
142     }
143 
144     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)145     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
146         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
147                 != PERMISSION_GRANTED) {
148             pw.println("Permission Denial: can't dump UwbService from from pid="
149                     + Binder.getCallingPid()
150                     + ", uid=" + Binder.getCallingUid());
151             return;
152         }
153         mUwbSettingsStore.dump(fd, pw, args);
154         pw.println();
155         mUwbInjector.getUwbMetrics().dump(fd, pw, args);
156         pw.println();
157         mUwbServiceCore.dump(fd, pw, args);
158         pw.println();
159         mUwbInjector.getUwbSessionManager().dump(fd, pw, args);
160         pw.println();
161         mUwbInjector.getUwbCountryCode().dump(fd, pw, args);
162         pw.println();
163         mUwbInjector.getUwbConfigStore().dump(fd, pw, args);
164         pw.println();
165         if (isUwbEnabled()) {
166             dumpPowerStats(fd, pw, args);
167         }
168     }
169 
dumpPowerStats(FileDescriptor fd, PrintWriter pw, String[] args)170     private void dumpPowerStats(FileDescriptor fd, PrintWriter pw, String[] args) {
171         pw.println("---- PowerStats ----");
172         try {
173             PersistableBundle bundle = getSpecificationInfo(null);
174             GenericSpecificationParams params = GenericSpecificationParams.fromBundle(bundle);
175             if (params == null) {
176                 pw.println("Spec info is empty. Fail to get power stats.");
177                 return;
178             }
179             if (params.hasPowerStatsSupport()) {
180                 pw.println(mUwbInjector.getNativeUwbManager().getPowerStats(getDefaultChipId()));
181             } else {
182                 pw.println("power stats query is not supported");
183             }
184         } catch (Exception e) {
185             pw.println("Exception while getting power stats.");
186             e.printStackTrace(pw);
187         }
188         pw.println("---- PowerStats ----");
189     }
190 
enforceUwbPrivilegedPermission()191     private void enforceUwbPrivilegedPermission() {
192         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.UWB_PRIVILEGED,
193                 "UwbService");
194     }
195 
onUserRestrictionsChanged()196     private void onUserRestrictionsChanged() {
197         if (mUwbUserRestricted == isUwbUserRestricted()) {
198             return;
199         }
200 
201         Log.i(TAG, "Disallow UWB user restriction changed from " + mUwbUserRestricted + " to "
202                 + !mUwbUserRestricted + ".");
203         mUwbUserRestricted = !mUwbUserRestricted;
204 
205         try {
206             mUwbServiceCore.setEnabled(isUwbEnabled());
207         } catch (Exception e) {
208             Log.e(TAG, "Unable to set UWB Adapter state.", e);
209         }
210     }
211 
212     @Override
registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)213     public void registerAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
214             throws RemoteException {
215         enforceUwbPrivilegedPermission();
216         mUwbServiceCore.registerAdapterStateCallbacks(adapterStateCallbacks);
217     }
218 
219     @Override
registerVendorExtensionCallback(IUwbVendorUciCallback callbacks)220     public void registerVendorExtensionCallback(IUwbVendorUciCallback callbacks)
221             throws RemoteException {
222         Log.i(TAG, "Register the callback");
223         enforceUwbPrivilegedPermission();
224         mUwbServiceCore.registerVendorExtensionCallback(callbacks);
225     }
226 
227     @Override
unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks)228     public void unregisterVendorExtensionCallback(IUwbVendorUciCallback callbacks)
229             throws RemoteException {
230         Log.i(TAG, "Unregister the callback");
231         enforceUwbPrivilegedPermission();
232         mUwbServiceCore.unregisterVendorExtensionCallback(callbacks);
233     }
234 
235 
236     @Override
unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)237     public void unregisterAdapterStateCallbacks(IUwbAdapterStateCallbacks adapterStateCallbacks)
238             throws RemoteException {
239         enforceUwbPrivilegedPermission();
240         mUwbServiceCore.unregisterAdapterStateCallbacks(adapterStateCallbacks);
241     }
242 
243     @Override
registerOemExtensionCallback(IUwbOemExtensionCallback callbacks)244     public void registerOemExtensionCallback(IUwbOemExtensionCallback callbacks)
245             throws RemoteException {
246         if (!SdkLevel.isAtLeastU()) {
247             throw new UnsupportedOperationException();
248         }
249         Log.i(TAG, "Register Oem Extension callback");
250         enforceUwbPrivilegedPermission();
251         mUwbServiceCore.registerOemExtensionCallback(callbacks);
252     }
253 
254     @Override
unregisterOemExtensionCallback(IUwbOemExtensionCallback callbacks)255     public void unregisterOemExtensionCallback(IUwbOemExtensionCallback callbacks)
256             throws RemoteException {
257         if (!SdkLevel.isAtLeastU()) {
258             throw new UnsupportedOperationException();
259         }
260         Log.i(TAG, "Unregister Oem Extension callback");
261         enforceUwbPrivilegedPermission();
262         mUwbServiceCore.unregisterOemExtensionCallback(callbacks);
263     }
264 
265     @Override
getTimestampResolutionNanos(String chipId)266     public long getTimestampResolutionNanos(String chipId) throws RemoteException {
267         enforceUwbPrivilegedPermission();
268         validateChipId(chipId);
269         // TODO(/b/237601383): Determine whether getTimestampResolutionNanos should take a chipId
270         // parameter
271         return mUwbServiceCore.getTimestampResolutionNanos();
272     }
273 
274     @Override
getSpecificationInfo(String chipId)275     public PersistableBundle getSpecificationInfo(String chipId) throws RemoteException {
276         enforceUwbPrivilegedPermission();
277         chipId = validateChipId(chipId);
278         return mUwbServiceCore.getSpecificationInfo(chipId);
279     }
280 
281 
282     @Override
queryUwbsTimestampMicros()283     public long queryUwbsTimestampMicros() throws RemoteException {
284         if (!SdkLevel.isAtLeastV()) {
285             throw new UnsupportedOperationException();
286         }
287         enforceUwbPrivilegedPermission();
288         return mUwbServiceCore.queryUwbsTimestampMicros();
289     }
290 
291     @Override
openRanging(AttributionSource attributionSource, SessionHandle sessionHandle, IUwbRangingCallbacks rangingCallbacks, PersistableBundle parameters, String chipId)292     public void openRanging(AttributionSource attributionSource,
293             SessionHandle sessionHandle,
294             IUwbRangingCallbacks rangingCallbacks,
295             PersistableBundle parameters,
296             String chipId) throws RemoteException {
297         enforceUwbPrivilegedPermission();
298         chipId = validateChipId(chipId);
299         mUwbInjector.enforceUwbRangingPermissionForPreflight(attributionSource);
300         mUwbServiceCore.openRanging(attributionSource,
301                 sessionHandle,
302                 rangingCallbacks,
303                 parameters,
304                 chipId);
305     }
306 
307     @Override
startRanging(SessionHandle sessionHandle, PersistableBundle parameters)308     public void startRanging(SessionHandle sessionHandle, PersistableBundle parameters)
309             throws RemoteException {
310         enforceUwbPrivilegedPermission();
311         mUwbServiceCore.startRanging(sessionHandle, parameters);
312     }
313 
314     @Override
reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)315     public void reconfigureRanging(SessionHandle sessionHandle, PersistableBundle parameters)
316             throws RemoteException {
317         enforceUwbPrivilegedPermission();
318         mUwbServiceCore.reconfigureRanging(sessionHandle, parameters);
319     }
320 
321     @Override
stopRanging(SessionHandle sessionHandle)322     public void stopRanging(SessionHandle sessionHandle) throws RemoteException {
323         enforceUwbPrivilegedPermission();
324         mUwbServiceCore.stopRanging(sessionHandle);
325     }
326 
327     @Override
closeRanging(SessionHandle sessionHandle)328     public void closeRanging(SessionHandle sessionHandle) throws RemoteException {
329         enforceUwbPrivilegedPermission();
330         mUwbServiceCore.closeRanging(sessionHandle);
331     }
332 
333     @Override
sendVendorUciMessage(int mt, int gid, int oid, byte[] payload)334     public synchronized int sendVendorUciMessage(int mt, int gid, int oid, byte[] payload)
335             throws RemoteException {
336         enforceUwbPrivilegedPermission();
337         // TODO(b/237533396): Add a sendVendorUciMessage that takes a chipId parameter
338         return mUwbServiceCore.sendVendorUciMessage(mt, gid, oid, payload, getDefaultChipId());
339     }
340 
341     @Override
addControlee(SessionHandle sessionHandle, PersistableBundle params)342     public void addControlee(SessionHandle sessionHandle, PersistableBundle params) {
343         enforceUwbPrivilegedPermission();
344         mUwbServiceCore.addControlee(sessionHandle, params);
345     }
346 
347     @Override
removeControlee(SessionHandle sessionHandle, PersistableBundle params)348     public void removeControlee(SessionHandle sessionHandle, PersistableBundle params) {
349         enforceUwbPrivilegedPermission();
350         mUwbServiceCore.removeControlee(sessionHandle, params);
351     }
352 
353     @Override
pause(SessionHandle sessionHandle, PersistableBundle params)354     public void pause(SessionHandle sessionHandle, PersistableBundle params) {
355         enforceUwbPrivilegedPermission();
356         mUwbServiceCore.pause(sessionHandle, params);
357     }
358 
359     @Override
resume(SessionHandle sessionHandle, PersistableBundle params)360     public void resume(SessionHandle sessionHandle, PersistableBundle params) {
361         enforceUwbPrivilegedPermission();
362         mUwbServiceCore.resume(sessionHandle, params);
363     }
364 
365     @Override
sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress, PersistableBundle params, byte[] data)366     public void sendData(SessionHandle sessionHandle, UwbAddress remoteDeviceAddress,
367             PersistableBundle params, byte[] data) throws RemoteException {
368         enforceUwbPrivilegedPermission();
369         mUwbServiceCore.sendData(sessionHandle, remoteDeviceAddress, params, data);
370     }
371 
372 
373     @Override
setDataTransferPhaseConfig(SessionHandle sessionHandle, PersistableBundle params)374     public void setDataTransferPhaseConfig(SessionHandle sessionHandle, PersistableBundle params)
375             throws RemoteException {
376         if (!SdkLevel.isAtLeastV() || !mUwbInjector.getFeatureFlags().dataTransferPhaseConfig()) {
377             throw new UnsupportedOperationException();
378         }
379         enforceUwbPrivilegedPermission();
380         mUwbServiceCore.setDataTransferPhaseConfig(sessionHandle, params);
381     }
382 
383     @Override
updateRangingRoundsDtTag(SessionHandle sessionHandle, PersistableBundle parameters)384     public void updateRangingRoundsDtTag(SessionHandle sessionHandle,
385             PersistableBundle parameters) throws RemoteException {
386         if (!SdkLevel.isAtLeastU()) {
387             throw new UnsupportedOperationException();
388         }
389         enforceUwbPrivilegedPermission();
390         mUwbServiceCore.rangingRoundsUpdateDtTag(sessionHandle, parameters);
391     }
392 
393     @Override
queryMaxDataSizeBytes(SessionHandle sessionHandle)394     public int queryMaxDataSizeBytes(SessionHandle sessionHandle) {
395         if (!SdkLevel.isAtLeastU()) {
396             throw new UnsupportedOperationException();
397         }
398         enforceUwbPrivilegedPermission();
399         return mUwbServiceCore.queryMaxDataSizeBytes(sessionHandle);
400     }
401 
402     @Override
getAdapterState()403     public synchronized int getAdapterState() throws RemoteException {
404         return mUwbServiceCore.getAdapterState();
405     }
406 
407     @Override
setHybridSessionControllerConfiguration(SessionHandle sessionHandle, PersistableBundle params)408     public void setHybridSessionControllerConfiguration(SessionHandle sessionHandle,
409             PersistableBundle params) {
410         if (!SdkLevel.isAtLeastV()) {
411             throw new UnsupportedOperationException();
412         }
413         enforceUwbPrivilegedPermission();
414         mUwbServiceCore.setHybridSessionControllerConfiguration(sessionHandle, params);
415     }
416 
417     @Override
setHybridSessionControleeConfiguration(SessionHandle sessionHandle, PersistableBundle params)418     public void setHybridSessionControleeConfiguration(SessionHandle sessionHandle,
419             PersistableBundle params) {
420         if (!SdkLevel.isAtLeastV()) {
421             throw new UnsupportedOperationException();
422         }
423         enforceUwbPrivilegedPermission();
424         mUwbServiceCore.setHybridSessionControleeConfiguration(sessionHandle, params);
425     }
426 
427     @Override
setEnabled(boolean enabled)428     public synchronized void setEnabled(boolean enabled) throws RemoteException {
429         enforceUwbPrivilegedPermission();
430         if (mUwbInjector.getDeviceConfigFacade().isUwbDisabledUntilFirstToggle()) {
431             persistUwbFirstToggleDone();
432         }
433         persistUwbToggleState(enabled);
434         // Shell command from rooted shell, we allow UWB toggle on even if APM mode and
435         // user restriction are on.
436         if (Binder.getCallingUid() == Process.ROOT_UID) {
437             mUwbServiceCore.setEnabled(isUwbToggleEnabled());
438             return;
439         }
440         mUwbServiceCore.setEnabled(isUwbEnabled());
441     }
442 
443     @Override
isHwIdleTurnOffEnabled()444     public synchronized boolean isHwIdleTurnOffEnabled() throws RemoteException {
445         return mUwbInjector.getDeviceConfigFacade().isHwIdleTurnOffEnabled();
446     }
447 
448     @Override
isHwEnableRequested(AttributionSource attributionSource)449     public synchronized boolean isHwEnableRequested(AttributionSource attributionSource)
450             throws RemoteException {
451         if (!mUwbInjector.getDeviceConfigFacade().isHwIdleTurnOffEnabled()) {
452             throw new IllegalStateException("Hw Idle turn off not enabled");
453         }
454         return mUwbServiceCore.isHwEnableRequested(attributionSource);
455     }
456 
457     @Override
requestHwEnabled( boolean enabled, AttributionSource attributionSource, IBinder binder)458     public synchronized void requestHwEnabled(
459             boolean enabled, AttributionSource attributionSource, IBinder binder)
460             throws RemoteException {
461         enforceUwbPrivilegedPermission();
462         if (!mUwbInjector.getDeviceConfigFacade().isHwIdleTurnOffEnabled()) {
463             throw new IllegalStateException("Hw Idle turn off not enabled");
464         }
465         mUwbServiceCore.requestHwEnabled(enabled, attributionSource, binder);
466     }
467 
468     @Override
getChipInfos()469     public List<PersistableBundle> getChipInfos() {
470         enforceUwbPrivilegedPermission();
471         List<ChipInfoParams> chipInfoParamsList = mUwbInjector.getMultichipData().getChipInfos();
472         List<PersistableBundle> chipInfos = new ArrayList<>();
473         for (ChipInfoParams chipInfoParams : chipInfoParamsList) {
474             chipInfos.add(chipInfoParams.toBundle());
475         }
476         return chipInfos;
477     }
478 
479     @Override
getChipIds()480     public List<String> getChipIds() {
481         enforceUwbPrivilegedPermission();
482         List<ChipInfoParams> chipInfoParamsList = mUwbInjector.getMultichipData().getChipInfos();
483         List<String> chipIds = new ArrayList<>();
484         for (ChipInfoParams chipInfoParams : chipInfoParamsList) {
485             chipIds.add(chipInfoParams.getChipId());
486         }
487         return chipIds;
488     }
489 
490     @Override
getDefaultChipId()491     public String getDefaultChipId() {
492         enforceUwbPrivilegedPermission();
493         return mUwbInjector.getMultichipData().getDefaultChipId();
494     }
495 
496     @Override
addServiceProfile(@onNull PersistableBundle parameters)497     public PersistableBundle addServiceProfile(@NonNull PersistableBundle parameters) {
498         enforceUwbPrivilegedPermission();
499         ServiceProfile serviceProfile = ServiceProfile.fromBundle(parameters);
500         Optional<UUID> serviceInstanceID = mUwbInjector
501                 .getProfileManager()
502                 .addServiceProfile(serviceProfile.getServiceID());
503         return new UuidBundleWrapper.Builder()
504                 .setServiceInstanceID(serviceInstanceID)
505                 .build()
506                 .toBundle();
507     }
508 
509     @Override
removeServiceProfile(@onNull PersistableBundle parameters)510     public int removeServiceProfile(@NonNull PersistableBundle parameters) {
511         enforceUwbPrivilegedPermission();
512         UuidBundleWrapper uuidBundleWrapper = UuidBundleWrapper.fromBundle(parameters);
513         if (uuidBundleWrapper.getServiceInstanceID().isPresent()) {
514             return mUwbInjector
515                     .getProfileManager()
516                     .removeServiceProfile(uuidBundleWrapper.getServiceInstanceID().get());
517         }
518         return UwbUciConstants.STATUS_CODE_FAILED;
519     }
520 
521     @Override
getAllServiceProfiles()522     public PersistableBundle getAllServiceProfiles() {
523         enforceUwbPrivilegedPermission();
524         // TODO(b/200678461): Implement this.
525         throw new IllegalStateException("Not implemented");
526     }
527 
528     @NonNull
529     @Override
getAdfProvisioningAuthorities(@onNull PersistableBundle parameters)530     public PersistableBundle getAdfProvisioningAuthorities(@NonNull PersistableBundle parameters) {
531         enforceUwbPrivilegedPermission();
532         // TODO(b/200678461): Implement this.
533         throw new IllegalStateException("Not implemented");
534     }
535 
536     @NonNull
537     @Override
getAdfCertificateAndInfo(@onNull PersistableBundle parameters)538     public PersistableBundle getAdfCertificateAndInfo(@NonNull PersistableBundle parameters) {
539         enforceUwbPrivilegedPermission();
540         // TODO(b/200678461): Implement this.
541         throw new IllegalStateException("Not implemented");
542     }
543 
544     @Override
provisionProfileAdfByScript(@onNull PersistableBundle serviceProfileBundle, @NonNull IUwbAdfProvisionStateCallbacks callback)545     public void provisionProfileAdfByScript(@NonNull PersistableBundle serviceProfileBundle,
546             @NonNull IUwbAdfProvisionStateCallbacks callback) {
547         enforceUwbPrivilegedPermission();
548         // TODO(b/200678461): Implement this.
549         throw new IllegalStateException("Not implemented");
550     }
551 
552     @Override
removeProfileAdf(@onNull PersistableBundle serviceProfileBundle)553     public int removeProfileAdf(@NonNull PersistableBundle serviceProfileBundle) {
554         enforceUwbPrivilegedPermission();
555         // TODO(b/200678461): Implement this.
556         throw new IllegalStateException("Not implemented");
557     }
558 
559     @Override
handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)560     public int handleShellCommand(@NonNull ParcelFileDescriptor in,
561             @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
562             @NonNull String[] args) {
563 
564         UwbShellCommand shellCommand = mUwbInjector.makeUwbShellCommand(this);
565         return shellCommand.exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
566                 err.getFileDescriptor(), args);
567     }
568 
569     @Override
updatePose(SessionHandle sessionHandle, PersistableBundle params)570     public void updatePose(SessionHandle sessionHandle, PersistableBundle params) {
571         enforceUwbPrivilegedPermission();
572         mUwbServiceCore.updatePose(sessionHandle, params);
573     }
574 
persistUwbToggleState(boolean enabled)575     private void persistUwbToggleState(boolean enabled) {
576         mUwbSettingsStore.put(UwbSettingsStore.SETTINGS_TOGGLE_STATE, enabled);
577     }
578 
isUwbFirstToggleDone()579     private boolean isUwbFirstToggleDone() {
580         return mUwbSettingsStore.get(UwbSettingsStore.SETTINGS_FIRST_TOGGLE_DONE);
581     }
582 
persistUwbFirstToggleDone()583     private void persistUwbFirstToggleDone() {
584         mUwbSettingsStore.put(UwbSettingsStore.SETTINGS_FIRST_TOGGLE_DONE, true);
585     }
586 
isUwbToggleEnabled()587     private boolean isUwbToggleEnabled() {
588         return mUwbSettingsStore.get(UwbSettingsStore.SETTINGS_TOGGLE_STATE);
589     }
590 
isAirplaneModeSensitive()591     private boolean isAirplaneModeSensitive() {
592         if (!SdkLevel.isAtLeastU()) return true; // config changed only for Android U.
593         final String apmRadios =
594                 mUwbInjector.getGlobalSettingsString(Settings.Global.AIRPLANE_MODE_RADIOS);
595         return apmRadios == null || apmRadios.contains(SETTINGS_RADIO_UWB);
596     }
597 
598     /** Returns true if airplane mode is turned on. */
isAirplaneModeOn()599     private boolean isAirplaneModeOn() {
600         if (!isAirplaneModeSensitive()) return false;
601         return mUwbInjector.getGlobalSettingsInt(
602                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
603     }
604 
isSatelliteModeSensitive()605     private boolean isSatelliteModeSensitive() {
606         if (!SdkLevel.isAtLeastU()) return false; // satellite mode enabled only for Android U.
607         final String satelliteRadios =
608                 mUwbInjector.getGlobalSettingsString(SETTINGS_SATELLITE_MODE_RADIOS);
609         return satelliteRadios == null || satelliteRadios.contains(SETTINGS_RADIO_UWB);
610     }
611 
612     /** Returns true if satellite mode is turned on. */
isSatelliteModeOn()613     private boolean isSatelliteModeOn() {
614         if (!isSatelliteModeSensitive()) return false;
615         return mUwbInjector.getGlobalSettingsInt(
616                 SETTINGS_SATELLITE_MODE_ENABLED, 0) == 1;
617     }
618 
619     /** Returns true if UWB has user restriction set. */
isUwbUserRestricted()620     private boolean isUwbUserRestricted() {
621         if (!SdkLevel.isAtLeastU()) {
622             return false; // older platforms did not have a uwb user restriction.
623         }
624 
625         final long ident = Binder.clearCallingIdentity();
626         try {
627             return mUwbInjector.getUserManager().getUserRestrictions().getBoolean(
628                     UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO);
629         } finally {
630             Binder.restoreCallingIdentity(ident);
631         }
632     }
633 
634     /**
635      * Returns true if UWB is enabled - based on UWB, APM toggle, satellite mode and user
636      * restrictions.
637      */
isUwbEnabled()638     private boolean isUwbEnabled() {
639         return isUwbToggleEnabled() && !isAirplaneModeOn() && !isSatelliteModeOn()
640                 && !isUwbUserRestricted();
641     }
642 
registerAirplaneModeReceiver()643     private void registerAirplaneModeReceiver() {
644         if (isAirplaneModeSensitive()) {
645             mContext.registerReceiver(
646                     new BroadcastReceiver() {
647                         @Override
648                         public void onReceive(Context context, Intent intent) {
649                             Log.i(TAG, "Airplane mode change detected");
650                             mUwbInjector.getUwbCountryCode().clearCachedCountryCode();
651                             handleAirplaneOrSatelliteModeEvent();
652                         }
653                     },
654                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED),
655                     null,
656                     mUwbServiceCore.getHandler());
657         }
658     }
659 
registerSatelliteModeReceiver()660     private void registerSatelliteModeReceiver() {
661         Uri uri = Settings.Global.getUriFor(SETTINGS_SATELLITE_MODE_ENABLED);
662         if (uri == null) {
663             Log.e(TAG, "satellite mode key does not exist in Settings");
664             return;
665         }
666         mUwbInjector.registerContentObserver(
667                 uri,
668                 false,
669                 new ContentObserver(mUwbServiceCore.getHandler()) {
670                     @Override
671                     public void onChange(boolean selfChange) {
672                         if (isSatelliteModeSensitive()) {
673                             Log.i(TAG, "Satellite mode change detected");
674                             handleAirplaneOrSatelliteModeEvent();
675                         }
676                     }
677                 });
678     }
679 
registerUserRestrictionsReceiver()680     private void registerUserRestrictionsReceiver() {
681         mContext.registerReceiver(
682                 new BroadcastReceiver() {
683                     @Override
684                     public void onReceive(Context context, Intent intent) {
685                         onUserRestrictionsChanged();
686                     }
687                 },
688                 new IntentFilter(UserManager.ACTION_USER_RESTRICTIONS_CHANGED),
689                 null,
690                 mUwbServiceCore.getHandler());
691     }
692 
handleAirplaneOrSatelliteModeEvent()693     private void handleAirplaneOrSatelliteModeEvent() {
694         try {
695             mUwbServiceCore.setEnabled(isUwbEnabled());
696         } catch (Exception e) {
697             Log.e(TAG, "Unable to set UWB Adapter state.", e);
698         }
699     }
700 
validateChipId(String chipId)701     private String validateChipId(String chipId) {
702         if (chipId == null || chipId.isEmpty()) {
703             return getDefaultChipId();
704         }
705 
706         if (!getChipIds().contains(chipId)) {
707             throw new IllegalArgumentException("invalid chipId: " + chipId);
708         }
709 
710         return chipId;
711     }
712 
handleUserSwitch(int userId)713     public void handleUserSwitch(int userId) {
714         mUwbServiceCore.getHandler().post(() -> {
715             Log.d(TAG, "Handle user switch " + userId);
716             mUwbInjector.getUwbConfigStore().handleUserSwitch(userId);
717         });
718     }
719 
handleUserUnlock(int userId)720     public void handleUserUnlock(int userId) {
721         mUwbServiceCore.getHandler().post(() -> {
722             Log.d(TAG, "Handle user unlock " + userId);
723             mUwbInjector.getUwbConfigStore().handleUserUnlock(userId);
724         });
725     }
726 
727     @Override
getUwbActivityEnergyInfoAsync( IOnUwbActivityEnergyInfoListener listener)728     public synchronized void getUwbActivityEnergyInfoAsync(
729             IOnUwbActivityEnergyInfoListener listener) throws RemoteException {
730         Log.i(TAG, "getUwbActivityEnergyInfoAsync uid=" + Binder.getCallingUid());
731         enforceUwbPrivilegedPermission();
732         mUwbServiceCore.reportUwbActivityEnergyInfo(listener);
733     }
734 
735 }
736