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