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