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