Set importance for processes displaying app-overlays based on visibility

We were previously setting this based on when the window was added and
removed. This can lead to issues where an app isn't allowed to show
alert windows so window manager hides the window after the permission is
revoked, but the window still exist in the system so the process
importance will still be high. We now set the process importance based
on if it has visible window surfaces or not.

Bug: 33256752
Test: cts/.../run-test CtsAppTestCases android.app.cts.AlertWindowsTests
Change-Id: I4e406a94683ec0eecc0911d0195e641c693e1c4a
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 782f9f2..e6fd0ab 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -16,7 +16,10 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -54,6 +57,8 @@
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * This class represents an active client session.  There is generally one
@@ -70,7 +75,11 @@
     private final String mStringName;
     SurfaceSession mSurfaceSession;
     private int mNumWindow = 0;
-    private int mNumOverlayWindow = 0;
+    // Set of visible application overlay window surfaces connected to this session.
+    private final Set<WindowSurfaceController> mAppOverlaySurfaces = new HashSet<>();
+    // Set of visible alert window surfaces connected to this session.
+    private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>();
+    final boolean mCanAddInternalSystemWindow;
     private boolean mClientDead = false;
     private float mLastReportedAnimatorScale;
 
@@ -82,6 +91,8 @@
         mUid = Binder.getCallingUid();
         mPid = Binder.getCallingPid();
         mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
+        mCanAddInternalSystemWindow = service.mContext.checkCallingPermission(
+                INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
         StringBuilder sb = new StringBuilder();
         sb.append("Session{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
@@ -544,7 +555,7 @@
         }
     }
 
-    void windowAddedLocked(int type) {
+    void windowAddedLocked() {
         if (mSurfaceSession == null) {
             if (WindowManagerService.localLOGV) Slog.v(
                 TAG_WM, "First window added to " + this + ", creating SurfaceSession");
@@ -557,24 +568,52 @@
             }
         }
         mNumWindow++;
-        if (type == TYPE_APPLICATION_OVERLAY) {
-            mNumOverlayWindow++;
-            setHasOverlayUi(true);
-        }
     }
 
-    void windowRemovedLocked(int type) {
+    void windowRemovedLocked() {
         mNumWindow--;
-        if (type == TYPE_APPLICATION_OVERLAY) {
-            mNumOverlayWindow--;
-            if (mNumOverlayWindow == 0) {
-                setHasOverlayUi(false);
-            } else if (mNumOverlayWindow < 0) {
-                throw new IllegalStateException("mNumOverlayWindow=" + mNumOverlayWindow
-                        + " less than 0 for session=" + this);
+        killSessionLocked();
+    }
+
+
+    void onWindowSurfaceVisibilityChanged(WindowSurfaceController surfaceController,
+            boolean visible, int type) {
+
+        if (!isSystemAlertWindowType(type)) {
+            return;
+        }
+
+        boolean changed;
+
+        if (!mCanAddInternalSystemWindow) {
+            // We want to track non-system signature apps adding alert windows so we can post an
+            // on-going notification for the user to control their visibility.
+            if (visible) {
+                changed = mAlertWindowSurfaces.add(surfaceController);
+            } else {
+                changed = mAlertWindowSurfaces.remove(surfaceController);
+            }
+
+            if (changed) {
+                // TODO: Update notification.
             }
         }
-        killSessionLocked();
+
+        if (type != TYPE_APPLICATION_OVERLAY) {
+            return;
+        }
+
+        if (visible) {
+            changed = mAppOverlaySurfaces.add(surfaceController);
+        } else {
+            changed = mAppOverlaySurfaces.remove(surfaceController);
+        }
+
+        if (changed) {
+            // Notify activity manager of changes to app overlay windows so it can adjust the
+            // importance score for the process.
+            setHasOverlayUi(!mAppOverlaySurfaces.isEmpty());
+        }
     }
 
     private void killSessionLocked() {
@@ -598,6 +637,7 @@
         }
         mSurfaceSession = null;
         setHasOverlayUi(false);
+        // TODO: Update notification
     }
 
     private void setHasOverlayUi(boolean hasOverlayUi) {
@@ -606,7 +646,8 @@
 
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
-                pw.print(" mNumOverlayWindow="); pw.print(mNumOverlayWindow);
+                pw.print(" mAppOverlaySurfaces="); pw.print(mAppOverlaySurfaces);
+                pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
                 pw.print(" mClientDead="); pw.print(mClientDead);
                 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
     }