Merge "Allow permissions to be runtime-only." into oc-dev am: 941e9e2b38
am: 57a9464831

Change-Id: Ibf8b8f13ff5a8819671142e77ee238ba08805d40
diff --git a/api/current.txt b/api/current.txt
index e7b4414..45d2e54 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10809,6 +10809,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_RUNTIME_ONLY = 8192; // 0x2000
     field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
diff --git a/api/system-current.txt b/api/system-current.txt
index 4ade731..cd161efe 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11559,6 +11559,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_RUNTIME_ONLY = 8192; // 0x2000
     field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
diff --git a/api/test-current.txt b/api/test-current.txt
index 10a8bc4..8329e60 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10849,6 +10849,7 @@
     field public static final int PROTECTION_FLAG_PRE23 = 128; // 0x80
     field public static final int PROTECTION_FLAG_PREINSTALLED = 1024; // 0x400
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
+    field public static final int PROTECTION_FLAG_RUNTIME_ONLY = 8192; // 0x2000
     field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
     field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2dfb45f..940447c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3114,6 +3114,7 @@
 
         if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
             if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_EPHEMERAL) == 0
+                    && (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0
                     && (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
                     PermissionInfo.PROTECTION_SIGNATURE) {
                 outError[0] = "<permission>  protectionLevel specifies a non-ephemeral flag but is "
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 0703138..694e607 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -131,6 +131,13 @@
     public static final int PROTECTION_FLAG_EPHEMERAL = 0x1000;
 
     /**
+     * Additional flag for {@link #protectionLevel}, corresponding
+     * to the <code>runtime</code> value of
+     * {@link android.R.attr#protectionLevel}.
+     */
+    public static final int PROTECTION_FLAG_RUNTIME_ONLY = 0x2000;
+
+    /**
      * Mask for {@link #protectionLevel}: the basic protection type.
      */
     public static final int PROTECTION_MASK_BASE = 0xf;
@@ -250,6 +257,9 @@
         if ((level&PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0) {
             protLevel += "|ephemeral";
         }
+        if ((level&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0) {
+            protLevel += "|runtime";
+        }
         return protLevel;
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fe4fafe..c07b50b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -915,7 +915,7 @@
         android:permissionGroup="android.permission-group.PHONE"
         android:label="@string/permlab_answerPhoneCalls"
         android:description="@string/permdesc_answerPhoneCalls"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous|runtime" />
 
 
     <!-- ====================================================================== -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index ed5a42b..3e4b66d7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -245,6 +245,10 @@
         <!-- Additional flag from base permission type: this permission can be granted to ephemeral
              apps -->
         <flag name="ephemeral" value="0x1000" />
+        <!-- Additional flag from base permission type: this permission can only be granted to apps
+             that target runtime permissions ({@link android.os.Build.VERSION_CODES#M} and above)
+             -->
+        <flag name="runtime" value="0x2000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 07c9dec..2100038 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -98,4 +98,8 @@
     public boolean isInstant() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0;
     }
+
+    public boolean isRuntimeOnly() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bf0d0b1..86083c7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2056,6 +2056,7 @@
             }
             if (bp != null && (bp.isRuntime() || bp.isDevelopment())
                     && (!instantApp || bp.isInstant())
+                    && (supportsRuntimePermissions || !bp.isRuntimeOnly())
                     && (grantedPermissions == null
                            || ArrayUtils.contains(grantedPermissions, permission))) {
                 final int flags = permissionsState.getPermissionFlags(permission, userId);
@@ -11415,6 +11416,8 @@
         for (int i=0; i<N; i++) {
             final String name = pkg.requestedPermissions.get(i);
             final BasePermission bp = mSettings.mPermissions.get(name);
+            final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+                    >= Build.VERSION_CODES.M;
 
             if (DEBUG_INSTALL) {
                 Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
@@ -11436,6 +11439,12 @@
                 continue;
             }
 
+            if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
+                Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
+                        + pkg.packageName);
+                continue;
+            }
+
             final String perm = bp.name;
             boolean allowedSig = false;
             int grant = GRANT_DENIED;
@@ -11451,8 +11460,6 @@
             }
 
             final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
-            final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
-                    >= Build.VERSION_CODES.M;
             switch (level) {
                 case PermissionInfo.PROTECTION_NORMAL: {
                     // For all apps normal permissions are install time ones.