Merge "Add flags to <uses-permission> manifest tags." into sc-dev

This commit is contained in:
Jeff Sharkey
2021-03-19 00:06:12 +00:00
committed by Android (Google) Code Review
10 changed files with 197 additions and 19 deletions

View File

@@ -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);

View File

@@ -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,9 +1552,21 @@ 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() {

View File

@@ -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;
@@ -192,6 +194,14 @@ public interface ParsingPackageRead extends Parcelable {
@NonNull
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
@@ -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

View File

@@ -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);
}
}

View File

@@ -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);
}
};
}

View File

@@ -2063,6 +2063,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

View File

@@ -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);
}

View File

@@ -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;
@@ -27322,6 +27323,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;
}
}

View File

@@ -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")

View File

@@ -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(),