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