PackageParser: Add serialization mechanism for parse results.
Also adds unit tests that assert that the cached value is equivalent to the parsed value. bug: 30792387 Test: PackageParserTest Change-Id: Ibf6dfd1225243b436e3d7473170c2ccc31cfbbd7
This commit is contained in:
@@ -1883,7 +1883,8 @@ public class IntentFilter implements Parcelable {
|
||||
*/
|
||||
}
|
||||
|
||||
private IntentFilter(Parcel source) {
|
||||
/** @hide */
|
||||
public IntentFilter(Parcel source) {
|
||||
mActions = new ArrayList<String>();
|
||||
source.readStringList(mActions);
|
||||
if (source.readInt() != 0) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
@@ -65,6 +67,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -80,6 +83,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.zip.ZipEntry;
|
||||
@@ -307,14 +311,16 @@ public class PackageParser {
|
||||
}
|
||||
}
|
||||
|
||||
static class ParseComponentArgs extends ParsePackageItemArgs {
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static class ParseComponentArgs extends ParsePackageItemArgs {
|
||||
final String[] sepProcesses;
|
||||
final int processRes;
|
||||
final int descriptionRes;
|
||||
final int enabledRes;
|
||||
int flags;
|
||||
|
||||
ParseComponentArgs(Package _owner, String[] _outError,
|
||||
public ParseComponentArgs(Package _owner, String[] _outError,
|
||||
int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
|
||||
int _bannerRes,
|
||||
String[] _sepProcesses, int _processRes,
|
||||
@@ -874,12 +880,24 @@ public class PackageParser {
|
||||
|
||||
@VisibleForTesting
|
||||
protected Package fromCacheEntry(byte[] bytes) throws IOException {
|
||||
return null;
|
||||
Parcel p = Parcel.obtain();
|
||||
p.unmarshall(bytes, 0, bytes.length);
|
||||
p.setDataPosition(0);
|
||||
|
||||
PackageParser.Package pkg = new PackageParser.Package(p);
|
||||
p.recycle();
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected byte[] toCacheEntry(Package pkg) throws IOException {
|
||||
return null;
|
||||
Parcel p = Parcel.obtain();
|
||||
pkg.writeToParcel(p, 0 /* flags */);
|
||||
byte[] serialized = p.marshall();
|
||||
p.recycle();
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1516,7 +1534,7 @@ public class PackageParser {
|
||||
final Certificate[][] certificates;
|
||||
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
|
||||
// TODO: factor signature related items out of Package object
|
||||
final Package tempPkg = new Package(null);
|
||||
final Package tempPkg = new Package((String) null);
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
|
||||
try {
|
||||
collectCertificates(tempPkg, apkFile, 0 /*parseFlags*/);
|
||||
@@ -3623,6 +3641,13 @@ public class PackageParser {
|
||||
private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
|
||||
String[] outError, String tag, TypedArray sa, boolean nameRequired,
|
||||
int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
|
||||
// This case can only happen in unit tests where we sometimes need to create fakes
|
||||
// of various package parser data structures.
|
||||
if (sa == null) {
|
||||
outError[0] = tag + " does not contain any attributes";
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = sa.getNonConfigurationString(nameRes, 0);
|
||||
if (name == null) {
|
||||
if (nameRequired) {
|
||||
@@ -5113,7 +5138,7 @@ public class PackageParser {
|
||||
* Representation of a full package parsed from APK files on disk. A package
|
||||
* consists of a single base APK, and zero or more split APKs.
|
||||
*/
|
||||
public final static class Package {
|
||||
public final static class Package implements Parcelable {
|
||||
|
||||
public String packageName;
|
||||
|
||||
@@ -5154,7 +5179,7 @@ public class PackageParser {
|
||||
public boolean baseHardwareAccelerated;
|
||||
|
||||
// For now we only support one application per package.
|
||||
public final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
public ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
|
||||
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
|
||||
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
|
||||
@@ -5578,13 +5603,296 @@ public class PackageParser {
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " " + packageName + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Package(Parcel dest) {
|
||||
// We use the boot classloader for all classes that we load.
|
||||
final ClassLoader boot = Object.class.getClassLoader();
|
||||
|
||||
packageName = dest.readString();
|
||||
splitNames = dest.readStringArray();
|
||||
volumeUuid = dest.readString();
|
||||
codePath = dest.readString();
|
||||
baseCodePath = dest.readString();
|
||||
splitCodePaths = dest.readStringArray();
|
||||
baseRevisionCode = dest.readInt();
|
||||
splitRevisionCodes = dest.createIntArray();
|
||||
splitFlags = dest.createIntArray();
|
||||
splitPrivateFlags = dest.createIntArray();
|
||||
baseHardwareAccelerated = (dest.readInt() == 1);
|
||||
applicationInfo = dest.readParcelable(boot);
|
||||
|
||||
// We don't serialize the "owner" package and the application info object for each of
|
||||
// these components, in order to save space and to avoid circular dependencies while
|
||||
// serialization. We need to fix them all up here.
|
||||
dest.readParcelableList(permissions, boot);
|
||||
fixupOwner(permissions);
|
||||
dest.readParcelableList(permissionGroups, boot);
|
||||
fixupOwner(permissionGroups);
|
||||
dest.readParcelableList(activities, boot);
|
||||
fixupOwner(activities);
|
||||
dest.readParcelableList(receivers, boot);
|
||||
fixupOwner(receivers);
|
||||
dest.readParcelableList(providers, boot);
|
||||
fixupOwner(providers);
|
||||
dest.readParcelableList(services, boot);
|
||||
fixupOwner(services);
|
||||
dest.readParcelableList(instrumentation, boot);
|
||||
fixupOwner(instrumentation);
|
||||
|
||||
dest.readStringList(requestedPermissions);
|
||||
protectedBroadcasts = dest.createStringArrayList();
|
||||
parentPackage = dest.readParcelable(boot);
|
||||
|
||||
childPackages = new ArrayList<>();
|
||||
dest.readParcelableList(childPackages, boot);
|
||||
if (childPackages.size() == 0) {
|
||||
childPackages = null;
|
||||
}
|
||||
|
||||
libraryNames = dest.createStringArrayList();
|
||||
usesLibraries = dest.createStringArrayList();
|
||||
usesOptionalLibraries = dest.createStringArrayList();
|
||||
usesLibraryFiles = dest.readStringArray();
|
||||
|
||||
preferredActivityFilters = new ArrayList<>();
|
||||
dest.readParcelableList(preferredActivityFilters, boot);
|
||||
if (preferredActivityFilters.size() == 0) {
|
||||
preferredActivityFilters = null;
|
||||
}
|
||||
|
||||
mOriginalPackages = dest.createStringArrayList();
|
||||
mRealPackage = dest.readString();
|
||||
mAdoptPermissions = dest.createStringArrayList();
|
||||
mAppMetaData = dest.readBundle();
|
||||
mVersionCode = dest.readInt();
|
||||
mVersionName = dest.readString();
|
||||
mSharedUserId = dest.readString();
|
||||
mSharedUserLabel = dest.readInt();
|
||||
|
||||
mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
|
||||
mCertificates = (Certificate[][]) dest.readSerializable();
|
||||
|
||||
mPreferredOrder = dest.readInt();
|
||||
|
||||
// long[] packageUsageTimeMillis is not persisted because it isn't information that
|
||||
// is parsed from the APK.
|
||||
|
||||
// Object mExtras is not persisted because it is not information that is read from
|
||||
// the APK, rather, it is supplied by callers.
|
||||
|
||||
|
||||
configPreferences = new ArrayList<>();
|
||||
dest.readParcelableList(configPreferences, boot);
|
||||
if (configPreferences.size() == 0) {
|
||||
configPreferences = null;
|
||||
}
|
||||
|
||||
reqFeatures = new ArrayList<>();
|
||||
dest.readParcelableList(reqFeatures, boot);
|
||||
if (reqFeatures.size() == 0) {
|
||||
reqFeatures = null;
|
||||
}
|
||||
|
||||
featureGroups = new ArrayList<>();
|
||||
dest.readParcelableList(featureGroups, boot);
|
||||
if (featureGroups.size() == 0) {
|
||||
featureGroups = null;
|
||||
}
|
||||
|
||||
installLocation = dest.readInt();
|
||||
coreApp = (dest.readInt() == 1);
|
||||
mRequiredForAllUsers = (dest.readInt() == 1);
|
||||
mRestrictedAccountType = dest.readString();
|
||||
mRequiredAccountType = dest.readString();
|
||||
mOverlayTarget = dest.readString();
|
||||
mOverlayPriority = dest.readInt();
|
||||
mTrustedOverlay = (dest.readInt() == 1);
|
||||
mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
|
||||
mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
|
||||
|
||||
mKeySetMapping = readKeySetMapping(dest);
|
||||
|
||||
cpuAbiOverride = dest.readString();
|
||||
use32bitAbi = (dest.readInt() == 1);
|
||||
restrictUpdateHash = dest.createByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the package owner and the the {@code applicationInfo} for every component
|
||||
* owner by this package.
|
||||
*/
|
||||
private void fixupOwner(List<? extends Component<?>> list) {
|
||||
if (list != null) {
|
||||
for (Component<?> c : list) {
|
||||
c.owner = this;
|
||||
if (c instanceof Activity) {
|
||||
((Activity) c).info.applicationInfo = this.applicationInfo;
|
||||
} else if (c instanceof Service) {
|
||||
((Service) c).info.applicationInfo = this.applicationInfo;
|
||||
} else if (c instanceof Provider) {
|
||||
((Provider) c).info.applicationInfo = this.applicationInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(packageName);
|
||||
dest.writeStringArray(splitNames);
|
||||
dest.writeString(volumeUuid);
|
||||
dest.writeString(codePath);
|
||||
dest.writeString(baseCodePath);
|
||||
dest.writeStringArray(splitCodePaths);
|
||||
dest.writeInt(baseRevisionCode);
|
||||
dest.writeIntArray(splitRevisionCodes);
|
||||
dest.writeIntArray(splitFlags);
|
||||
dest.writeIntArray(splitPrivateFlags);
|
||||
dest.writeInt(baseHardwareAccelerated ? 1 : 0);
|
||||
dest.writeParcelable(applicationInfo, flags);
|
||||
|
||||
dest.writeParcelableList(permissions, flags);
|
||||
dest.writeParcelableList(permissionGroups, flags);
|
||||
dest.writeParcelableList(activities, flags);
|
||||
dest.writeParcelableList(receivers, flags);
|
||||
dest.writeParcelableList(providers, flags);
|
||||
dest.writeParcelableList(services, flags);
|
||||
dest.writeParcelableList(instrumentation, flags);
|
||||
|
||||
dest.writeStringList(requestedPermissions);
|
||||
dest.writeStringList(protectedBroadcasts);
|
||||
dest.writeParcelable(parentPackage, flags);
|
||||
dest.writeParcelableList(childPackages, flags);
|
||||
dest.writeStringList(libraryNames);
|
||||
dest.writeStringList(usesLibraries);
|
||||
dest.writeStringList(usesOptionalLibraries);
|
||||
dest.writeStringArray(usesLibraryFiles);
|
||||
|
||||
dest.writeParcelableList(preferredActivityFilters, flags);
|
||||
|
||||
dest.writeStringList(mOriginalPackages);
|
||||
dest.writeString(mRealPackage);
|
||||
dest.writeStringList(mAdoptPermissions);
|
||||
dest.writeBundle(mAppMetaData);
|
||||
dest.writeInt(mVersionCode);
|
||||
dest.writeString(mVersionName);
|
||||
dest.writeString(mSharedUserId);
|
||||
dest.writeInt(mSharedUserLabel);
|
||||
|
||||
dest.writeParcelableArray(mSignatures, flags);
|
||||
dest.writeSerializable(mCertificates);
|
||||
|
||||
dest.writeInt(mPreferredOrder);
|
||||
|
||||
// long[] packageUsageTimeMillis is not persisted because it isn't information that
|
||||
// is parsed from the APK.
|
||||
|
||||
// Object mExtras is not persisted because it is not information that is read from
|
||||
// the APK, rather, it is supplied by callers.
|
||||
|
||||
dest.writeParcelableList(configPreferences, flags);
|
||||
dest.writeParcelableList(reqFeatures, flags);
|
||||
dest.writeParcelableList(featureGroups, flags);
|
||||
|
||||
dest.writeInt(installLocation);
|
||||
dest.writeInt(coreApp ? 1 : 0);
|
||||
dest.writeInt(mRequiredForAllUsers ? 1 : 0);
|
||||
dest.writeString(mRestrictedAccountType);
|
||||
dest.writeString(mRequiredAccountType);
|
||||
dest.writeString(mOverlayTarget);
|
||||
dest.writeInt(mOverlayPriority);
|
||||
dest.writeInt(mTrustedOverlay ? 1 : 0);
|
||||
dest.writeArraySet(mSigningKeys);
|
||||
dest.writeArraySet(mUpgradeKeySets);
|
||||
writeKeySetMapping(dest, mKeySetMapping);
|
||||
dest.writeString(cpuAbiOverride);
|
||||
dest.writeInt(use32bitAbi ? 1 : 0);
|
||||
dest.writeByteArray(restrictUpdateHash);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
|
||||
*/
|
||||
private static void writeKeySetMapping(
|
||||
Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) {
|
||||
if (keySetMapping == null) {
|
||||
dest.writeInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final int N = keySetMapping.size();
|
||||
dest.writeInt(N);
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
dest.writeString(keySetMapping.keyAt(i));
|
||||
ArraySet<PublicKey> keys = keySetMapping.valueAt(i);
|
||||
if (keys == null) {
|
||||
dest.writeInt(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
final int M = keys.size();
|
||||
dest.writeInt(M);
|
||||
for (int j = 0; j < M; j++) {
|
||||
dest.writeSerializable(keys.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a keyset mapping from the given parcel at the given data position. May return
|
||||
* {@code null} if the serialized mapping was {@code null}.
|
||||
*/
|
||||
private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) {
|
||||
final int N = in.readInt();
|
||||
if (N == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
String key = in.readString();
|
||||
final int M = in.readInt();
|
||||
if (M == -1) {
|
||||
keySetMapping.put(key, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
ArraySet<PublicKey> keys = new ArraySet<>(M);
|
||||
for (int j = 0; j < M; ++j) {
|
||||
PublicKey pk = (PublicKey) in.readSerializable();
|
||||
keys.add(pk);
|
||||
}
|
||||
|
||||
keySetMapping.put(key, keys);
|
||||
}
|
||||
|
||||
return keySetMapping;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() {
|
||||
public Package createFromParcel(Parcel in) {
|
||||
return new Package(in);
|
||||
}
|
||||
|
||||
public Package[] newArray(int size) {
|
||||
return new Package[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class Component<II extends IntentInfo> {
|
||||
public final Package owner;
|
||||
public static abstract class Component<II extends IntentInfo> {
|
||||
public final ArrayList<II> intents;
|
||||
public final String className;
|
||||
|
||||
public Bundle metaData;
|
||||
public Package owner;
|
||||
|
||||
ComponentName componentName;
|
||||
String componentShortName;
|
||||
@@ -5655,6 +5963,83 @@ public class PackageParser {
|
||||
return componentName;
|
||||
}
|
||||
|
||||
protected Component(Parcel in) {
|
||||
className = in.readString();
|
||||
metaData = in.readBundle();
|
||||
intents = createIntentsList(in);
|
||||
|
||||
owner = null;
|
||||
}
|
||||
|
||||
protected void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(className);
|
||||
dest.writeBundle(metaData);
|
||||
|
||||
writeIntentsList(intents, dest, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Implementation note: The serialized form for the intent list also contains the name
|
||||
* of the concrete class that's stored in the list, and assumes that every element of the
|
||||
* list is of the same type. This is very similar to the original parcelable mechanism.
|
||||
* We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
|
||||
* and is public API. It also declares Parcelable related methods as final which means
|
||||
* we can't extend them. The approach of using composition instead of inheritance leads to
|
||||
* a large set of cascading changes in the PackageManagerService, which seem undesirable.
|
||||
*
|
||||
* <p>
|
||||
* <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
|
||||
* to make sure their owner fields are consistent. See {@code fixupOwner}.
|
||||
*/
|
||||
private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out,
|
||||
int flags) {
|
||||
if (list == null) {
|
||||
out.writeInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final int N = list.size();
|
||||
out.writeInt(N);
|
||||
|
||||
// Don't bother writing the component name if the list is empty.
|
||||
if (N > 0) {
|
||||
IntentInfo info = list.get(0);
|
||||
out.writeString(info.getClass().getName());
|
||||
|
||||
for (int i = 0; i < N;i++) {
|
||||
list.get(i).writeIntentInfoToParcel(out, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) {
|
||||
int N = in.readInt();
|
||||
if (N == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (N == 0) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
|
||||
String componentName = in.readString();
|
||||
final ArrayList<T> intentsList;
|
||||
try {
|
||||
final Class<T> cls = (Class<T>) Class.forName(componentName);
|
||||
final Constructor<T> cons = cls.getConstructor(Parcel.class);
|
||||
|
||||
intentsList = new ArrayList<>(N);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
intentsList.add(cons.newInstance(in));
|
||||
}
|
||||
} catch (ReflectiveOperationException ree) {
|
||||
throw new AssertionError("Unable to construct intent list for: " + componentName);
|
||||
}
|
||||
|
||||
return intentsList;
|
||||
}
|
||||
|
||||
public void appendComponentShortName(StringBuilder sb) {
|
||||
ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
|
||||
}
|
||||
@@ -5669,7 +6054,7 @@ public class PackageParser {
|
||||
}
|
||||
}
|
||||
|
||||
public final static class Permission extends Component<IntentInfo> {
|
||||
public final static class Permission extends Component<IntentInfo> implements Parcelable {
|
||||
public final PermissionInfo info;
|
||||
public boolean tree;
|
||||
public PermissionGroup group;
|
||||
@@ -5694,9 +6079,40 @@ public class PackageParser {
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " " + info.name + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(info, flags);
|
||||
dest.writeInt(tree ? 1 : 0);
|
||||
dest.writeParcelable(group, flags);
|
||||
}
|
||||
|
||||
private Permission(Parcel in) {
|
||||
super(in);
|
||||
final ClassLoader boot = Object.class.getClassLoader();
|
||||
info = in.readParcelable(boot);
|
||||
tree = (in.readInt() == 1);
|
||||
group = in.readParcelable(boot);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() {
|
||||
public Permission createFromParcel(Parcel in) {
|
||||
return new Permission(in);
|
||||
}
|
||||
|
||||
public Permission[] newArray(int size) {
|
||||
return new Permission[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public final static class PermissionGroup extends Component<IntentInfo> {
|
||||
public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
|
||||
public final PermissionGroupInfo info;
|
||||
|
||||
public PermissionGroup(Package _owner) {
|
||||
@@ -5719,6 +6135,32 @@ public class PackageParser {
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " " + info.name + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(info, flags);
|
||||
}
|
||||
|
||||
private PermissionGroup(Parcel in) {
|
||||
super(in);
|
||||
info = in.readParcelable(Object.class.getClassLoader());
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() {
|
||||
public PermissionGroup createFromParcel(Parcel in) {
|
||||
return new PermissionGroup(in);
|
||||
}
|
||||
|
||||
public PermissionGroup[] newArray(int size) {
|
||||
return new PermissionGroup[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean copyNeeded(int flags, Package p,
|
||||
@@ -5871,7 +6313,7 @@ public class PackageParser {
|
||||
return pgi;
|
||||
}
|
||||
|
||||
public final static class Activity extends Component<ActivityIntentInfo> {
|
||||
public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
|
||||
public final ActivityInfo info;
|
||||
|
||||
public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
|
||||
@@ -5894,6 +6336,36 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
|
||||
}
|
||||
|
||||
private Activity(Parcel in) {
|
||||
super(in);
|
||||
info = in.readParcelable(Object.class.getClassLoader());
|
||||
|
||||
for (ActivityIntentInfo aii : intents) {
|
||||
aii.activity = this;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() {
|
||||
public Activity createFromParcel(Parcel in) {
|
||||
return new Activity(in);
|
||||
}
|
||||
|
||||
public Activity[] newArray(int size) {
|
||||
return new Activity[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final ActivityInfo generateActivityInfo(Activity a, int flags,
|
||||
@@ -5925,7 +6397,7 @@ public class PackageParser {
|
||||
return ai;
|
||||
}
|
||||
|
||||
public final static class Service extends Component<ServiceIntentInfo> {
|
||||
public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
|
||||
public final ServiceInfo info;
|
||||
|
||||
public Service(final ParseComponentArgs args, final ServiceInfo _info) {
|
||||
@@ -5948,6 +6420,36 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
|
||||
}
|
||||
|
||||
private Service(Parcel in) {
|
||||
super(in);
|
||||
info = in.readParcelable(Object.class.getClassLoader());
|
||||
|
||||
for (ServiceIntentInfo aii : intents) {
|
||||
aii.service = this;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() {
|
||||
public Service createFromParcel(Parcel in) {
|
||||
return new Service(in);
|
||||
}
|
||||
|
||||
public Service[] newArray(int size) {
|
||||
return new Service[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final ServiceInfo generateServiceInfo(Service s, int flags,
|
||||
@@ -5966,7 +6468,7 @@ public class PackageParser {
|
||||
return si;
|
||||
}
|
||||
|
||||
public final static class Provider extends Component<ProviderIntentInfo> {
|
||||
public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
|
||||
public final ProviderInfo info;
|
||||
public boolean syncable;
|
||||
|
||||
@@ -5997,6 +6499,38 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
|
||||
dest.writeInt((syncable) ? 1 : 0);
|
||||
}
|
||||
|
||||
private Provider(Parcel in) {
|
||||
super(in);
|
||||
info = in.readParcelable(Object.class.getClassLoader());
|
||||
syncable = (in.readInt() == 1);
|
||||
|
||||
for (ProviderIntentInfo aii : intents) {
|
||||
aii.provider = this;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() {
|
||||
public Provider createFromParcel(Parcel in) {
|
||||
return new Provider(in);
|
||||
}
|
||||
|
||||
public Provider[] newArray(int size) {
|
||||
return new Provider[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final ProviderInfo generateProviderInfo(Provider p, int flags,
|
||||
@@ -6020,7 +6554,8 @@ public class PackageParser {
|
||||
return pi;
|
||||
}
|
||||
|
||||
public final static class Instrumentation extends Component<IntentInfo> {
|
||||
public final static class Instrumentation extends Component<IntentInfo> implements
|
||||
Parcelable {
|
||||
public final InstrumentationInfo info;
|
||||
|
||||
public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
|
||||
@@ -6042,6 +6577,32 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(info, flags);
|
||||
}
|
||||
|
||||
private Instrumentation(Parcel in) {
|
||||
super(in);
|
||||
info = in.readParcelable(Object.class.getClassLoader());
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() {
|
||||
public Instrumentation createFromParcel(Parcel in) {
|
||||
return new Instrumentation(in);
|
||||
}
|
||||
|
||||
public Instrumentation[] newArray(int size) {
|
||||
return new Instrumentation[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final InstrumentationInfo generateInstrumentationInfo(
|
||||
@@ -6055,7 +6616,7 @@ public class PackageParser {
|
||||
return ii;
|
||||
}
|
||||
|
||||
public static class IntentInfo extends IntentFilter {
|
||||
public static abstract class IntentInfo extends IntentFilter {
|
||||
public boolean hasDefault;
|
||||
public int labelRes;
|
||||
public CharSequence nonLocalizedLabel;
|
||||
@@ -6063,10 +6624,36 @@ public class PackageParser {
|
||||
public int logo;
|
||||
public int banner;
|
||||
public int preferred;
|
||||
|
||||
protected IntentInfo() {
|
||||
}
|
||||
|
||||
protected IntentInfo(Parcel dest) {
|
||||
super(dest);
|
||||
hasDefault = (dest.readInt() == 1);
|
||||
labelRes = dest.readInt();
|
||||
nonLocalizedLabel = dest.readCharSequence();
|
||||
icon = dest.readInt();
|
||||
logo = dest.readInt();
|
||||
banner = dest.readInt();
|
||||
preferred = dest.readInt();
|
||||
}
|
||||
|
||||
|
||||
public void writeIntentInfoToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(hasDefault ? 1 : 0);
|
||||
dest.writeInt(labelRes);
|
||||
dest.writeCharSequence(nonLocalizedLabel);
|
||||
dest.writeInt(icon);
|
||||
dest.writeInt(logo);
|
||||
dest.writeInt(banner);
|
||||
dest.writeInt(preferred);
|
||||
}
|
||||
}
|
||||
|
||||
public final static class ActivityIntentInfo extends IntentInfo {
|
||||
public final Activity activity;
|
||||
public Activity activity;
|
||||
|
||||
public ActivityIntentInfo(Activity _activity) {
|
||||
activity = _activity;
|
||||
@@ -6081,10 +6668,14 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ActivityIntentInfo(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
}
|
||||
|
||||
public final static class ServiceIntentInfo extends IntentInfo {
|
||||
public final Service service;
|
||||
public Service service;
|
||||
|
||||
public ServiceIntentInfo(Service _service) {
|
||||
service = _service;
|
||||
@@ -6099,10 +6690,14 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ServiceIntentInfo(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ProviderIntentInfo extends IntentInfo {
|
||||
public final Provider provider;
|
||||
public Provider provider;
|
||||
|
||||
public ProviderIntentInfo(Provider provider) {
|
||||
this.provider = provider;
|
||||
@@ -6117,6 +6712,10 @@ public class PackageParser {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public ProviderIntentInfo(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,14 +15,37 @@
|
||||
*/
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.annotation.TestApi;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
import android.content.pm.FeatureGroupInfo;
|
||||
import android.content.pm.FeatureInfo;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -87,6 +110,36 @@ public class PackageParserTest {
|
||||
assertEquals("android", pkg.packageName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_serializePackage() throws Exception {
|
||||
PackageParser pp = new PackageParser();
|
||||
pp.setCacheDir(mTmpDir);
|
||||
|
||||
PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
|
||||
true /* useCaches */);
|
||||
|
||||
Parcel p = Parcel.obtain();
|
||||
pkg.writeToParcel(p, 0 /* flags */);
|
||||
|
||||
p.setDataPosition(0);
|
||||
PackageParser.Package deserialized = new PackageParser.Package(p);
|
||||
|
||||
assertPackagesEqual(pkg, deserialized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_roundTripKnownFields() throws Exception {
|
||||
PackageParser.Package pkg = new PackageParser.Package("foo");
|
||||
setKnownFields(pkg);
|
||||
|
||||
Parcel p = Parcel.obtain();
|
||||
pkg.writeToParcel(p, 0 /* flags */);
|
||||
|
||||
p.setDataPosition(0);
|
||||
PackageParser.Package deserialized = new PackageParser.Package(p);
|
||||
assertAllFieldsExist(deserialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* A trivial subclass of package parser that only caches the package name, and throws away
|
||||
* all other information.
|
||||
@@ -102,4 +155,375 @@ public class PackageParserTest {
|
||||
return new Package(new String(cacheEntry, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: The equality assertions below are based on code autogenerated by IntelliJ.
|
||||
|
||||
public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) {
|
||||
assertEquals(a.baseRevisionCode, b.baseRevisionCode);
|
||||
assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated);
|
||||
assertEquals(a.mVersionCode, b.mVersionCode);
|
||||
assertEquals(a.mSharedUserLabel, b.mSharedUserLabel);
|
||||
assertEquals(a.mPreferredOrder, b.mPreferredOrder);
|
||||
assertEquals(a.installLocation, b.installLocation);
|
||||
assertEquals(a.coreApp, b.coreApp);
|
||||
assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers);
|
||||
assertEquals(a.mOverlayPriority, b.mOverlayPriority);
|
||||
assertEquals(a.mTrustedOverlay, b.mTrustedOverlay);
|
||||
assertEquals(a.use32bitAbi, b.use32bitAbi);
|
||||
assertEquals(a.packageName, b.packageName);
|
||||
assertTrue(Arrays.equals(a.splitNames, b.splitNames));
|
||||
assertEquals(a.volumeUuid, b.volumeUuid);
|
||||
assertEquals(a.codePath, b.codePath);
|
||||
assertEquals(a.baseCodePath, b.baseCodePath);
|
||||
assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths));
|
||||
assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes));
|
||||
assertTrue(Arrays.equals(a.splitFlags, b.splitFlags));
|
||||
assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags));
|
||||
assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo);
|
||||
|
||||
assertEquals(a.permissions.size(), b.permissions.size());
|
||||
for (int i = 0; i < a.permissions.size(); ++i) {
|
||||
assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i));
|
||||
assertSame(a.permissions.get(i).owner, a);
|
||||
assertSame(b.permissions.get(i).owner, b);
|
||||
}
|
||||
|
||||
assertEquals(a.permissionGroups.size(), b.permissionGroups.size());
|
||||
for (int i = 0; i < a.permissionGroups.size(); ++i) {
|
||||
assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i));
|
||||
}
|
||||
|
||||
assertEquals(a.activities.size(), b.activities.size());
|
||||
for (int i = 0; i < a.activities.size(); ++i) {
|
||||
assertActivitiesEqual(a.activities.get(i), b.activities.get(i));
|
||||
}
|
||||
|
||||
assertEquals(a.receivers.size(), b.receivers.size());
|
||||
for (int i = 0; i < a.receivers.size(); ++i) {
|
||||
assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i));
|
||||
}
|
||||
|
||||
assertEquals(a.providers.size(), b.providers.size());
|
||||
for (int i = 0; i < a.providers.size(); ++i) {
|
||||
assertProvidersEqual(a.providers.get(i), b.providers.get(i));
|
||||
}
|
||||
|
||||
assertEquals(a.services.size(), b.services.size());
|
||||
for (int i = 0; i < a.services.size(); ++i) {
|
||||
assertServicesEqual(a.services.get(i), b.services.get(i));
|
||||
}
|
||||
|
||||
assertEquals(a.instrumentation.size(), b.instrumentation.size());
|
||||
for (int i = 0; i < a.instrumentation.size(); ++i) {
|
||||
assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i));
|
||||
}
|
||||
|
||||
assertEquals(a.requestedPermissions, b.requestedPermissions);
|
||||
assertEquals(a.protectedBroadcasts, b.protectedBroadcasts);
|
||||
assertEquals(a.parentPackage, b.parentPackage);
|
||||
assertEquals(a.childPackages, b.childPackages);
|
||||
assertEquals(a.libraryNames, b.libraryNames);
|
||||
assertEquals(a.usesLibraries, b.usesLibraries);
|
||||
assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries);
|
||||
assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles));
|
||||
assertEquals(a.mOriginalPackages, b.mOriginalPackages);
|
||||
assertEquals(a.mRealPackage, b.mRealPackage);
|
||||
assertEquals(a.mAdoptPermissions, b.mAdoptPermissions);
|
||||
assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData);
|
||||
assertEquals(a.mVersionName, b.mVersionName);
|
||||
assertEquals(a.mSharedUserId, b.mSharedUserId);
|
||||
assertTrue(Arrays.equals(a.mSignatures, b.mSignatures));
|
||||
assertTrue(Arrays.equals(a.mCertificates, b.mCertificates));
|
||||
assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills));
|
||||
assertEquals(a.mExtras, b.mExtras);
|
||||
assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
|
||||
assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
|
||||
assertEquals(a.mOverlayTarget, b.mOverlayTarget);
|
||||
assertEquals(a.mSigningKeys, b.mSigningKeys);
|
||||
assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets);
|
||||
assertEquals(a.mKeySetMapping, b.mKeySetMapping);
|
||||
assertEquals(a.cpuAbiOverride, b.cpuAbiOverride);
|
||||
assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash));
|
||||
}
|
||||
|
||||
private static void assertBundleApproximateEquals(Bundle a, Bundle b) {
|
||||
if (a == b) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Force the bundles to be unparceled.
|
||||
a.getBoolean("foo");
|
||||
b.getBoolean("foo");
|
||||
|
||||
assertEquals(a.toString(), b.toString());
|
||||
}
|
||||
|
||||
private static void assertComponentsEqual(PackageParser.Component<?> a,
|
||||
PackageParser.Component<?> b) {
|
||||
assertEquals(a.className, b.className);
|
||||
assertBundleApproximateEquals(a.metaData, b.metaData);
|
||||
assertEquals(a.getComponentName(), b.getComponentName());
|
||||
|
||||
if (a.intents != null && b.intents != null) {
|
||||
assertEquals(a.intents.size(), b.intents.size());
|
||||
} else if (a.intents == null || b.intents == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.intents.size(); ++i) {
|
||||
PackageParser.IntentInfo aIntent = a.intents.get(i);
|
||||
PackageParser.IntentInfo bIntent = b.intents.get(i);
|
||||
|
||||
assertEquals(aIntent.hasDefault, bIntent.hasDefault);
|
||||
assertEquals(aIntent.labelRes, bIntent.labelRes);
|
||||
assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel);
|
||||
assertEquals(aIntent.icon, bIntent.icon);
|
||||
assertEquals(aIntent.logo, bIntent.logo);
|
||||
assertEquals(aIntent.banner, bIntent.banner);
|
||||
assertEquals(aIntent.preferred, bIntent.preferred);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertPermissionsEqual(PackageParser.Permission a,
|
||||
PackageParser.Permission b) {
|
||||
assertComponentsEqual(a, b);
|
||||
assertEquals(a.tree, b.tree);
|
||||
|
||||
// Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform
|
||||
// a full structural equality here because the code that serializes them isn't parser
|
||||
// specific and is tested elsewhere.
|
||||
assertEquals(a.info.protectionLevel, b.info.protectionLevel);
|
||||
assertEquals(a.info.group, b.info.group);
|
||||
assertEquals(a.info.flags, b.info.flags);
|
||||
|
||||
if (a.group != null && b.group != null) {
|
||||
assertPermissionGroupsEqual(a.group, b.group);
|
||||
} else if (a.group != null || b.group != null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertInstrumentationEqual(PackageParser.Instrumentation a,
|
||||
PackageParser.Instrumentation b) {
|
||||
assertComponentsEqual(a, b);
|
||||
|
||||
// Sanity check for InstrumentationInfo.
|
||||
assertEquals(a.info.targetPackage, b.info.targetPackage);
|
||||
assertEquals(a.info.sourceDir, b.info.sourceDir);
|
||||
assertEquals(a.info.publicSourceDir, b.info.publicSourceDir);
|
||||
}
|
||||
|
||||
private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) {
|
||||
assertComponentsEqual(a, b);
|
||||
|
||||
// Sanity check for ServiceInfo.
|
||||
assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
|
||||
assertEquals(a.info.name, b.info.name);
|
||||
}
|
||||
|
||||
private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) {
|
||||
assertComponentsEqual(a, b);
|
||||
|
||||
// Sanity check for ProviderInfo
|
||||
assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
|
||||
assertEquals(a.info.name, b.info.name);
|
||||
}
|
||||
|
||||
private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) {
|
||||
assertComponentsEqual(a, b);
|
||||
|
||||
// Sanity check for ActivityInfo.
|
||||
assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
|
||||
assertEquals(a.info.name, b.info.name);
|
||||
}
|
||||
|
||||
private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a,
|
||||
PackageParser.PermissionGroup b) {
|
||||
assertComponentsEqual(a, b);
|
||||
|
||||
// Sanity check for PermissionGroupInfo.
|
||||
assertEquals(a.info.name, b.info.name);
|
||||
assertEquals(a.info.descriptionRes, b.info.descriptionRes);
|
||||
}
|
||||
|
||||
private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) {
|
||||
assertEquals(a.descriptionRes, that.descriptionRes);
|
||||
assertEquals(a.theme, that.theme);
|
||||
assertEquals(a.fullBackupContent, that.fullBackupContent);
|
||||
assertEquals(a.uiOptions, that.uiOptions);
|
||||
assertEquals(a.flags, that.flags);
|
||||
assertEquals(a.privateFlags, that.privateFlags);
|
||||
assertEquals(a.requiresSmallestWidthDp, that.requiresSmallestWidthDp);
|
||||
assertEquals(a.compatibleWidthLimitDp, that.compatibleWidthLimitDp);
|
||||
assertEquals(a.largestWidthLimitDp, that.largestWidthLimitDp);
|
||||
assertEquals(a.nativeLibraryRootRequiresIsa, that.nativeLibraryRootRequiresIsa);
|
||||
assertEquals(a.uid, that.uid);
|
||||
assertEquals(a.minSdkVersion, that.minSdkVersion);
|
||||
assertEquals(a.targetSdkVersion, that.targetSdkVersion);
|
||||
assertEquals(a.versionCode, that.versionCode);
|
||||
assertEquals(a.enabled, that.enabled);
|
||||
assertEquals(a.enabledSetting, that.enabledSetting);
|
||||
assertEquals(a.installLocation, that.installLocation);
|
||||
assertEquals(a.networkSecurityConfigRes, that.networkSecurityConfigRes);
|
||||
assertEquals(a.taskAffinity, that.taskAffinity);
|
||||
assertEquals(a.permission, that.permission);
|
||||
assertEquals(a.processName, that.processName);
|
||||
assertEquals(a.className, that.className);
|
||||
assertEquals(a.manageSpaceActivityName, that.manageSpaceActivityName);
|
||||
assertEquals(a.backupAgentName, that.backupAgentName);
|
||||
assertEquals(a.volumeUuid, that.volumeUuid);
|
||||
assertEquals(a.scanSourceDir, that.scanSourceDir);
|
||||
assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir);
|
||||
assertEquals(a.sourceDir, that.sourceDir);
|
||||
assertEquals(a.publicSourceDir, that.publicSourceDir);
|
||||
assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs));
|
||||
assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs));
|
||||
assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs));
|
||||
assertEquals(a.seinfo, that.seinfo);
|
||||
assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
|
||||
assertEquals(a.dataDir, that.dataDir);
|
||||
assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
|
||||
assertEquals(a.deviceEncryptedDataDir, that.deviceEncryptedDataDir);
|
||||
assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
|
||||
assertEquals(a.credentialEncryptedDataDir, that.credentialEncryptedDataDir);
|
||||
assertEquals(a.nativeLibraryDir, that.nativeLibraryDir);
|
||||
assertEquals(a.secondaryNativeLibraryDir, that.secondaryNativeLibraryDir);
|
||||
assertEquals(a.nativeLibraryRootDir, that.nativeLibraryRootDir);
|
||||
assertEquals(a.primaryCpuAbi, that.primaryCpuAbi);
|
||||
assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi);
|
||||
}
|
||||
|
||||
public static void setKnownFields(PackageParser.Package pkg) {
|
||||
pkg.baseRevisionCode = 100;
|
||||
pkg.baseHardwareAccelerated = true;
|
||||
pkg.mVersionCode = 100;
|
||||
pkg.mSharedUserLabel = 100;
|
||||
pkg.mPreferredOrder = 100;
|
||||
pkg.installLocation = 100;
|
||||
pkg.coreApp = true;
|
||||
pkg.mRequiredForAllUsers = true;
|
||||
pkg.mOverlayPriority = 100;
|
||||
pkg.mTrustedOverlay = true;
|
||||
pkg.use32bitAbi = true;
|
||||
pkg.packageName = "foo";
|
||||
pkg.splitNames = new String[] { "foo" };
|
||||
pkg.volumeUuid = "foo";
|
||||
pkg.codePath = "foo";
|
||||
pkg.baseCodePath = "foo";
|
||||
pkg.splitCodePaths = new String[] { "foo" };
|
||||
pkg.splitRevisionCodes = new int[] { 100 };
|
||||
pkg.splitFlags = new int[] { 100 };
|
||||
pkg.splitPrivateFlags = new int[] { 100 };
|
||||
pkg.applicationInfo = new ApplicationInfo();
|
||||
|
||||
pkg.permissions.add(new PackageParser.Permission(pkg));
|
||||
pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg));
|
||||
|
||||
final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs(
|
||||
pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0);
|
||||
|
||||
pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo()));
|
||||
pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo()));
|
||||
pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo()));
|
||||
pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
|
||||
pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
|
||||
pkg.requestedPermissions.add("foo");
|
||||
|
||||
pkg.protectedBroadcasts = new ArrayList<>();
|
||||
pkg.protectedBroadcasts.add("foo");
|
||||
|
||||
pkg.parentPackage = new PackageParser.Package("foo");
|
||||
|
||||
pkg.childPackages = new ArrayList<>();
|
||||
pkg.childPackages.add(new PackageParser.Package("bar"));
|
||||
|
||||
pkg.libraryNames = new ArrayList<>();
|
||||
pkg.libraryNames.add("foo");
|
||||
|
||||
pkg.usesLibraries = new ArrayList<>();
|
||||
pkg.usesLibraries.add("foo");
|
||||
|
||||
pkg.usesOptionalLibraries = new ArrayList<>();
|
||||
pkg.usesOptionalLibraries.add("foo");
|
||||
|
||||
pkg.usesLibraryFiles = new String[] { "foo "};
|
||||
|
||||
pkg.mOriginalPackages = new ArrayList<>();
|
||||
pkg.mOriginalPackages.add("foo");
|
||||
|
||||
pkg.mRealPackage = "foo";
|
||||
|
||||
pkg.mAdoptPermissions = new ArrayList<>();
|
||||
pkg.mAdoptPermissions.add("foo");
|
||||
|
||||
pkg.mAppMetaData = new Bundle();
|
||||
pkg.mVersionName = "foo";
|
||||
pkg.mSharedUserId = "foo";
|
||||
pkg.mSignatures = new Signature[] { new Signature(new byte[16]) };
|
||||
pkg.mCertificates = new Certificate[][] { new Certificate[] { null }};
|
||||
pkg.mExtras = new Bundle();
|
||||
pkg.mRestrictedAccountType = "foo";
|
||||
pkg.mRequiredAccountType = "foo";
|
||||
pkg.mOverlayTarget = "foo";
|
||||
pkg.mSigningKeys = new ArraySet<>();
|
||||
pkg.mUpgradeKeySets = new ArraySet<>();
|
||||
pkg.mKeySetMapping = new ArrayMap<>();
|
||||
pkg.cpuAbiOverride = "foo";
|
||||
pkg.restrictUpdateHash = new byte[16];
|
||||
|
||||
pkg.preferredActivityFilters = new ArrayList<>();
|
||||
pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo(
|
||||
new PackageParser.Activity(dummy, new ActivityInfo())));
|
||||
|
||||
pkg.configPreferences = new ArrayList<>();
|
||||
pkg.configPreferences.add(new ConfigurationInfo());
|
||||
|
||||
pkg.reqFeatures = new ArrayList<>();
|
||||
pkg.reqFeatures.add(new FeatureInfo());
|
||||
|
||||
pkg.featureGroups = new ArrayList<>();
|
||||
pkg.featureGroups.add(new FeatureGroupInfo());
|
||||
}
|
||||
|
||||
private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
|
||||
Field[] fields = PackageParser.Package.class.getDeclaredFields();
|
||||
|
||||
Set<String> nonSerializedFields = new HashSet<>();
|
||||
nonSerializedFields.add("mExtras");
|
||||
nonSerializedFields.add("packageUsageTimeMillis");
|
||||
|
||||
for (Field f : fields) {
|
||||
final Class<?> fieldType = f.getType();
|
||||
|
||||
if (nonSerializedFields.contains(f.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (List.class.isAssignableFrom(fieldType)) {
|
||||
// Sanity check for list fields: Assume they're non-null and contain precisely
|
||||
// one element.
|
||||
List<?> list = (List<?>) f.get(pkg);
|
||||
assertNotNull(list);
|
||||
assertEquals(1, list.size());
|
||||
} else if (fieldType.getComponentType() != null) {
|
||||
// Sanity check for array fields: Assume they're non-null and contain precisely
|
||||
// one element.
|
||||
Object array = f.get(pkg);
|
||||
assertNotNull(Array.get(array, 0));
|
||||
} else if (fieldType == String.class) {
|
||||
// String fields: Check that they're set to "foo".
|
||||
String value = (String) f.get(pkg);
|
||||
assertEquals("foo", value);
|
||||
} else if (fieldType == int.class) {
|
||||
// int fields: Check that they're set to 100.
|
||||
int value = (int) f.get(pkg);
|
||||
assertEquals(100, value);
|
||||
} else {
|
||||
// All other fields: Check that they're set.
|
||||
Object o = f.get(pkg);
|
||||
assertNotNull("Field was null: " + f.getName(), o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user