Loading services/core/java/com/android/server/SensitiveContentProtectionManagerService.java +98 −28 Original line number Diff line number Diff line Loading @@ -34,11 +34,11 @@ import android.service.notification.StatusBarNotification; import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.SensitiveContentPackages.PackageInfo; import com.android.server.wm.WindowManagerInternal; import java.util.Collections; import java.util.Set; /** Loading @@ -54,6 +54,10 @@ public final class SensitiveContentProtectionManagerService extends SystemServic private @Nullable MediaProjectionManager mProjectionManager; private @Nullable WindowManagerInternal mWindowManager; final Object mSensitiveContentProtectionLock = new Object(); @GuardedBy("mSensitiveContentProtectionLock") private boolean mProjectionActive = false; private final MediaProjectionManager.Callback mProjectionCallback = new MediaProjectionManager.Callback() { @Override Loading Loading @@ -132,14 +136,23 @@ public final class SensitiveContentProtectionManagerService extends SystemServic } private void onProjectionStart() { StatusBarNotification[] notifications; try { notifications = mNotificationListener.getActiveNotifications(); } catch (SecurityException e) { Log.e(TAG, "SensitiveContentProtectionManagerService doesn't have access.", e); notifications = new StatusBarNotification[0]; synchronized (mSensitiveContentProtectionLock) { mProjectionActive = true; updateAppsThatShouldBlockScreenCapture(); } } private void onProjectionEnd() { synchronized (mSensitiveContentProtectionLock) { mProjectionActive = false; // notify windowmanager to clear any sensitive notifications observed during projection // session mWindowManager.clearBlockedApps(); } } private void updateAppsThatShouldBlockScreenCapture() { RankingMap rankingMap; try { rankingMap = mNotificationListener.getCurrentRanking(); Loading @@ -148,41 +161,98 @@ public final class SensitiveContentProtectionManagerService extends SystemServic rankingMap = null; } // notify windowmanager of any currently posted sensitive content notifications Set<PackageInfo> packageInfos = getSensitivePackagesFromNotifications( notifications, rankingMap); updateAppsThatShouldBlockScreenCapture(rankingMap); } mWindowManager.setShouldBlockScreenCaptureForApp(packageInfos); private void updateAppsThatShouldBlockScreenCapture(RankingMap rankingMap) { StatusBarNotification[] notifications; try { notifications = mNotificationListener.getActiveNotifications(); } catch (SecurityException e) { Log.e(TAG, "SensitiveContentProtectionManagerService doesn't have access.", e); notifications = new StatusBarNotification[0]; } private void onProjectionEnd() { // notify windowmanager to clear any sensitive notifications observed during projection // session mWindowManager.setShouldBlockScreenCaptureForApp(Collections.emptySet()); // notify windowmanager of any currently posted sensitive content notifications ArraySet<PackageInfo> packageInfos = getSensitivePackagesFromNotifications( notifications, rankingMap); mWindowManager.addBlockScreenCaptureForApps(packageInfos); } private Set<PackageInfo> getSensitivePackagesFromNotifications( StatusBarNotification[] notifications, RankingMap rankingMap) { private ArraySet<PackageInfo> getSensitivePackagesFromNotifications( @NonNull StatusBarNotification[] notifications, RankingMap rankingMap) { ArraySet<PackageInfo> sensitivePackages = new ArraySet<>(); if (rankingMap == null) { Log.w(TAG, "Ranking map not initialized."); return Collections.emptySet(); return sensitivePackages; } Set<PackageInfo> sensitivePackages = new ArraySet<>(); for (StatusBarNotification sbn : notifications) { NotificationListenerService.Ranking ranking = rankingMap.getRawRankingObject(sbn.getKey()); if (ranking != null && ranking.hasSensitiveContent()) { PackageInfo info = new PackageInfo(sbn.getPackageName(), sbn.getUid()); PackageInfo info = getSensitivePackageFromNotification(sbn, rankingMap); if (info != null) { sensitivePackages.add(info); } } return sensitivePackages; } // TODO(b/317251408): add trigger that updates on onNotificationPosted, // onNotificationRankingUpdate and onListenerConnected private PackageInfo getSensitivePackageFromNotification(StatusBarNotification sbn, RankingMap rankingMap) { if (sbn == null) { Log.w(TAG, "Unable to protect null notification"); return null; } if (rankingMap == null) { Log.w(TAG, "Ranking map not initialized."); return null; } NotificationListenerService.Ranking ranking = rankingMap.getRawRankingObject(sbn.getKey()); if (ranking != null && ranking.hasSensitiveContent()) { return new PackageInfo(sbn.getPackageName(), sbn.getUid()); } return null; } @VisibleForTesting static class NotificationListener extends NotificationListenerService {} class NotificationListener extends NotificationListenerService { @Override public void onListenerConnected() { super.onListenerConnected(); // Projection started before notification listener was connected synchronized (mSensitiveContentProtectionLock) { if (mProjectionActive) { updateAppsThatShouldBlockScreenCapture(); } } } @Override public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { super.onNotificationPosted(sbn, rankingMap); synchronized (mSensitiveContentProtectionLock) { if (!mProjectionActive) { return; } // notify windowmanager of any currently posted sensitive content notifications PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap); if (packageInfo != null) { mWindowManager.addBlockScreenCaptureForApps(new ArraySet(Set.of(packageInfo))); } } } @Override public void onNotificationRankingUpdate(RankingMap rankingMap) { super.onNotificationRankingUpdate(rankingMap); synchronized (mSensitiveContentProtectionLock) { if (mProjectionActive) { updateAppsThatShouldBlockScreenCapture(rankingMap); } } } } } services/core/java/com/android/server/wm/SensitiveContentPackages.java +26 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.util.ArraySet; import java.io.PrintWriter; import java.util.Objects; import java.util.Set; /** * Cache of distinct package/uid pairs that require being blocked from screen capture. This class is Loading @@ -41,10 +40,33 @@ public class SensitiveContentPackages { return false; } /** Replaces the set of package/uid pairs to set that should be blocked from screen capture */ public void setShouldBlockScreenCaptureForApp(@NonNull Set<PackageInfo> packageInfos) { mProtectedPackages.clear(); /** * Adds the set of package/uid pairs to set that should be blocked from screen capture * * @param packageInfos packages to be blocked * @return {@code true} if packages set is modified, {@code false} otherwise. */ public boolean addBlockScreenCaptureForApps(@NonNull ArraySet<PackageInfo> packageInfos) { if (mProtectedPackages.equals(packageInfos)) { // new set is equal to current set of packages, no need to update return false; } mProtectedPackages.addAll(packageInfos); return true; } /** * Clears the set of package/uid pairs that should be blocked from screen capture * * @return {@code true} if packages set is modified, {@code false} otherwise. */ public boolean clearBlockedApps() { if (mProtectedPackages.isEmpty()) { // set was already empty return false; } mProtectedPackages.clear(); return true; } void dump(PrintWriter pw) { Loading services/core/java/com/android/server/wm/WindowManagerInternal.java +10 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.hardware.display.VirtualDisplayConfig; import android.os.Bundle; import android.os.IBinder; import android.os.Message; import android.util.ArraySet; import android.util.Pair; import android.view.ContentRecordingSession; import android.view.Display; Loading Loading @@ -1020,5 +1021,13 @@ public abstract class WindowManagerInternal { * * @param packageInfos set of {@link PackageInfo} whose windows should be blocked from capture */ public abstract void setShouldBlockScreenCaptureForApp(@NonNull Set<PackageInfo> packageInfos); public abstract void addBlockScreenCaptureForApps(@NonNull ArraySet<PackageInfo> packageInfos); /** * Clears apps added to collection of apps in which screen capture should be disabled. * * <p> This clears and resets any existing set or added applications from * * {@link #addBlockScreenCaptureForApps(ArraySet)} */ public abstract void clearBlockedApps(); } services/core/java/com/android/server/wm/WindowManagerService.java +16 −4 Original line number Diff line number Diff line Loading @@ -370,7 +370,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; Loading Loading @@ -8576,14 +8575,27 @@ public class WindowManagerService extends IWindowManager.Stub } @Override public void setShouldBlockScreenCaptureForApp(Set<PackageInfo> packageInfos) { public void addBlockScreenCaptureForApps(ArraySet<PackageInfo> packageInfos) { synchronized (mGlobalLock) { mSensitiveContentPackages.setShouldBlockScreenCaptureForApp(packageInfos); boolean modified = mSensitiveContentPackages.addBlockScreenCaptureForApps(packageInfos); if (modified) { WindowManagerService.this.refreshScreenCaptureDisabled(); } } } @Override public void clearBlockedApps() { synchronized (mGlobalLock) { boolean modified = mSensitiveContentPackages.clearBlockedApps(); if (modified) { WindowManagerService.this.refreshScreenCaptureDisabled(); } } } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { @Override Loading services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceTest.java +347 −28 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/SensitiveContentProtectionManagerService.java +98 −28 Original line number Diff line number Diff line Loading @@ -34,11 +34,11 @@ import android.service.notification.StatusBarNotification; import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.SensitiveContentPackages.PackageInfo; import com.android.server.wm.WindowManagerInternal; import java.util.Collections; import java.util.Set; /** Loading @@ -54,6 +54,10 @@ public final class SensitiveContentProtectionManagerService extends SystemServic private @Nullable MediaProjectionManager mProjectionManager; private @Nullable WindowManagerInternal mWindowManager; final Object mSensitiveContentProtectionLock = new Object(); @GuardedBy("mSensitiveContentProtectionLock") private boolean mProjectionActive = false; private final MediaProjectionManager.Callback mProjectionCallback = new MediaProjectionManager.Callback() { @Override Loading Loading @@ -132,14 +136,23 @@ public final class SensitiveContentProtectionManagerService extends SystemServic } private void onProjectionStart() { StatusBarNotification[] notifications; try { notifications = mNotificationListener.getActiveNotifications(); } catch (SecurityException e) { Log.e(TAG, "SensitiveContentProtectionManagerService doesn't have access.", e); notifications = new StatusBarNotification[0]; synchronized (mSensitiveContentProtectionLock) { mProjectionActive = true; updateAppsThatShouldBlockScreenCapture(); } } private void onProjectionEnd() { synchronized (mSensitiveContentProtectionLock) { mProjectionActive = false; // notify windowmanager to clear any sensitive notifications observed during projection // session mWindowManager.clearBlockedApps(); } } private void updateAppsThatShouldBlockScreenCapture() { RankingMap rankingMap; try { rankingMap = mNotificationListener.getCurrentRanking(); Loading @@ -148,41 +161,98 @@ public final class SensitiveContentProtectionManagerService extends SystemServic rankingMap = null; } // notify windowmanager of any currently posted sensitive content notifications Set<PackageInfo> packageInfos = getSensitivePackagesFromNotifications( notifications, rankingMap); updateAppsThatShouldBlockScreenCapture(rankingMap); } mWindowManager.setShouldBlockScreenCaptureForApp(packageInfos); private void updateAppsThatShouldBlockScreenCapture(RankingMap rankingMap) { StatusBarNotification[] notifications; try { notifications = mNotificationListener.getActiveNotifications(); } catch (SecurityException e) { Log.e(TAG, "SensitiveContentProtectionManagerService doesn't have access.", e); notifications = new StatusBarNotification[0]; } private void onProjectionEnd() { // notify windowmanager to clear any sensitive notifications observed during projection // session mWindowManager.setShouldBlockScreenCaptureForApp(Collections.emptySet()); // notify windowmanager of any currently posted sensitive content notifications ArraySet<PackageInfo> packageInfos = getSensitivePackagesFromNotifications( notifications, rankingMap); mWindowManager.addBlockScreenCaptureForApps(packageInfos); } private Set<PackageInfo> getSensitivePackagesFromNotifications( StatusBarNotification[] notifications, RankingMap rankingMap) { private ArraySet<PackageInfo> getSensitivePackagesFromNotifications( @NonNull StatusBarNotification[] notifications, RankingMap rankingMap) { ArraySet<PackageInfo> sensitivePackages = new ArraySet<>(); if (rankingMap == null) { Log.w(TAG, "Ranking map not initialized."); return Collections.emptySet(); return sensitivePackages; } Set<PackageInfo> sensitivePackages = new ArraySet<>(); for (StatusBarNotification sbn : notifications) { NotificationListenerService.Ranking ranking = rankingMap.getRawRankingObject(sbn.getKey()); if (ranking != null && ranking.hasSensitiveContent()) { PackageInfo info = new PackageInfo(sbn.getPackageName(), sbn.getUid()); PackageInfo info = getSensitivePackageFromNotification(sbn, rankingMap); if (info != null) { sensitivePackages.add(info); } } return sensitivePackages; } // TODO(b/317251408): add trigger that updates on onNotificationPosted, // onNotificationRankingUpdate and onListenerConnected private PackageInfo getSensitivePackageFromNotification(StatusBarNotification sbn, RankingMap rankingMap) { if (sbn == null) { Log.w(TAG, "Unable to protect null notification"); return null; } if (rankingMap == null) { Log.w(TAG, "Ranking map not initialized."); return null; } NotificationListenerService.Ranking ranking = rankingMap.getRawRankingObject(sbn.getKey()); if (ranking != null && ranking.hasSensitiveContent()) { return new PackageInfo(sbn.getPackageName(), sbn.getUid()); } return null; } @VisibleForTesting static class NotificationListener extends NotificationListenerService {} class NotificationListener extends NotificationListenerService { @Override public void onListenerConnected() { super.onListenerConnected(); // Projection started before notification listener was connected synchronized (mSensitiveContentProtectionLock) { if (mProjectionActive) { updateAppsThatShouldBlockScreenCapture(); } } } @Override public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { super.onNotificationPosted(sbn, rankingMap); synchronized (mSensitiveContentProtectionLock) { if (!mProjectionActive) { return; } // notify windowmanager of any currently posted sensitive content notifications PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap); if (packageInfo != null) { mWindowManager.addBlockScreenCaptureForApps(new ArraySet(Set.of(packageInfo))); } } } @Override public void onNotificationRankingUpdate(RankingMap rankingMap) { super.onNotificationRankingUpdate(rankingMap); synchronized (mSensitiveContentProtectionLock) { if (mProjectionActive) { updateAppsThatShouldBlockScreenCapture(rankingMap); } } } } }
services/core/java/com/android/server/wm/SensitiveContentPackages.java +26 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.util.ArraySet; import java.io.PrintWriter; import java.util.Objects; import java.util.Set; /** * Cache of distinct package/uid pairs that require being blocked from screen capture. This class is Loading @@ -41,10 +40,33 @@ public class SensitiveContentPackages { return false; } /** Replaces the set of package/uid pairs to set that should be blocked from screen capture */ public void setShouldBlockScreenCaptureForApp(@NonNull Set<PackageInfo> packageInfos) { mProtectedPackages.clear(); /** * Adds the set of package/uid pairs to set that should be blocked from screen capture * * @param packageInfos packages to be blocked * @return {@code true} if packages set is modified, {@code false} otherwise. */ public boolean addBlockScreenCaptureForApps(@NonNull ArraySet<PackageInfo> packageInfos) { if (mProtectedPackages.equals(packageInfos)) { // new set is equal to current set of packages, no need to update return false; } mProtectedPackages.addAll(packageInfos); return true; } /** * Clears the set of package/uid pairs that should be blocked from screen capture * * @return {@code true} if packages set is modified, {@code false} otherwise. */ public boolean clearBlockedApps() { if (mProtectedPackages.isEmpty()) { // set was already empty return false; } mProtectedPackages.clear(); return true; } void dump(PrintWriter pw) { Loading
services/core/java/com/android/server/wm/WindowManagerInternal.java +10 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.hardware.display.VirtualDisplayConfig; import android.os.Bundle; import android.os.IBinder; import android.os.Message; import android.util.ArraySet; import android.util.Pair; import android.view.ContentRecordingSession; import android.view.Display; Loading Loading @@ -1020,5 +1021,13 @@ public abstract class WindowManagerInternal { * * @param packageInfos set of {@link PackageInfo} whose windows should be blocked from capture */ public abstract void setShouldBlockScreenCaptureForApp(@NonNull Set<PackageInfo> packageInfos); public abstract void addBlockScreenCaptureForApps(@NonNull ArraySet<PackageInfo> packageInfos); /** * Clears apps added to collection of apps in which screen capture should be disabled. * * <p> This clears and resets any existing set or added applications from * * {@link #addBlockScreenCaptureForApps(ArraySet)} */ public abstract void clearBlockedApps(); }
services/core/java/com/android/server/wm/WindowManagerService.java +16 −4 Original line number Diff line number Diff line Loading @@ -370,7 +370,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; Loading Loading @@ -8576,14 +8575,27 @@ public class WindowManagerService extends IWindowManager.Stub } @Override public void setShouldBlockScreenCaptureForApp(Set<PackageInfo> packageInfos) { public void addBlockScreenCaptureForApps(ArraySet<PackageInfo> packageInfos) { synchronized (mGlobalLock) { mSensitiveContentPackages.setShouldBlockScreenCaptureForApp(packageInfos); boolean modified = mSensitiveContentPackages.addBlockScreenCaptureForApps(packageInfos); if (modified) { WindowManagerService.this.refreshScreenCaptureDisabled(); } } } @Override public void clearBlockedApps() { synchronized (mGlobalLock) { boolean modified = mSensitiveContentPackages.clearBlockedApps(); if (modified) { WindowManagerService.this.refreshScreenCaptureDisabled(); } } } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { @Override Loading
services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceTest.java +347 −28 File changed.Preview size limit exceeded, changes collapsed. Show changes