• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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