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