summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--core/res/res/values/attrs_manifest.xml8
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java3
10 files changed, 197 insertions, 19 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);
+ }
+ };
+}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cc52655ad7d2..0350609f9a28 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2058,6 +2058,14 @@
requested. If it does support the feature, it will be as if the manifest didn't
request it at all. -->
<attr name="requiredNotFeature" format="string" />
+ <!-- Optional: set of flags that should apply to this permission request. -->
+ <attr name="usesPermissionFlags">
+ <!-- Strong assertion by a developer that they will never use this
+ permission to derive the physical location of the device, even
+ when the app has been granted the ACCESS_FINE_LOCATION and/or
+ ACCESS_COARSE_LOCATION permissions. -->
+ <flag name="neverForLocation" value="0x1" />
+ </attr>
</declare-styleable>
<!-- <code>required-feature</code> and <code>required-not-feature</code> elements inside
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index c2957780c9d7..b089014b6e1e 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1141,4 +1141,12 @@ public abstract class PackageManagerInternal {
*/
public abstract boolean isPackageFrozen(
@NonNull String packageName, int callingUid, int userId);
+
+ /**
+ * Returns true if the given {@code packageName} has declared the
+ * {@code neverForLocation} flag in the {@code uses-permission} manifest tag
+ * where they request the given {@code permissionName}.
+ */
+ public abstract boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
+ @NonNull String permissionName);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a1da241c6642..508491c39a7b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -252,6 +252,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.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.Resources;
@@ -27264,6 +27265,28 @@ public class PackageManagerService extends IPackageManager.Stub
return PackageManagerService.this.getPackageStartability(
packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
}
+
+ @Override
+ public boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
+ @NonNull String permissionName) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(permissionName);
+ final AndroidPackage pkg;
+ synchronized (mLock) {
+ pkg = mPackages.get(packageName);
+ }
+ if (pkg == null) return 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, permissionName)) {
+ return (usesPermission.usesPermissionFlags
+ & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0;
+ }
+ }
+ return false;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index ba6011140cf1..128cbaaffd74 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -48,6 +48,7 @@ import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
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.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -854,7 +855,7 @@ public class PackageParserTest {
.addProvider(new ParsedProvider())
.addService(new ParsedService())
.addInstrumentation(new ParsedInstrumentation())
- .addRequestedPermission("foo7")
+ .addUsesPermission(new ParsedUsesPermission("foo7", 0))
.addImplicitPermission("foo25")
.addProtectedBroadcast("foo8")
.setStaticSharedLibName("foo23")
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index b5add849c2dc..8e1fc165fb25 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -43,6 +43,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.component.ParsedUsesPermission;
import android.content.res.TypedArray;
import android.os.Environment;
import android.os.UserHandle;
@@ -429,7 +430,7 @@ public class ScanTests {
@Test
public void factoryTestFlagSet() throws Exception {
final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
- .addRequestedPermission(Manifest.permission.FACTORY_TEST);
+ .addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
createBasicScanRequestBuilder(basicPackage).build(),