summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2020-01-03 20:31:01 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-01-03 20:31:01 +0000
commita574814474efbc4e181e11dc85dce0457eb37393 (patch)
treedf94dab76610d6012a8c1eee8ac387801772cf7a /core/java/android
parent789381b895f6728b4bc78738489bdd0ba1a4828c (diff)
parente52bd98d3f0fb8f1a349e8ff9b75cce0b6cbf6c1 (diff)
Merge changes from topic "appOpFeatureId"
* changes: Restrict the number of features or size of ids. Use Pools for noteOp related data objects Allow apps to define featureIds in the manifest
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/AppOpsManager.java173
-rw-r--r--core/java/android/content/pm/PackageParser.java1
-rw-r--r--core/java/android/content/pm/parsing/AndroidPackage.java4
-rw-r--r--core/java/android/content/pm/parsing/ApkParseUtils.java36
-rw-r--r--core/java/android/content/pm/parsing/ComponentParseUtils.java265
-rw-r--r--core/java/android/content/pm/parsing/PackageImpl.java18
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java3
7 files changed, 457 insertions, 43 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4840963f2633..c94e61a9a041 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -51,6 +51,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseArray;
import android.util.LongSparseLongArray;
+import android.util.Pools;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -2341,15 +2342,31 @@ public class AppOpsManager {
*/
@TestApi
@SystemApi
- @Immutable
- @DataClass(genHiddenConstructor = true)
+ // @DataClass(genHiddenConstructor = true, genHiddenCopyConstructor = true)
+ // genHiddenCopyConstructor does not work for @hide @SystemApi classes
public static final class OpEventProxyInfo implements Parcelable {
/** UID of the proxy app that noted the op */
- private final @IntRange(from = 0) int mUid;
+ private @IntRange(from = 0) int mUid;
/** Package of the proxy that noted the op */
- private final @Nullable String mPackageName;
+ private @Nullable String mPackageName;
/** ID of the feature of the proxy that noted the op */
- private final @Nullable String mFeatureId;
+ private @Nullable String mFeatureId;
+
+ /**
+ * Reinit existing object with new state.
+ *
+ * @param uid UID of the proxy app that noted the op
+ * @param packageName Package of the proxy that noted the op
+ * @param featureId ID of the feature of the proxy that noted the op
+ *
+ * @hide
+ */
+ public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
+ @Nullable String featureId) {
+ mUid = Preconditions.checkArgumentNonnegative(uid);
+ mPackageName = packageName;
+ mFeatureId = featureId;
+ }
@@ -2393,6 +2410,18 @@ public class AppOpsManager {
}
/**
+ * Copy constructor
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public OpEventProxyInfo(@NonNull OpEventProxyInfo orig) {
+ mUid = orig.mUid;
+ mPackageName = orig.mPackageName;
+ mFeatureId = orig.mFeatureId;
+ }
+
+ /**
* UID of the proxy app that noted the op
*/
@DataClass.Generated.Member
@@ -2471,14 +2500,15 @@ public class AppOpsManager {
}
};
+ /*
@DataClass.Generated(
- time = 1576194071700L,
+ time = 1576814974615L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mFeatureId\npublic void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
@Deprecated
private void __metadata() {}
-
+ */
//@formatter:on
// End of generated code
@@ -2490,15 +2520,48 @@ public class AppOpsManager {
*
* @hide
*/
- @Immutable
//@DataClass codegen verifier is broken
public static final class NoteOpEvent implements Parcelable {
/** Time of noteOp event */
- public final @IntRange(from = 0) long noteTime;
+ private @IntRange(from = 0) long mNoteTime;
/** The duration of this event (in case this is a startOp event, -1 otherwise). */
- public final @IntRange(from = -1) long duration;
+ private @IntRange(from = -1) long mDuration;
/** Proxy information of the noteOp event */
- public final @Nullable OpEventProxyInfo proxy;
+ private @Nullable OpEventProxyInfo mProxy;
+
+ /**
+ * Reinit existing object with new state.
+ *
+ * @param noteTime Time of noteOp event
+ * @param duration The duration of this event (in case this is a startOp event,
+ * -1 otherwise).
+ * @param proxy Proxy information of the noteOp event
+ * @param proxyPool The pool to release previous {@link OpEventProxyInfo} to
+ */
+ public void reinit(@IntRange(from = 0) long noteTime,
+ @IntRange(from = -1) long duration,
+ @Nullable OpEventProxyInfo proxy,
+ @NonNull Pools.Pool<OpEventProxyInfo> proxyPool) {
+ mNoteTime = Preconditions.checkArgumentNonnegative(noteTime);
+ mDuration = Preconditions.checkArgumentInRange(duration, -1L, Long.MAX_VALUE,
+ "duration");
+
+ if (mProxy != null) {
+ proxyPool.release(mProxy);
+ }
+ mProxy = proxy;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @hide
+ */
+ public NoteOpEvent(@NonNull NoteOpEvent original) {
+ this(original.mNoteTime, original.mDuration,
+ original.mProxy != null ? new OpEventProxyInfo(original.mProxy) : null);
+ }
+
// Code below generated by codegen v1.0.14.
@@ -2529,19 +2592,43 @@ public class AppOpsManager {
@IntRange(from = 0) long noteTime,
@IntRange(from = -1) long duration,
@Nullable OpEventProxyInfo proxy) {
- this.noteTime = noteTime;
+ this.mNoteTime = noteTime;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, noteTime,
+ IntRange.class, null, mNoteTime,
"from", 0);
- this.duration = duration;
+ this.mDuration = duration;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, duration,
+ IntRange.class, null, mDuration,
"from", -1);
- this.proxy = proxy;
+ this.mProxy = proxy;
// onConstructed(); // You can define this method to get a callback
}
+ /**
+ * Time of noteOp event
+ */
+ @DataClass.Generated.Member
+ public @IntRange(from = 0) long getNoteTime() {
+ return mNoteTime;
+ }
+
+ /**
+ * The duration of this event (in case this is a startOp event, -1 otherwise).
+ */
+ @DataClass.Generated.Member
+ public @IntRange(from = -1) long getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Proxy information of the noteOp event
+ */
+ @DataClass.Generated.Member
+ public @Nullable OpEventProxyInfo getProxy() {
+ return mProxy;
+ }
+
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -2549,11 +2636,11 @@ public class AppOpsManager {
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (proxy != null) flg |= 0x4;
+ if (mProxy != null) flg |= 0x4;
dest.writeByte(flg);
- dest.writeLong(noteTime);
- dest.writeLong(duration);
- if (proxy != null) dest.writeTypedObject(proxy, flags);
+ dest.writeLong(mNoteTime);
+ dest.writeLong(mDuration);
+ if (mProxy != null) dest.writeTypedObject(mProxy, flags);
}
@Override
@@ -2568,20 +2655,19 @@ public class AppOpsManager {
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
- long _noteTime = in.readLong();
- long _duration = in.readLong();
- OpEventProxyInfo _proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(
- OpEventProxyInfo.CREATOR);
+ long noteTime = in.readLong();
+ long duration = in.readLong();
+ OpEventProxyInfo proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(OpEventProxyInfo.CREATOR);
- this.noteTime = _noteTime;
+ this.mNoteTime = noteTime;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, noteTime,
+ IntRange.class, null, mNoteTime,
"from", 0);
- this.duration = _duration;
+ this.mDuration = duration;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, duration,
+ IntRange.class, null, mDuration,
"from", -1);
- this.proxy = _proxy;
+ this.mProxy = proxy;
// onConstructed(); // You can define this method to get a callback
}
@@ -2602,10 +2688,10 @@ public class AppOpsManager {
/*
@DataClass.Generated(
- time = 1574809856220L,
+ time = 1576811792274L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "public final @android.annotation.IntRange(from=0L) long noteTime\npublic final @android.annotation.IntRange(from=-1) long duration\npublic final @android.annotation.Nullable android.app.NoteOpEventProxyInfo proxy\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+ inputSignatures = "private @android.annotation.IntRange(from=0L) long mNoteTime\nprivate @android.annotation.IntRange(from=-1) long mDuration\nprivate @android.annotation.Nullable android.app.OpEventProxyInfo mProxy\npublic void reinit(long,long,android.app.OpEventProxyInfo,android.util.Pools.Pool<android.app.OpEventProxyInfo>)\npublic @java.lang.Override java.lang.Object clone()\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable, java.lang.Cloneable]\n@com.android.internal.util.DataClass")
@Deprecated
private void __metadata() {}
*/
@@ -2751,7 +2837,7 @@ public class AppOpsManager {
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -2847,7 +2933,7 @@ public class AppOpsManager {
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -2922,7 +3008,7 @@ public class AppOpsManager {
return -1;
}
- return lastEvent.duration;
+ return lastEvent.getDuration();
}
/**
@@ -3000,7 +3086,7 @@ public class AppOpsManager {
return null;
}
- return lastEvent.proxy;
+ return lastEvent.getProxy();
}
private static class LongSparseArrayParceling implements
@@ -3304,7 +3390,7 @@ public class AppOpsManager {
toUidState, flags);
if (lastAccessEvent == null || (lastFeatureAccessEvent != null
- && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+ && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
lastAccessEvent = lastFeatureAccessEvent;
}
}
@@ -3335,7 +3421,7 @@ public class AppOpsManager {
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -3418,7 +3504,7 @@ public class AppOpsManager {
toUidState, flags);
if (lastAccessEvent == null || (lastFeatureAccessEvent != null
- && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+ && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
lastAccessEvent = lastFeatureAccessEvent;
}
}
@@ -3449,7 +3535,7 @@ public class AppOpsManager {
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -3544,7 +3630,7 @@ public class AppOpsManager {
return -1;
}
- return lastEvent.duration;
+ return lastEvent.getDuration();
}
/**
@@ -3674,7 +3760,7 @@ public class AppOpsManager {
return null;
}
- return lastEvent.proxy;
+ return lastEvent.getProxy();
}
@@ -7331,7 +7417,8 @@ public class AppOpsManager {
final long key = makeKey(uidState, flag);
NoteOpEvent event = events.get(key);
- if (lastEvent == null || event != null && event.noteTime > lastEvent.noteTime) {
+ if (lastEvent == null
+ || event != null && event.getNoteTime() > lastEvent.getNoteTime()) {
lastEvent = event;
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 47edf2e6fd3a..32803ab8f859 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -202,6 +202,7 @@ public class PackageParser {
public static final String TAG_OVERLAY = "overlay";
public static final String TAG_PACKAGE = "package";
public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
+ public static final String TAG_FEATURE = "feature";
public static final String TAG_PERMISSION = "permission";
public static final String TAG_PERMISSION_GROUP = "permission-group";
public static final String TAG_PERMISSION_TREE = "permission-tree";
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 0562dffc551e..990c8359e698 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -27,6 +27,7 @@ import android.content.pm.PackageUserState;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
@@ -245,6 +246,9 @@ public interface AndroidPackage extends Parcelable {
List<ParsedInstrumentation> getInstrumentations();
@Nullable
+ List<ParsedFeature> getFeatures();
+
+ @Nullable
List<ParsedPermissionGroup> getPermissionGroups();
@Nullable
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 3f2296729891..a001ada8df4a 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -793,6 +793,10 @@ public class ApkParseUtils {
parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
success = parseResult.isSuccess();
break;
+ case PackageParser.TAG_FEATURE:
+ parseResult = parseFeature(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
case PackageParser.TAG_PERMISSION_GROUP:
parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
parser);
@@ -880,6 +884,13 @@ public class ApkParseUtils {
);
}
+ if (!ComponentParseUtils.ParsedFeature.isCombinationValid(parsingPackage.getFeatures())) {
+ return parseInput.error(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Combination <feature> tags are not valid"
+ );
+ }
+
convertNewPermissions(parsingPackage);
convertSplitPermissions(parsingPackage);
@@ -1260,6 +1271,31 @@ public class ApkParseUtils {
return parseInput.success(parsingPackage);
}
+ private static ParseResult parseFeature(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+
+ ComponentParseUtils.ParsedFeature parsedFeature =
+ ComponentParseUtils.parseFeature(res, parser, outError);
+
+ if (parsedFeature == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addFeature(parsedFeature);
+
+ return parseInput.success(parsingPackage);
+ }
+
+
private static ParseResult parsePermissionGroup(
ParseInput parseInput,
ParsingPackage parsingPackage,
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index fc210b266040..7b24d3df92a2 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -24,6 +24,9 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
@@ -47,6 +50,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
@@ -54,6 +58,7 @@ import android.util.TypedValue;
import android.view.Gravity;
import com.android.internal.R;
+import com.android.internal.util.DataClass;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -62,6 +67,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -931,6 +937,186 @@ public class ComponentParseUtils {
};
}
+ /**
+ * A {@link android.R.styleable#AndroidManifestFeature &lt;feature&gt;} tag parsed from the
+ * manifest.
+ */
+ // @DataClass verifier is broken, hence comment out for now
+ public static class ParsedFeature implements Parcelable {
+ /** Maximum length of featureId */
+ public static final int MAX_FEATURE_ID_LEN = 50;
+
+ /** Maximum amount of features per package */
+ private static final int MAX_NUM_FEATURES = 1000;
+
+ /** Id of the feature */
+ public final @NonNull String id;
+
+ /** User visible label fo the feature */
+ public final @StringRes int label;
+
+ /** Ids of previously declared features this feature inherits from */
+ public final @NonNull List<String> inheritFrom;
+
+ /**
+ * @return Is this set of features a valid combination for a single package?
+ */
+ public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
+ if (features == null) {
+ return true;
+ }
+
+ ArraySet<String> featureIds = new ArraySet<>(features.size());
+ ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
+
+ int numFeatures = features.size();
+ if (numFeatures > MAX_NUM_FEATURES) {
+ return false;
+ }
+
+ for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+ boolean wasAdded = featureIds.add(features.get(featureNum).id);
+ if (!wasAdded) {
+ // feature id is not unique
+ return false;
+ }
+ }
+
+ for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+ ParsedFeature feature = features.get(featureNum);
+
+ int numInheritFrom = feature.inheritFrom.size();
+ for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
+ String inheritFrom = feature.inheritFrom.get(inheritFromNum);
+
+ if (featureIds.contains(inheritFrom)) {
+ // Cannot inherit from a feature that is still defined
+ return false;
+ }
+
+ boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
+ if (!wasAdded) {
+ // inheritFrom is not unique
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+
+ // Code below generated by codegen v1.0.14.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new ParsedFeature.
+ *
+ * @param id
+ * Id of the feature
+ * @param label
+ * User visible label fo the feature (if defined as resource)
+ * @param inheritFrom
+ * Ids of previously declared features this feature inherits from
+ */
+ @DataClass.Generated.Member
+ public ParsedFeature(
+ @NonNull String id,
+ @StringRes int label,
+ @NonNull List<String> inheritFrom) {
+ this.id = id;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, id);
+ this.label = label;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ this.inheritFrom = inheritFrom;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeString(id);
+ dest.writeInt(label);
+ dest.writeStringList(inheritFrom);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected ParsedFeature(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String _id = in.readString();
+ int _label = in.readInt();
+ List<String> _inheritFrom = new ArrayList<>();
+ in.readStringList(_inheritFrom);
+
+ this.id = _id;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, id);
+ this.label = _label;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ this.inheritFrom = _inheritFrom;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
+ = new Parcelable.Creator<ParsedFeature>() {
+ @Override
+ public ParsedFeature[] newArray(int size) {
+ return new ParsedFeature[size];
+ }
+
+ @Override
+ public ParsedFeature createFromParcel(@NonNull Parcel in) {
+ return new ParsedFeature(in);
+ }
+ };
+
+ /*@DataClass.Generated(
+ time = 1576783172965L,
+ codegenVersion = "1.0.14",
+ sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java",
+ inputSignatures = "public final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+ */
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+ }
+
public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
public String backgroundPermission;
@@ -2566,6 +2752,85 @@ public class ComponentParseUtils {
return result;
}
+ public static ParsedFeature parseFeature(
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ String featureId;
+ int label;
+ List<String> inheritFrom = null;
+
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
+ if (sa == null) {
+ outError[0] = "<feature> could not be parsed";
+ return null;
+ }
+
+ try {
+ featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
+ 0);
+ if (featureId == null) {
+ outError[0] = "<featureId> does not specify android:featureId";
+ return null;
+ }
+ if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
+ outError[0] = "<featureId> is too long. Max length is "
+ + ParsedFeature.MAX_FEATURE_ID_LEN;
+ return null;
+ }
+
+ label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
+ if (label == Resources.ID_NULL) {
+ outError[0] = "<featureId> does not specify android:label";
+ return null;
+ }
+ } finally {
+ sa.recycle();
+ }
+
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("inherit-from")) {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
+ if (sa == null) {
+ outError[0] = "<inherit-from> could not be parsed";
+ return null;
+ }
+
+ try {
+ String inheritFromId = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
+
+ if (inheritFrom == null) {
+ inheritFrom = new ArrayList<>();
+ }
+ inheritFrom.add(inheritFromId);
+ } finally {
+ sa.recycle();
+ }
+ } else {
+ outError[0] = "Bad element under <feature>: " + tagName;
+ return null;
+ }
+ }
+
+ if (inheritFrom == null) {
+ inheritFrom = Collections.emptyList();
+ } else {
+ ((ArrayList) inheritFrom).trimToSize();
+ }
+
+ return new ParsedFeature(featureId, label, inheritFrom);
+ }
+
public static ParsedPermission parsePermission(
ParsingPackage parsingPackage,
Resources res,
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 18dee23dc690..8677fced18fa 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -36,6 +36,7 @@ import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
@@ -175,6 +176,9 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
private ArrayList<ComponentParseUtils.ParsedProvider> providers;
@Nullable
+ private ArrayList<ComponentParseUtils.ParsedFeature> features;
+
+ @Nullable
private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
@Nullable
@@ -580,6 +584,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
return permissions;
}
+ @Nullable
+ @Override
+ public List<ParsedFeature> getFeatures() {
+ return features;
+ }
+
@Override
public String getCpuAbiOverride() {
return cpuAbiOverride;
@@ -792,6 +802,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
}
@Override
+ public PackageImpl addFeature(ParsedFeature feature) {
+ this.features = ArrayUtils.add(this.features, feature);
+ return this;
+ }
+
+ @Override
public PackageImpl addPermission(ParsedPermission permission) {
this.permissions = ArrayUtils.add(this.permissions, permission);
return this;
@@ -3021,6 +3037,7 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
dest.writeTypedList(this.receivers);
dest.writeTypedList(this.services);
dest.writeTypedList(this.providers);
+ dest.writeTypedList(this.features);
dest.writeTypedList(this.permissions);
dest.writeTypedList(this.permissionGroups);
dest.writeTypedList(this.instrumentations);
@@ -3173,6 +3190,7 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
this.services = in.createTypedArrayList(ParsedService.CREATOR);
this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+ this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 47dac5584c89..411c74991594 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -24,6 +24,7 @@ import android.content.pm.FeatureInfo;
import android.content.pm.PackageParser;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
@@ -64,6 +65,8 @@ public interface ParsingPackage extends AndroidPackage {
ParsingPackage addOverlayable(String overlayableName, String actorName);
+ ParsingPackage addFeature(ParsedFeature permission);
+
ParsingPackage addPermission(ParsedPermission permission);
ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);