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