diff options
| author | Philip P. Moltmann <moltmann@google.com> | 2020-01-03 20:31:01 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-01-03 20:31:01 +0000 |
| commit | a574814474efbc4e181e11dc85dce0457eb37393 (patch) | |
| tree | df94dab76610d6012a8c1eee8ac387801772cf7a /core/java/android | |
| parent | 789381b895f6728b4bc78738489bdd0ba1a4828c (diff) | |
| parent | e52bd98d3f0fb8f1a349e8ff9b75cce0b6cbf6c1 (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')
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 <feature>} 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); |
