Introduce maxSdkVersion for <uses-permission>

This way an application can automatically sunset its permission requests
when running on later versions of the OS where those permissions are no
longer relevant, but may be alarming to the user.  A canonical example
is WRITE_EXTERNAL_STORAGE, which as of KLP becomes unnecessary for an app
to use the external storage volume solely for its own large-data needs,
without the need for actual file-system sharing among multiple apps.

Bug 9761041

Change-Id: I60130af3a108fe4a750c356038a1c8cb897e9c8b
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4494e69..2e25177 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1441,18 +1441,29 @@
 */
         boolean required = true; // Optional <uses-permission> not supported
 
+        int maxSdkVersion = 0;
+        TypedValue val = sa.peekValue(
+                com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+        if (val != null) {
+            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+                maxSdkVersion = val.data;
+            }
+        }
+
         sa.recycle();
 
-        if (name != null) {
-            int index = pkg.requestedPermissions.indexOf(name);
-            if (index == -1) {
-                pkg.requestedPermissions.add(name.intern());
-                pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
-            } else {
-                if (pkg.requestedPermissionsRequired.get(index) != required) {
-                    outError[0] = "conflicting <uses-permission> entries";
-                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-                    return false;
+        if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
+            if (name != null) {
+                int index = pkg.requestedPermissions.indexOf(name);
+                if (index == -1) {
+                    pkg.requestedPermissions.add(name.intern());
+                    pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+                } else {
+                    if (pkg.requestedPermissionsRequired.get(index) != required) {
+                        outError[0] = "conflicting <uses-permission> entries";
+                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                        return false;
+                    }
                 }
             }
         }
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d2ada7a..80810d5 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1048,6 +1048,11 @@
         tag; often this is one of the {@link android.Manifest.permission standard
         system permissions}. -->
         <attr name="name" />
+        <!-- Optional: specify the maximum version of the Android OS for which the
+             application wishes to request the permission.  When running on a version
+             of Android higher than the number given here, the permission will not
+             be requested.  -->
+        <attr name="maxSdkVersion" format="integer" />
         <!--  Specify whether this permission is required for the application.
               The default is true, meaning the application requires the
               permission, and it must always be granted when it is installed.
@@ -1129,7 +1134,7 @@
              on.  You can use this to ensure your application is filtered out
              of later versions of the platform when you know you have
              incompatibility with them. -->
-        <attr name="maxSdkVersion" format="integer" />
+        <attr name="maxSdkVersion" />
     </declare-styleable>
     
     <!-- The <code>library</code> tag declares that this apk is providing itself