blob: c56a393c094f04c1b9f2880fe5c90375e322f506 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import static org.junit.Assert.*;
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.SharedLibraryInfo;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
import android.util.ArraySet;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class PackageParserTest {
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private File mTmpDir;
private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
@Before
public void setUp() throws IOException {
// Create a new temporary directory for each of our tests.
mTmpDir = mTemporaryFolder.newFolder("PackageParserTest");
}
@Test
public void testParse_noCache() throws Exception {
PackageParser pp = new CachePackageNameParser();
PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
false /* useCaches */);
assertNotNull(pkg);
pp.setCacheDir(mTmpDir);
pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
false /* useCaches */);
assertNotNull(pkg);
// Make sure that we always write out a cache entry for future reference,
// whether or not we're asked to use caches.
assertEquals(1, mTmpDir.list().length);
}
@Test
public void testParse_withCache() throws Exception {
PackageParser pp = new CachePackageNameParser();
pp.setCacheDir(mTmpDir);
// The first parse will write this package to the cache.
pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
// Now attempt to parse the package again, should return the
// cached result.
PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
true /* useCaches */);
assertEquals("cache_android", pkg.packageName);
// Try again, with useCaches == false, shouldn't return the parsed
// result.
pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
assertEquals("android", pkg.packageName);
// We haven't set a cache directory here : the parse should still succeed,
// just not using the cached results.
pp = new CachePackageNameParser();
pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
assertEquals("android", pkg.packageName);
pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
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
@SmallTest
@Presubmit
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);
}
@Test
public void test_stringInterning() 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);
p.setDataPosition(0);
PackageParser.Package deserialized2 = new PackageParser.Package(p);
assertSame(deserialized.packageName, deserialized2.packageName);
assertSame(deserialized.applicationInfo.permission,
deserialized2.applicationInfo.permission);
assertSame(deserialized.requestedPermissions.get(0),
deserialized2.requestedPermissions.get(0));
assertSame(deserialized.protectedBroadcasts.get(0),
deserialized2.protectedBroadcasts.get(0));
assertSame(deserialized.usesLibraries.get(0),
deserialized2.usesLibraries.get(0));
assertSame(deserialized.usesOptionalLibraries.get(0),
deserialized2.usesOptionalLibraries.get(0));
assertSame(deserialized.mVersionName, deserialized2.mVersionName);
assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId);
}
/**
* A trivial subclass of package parser that only caches the package name, and throws away
* all other information.
*/
public static class CachePackageNameParser extends PackageParser {
@Override
public byte[] toCacheEntry(Package pkg) {
return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8);
}
@Override
public Package fromCacheEntry(byte[] cacheEntry) {
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.mCompileSdkVersion, b.mCompileSdkVersion);
assertEquals(a.mCompileSdkVersionCodename, b.mCompileSdkVersionCodename);
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.mSigningDetails.signatures, b.mSigningDetails.signatures));
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.mOverlayCategory, b.mOverlayCategory);
assertEquals(a.mOverlayPriority, b.mOverlayPriority);
assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic);
assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys);
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.targetProcesses, b.info.targetProcesses);
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.credentialProtectedDataDir, that.credentialProtectedDataDir);
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.use32bitAbi = true;
pkg.packageName = "foo";
pkg.splitNames = new String[] { "foo2" };
pkg.volumeUuid = "foo3";
pkg.codePath = "foo4";
pkg.baseCodePath = "foo5";
pkg.splitCodePaths = new String[] { "foo6" };
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("foo7");
pkg.protectedBroadcasts = new ArrayList<>();
pkg.protectedBroadcasts.add("foo8");
pkg.parentPackage = new PackageParser.Package("foo9");
pkg.childPackages = new ArrayList<>();
pkg.childPackages.add(new PackageParser.Package("bar"));
pkg.staticSharedLibName = "foo23";
pkg.staticSharedLibVersion = 100;
pkg.usesStaticLibraries = new ArrayList<>();
pkg.usesStaticLibraries.add("foo23");
pkg.usesStaticLibrariesCertDigests = new String[1][];
pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" };
pkg.usesStaticLibrariesVersions = new long[] { 100 };
pkg.libraryNames = new ArrayList<>();
pkg.libraryNames.add("foo10");
pkg.usesLibraries = new ArrayList<>();
pkg.usesLibraries.add("foo11");
pkg.usesOptionalLibraries = new ArrayList<>();
pkg.usesOptionalLibraries.add("foo12");
pkg.usesLibraryFiles = new String[] { "foo13"};
pkg.usesLibraryInfos = new ArrayList<>();
pkg.usesLibraryInfos.add(
new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null));
pkg.mOriginalPackages = new ArrayList<>();
pkg.mOriginalPackages.add("foo14");
pkg.mRealPackage = "foo15";
pkg.mAdoptPermissions = new ArrayList<>();
pkg.mAdoptPermissions.add("foo16");
pkg.mAppMetaData = new Bundle();
pkg.mVersionName = "foo17";
pkg.mSharedUserId = "foo18";
pkg.mSigningDetails =
new PackageParser.SigningDetails(
new Signature[] { new Signature(new byte[16]) },
2,
new ArraySet<>(),
null,
null);
pkg.mExtras = new Bundle();
pkg.mRestrictedAccountType = "foo19";
pkg.mRequiredAccountType = "foo20";
pkg.mOverlayTarget = "foo21";
pkg.mOverlayPriority = 100;
pkg.mUpgradeKeySets = new ArraySet<>();
pkg.mKeySetMapping = new ArrayMap<>();
pkg.cpuAbiOverride = "foo22";
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());
pkg.mCompileSdkVersionCodename = "foo23";
pkg.mCompileSdkVersion = 100;
pkg.mVersionCodeMajor = 100;
pkg.mOverlayCategory = "foo24";
pkg.mOverlayIsStatic = true;
pkg.baseHardwareAccelerated = true;
pkg.coreApp = true;
pkg.mRequiredForAllUsers = true;
pkg.visibleToInstantApps = true;
pkg.use32bitAbi = true;
}
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");
nonSerializedFields.add("isStub");
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 was null: " + f, 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);
assertTrue("Bad value for field: " + f, value != null && value.startsWith("foo"));
} else if (fieldType == int.class) {
// int fields: Check that they're set to 100.
int value = (int) f.get(pkg);
assertEquals("Bad value for field: " + f, 100, value);
} else if (fieldType == boolean.class) {
// boolean fields: Check that they're set to true.
boolean value = (boolean) f.get(pkg);
assertEquals("Bad value for field: " + f, true, value);
} else {
// All other fields: Check that they're set.
Object o = f.get(pkg);
assertNotNull("Field was null: " + f, o);
}
}
}
}