1 /* 2 * Copyright (C) 2017 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 18 package com.android.server.companion; 19 20 import static android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES; 21 import static android.Manifest.permission.BLUETOOTH_CONNECT; 22 import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES; 23 import static android.Manifest.permission.MANAGE_COMPANION_DEVICES; 24 import static android.Manifest.permission.REQUEST_COMPANION_SELF_MANAGED; 25 import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE; 26 import static android.Manifest.permission.USE_COMPANION_TRANSPORTS; 27 import static android.content.pm.PackageManager.CERT_INPUT_SHA256; 28 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 29 import static android.os.Process.SYSTEM_UID; 30 import static android.os.UserHandle.getCallingUserId; 31 32 import static com.android.internal.util.CollectionUtils.any; 33 import static com.android.internal.util.Preconditions.checkState; 34 import static com.android.server.companion.association.DisassociationProcessor.REASON_API; 35 import static com.android.server.companion.association.DisassociationProcessor.REASON_PKG_DATA_CLEARED; 36 import static com.android.server.companion.utils.PackageUtils.enforceUsesCompanionDeviceFeature; 37 import static com.android.server.companion.utils.PackageUtils.isRestrictedSettingsAllowed; 38 import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage; 39 import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOr; 40 import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId; 41 42 import static java.util.Objects.requireNonNull; 43 44 import android.annotation.EnforcePermission; 45 import android.annotation.NonNull; 46 import android.annotation.Nullable; 47 import android.annotation.SuppressLint; 48 import android.annotation.UserIdInt; 49 import android.app.ActivityManager; 50 import android.app.ActivityManagerInternal; 51 import android.app.AppOpsManager; 52 import android.app.KeyguardManager; 53 import android.app.NotificationManager; 54 import android.app.PendingIntent; 55 import android.app.ecm.EnhancedConfirmationManager; 56 import android.bluetooth.BluetoothAdapter; 57 import android.bluetooth.BluetoothDevice; 58 import android.bluetooth.BluetoothManager; 59 import android.companion.AssociationInfo; 60 import android.companion.AssociationRequest; 61 import android.companion.DeviceId; 62 import android.companion.IAssociationRequestCallback; 63 import android.companion.ICompanionDeviceManager; 64 import android.companion.IOnAssociationsChangedListener; 65 import android.companion.IOnMessageReceivedListener; 66 import android.companion.IOnTransportsChangedListener; 67 import android.companion.ISystemDataTransferCallback; 68 import android.companion.ObservingDevicePresenceRequest; 69 import android.companion.datatransfer.PermissionSyncRequest; 70 import android.content.ComponentName; 71 import android.content.Context; 72 import android.content.Intent; 73 import android.content.pm.PackageManagerInternal; 74 import android.net.MacAddress; 75 import android.os.Binder; 76 import android.os.Parcel; 77 import android.os.ParcelFileDescriptor; 78 import android.os.PowerExemptionManager; 79 import android.os.PowerManagerInternal; 80 import android.os.RemoteException; 81 import android.os.UserHandle; 82 import android.os.UserManager; 83 import android.permission.flags.Flags; 84 import android.util.ExceptionUtils; 85 import android.util.Slog; 86 87 import com.android.internal.content.PackageMonitor; 88 import com.android.internal.notification.NotificationAccessConfirmationActivityContract; 89 import com.android.internal.util.ArrayUtils; 90 import com.android.internal.util.DumpUtils; 91 import com.android.server.FgThread; 92 import com.android.server.LocalServices; 93 import com.android.server.SystemService; 94 import com.android.server.companion.association.AssociationDiskStore; 95 import com.android.server.companion.association.AssociationRequestsProcessor; 96 import com.android.server.companion.association.AssociationStore; 97 import com.android.server.companion.association.DisassociationProcessor; 98 import com.android.server.companion.association.InactiveAssociationsRemovalService; 99 import com.android.server.companion.datatransfer.SystemDataTransferProcessor; 100 import com.android.server.companion.datatransfer.SystemDataTransferRequestStore; 101 import com.android.server.companion.datatransfer.contextsync.CrossDeviceCall; 102 import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController; 103 import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncControllerCallback; 104 import com.android.server.companion.devicepresence.CompanionAppBinder; 105 import com.android.server.companion.devicepresence.DevicePresenceProcessor; 106 import com.android.server.companion.devicepresence.ObservableUuid; 107 import com.android.server.companion.devicepresence.ObservableUuidStore; 108 import com.android.server.companion.transport.CompanionTransportManager; 109 import com.android.server.wm.ActivityTaskManagerInternal; 110 111 import java.io.FileDescriptor; 112 import java.io.PrintWriter; 113 import java.util.Collection; 114 import java.util.List; 115 import java.util.concurrent.ExecutorService; 116 import java.util.concurrent.Executors; 117 118 @SuppressLint("LongLogTag") 119 public class CompanionDeviceManagerService extends SystemService { 120 private static final String TAG = "CDM_CompanionDeviceManagerService"; 121 122 private static final long PAIR_WITHOUT_PROMPT_WINDOW_MS = 10 * 60 * 1000; // 10 min 123 private static final int MAX_CN_LENGTH = 500; 124 125 private final AssociationStore mAssociationStore; 126 private final SystemDataTransferRequestStore mSystemDataTransferRequestStore; 127 private final ObservableUuidStore mObservableUuidStore; 128 129 private final CompanionExemptionProcessor mCompanionExemptionProcessor; 130 private final AssociationRequestsProcessor mAssociationRequestsProcessor; 131 private final SystemDataTransferProcessor mSystemDataTransferProcessor; 132 private final BackupRestoreProcessor mBackupRestoreProcessor; 133 private final DevicePresenceProcessor mDevicePresenceProcessor; 134 private final CompanionAppBinder mCompanionAppBinder; 135 private final CompanionTransportManager mTransportManager; 136 private final DisassociationProcessor mDisassociationProcessor; 137 private final CrossDeviceSyncController mCrossDeviceSyncController; 138 CompanionDeviceManagerService(Context context)139 public CompanionDeviceManagerService(Context context) { 140 super(context); 141 142 final ActivityManager activityManager = context.getSystemService(ActivityManager.class); 143 final PowerExemptionManager powerExemptionManager = context.getSystemService( 144 PowerExemptionManager.class); 145 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 146 final ActivityTaskManagerInternal atmInternal = LocalServices.getService( 147 ActivityTaskManagerInternal.class); 148 final ActivityManagerInternal amInternal = LocalServices.getService( 149 ActivityManagerInternal.class); 150 final PackageManagerInternal packageManagerInternal = LocalServices.getService( 151 PackageManagerInternal.class); 152 final UserManager userManager = context.getSystemService(UserManager.class); 153 final PowerManagerInternal powerManagerInternal = LocalServices.getService( 154 PowerManagerInternal.class); 155 156 final AssociationDiskStore associationDiskStore = new AssociationDiskStore(); 157 mAssociationStore = new AssociationStore(context, userManager, associationDiskStore); 158 mSystemDataTransferRequestStore = new SystemDataTransferRequestStore(); 159 mObservableUuidStore = new ObservableUuidStore(); 160 161 // Init processors 162 mAssociationRequestsProcessor = new AssociationRequestsProcessor(context, 163 packageManagerInternal, mAssociationStore); 164 mBackupRestoreProcessor = new BackupRestoreProcessor(context, packageManagerInternal, 165 mAssociationStore, associationDiskStore, mSystemDataTransferRequestStore, 166 mAssociationRequestsProcessor); 167 168 mCompanionAppBinder = new CompanionAppBinder(context); 169 170 mCompanionExemptionProcessor = new CompanionExemptionProcessor(context, 171 powerExemptionManager, appOpsManager, packageManagerInternal, atmInternal, 172 amInternal, mAssociationStore); 173 174 mDevicePresenceProcessor = new DevicePresenceProcessor(context, 175 mCompanionAppBinder, userManager, mAssociationStore, mObservableUuidStore, 176 powerManagerInternal, mCompanionExemptionProcessor); 177 178 mTransportManager = new CompanionTransportManager(context, mAssociationStore); 179 180 mDisassociationProcessor = new DisassociationProcessor(context, activityManager, 181 mAssociationStore, packageManagerInternal, mDevicePresenceProcessor, 182 mCompanionAppBinder, mSystemDataTransferRequestStore, mTransportManager); 183 184 mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, 185 packageManagerInternal, mAssociationStore, 186 mSystemDataTransferRequestStore, mTransportManager); 187 188 // TODO(b/279663946): move context sync to a dedicated system service 189 mCrossDeviceSyncController = new CrossDeviceSyncController(getContext(), mTransportManager); 190 } 191 192 @Override onStart()193 public void onStart() { 194 // Init association stores 195 mAssociationStore.refreshCache(); 196 197 // Init UUID store 198 mObservableUuidStore.getObservableUuidsForUser(getContext().getUserId()); 199 200 // Publish "binder" service. 201 final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl(); 202 publishBinderService(Context.COMPANION_DEVICE_SERVICE, impl); 203 204 // Publish "local" service. 205 LocalServices.addService(CompanionDeviceManagerServiceInternal.class, new LocalService()); 206 } 207 208 @Override onBootPhase(int phase)209 public void onBootPhase(int phase) { 210 final Context context = getContext(); 211 if (phase == PHASE_SYSTEM_SERVICES_READY) { 212 // WARNING: moving PackageMonitor to another thread (Looper) may introduce significant 213 // delays (even in case of the Main Thread). It may be fine overall, but would require 214 // updating the tests (adding a delay there). 215 mPackageMonitor.register(context, FgThread.get().getLooper(), UserHandle.ALL, true); 216 } else if (phase == PHASE_BOOT_COMPLETED) { 217 mDevicePresenceProcessor.init(context); 218 // Run the Inactive Association Removal job service daily. 219 InactiveAssociationsRemovalService.schedule(getContext()); 220 mCrossDeviceSyncController.onBootCompleted(); 221 } 222 } 223 224 @Override onUserUnlocking(@onNull TargetUser user)225 public void onUserUnlocking(@NonNull TargetUser user) { 226 Slog.d(TAG, "onUserUnlocking..."); 227 final int userId = user.getUserIdentifier(); 228 final List<AssociationInfo> associations = mAssociationStore.getActiveAssociationsByUser( 229 userId); 230 231 if (associations.isEmpty()) return; 232 233 mCompanionExemptionProcessor.updateAtm(userId, associations); 234 ExecutorService executor = Executors.newSingleThreadExecutor(); 235 executor.execute(mCompanionExemptionProcessor::updateAutoRevokeExemptions); 236 } 237 238 @Override onUserUnlocked(@onNull TargetUser user)239 public void onUserUnlocked(@NonNull TargetUser user) { 240 Slog.i(TAG, "onUserUnlocked() user=" + user); 241 // Notify and bind the app after the phone is unlocked. 242 mDevicePresenceProcessor.sendDevicePresenceEventOnUnlocked(user.getUserIdentifier()); 243 } 244 onPackageRemoveOrDataClearedInternal( @serIdInt int userId, @NonNull String packageName)245 private void onPackageRemoveOrDataClearedInternal( 246 @UserIdInt int userId, @NonNull String packageName) { 247 // Clear all associations for the package. 248 final List<AssociationInfo> associationsForPackage = 249 mAssociationStore.getAssociationsByPackage(userId, packageName); 250 if (!associationsForPackage.isEmpty()) { 251 Slog.i(TAG, "Package removed or data cleared for user=[" + userId + "], package=[" 252 + packageName + "]. Cleaning up CDM data..."); 253 254 for (AssociationInfo association : associationsForPackage) { 255 mDisassociationProcessor.disassociate(association.getId(), REASON_PKG_DATA_CLEARED); 256 } 257 258 mCompanionAppBinder.onPackageChanged(userId); 259 } 260 261 // Clear observable UUIDs for the package. 262 final List<ObservableUuid> uuidsTobeObserved = 263 mObservableUuidStore.getObservableUuidsForPackage(userId, packageName); 264 for (ObservableUuid uuid : uuidsTobeObserved) { 265 mObservableUuidStore.removeObservableUuid(userId, uuid.getUuid(), packageName); 266 } 267 } 268 onPackageModifiedInternal(@serIdInt int userId, @NonNull String packageName)269 private void onPackageModifiedInternal(@UserIdInt int userId, @NonNull String packageName) { 270 final List<AssociationInfo> associations = 271 mAssociationStore.getAssociationsByPackage(userId, packageName); 272 if (!associations.isEmpty()) { 273 mCompanionExemptionProcessor.exemptPackage(userId, packageName, false); 274 275 mCompanionAppBinder.onPackageChanged(userId); 276 } 277 } 278 onPackageAddedInternal(@serIdInt int userId, @NonNull String packageName)279 private void onPackageAddedInternal(@UserIdInt int userId, @NonNull String packageName) { 280 mBackupRestoreProcessor.restorePendingAssociations(userId, packageName); 281 } 282 removeInactiveSelfManagedAssociations()283 void removeInactiveSelfManagedAssociations() { 284 mDisassociationProcessor.removeIdleSelfManagedAssociations(); 285 } 286 287 public class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub { 288 @Override onTransact(int code, Parcel data, Parcel reply, int flags)289 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 290 throws RemoteException { 291 try { 292 return super.onTransact(code, data, reply, flags); 293 } catch (Throwable e) { 294 Slog.e(TAG, "Error during IPC", e); 295 throw ExceptionUtils.propagate(e, RemoteException.class); 296 } 297 } 298 299 @Override associate(AssociationRequest request, IAssociationRequestCallback callback, String packageName, int userId)300 public void associate(AssociationRequest request, IAssociationRequestCallback callback, 301 String packageName, int userId) throws RemoteException { 302 Slog.i(TAG, "associate() " 303 + "request=" + request + ", " 304 + "package=u" + userId + "/" + packageName); 305 enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName, 306 "create associations"); 307 308 if (request.isSkipRoleGrant()) { 309 checkCallerCanSkipRoleGrant(); 310 mAssociationRequestsProcessor.createAssociation(userId, packageName, 311 /* macAddress= */ null, request.getDisplayName(), 312 request.getDeviceProfile(), /* associatedDevice= */ null, 313 request.isSelfManaged(), callback, /* resultReceiver= */ null, 314 request.getDeviceIcon(), /* skipRoleGrant= */ true); 315 } else { 316 mAssociationRequestsProcessor.processNewAssociationRequest( 317 request, packageName, userId, callback); 318 } 319 } 320 321 @Override buildAssociationCancellationIntent(String packageName, int userId)322 public PendingIntent buildAssociationCancellationIntent(String packageName, 323 int userId) throws RemoteException { 324 Slog.i(TAG, "buildAssociationCancellationIntent() " 325 + "package=u" + userId + "/" + packageName); 326 enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName, 327 "build association cancellation intent"); 328 329 return mAssociationRequestsProcessor.buildAssociationCancellationIntent( 330 packageName, userId); 331 } 332 333 @Override getAssociations(String packageName, int userId)334 public List<AssociationInfo> getAssociations(String packageName, int userId) { 335 enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName, 336 "get associations"); 337 return mAssociationStore.getActiveAssociationsByPackage(userId, packageName); 338 } 339 340 @Override 341 @EnforcePermission(MANAGE_COMPANION_DEVICES) getAllAssociationsForUser(int userId)342 public List<AssociationInfo> getAllAssociationsForUser(int userId) throws RemoteException { 343 getAllAssociationsForUser_enforcePermission(); 344 345 enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId); 346 347 if (userId == UserHandle.USER_ALL) { 348 return mAssociationStore.getActiveAssociations(); 349 } 350 return mAssociationStore.getActiveAssociationsByUser(userId); 351 } 352 353 @Override 354 @EnforcePermission(MANAGE_COMPANION_DEVICES) addOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId)355 public void addOnAssociationsChangedListener(IOnAssociationsChangedListener listener, 356 int userId) { 357 addOnAssociationsChangedListener_enforcePermission(); 358 359 enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId); 360 361 mAssociationStore.registerRemoteListener(listener, userId); 362 } 363 364 @Override 365 @EnforcePermission(MANAGE_COMPANION_DEVICES) removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId)366 public void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, 367 int userId) { 368 removeOnAssociationsChangedListener_enforcePermission(); 369 370 enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId); 371 372 mAssociationStore.unregisterRemoteListener(listener); 373 } 374 375 @Override 376 @EnforcePermission(USE_COMPANION_TRANSPORTS) addOnTransportsChangedListener(IOnTransportsChangedListener listener)377 public void addOnTransportsChangedListener(IOnTransportsChangedListener listener) { 378 addOnTransportsChangedListener_enforcePermission(); 379 380 mTransportManager.addListener(listener); 381 } 382 383 @Override 384 @EnforcePermission(USE_COMPANION_TRANSPORTS) removeOnTransportsChangedListener(IOnTransportsChangedListener listener)385 public void removeOnTransportsChangedListener(IOnTransportsChangedListener listener) { 386 removeOnTransportsChangedListener_enforcePermission(); 387 388 mTransportManager.removeListener(listener); 389 } 390 391 @Override 392 @EnforcePermission(USE_COMPANION_TRANSPORTS) sendMessage(int messageType, byte[] data, int[] associationIds)393 public void sendMessage(int messageType, byte[] data, int[] associationIds) { 394 sendMessage_enforcePermission(); 395 396 mTransportManager.sendMessage(messageType, data, associationIds); 397 } 398 399 @Override 400 @EnforcePermission(USE_COMPANION_TRANSPORTS) addOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener)401 public void addOnMessageReceivedListener(int messageType, 402 IOnMessageReceivedListener listener) { 403 addOnMessageReceivedListener_enforcePermission(); 404 405 mTransportManager.addListener(messageType, listener); 406 } 407 408 @Override 409 @EnforcePermission(USE_COMPANION_TRANSPORTS) removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener)410 public void removeOnMessageReceivedListener(int messageType, 411 IOnMessageReceivedListener listener) { 412 removeOnMessageReceivedListener_enforcePermission(); 413 414 mTransportManager.removeListener(messageType, listener); 415 } 416 417 /** 418 * @deprecated use {@link #disassociate(int)} instead 419 */ 420 @Deprecated 421 @Override legacyDisassociate(String deviceMacAddress, String packageName, int userId)422 public void legacyDisassociate(String deviceMacAddress, String packageName, int userId) { 423 requireNonNull(deviceMacAddress); 424 requireNonNull(packageName); 425 426 mDisassociationProcessor.disassociate(userId, packageName, deviceMacAddress); 427 } 428 429 @Override disassociate(int associationId)430 public void disassociate(int associationId) { 431 mDisassociationProcessor.disassociate(associationId, REASON_API); 432 } 433 434 @Override requestNotificationAccess(ComponentName component, int userId)435 public PendingIntent requestNotificationAccess(ComponentName component, int userId) 436 throws RemoteException { 437 int callingUid = getCallingUid(); 438 final String callingPackage = component.getPackageName(); 439 440 checkCanCallNotificationApi(callingPackage, userId); 441 442 if (component.flattenToString().length() > MAX_CN_LENGTH) { 443 throw new IllegalArgumentException("Component name is too long."); 444 } 445 446 return Binder.withCleanCallingIdentity(() -> { 447 final Intent intent; 448 if (!isRestrictedSettingsAllowed(getContext(), callingPackage, callingUid)) { 449 Slog.e(TAG, "Side loaded app must enable restricted " 450 + "setting before request the notification access"); 451 if (Flags.enhancedConfirmationModeApisEnabled()) { 452 intent = getContext() 453 .getSystemService(EnhancedConfirmationManager.class) 454 .createRestrictedSettingDialogIntent(callingPackage, 455 AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS); 456 } else { 457 return null; 458 } 459 } else { 460 intent = NotificationAccessConfirmationActivityContract.launcherIntent( 461 getContext(), userId, component); 462 } 463 464 return PendingIntent.getActivityAsUser(getContext(), 465 0 /* request code */, 466 intent, 467 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT 468 | PendingIntent.FLAG_CANCEL_CURRENT, 469 null /* options */, 470 new UserHandle(userId)); 471 }); 472 } 473 474 /** 475 * @deprecated Use 476 * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead. 477 */ 478 @Deprecated 479 @Override hasNotificationAccess(ComponentName component)480 public boolean hasNotificationAccess(ComponentName component) throws RemoteException { 481 checkCanCallNotificationApi(component.getPackageName(), getCallingUserId()); 482 NotificationManager nm = getContext().getSystemService(NotificationManager.class); 483 return nm.isNotificationListenerAccessGranted(component); 484 } 485 486 @Override 487 @EnforcePermission(MANAGE_COMPANION_DEVICES) isDeviceAssociatedForWifiConnection(String packageName, String macAddress, int userId)488 public boolean isDeviceAssociatedForWifiConnection(String packageName, String macAddress, 489 int userId) { 490 isDeviceAssociatedForWifiConnection_enforcePermission(); 491 492 boolean bypassMacPermission = getContext().getPackageManager().checkPermission( 493 android.Manifest.permission.COMPANION_APPROVE_WIFI_CONNECTIONS, packageName) 494 == PERMISSION_GRANTED; 495 if (bypassMacPermission) { 496 return true; 497 } 498 499 return any(mAssociationStore.getActiveAssociationsByPackage(userId, packageName), 500 a -> a.isLinkedTo(macAddress)); 501 } 502 503 @Override 504 @Deprecated 505 @EnforcePermission(REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) legacyStartObservingDevicePresence(String deviceAddress, String callingPackage, int userId)506 public void legacyStartObservingDevicePresence(String deviceAddress, String callingPackage, 507 int userId) throws RemoteException { 508 legacyStartObservingDevicePresence_enforcePermission(); 509 510 mDevicePresenceProcessor.startObservingDevicePresence(userId, callingPackage, 511 deviceAddress); 512 } 513 514 @Override 515 @Deprecated 516 @EnforcePermission(REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) legacyStopObservingDevicePresence(String deviceAddress, String callingPackage, int userId)517 public void legacyStopObservingDevicePresence(String deviceAddress, String callingPackage, 518 int userId) throws RemoteException { 519 legacyStopObservingDevicePresence_enforcePermission(); 520 521 mDevicePresenceProcessor.stopObservingDevicePresence(userId, callingPackage, 522 deviceAddress); 523 } 524 525 @Override 526 @EnforcePermission(REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) startObservingDevicePresence(ObservingDevicePresenceRequest request, String packageName, int userId)527 public void startObservingDevicePresence(ObservingDevicePresenceRequest request, 528 String packageName, int userId) { 529 startObservingDevicePresence_enforcePermission(); 530 531 mDevicePresenceProcessor.startObservingDevicePresence( 532 request, packageName, userId, /* enforcePermissions */ true); 533 } 534 535 @Override 536 @EnforcePermission(REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) stopObservingDevicePresence(ObservingDevicePresenceRequest request, String packageName, int userId)537 public void stopObservingDevicePresence(ObservingDevicePresenceRequest request, 538 String packageName, int userId) { 539 stopObservingDevicePresence_enforcePermission(); 540 541 mDevicePresenceProcessor.stopObservingDevicePresence( 542 request, packageName, userId, /* enforcePermissions */ true); 543 } 544 545 @Override 546 @EnforcePermission(BLUETOOTH_CONNECT) removeBond(int associationId, String packageName, int userId)547 public boolean removeBond(int associationId, String packageName, int userId) { 548 removeBond_enforcePermission(); 549 550 Slog.i(TAG, "removeBond() " 551 + "associationId=" + associationId + ", " 552 + "package=u" + userId + "/" + packageName); 553 enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName, 554 "remove bonds"); 555 556 AssociationInfo association = mAssociationStore 557 .getAssociationWithCallerChecks(associationId); 558 MacAddress address = association.getDeviceMacAddress(); 559 if (address == null) { 560 throw new IllegalArgumentException( 561 "Association id=[" + associationId + "] doesn't have a device address."); 562 } 563 564 BluetoothAdapter btAdapter = getContext().getSystemService(BluetoothManager.class) 565 .getAdapter(); 566 BluetoothDevice btDevice = btAdapter.getRemoteDevice(address.toString().toUpperCase()); 567 return btDevice.removeBond(); 568 } 569 570 @Override buildPermissionTransferUserConsentIntent(String packageName, int userId, int associationId)571 public PendingIntent buildPermissionTransferUserConsentIntent(String packageName, 572 int userId, int associationId) { 573 return mSystemDataTransferProcessor.buildPermissionTransferUserConsentIntent( 574 packageName, userId, associationId); 575 } 576 577 @Override isPermissionTransferUserConsented(String packageName, int userId, int associationId)578 public boolean isPermissionTransferUserConsented(String packageName, int userId, 579 int associationId) { 580 return mSystemDataTransferProcessor.isPermissionTransferUserConsented(associationId); 581 } 582 583 @Override startSystemDataTransfer(String packageName, int userId, int associationId, ISystemDataTransferCallback callback)584 public void startSystemDataTransfer(String packageName, int userId, int associationId, 585 ISystemDataTransferCallback callback) { 586 mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId, 587 associationId, callback); 588 } 589 590 @Override 591 @EnforcePermission(DELIVER_COMPANION_MESSAGES) attachSystemDataTransport(String packageName, int userId, int associationId, ParcelFileDescriptor fd, int flags)592 public void attachSystemDataTransport(String packageName, int userId, int associationId, 593 ParcelFileDescriptor fd, int flags) { 594 attachSystemDataTransport_enforcePermission(); 595 596 mTransportManager.attachSystemDataTransport(associationId, fd, flags); 597 } 598 599 @Override 600 @EnforcePermission(DELIVER_COMPANION_MESSAGES) detachSystemDataTransport(String packageName, int userId, int associationId)601 public void detachSystemDataTransport(String packageName, int userId, int associationId) { 602 detachSystemDataTransport_enforcePermission(); 603 604 mTransportManager.detachSystemDataTransport(associationId); 605 } 606 607 @Override 608 @EnforcePermission(MANAGE_COMPANION_DEVICES) enableSecureTransport(boolean enabled)609 public void enableSecureTransport(boolean enabled) { 610 enableSecureTransport_enforcePermission(); 611 612 mTransportManager.enableSecureTransport(enabled); 613 } 614 615 @Override enableSystemDataSync(int associationId, int flags)616 public void enableSystemDataSync(int associationId, int flags) { 617 mAssociationRequestsProcessor.enableSystemDataSync(associationId, flags); 618 } 619 620 @Override disableSystemDataSync(int associationId, int flags)621 public void disableSystemDataSync(int associationId, int flags) { 622 mAssociationRequestsProcessor.disableSystemDataSync(associationId, flags); 623 } 624 625 @Override enablePermissionsSync(int associationId)626 public void enablePermissionsSync(int associationId) { 627 if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { 628 throw new SecurityException("Caller must be system UID"); 629 } 630 mSystemDataTransferProcessor.enablePermissionsSync(associationId); 631 } 632 633 @Override disablePermissionsSync(int associationId)634 public void disablePermissionsSync(int associationId) { 635 if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { 636 throw new SecurityException("Caller must be system UID"); 637 } 638 mSystemDataTransferProcessor.disablePermissionsSync(associationId); 639 } 640 641 @Override getPermissionSyncRequest(int associationId)642 public PermissionSyncRequest getPermissionSyncRequest(int associationId) { 643 if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { 644 throw new SecurityException("Caller must be system UID"); 645 } 646 return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); 647 } 648 649 @Override 650 @EnforcePermission(REQUEST_COMPANION_SELF_MANAGED) notifySelfManagedDeviceAppeared(int associationId)651 public void notifySelfManagedDeviceAppeared(int associationId) { 652 notifySelfManagedDeviceAppeared_enforcePermission(); 653 654 mDevicePresenceProcessor.notifySelfManagedDevicePresenceEvent(associationId, true); 655 } 656 657 @Override 658 @EnforcePermission(REQUEST_COMPANION_SELF_MANAGED) notifySelfManagedDeviceDisappeared(int associationId)659 public void notifySelfManagedDeviceDisappeared(int associationId) { 660 notifySelfManagedDeviceDisappeared_enforcePermission(); 661 662 mDevicePresenceProcessor.notifySelfManagedDevicePresenceEvent(associationId, false); 663 } 664 665 @Override isCompanionApplicationBound(String packageName, int userId)666 public boolean isCompanionApplicationBound(String packageName, int userId) { 667 return mCompanionAppBinder.isCompanionApplicationBound(userId, packageName); 668 } 669 670 @Override 671 @EnforcePermission(ASSOCIATE_COMPANION_DEVICES) createAssociation(String packageName, String macAddress, int userId, byte[] certificate)672 public void createAssociation(String packageName, String macAddress, int userId, 673 byte[] certificate) { 674 createAssociation_enforcePermission(); 675 676 if (!getContext().getPackageManager().hasSigningCertificate( 677 packageName, certificate, CERT_INPUT_SHA256)) { 678 Slog.e(TAG, "Given certificate doesn't match the package certificate."); 679 return; 680 } 681 682 final MacAddress macAddressObj = MacAddress.fromString(macAddress); 683 mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddressObj, 684 null, null, null, false, null, null, null, false); 685 } 686 checkCanCallNotificationApi(String callingPackage, int userId)687 private void checkCanCallNotificationApi(String callingPackage, int userId) { 688 enforceCallerIsSystemOr(userId, callingPackage); 689 690 if (getCallingUid() == SYSTEM_UID) return; 691 692 enforceUsesCompanionDeviceFeature(getContext(), userId, callingPackage); 693 checkState(!ArrayUtils.isEmpty( 694 mAssociationStore.getActiveAssociationsByPackage(userId, 695 callingPackage)), 696 "App must have an association before calling this API"); 697 } 698 checkCallerCanSkipRoleGrant()699 private void checkCallerCanSkipRoleGrant() { 700 final Context context = 701 getContext().createContextAsUser(Binder.getCallingUserHandle(), 0); 702 final KeyguardManager keyguardManager = 703 context.getSystemService(KeyguardManager.class); 704 if (keyguardManager != null && keyguardManager.isKeyguardSecure()) { 705 throw new SecurityException("Skipping CDM role grant requires insecure keyguard."); 706 } 707 if (getContext().checkCallingPermission(ASSOCIATE_COMPANION_DEVICES) 708 != PERMISSION_GRANTED) { 709 throw new SecurityException( 710 "Skipping CDM role grant requires ASSOCIATE_COMPANION_DEVICES permission."); 711 } 712 } 713 714 @Override canPairWithoutPrompt(String packageName, String macAddress, int userId)715 public boolean canPairWithoutPrompt(String packageName, String macAddress, int userId) { 716 final AssociationInfo association = 717 mAssociationStore.getFirstAssociationByAddress( 718 userId, packageName, macAddress); 719 if (association == null) { 720 return false; 721 } 722 return System.currentTimeMillis() - association.getTimeApprovedMs() 723 < PAIR_WITHOUT_PROMPT_WINDOW_MS; 724 } 725 726 @Override setDeviceId(int associationId, DeviceId deviceId)727 public void setDeviceId(int associationId, DeviceId deviceId) { 728 mAssociationRequestsProcessor.setDeviceId(associationId, deviceId); 729 } 730 731 732 @Override getBackupPayload(int userId)733 public byte[] getBackupPayload(int userId) { 734 if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { 735 throw new SecurityException("Caller must be system"); 736 } 737 return mBackupRestoreProcessor.getBackupPayload(userId); 738 } 739 740 @Override applyRestoredPayload(byte[] payload, int userId)741 public void applyRestoredPayload(byte[] payload, int userId) { 742 if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { 743 throw new SecurityException("Caller must be system"); 744 } 745 mBackupRestoreProcessor.applyRestoredPayload(payload, userId); 746 } 747 748 @Override handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)749 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 750 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 751 @NonNull String[] args) { 752 return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, 753 mAssociationStore, mDevicePresenceProcessor, mTransportManager, 754 mSystemDataTransferProcessor, mAssociationRequestsProcessor, 755 mBackupRestoreProcessor, mDisassociationProcessor) 756 .exec(this, in.getFileDescriptor(), out.getFileDescriptor(), 757 err.getFileDescriptor(), args); 758 } 759 760 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter out, @Nullable String[] args)761 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter out, 762 @Nullable String[] args) { 763 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, out)) { 764 return; 765 } 766 767 mAssociationStore.dump(out); 768 mDevicePresenceProcessor.dump(out); 769 mCompanionAppBinder.dump(out); 770 mTransportManager.dump(out); 771 mSystemDataTransferRequestStore.dump(out); 772 } 773 } 774 775 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 776 @Override 777 public void onPackageRemoved(String packageName, int uid) { 778 onPackageRemoveOrDataClearedInternal(getChangingUserId(), packageName); 779 } 780 781 @Override 782 public void onPackageDataCleared(String packageName, int uid) { 783 onPackageRemoveOrDataClearedInternal(getChangingUserId(), packageName); 784 } 785 786 @Override 787 public void onPackageModified(@NonNull String packageName) { 788 onPackageModifiedInternal(getChangingUserId(), packageName); 789 } 790 791 @Override 792 public void onPackageAdded(String packageName, int uid) { 793 onPackageAddedInternal(getChangingUserId(), packageName); 794 } 795 }; 796 797 private class LocalService implements CompanionDeviceManagerServiceInternal { 798 799 @Override removeInactiveSelfManagedAssociations()800 public void removeInactiveSelfManagedAssociations() { 801 mDisassociationProcessor.removeIdleSelfManagedAssociations(); 802 } 803 804 @Override registerCallMetadataSyncCallback(CrossDeviceSyncControllerCallback callback, @CrossDeviceSyncControllerCallback.Type int type)805 public void registerCallMetadataSyncCallback(CrossDeviceSyncControllerCallback callback, 806 @CrossDeviceSyncControllerCallback.Type int type) { 807 if (CompanionDeviceConfig.isEnabled( 808 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 809 mCrossDeviceSyncController.registerCallMetadataSyncCallback(callback, type); 810 } 811 } 812 813 @Override crossDeviceSync(int userId, Collection<CrossDeviceCall> calls)814 public void crossDeviceSync(int userId, Collection<CrossDeviceCall> calls) { 815 if (CompanionDeviceConfig.isEnabled( 816 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 817 mCrossDeviceSyncController.syncToAllDevicesForUserId(userId, calls); 818 } 819 } 820 821 @Override crossDeviceSync(AssociationInfo associationInfo, Collection<CrossDeviceCall> calls)822 public void crossDeviceSync(AssociationInfo associationInfo, 823 Collection<CrossDeviceCall> calls) { 824 if (CompanionDeviceConfig.isEnabled( 825 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 826 mCrossDeviceSyncController.syncToSingleDevice(associationInfo, calls); 827 } 828 } 829 830 @Override sendCrossDeviceSyncMessage(int associationId, byte[] message)831 public void sendCrossDeviceSyncMessage(int associationId, byte[] message) { 832 if (CompanionDeviceConfig.isEnabled( 833 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 834 mCrossDeviceSyncController.syncMessageToDevice(associationId, message); 835 } 836 } 837 838 @Override sendCrossDeviceSyncMessageToAllDevices(int userId, byte[] message)839 public void sendCrossDeviceSyncMessageToAllDevices(int userId, byte[] message) { 840 if (CompanionDeviceConfig.isEnabled( 841 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 842 mCrossDeviceSyncController.syncMessageToAllDevicesForUserId(userId, message); 843 } 844 } 845 846 @Override addSelfOwnedCallId(String callId)847 public void addSelfOwnedCallId(String callId) { 848 if (CompanionDeviceConfig.isEnabled( 849 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 850 mCrossDeviceSyncController.addSelfOwnedCallId(callId); 851 } 852 } 853 854 @Override removeSelfOwnedCallId(String callId)855 public void removeSelfOwnedCallId(String callId) { 856 if (CompanionDeviceConfig.isEnabled( 857 CompanionDeviceConfig.ENABLE_CONTEXT_SYNC_TELECOM)) { 858 mCrossDeviceSyncController.removeSelfOwnedCallId(callId); 859 } 860 } 861 } 862 } 863