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.view.contentcapture.ContentCaptureHelper.toList;
22 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
23 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
24 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
25 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_TRUE;
26 
27 import static com.android.internal.util.SyncResultReceiver.bundleFor;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.annotation.UserIdInt;
32 import android.app.ActivityManagerInternal;
33 import android.app.ActivityThread;
34 import android.content.ComponentName;
35 import android.content.ContentCaptureOptions;
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.pm.ActivityPresentationInfo;
39 import android.content.pm.PackageManager;
40 import android.content.pm.PackageManager.NameNotFoundException;
41 import android.content.pm.UserInfo;
42 import android.database.ContentObserver;
43 import android.os.Binder;
44 import android.os.Build;
45 import android.os.Bundle;
46 import android.os.IBinder;
47 import android.os.RemoteException;
48 import android.os.ResultReceiver;
49 import android.os.ShellCallback;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.provider.DeviceConfig;
53 import android.provider.DeviceConfig.Properties;
54 import android.provider.Settings;
55 import android.service.contentcapture.ActivityEvent.ActivityEventType;
56 import android.util.ArraySet;
57 import android.util.LocalLog;
58 import android.util.Slog;
59 import android.util.SparseArray;
60 import android.util.SparseBooleanArray;
61 import android.view.contentcapture.ContentCaptureCondition;
62 import android.view.contentcapture.ContentCaptureHelper;
63 import android.view.contentcapture.ContentCaptureManager;
64 import android.view.contentcapture.DataRemovalRequest;
65 import android.view.contentcapture.IContentCaptureManager;
66 
67 import com.android.internal.annotations.GuardedBy;
68 import com.android.internal.infra.AbstractRemoteService;
69 import com.android.internal.infra.GlobalWhitelistState;
70 import com.android.internal.os.IResultReceiver;
71 import com.android.internal.util.DumpUtils;
72 import com.android.internal.util.Preconditions;
73 import com.android.server.LocalServices;
74 import com.android.server.infra.AbstractMasterSystemService;
75 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
76 
77 import java.io.FileDescriptor;
78 import java.io.PrintWriter;
79 import java.util.ArrayList;
80 import java.util.List;
81 
82 /**
83  * A service used to observe the contents of the screen.
84  *
85  * <p>The data collected by this service can be analyzed on-device and combined
86  * with other sources to provide contextual data in other areas of the system
87  * such as Autofill.
88  */
89 public final class ContentCaptureManagerService extends
90         AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
91 
92     static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
93 
94     private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
95 
96     private final LocalService mLocalService = new LocalService();
97 
98     @Nullable
99     final LocalLog mRequestsHistory;
100 
101     @GuardedBy("mLock")
102     private ActivityManagerInternal mAm;
103 
104     /**
105      * Users disabled by {@link android.provider.Settings.Secure#CONTENT_CAPTURE_ENABLED}
106      */
107     @GuardedBy("mLock")
108     @Nullable
109     private SparseBooleanArray mDisabledBySettings;
110 
111     /**
112      * Global kill-switch based on value defined by
113      * {@link ContentCaptureManager#DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED}.
114      */
115     @GuardedBy("mLock")
116     @Nullable
117     private boolean mDisabledByDeviceConfig;
118 
119     // Device-config settings that are cached and passed back to apps
120     @GuardedBy("mLock") int mDevCfgLoggingLevel;
121     @GuardedBy("mLock") int mDevCfgMaxBufferSize;
122     @GuardedBy("mLock") int mDevCfgIdleFlushingFrequencyMs;
123     @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs;
124     @GuardedBy("mLock") int mDevCfgLogHistorySize;
125     @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
126 
127     final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
128             new GlobalContentCaptureOptions();
129 
ContentCaptureManagerService(@onNull Context context)130     public ContentCaptureManagerService(@NonNull Context context) {
131         super(context, new FrameworkResourcesServiceNameResolver(context,
132                 com.android.internal.R.string.config_defaultContentCaptureService),
133                 UserManager.DISALLOW_CONTENT_CAPTURE,
134                 /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
135         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
136                 ActivityThread.currentApplication().getMainExecutor(),
137                 (properties) -> onDeviceConfigChange(properties));
138         setDeviceConfigProperties();
139 
140         if (mDevCfgLogHistorySize > 0) {
141             if (debug) Slog.d(mTag, "log history size: " + mDevCfgLogHistorySize);
142             mRequestsHistory = new LocalLog(mDevCfgLogHistorySize);
143         } else {
144             if (debug) {
145                 Slog.d(mTag, "disabled log history because size is " + mDevCfgLogHistorySize);
146             }
147             mRequestsHistory = null;
148         }
149 
150         final UserManager um = getContext().getSystemService(UserManager.class);
151         final List<UserInfo> users = um.getUsers();
152         for (int i = 0; i < users.size(); i++) {
153             final int userId = users.get(i).id;
154             final boolean disabled = !isEnabledBySettings(userId);
155             // Sets which services are disabled by settings
156             if (disabled) {
157                 Slog.i(mTag, "user " + userId + " disabled by settings");
158                 if (mDisabledBySettings == null) {
159                     mDisabledBySettings = new SparseBooleanArray(1);
160                 }
161                 mDisabledBySettings.put(userId, true);
162             }
163             // Sets the global options for the service.
164             mGlobalContentCaptureOptions.setServiceInfo(userId,
165                     mServiceNameResolver.getServiceName(userId),
166                     mServiceNameResolver.isTemporary(userId));
167         }
168     }
169 
170     @Override // from AbstractMasterSystemService
newServiceLocked(@serIdInt int resolvedUserId, boolean disabled)171     protected ContentCapturePerUserService newServiceLocked(@UserIdInt int resolvedUserId,
172             boolean disabled) {
173         return new ContentCapturePerUserService(this, mLock, disabled, resolvedUserId);
174     }
175 
176     @Override // from SystemService
onStart()177     public void onStart() {
178         publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE,
179                 new ContentCaptureManagerServiceStub());
180         publishLocalService(ContentCaptureManagerInternal.class, mLocalService);
181     }
182 
183     @Override // from AbstractMasterSystemService
onServiceRemoved(@onNull ContentCapturePerUserService service, @UserIdInt int userId)184     protected void onServiceRemoved(@NonNull ContentCapturePerUserService service,
185             @UserIdInt int userId) {
186         service.destroyLocked();
187     }
188 
189     @Override // from AbstractMasterSystemService
onServicePackageUpdatingLocked(int userId)190     protected void onServicePackageUpdatingLocked(int userId) {
191         final ContentCapturePerUserService service = getServiceForUserLocked(userId);
192         if (service != null) {
193             service.onPackageUpdatingLocked();
194         }
195     }
196 
197     @Override // from AbstractMasterSystemService
onServicePackageUpdatedLocked(@serIdInt int userId)198     protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
199         final ContentCapturePerUserService service = getServiceForUserLocked(userId);
200         if (service != null) {
201             service.onPackageUpdatedLocked();
202         }
203     }
204 
205     @Override // from AbstractMasterSystemService
onServiceNameChanged(@serIdInt int userId, @NonNull String serviceName, boolean isTemporary)206     protected void onServiceNameChanged(@UserIdInt int userId, @NonNull String serviceName,
207             boolean isTemporary) {
208         mGlobalContentCaptureOptions.setServiceInfo(userId, serviceName, isTemporary);
209 
210         super.onServiceNameChanged(userId, serviceName, isTemporary);
211     }
212 
213     @Override // from AbstractMasterSystemService
enforceCallingPermissionForManagement()214     protected void enforceCallingPermissionForManagement() {
215         getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
216     }
217 
218     @Override // from AbstractMasterSystemService
getMaximumTemporaryServiceDurationMs()219     protected int getMaximumTemporaryServiceDurationMs() {
220         return MAX_TEMP_SERVICE_DURATION_MS;
221     }
222 
223     @Override // from AbstractMasterSystemService
registerForExtraSettingsChanges(@onNull ContentResolver resolver, @NonNull ContentObserver observer)224     protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
225             @NonNull ContentObserver observer) {
226         resolver.registerContentObserver(Settings.Secure.getUriFor(
227                 Settings.Secure.CONTENT_CAPTURE_ENABLED), false, observer,
228                 UserHandle.USER_ALL);
229     }
230 
231     @Override // from AbstractMasterSystemService
onSettingsChanged(@serIdInt int userId, @NonNull String property)232     protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
233         switch (property) {
234             case Settings.Secure.CONTENT_CAPTURE_ENABLED:
235                 setContentCaptureFeatureEnabledBySettingsForUser(userId,
236                         isEnabledBySettings(userId));
237                 return;
238             default:
239                 Slog.w(mTag, "Unexpected property (" + property + "); updating cache instead");
240         }
241     }
242 
243     @Override // from AbstractMasterSystemService
isDisabledLocked(@serIdInt int userId)244     protected boolean isDisabledLocked(@UserIdInt int userId) {
245         return mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId)
246                 || super.isDisabledLocked(userId);
247     }
248 
isDisabledBySettingsLocked(@serIdInt int userId)249     private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
250         return mDisabledBySettings != null && mDisabledBySettings.get(userId);
251     }
252 
isEnabledBySettings(@serIdInt int userId)253     private boolean isEnabledBySettings(@UserIdInt int userId) {
254         final boolean enabled = Settings.Secure.getIntForUser(getContext().getContentResolver(),
255                 Settings.Secure.CONTENT_CAPTURE_ENABLED, 1, userId) == 1 ? true : false;
256         return enabled;
257     }
258 
onDeviceConfigChange(@onNull Properties properties)259     private void onDeviceConfigChange(@NonNull Properties properties) {
260         for (String key : properties.getKeyset()) {
261             switch (key) {
262                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
263                     setDisabledByDeviceConfig(properties.getString(key, null));
264                     return;
265                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
266                     setLoggingLevelFromDeviceConfig();
267                     return;
268                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
269                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
270                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
271                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
272                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
273                     setFineTuneParamsFromDeviceConfig();
274                     return;
275                 default:
276                     Slog.i(mTag, "Ignoring change on " + key);
277             }
278         }
279     }
280 
setFineTuneParamsFromDeviceConfig()281     private void setFineTuneParamsFromDeviceConfig() {
282         synchronized (mLock) {
283             mDevCfgMaxBufferSize = DeviceConfig.getInt(
284                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
285                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
286                     ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
287             mDevCfgIdleFlushingFrequencyMs = DeviceConfig.getInt(
288                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
289                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
290                     ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
291             mDevCfgTextChangeFlushingFrequencyMs = DeviceConfig.getInt(
292                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
293                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
294                     ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
295             mDevCfgLogHistorySize = DeviceConfig.getInt(
296                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
297                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
298             mDevCfgIdleUnbindTimeoutMs = DeviceConfig.getInt(
299                     DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
300                     ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
301                     (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
302             if (verbose) {
303                 Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): "
304                         + "bufferSize=" + mDevCfgMaxBufferSize
305                         + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
306                         + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
307                         + ", logHistory=" + mDevCfgLogHistorySize
308                         + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs);
309             }
310         }
311     }
312 
setLoggingLevelFromDeviceConfig()313     private void setLoggingLevelFromDeviceConfig() {
314         mDevCfgLoggingLevel = DeviceConfig.getInt(
315                 DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
316                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL,
317                 ContentCaptureHelper.getDefaultLoggingLevel());
318         ContentCaptureHelper.setLoggingLevel(mDevCfgLoggingLevel);
319         verbose = ContentCaptureHelper.sVerbose;
320         debug = ContentCaptureHelper.sDebug;
321         if (verbose) {
322             Slog.v(mTag, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel
323                     + ", debug=" + debug + ", verbose=" + verbose);
324         }
325     }
326 
setDeviceConfigProperties()327     private void setDeviceConfigProperties() {
328         setLoggingLevelFromDeviceConfig();
329         setFineTuneParamsFromDeviceConfig();
330         final String enabled = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
331                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
332         setDisabledByDeviceConfig(enabled);
333     }
334 
setDisabledByDeviceConfig(@ullable String explicitlyEnabled)335     private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) {
336         if (verbose) {
337             Slog.v(mTag, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled);
338         }
339         final UserManager um = getContext().getSystemService(UserManager.class);
340         final List<UserInfo> users = um.getUsers();
341 
342         final boolean newDisabledValue;
343 
344         if (explicitlyEnabled != null && explicitlyEnabled.equalsIgnoreCase("false")) {
345             newDisabledValue = true;
346         } else {
347             newDisabledValue = false;
348         }
349 
350         synchronized (mLock) {
351             if (mDisabledByDeviceConfig == newDisabledValue) {
352                 if (verbose) {
353                     Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue);
354                 }
355                 return;
356             }
357             mDisabledByDeviceConfig = newDisabledValue;
358 
359             Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
360             for (int i = 0; i < users.size(); i++) {
361                 final int userId = users.get(i).id;
362                 boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId);
363                 Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user "
364                         + userId + " to " + (disabled ? "'disabled'" : "'enabled'"));
365                 updateCachedServiceLocked(userId, disabled);
366             }
367         }
368     }
369 
setContentCaptureFeatureEnabledBySettingsForUser(@serIdInt int userId, boolean enabled)370     private void setContentCaptureFeatureEnabledBySettingsForUser(@UserIdInt int userId,
371             boolean enabled) {
372         synchronized (mLock) {
373             if (mDisabledBySettings == null) {
374                 mDisabledBySettings = new SparseBooleanArray();
375             }
376             final boolean alreadyEnabled = !mDisabledBySettings.get(userId);
377             if (!(enabled ^ alreadyEnabled)) {
378                 if (debug) {
379                     Slog.d(mTag, "setContentCaptureFeatureEnabledForUser(): already " + enabled);
380                 }
381                 return;
382             }
383             if (enabled) {
384                 Slog.i(mTag, "setContentCaptureFeatureEnabled(): enabling service for user "
385                         + userId);
386                 mDisabledBySettings.delete(userId);
387             } else {
388                 Slog.i(mTag, "setContentCaptureFeatureEnabled(): disabling service for user "
389                         + userId);
390                 mDisabledBySettings.put(userId, true);
391             }
392             final boolean disabled = !enabled || mDisabledByDeviceConfig;
393             updateCachedServiceLocked(userId, disabled);
394         }
395     }
396 
397     // Called by Shell command.
destroySessions(@serIdInt int userId, @NonNull IResultReceiver receiver)398     void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
399         Slog.i(mTag, "destroySessions() for userId " + userId);
400         enforceCallingPermissionForManagement();
401 
402         synchronized (mLock) {
403             if (userId != UserHandle.USER_ALL) {
404                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
405                 if (service != null) {
406                     service.destroySessionsLocked();
407                 }
408             } else {
409                 visitServicesLocked((s) -> s.destroySessionsLocked());
410             }
411         }
412 
413         try {
414             receiver.send(0, new Bundle());
415         } catch (RemoteException e) {
416             // Just ignore it...
417         }
418     }
419 
420     // Called by Shell command.
listSessions(int userId, IResultReceiver receiver)421     void listSessions(int userId, IResultReceiver receiver) {
422         Slog.i(mTag, "listSessions() for userId " + userId);
423         enforceCallingPermissionForManagement();
424 
425         final Bundle resultData = new Bundle();
426         final ArrayList<String> sessions = new ArrayList<>();
427 
428         synchronized (mLock) {
429             if (userId != UserHandle.USER_ALL) {
430                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
431                 if (service != null) {
432                     service.listSessionsLocked(sessions);
433                 }
434             } else {
435                 visitServicesLocked((s) -> s.listSessionsLocked(sessions));
436             }
437         }
438 
439         resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions);
440         try {
441             receiver.send(0, resultData);
442         } catch (RemoteException e) {
443             // Just ignore it...
444         }
445     }
446 
getAmInternal()447     private ActivityManagerInternal getAmInternal() {
448         synchronized (mLock) {
449             if (mAm == null) {
450                 mAm = LocalServices.getService(ActivityManagerInternal.class);
451             }
452         }
453         return mAm;
454     }
455 
456     @GuardedBy("mLock")
assertCalledByServiceLocked(@onNull String methodName)457     private void assertCalledByServiceLocked(@NonNull String methodName) {
458         if (!isCalledByServiceLocked(methodName)) {
459             throw new SecurityException("caller is not user's ContentCapture service");
460         }
461     }
462 
463     @GuardedBy("mLock")
isCalledByServiceLocked(@onNull String methodName)464     private boolean isCalledByServiceLocked(@NonNull String methodName) {
465         final int userId = UserHandle.getCallingUserId();
466         final int callingUid = Binder.getCallingUid();
467         final String serviceName = mServiceNameResolver.getServiceName(userId);
468         if (serviceName == null) {
469             Slog.e(mTag, methodName + ": called by UID " + callingUid
470                     + ", but there's no service set for user " + userId);
471             return false;
472         }
473 
474         final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
475         if (serviceComponent == null) {
476             Slog.w(mTag, methodName + ": invalid service name: " + serviceName);
477             return false;
478         }
479 
480         final String servicePackageName = serviceComponent.getPackageName();
481 
482         final PackageManager pm = getContext().getPackageManager();
483         final int serviceUid;
484         try {
485             serviceUid = pm.getPackageUidAsUser(servicePackageName, UserHandle.getCallingUserId());
486         } catch (NameNotFoundException e) {
487             Slog.w(mTag, methodName + ": could not verify UID for " + serviceName);
488             return false;
489         }
490         if (callingUid != serviceUid) {
491             Slog.e(mTag, methodName + ": called by UID " + callingUid + ", but service UID is "
492                     + serviceUid);
493             return false;
494         }
495 
496         return true;
497     }
498 
499     /**
500      * Executes the given {@code runnable} and if it throws a {@link SecurityException},
501      * send it back to the receiver.
502      *
503      * @return whether the exception was thrown or not.
504      */
throwsSecurityException(@onNull IResultReceiver result, @NonNull Runnable runable)505     private boolean throwsSecurityException(@NonNull IResultReceiver result,
506             @NonNull Runnable runable) {
507         try {
508             runable.run();
509             return false;
510         } catch (SecurityException e) {
511             try {
512                 result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
513             } catch (RemoteException e2) {
514                 Slog.w(mTag, "Unable to send security exception (" + e + "): ", e2);
515             }
516         }
517         return true;
518     }
519 
520     @Override // from AbstractMasterSystemService
dumpLocked(String prefix, PrintWriter pw)521     protected void dumpLocked(String prefix, PrintWriter pw) {
522         super.dumpLocked(prefix, pw);
523 
524         final String prefix2 = prefix + "  ";
525 
526         pw.print(prefix); pw.print("Users disabled by Settings: "); pw.println(mDisabledBySettings);
527         pw.print(prefix); pw.println("DeviceConfig Settings: ");
528         pw.print(prefix2); pw.print("disabled: "); pw.println(mDisabledByDeviceConfig);
529         pw.print(prefix2); pw.print("loggingLevel: "); pw.println(mDevCfgLoggingLevel);
530         pw.print(prefix2); pw.print("maxBufferSize: "); pw.println(mDevCfgMaxBufferSize);
531         pw.print(prefix2); pw.print("idleFlushingFrequencyMs: ");
532         pw.println(mDevCfgIdleFlushingFrequencyMs);
533         pw.print(prefix2); pw.print("textChangeFlushingFrequencyMs: ");
534         pw.println(mDevCfgTextChangeFlushingFrequencyMs);
535         pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
536         pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
537         pw.println(mDevCfgIdleUnbindTimeoutMs);
538         pw.print(prefix); pw.println("Global Options:");
539         mGlobalContentCaptureOptions.dump(prefix2, pw);
540     }
541 
542     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
543 
544         @Override
startSession(@onNull IBinder activityToken, @NonNull ComponentName componentName, int sessionId, int flags, @NonNull IResultReceiver result)545         public void startSession(@NonNull IBinder activityToken,
546                 @NonNull ComponentName componentName, int sessionId, int flags,
547                 @NonNull IResultReceiver result) {
548             Preconditions.checkNotNull(activityToken);
549             Preconditions.checkNotNull(sessionId);
550             final int userId = UserHandle.getCallingUserId();
551 
552             final ActivityPresentationInfo activityPresentationInfo = getAmInternal()
553                     .getActivityPresentationInfo(activityToken);
554 
555             synchronized (mLock) {
556                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
557                 service.startSessionLocked(activityToken, activityPresentationInfo, sessionId,
558                         Binder.getCallingUid(), flags, result);
559             }
560         }
561 
562         @Override
finishSession(int sessionId)563         public void finishSession(int sessionId) {
564             Preconditions.checkNotNull(sessionId);
565             final int userId = UserHandle.getCallingUserId();
566 
567             synchronized (mLock) {
568                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
569                 service.finishSessionLocked(sessionId);
570             }
571         }
572 
573         @Override
getServiceComponentName(@onNull IResultReceiver result)574         public void getServiceComponentName(@NonNull IResultReceiver result) {
575             final int userId = UserHandle.getCallingUserId();
576             ComponentName connectedServiceComponentName;
577             synchronized (mLock) {
578                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
579                 connectedServiceComponentName = service.getServiceComponentName();
580             }
581             try {
582                 result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName));
583             } catch (RemoteException e) {
584                 Slog.w(mTag, "Unable to send service component name: " + e);
585             }
586         }
587 
588         @Override
removeData(@onNull DataRemovalRequest request)589         public void removeData(@NonNull DataRemovalRequest request) {
590             Preconditions.checkNotNull(request);
591             assertCalledByPackageOwner(request.getPackageName());
592 
593             final int userId = UserHandle.getCallingUserId();
594             synchronized (mLock) {
595                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
596                 service.removeDataLocked(request);
597             }
598         }
599 
600         @Override
isContentCaptureFeatureEnabled(@onNull IResultReceiver result)601         public void isContentCaptureFeatureEnabled(@NonNull IResultReceiver result) {
602             boolean enabled;
603             synchronized (mLock) {
604                 if (throwsSecurityException(result,
605                         () -> assertCalledByServiceLocked("isContentCaptureFeatureEnabled()"))) {
606                     return;
607                 }
608 
609                 final int userId = UserHandle.getCallingUserId();
610                 enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
611             }
612             try {
613                 result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null);
614             } catch (RemoteException e) {
615                 Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
616             }
617         }
618 
619         @Override
getServiceSettingsActivity(@onNull IResultReceiver result)620         public void getServiceSettingsActivity(@NonNull IResultReceiver result) {
621             if (throwsSecurityException(result, () -> enforceCallingPermissionForManagement())) {
622                 return;
623             }
624 
625             final int userId = UserHandle.getCallingUserId();
626             final ComponentName componentName;
627             synchronized (mLock) {
628                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
629                 if (service == null) return;
630                 componentName = service.getServiceSettingsActivityLocked();
631             }
632             try {
633                 result.send(RESULT_CODE_OK, bundleFor(componentName));
634             } catch (RemoteException e) {
635                 Slog.w(mTag, "Unable to send getServiceSettingsIntent(): " + e);
636             }
637         }
638 
639         @Override
getContentCaptureConditions(@onNull String packageName, @NonNull IResultReceiver result)640         public void getContentCaptureConditions(@NonNull String packageName,
641                 @NonNull IResultReceiver result) {
642             if (throwsSecurityException(result, () -> assertCalledByPackageOwner(packageName))) {
643                 return;
644             }
645 
646             final int userId = UserHandle.getCallingUserId();
647             final ArrayList<ContentCaptureCondition> conditions;
648             synchronized (mLock) {
649                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
650                 conditions = service == null ? null
651                         : toList(service.getContentCaptureConditionsLocked(packageName));
652             }
653             try {
654                 result.send(RESULT_CODE_OK, bundleFor(conditions));
655             } catch (RemoteException e) {
656                 Slog.w(mTag, "Unable to send getServiceComponentName(): " + e);
657             }
658         }
659 
660         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)661         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
662             if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
663 
664             boolean showHistory = true;
665             if (args != null) {
666                 for (String arg : args) {
667                     switch (arg) {
668                         case "--no-history":
669                             showHistory = false;
670                             break;
671                         case "--help":
672                             pw.println("Usage: dumpsys content_capture [--no-history]");
673                             return;
674                         default:
675                             Slog.w(mTag, "Ignoring invalid dump arg: " + arg);
676                     }
677                 }
678             }
679 
680             synchronized (mLock) {
681                 dumpLocked("", pw);
682             }
683             pw.print("Requests history: ");
684             if (mRequestsHistory == null) {
685                 pw.println("disabled by device config");
686             } else if (showHistory) {
687                 pw.println();
688                 mRequestsHistory.reverseDump(fd, pw, args);
689                 pw.println();
690             } else {
691                 pw.println();
692             }
693         }
694 
695         @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)696         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
697                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
698                 throws RemoteException {
699             new ContentCaptureManagerServiceShellCommand(ContentCaptureManagerService.this).exec(
700                     this, in, out, err, args, callback, resultReceiver);
701         }
702     }
703 
704     private final class LocalService extends ContentCaptureManagerInternal {
705 
706         @Override
isContentCaptureServiceForUser(int uid, @UserIdInt int userId)707         public boolean isContentCaptureServiceForUser(int uid, @UserIdInt int userId) {
708             synchronized (mLock) {
709                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
710                 if (service != null) {
711                     return service.isContentCaptureServiceForUserLocked(uid);
712                 }
713             }
714             return false;
715         }
716 
717         @Override
sendActivityAssistData(@serIdInt int userId, @NonNull IBinder activityToken, @NonNull Bundle data)718         public boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken,
719                 @NonNull Bundle data) {
720             synchronized (mLock) {
721                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
722                 if (service != null) {
723                     return service.sendActivityAssistDataLocked(activityToken, data);
724                 }
725             }
726             return false;
727         }
728 
729         @Override
getOptionsForPackage(int userId, @NonNull String packageName)730         public ContentCaptureOptions getOptionsForPackage(int userId, @NonNull String packageName) {
731             return mGlobalContentCaptureOptions.getOptions(userId, packageName);
732         }
733 
734         @Override
notifyActivityEvent(int userId, @NonNull ComponentName activityComponent, @ActivityEventType int eventType)735         public void notifyActivityEvent(int userId, @NonNull ComponentName activityComponent,
736                 @ActivityEventType int eventType) {
737             synchronized (mLock) {
738                 final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
739                 if (service != null) {
740                     service.onActivityEventLocked(activityComponent, eventType);
741                 }
742             }
743         }
744     }
745 
746     /**
747      * Content capture options associated with all services.
748      *
749      * <p>This object is defined here instead of on each {@link ContentCapturePerUserService}
750      * because it cannot hold a lock on the main lock when
751      * {@link GlobalContentCaptureOptions#getOptions(int, String)} is called by external services.
752      */
753     final class GlobalContentCaptureOptions extends GlobalWhitelistState {
754 
755         @GuardedBy("mGlobalWhitelistStateLock")
756         private final SparseArray<String> mServicePackages = new SparseArray<>();
757         @GuardedBy("mGlobalWhitelistStateLock")
758         private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
759 
setServiceInfo(@serIdInt int userId, @Nullable String serviceName, boolean isTemporary)760         private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
761                 boolean isTemporary) {
762             synchronized (mGlobalWhitelistStateLock) {
763                 if (isTemporary) {
764                     mTemporaryServices.put(userId, true);
765                 } else {
766                     mTemporaryServices.delete(userId);
767                 }
768                 if (serviceName != null) {
769                     final ComponentName componentName =
770                             ComponentName.unflattenFromString(serviceName);
771                     if (componentName == null) {
772                         Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName);
773                         mServicePackages.remove(userId);
774                     } else {
775                         mServicePackages.put(userId, componentName.getPackageName());
776                     }
777                 } else {
778                     mServicePackages.remove(userId);
779                 }
780             }
781         }
782 
783         @Nullable
784         @GuardedBy("mGlobalWhitelistStateLock")
getOptions(@serIdInt int userId, @NonNull String packageName)785         public ContentCaptureOptions getOptions(@UserIdInt int userId,
786                 @NonNull String packageName) {
787             boolean packageWhitelisted;
788             ArraySet<ComponentName> whitelistedComponents = null;
789             synchronized (mGlobalWhitelistStateLock) {
790                 packageWhitelisted = isWhitelisted(userId, packageName);
791                 if (!packageWhitelisted) {
792                     // Full package is not whitelisted: check individual components first
793                     whitelistedComponents = getWhitelistedComponents(userId, packageName);
794                     if (whitelistedComponents == null
795                             && packageName.equals(mServicePackages.get(userId))) {
796                         // No components whitelisted either, but let it go because it's the
797                         // service's own package
798                         if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
799                         return new ContentCaptureOptions(mDevCfgLoggingLevel);
800                     }
801                 }
802             } // synchronized
803 
804             // Restrict what temporary services can whitelist
805             if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
806                 if (!packageName.equals(mServicePackages.get(userId))) {
807                     Slog.w(mTag, "Ignoring package " + packageName + " while using temporary "
808                             + "service " + mServicePackages.get(userId));
809                     return null;
810                 }
811             }
812 
813             if (!packageWhitelisted && whitelistedComponents == null) {
814                 // No can do!
815                 if (verbose) {
816                     Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
817                 }
818                 return null;
819             }
820 
821             final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
822                     mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
823                     mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
824                     whitelistedComponents);
825             if (verbose) Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
826             return options;
827         }
828 
829         @Override
dump(@onNull String prefix, @NonNull PrintWriter pw)830         public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
831             super.dump(prefix, pw);
832 
833             synchronized (mGlobalWhitelistStateLock) {
834                 if (mServicePackages.size() > 0) {
835                     pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
836                 }
837                 if (mTemporaryServices.size() > 0) {
838                     pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
839                 }
840             }
841         }
842     }
843 }
844