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