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