1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.contentcapture;
18 
19 import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
20 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
21 import static android.service.contentcapture.ContentCaptureService.ASSIST_CONTENT_ACTIVITY_START_KEY;
22 import static android.service.contentcapture.ContentCaptureService.setClientState;
23 import static android.view.contentcapture.ContentCaptureHelper.toList;
24 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
25 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS;
26 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT;
27 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE;
28 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG;
29 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
30 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
31 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER;
32 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT;
33 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
34 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
35 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
36 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_TRUE;
37 import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
38 
39 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ACCEPT_DATA_SHARE_REQUEST;
40 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL;
41 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CONCURRENT_REQUEST;
42 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_EMPTY_DATA;
43 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_IOEXCEPTION;
44 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL;
45 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED;
46 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_WRITE_FINISHED;
47 import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__REJECT_DATA_SHARE_REQUEST;
48 import static com.android.internal.util.SyncResultReceiver.bundleFor;
49 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
50 
51 import android.annotation.NonNull;
52 import android.annotation.Nullable;
53 import android.annotation.UserIdInt;
54 import android.app.ActivityManagerInternal;
55 import android.app.ActivityThread;
56 import android.app.admin.DevicePolicyCache;
57 import android.app.assist.ActivityId;
58 import android.app.assist.AssistContent;
59 import android.content.ComponentName;
60 import android.content.ContentCaptureOptions;
61 import android.content.ContentResolver;
62 import android.content.Context;
63 import android.content.Intent;
64 import android.content.pm.ActivityPresentationInfo;
65 import android.content.pm.PackageManager;
66 import android.content.pm.PackageManager.NameNotFoundException;
67 import android.content.pm.ParceledListSlice;
68 import android.content.pm.UserInfo;
69 import android.database.ContentObserver;
70 import android.os.Binder;
71 import android.os.Build;
72 import android.os.Bundle;
73 import android.os.Handler;
74 import android.os.IBinder;
75 import android.os.Looper;
76 import android.os.ParcelFileDescriptor;
77 import android.os.RemoteCallbackList;
78 import android.os.RemoteException;
79 import android.os.ResultReceiver;
80 import android.os.ShellCallback;
81 import android.os.UserHandle;
82 import android.os.UserManager;
83 import android.provider.DeviceConfig;
84 import android.provider.DeviceConfig.Properties;
85 import android.provider.Settings;
86 import android.service.contentcapture.ActivityEvent.ActivityEventType;
87 import android.service.contentcapture.ContentCaptureServiceInfo;
88 import android.service.contentcapture.IDataShareCallback;
89 import android.service.contentcapture.IDataShareReadAdapter;
90 import android.service.voice.VoiceInteractionManagerInternal;
91 import android.util.ArraySet;
92 import android.util.LocalLog;
93 import android.util.Pair;
94 import android.util.Slog;
95 import android.util.SparseArray;
96 import android.util.SparseBooleanArray;
97 import android.view.contentcapture.ContentCaptureCondition;
98 import android.view.contentcapture.ContentCaptureEvent;
99 import android.view.contentcapture.ContentCaptureHelper;
100 import android.view.contentcapture.ContentCaptureManager;
101 import android.view.contentcapture.DataRemovalRequest;
102 import android.view.contentcapture.DataShareRequest;
103 import android.view.contentcapture.IContentCaptureManager;
104 import android.view.contentcapture.IContentCaptureOptionsCallback;
105 import android.view.contentcapture.IDataShareWriteAdapter;
106 
107 import com.android.internal.annotations.GuardedBy;
108 import com.android.internal.annotations.VisibleForTesting;
109 import com.android.internal.infra.AbstractRemoteService;
110 import com.android.internal.infra.GlobalWhitelistState;
111 import com.android.internal.os.BackgroundThread;
112 import com.android.internal.os.IResultReceiver;
113 import com.android.internal.util.DumpUtils;
114 import com.android.server.LocalServices;
115 import com.android.server.contentprotection.ContentProtectionAllowlistManager;
116 import com.android.server.contentprotection.ContentProtectionConsentManager;
117 import com.android.server.contentprotection.RemoteContentProtectionService;
118 import com.android.server.infra.AbstractMasterSystemService;
119 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
120 
121 import java.io.FileDescriptor;
122 import java.io.IOException;
123 import java.io.InputStream;
124 import java.io.OutputStream;
125 import java.io.PrintWriter;
126 import java.util.ArrayList;
127 import java.util.Arrays;
128 import java.util.Collections;
129 import java.util.HashSet;
130 import java.util.List;
131 import java.util.Objects;
132 import java.util.Set;
133 import java.util.concurrent.Executor;
134 import java.util.concurrent.Executors;
135 import java.util.concurrent.atomic.AtomicBoolean;
136 
137 /**
138  * A service used to observe the contents of the screen.
139  *
140  * <p>The data collected by this service can be analyzed on-device and combined
141  * with other sources to provide contextual data in other areas of the system
142  * such as Autofill.
143  */
144 public class ContentCaptureManagerService extends
145         AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
146 
147     private static final String TAG = ContentCaptureManagerService.class.getSimpleName();
148     static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
149 
150     private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
151     private static final int MAX_DATA_SHARE_FILE_DESCRIPTORS_TTL_MS =  1_000 * 60 * 5; // 5 minutes
152     private static final int MAX_CONCURRENT_FILE_SHARING_REQUESTS = 10;
153     private static final int DATA_SHARE_BYTE_BUFFER_LENGTH = 1_024;
154 
155     private static final String CONTENT_PROTECTION_GROUP_CONFIG_SEPARATOR_GROUP = ";";
156     private static final String CONTENT_PROTECTION_GROUP_CONFIG_SEPARATOR_VALUE = ",";
157 
158     // Needed to pass checkstyle_hook as names are too long for one line.
159     private static final int EVENT__DATA_SHARE_ERROR_CONCURRENT_REQUEST =
160             CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CONCURRENT_REQUEST;
161     private static final int EVENT__DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED =
162             CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED;
163     private static final int EVENT__DATA_SHARE_WRITE_FINISHED =
164             CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_WRITE_FINISHED;
165 
166     private final LocalService mLocalService = new LocalService();
167 
168     private final ContentCaptureManagerServiceStub mContentCaptureManagerServiceStub =
169             new ContentCaptureManagerServiceStub();
170 
171     @Nullable
172     final LocalLog mRequestsHistory;
173 
174     @GuardedBy("mLock")
175     private ActivityManagerInternal mAm;
176 
177     /**
178      * Users disabled by {@link android.provider.Settings.Secure#CONTENT_CAPTURE_ENABLED}
179      */
180     @GuardedBy("mLock")
181     @Nullable
182     private SparseBooleanArray mDisabledBySettings;
183 
184     /**
185      * Global kill-switch based on value defined by
186      * {@link ContentCaptureManager#DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED}.
187      */
188     @GuardedBy("mLock")
189     @Nullable
190     private boolean mDisabledByDeviceConfig;
191 
192     @GuardedBy("mLock")
193     private boolean activityStartAssistDataEnabled;
194 
195     // Device-config settings that are cached and passed back to apps
196     @GuardedBy("mLock")
197     int mDevCfgLoggingLevel;
198 
199     @GuardedBy("mLock")
200     int mDevCfgMaxBufferSize;
201 
202     @GuardedBy("mLock")
203     int mDevCfgIdleFlushingFrequencyMs;
204 
205     @GuardedBy("mLock")
206     int mDevCfgTextChangeFlushingFrequencyMs;
207 
208     @GuardedBy("mLock")
209     int mDevCfgLogHistorySize;
210 
211     @GuardedBy("mLock")
212     int mDevCfgIdleUnbindTimeoutMs;
213 
214     @GuardedBy("mLock")
215     boolean mDevCfgDisableFlushForViewTreeAppearing;
216 
217     @GuardedBy("mLock")
218     boolean mDevCfgEnableContentProtectionReceiver;
219 
220     @GuardedBy("mLock")
221     int mDevCfgContentProtectionBufferSize;
222 
223     @GuardedBy("mLock")
224     @NonNull
225     List<List<String>> mDevCfgContentProtectionRequiredGroups;
226 
227     @GuardedBy("mLock")
228     @NonNull
229     List<List<String>> mDevCfgContentProtectionOptionalGroups;
230 
231     @GuardedBy("mLock")
232     int mDevCfgContentProtectionOptionalGroupsThreshold;
233 
234     @GuardedBy("mLock")
235     long mDevCfgContentProtectionAllowlistDelayMs;
236 
237     @GuardedBy("mLock")
238     long mDevCfgContentProtectionAllowlistTimeoutMs;
239 
240     @GuardedBy("mLock")
241     long mDevCfgContentProtectionAutoDisconnectTimeoutMs;
242 
243     private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
244     private final Handler mHandler = new Handler(Looper.getMainLooper());
245 
246     @GuardedBy("mLock")
247     private final Set<String> mPackagesWithShareRequests = new HashSet<>();
248 
249     private final RemoteCallbackList<IContentCaptureOptionsCallback> mCallbacks =
250             new RemoteCallbackList<>();
251 
252     final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
253             new GlobalContentCaptureOptions();
254 
255     @GuardedBy("mLock")
256     @Nullable
257     private ComponentName mContentProtectionServiceComponentName;
258 
259     @GuardedBy("mLock")
260     @Nullable
261     private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
262 
263     @GuardedBy("mLock")
264     @Nullable
265     private ContentProtectionConsentManager mContentProtectionConsentManager;
266 
ContentCaptureManagerService(@onNull Context context)267     public ContentCaptureManagerService(@NonNull Context context) {
268         super(context, new FrameworkResourcesServiceNameResolver(context,
269                 com.android.internal.R.string.config_defaultContentCaptureService),
270                 UserManager.DISALLOW_CONTENT_CAPTURE,
271                 /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
272 
273         mDevCfgContentProtectionRequiredGroups =
274                 ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS;
275         mDevCfgContentProtectionOptionalGroups =
276                 ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS;
277         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
278                 ActivityThread.currentApplication().getMainExecutor(),
279                 (properties) -> onDeviceConfigChange(properties));
280         setDeviceConfigProperties();
281 
282         if (mDevCfgLogHistorySize > 0) {
283             if (debug) Slog.d(TAG, "log history size: " + mDevCfgLogHistorySize);
284             mRequestsHistory = new LocalLog(mDevCfgLogHistorySize);
285         } else {
286             if (debug) {
287                 Slog.d(TAG, "disabled log history because size is " + mDevCfgLogHistorySize);
288             }
289             mRequestsHistory = null;
290         }
291 
292         final List<UserInfo> users = getSupportedUsers();
293         for (int i = 0; i < users.size(); i++) {
294             final int userId = users.get(i).id;
295             final boolean disabled = !isEnabledBySettings(userId);
296             // Sets which services are disabled by settings
297             if (disabled) {
298                 Slog.i(TAG, "user " + userId + " disabled by settings");
299                 if (mDisabledBySettings == null) {
300                     mDisabledBySettings = new SparseBooleanArray(1);
301                 }
302                 mDisabledBySettings.put(userId, true);
303             }
304             // Sets the global options for the service.
305             mGlobalContentCaptureOptions.setServiceInfo(userId,
306                     mServiceNameResolver.getServiceName(userId),
307                     mServiceNameResolver.isTemporary(userId));
308         }
309     }
310 
311     @Override // from AbstractMasterSystemService
newServiceLocked(@serIdInt int resolvedUserId, boolean disabled)312     protected ContentCapturePerUserService newServiceLocked(@UserIdInt int resolvedUserId,
313             boolean disabled) {
314         return new ContentCapturePerUserService(this, mLock, disabled, resolvedUserId);
315     }
316 
317     @Override // from SystemService
isUserSupported(TargetUser user)318     public boolean isUserSupported(TargetUser user) {
319         return user.isFull() || user.isProfile();
320     }
321 
322     @Override // from SystemService
onStart()323     public void onStart() {
324         publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE, mContentCaptureManagerServiceStub);
325         publishLocalService(ContentCaptureManagerInternal.class, mLocalService);
326     }
327 
328     @Override // from AbstractMasterSystemService
onServiceRemoved(@onNull ContentCapturePerUserService service, @UserIdInt int userId)329     protected void onServiceRemoved(@NonNull ContentCapturePerUserService service,
330             @UserIdInt int userId) {
331         service.destroyLocked();
332     }
333 
334     @Override // from AbstractMasterSystemService
onServicePackageUpdatingLocked(int userId)335     protected void onServicePackageUpdatingLocked(int userId) {
336         final ContentCapturePerUserService service = getServiceForUserLocked(userId);
337         if (service != null) {
338             service.onPackageUpdatingLocked();
339         }
340     }
341 
342     @Override // from AbstractMasterSystemService
onServicePackageUpdatedLocked(@serIdInt int userId)343     protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
344         final ContentCapturePerUserService service = getServiceForUserLocked(userId);
345         if (service != null) {
346             service.onPackageUpdatedLocked();
347         }
348     }
349 
350     @Override // from AbstractMasterSystemService
onServiceNameChanged(@serIdInt int userId, @NonNull String serviceName, boolean isTemporary)351     protected void onServiceNameChanged(@UserIdInt int userId, @NonNull String serviceName,
352             boolean isTemporary) {
353         mGlobalContentCaptureOptions.setServiceInfo(userId, serviceName, isTemporary);
354 
355         super.onServiceNameChanged(userId, serviceName, isTemporary);
356     }
357 
358     @Override // from AbstractMasterSystemService
enforceCallingPermissionForManagement()359     protected void enforceCallingPermissionForManagement() {
360         getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, TAG);
361     }
362 
363     @Override // from AbstractMasterSystemService
getMaximumTemporaryServiceDurationMs()364     protected int getMaximumTemporaryServiceDurationMs() {
365         return MAX_TEMP_SERVICE_DURATION_MS;
366     }
367 
368     @Override // from AbstractMasterSystemService
registerForExtraSettingsChanges(@onNull ContentResolver resolver, @NonNull ContentObserver observer)369     protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
370             @NonNull ContentObserver observer) {
371         resolver.registerContentObserver(Settings.Secure.getUriFor(
372                 Settings.Secure.CONTENT_CAPTURE_ENABLED), false, observer,
373                 UserHandle.USER_ALL);
374     }
375 
376     @Override // from AbstractMasterSystemService
onSettingsChanged(@serIdInt int userId, @NonNull String property)377     protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
378         switch (property) {
379             case Settings.Secure.CONTENT_CAPTURE_ENABLED:
380                 setContentCaptureFeatureEnabledBySettingsForUser(userId,
381                         isEnabledBySettings(userId));
382                 return;
383             default:
384                 Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
385         }
386     }
387 
388     @Override // from AbstractMasterSystemService
isDisabledLocked(@serIdInt int userId)389     protected boolean isDisabledLocked(@UserIdInt int userId) {
390         return mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId)
391                 || super.isDisabledLocked(userId);
392     }
393 
394     @Override
assertCalledByPackageOwner(@onNull String packageName)395     protected void assertCalledByPackageOwner(@NonNull String packageName) {
396         try {
397             super.assertCalledByPackageOwner(packageName);
398         } catch (SecurityException e) {
399             final int callingUid = Binder.getCallingUid();
400 
401             VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity
402                     hotwordDetectionServiceIdentity =
403                     LocalServices.getService(VoiceInteractionManagerInternal.class)
404                             .getHotwordDetectionServiceIdentity();
405 
406             if (callingUid != hotwordDetectionServiceIdentity.getIsolatedUid()) {
407                 super.assertCalledByPackageOwner(packageName);
408                 return;
409             }
410 
411             final String[] packages =
412                     getContext()
413                             .getPackageManager()
414                             .getPackagesForUid(hotwordDetectionServiceIdentity.getOwnerUid());
415             if (packages != null) {
416                 for (String candidate : packages) {
417                     if (packageName.equals(candidate)) return; // Found it
418                 }
419             }
420 
421             throw e;
422         }
423     }
424 
isDisabledBySettingsLocked(@serIdInt int userId)425     private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
426         return mDisabledBySettings != null && mDisabledBySettings.get(userId);
427     }
428 
isEnabledBySettings(@serIdInt int userId)429     private boolean isEnabledBySettings(@UserIdInt int userId) {
430         final boolean enabled = Settings.Secure.getIntForUser(getContext().getContentResolver(),
431                 Settings.Secure.CONTENT_CAPTURE_ENABLED, 1, userId) == 1 ? true : false;
432         return enabled;
433     }
434 
onDeviceConfigChange(@onNull Properties properties)435     private void onDeviceConfigChange(@NonNull Properties properties) {
436         for (String key : properties.getKeyset()) {
437             switch (key) {
438                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
439                     setDisabledByDeviceConfig(properties.getString(key, null));
440                     return;
441                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
442                     setLoggingLevelFromDeviceConfig();
443                     return;
444                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
445                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
446                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
447                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
448                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
449                 case ContentCaptureManager
450                         .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING:
451                     // Content protection below
452                 case DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
453                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
454                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
455                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
456                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
457                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS:
458                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS:
459                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT:
460                     setFineTuneParamsFromDeviceConfig();
461                     return;
462                 case DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT:
463                     setActivityStartAssistDataEnabled();
464                 default:
465                     Slog.i(TAG, "Ignoring change on " + key);
466             }
467         }
468     }
469 
470     /** @hide */
471     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setFineTuneParamsFromDeviceConfig()472     protected void setFineTuneParamsFromDeviceConfig() {
473         boolean enableContentProtectionReceiverOld;
474         boolean enableContentProtectionReceiverNew;
475         String contentProtectionRequiredGroupsConfig;
476         String contentProtectionOptionalGroupsConfig;
477         int contentProtectionOptionalGroupsThreshold;
478         long contentProtectionAllowlistDelayMs;
479         long contentProtectionAllowlistTimeoutMs;
480         ContentProtectionAllowlistManager contentProtectionAllowlistManagerOld;
481 
482         synchronized (mLock) {
483             mDevCfgMaxBufferSize =
484                     DeviceConfig.getInt(
485                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
486                             ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
487                             ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
488             mDevCfgIdleFlushingFrequencyMs =
489                     DeviceConfig.getInt(
490                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
491                             ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
492                             ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
493             mDevCfgTextChangeFlushingFrequencyMs =
494                     DeviceConfig.getInt(
495                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
496                             ContentCaptureManager
497                                     .DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
498                             ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
499             mDevCfgLogHistorySize =
500                     DeviceConfig.getInt(
501                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
502                             ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE,
503                             20);
504             mDevCfgIdleUnbindTimeoutMs =
505                     DeviceConfig.getInt(
506                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
507                             ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
508                             (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
509             mDevCfgDisableFlushForViewTreeAppearing =
510                     DeviceConfig.getBoolean(
511                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
512                             ContentCaptureManager
513                                     .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
514                             false);
515 
516             enableContentProtectionReceiverOld = mDevCfgEnableContentProtectionReceiver;
517             enableContentProtectionReceiverNew = getDeviceConfigEnableContentProtectionReceiver();
518             mDevCfgContentProtectionBufferSize =
519                     DeviceConfig.getInt(
520                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
521                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
522                             ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE);
523             contentProtectionRequiredGroupsConfig =
524                     DeviceConfig.getString(
525                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
526                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG,
527                             ContentCaptureManager
528                                     .DEFAULT_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG);
529             contentProtectionOptionalGroupsConfig =
530                     DeviceConfig.getString(
531                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
532                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG,
533                             ContentCaptureManager
534                                     .DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG);
535             contentProtectionOptionalGroupsThreshold =
536                     DeviceConfig.getInt(
537                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
538                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD,
539                             ContentCaptureManager
540                                     .DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD);
541             contentProtectionAllowlistDelayMs =
542                     DeviceConfig.getLong(
543                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
544                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS,
545                             ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS);
546             contentProtectionAllowlistTimeoutMs =
547                     DeviceConfig.getLong(
548                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
549                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS,
550                             ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS);
551             mDevCfgContentProtectionAutoDisconnectTimeoutMs =
552                     DeviceConfig.getLong(
553                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
554                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT,
555                             ContentCaptureManager
556                                     .DEFAULT_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT_MS);
557             contentProtectionAllowlistManagerOld = mContentProtectionAllowlistManager;
558 
559             if (verbose) {
560                 Slog.v(
561                         TAG,
562                         "setFineTuneParamsFromDeviceConfig(): "
563                                 + "bufferSize="
564                                 + mDevCfgMaxBufferSize
565                                 + ", idleFlush="
566                                 + mDevCfgIdleFlushingFrequencyMs
567                                 + ", textFlush="
568                                 + mDevCfgTextChangeFlushingFrequencyMs
569                                 + ", logHistory="
570                                 + mDevCfgLogHistorySize
571                                 + ", idleUnbindTimeoutMs="
572                                 + mDevCfgIdleUnbindTimeoutMs
573                                 + ", disableFlushForViewTreeAppearing="
574                                 + mDevCfgDisableFlushForViewTreeAppearing
575                                 + ", enableContentProtectionReceiver="
576                                 + enableContentProtectionReceiverNew
577                                 + ", contentProtectionBufferSize="
578                                 + mDevCfgContentProtectionBufferSize
579                                 + ", contentProtectionRequiredGroupsConfig="
580                                 + contentProtectionRequiredGroupsConfig
581                                 + ", contentProtectionOptionalGroupsConfig="
582                                 + contentProtectionOptionalGroupsConfig
583                                 + ", contentProtectionOptionalGroupsThreshold="
584                                 + contentProtectionOptionalGroupsThreshold
585                                 + ", contentProtectionAllowlistDelayMs="
586                                 + contentProtectionAllowlistDelayMs
587                                 + ", contentProtectionAllowlistTimeoutMs="
588                                 + contentProtectionAllowlistTimeoutMs
589                                 + ", contentProtectionAutoDisconnectTimeoutMs="
590                                 + mDevCfgContentProtectionAutoDisconnectTimeoutMs);
591             }
592         }
593 
594         List<List<String>> contentProtectionRequiredGroups =
595                 parseContentProtectionGroupsConfig(contentProtectionRequiredGroupsConfig);
596         List<List<String>> contentProtectionOptionalGroups =
597                 parseContentProtectionGroupsConfig(contentProtectionOptionalGroupsConfig);
598         ComponentName contentProtectionServiceComponentNameNew = null;
599         ContentProtectionAllowlistManager contentProtectionAllowlistManagerNew = null;
600         ContentProtectionConsentManager contentProtectionConsentManagerNew = null;
601 
602         if (contentProtectionAllowlistManagerOld != null && !enableContentProtectionReceiverNew) {
603             contentProtectionAllowlistManagerOld.stop();
604         }
605         if (!enableContentProtectionReceiverOld && enableContentProtectionReceiverNew) {
606             contentProtectionServiceComponentNameNew = getContentProtectionServiceComponentName();
607             if (contentProtectionServiceComponentNameNew != null) {
608                 contentProtectionAllowlistManagerNew =
609                         createContentProtectionAllowlistManager(
610                                 contentProtectionAllowlistTimeoutMs);
611                 contentProtectionAllowlistManagerNew.start(contentProtectionAllowlistDelayMs);
612                 contentProtectionConsentManagerNew = createContentProtectionConsentManager();
613             }
614         }
615 
616         synchronized (mLock) {
617             mDevCfgEnableContentProtectionReceiver = enableContentProtectionReceiverNew;
618             mDevCfgContentProtectionRequiredGroups = contentProtectionRequiredGroups;
619             mDevCfgContentProtectionOptionalGroups = contentProtectionOptionalGroups;
620             mDevCfgContentProtectionOptionalGroupsThreshold =
621                     contentProtectionOptionalGroupsThreshold;
622             mDevCfgContentProtectionAllowlistDelayMs = contentProtectionAllowlistDelayMs;
623 
624             if (enableContentProtectionReceiverOld ^ enableContentProtectionReceiverNew) {
625                 mContentProtectionServiceComponentName = contentProtectionServiceComponentNameNew;
626                 mContentProtectionAllowlistManager = contentProtectionAllowlistManagerNew;
627                 mContentProtectionConsentManager = contentProtectionConsentManagerNew;
628             }
629         }
630     }
631 
setLoggingLevelFromDeviceConfig()632     private void setLoggingLevelFromDeviceConfig() {
633         mDevCfgLoggingLevel = DeviceConfig.getInt(
634                 DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
635                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL,
636                 ContentCaptureHelper.getDefaultLoggingLevel());
637         ContentCaptureHelper.setLoggingLevel(mDevCfgLoggingLevel);
638         verbose = ContentCaptureHelper.sVerbose;
639         debug = ContentCaptureHelper.sDebug;
640         if (verbose) {
641             Slog.v(TAG, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel
642                     + ", debug=" + debug + ", verbose=" + verbose);
643         }
644     }
645 
setDeviceConfigProperties()646     private void setDeviceConfigProperties() {
647         setLoggingLevelFromDeviceConfig();
648         setFineTuneParamsFromDeviceConfig();
649         final String enabled = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
650                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
651         setDisabledByDeviceConfig(enabled);
652         setActivityStartAssistDataEnabled();
653     }
654 
setActivityStartAssistDataEnabled()655     private void setActivityStartAssistDataEnabled() {
656         synchronized (mLock) {
657             this.activityStartAssistDataEnabled = DeviceConfig.getBoolean(
658                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
659                     DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT, false);
660         }
661     }
662 
setDisabledByDeviceConfig(@ullable String explicitlyEnabled)663     private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) {
664         if (verbose) {
665             Slog.v(TAG, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled);
666         }
667         final List<UserInfo> users = getSupportedUsers();
668 
669         final boolean newDisabledValue;
670 
671         if (explicitlyEnabled != null && explicitlyEnabled.equalsIgnoreCase("false")) {
672             newDisabledValue = true;
673         } else {
674             newDisabledValue = false;
675         }
676 
677         synchronized (mLock) {
678             if (mDisabledByDeviceConfig == newDisabledValue) {
679                 if (verbose) {
680                     Slog.v(TAG, "setDisabledByDeviceConfig(): already " + newDisabledValue);
681                 }
682                 return;
683             }
684             mDisabledByDeviceConfig = newDisabledValue;
685 
686             Slog.i(TAG, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
687             for (int i = 0; i < users.size(); i++) {
688                 final int userId = users.get(i).id;
689                 boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId);
690                 Slog.i(TAG, "setDisabledByDeviceConfig(): updating service for user "
691                         + userId + " to " + (disabled ? "'disabled'" : "'enabled'"));
692                 updateCachedServiceLocked(userId, disabled);
693             }
694         }
695     }
696 
setContentCaptureFeatureEnabledBySettingsForUser(@serIdInt int userId, boolean enabled)697     private void setContentCaptureFeatureEnabledBySettingsForUser(@UserIdInt int userId,
698             boolean enabled) {
699         synchronized (mLock) {
700             if (mDisabledBySettings == null) {
701                 mDisabledBySettings = new SparseBooleanArray();
702             }
703             final boolean alreadyEnabled = !mDisabledBySettings.get(userId);
704             if (!(enabled ^ alreadyEnabled)) {
705                 if (debug) {
706                     Slog.d(TAG, "setContentCaptureFeatureEnabledForUser(): already " + enabled);
707                 }
708                 return;
709             }
710             if (enabled) {
711                 Slog.i(TAG, "setContentCaptureFeatureEnabled(): enabling service for user "
712                         + userId);
713                 mDisabledBySettings.delete(userId);
714             } else {
715                 Slog.i(TAG, "setContentCaptureFeatureEnabled(): disabling service for user "
716                         + userId);
717                 mDisabledBySettings.put(userId, true);
718             }
719             final boolean disabled = !enabled || mDisabledByDeviceConfig;
720             updateCachedServiceLocked(userId, disabled);
721         }
722     }
723 
724     // Called by Shell command.
destroySessions(@serIdInt int userId, @NonNull IResultReceiver receiver)725     void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
726         Slog.i(TAG, "destroySessions() for userId " + userId);
727         enforceCallingPermissionForManagement();
728 
729         synchronized (mLock) {
730             if (userId != UserHandle.USER_ALL) {
731                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
732                 if (service != null) {
733                     service.destroySessionsLocked();
734                 }
735             } else {
736                 visitServicesLocked((s) -> s.destroySessionsLocked());
737             }
738         }
739 
740         try {
741             receiver.send(0, new Bundle());
742         } catch (RemoteException e) {
743             // Just ignore it...
744         }
745     }
746 
747     // Called by Shell command.
listSessions(int userId, IResultReceiver receiver)748     void listSessions(int userId, IResultReceiver receiver) {
749         Slog.i(TAG, "listSessions() for userId " + userId);
750         enforceCallingPermissionForManagement();
751 
752         final Bundle resultData = new Bundle();
753         final ArrayList<String> sessions = new ArrayList<>();
754 
755         synchronized (mLock) {
756             if (userId != UserHandle.USER_ALL) {
757                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
758                 if (service != null) {
759                     service.listSessionsLocked(sessions);
760                 }
761             } else {
762                 visitServicesLocked((s) -> s.listSessionsLocked(sessions));
763             }
764         }
765 
766         resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions);
767         try {
768             receiver.send(0, resultData);
769         } catch (RemoteException e) {
770             // Just ignore it...
771         }
772     }
773 
updateOptions(String packageName, ContentCaptureOptions options)774     void updateOptions(String packageName, ContentCaptureOptions options) {
775         mCallbacks.broadcast((callback, pkg) -> {
776             if (pkg.equals(packageName)) {
777                 try {
778                     callback.setContentCaptureOptions(options);
779                 } catch (RemoteException e) {
780                     Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
781                 }
782             }
783         });
784     }
785 
getAmInternal()786     private ActivityManagerInternal getAmInternal() {
787         synchronized (mLock) {
788             if (mAm == null) {
789                 mAm = LocalServices.getService(ActivityManagerInternal.class);
790             }
791         }
792         return mAm;
793     }
794 
795     @GuardedBy("mLock")
assertCalledByServiceLocked(@onNull String methodName)796     private void assertCalledByServiceLocked(@NonNull String methodName) {
797         if (!isCalledByServiceLocked(methodName)) {
798             throw new SecurityException("caller is not user's ContentCapture service");
799         }
800     }
801 
802     @GuardedBy("mLock")
isCalledByServiceLocked(@onNull String methodName)803     private boolean isCalledByServiceLocked(@NonNull String methodName) {
804         final int userId = UserHandle.getCallingUserId();
805         final int callingUid = Binder.getCallingUid();
806         final String serviceName = mServiceNameResolver.getServiceName(userId);
807         if (serviceName == null) {
808             Slog.e(TAG, methodName + ": called by UID " + callingUid
809                     + ", but there's no service set for user " + userId);
810             return false;
811         }
812 
813         final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
814         if (serviceComponent == null) {
815             Slog.w(TAG, methodName + ": invalid service name: " + serviceName);
816             return false;
817         }
818 
819         final String servicePackageName = serviceComponent.getPackageName();
820 
821         final PackageManager pm = getContext().getPackageManager();
822         final int serviceUid;
823         try {
824             serviceUid = pm.getPackageUidAsUser(servicePackageName, UserHandle.getCallingUserId());
825         } catch (NameNotFoundException e) {
826             Slog.w(TAG, methodName + ": could not verify UID for " + serviceName);
827             return false;
828         }
829         if (callingUid != serviceUid) {
830             Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is "
831                     + serviceUid);
832             return false;
833         }
834 
835         return true;
836     }
837 
838     /**
839      * Executes the given {@code runnable} and if it throws a {@link SecurityException},
840      * send it back to the receiver.
841      *
842      * @return whether the exception was thrown or not.
843      */
throwsSecurityException(@onNull IResultReceiver result, @NonNull Runnable runable)844     private boolean throwsSecurityException(@NonNull IResultReceiver result,
845             @NonNull Runnable runable) {
846         try {
847             runable.run();
848             return false;
849         } catch (SecurityException e) {
850             try {
851                 result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
852             } catch (RemoteException e2) {
853                 Slog.w(TAG, "Unable to send security exception (" + e + "): ", e2);
854             }
855         }
856         return true;
857     }
858 
859     @GuardedBy("mLock")
isDefaultServiceLocked(int userId)860     private boolean isDefaultServiceLocked(int userId) {
861         final String defaultServiceName = mServiceNameResolver.getDefaultServiceName(userId);
862         if (defaultServiceName == null) {
863             return false;
864         }
865 
866         final String currentServiceName = mServiceNameResolver.getServiceName(userId);
867         return defaultServiceName.equals(currentServiceName);
868     }
869 
870     @Override // from AbstractMasterSystemService
871     @GuardedBy("mLock")
dumpLocked(String prefix, PrintWriter pw)872     protected void dumpLocked(String prefix, PrintWriter pw) {
873         super.dumpLocked(prefix, pw);
874 
875         final String prefix2 = prefix + "  ";
876 
877         pw.print(prefix);
878         pw.print("Users disabled by Settings: ");
879         pw.println(mDisabledBySettings);
880         pw.print(prefix);
881         pw.println("DeviceConfig Settings: ");
882         pw.print(prefix2);
883         pw.print("disabled: ");
884         pw.println(mDisabledByDeviceConfig);
885         pw.print(prefix2);
886         pw.print("loggingLevel: ");
887         pw.println(mDevCfgLoggingLevel);
888         pw.print(prefix2);
889         pw.print("maxBufferSize: ");
890         pw.println(mDevCfgMaxBufferSize);
891         pw.print(prefix2);
892         pw.print("idleFlushingFrequencyMs: ");
893         pw.println(mDevCfgIdleFlushingFrequencyMs);
894         pw.print(prefix2);
895         pw.print("textChangeFlushingFrequencyMs: ");
896         pw.println(mDevCfgTextChangeFlushingFrequencyMs);
897         pw.print(prefix2);
898         pw.print("logHistorySize: ");
899         pw.println(mDevCfgLogHistorySize);
900         pw.print(prefix2);
901         pw.print("idleUnbindTimeoutMs: ");
902         pw.println(mDevCfgIdleUnbindTimeoutMs);
903         pw.print(prefix2);
904         pw.print("disableFlushForViewTreeAppearing: ");
905         pw.println(mDevCfgDisableFlushForViewTreeAppearing);
906         pw.print(prefix2);
907         pw.print("enableContentProtectionReceiver: ");
908         pw.println(mDevCfgEnableContentProtectionReceiver);
909         pw.print(prefix2);
910         pw.print("contentProtectionBufferSize: ");
911         pw.println(mDevCfgContentProtectionBufferSize);
912         pw.print(prefix2);
913         pw.print("contentProtectionRequiredGroupsSize: ");
914         pw.println(mDevCfgContentProtectionRequiredGroups.size());
915         pw.print(prefix2);
916         pw.print("contentProtectionOptionalGroupsSize: ");
917         pw.println(mDevCfgContentProtectionOptionalGroups.size());
918         pw.print(prefix2);
919         pw.print("contentProtectionOptionalGroupsThreshold: ");
920         pw.println(mDevCfgContentProtectionOptionalGroupsThreshold);
921         pw.print(prefix2);
922         pw.print("contentProtectionAllowlistDelayMs: ");
923         pw.println(mDevCfgContentProtectionAllowlistDelayMs);
924         pw.print(prefix2);
925         pw.print("contentProtectionAllowlistTimeoutMs: ");
926         pw.println(mDevCfgContentProtectionAllowlistTimeoutMs);
927         pw.print(prefix2);
928         pw.print("contentProtectionAutoDisconnectTimeoutMs: ");
929         pw.println(mDevCfgContentProtectionAutoDisconnectTimeoutMs);
930         pw.print(prefix2);
931         pw.print("activityStartAssistDataEnabled: ");
932         pw.println(activityStartAssistDataEnabled);
933         pw.print(prefix);
934         pw.println("Global Options:");
935         mGlobalContentCaptureOptions.dump(prefix2, pw);
936     }
937 
938     /** @hide */
939     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getDeviceConfigEnableContentProtectionReceiver()940     protected boolean getDeviceConfigEnableContentProtectionReceiver() {
941         return DeviceConfig.getBoolean(
942                 DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
943                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
944                 ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
945     }
946 
947     /** @hide */
948     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
949     @NonNull
createContentProtectionAllowlistManager( long timeoutMs)950     protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager(
951             long timeoutMs) {
952         // Same handler as used by AbstractMasterSystemService
953         return new ContentProtectionAllowlistManager(
954                 this, BackgroundThread.getHandler(), timeoutMs);
955     }
956 
957     /** @hide */
958     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
959     @NonNull
createContentProtectionConsentManager()960     protected ContentProtectionConsentManager createContentProtectionConsentManager() {
961         // Same handler as used by AbstractMasterSystemService
962         return new ContentProtectionConsentManager(
963                 BackgroundThread.getHandler(),
964                 getContext().getContentResolver(),
965                 DevicePolicyCache.getInstance());
966     }
967 
968     @Nullable
getContentProtectionServiceComponentName()969     private ComponentName getContentProtectionServiceComponentName() {
970         String flatComponentName = getContentProtectionServiceFlatComponentName();
971         if (flatComponentName == null) {
972             return null;
973         }
974         return ComponentName.unflattenFromString(flatComponentName);
975     }
976 
977     /** @hide */
978     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
979     @Nullable
getContentProtectionServiceFlatComponentName()980     protected String getContentProtectionServiceFlatComponentName() {
981         return getContext()
982                 .getString(com.android.internal.R.string.config_defaultContentProtectionService);
983     }
984 
985     /**
986      * Can also throw runtime exceptions such as {@link SecurityException}.
987      *
988      * @hide
989      */
990     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
991     @NonNull
createContentProtectionServiceInfo( @onNull ComponentName componentName)992     protected ContentCaptureServiceInfo createContentProtectionServiceInfo(
993             @NonNull ComponentName componentName) throws PackageManager.NameNotFoundException {
994         return new ContentCaptureServiceInfo(
995                 getContext(), componentName, /* isTemp= */ false, UserHandle.getCallingUserId());
996     }
997 
998     /** @hide */
999     @Nullable
createRemoteContentProtectionService()1000     public RemoteContentProtectionService createRemoteContentProtectionService() {
1001         ComponentName componentName;
1002         long autoDisconnectTimeoutMs;
1003         synchronized (mLock) {
1004             if (!mDevCfgEnableContentProtectionReceiver
1005                     || mContentProtectionServiceComponentName == null) {
1006                 return null;
1007             }
1008             componentName = mContentProtectionServiceComponentName;
1009             autoDisconnectTimeoutMs = mDevCfgContentProtectionAutoDisconnectTimeoutMs;
1010         }
1011 
1012         // Check permissions by trying to construct {@link ContentCaptureServiceInfo}
1013         try {
1014             createContentProtectionServiceInfo(componentName);
1015         } catch (Exception ex) {
1016             // Swallow, exception was already logged
1017             return null;
1018         }
1019 
1020         return createRemoteContentProtectionService(componentName, autoDisconnectTimeoutMs);
1021     }
1022 
1023     /** @hide */
1024     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1025     @NonNull
createRemoteContentProtectionService( @onNull ComponentName componentName, long autoDisconnectTimeoutMs)1026     protected RemoteContentProtectionService createRemoteContentProtectionService(
1027             @NonNull ComponentName componentName, long autoDisconnectTimeoutMs) {
1028         return new RemoteContentProtectionService(
1029                 getContext(),
1030                 componentName,
1031                 UserHandle.getCallingUserId(),
1032                 isBindInstantServiceAllowed(),
1033                 autoDisconnectTimeoutMs);
1034     }
1035 
1036     /** @hide */
1037     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1038     @NonNull
getContentCaptureManagerServiceStub()1039     protected ContentCaptureManagerServiceStub getContentCaptureManagerServiceStub() {
1040         return mContentCaptureManagerServiceStub;
1041     }
1042 
1043     /**
1044      * Parses a simple config in format "group;group" where each "group" is itself in the format of
1045      * "string1,string2", eg:
1046      *
1047      * <p>"a" -> [["a"]]
1048      *
1049      * <p>"a,b" -> [["a", "b"]]
1050      *
1051      * <p>"a,b;c;d,e" -> [["a", "b"], ["c"], ["d", "e"]]
1052      *
1053      * @hide
1054      */
1055     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1056     @NonNull
parseContentProtectionGroupsConfig(@ullable String config)1057     protected List<List<String>> parseContentProtectionGroupsConfig(@Nullable String config) {
1058         if (verbose) {
1059             Slog.v(TAG, "parseContentProtectionGroupsConfig: " + config);
1060         }
1061         if (config == null) {
1062             return Collections.emptyList();
1063         }
1064         return Arrays.stream(config.split(CONTENT_PROTECTION_GROUP_CONFIG_SEPARATOR_GROUP))
1065                 .map(this::parseContentProtectionGroupConfigValues)
1066                 .filter(group -> !group.isEmpty())
1067                 .toList();
1068     }
1069 
parseContentProtectionGroupConfigValues(@onNull String group)1070     private List<String> parseContentProtectionGroupConfigValues(@NonNull String group) {
1071         return Arrays.stream(group.split(CONTENT_PROTECTION_GROUP_CONFIG_SEPARATOR_VALUE))
1072                 .filter(value -> !value.isEmpty())
1073                 .toList();
1074     }
1075 
1076     @GuardedBy("mLock")
isContentProtectionEnabledLocked()1077     private boolean isContentProtectionEnabledLocked() {
1078         return mDevCfgEnableContentProtectionReceiver
1079                 && mContentProtectionServiceComponentName != null
1080                 && mContentProtectionAllowlistManager != null
1081                 && mContentProtectionConsentManager != null
1082                 && !(mDevCfgContentProtectionRequiredGroups.isEmpty()
1083                         && mDevCfgContentProtectionOptionalGroups.isEmpty());
1084     }
1085 
1086     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
1087 
1088         @Override
startSession(@onNull IBinder activityToken, @NonNull IBinder shareableActivityToken, @NonNull ComponentName componentName, int sessionId, int flags, @NonNull IResultReceiver result)1089         public void startSession(@NonNull IBinder activityToken,
1090                 @NonNull IBinder shareableActivityToken, @NonNull ComponentName componentName,
1091                 int sessionId, int flags, @NonNull IResultReceiver result) {
1092             Objects.requireNonNull(activityToken);
1093             Objects.requireNonNull(shareableActivityToken);
1094             final int userId = UserHandle.getCallingUserId();
1095 
1096             final ActivityPresentationInfo activityPresentationInfo = getAmInternal()
1097                     .getActivityPresentationInfo(activityToken);
1098 
1099             synchronized (mLock) {
1100                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1101                 if (!isDefaultServiceLocked(userId) && !isCalledByServiceLocked("startSession()")) {
1102                     setClientState(result, STATE_DISABLED, /* binder= */ null);
1103                     return;
1104                 }
1105                 service.startSessionLocked(activityToken, shareableActivityToken,
1106                         activityPresentationInfo, sessionId, Binder.getCallingUid(), flags, result);
1107             }
1108         }
1109 
1110         @Override
finishSession(int sessionId)1111         public void finishSession(int sessionId) {
1112             final int userId = UserHandle.getCallingUserId();
1113 
1114             synchronized (mLock) {
1115                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1116                 service.finishSessionLocked(sessionId);
1117             }
1118         }
1119 
1120         @Override
getServiceComponentName(@onNull IResultReceiver result)1121         public void getServiceComponentName(@NonNull IResultReceiver result) {
1122             final int userId = UserHandle.getCallingUserId();
1123             ComponentName connectedServiceComponentName;
1124             synchronized (mLock) {
1125                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1126                 connectedServiceComponentName = service.getServiceComponentName();
1127             }
1128             try {
1129                 result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName));
1130             } catch (RemoteException e) {
1131                 Slog.w(TAG, "Unable to send service component name: " + e);
1132             }
1133         }
1134 
1135         @Override
removeData(@onNull DataRemovalRequest request)1136         public void removeData(@NonNull DataRemovalRequest request) {
1137             Objects.requireNonNull(request);
1138             assertCalledByPackageOwner(request.getPackageName());
1139 
1140             final int userId = UserHandle.getCallingUserId();
1141             synchronized (mLock) {
1142                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1143                 service.removeDataLocked(request);
1144             }
1145         }
1146 
1147         @Override
shareData(@onNull DataShareRequest request, @NonNull IDataShareWriteAdapter clientAdapter)1148         public void shareData(@NonNull DataShareRequest request,
1149                 @NonNull IDataShareWriteAdapter clientAdapter) {
1150             Objects.requireNonNull(request);
1151             Objects.requireNonNull(clientAdapter);
1152 
1153             assertCalledByPackageOwner(request.getPackageName());
1154 
1155             final int userId = UserHandle.getCallingUserId();
1156             synchronized (mLock) {
1157                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1158 
1159                 if (mPackagesWithShareRequests.size() >= MAX_CONCURRENT_FILE_SHARING_REQUESTS
1160                         || mPackagesWithShareRequests.contains(request.getPackageName())) {
1161                     try {
1162                         String serviceName = mServiceNameResolver.getServiceName(userId);
1163                         ContentCaptureMetricsLogger.writeServiceEvent(
1164                                 EVENT__DATA_SHARE_ERROR_CONCURRENT_REQUEST,
1165                                 serviceName);
1166                         clientAdapter.error(
1167                                 ContentCaptureManager.DATA_SHARE_ERROR_CONCURRENT_REQUEST);
1168                     } catch (RemoteException e) {
1169                         Slog.e(TAG, "Failed to send error message to client");
1170                     }
1171                     return;
1172                 }
1173 
1174                 service.onDataSharedLocked(request,
1175                         new DataShareCallbackDelegate(request, clientAdapter,
1176                                 ContentCaptureManagerService.this));
1177             }
1178         }
1179 
1180         @Override
isContentCaptureFeatureEnabled(@onNull IResultReceiver result)1181         public void isContentCaptureFeatureEnabled(@NonNull IResultReceiver result) {
1182             boolean enabled;
1183             synchronized (mLock) {
1184                 if (throwsSecurityException(result,
1185                         () -> assertCalledByServiceLocked("isContentCaptureFeatureEnabled()"))) {
1186                     return;
1187                 }
1188 
1189                 final int userId = UserHandle.getCallingUserId();
1190                 enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
1191             }
1192             try {
1193                 result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null);
1194             } catch (RemoteException e) {
1195                 Slog.w(TAG, "Unable to send isContentCaptureFeatureEnabled(): " + e);
1196             }
1197         }
1198 
1199         @Override
getServiceSettingsActivity(@onNull IResultReceiver result)1200         public void getServiceSettingsActivity(@NonNull IResultReceiver result) {
1201             if (throwsSecurityException(result, () -> enforceCallingPermissionForManagement())) {
1202                 return;
1203             }
1204 
1205             final int userId = UserHandle.getCallingUserId();
1206             final ComponentName componentName;
1207             synchronized (mLock) {
1208                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1209                 if (service == null) return;
1210                 componentName = service.getServiceSettingsActivityLocked();
1211             }
1212             try {
1213                 result.send(RESULT_CODE_OK, bundleFor(componentName));
1214             } catch (RemoteException e) {
1215                 Slog.w(TAG, "Unable to send getServiceSettingsIntent(): " + e);
1216             }
1217         }
1218 
1219         @Override
getContentCaptureConditions(@onNull String packageName, @NonNull IResultReceiver result)1220         public void getContentCaptureConditions(@NonNull String packageName,
1221                 @NonNull IResultReceiver result) {
1222             if (throwsSecurityException(result, () -> assertCalledByPackageOwner(packageName))) {
1223                 return;
1224             }
1225 
1226             final int userId = UserHandle.getCallingUserId();
1227             final ArrayList<ContentCaptureCondition> conditions;
1228             synchronized (mLock) {
1229                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
1230                 conditions = service == null ? null
1231                         : toList(service.getContentCaptureConditionsLocked(packageName));
1232             }
1233             try {
1234                 result.send(RESULT_CODE_OK, bundleFor(conditions));
1235             } catch (RemoteException e) {
1236                 Slog.w(TAG, "Unable to send getServiceComponentName(): " + e);
1237             }
1238         }
1239 
1240         @Override
registerContentCaptureOptionsCallback(@onNull String packageName, IContentCaptureOptionsCallback callback)1241         public void registerContentCaptureOptionsCallback(@NonNull String packageName,
1242                 IContentCaptureOptionsCallback callback) {
1243             assertCalledByPackageOwner(packageName);
1244 
1245             mCallbacks.register(callback, packageName);
1246 
1247             // Set options here in case it was updated before this was registered.
1248             final int userId = UserHandle.getCallingUserId();
1249             final ContentCaptureOptions options = mGlobalContentCaptureOptions.getOptions(userId,
1250                     packageName);
1251             if (options != null) {
1252                 try {
1253                     callback.setContentCaptureOptions(options);
1254                 } catch (RemoteException e) {
1255                     Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
1256                 }
1257             }
1258         }
1259 
1260         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1261         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1262             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
1263 
1264             boolean showHistory = true;
1265             if (args != null) {
1266                 for (String arg : args) {
1267                     switch (arg) {
1268                         case "--no-history":
1269                             showHistory = false;
1270                             break;
1271                         case "--help":
1272                             pw.println("Usage: dumpsys content_capture [--no-history]");
1273                             return;
1274                         default:
1275                             Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
1276                     }
1277                 }
1278             }
1279 
1280             synchronized (mLock) {
1281                 dumpLocked("", pw);
1282             }
1283             pw.print("Requests history: ");
1284             if (mRequestsHistory == null) {
1285                 pw.println("disabled by device config");
1286             } else if (showHistory) {
1287                 pw.println();
1288                 mRequestsHistory.reverseDump(fd, pw, args);
1289                 pw.println();
1290             } else {
1291                 pw.println();
1292             }
1293         }
1294 
1295         @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1296         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1297                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1298                 throws RemoteException {
1299             new ContentCaptureManagerServiceShellCommand(ContentCaptureManagerService.this).exec(
1300                     this, in, out, err, args, callback, resultReceiver);
1301         }
1302 
1303         @Override
resetTemporaryService(@serIdInt int userId)1304         public void resetTemporaryService(@UserIdInt int userId) {
1305             ContentCaptureManagerService.this.resetTemporaryService(userId);
1306         }
1307 
1308         @Override
setTemporaryService( @serIdInt int userId, @NonNull String serviceName, int duration)1309         public void setTemporaryService(
1310                 @UserIdInt int userId, @NonNull String serviceName, int duration) {
1311             ContentCaptureManagerService.this.setTemporaryService(
1312                     userId, serviceName, duration);
1313         }
1314 
1315         @Override
setDefaultServiceEnabled(@serIdInt int userId, boolean enabled)1316         public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
1317             ContentCaptureManagerService.this.setDefaultServiceEnabled(userId, enabled);
1318         }
1319 
1320         @Override
onLoginDetected(@onNull ParceledListSlice<ContentCaptureEvent> events)1321         public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
1322             Binder.withCleanCallingIdentity(
1323                     () -> {
1324                         RemoteContentProtectionService service =
1325                                 createRemoteContentProtectionService();
1326                         if (service == null) {
1327                             return;
1328                         }
1329                         try {
1330                             service.onLoginDetected(events);
1331                         } catch (Exception ex) {
1332                             Slog.e(TAG, "Failed to call remote service", ex);
1333                         }
1334                     });
1335         }
1336     }
1337 
1338     private final class LocalService extends ContentCaptureManagerInternal {
1339 
1340         @Override
isContentCaptureServiceForUser(int uid, @UserIdInt int userId)1341         public boolean isContentCaptureServiceForUser(int uid, @UserIdInt int userId) {
1342             synchronized (mLock) {
1343                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
1344                 if (service != null) {
1345                     return service.isContentCaptureServiceForUserLocked(uid);
1346                 }
1347             }
1348             return false;
1349         }
1350 
1351         @Override
1352         @SuppressWarnings("GuardedBy")
sendActivityStartAssistData(@serIdInt int userId, @NonNull IBinder activityToken, @NonNull Intent intentData)1353         public boolean sendActivityStartAssistData(@UserIdInt int userId,
1354                 @NonNull IBinder activityToken,
1355                 @NonNull Intent intentData) {
1356             synchronized (mLock) {
1357                 if (!activityStartAssistDataEnabled) {
1358                     return false;
1359                 }
1360                 Intent intent = new Intent(intentData);
1361                 intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
1362                         | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
1363                 Bundle assistContentExtras = new Bundle();
1364                 assistContentExtras.putBoolean(ASSIST_CONTENT_ACTIVITY_START_KEY, true);
1365                 AssistContent assistContent = new AssistContent(assistContentExtras);
1366                 assistContent.setDefaultIntent(intent);
1367 
1368                 final Bundle activityAssistData = new Bundle();
1369                 activityAssistData.putParcelable(ASSIST_KEY_CONTENT, assistContent);
1370                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
1371                 if (service != null) {
1372                     return service.sendActivityAssistDataLocked(activityToken, activityAssistData);
1373                 }
1374             }
1375             return false;
1376         }
1377 
1378         @Override
sendActivityAssistData(@serIdInt int userId, @NonNull IBinder activityToken, @NonNull Bundle data)1379         public boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken,
1380                 @NonNull Bundle data) {
1381             synchronized (mLock) {
1382                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
1383                 if (service != null) {
1384                     return service.sendActivityAssistDataLocked(activityToken, data);
1385                 }
1386             }
1387             return false;
1388         }
1389 
1390         @Override
getOptionsForPackage(int userId, @NonNull String packageName)1391         public ContentCaptureOptions getOptionsForPackage(int userId, @NonNull String packageName) {
1392             return mGlobalContentCaptureOptions.getOptions(userId, packageName);
1393         }
1394 
1395         // ErrorProne says ContentCaptureManagerService.this.mLock needs to be guarded by
1396         // 'service.mLock', which is the same as mLock.
1397         @SuppressWarnings("GuardedBy")
1398         @Override
notifyActivityEvent(int userId, @NonNull ComponentName activityComponent, @ActivityEventType int eventType, @NonNull ActivityId activityId)1399         public void notifyActivityEvent(int userId, @NonNull ComponentName activityComponent,
1400                 @ActivityEventType int eventType, @NonNull ActivityId activityId) {
1401             synchronized (mLock) {
1402                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
1403                 if (service != null) {
1404                     service.onActivityEventLocked(activityId, activityComponent, eventType);
1405                 }
1406             }
1407         }
1408     }
1409 
1410     /**
1411      * Content capture options associated with all services.
1412      *
1413      * <p>This object is defined here instead of on each {@link ContentCapturePerUserService}
1414      * because it cannot hold a lock on the main lock when
1415      * {@link GlobalContentCaptureOptions#getOptions(int, String)} is called by external services.
1416      */
1417     final class GlobalContentCaptureOptions extends GlobalWhitelistState {
1418 
1419         @GuardedBy("mGlobalWhitelistStateLock")
1420         private final SparseArray<String> mServicePackages = new SparseArray<>();
1421         @GuardedBy("mGlobalWhitelistStateLock")
1422         private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
1423 
setServiceInfo(@serIdInt int userId, @Nullable String serviceName, boolean isTemporary)1424         private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
1425                 boolean isTemporary) {
1426             synchronized (mGlobalWhitelistStateLock) {
1427                 if (isTemporary) {
1428                     mTemporaryServices.put(userId, true);
1429                 } else {
1430                     mTemporaryServices.delete(userId);
1431                 }
1432                 if (serviceName != null) {
1433                     final ComponentName componentName =
1434                             ComponentName.unflattenFromString(serviceName);
1435                     if (componentName == null) {
1436                         Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName);
1437                         mServicePackages.remove(userId);
1438                     } else {
1439                         mServicePackages.put(userId, componentName.getPackageName());
1440                     }
1441                 } else {
1442                     mServicePackages.remove(userId);
1443                 }
1444             }
1445         }
1446 
1447         @Nullable
1448         @GuardedBy("mGlobalWhitelistStateLock")
getOptions(@serIdInt int userId, @NonNull String packageName)1449         public ContentCaptureOptions getOptions(@UserIdInt int userId,
1450                 @NonNull String packageName) {
1451             boolean isContentCaptureReceiverEnabled;
1452             boolean isContentProtectionReceiverEnabled =
1453                     isContentProtectionReceiverEnabled(userId, packageName);
1454             ArraySet<ComponentName> whitelistedComponents = null;
1455 
1456             synchronized (mGlobalWhitelistStateLock) {
1457                 isContentCaptureReceiverEnabled =
1458                         isContentCaptureReceiverEnabled(userId, packageName);
1459                 if (!isContentCaptureReceiverEnabled) {
1460                     // Full package is not allowlisted: check individual components next
1461                     whitelistedComponents = getWhitelistedComponents(userId, packageName);
1462                     if (!isContentProtectionReceiverEnabled
1463                             && whitelistedComponents == null
1464                             && packageName.equals(mServicePackages.get(userId))) {
1465                         // No components allowlisted either, but let it go because it's the
1466                         // service's own package
1467                         if (verbose) Slog.v(TAG, "getOptionsForPackage() lite for " + packageName);
1468                         return new ContentCaptureOptions(mDevCfgLoggingLevel);
1469                     }
1470                 }
1471             } // synchronized
1472 
1473             // Restrict what temporary services can allowlist
1474             if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
1475                 if (!packageName.equals(mServicePackages.get(userId))) {
1476                     Slog.w(TAG, "Ignoring package " + packageName + " while using temporary "
1477                             + "service " + mServicePackages.get(userId));
1478                     return null;
1479                 }
1480             }
1481 
1482             if (!isContentCaptureReceiverEnabled
1483                     && !isContentProtectionReceiverEnabled
1484                     && whitelistedComponents == null) {
1485                 // No can do!
1486                 if (verbose) {
1487                     Slog.v(TAG, "getOptionsForPackage(" + packageName + "): not whitelisted");
1488                 }
1489                 return null;
1490             }
1491 
1492             synchronized (mLock) {
1493                 final ContentCaptureOptions options =
1494                         new ContentCaptureOptions(
1495                                 mDevCfgLoggingLevel,
1496                                 mDevCfgMaxBufferSize,
1497                                 mDevCfgIdleFlushingFrequencyMs,
1498                                 mDevCfgTextChangeFlushingFrequencyMs,
1499                                 mDevCfgLogHistorySize,
1500                                 mDevCfgDisableFlushForViewTreeAppearing,
1501                                 isContentCaptureReceiverEnabled || whitelistedComponents != null,
1502                                 new ContentCaptureOptions.ContentProtectionOptions(
1503                                         isContentProtectionReceiverEnabled,
1504                                         mDevCfgContentProtectionBufferSize,
1505                                         mDevCfgContentProtectionRequiredGroups,
1506                                         mDevCfgContentProtectionOptionalGroups,
1507                                         mDevCfgContentProtectionOptionalGroupsThreshold),
1508                                 whitelistedComponents);
1509                 if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options);
1510                 return options;
1511             }
1512         }
1513 
1514         @Override
dump(@onNull String prefix, @NonNull PrintWriter pw)1515         public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
1516             super.dump(prefix, pw);
1517 
1518             synchronized (mGlobalWhitelistStateLock) {
1519                 if (mServicePackages.size() > 0) {
1520                     pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
1521                 }
1522                 if (mTemporaryServices.size() > 0) {
1523                     pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
1524                 }
1525             }
1526         }
1527 
1528         @Override // from GlobalWhitelistState
isWhitelisted(@serIdInt int userId, @NonNull String packageName)1529         public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) {
1530             return isContentCaptureReceiverEnabled(userId, packageName)
1531                     || isContentProtectionReceiverEnabled(userId, packageName);
1532         }
1533 
1534         @Override // from GlobalWhitelistState
isWhitelisted(@serIdInt int userId, @NonNull ComponentName componentName)1535         public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
1536             return super.isWhitelisted(userId, componentName)
1537                     || isContentProtectionReceiverEnabled(userId, componentName.getPackageName());
1538         }
1539 
isContentCaptureReceiverEnabled( @serIdInt int userId, @NonNull String packageName)1540         private boolean isContentCaptureReceiverEnabled(
1541                 @UserIdInt int userId, @NonNull String packageName) {
1542             return super.isWhitelisted(userId, packageName);
1543         }
1544 
isContentProtectionReceiverEnabled( @serIdInt int userId, @NonNull String packageName)1545         private boolean isContentProtectionReceiverEnabled(
1546                 @UserIdInt int userId, @NonNull String packageName) {
1547             ContentProtectionConsentManager consentManager;
1548             ContentProtectionAllowlistManager allowlistManager;
1549             synchronized (mLock) {
1550                 if (!isContentProtectionEnabledLocked()) {
1551                     return false;
1552                 }
1553                 consentManager = mContentProtectionConsentManager;
1554                 allowlistManager = mContentProtectionAllowlistManager;
1555             }
1556             return consentManager.isConsentGranted(userId)
1557                     && allowlistManager.isAllowed(packageName);
1558         }
1559     }
1560 
1561     private static class DataShareCallbackDelegate extends IDataShareCallback.Stub {
1562 
1563         @NonNull private final DataShareRequest mDataShareRequest;
1564         @NonNull private final IDataShareWriteAdapter mClientAdapter;
1565         @NonNull private final ContentCaptureManagerService mParentService;
1566         @NonNull private final AtomicBoolean mLoggedWriteFinish = new AtomicBoolean(false);
1567 
DataShareCallbackDelegate(@onNull DataShareRequest dataShareRequest, @NonNull IDataShareWriteAdapter clientAdapter, ContentCaptureManagerService parentService)1568         DataShareCallbackDelegate(@NonNull DataShareRequest dataShareRequest,
1569                 @NonNull IDataShareWriteAdapter clientAdapter,
1570                 ContentCaptureManagerService parentService) {
1571             mDataShareRequest = dataShareRequest;
1572             mClientAdapter = clientAdapter;
1573             mParentService = parentService;
1574         }
1575 
1576         @Override
accept(@onNull IDataShareReadAdapter serviceAdapter)1577         public void accept(@NonNull IDataShareReadAdapter serviceAdapter) {
1578             Slog.i(TAG, "Data share request accepted by Content Capture service");
1579             logServiceEvent(CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ACCEPT_DATA_SHARE_REQUEST);
1580 
1581             Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
1582             if (clientPipe == null) {
1583                 logServiceEvent(
1584                         CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL);
1585                 sendErrorSignal(mClientAdapter, serviceAdapter,
1586                         ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
1587                 return;
1588             }
1589 
1590             ParcelFileDescriptor sourceIn = clientPipe.second;
1591             ParcelFileDescriptor sinkIn = clientPipe.first;
1592 
1593             Pair<ParcelFileDescriptor, ParcelFileDescriptor> servicePipe = createPipe();
1594             if (servicePipe == null) {
1595                 logServiceEvent(
1596                         CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL);
1597                 bestEffortCloseFileDescriptors(sourceIn, sinkIn);
1598 
1599                 sendErrorSignal(mClientAdapter, serviceAdapter,
1600                         ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
1601                 return;
1602             }
1603 
1604             ParcelFileDescriptor sourceOut = servicePipe.second;
1605             ParcelFileDescriptor sinkOut = servicePipe.first;
1606 
1607             synchronized (mParentService.mLock) {
1608                 mParentService.mPackagesWithShareRequests.add(mDataShareRequest.getPackageName());
1609             }
1610 
1611             if (!setUpSharingPipeline(mClientAdapter, serviceAdapter, sourceIn, sinkOut)) {
1612                 sendErrorSignal(mClientAdapter, serviceAdapter,
1613                         ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
1614                 bestEffortCloseFileDescriptors(sourceIn, sinkIn, sourceOut, sinkOut);
1615                 synchronized (mParentService.mLock) {
1616                     mParentService.mPackagesWithShareRequests
1617                         .remove(mDataShareRequest.getPackageName());
1618                 }
1619                 return;
1620             }
1621 
1622             // File descriptors received by remote apps will be copies of the current one. Close
1623             // the ones that belong to the system server, so there's only 1 open left for the
1624             // current pipe. Therefore when remote parties decide to close them - all descriptors
1625             // pointing to the pipe will be closed.
1626             bestEffortCloseFileDescriptors(sourceIn, sinkOut);
1627 
1628             mParentService.mDataShareExecutor.execute(() -> {
1629                 boolean receivedData = false;
1630                 try (InputStream fis =
1631                              new ParcelFileDescriptor.AutoCloseInputStream(sinkIn);
1632                      OutputStream fos =
1633                              new ParcelFileDescriptor.AutoCloseOutputStream(sourceOut)) {
1634 
1635                     byte[] byteBuffer = new byte[DATA_SHARE_BYTE_BUFFER_LENGTH];
1636                     while (true) {
1637                         int readBytes = fis.read(byteBuffer);
1638 
1639                         if (readBytes == -1) {
1640                             break;
1641                         }
1642 
1643                         fos.write(byteBuffer, 0 /* offset */, readBytes);
1644 
1645                         receivedData = true;
1646                     }
1647                 } catch (IOException e) {
1648                     Slog.e(TAG, "Failed to pipe client and service streams", e);
1649                     logServiceEvent(
1650                             CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_IOEXCEPTION);
1651 
1652                     sendErrorSignal(mClientAdapter, serviceAdapter,
1653                             ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
1654                 } finally {
1655                     synchronized (mParentService.mLock) {
1656                         mParentService.mPackagesWithShareRequests
1657                                 .remove(mDataShareRequest.getPackageName());
1658                     }
1659                     if (receivedData) {
1660                         if (!mLoggedWriteFinish.get()) {
1661                             logServiceEvent(EVENT__DATA_SHARE_WRITE_FINISHED);
1662                             mLoggedWriteFinish.set(true);
1663                         }
1664                         try {
1665                             mClientAdapter.finish();
1666                         } catch (RemoteException e) {
1667                             Slog.e(TAG, "Failed to call finish() the client operation", e);
1668                         }
1669                         try {
1670                             serviceAdapter.finish();
1671                         } catch (RemoteException e) {
1672                             Slog.e(TAG, "Failed to call finish() the service operation", e);
1673                         }
1674                     } else {
1675                         // Client or service may have crashed before sending.
1676                         logServiceEvent(
1677                                 CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_EMPTY_DATA);
1678                         sendErrorSignal(mClientAdapter, serviceAdapter,
1679                                 ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
1680                     }
1681                 }
1682             });
1683 
1684             mParentService.mHandler.postDelayed(() ->
1685                     enforceDataSharingTtl(
1686                             sourceIn,
1687                             sinkIn,
1688                             sourceOut,
1689                             sinkOut,
1690                             serviceAdapter),
1691                     MAX_DATA_SHARE_FILE_DESCRIPTORS_TTL_MS);
1692         }
1693 
1694         @Override
reject()1695         public void reject() {
1696             Slog.i(TAG, "Data share request rejected by Content Capture service");
1697             logServiceEvent(CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__REJECT_DATA_SHARE_REQUEST);
1698 
1699             try {
1700                 mClientAdapter.rejected();
1701             } catch (RemoteException e) {
1702                 Slog.w(TAG, "Failed to call rejected() the client operation", e);
1703                 try {
1704                     mClientAdapter.error(ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
1705                 } catch (RemoteException e2) {
1706                     Slog.w(TAG, "Failed to call error() the client operation", e2);
1707                 }
1708             }
1709         }
1710 
setUpSharingPipeline( IDataShareWriteAdapter clientAdapter, IDataShareReadAdapter serviceAdapter, ParcelFileDescriptor sourceIn, ParcelFileDescriptor sinkOut)1711         private boolean setUpSharingPipeline(
1712                 IDataShareWriteAdapter clientAdapter,
1713                 IDataShareReadAdapter serviceAdapter,
1714                 ParcelFileDescriptor sourceIn,
1715                 ParcelFileDescriptor sinkOut) {
1716             try {
1717                 clientAdapter.write(sourceIn);
1718             } catch (RemoteException e) {
1719                 Slog.e(TAG, "Failed to call write() the client operation", e);
1720                 logServiceEvent(
1721                         CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL);
1722                 return false;
1723             }
1724 
1725             try {
1726                 serviceAdapter.start(sinkOut);
1727             } catch (RemoteException e) {
1728                 Slog.e(TAG, "Failed to call start() the service operation", e);
1729                 logServiceEvent(
1730                         CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL);
1731                 return false;
1732             }
1733 
1734             return true;
1735         }
1736 
enforceDataSharingTtl(ParcelFileDescriptor sourceIn, ParcelFileDescriptor sinkIn, ParcelFileDescriptor sourceOut, ParcelFileDescriptor sinkOut, IDataShareReadAdapter serviceAdapter)1737         private void enforceDataSharingTtl(ParcelFileDescriptor sourceIn,
1738                 ParcelFileDescriptor sinkIn,
1739                 ParcelFileDescriptor sourceOut,
1740                 ParcelFileDescriptor sinkOut,
1741                 IDataShareReadAdapter serviceAdapter) {
1742 
1743             synchronized (mParentService.mLock) {
1744                 mParentService.mPackagesWithShareRequests
1745                         .remove(mDataShareRequest.getPackageName());
1746 
1747                 // Interaction finished successfully <=> all data has been written to Content
1748                 // Capture Service. If it hasn't been read successfully, service would be able
1749                 // to signal by closing the input stream while not have finished reading.
1750                 boolean finishedSuccessfully = !sinkIn.getFileDescriptor().valid()
1751                         && !sourceOut.getFileDescriptor().valid();
1752 
1753                 if (finishedSuccessfully) {
1754                     if (!mLoggedWriteFinish.get()) {
1755                         logServiceEvent(EVENT__DATA_SHARE_WRITE_FINISHED);
1756                         mLoggedWriteFinish.set(true);
1757                     }
1758                     Slog.i(TAG, "Content capture data sharing session terminated "
1759                             + "successfully for package '"
1760                             + mDataShareRequest.getPackageName()
1761                             + "'");
1762                 } else {
1763                     logServiceEvent(EVENT__DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED);
1764                     Slog.i(TAG, "Reached the timeout of Content Capture data sharing session "
1765                             + "for package '"
1766                             + mDataShareRequest.getPackageName()
1767                             + "', terminating the pipe.");
1768                 }
1769 
1770                 // Ensure all the descriptors are closed after the session.
1771                 bestEffortCloseFileDescriptors(sourceIn, sinkIn, sourceOut, sinkOut);
1772 
1773                 if (!finishedSuccessfully) {
1774                     sendErrorSignal(mClientAdapter, serviceAdapter,
1775                             ContentCaptureManager.DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED);
1776                 }
1777             }
1778         }
1779 
createPipe()1780         private Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() {
1781             ParcelFileDescriptor[] fileDescriptors;
1782             try {
1783                 fileDescriptors = ParcelFileDescriptor.createPipe();
1784             } catch (IOException e) {
1785                 Slog.e(TAG, "Failed to create a content capture data-sharing pipe", e);
1786                 return null;
1787             }
1788 
1789             if (fileDescriptors.length != 2) {
1790                 Slog.e(TAG, "Failed to create a content capture data-sharing pipe, "
1791                         + "unexpected number of file descriptors");
1792                 return null;
1793             }
1794 
1795             if (!fileDescriptors[0].getFileDescriptor().valid()
1796                     || !fileDescriptors[1].getFileDescriptor().valid()) {
1797                 Slog.e(TAG, "Failed to create a content capture data-sharing pipe, didn't "
1798                         + "receive a pair of valid file descriptors.");
1799                 return null;
1800             }
1801 
1802             return Pair.create(fileDescriptors[0], fileDescriptors[1]);
1803         }
1804 
bestEffortCloseFileDescriptor(ParcelFileDescriptor fd)1805         private void bestEffortCloseFileDescriptor(ParcelFileDescriptor fd) {
1806             try {
1807                 fd.close();
1808             } catch (IOException e) {
1809                 Slog.e(TAG, "Failed to close a file descriptor", e);
1810             }
1811         }
1812 
bestEffortCloseFileDescriptors(ParcelFileDescriptor... fds)1813         private void bestEffortCloseFileDescriptors(ParcelFileDescriptor... fds) {
1814             for (ParcelFileDescriptor fd : fds) {
1815                 bestEffortCloseFileDescriptor(fd);
1816             }
1817         }
1818 
sendErrorSignal( IDataShareWriteAdapter clientAdapter, IDataShareReadAdapter serviceAdapter, int errorCode)1819         private static void sendErrorSignal(
1820                 IDataShareWriteAdapter clientAdapter,
1821                 IDataShareReadAdapter serviceAdapter,
1822                 int errorCode) {
1823             try {
1824                 clientAdapter.error(errorCode);
1825             } catch (RemoteException e) {
1826                 Slog.e(TAG, "Failed to call error() the client operation", e);
1827             }
1828             try {
1829                 serviceAdapter.error(errorCode);
1830             } catch (RemoteException e) {
1831                 Slog.e(TAG, "Failed to call error() the service operation", e);
1832             }
1833         }
1834 
logServiceEvent(int eventType)1835         private void logServiceEvent(int eventType) {
1836             int userId = UserHandle.getCallingUserId();
1837             String serviceName = mParentService.mServiceNameResolver.getServiceName(userId);
1838             ContentCaptureMetricsLogger.writeServiceEvent(eventType, serviceName);
1839         }
1840     }
1841 }
1842