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