Bug: 21589105 Rescoping SYSTEM_ALERT_WINDOW...

AppOpsManager:
Changed the default mode for SYSTEM_ALERT_WINDOW to MODE_DEFAULT instead of
MODE_ALLOWED. Otherwise, an app that did not declare for this permission will
actually be allowed to perform OP_SYSTEM_ALERT_WINDOW, which is undesirable.
This change also allows callers to make their own decision based on the
current policy (M vs pre-M apps).

policy/PhoneWindowManager:
Added additional checks that will handle MODE_DEFAULT - this happens when an app
is newly installed but not yet configured.

wm/WindowManagerService:
Enriched some checks to include the treatment of MODE_DEFAULT - this will allow
pre-M apps uninterupted capability to draw on top of other apps.

Change-Id: I8de77730e158c97587427820cfba721bd5607bea
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bf3bfae..3fb50db 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -765,7 +765,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
-            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3393d7d..c75a418 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -123,6 +123,7 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 
@@ -1827,21 +1828,33 @@
         if (permission != null) {
             if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) {
                 final int callingUid = Binder.getCallingUid();
-                // check if this is a system uid first before bothering with
-                // obtaining package name
+                // system processes will be automatically allowed privilege to draw
                 if (callingUid == Process.SYSTEM_UID) {
                     return WindowManagerGlobal.ADD_OKAY;
                 }
 
+                // check if user has enabled this operation. SecurityException will be thrown if
+                // this app has not been allowed by the user
                 final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid,
                         attrs.packageName);
-                if (mode == AppOpsManager.MODE_DEFAULT) {
-                    if (mContext.checkCallingPermission(permission) !=
-                            PackageManager.PERMISSION_GRANTED) {
+                switch (mode) {
+                    case AppOpsManager.MODE_ALLOWED:
+                    case AppOpsManager.MODE_IGNORED:
+                        // although we return ADD_OKAY for MODE_IGNORED, the added window will
+                        // actually be hidden in WindowManagerService
+                        return WindowManagerGlobal.ADD_OKAY;
+                    case AppOpsManager.MODE_ERRORED:
                         return WindowManagerGlobal.ADD_PERMISSION_DENIED;
-                    }
+                    default:
+                        // in the default mode, we will make a decision here based on
+                        // checkCallingPermission()
+                        if (mContext.checkCallingPermission(permission) !=
+                                PackageManager.PERMISSION_GRANTED) {
+                            return WindowManagerGlobal.ADD_PERMISSION_DENIED;
+                        } else {
+                            return WindowManagerGlobal.ADD_OKAY;
+                        }
                 }
-                return WindowManagerGlobal.ADD_OKAY;
             }
 
             if (mContext.checkCallingOrSelfPermission(permission)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ac4fea8..fd27f42 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2543,8 +2543,10 @@
             win.attach();
             mWindowMap.put(client.asBinder(), win);
             if (win.mAppOp != AppOpsManager.OP_NONE) {
-                if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
-                        != AppOpsManager.MODE_ALLOWED) {
+                int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
+                        win.getOwningPackage());
+                if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
+                        (startOpResult != AppOpsManager.MODE_DEFAULT)) {
                     win.setAppOpVisibilityLw(false);
                 }
             }
@@ -2899,7 +2901,8 @@
                     if (win.mAppOp != AppOpsManager.OP_NONE) {
                         final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
                                 win.getOwningPackage());
-                        win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
+                        win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED ||
+                                mode == AppOpsManager.MODE_DEFAULT);
                     }
                 }
             }