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