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