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