summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2021-03-11 15:27:00 -0700
committerJeff Sharkey <jsharkey@android.com>2021-03-16 14:29:59 -0600
commitea48e8e8b09ae9edab366b34fc78285aa6fe4aa7 (patch)
tree1a276fa9500710e7dffff6f62074ddd32e10260e /core/java/android
parentb938d78c8fea935122a9e2983e59379b22f05c13 (diff)
Add flags to <uses-permission> manifest tags.
As part of an upcoming feature, developers will need the ability to clearly communicate that they'll never use a permission derive the physical location of the device, regardless of ACCESS_FINE_LOCATION and/or ACCESS_COARSE_LOCATION being granted. The first use of this is the BLUETOOTH permission, but developers may need to communicate this for other permissions such as READ_PHONE_STATE, etc. This change begins parsing this developer declaration as one of multiple "usesPermissionFlags", which are then stored in a new ParsedUsesPermission object. To minimize refactoring, we continue to offer this data through the older String-based APIs. Bug: 181812281 Test: atest FrameworksServicesTests:PackageParserTest Test: atest com.android.server.pm.parsing Test: atest -p core/java/android/content/pm \ core/java/com/android/internal/content \ services/core/java/com/android/server/pm \ services/tests/servicestests/src/com/android/server/pm Change-Id: I2ccda05cf416653d311151591f91ae55a729e05b
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java3
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java27
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageRead.java12
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java39
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedUsesPermission.java90
5 files changed, 154 insertions, 17 deletions
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 29edd405be6b..ba6416d0a396 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -34,6 +34,7 @@ import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
import android.os.Bundle;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -89,7 +90,7 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage addReqFeature(FeatureInfo reqFeature);
- ParsingPackage addRequestedPermission(String permission);
+ ParsingPackage addUsesPermission(ParsedUsesPermission parsedUsesPermission);
ParsingPackage addService(ParsedService parsedService);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 067787d725d9..b3c26abc57dc 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -44,6 +44,7 @@ import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Bundle;
@@ -71,6 +72,7 @@ import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
import java.security.PublicKey;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -227,8 +229,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
protected List<String> adoptPermissions = emptyList();
@NonNull
- @DataClass.ParcelWith(ForInternedStringList.class)
- private List<String> requestedPermissions = emptyList();
+ private List<ParsedUsesPermission> usesPermissions = emptyList();
+
@NonNull
@DataClass.ParcelWith(ForInternedStringList.class)
private List<String> implicitPermissions = emptyList();
@@ -691,9 +693,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
- public ParsingPackageImpl addRequestedPermission(String permission) {
- this.requestedPermissions = CollectionUtils.add(this.requestedPermissions,
- TextUtils.safeIntern(permission));
+ public ParsingPackageImpl addUsesPermission(ParsedUsesPermission permission) {
+ this.usesPermissions = CollectionUtils.add(this.usesPermissions, permission);
return this;
}
@@ -1134,7 +1135,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
dest.writeByteArray(this.restrictUpdateHash);
dest.writeStringList(this.originalPackages);
sForInternedStringList.parcel(this.adoptPermissions, dest, flags);
- sForInternedStringList.parcel(this.requestedPermissions, dest, flags);
+ dest.writeTypedList(this.usesPermissions);
sForInternedStringList.parcel(this.implicitPermissions, dest, flags);
sForStringSet.parcel(this.upgradeKeySets, dest, flags);
dest.writeMap(this.keySetMapping);
@@ -1255,7 +1256,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
this.restrictUpdateHash = in.createByteArray();
this.originalPackages = in.createStringArrayList();
this.adoptPermissions = sForInternedStringList.unparcel(in);
- this.requestedPermissions = sForInternedStringList.unparcel(in);
+ this.usesPermissions = in.createTypedArrayList(ParsedUsesPermission.CREATOR);
this.implicitPermissions = sForInternedStringList.unparcel(in);
this.upgradeKeySets = sForStringSet.unparcel(in);
this.keySetMapping = in.readHashMap(boot);
@@ -1551,11 +1552,23 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
@NonNull
@Override
public List<String> getRequestedPermissions() {
+ final List<ParsedUsesPermission> usesPermissions = getUsesPermissions();
+ final int size = usesPermissions.size();
+ final List<String> requestedPermissions = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ requestedPermissions.add(usesPermissions.get(i).name);
+ }
return requestedPermissions;
}
@NonNull
@Override
+ public List<ParsedUsesPermission> getUsesPermissions() {
+ return usesPermissions;
+ }
+
+ @NonNull
+ @Override
public List<String> getImplicitPermissions() {
return implicitPermissions;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index f7f3e19efdf3..9f5218371393 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -37,6 +37,7 @@ import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.ArraySet;
@@ -45,6 +46,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import java.security.PublicKey;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -193,6 +195,14 @@ public interface ParsingPackageRead extends Parcelable {
List<FeatureInfo> getReqFeatures();
/**
+ * @deprecated consider migrating to {@link #getUsesPermissions} which has
+ * more parsed details, such as flags
+ */
+ @NonNull
+ @Deprecated
+ List<String> getRequestedPermissions();
+
+ /**
* All the permissions declared. This is an effective set, and may include permissions
* transformed from split/migrated permissions from previous versions, so may not be exactly
* what the package declares in its manifest.
@@ -200,7 +210,7 @@ public interface ParsingPackageRead extends Parcelable {
* @see R.styleable#AndroidManifestUsesPermission
*/
@NonNull
- List<String> getRequestedPermissions();
+ List<ParsedUsesPermission> getUsesPermissions();
/**
* Returns the properties set on the application
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 0c033fddf069..2be0157836ae 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -67,6 +67,7 @@ import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedProviderUtils;
import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.component.ParsedServiceUtils;
+import android.content.pm.parsing.component.ParsedUsesPermission;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
@@ -119,6 +120,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
@@ -1206,6 +1208,10 @@ public class ParsingPackageUtils {
requiredNotFeatures.add(feature);
}
+ final int usesPermissionFlags = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_usesPermissionFlags,
+ 0);
+
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1270,14 +1276,31 @@ public class ParsingPackageUtils {
}
}
- if (!pkg.getRequestedPermissions().contains(name)) {
- pkg.addRequestedPermission(name.intern());
- } else {
- Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
- + name + " in package: " + pkg.getPackageName() + " at: "
- + parser.getPositionDescription());
+ // Quietly ignore duplicate permission requests, but fail loudly if
+ // the two requests have conflicting flags
+ boolean found = false;
+ final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+ final int size = usesPermissions.size();
+ for (int i = 0; i < size; i++) {
+ final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+ if (Objects.equals(usesPermission.name, name)) {
+ if (usesPermission.usesPermissionFlags != usesPermissionFlags) {
+ return input.error("Conflicting uses-permissions flags: "
+ + name + " in package: " + pkg.getPackageName() + " at: "
+ + parser.getPositionDescription());
+ } else {
+ Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+ + name + " in package: " + pkg.getPackageName() + " at: "
+ + parser.getPositionDescription());
+ }
+ found = true;
+ break;
+ }
}
+ if (!found) {
+ pkg.addUsesPermission(new ParsedUsesPermission(name, usesPermissionFlags));
+ }
return success;
} finally {
sa.recycle();
@@ -2755,7 +2778,7 @@ public class ParsingPackageUtils {
newPermsMsg.append(' ');
}
newPermsMsg.append(npi.name);
- pkg.addRequestedPermission(npi.name)
+ pkg.addUsesPermission(new ParsedUsesPermission(npi.name, 0))
.addImplicitPermission(npi.name);
}
}
@@ -2777,7 +2800,7 @@ public class ParsingPackageUtils {
for (int in = 0; in < newPerms.size(); in++) {
final String perm = newPerms.get(in);
if (!requestedPermissions.contains(perm)) {
- pkg.addRequestedPermission(perm)
+ pkg.addUsesPermission(new ParsedUsesPermission(perm, 0))
.addImplicitPermission(perm);
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
new file mode 100644
index 000000000000..b9c2e366c2d5
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.parsing.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A {@link android.R.styleable#AndroidManifestUsesPermission
+ * &lt;uses-permission&gt;} tag parsed from the manifest.
+ *
+ * @hide
+ */
+public class ParsedUsesPermission implements Parcelable {
+ /** Name of the permission requested */
+ public @NonNull String name;
+
+ /** Set of flags that should apply to this permission request. */
+ public @UsesPermissionFlags int usesPermissionFlags;
+
+ /**
+ * Strong assertion by a developer that they will never use this permission
+ * to derive the physical location of the device, regardless of
+ * ACCESS_FINE_LOCATION and/or ACCESS_COARSE_LOCATION being granted.
+ */
+ public static final int FLAG_NEVER_FOR_LOCATION = 0x1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_NEVER_FOR_LOCATION
+ })
+ public @interface UsesPermissionFlags {}
+
+ public ParsedUsesPermission(@NonNull String name,
+ @UsesPermissionFlags int usesPermissionFlags) {
+ this.name = name.intern();
+ this.usesPermissionFlags = usesPermissionFlags;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ sForInternedString.parcel(this.name, dest, flags);
+ dest.writeInt(usesPermissionFlags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ protected ParsedUsesPermission(@NonNull Parcel in) {
+ this.name = sForInternedString.unparcel(in);
+ this.usesPermissionFlags = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<ParsedUsesPermission> CREATOR
+ = new Parcelable.Creator<ParsedUsesPermission>() {
+ @Override
+ public ParsedUsesPermission[] newArray(int size) {
+ return new ParsedUsesPermission[size];
+ }
+
+ @Override
+ public ParsedUsesPermission createFromParcel(@NonNull Parcel in) {
+ return new ParsedUsesPermission(in);
+ }
+ };
+}