Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7cf50ee authored by Richard MacGregor's avatar Richard MacGregor
Browse files

Trigger window sensitive on notification updates

Update apps that should block screen capture on new notification or
notification ranking updates

Bug: 317251408
Flag: ACONFIG com.android.server.notification.sensitive_notification_app_protection DISABLED
Test: atest SensitiveContentProtectionManagerServiceTest
Test: atest SensitiveContentPackagesTest
Test: atest WindowManagerServiceTests
Test: atest WindowStateTests
Change-Id: I2ea30459f37c1e2a831a161b2f62e7a7f6414ac1
parent 28209a0c
Loading
Loading
Loading
Loading
+98 −28
Original line number Diff line number Diff line
@@ -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;

/**
@@ -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
@@ -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();
@@ -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);
                }
            }
        }
    }
}
+26 −4
Original line number Diff line number Diff line
@@ -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
@@ -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) {
+10 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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();
}
+16 −4
Original line number Diff line number Diff line
@@ -369,7 +369,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;
@@ -8566,14 +8565,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
+347 −28

File changed.

Preview size limit exceeded, changes collapsed.

Loading