Fix issue #17752399: Multiple apps broken by GET_TASKS permission change

Keep around GET_TASKS as a permission available to apps, so apps still
think they have it and don't get all uppity because they don't.

Add a new REAL_GET_TASKS that is the actual permission now.

Plus some temporary compatibility code until everyone can transition
fromn GET_TASKS to REAL_GET_TASKS.

Change-Id: I12c1102eed24844685dcbd2fa3b612811603958f
diff --git a/api/current.txt b/api/current.txt
index eb7891a..17c9dcc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -67,7 +67,7 @@
     field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
-    field public static final java.lang.String GET_TASKS = "android.permission.GET_TASKS";
+    field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index cd6088f..84a7f5d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -931,7 +931,7 @@
      * purposes of control flow will be incorrect.</p>
      *
      * @deprecated As of {@link android.os.Build.VERSION_CODES#L}, this method is
-     * no longer available to third party applications: as the introduction of
+     * no longer available to third party applications: the introduction of
      * document-centric recents means
      * it can leak personal information to the caller.  For backwards compatibility,
      * it will still return a small subset of its data: at least the caller's
@@ -947,9 +947,6 @@
      * 
      * @return Returns a list of RecentTaskInfo records describing each of
      * the recent tasks.
-     * 
-     * @throws SecurityException Throws SecurityException if the caller does
-     * not hold the {@link android.Manifest.permission#GET_TASKS} permission.
      */
     @Deprecated
     public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags)
@@ -976,9 +973,6 @@
      * @return Returns a list of RecentTaskInfo records describing each of
      * the recent tasks.
      *
-     * @throws SecurityException Throws SecurityException if the caller does
-     * not hold the {@link android.Manifest.permission#GET_TASKS} or the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permissions.
      * @hide
      */
     public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId)
@@ -1236,9 +1230,6 @@
      *
      * @return Returns a list of RunningTaskInfo records describing each of
      * the running tasks.
-     *
-     * @throws SecurityException Throws SecurityException if the caller does
-     * not hold the {@link android.Manifest.permission#GET_TASKS} permission.
      */
     @Deprecated
     public List<RunningTaskInfo> getRunningTasks(int maxNum)
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6d9c58b..c37534a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@
 
     int getFlagsForUid(int uid);
 
+    boolean isUidPrivileged(int uid);
+
     String[] getAppOpPermissionPackages(String permissionName);
 
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 03a5e23..6d78127 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1382,10 +1382,25 @@
         android:description="@string/permgroupdesc_appInfo"
         android:priority="220" />
 
-    <!-- @SystemApi Allows an application to get information about the currently
-         or recently running tasks. -->
+    <!-- @deprecated No longer enforced. -->
     <permission android:name="android.permission.GET_TASKS"
         android:permissionGroup="android.permission-group.APP_INFO"
+        android:protectionLevel="normal"
+        android:label="@string/permlab_getTasks"
+        android:description="@string/permdesc_getTasks" />
+
+    <!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
+         give access to task information.  We need this new one because there are
+         many existing apps that use add libraries and such that have validation
+         code to ensure the app has requested the GET_TASKS permission by seeing
+         if it has been granted the permission...  if it hasn't, it kills the app
+         with a message about being upset.  So we need to have it continue to look
+         like the app is getting that permission, even though it will never be
+         checked, and new privileged apps can now request this one for real access.
+         @hide
+         @SystemApi -->
+    <permission android:name="android.permission.REAL_GET_TASKS"
+        android:permissionGroup="android.permission-group.APP_INFO"
         android:protectionLevel="signature|system"
         android:label="@string/permlab_getTasks"
         android:description="@string/permdesc_getTasks" />
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
index 0c502c0..0898fae 100644
--- a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
@@ -60,7 +60,7 @@
     <uses-permission android:name="android.permission.FORCE_BACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
-    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.GLOBAL_SEARCH" />
     <uses-permission android:name="android.permission.HARDWARE_TEST" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9f9dc23..7e6afa6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -39,7 +39,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
     <!-- System tool permissions granted to the shell. -->
-    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
     <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1d629fd..eeb79b9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -64,7 +64,7 @@
     <uses-permission android:name="android.permission.VIBRATE" />
 
     <!-- ActivityManager -->
-    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4a10b73..9e0483d 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8175,13 +8175,8 @@
             if (localLOGV) Slog.v(
                 TAG, "getTasks: max=" + maxNum + ", flags=" + flags);
 
-            final boolean allowed = checkCallingPermission(
-                    android.Manifest.permission.GET_TASKS)
-                    == PackageManager.PERMISSION_GRANTED;
-            if (!allowed) {
-                Slog.w(TAG, "getTasks: caller " + callingUid
-                        + " does not hold GET_TASKS; limiting output");
-            }
+            final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
+                    callingUid);
 
             // TODO: Improve with MRU list from all ActivityStacks.
             mStackSupervisor.getTasksLocked(maxNum, list, callingUid, allowed);
@@ -8218,6 +8213,33 @@
         return rti;
     }
 
+    private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
+        boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
+                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+        if (!allowed) {
+            if (checkPermission(android.Manifest.permission.GET_TASKS,
+                    callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
+                // Temporary compatibility: some existing apps on the system image may
+                // still be requesting the old permission and not switched to the new
+                // one; if so, we'll still allow them full access.  This means we need
+                // to see if they are holding the old permission and are a system app.
+                try {
+                    if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
+                        allowed = true;
+                        Slog.w(TAG, caller + ": caller " + callingUid
+                                + " is using old GET_TASKS but privileged; allowing");
+                    }
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        if (!allowed) {
+            Slog.w(TAG, caller + ": caller " + callingUid
+                    + " does not hold GET_TASKS; limiting output");
+        }
+        return allowed;
+    }
+
     @Override
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
         final int callingUid = Binder.getCallingUid();
@@ -8227,12 +8249,8 @@
         final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
         final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;
         synchronized (this) {
-            final boolean allowed = checkCallingPermission(android.Manifest.permission.GET_TASKS)
-                    == PackageManager.PERMISSION_GRANTED;
-            if (!allowed) {
-                Slog.w(TAG, "getRecentTasks: caller " + callingUid
-                        + " does not hold GET_TASKS; limiting output");
-            }
+            final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+                    callingUid);
             final boolean detailed = checkCallingPermission(
                     android.Manifest.permission.GET_DETAILED_TASKS)
                     == PackageManager.PERMISSION_GRANTED;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 50cb5fc..2dad67521 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2880,6 +2880,28 @@
     }
 
     @Override
+    public boolean isUidPrivileged(int uid) {
+        uid = UserHandle.getAppId(uid);
+        // reader
+        synchronized (mPackages) {
+            Object obj = mSettings.getUserIdLPr(uid);
+            if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+                final Iterator<PackageSetting> it = sus.packages.iterator();
+                while (it.hasNext()) {
+                    if (it.next().isPrivileged()) {
+                        return true;
+                    }
+                }
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return ps.isPrivileged();
+            }
+        }
+        return false;
+    }
+
+    @Override
     public String[] getAppOpPermissionPackages(String permissionName) {
         synchronized (mPackages) {
             ArraySet<String> pkgs = mAppOpPermissionPackages.get(permissionName);
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index f31f4f2..3930fd6 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -16,7 +16,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.google.android.test.activity">
-    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />