1 /* 2 * Copyright (C) 2023 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; 18 19 import static android.permission.flags.Flags.sensitiveContentImprovements; 20 import static android.permission.flags.Flags.sensitiveContentMetricsBugfix; 21 import static android.permission.flags.Flags.sensitiveNotificationAppProtection; 22 import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS; 23 import static android.view.flags.Flags.sensitiveContentAppProtection; 24 25 import static com.android.internal.util.FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION; 26 import static com.android.internal.util.FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__FRAMEWORKS; 27 import static com.android.internal.util.FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START; 28 import static com.android.internal.util.FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP; 29 import static com.android.internal.util.FrameworkStatsLog.SENSITIVE_NOTIFICATION_APP_PROTECTION_SESSION; 30 import static com.android.server.wm.WindowManagerInternal.OnWindowRemovedListener; 31 32 import android.annotation.NonNull; 33 import android.annotation.Nullable; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.pm.PackageManager; 37 import android.content.pm.PackageManagerInternal; 38 import android.media.projection.MediaProjectionInfo; 39 import android.media.projection.MediaProjectionManager; 40 import android.os.Binder; 41 import android.os.IBinder; 42 import android.os.RemoteException; 43 import android.os.Trace; 44 import android.os.UserHandle; 45 import android.provider.Settings; 46 import android.service.notification.NotificationListenerService; 47 import android.service.notification.NotificationListenerService.RankingMap; 48 import android.service.notification.StatusBarNotification; 49 import android.util.ArraySet; 50 import android.util.Log; 51 import android.view.ISensitiveContentProtectionManager; 52 53 import com.android.internal.annotations.GuardedBy; 54 import com.android.internal.annotations.VisibleForTesting; 55 import com.android.internal.util.FrameworkStatsLog; 56 import com.android.server.wm.SensitiveContentPackages.PackageInfo; 57 import com.android.server.wm.WindowManagerInternal; 58 59 import java.util.Objects; 60 import java.util.Random; 61 import java.util.Set; 62 63 /** 64 * This service protects sensitive content from screen sharing. The service monitors notifications 65 * for sensitive content and protects from screen share. The service also protects sensitive 66 * content rendered on screen during screen share. 67 */ 68 public final class SensitiveContentProtectionManagerService extends SystemService { 69 private static final String TAG = "SensitiveContentProtect"; 70 private static final boolean DEBUG = false; 71 72 @VisibleForTesting 73 @Nullable 74 NotificationListener mNotificationListener; 75 @Nullable 76 private MediaProjectionManager mProjectionManager; 77 78 @GuardedBy("mSensitiveContentProtectionLock") 79 @Nullable 80 private MediaProjectionSession mMediaProjectionSession; 81 82 private PackageManagerInternal mPackageManagerInternal; 83 84 @Nullable 85 private WindowManagerInternal mWindowManager; 86 87 // screen recorder packages exempted from screen share protection. 88 private ArraySet<String> mExemptedPackages = null; 89 90 final Object mSensitiveContentProtectionLock = new Object(); 91 92 private final ArraySet<PackageInfo> mPackagesShowingSensitiveContent = new ArraySet<>(); 93 94 @GuardedBy("mSensitiveContentProtectionLock") 95 private boolean mProjectionActive = false; 96 97 private static class MediaProjectionSession { 98 private final int mUid; // UID of app that started projection session 99 private final long mSessionId; 100 private final boolean mIsExempted; 101 private final ArraySet<String> mAllSeenNotificationKeys = new ArraySet<>(); 102 private final ArraySet<String> mSeenOtpNotificationKeys = new ArraySet<>(); 103 MediaProjectionSession(int uid, boolean isExempted, long sessionId)104 MediaProjectionSession(int uid, boolean isExempted, long sessionId) { 105 mUid = uid; 106 mIsExempted = isExempted; 107 mSessionId = sessionId; 108 } 109 logProjectionSessionStart()110 public void logProjectionSessionStart() { 111 FrameworkStatsLog.write( 112 SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION, 113 mSessionId, 114 mUid, 115 mIsExempted, 116 SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START, 117 SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__FRAMEWORKS 118 ); 119 } 120 logProjectionSessionStop()121 public void logProjectionSessionStop() { 122 FrameworkStatsLog.write( 123 SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION, 124 mSessionId, 125 mUid, 126 mIsExempted, 127 SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP, 128 SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__FRAMEWORKS 129 ); 130 } 131 logAppNotificationsProtected()132 public void logAppNotificationsProtected() { 133 FrameworkStatsLog.write( 134 SENSITIVE_NOTIFICATION_APP_PROTECTION_SESSION, 135 mSessionId, 136 mAllSeenNotificationKeys.size(), 137 mSeenOtpNotificationKeys.size()); 138 } 139 logAppBlocked(int uid)140 public void logAppBlocked(int uid) { 141 FrameworkStatsLog.write( 142 FrameworkStatsLog.SENSITIVE_CONTENT_APP_PROTECTION, 143 mSessionId, 144 uid, 145 mUid, 146 FrameworkStatsLog.SENSITIVE_CONTENT_APP_PROTECTION__STATE__BLOCKED 147 ); 148 } 149 logAppUnblocked(int uid)150 public void logAppUnblocked(int uid) { 151 FrameworkStatsLog.write( 152 FrameworkStatsLog.SENSITIVE_CONTENT_APP_PROTECTION, 153 mSessionId, 154 uid, 155 mUid, 156 FrameworkStatsLog.SENSITIVE_CONTENT_APP_PROTECTION__STATE__UNBLOCKED 157 ); 158 } 159 addSeenNotificationKey(String key)160 private void addSeenNotificationKey(String key) { 161 mAllSeenNotificationKeys.add(key); 162 } 163 addSeenOtpNotificationKey(String key)164 private void addSeenOtpNotificationKey(String key) { 165 mAllSeenNotificationKeys.add(key); 166 mSeenOtpNotificationKeys.add(key); 167 } 168 addSeenNotifications( @onNull StatusBarNotification[] notifications, @NonNull RankingMap rankingMap)169 public void addSeenNotifications( 170 @NonNull StatusBarNotification[] notifications, 171 @NonNull RankingMap rankingMap) { 172 for (StatusBarNotification sbn : notifications) { 173 if (sbn == null) { 174 Log.w(TAG, "Unable to parse null notification"); 175 continue; 176 } 177 178 if (notificationHasSensitiveContent(sbn, rankingMap)) { 179 addSeenOtpNotificationKey(sbn.getKey()); 180 } else { 181 addSeenNotificationKey(sbn.getKey()); 182 } 183 } 184 } 185 } 186 187 private final MediaProjectionManager.Callback mProjectionCallback = 188 new MediaProjectionManager.Callback() { 189 @Override 190 public void onStart(MediaProjectionInfo info) { 191 if (DEBUG) Log.d(TAG, "onStart projection: " + info); 192 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, 193 "SensitiveContentProtectionManagerService.onProjectionStart"); 194 try { 195 onProjectionStart(info); 196 } finally { 197 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 198 } 199 } 200 201 @Override 202 public void onStop(MediaProjectionInfo info) { 203 if (DEBUG) Log.d(TAG, "onStop projection: " + info); 204 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, 205 "SensitiveContentProtectionManagerService.onProjectionStop"); 206 try { 207 onProjectionEnd(); 208 } finally { 209 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 210 } 211 } 212 }; 213 214 private final OnWindowRemovedListener mOnWindowRemovedListener = token -> { 215 synchronized (mSensitiveContentProtectionLock) { 216 mPackagesShowingSensitiveContent.removeIf(pkgInfo -> pkgInfo.getWindowToken() == token); 217 } 218 }; 219 SensitiveContentProtectionManagerService(@onNull Context context)220 public SensitiveContentProtectionManagerService(@NonNull Context context) { 221 super(context); 222 if (sensitiveNotificationAppProtection()) { 223 mNotificationListener = new NotificationListener(); 224 } 225 } 226 227 @Override onStart()228 public void onStart() {} 229 230 @Override onBootPhase(int phase)231 public void onBootPhase(int phase) { 232 if (phase != SystemService.PHASE_BOOT_COMPLETED) { 233 return; 234 } 235 236 if (DEBUG) Log.d(TAG, "onBootPhase - PHASE_BOOT_COMPLETED"); 237 init(getContext().getSystemService(MediaProjectionManager.class), 238 LocalServices.getService(WindowManagerInternal.class), 239 LocalServices.getService(PackageManagerInternal.class), 240 getExemptedPackages() 241 ); 242 if (sensitiveContentAppProtection()) { 243 publishBinderService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE, 244 new SensitiveContentProtectionManagerServiceBinder()); 245 } 246 } 247 248 @VisibleForTesting init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager, PackageManagerInternal packageManagerInternal, ArraySet<String> exemptedPackages)249 void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager, 250 PackageManagerInternal packageManagerInternal, ArraySet<String> exemptedPackages) { 251 if (DEBUG) Log.d(TAG, "init"); 252 253 Objects.requireNonNull(projectionManager); 254 Objects.requireNonNull(windowManager); 255 256 mProjectionManager = projectionManager; 257 mWindowManager = windowManager; 258 mPackageManagerInternal = packageManagerInternal; 259 mExemptedPackages = exemptedPackages; 260 261 // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary 262 // handler, delegate, and binder death recipient 263 mProjectionManager.addCallback(mProjectionCallback, getContext().getMainThreadHandler()); 264 265 if (sensitiveNotificationAppProtection()) { 266 try { 267 mNotificationListener.registerAsSystemService( 268 getContext(), 269 new ComponentName(getContext(), NotificationListener.class), 270 UserHandle.USER_ALL); 271 } catch (RemoteException e) { 272 // Intra-process call, should never happen. 273 } 274 } 275 276 if (sensitiveContentAppProtection()) { 277 mWindowManager.registerOnWindowRemovedListener(mOnWindowRemovedListener); 278 } 279 } 280 281 /** Cleanup any callbacks and listeners */ 282 @VisibleForTesting onDestroy()283 void onDestroy() { 284 if (mProjectionManager != null) { 285 mProjectionManager.removeCallback(mProjectionCallback); 286 } 287 if (sensitiveNotificationAppProtection()) { 288 try { 289 mNotificationListener.unregisterAsSystemService(); 290 } catch (RemoteException e) { 291 // Intra-process call, should never happen. 292 } 293 } 294 295 if (mWindowManager != null) { 296 onProjectionEnd(); 297 } 298 } 299 canRecordSensitiveContent(@onNull String packageName)300 private boolean canRecordSensitiveContent(@NonNull String packageName) { 301 return getContext().getPackageManager() 302 .checkPermission(android.Manifest.permission.RECORD_SENSITIVE_CONTENT, 303 packageName) == PackageManager.PERMISSION_GRANTED; 304 } 305 306 // These packages are exempted from screen share protection. getExemptedPackages()307 private ArraySet<String> getExemptedPackages() { 308 return SystemConfig.getInstance().getBugreportWhitelistedPackages(); 309 } 310 onProjectionStart(MediaProjectionInfo projectionInfo)311 private void onProjectionStart(MediaProjectionInfo projectionInfo) { 312 boolean isPackageExempted = (mExemptedPackages != null && mExemptedPackages.contains( 313 projectionInfo.getPackageName())) 314 || canRecordSensitiveContent(projectionInfo.getPackageName()) 315 || isAutofillServiceRecorderPackage(projectionInfo.getUserHandle().getIdentifier(), 316 projectionInfo.getPackageName()); 317 // TODO(b/324447419): move GlobalSettings lookup to background thread 318 boolean isFeatureDisabled = Settings.Global.getInt(getContext().getContentResolver(), 319 DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0; 320 int uid = mPackageManagerInternal.getPackageUid(projectionInfo.getPackageName(), 0, 321 projectionInfo.getUserHandle().getIdentifier()); 322 synchronized (mSensitiveContentProtectionLock) { 323 mMediaProjectionSession = new MediaProjectionSession( 324 uid, isPackageExempted || isFeatureDisabled, new Random().nextLong()); 325 mMediaProjectionSession.logProjectionSessionStart(); 326 327 if (isPackageExempted || isFeatureDisabled) { 328 Log.w(TAG, "projection session is exempted, package =" 329 + projectionInfo.getPackageName() + ", isFeatureDisabled=" 330 + isFeatureDisabled); 331 return; 332 } 333 334 mProjectionActive = true; 335 336 if (sensitiveContentMetricsBugfix()) { 337 mWindowManager.setBlockScreenCaptureForAppsSessionId( 338 mMediaProjectionSession.mSessionId); 339 } 340 341 if (sensitiveNotificationAppProtection()) { 342 updateAppsThatShouldBlockScreenCapture(); 343 } 344 345 if (sensitiveContentAppProtection() && mPackagesShowingSensitiveContent.size() > 0) { 346 mWindowManager.addBlockScreenCaptureForApps(mPackagesShowingSensitiveContent); 347 } 348 } 349 } 350 onProjectionEnd()351 private void onProjectionEnd() { 352 synchronized (mSensitiveContentProtectionLock) { 353 mProjectionActive = false; 354 if (mMediaProjectionSession != null) { 355 mMediaProjectionSession.logProjectionSessionStop(); 356 if (sensitiveContentImprovements()) { 357 mMediaProjectionSession.logAppNotificationsProtected(); 358 } 359 mMediaProjectionSession = null; 360 } 361 362 // notify windowmanager to clear any sensitive notifications observed during projection 363 // session 364 mWindowManager.clearBlockedApps(); 365 } 366 } 367 368 @GuardedBy("mSensitiveContentProtectionLock") updateAppsThatShouldBlockScreenCapture()369 private void updateAppsThatShouldBlockScreenCapture() { 370 RankingMap rankingMap; 371 try { 372 rankingMap = mNotificationListener.getCurrentRanking(); 373 } catch (SecurityException e) { 374 Log.e(TAG, "SensitiveContentProtectionManagerService doesn't have access.", e); 375 rankingMap = null; 376 } 377 378 if (rankingMap == null) { 379 Log.w(TAG, "Ranking map not initialized."); 380 return; 381 } 382 383 updateAppsThatShouldBlockScreenCapture(rankingMap); 384 } 385 386 @GuardedBy("mSensitiveContentProtectionLock") updateAppsThatShouldBlockScreenCapture(@onNull RankingMap rankingMap)387 private void updateAppsThatShouldBlockScreenCapture(@NonNull RankingMap rankingMap) { 388 StatusBarNotification[] notifications; 389 try { 390 notifications = mNotificationListener.getActiveNotifications(); 391 } catch (SecurityException e) { 392 Log.e(TAG, "SensitiveContentProtectionManagerService doesn't have access.", e); 393 notifications = new StatusBarNotification[0]; 394 } 395 396 if (sensitiveContentImprovements() && mMediaProjectionSession != null) { 397 mMediaProjectionSession.addSeenNotifications(notifications, rankingMap); 398 } 399 400 // notify windowmanager of any currently posted sensitive content notifications 401 ArraySet<PackageInfo> packageInfos = 402 getSensitivePackagesFromNotifications(notifications, rankingMap); 403 404 if (packageInfos.size() > 0) { 405 mWindowManager.addBlockScreenCaptureForApps(packageInfos); 406 } 407 } 408 getSensitivePackagesFromNotifications( @onNull StatusBarNotification[] notifications, @NonNull RankingMap rankingMap)409 private static @NonNull ArraySet<PackageInfo> getSensitivePackagesFromNotifications( 410 @NonNull StatusBarNotification[] notifications, @NonNull RankingMap rankingMap) { 411 ArraySet<PackageInfo> sensitivePackages = new ArraySet<>(); 412 for (StatusBarNotification sbn : notifications) { 413 if (sbn == null) { 414 Log.w(TAG, "Unable to parse null notification"); 415 continue; 416 } 417 418 PackageInfo info = getSensitivePackageFromNotification(sbn, rankingMap); 419 if (info != null) { 420 sensitivePackages.add(info); 421 } 422 } 423 return sensitivePackages; 424 } 425 getSensitivePackageFromNotification( @onNull StatusBarNotification sbn, @NonNull RankingMap rankingMap)426 private static @Nullable PackageInfo getSensitivePackageFromNotification( 427 @NonNull StatusBarNotification sbn, @NonNull RankingMap rankingMap) { 428 if (notificationHasSensitiveContent(sbn, rankingMap)) { 429 return new PackageInfo(sbn.getPackageName(), sbn.getUid()); 430 } 431 return null; 432 } 433 notificationHasSensitiveContent( @onNull StatusBarNotification sbn, @NonNull RankingMap rankingMap)434 private static boolean notificationHasSensitiveContent( 435 @NonNull StatusBarNotification sbn, @NonNull RankingMap rankingMap) { 436 NotificationListenerService.Ranking ranking = rankingMap.getRawRankingObject(sbn.getKey()); 437 return ranking != null && ranking.hasSensitiveContent(); 438 } 439 440 @VisibleForTesting 441 class NotificationListener extends NotificationListenerService { 442 @Override onListenerConnected()443 public void onListenerConnected() { 444 super.onListenerConnected(); 445 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, 446 "SensitiveContentProtectionManagerService.onListenerConnected"); 447 try { 448 // Projection started before notification listener was connected 449 synchronized (mSensitiveContentProtectionLock) { 450 if (mProjectionActive) { 451 updateAppsThatShouldBlockScreenCapture(); 452 } 453 } 454 } finally { 455 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 456 } 457 } 458 459 @Override onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap)460 public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { 461 super.onNotificationPosted(sbn, rankingMap); 462 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, 463 "SensitiveContentProtectionManagerService.onNotificationPosted"); 464 try { 465 if (sbn == null) { 466 Log.w(TAG, "Unable to parse null notification"); 467 return; 468 } 469 470 if (rankingMap == null) { 471 Log.w(TAG, "Ranking map not initialized."); 472 return; 473 } 474 475 synchronized (mSensitiveContentProtectionLock) { 476 if (!mProjectionActive) { 477 return; 478 } 479 480 // notify windowmanager of any currently posted sensitive content notifications 481 PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap); 482 483 if (packageInfo != null) { 484 mWindowManager.addBlockScreenCaptureForApps( 485 new ArraySet(Set.of(packageInfo))); 486 } 487 488 if (sensitiveContentImprovements() && mMediaProjectionSession != null) { 489 if (packageInfo != null) { 490 mMediaProjectionSession.addSeenOtpNotificationKey(sbn.getKey()); 491 } else { 492 mMediaProjectionSession.addSeenNotificationKey(sbn.getKey()); 493 } 494 } 495 } 496 } finally { 497 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 498 } 499 } 500 501 @Override onNotificationRankingUpdate(RankingMap rankingMap)502 public void onNotificationRankingUpdate(RankingMap rankingMap) { 503 super.onNotificationRankingUpdate(rankingMap); 504 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, 505 "SensitiveContentProtectionManagerService.onNotificationRankingUpdate"); 506 try { 507 if (rankingMap == null) { 508 Log.w(TAG, "Ranking map not initialized."); 509 return; 510 } 511 512 synchronized (mSensitiveContentProtectionLock) { 513 if (mProjectionActive) { 514 updateAppsThatShouldBlockScreenCapture(rankingMap); 515 } 516 } 517 } finally { 518 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 519 } 520 } 521 } 522 523 /** 524 * Block projection for a package window when the window is showing sensitive content on 525 * the screen, the projection is unblocked when window no more shows sensitive content. 526 * 527 * @param windowToken window where the content is shown. 528 * @param packageName package name. 529 * @param uid uid of the package. 530 * @param isShowingSensitiveContent whether the window is showing sensitive content. 531 */ 532 @VisibleForTesting setSensitiveContentProtection(IBinder windowToken, String packageName, int uid, boolean isShowingSensitiveContent)533 void setSensitiveContentProtection(IBinder windowToken, String packageName, int uid, 534 boolean isShowingSensitiveContent) { 535 synchronized (mSensitiveContentProtectionLock) { 536 // The window token distinguish this package from packages added for notifications. 537 PackageInfo packageInfo = new PackageInfo(packageName, uid, windowToken); 538 // track these packages to protect when screen share starts. 539 if (isShowingSensitiveContent) { 540 mPackagesShowingSensitiveContent.add(packageInfo); 541 if (mPackagesShowingSensitiveContent.size() > 100) { 542 Log.w(TAG, "Unexpectedly large number of sensitive windows, count: " 543 + mPackagesShowingSensitiveContent.size()); 544 } 545 } else { 546 mPackagesShowingSensitiveContent.remove(packageInfo); 547 } 548 if (!mProjectionActive) { 549 return; 550 } 551 552 if (DEBUG) { 553 Log.d(TAG, "setSensitiveContentProtection - current package=" + packageInfo 554 + ", isShowingSensitiveContent=" + isShowingSensitiveContent 555 + ", sensitive packages=" + mPackagesShowingSensitiveContent); 556 } 557 558 ArraySet<PackageInfo> packageInfos = new ArraySet<>(); 559 packageInfos.add(packageInfo); 560 if (isShowingSensitiveContent) { 561 mWindowManager.addBlockScreenCaptureForApps(packageInfos); 562 if (mMediaProjectionSession != null) { 563 mMediaProjectionSession.logAppBlocked(uid); 564 } 565 } else { 566 mWindowManager.removeBlockScreenCaptureForApps(packageInfos); 567 if (mMediaProjectionSession != null) { 568 mMediaProjectionSession.logAppUnblocked(uid); 569 } 570 } 571 } 572 } 573 574 // TODO: b/328251279 - Autofill service exemption is temporary and will be removed in future. isAutofillServiceRecorderPackage(int userId, String projectionPackage)575 private boolean isAutofillServiceRecorderPackage(int userId, String projectionPackage) { 576 String autofillServiceName = Settings.Secure.getStringForUser( 577 getContext().getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, userId); 578 if (DEBUG) { 579 Log.d(TAG, "autofill service for user " + userId + " is " + autofillServiceName); 580 } 581 582 if (autofillServiceName == null) { 583 return false; 584 } 585 ComponentName serviceComponent = ComponentName.unflattenFromString(autofillServiceName); 586 if (serviceComponent == null) { 587 return false; 588 } 589 String autofillServicePackage = serviceComponent.getPackageName(); 590 591 return autofillServicePackage != null 592 && autofillServicePackage.equals(projectionPackage); 593 } 594 595 private final class SensitiveContentProtectionManagerServiceBinder 596 extends ISensitiveContentProtectionManager.Stub { setSensitiveContentProtection(IBinder windowToken, String packageName, boolean isShowingSensitiveContent)597 public void setSensitiveContentProtection(IBinder windowToken, String packageName, 598 boolean isShowingSensitiveContent) { 599 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, 600 "SensitiveContentProtectionManagerService.setSensitiveContentProtection"); 601 try { 602 int callingUid = Binder.getCallingUid(); 603 verifyCallingPackage(callingUid, packageName); 604 final long identity = Binder.clearCallingIdentity(); 605 try { 606 if (isShowingSensitiveContent 607 && mWindowManager.getWindowName(windowToken) == null) { 608 Log.e(TAG, "window token is not know to WMS, can't apply protection," 609 + " token: " + windowToken + ", package: " + packageName); 610 return; 611 } 612 SensitiveContentProtectionManagerService.this.setSensitiveContentProtection( 613 windowToken, packageName, callingUid, isShowingSensitiveContent); 614 } finally { 615 Binder.restoreCallingIdentity(identity); 616 } 617 } finally { 618 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 619 } 620 } 621 verifyCallingPackage(int callingUid, String callingPackage)622 private void verifyCallingPackage(int callingUid, String callingPackage) { 623 if (mPackageManagerInternal.getPackageUid( 624 callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) { 625 throw new SecurityException("Specified calling package [" + callingPackage 626 + "] does not match the calling uid " + callingUid); 627 } 628 } 629 } 630 } 631