1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.pm;
17 
18 import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
19 
20 import static com.google.common.truth.Truth.assertThat;
21 import static com.google.common.truth.Truth.assertWithMessage;
22 
23 import static org.junit.Assert.assertArrayEquals;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotEquals;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertSame;
30 import static org.junit.Assert.assertTrue;
31 import static org.junit.Assert.fail;
32 
33 import static java.lang.Boolean.TRUE;
34 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
35 import static java.util.stream.Collectors.toList;
36 
37 import android.annotation.NonNull;
38 import android.content.Context;
39 import android.content.pm.ActivityInfo;
40 import android.content.pm.ApplicationInfo;
41 import android.content.pm.ConfigurationInfo;
42 import android.content.pm.FeatureGroupInfo;
43 import android.content.pm.FeatureInfo;
44 import android.content.pm.PackageInfo;
45 import android.content.pm.PackageManager.Property;
46 import android.content.pm.ServiceInfo;
47 import android.content.pm.Signature;
48 import android.content.pm.SigningDetails;
49 import android.os.Bundle;
50 import android.os.Parcel;
51 import android.os.Parcelable;
52 import android.platform.test.annotations.Presubmit;
53 import android.util.ArraySet;
54 
55 import androidx.annotation.Nullable;
56 import androidx.test.InstrumentationRegistry;
57 import androidx.test.filters.MediumTest;
58 import androidx.test.filters.SmallTest;
59 import androidx.test.runner.AndroidJUnit4;
60 
61 import com.android.internal.util.ArrayUtils;
62 import com.android.server.pm.parsing.PackageCacher;
63 import com.android.server.pm.parsing.PackageInfoUtils;
64 import com.android.server.pm.parsing.PackageParser2;
65 import com.android.server.pm.parsing.TestPackageParser2;
66 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
67 import com.android.server.pm.parsing.pkg.PackageImpl;
68 import com.android.server.pm.parsing.pkg.ParsedPackage;
69 import com.android.server.pm.permission.CompatibilityPermissionInfo;
70 import com.android.server.pm.pkg.AndroidPackage;
71 import com.android.server.pm.pkg.PackageUserStateInternal;
72 import com.android.server.pm.pkg.component.ParsedActivity;
73 import com.android.server.pm.pkg.component.ParsedActivityImpl;
74 import com.android.server.pm.pkg.component.ParsedApexSystemService;
75 import com.android.server.pm.pkg.component.ParsedComponent;
76 import com.android.server.pm.pkg.component.ParsedInstrumentation;
77 import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
78 import com.android.server.pm.pkg.component.ParsedIntentInfo;
79 import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
80 import com.android.server.pm.pkg.component.ParsedPermission;
81 import com.android.server.pm.pkg.component.ParsedPermissionGroup;
82 import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
83 import com.android.server.pm.pkg.component.ParsedPermissionImpl;
84 import com.android.server.pm.pkg.component.ParsedPermissionUtils;
85 import com.android.server.pm.pkg.component.ParsedProvider;
86 import com.android.server.pm.pkg.component.ParsedProviderImpl;
87 import com.android.server.pm.pkg.component.ParsedService;
88 import com.android.server.pm.pkg.component.ParsedServiceImpl;
89 import com.android.server.pm.pkg.component.ParsedUsesPermission;
90 import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
91 import com.android.server.pm.pkg.parsing.ParsingPackage;
92 
93 import org.junit.Before;
94 import org.junit.Rule;
95 import org.junit.Test;
96 import org.junit.rules.TemporaryFolder;
97 import org.junit.runner.RunWith;
98 
99 import java.io.File;
100 import java.io.IOException;
101 import java.io.InputStream;
102 import java.lang.reflect.Array;
103 import java.lang.reflect.Field;
104 import java.nio.file.Files;
105 import java.util.ArrayList;
106 import java.util.Arrays;
107 import java.util.Collections;
108 import java.util.HashSet;
109 import java.util.Iterator;
110 import java.util.List;
111 import java.util.Map;
112 import java.util.Set;
113 
114 @Presubmit
115 @RunWith(AndroidJUnit4.class)
116 @MediumTest
117 public class PackageParserTest {
118     // TODO(b/135203078): Update this test with all fields and validate equality. Initial change
119     //  was just migrating to new interfaces. Consider adding actual equals() methods.
120 
121     @Rule
122     public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
123 
124     private File mTmpDir;
125     private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
126     private static final String TEST_APP1_APK = "PackageParserTestApp1.apk";
127     private static final String TEST_APP2_APK = "PackageParserTestApp2.apk";
128     private static final String TEST_APP3_APK = "PackageParserTestApp3.apk";
129     private static final String TEST_APP4_APK = "PackageParserTestApp4.apk";
130     private static final String TEST_APP5_APK = "PackageParserTestApp5.apk";
131     private static final String TEST_APP6_APK = "PackageParserTestApp6.apk";
132     private static final String PACKAGE_NAME = "com.android.servicestests.apps.packageparserapp";
133 
134     @Before
setUp()135     public void setUp() throws IOException {
136         // Create a new temporary directory for each of our tests.
137         mTmpDir = mTemporaryFolder.newFolder("PackageParserTest");
138     }
139 
140     @Test
testParse_noCache()141     public void testParse_noCache() throws Exception {
142         CachePackageNameParser pp = new CachePackageNameParser(null);
143         ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
144                 false /* useCaches */);
145         assertNotNull(pkg);
146 
147         pp.setCacheDir(mTmpDir);
148         pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
149                 false /* useCaches */);
150         assertNotNull(pkg);
151 
152         // Make sure that we always write out a cache entry for future reference,
153         // whether or not we're asked to use caches.
154         assertEquals(1, mTmpDir.list().length);
155     }
156 
157     @Test
testParse_withCache()158     public void testParse_withCache() throws Exception {
159         CachePackageNameParser pp = new CachePackageNameParser(null);
160 
161         pp.setCacheDir(mTmpDir);
162         // The first parse will write this package to the cache.
163         pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
164 
165         // Now attempt to parse the package again, should return the
166         // cached result.
167         ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
168                 true /* useCaches */);
169         assertEquals("cache_android", pkg.getPackageName());
170 
171         // Try again, with useCaches == false, shouldn't return the parsed
172         // result.
173         pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
174         assertEquals("android", pkg.getPackageName());
175 
176         // We haven't set a cache directory here : the parse should still succeed,
177         // just not using the cached results.
178         pp = new CachePackageNameParser(null);
179         pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
180         assertEquals("android", pkg.getPackageName());
181 
182         pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
183         assertEquals("android", pkg.getPackageName());
184     }
185 
186     @Test
test_serializePackage()187     public void test_serializePackage() throws Exception {
188         try (PackageParser2 pp = PackageParser2.forParsingFileWithDefaults()) {
189             AndroidPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
190                     true /* useCaches */).hideAsFinal();
191 
192             Parcel p = Parcel.obtain();
193             ((Parcelable) pkg).writeToParcel(p, 0 /* flags */);
194 
195             p.setDataPosition(0);
196             ParsedPackage deserialized = new PackageImpl(p);
197 
198             assertPackagesEqual(pkg, deserialized);
199         }
200     }
201 
202     @Test
203     @SmallTest
204     @Presubmit
test_roundTripKnownFields()205     public void test_roundTripKnownFields() throws Exception {
206         ParsingPackage pkg = PackageImpl.forTesting("foo");
207         setKnownFields(pkg);
208 
209         Parcel p = Parcel.obtain();
210         ((Parcelable) pkg).writeToParcel(p, 0 /* flags */);
211 
212         p.setDataPosition(0);
213         ParsedPackage deserialized = new PackageImpl(p);
214         assertAllFieldsExist(deserialized);
215     }
216 
217     @Test
test_stringInterning()218     public void test_stringInterning() throws Exception {
219         ParsingPackage pkg = PackageImpl.forTesting("foo");
220         setKnownFields(pkg);
221 
222         Parcel p = Parcel.obtain();
223         ((Parcelable) pkg.hideAsParsed().hideAsFinal()).writeToParcel(p, 0 /* flags */);
224 
225         p.setDataPosition(0);
226         AndroidPackage deserialized = new PackageImpl(p);
227 
228         p.setDataPosition(0);
229         AndroidPackage deserialized2 = new PackageImpl(p);
230 
231         assertSame(deserialized.getPackageName(), deserialized2.getPackageName());
232         assertSame(deserialized.getPermission(),
233                 deserialized2.getPermission());
234         assertSame(deserialized.getRequestedPermissions().get(0),
235                 deserialized2.getRequestedPermissions().get(0));
236 
237         List<String> protectedBroadcastsOne = new ArrayList<>(1);
238         protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts());
239 
240         List<String> protectedBroadcastsTwo = new ArrayList<>(1);
241         protectedBroadcastsTwo.addAll(deserialized2.getProtectedBroadcasts());
242 
243         assertSame(protectedBroadcastsOne.get(0), protectedBroadcastsTwo.get(0));
244 
245         assertSame(deserialized.getUsesLibraries().get(0),
246                 deserialized2.getUsesLibraries().get(0));
247         assertSame(deserialized.getUsesOptionalLibraries().get(0),
248                 deserialized2.getUsesOptionalLibraries().get(0));
249         assertSame(deserialized.getVersionName(), deserialized2.getVersionName());
250         assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId());
251     }
252 
extractFile(String filename)253     private File extractFile(String filename) throws Exception {
254         final Context context = InstrumentationRegistry.getTargetContext();
255         final File tmpFile = File.createTempFile(filename, ".apk");
256         try (InputStream inputStream = context.getAssets().openNonAsset(filename)) {
257             Files.copy(inputStream, tmpFile.toPath(), REPLACE_EXISTING);
258         }
259         return tmpFile;
260     }
261 
262     /**
263      * Extracts the asset file to $mTmpDir/$dirname/$filename.
264      */
extractFile(String filename, String dirname)265     private File extractFile(String filename, String dirname) throws Exception {
266         final Context context = InstrumentationRegistry.getTargetContext();
267         File dir = new File(mTmpDir, dirname);
268         dir.mkdir();
269         final File tmpFile = new File(dir, filename);
270         try (InputStream inputStream = context.getAssets().openNonAsset(filename)) {
271             Files.copy(inputStream, tmpFile.toPath(), REPLACE_EXISTING);
272         }
273         return tmpFile;
274     }
275 
276     /**
277      * Tests the path of cached ParsedPackage.
278      */
279     @Test
testCache_SameFileName()280     public void testCache_SameFileName() throws Exception {
281         // Prepare 2 package files with the same name but different paths
282         TestPackageParser2 parser = new TestPackageParser2(mTmpDir);
283         final File f1 = extractFile(TEST_APP1_APK, "dir1");
284         final File f2 = extractFile(TEST_APP1_APK, "dir2");
285         // Sleep for a while so that the cache file will be newer and valid
286         Thread.sleep(1000);
287         ParsedPackage pr1 = parser.parsePackage(f1, 0, true);
288         ParsedPackage pr2 = parser.parsePackage(f2, 0, true);
289         // Check the path of cached ParsedPackage
290         assertThat(pr1.getPath()).isEqualTo(f1.getAbsolutePath());
291         assertThat(pr2.getPath()).isEqualTo(f2.getAbsolutePath());
292     }
293 
294     /**
295      * Tests AndroidManifest.xml with no android:isolatedSplits attribute.
296      */
297     @Test
testParseIsolatedSplitsDefault()298     public void testParseIsolatedSplitsDefault() throws Exception {
299         final File testFile = extractFile(TEST_APP1_APK);
300         try {
301             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
302             assertFalse("isolatedSplits", pkg.isIsolatedSplitLoading());
303         } finally {
304             testFile.delete();
305         }
306     }
307 
308     /**
309      * Tests AndroidManifest.xml with an android:isolatedSplits attribute set to a constant.
310      */
311     @Test
testParseIsolatedSplitsConstant()312     public void testParseIsolatedSplitsConstant() throws Exception {
313         final File testFile = extractFile(TEST_APP2_APK);
314         try {
315             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
316             assertTrue("isolatedSplits", pkg.isIsolatedSplitLoading());
317         } finally {
318             testFile.delete();
319         }
320     }
321 
322     /**
323      * Tests AndroidManifest.xml with an android:isolatedSplits attribute set to a resource.
324      */
325     @Test
testParseIsolatedSplitsResource()326     public void testParseIsolatedSplitsResource() throws Exception {
327         final File testFile = extractFile(TEST_APP3_APK);
328         try {
329             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
330             assertTrue("isolatedSplits", pkg.isIsolatedSplitLoading());
331         } finally {
332             testFile.delete();
333         }
334     }
335 
336     @Test
testParseActivityRequiredDisplayCategoryValid()337     public void testParseActivityRequiredDisplayCategoryValid() throws Exception {
338         final File testFile = extractFile(TEST_APP4_APK);
339         String actualDisplayCategory = null;
340         try {
341             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
342             final List<ParsedActivity> activities = pkg.getActivities();
343             for (ParsedActivity activity : activities) {
344                 if ((PACKAGE_NAME + ".MyActivity").equals(activity.getName())) {
345                     actualDisplayCategory = activity.getRequiredDisplayCategory();
346                 }
347             }
348         } finally {
349             testFile.delete();
350         }
351         assertEquals("automotive", actualDisplayCategory);
352     }
353 
354     @Test
testParseActivityRequiredDisplayCategoryInvalid()355     public void testParseActivityRequiredDisplayCategoryInvalid() throws Exception {
356         final File testFile = extractFile(TEST_APP6_APK);
357         String actualDisplayCategory = null;
358         try {
359             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
360             final List<ParsedActivity> activities = pkg.getActivities();
361             for (ParsedActivity activity : activities) {
362                 if ((PACKAGE_NAME + ".MyActivity").equals(activity.getName())) {
363                     actualDisplayCategory = activity.getRequiredDisplayCategory();
364                 }
365             }
366         } catch (PackageManagerException e) {
367             assertThat(e.getMessage()).contains(
368                     "requiredDisplayCategory attribute can only consist"
369                             + " of alphanumeric characters, '_', and '.'");
370         } finally {
371             testFile.delete();
372         }
373         assertNotEquals("$automotive", actualDisplayCategory);
374     }
375 
376     private static final int PROPERTY_TYPE_BOOLEAN = 1;
377     private static final int PROPERTY_TYPE_FLOAT = 2;
378     private static final int PROPERTY_TYPE_INTEGER = 3;
379     private static final int PROPERTY_TYPE_RESOURCE = 4;
380     private static final int PROPERTY_TYPE_STRING = 5;
assertProperty(Map<String, Property> properties, String propertyName, int propertyType, Object propertyValue)381     public void assertProperty(Map<String, Property> properties, String propertyName,
382             int propertyType, Object propertyValue) {
383         assertTrue(properties.containsKey(propertyName));
384 
385         final Property testProperty = properties.get(propertyName);
386         assertEquals(propertyType, testProperty.getType());
387 
388         if (propertyType == PROPERTY_TYPE_BOOLEAN) {
389             assertTrue(testProperty.isBoolean());
390             assertFalse(testProperty.isFloat());
391             assertFalse(testProperty.isInteger());
392             assertFalse(testProperty.isResourceId());
393             assertFalse(testProperty.isString());
394 
395             // assert the property's type is set correctly
396             final Boolean boolValue = (Boolean) propertyValue;
397             if (boolValue.booleanValue()) {
398                 assertTrue(testProperty.getBoolean());
399             } else {
400                 assertFalse(testProperty.getBoolean());
401             }
402             // assert the other values have an appropriate default
403             assertEquals(0.0f, testProperty.getFloat(), 0.0f);
404             assertEquals(0, testProperty.getInteger());
405             assertEquals(0, testProperty.getResourceId());
406             assertEquals(null, testProperty.getString());
407         } else if (propertyType == PROPERTY_TYPE_FLOAT) {
408             assertFalse(testProperty.isBoolean());
409             assertTrue(testProperty.isFloat());
410             assertFalse(testProperty.isInteger());
411             assertFalse(testProperty.isResourceId());
412             assertFalse(testProperty.isString());
413 
414             // assert the property's type is set correctly
415             final Float floatValue = (Float) propertyValue;
416             assertEquals(floatValue.floatValue(), testProperty.getFloat(), 0.0f);
417             // assert the other values have an appropriate default
418             assertFalse(testProperty.getBoolean());
419             assertEquals(0, testProperty.getInteger());
420             assertEquals(0, testProperty.getResourceId());
421             assertEquals(null, testProperty.getString());
422         } else if (propertyType == PROPERTY_TYPE_INTEGER) {
423             assertFalse(testProperty.isBoolean());
424             assertFalse(testProperty.isFloat());
425             assertTrue(testProperty.isInteger());
426             assertFalse(testProperty.isResourceId());
427             assertFalse(testProperty.isString());
428 
429             // assert the property's type is set correctly
430             final Integer integerValue = (Integer) propertyValue;
431             assertEquals(integerValue.intValue(), testProperty.getInteger());
432             // assert the other values have an appropriate default
433             assertFalse(testProperty.getBoolean());
434             assertEquals(0.0f, testProperty.getFloat(), 0.0f);
435             assertEquals(0, testProperty.getResourceId());
436             assertEquals(null, testProperty.getString());
437         } else if (propertyType == PROPERTY_TYPE_RESOURCE) {
438             assertFalse(testProperty.isBoolean());
439             assertFalse(testProperty.isFloat());
440             assertFalse(testProperty.isInteger());
441             assertTrue(testProperty.isResourceId());
442             assertFalse(testProperty.isString());
443 
444             // assert the property's type is set correctly
445             final Integer resourceValue = (Integer) propertyValue;
446             assertEquals(resourceValue.intValue(), testProperty.getResourceId());
447             // assert the other values have an appropriate default
448             assertFalse(testProperty.getBoolean());
449             assertEquals(0.0f, testProperty.getFloat(), 0.0f);
450             assertEquals(0, testProperty.getInteger());
451             assertEquals(null, testProperty.getString());
452         } else if (propertyType == PROPERTY_TYPE_STRING) {
453             assertFalse(testProperty.isBoolean());
454             assertFalse(testProperty.isFloat());
455             assertFalse(testProperty.isInteger());
456             assertFalse(testProperty.isResourceId());
457             assertTrue(testProperty.isString());
458 
459             // assert the property's type is set correctly
460             final String stringValue = (String) propertyValue;
461             assertEquals(stringValue, testProperty.getString());
462             // assert the other values have an appropriate default
463             assertFalse(testProperty.getBoolean());
464             assertEquals(0.0f, testProperty.getFloat(), 0.0f);
465             assertEquals(0, testProperty.getInteger());
466             assertEquals(0, testProperty.getResourceId());
467         } else {
468             fail("Unknown property type");
469         }
470     }
471 
472     @Test
testParseApplicationProperties()473     public void testParseApplicationProperties() throws Exception {
474         final File testFile = extractFile(TEST_APP4_APK);
475         try {
476             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
477             final Map<String, Property> properties = pkg.getProperties();
478             assertEquals(10, properties.size());
479             assertProperty(properties,
480                     "android.cts.PROPERTY_RESOURCE_XML", PROPERTY_TYPE_RESOURCE, 0x7f060000);
481             assertProperty(properties,
482                     "android.cts.PROPERTY_RESOURCE_INTEGER", PROPERTY_TYPE_RESOURCE, 0x7f040000);
483             assertProperty(properties,
484                     "android.cts.PROPERTY_BOOLEAN", PROPERTY_TYPE_BOOLEAN, TRUE);
485             assertProperty(properties,
486                     "android.cts.PROPERTY_BOOLEAN_VIA_RESOURCE", PROPERTY_TYPE_BOOLEAN, TRUE);
487             assertProperty(properties,
488                     "android.cts.PROPERTY_FLOAT", PROPERTY_TYPE_FLOAT, 3.14f);
489             assertProperty(properties,
490                     "android.cts.PROPERTY_FLOAT_VIA_RESOURCE", PROPERTY_TYPE_FLOAT, 2.718f);
491             assertProperty(properties,
492                     "android.cts.PROPERTY_INTEGER", PROPERTY_TYPE_INTEGER, 42);
493             assertProperty(properties,
494                     "android.cts.PROPERTY_INTEGER_VIA_RESOURCE", PROPERTY_TYPE_INTEGER, 123);
495             assertProperty(properties,
496                     "android.cts.PROPERTY_STRING", PROPERTY_TYPE_STRING, "koala");
497             assertProperty(properties,
498                     "android.cts.PROPERTY_STRING_VIA_RESOURCE", PROPERTY_TYPE_STRING, "giraffe");
499         } finally {
500             testFile.delete();
501         }
502     }
503 
504     @Test
testParseActivityProperties()505     public void testParseActivityProperties() throws Exception {
506         final File testFile = extractFile(TEST_APP4_APK);
507         try {
508             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
509             final List<ParsedActivity> activities = pkg.getActivities();
510             for (ParsedActivity activity : activities) {
511                 final Map<String, Property> properties = activity.getProperties();
512                 if ((PACKAGE_NAME + ".MyActivityAlias").equals(activity.getName())) {
513                     assertEquals(2, properties.size());
514                     assertProperty(properties,
515                             "android.cts.PROPERTY_ACTIVITY_ALIAS", PROPERTY_TYPE_INTEGER, 123);
516                     assertProperty(properties,
517                             "android.cts.PROPERTY_COMPONENT", PROPERTY_TYPE_INTEGER, 123);
518                 } else if ((PACKAGE_NAME + ".MyActivity").equals(activity.getName())) {
519                     assertEquals(3, properties.size());
520                     assertProperty(properties,
521                             "android.cts.PROPERTY_ACTIVITY", PROPERTY_TYPE_INTEGER, 123);
522                     assertProperty(properties,
523                             "android.cts.PROPERTY_COMPONENT", PROPERTY_TYPE_INTEGER, 123);
524                     assertProperty(properties,
525                             "android.cts.PROPERTY_STRING", PROPERTY_TYPE_STRING, "koala activity");
526                 } else if ("android.app.AppDetailsActivity".equals(activity.getName())) {
527                     // ignore default added activity
528                 } else {
529                     fail("Found unknown activity; name = " + activity.getName());
530                 }
531             }
532         } finally {
533             testFile.delete();
534         }
535     }
536 
537     @Test
testParseProviderProperties()538     public void testParseProviderProperties() throws Exception {
539         final File testFile = extractFile(TEST_APP4_APK);
540         try {
541             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
542             final List<ParsedProvider> providers = pkg.getProviders();
543             for (ParsedProvider provider : providers) {
544                 final Map<String, Property> properties = provider.getProperties();
545                 if ((PACKAGE_NAME + ".MyProvider").equals(provider.getName())) {
546                     assertEquals(1, properties.size());
547                     assertProperty(properties,
548                             "android.cts.PROPERTY_PROVIDER", PROPERTY_TYPE_INTEGER, 123);
549                 } else {
550                     fail("Found unknown provider; name = " + provider.getName());
551                 }
552             }
553         } finally {
554             testFile.delete();
555         }
556     }
557 
558     @Test
testParseReceiverProperties()559     public void testParseReceiverProperties() throws Exception {
560         final File testFile = extractFile(TEST_APP4_APK);
561         try {
562             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
563             final List<ParsedActivity> receivers = pkg.getReceivers();
564             for (ParsedActivity receiver : receivers) {
565                 final Map<String, Property> properties = receiver.getProperties();
566                 if ((PACKAGE_NAME + ".MyReceiver").equals(receiver.getName())) {
567                     assertEquals(2, properties.size());
568                     assertProperty(properties,
569                             "android.cts.PROPERTY_RECEIVER", PROPERTY_TYPE_INTEGER, 123);
570                     assertProperty(properties,
571                             "android.cts.PROPERTY_STRING", PROPERTY_TYPE_STRING, "koala receiver");
572                 } else {
573                     fail("Found unknown receiver; name = " + receiver.getName());
574                 }
575             }
576         } finally {
577             testFile.delete();
578         }
579     }
580 
581     @Test
testParseServiceProperties()582     public void testParseServiceProperties() throws Exception {
583         final File testFile = extractFile(TEST_APP4_APK);
584         try {
585             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
586             final List<ParsedService> services = pkg.getServices();
587             for (ParsedService service : services) {
588                 final Map<String, Property> properties = service.getProperties();
589                 if ((PACKAGE_NAME + ".MyService").equals(service.getName())) {
590                     assertEquals(2, properties.size());
591                     assertProperty(properties,
592                             "android.cts.PROPERTY_SERVICE", PROPERTY_TYPE_INTEGER, 123);
593                     assertProperty(properties,
594                             "android.cts.PROPERTY_COMPONENT", PROPERTY_TYPE_RESOURCE, 0x7f040000);
595                 } else {
596                     fail("Found unknown service; name = " + service.getName());
597                 }
598             }
599         } finally {
600             testFile.delete();
601         }
602     }
603 
604     @Test
testParseApexSystemService()605     public void testParseApexSystemService() throws Exception {
606         final File testFile = extractFile(TEST_APP4_APK);
607         try {
608             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
609             final List<ParsedApexSystemService> systemServices = pkg.getApexSystemServices();
610             for (ParsedApexSystemService systemService: systemServices) {
611                 assertEquals(PACKAGE_NAME + ".SystemService", systemService.getName());
612                 assertEquals("service-test.jar", systemService.getJarPath());
613                 assertEquals("30", systemService.getMinSdkVersion());
614                 assertEquals("31", systemService.getMaxSdkVersion());
615             }
616         } finally {
617             testFile.delete();
618         }
619     }
620 
621     @Test
testParseModernPackageHasNoCompatPermissions()622     public void testParseModernPackageHasNoCompatPermissions() throws Exception {
623         final File testFile = extractFile(TEST_APP1_APK);
624         try {
625             final ParsedPackage pkg = new TestPackageParser2()
626                     .parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
627             final List<String> compatPermissions =
628                     Arrays.stream(COMPAT_PERMS).map(CompatibilityPermissionInfo::getName)
629                             .collect(toList());
630             assertWithMessage(
631                     "Compatibility permissions shouldn't be added into uses permissions.")
632                     .that(pkg.getUsesPermissions().stream().map(ParsedUsesPermission::getName)
633                             .collect(toList()))
634                     .containsNoneIn(compatPermissions);
635             assertWithMessage(
636                     "Compatibility permissions shouldn't be added into requested permissions.")
637                     .that(pkg.getRequestedPermissions()).containsNoneIn(compatPermissions);
638             assertWithMessage(
639                     "Compatibility permissions shouldn't be added into implicit permissions.")
640                     .that(pkg.getImplicitPermissions()).containsNoneIn(compatPermissions);
641         } finally {
642             testFile.delete();
643         }
644     }
645 
646     @Test
testParseLegacyPackageHasCompatPermissions()647     public void testParseLegacyPackageHasCompatPermissions() throws Exception {
648         final File testFile = extractFile(TEST_APP5_APK);
649         try {
650             final ParsedPackage pkg = new TestPackageParser2()
651                     .parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
652             assertWithMessage(
653                     "Compatibility permissions should be added into uses permissions.")
654                     .that(Arrays.stream(COMPAT_PERMS).map(CompatibilityPermissionInfo::getName)
655                             .allMatch(pkg.getUsesPermissions().stream()
656                                     .map(ParsedUsesPermission::getName)
657                             .collect(toList())::contains))
658                     .isTrue();
659             assertWithMessage(
660                     "Compatibility permissions should be added into requested permissions.")
661                     .that(Arrays.stream(COMPAT_PERMS).map(CompatibilityPermissionInfo::getName)
662                             .allMatch(pkg.getRequestedPermissions()::contains))
663                     .isTrue();
664             assertWithMessage(
665                     "Compatibility permissions should be added into implicit permissions.")
666                     .that(Arrays.stream(COMPAT_PERMS).map(CompatibilityPermissionInfo::getName)
667                             .allMatch(pkg.getImplicitPermissions()::contains))
668                     .isTrue();
669         } finally {
670             testFile.delete();
671         }
672     }
673 
674     @Test
testNoComponentMetadataIsCoercedToNullForInfoObject()675     public void testNoComponentMetadataIsCoercedToNullForInfoObject() throws Exception {
676         final File testFile = extractFile(TEST_APP4_APK);
677         try {
678             final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
679             var pkgSetting = mockPkgSetting(pkg);
680             ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(pkg, 0,
681                     PackageUserStateInternal.DEFAULT, 0, pkgSetting);
682             for (ParsedActivity activity : pkg.getActivities()) {
683                 assertNotNull(activity.getMetaData());
684                 assertNull(PackageInfoUtils.generateActivityInfo(pkg, activity, 0,
685                         PackageUserStateInternal.DEFAULT, appInfo, 0, pkgSetting)
686                         .metaData);
687             }
688             for (ParsedProvider provider : pkg.getProviders()) {
689                 assertNotNull(provider.getMetaData());
690                 assertNull(PackageInfoUtils.generateProviderInfo(pkg, provider, 0,
691                         PackageUserStateInternal.DEFAULT, appInfo, 0, pkgSetting)
692                         .metaData);
693             }
694             for (ParsedActivity receiver : pkg.getReceivers()) {
695                 assertNotNull(receiver.getMetaData());
696                 assertNull(PackageInfoUtils.generateActivityInfo(pkg, receiver, 0,
697                         PackageUserStateInternal.DEFAULT, appInfo, 0, pkgSetting)
698                         .metaData);
699             }
700             for (ParsedService service : pkg.getServices()) {
701                 assertNotNull(service.getMetaData());
702                 assertNull(PackageInfoUtils.generateServiceInfo(pkg, service, 0,
703                         PackageUserStateInternal.DEFAULT, appInfo, 0, pkgSetting)
704                         .metaData);
705             }
706         } finally {
707             testFile.delete();
708         }
709     }
710 
711     /**
712      * A subclass of package parser that adds a "cache_" prefix to the package name for the cached
713      * results. This is used by tests to tell if a ParsedPackage is generated from the cache or not.
714      */
715     public static class CachePackageNameParser extends PackageParser2 {
716 
CachePackageNameParser(@ullable File cacheDir)717         CachePackageNameParser(@Nullable File cacheDir) {
718             super(null, null, null, new Callback() {
719                 @Override
720                 public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
721                     return true;
722                 }
723 
724                 @Override
725                 public boolean hasFeature(String feature) {
726                     return false;
727                 }
728             });
729             if (cacheDir != null) {
730                 setCacheDir(cacheDir);
731             }
732         }
733 
setCacheDir(@onNull File cacheDir)734         void setCacheDir(@NonNull File cacheDir) {
735             this.mCacher = new PackageCacher(cacheDir) {
736                 @Override
737                 public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
738                     ParsedPackage parsed = super.fromCacheEntry(cacheEntry);
739                     parsed.setPackageName("cache_" + parsed.getPackageName());
740                     return parsed;
741                 }
742             };
743         }
744     }
745 
mockPkgSetting(AndroidPackage pkg)746     private static PackageSetting mockPkgSetting(AndroidPackage pkg) {
747         return new PackageSettingBuilder()
748                 .setName(pkg.getPackageName())
749                 .setRealName(pkg.getManifestPackageName())
750                 .setCodePath(pkg.getPath())
751                 .setPrimaryCpuAbiString(AndroidPackageUtils.getRawPrimaryCpuAbi(pkg))
752                 .setSecondaryCpuAbiString(AndroidPackageUtils.getRawSecondaryCpuAbi(pkg))
753                 .setPVersionCode(pkg.getLongVersionCode())
754                 .setPkgFlags(PackageInfoUtils.appInfoFlags(pkg, null))
755                 .setPrivateFlags(PackageInfoUtils.appInfoPrivateFlags(pkg, null))
756                 .setSharedUserId(pkg.getSharedUserLabelResourceId())
757                 .build();
758     }
759 
760     // NOTE: The equality assertions below are based on code autogenerated by IntelliJ.
761 
assertPackagesEqual(AndroidPackage a, AndroidPackage b)762     public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) {
763         assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
764         assertEquals(a.isHardwareAccelerated(), b.isHardwareAccelerated());
765         assertEquals(a.getLongVersionCode(), b.getLongVersionCode());
766         assertEquals(a.getSharedUserLabelResourceId(), b.getSharedUserLabelResourceId());
767         assertEquals(a.getInstallLocation(), b.getInstallLocation());
768         assertEquals(a.isCoreApp(), b.isCoreApp());
769         assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
770         assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
771         assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
772         assertEquals(a.is32BitAbiPreferred(), b.is32BitAbiPreferred());
773         assertEquals(a.getPackageName(), b.getPackageName());
774         assertArrayEquals(a.getSplitNames(), b.getSplitNames());
775         assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
776         assertEquals(a.getPath(), b.getPath());
777         assertEquals(a.getBaseApkPath(), b.getBaseApkPath());
778         assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths());
779         assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes());
780         assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
781 
782         PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0,
783                 Collections.emptySet(), Collections.emptySet(), PackageUserStateInternal.DEFAULT, 0,
784                 mockPkgSetting(a));
785         PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0,
786                 Collections.emptySet(), Collections.emptySet(), PackageUserStateInternal.DEFAULT, 0,
787                 mockPkgSetting(b));
788         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
789 
790         assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions()));
791         for (int i = 0; i < ArrayUtils.size(a.getPermissions()); ++i) {
792             assertPermissionsEqual(a.getPermissions().get(i), b.getPermissions().get(i));
793         }
794 
795         assertEquals(ArrayUtils.size(a.getPermissionGroups()),
796                 ArrayUtils.size(b.getPermissionGroups()));
797         for (int i = 0; i < a.getPermissionGroups().size(); ++i) {
798             assertPermissionGroupsEqual(a.getPermissionGroups().get(i),
799                     b.getPermissionGroups().get(i));
800         }
801 
802         assertEquals(ArrayUtils.size(a.getActivities()), ArrayUtils.size(b.getActivities()));
803         for (int i = 0; i < ArrayUtils.size(a.getActivities()); ++i) {
804             assertActivitiesEqual(a, a.getActivities().get(i), b, b.getActivities().get(i));
805         }
806 
807         assertEquals(ArrayUtils.size(a.getReceivers()), ArrayUtils.size(b.getReceivers()));
808         for (int i = 0; i < ArrayUtils.size(a.getReceivers()); ++i) {
809             assertActivitiesEqual(a, a.getReceivers().get(i), b, b.getReceivers().get(i));
810         }
811 
812         assertEquals(ArrayUtils.size(a.getProviders()), ArrayUtils.size(b.getProviders()));
813         for (int i = 0; i < ArrayUtils.size(a.getProviders()); ++i) {
814             assertProvidersEqual(a, a.getProviders().get(i), b, b.getProviders().get(i));
815         }
816 
817         assertEquals(ArrayUtils.size(a.getServices()), ArrayUtils.size(b.getServices()));
818         for (int i = 0; i < ArrayUtils.size(a.getServices()); ++i) {
819             assertServicesEqual(a, a.getServices().get(i), b, b.getServices().get(i));
820         }
821 
822         assertEquals(ArrayUtils.size(a.getInstrumentations()),
823                 ArrayUtils.size(b.getInstrumentations()));
824         for (int i = 0; i < ArrayUtils.size(a.getInstrumentations()); ++i) {
825             assertInstrumentationEqual(a.getInstrumentations().get(i),
826                     b.getInstrumentations().get(i));
827         }
828 
829         assertEquals(a.getProperties().size(), b.getProperties().size());
830         final Iterator<String> iter = a.getProperties().keySet().iterator();
831         while (iter.hasNext()) {
832             final String key = iter.next();
833             assertEquals(a.getProperties().get(key), b.getProperties().get(key));
834         }
835 
836         assertEquals(a.getRequestedPermissions(), b.getRequestedPermissions());
837         assertEquals(a.getProtectedBroadcasts(), b.getProtectedBroadcasts());
838         assertEquals(a.getLibraryNames(), b.getLibraryNames());
839         assertEquals(a.getUsesLibraries(), b.getUsesLibraries());
840         assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries());
841         assertEquals(a.getOriginalPackages(), b.getOriginalPackages());
842         assertEquals(a.getManifestPackageName(), b.getManifestPackageName());
843         assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions());
844         assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
845         assertEquals(a.getVersionName(), b.getVersionName());
846         assertEquals(a.getSharedUserId(), b.getSharedUserId());
847         assertArrayEquals(a.getSigningDetails().getSignatures(),
848                 b.getSigningDetails().getSignatures());
849         assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
850         assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
851         assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
852         assertEquals(a.getOverlayTargetOverlayableName(), b.getOverlayTargetOverlayableName());
853         assertEquals(a.getOverlayCategory(), b.getOverlayCategory());
854         assertEquals(a.getOverlayPriority(), b.getOverlayPriority());
855         assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic());
856         assertEquals(a.getSigningDetails().getPublicKeys(), b.getSigningDetails().getPublicKeys());
857         assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets());
858         assertEquals(a.getKeySetMapping(), b.getKeySetMapping());
859         assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash());
860     }
861 
assertBundleApproximateEquals(Bundle a, Bundle b)862     private static void assertBundleApproximateEquals(Bundle a, Bundle b) {
863         if (a == b) {
864             return;
865         }
866 
867         // Force the bundles to be unparceled.
868         a.getBoolean("foo");
869         b.getBoolean("foo");
870 
871         assertEquals(a.toString(), b.toString());
872     }
873 
assertComponentsEqual(ParsedComponent a, ParsedComponent b)874     private static void assertComponentsEqual(ParsedComponent a, ParsedComponent b) {
875         assertEquals(a.getName(), b.getName());
876         assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
877         assertEquals(a.getComponentName(), b.getComponentName());
878 
879         if (a.getIntents() != null && b.getIntents() != null) {
880             assertEquals(a.getIntents().size(), b.getIntents().size());
881         } else if (a.getIntents() == null || b.getIntents() == null) {
882             return;
883         }
884 
885         for (int i = 0; i < a.getIntents().size(); ++i) {
886             ParsedIntentInfo aIntent = a.getIntents().get(i);
887             ParsedIntentInfo bIntent = b.getIntents().get(i);
888 
889             assertEquals(aIntent.isHasDefault(), bIntent.isHasDefault());
890             assertEquals(aIntent.getLabelRes(), bIntent.getLabelRes());
891             assertEquals(aIntent.getNonLocalizedLabel(), bIntent.getNonLocalizedLabel());
892             assertEquals(aIntent.getIcon(), bIntent.getIcon());
893         }
894 
895         assertEquals(a.getProperties().size(), b.getProperties().size());
896         final Iterator<String> iter = a.getProperties().keySet().iterator();
897         while (iter.hasNext()) {
898             final String key = iter.next();
899             assertEquals(a.getProperties().get(key), b.getProperties().get(key));
900         }
901     }
902 
assertPermissionsEqual(ParsedPermission a, ParsedPermission b)903     private static void assertPermissionsEqual(ParsedPermission a, ParsedPermission b) {
904         assertComponentsEqual(a, b);
905         assertEquals(a.isTree(), b.isTree());
906 
907         // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform
908         // a full structural equality here because the code that serializes them isn't parser
909         // specific and is tested elsewhere.
910         assertEquals(ParsedPermissionUtils.getProtection(a),
911                 ParsedPermissionUtils.getProtection(b));
912         assertEquals(a.getGroup(), b.getGroup());
913         assertEquals(a.getFlags(), b.getFlags());
914 
915         if (a.getParsedPermissionGroup() != null && b.getParsedPermissionGroup() != null) {
916             assertPermissionGroupsEqual(a.getParsedPermissionGroup(), b.getParsedPermissionGroup());
917         } else if (a.getParsedPermissionGroup() != null || b.getParsedPermissionGroup() != null) {
918             throw new AssertionError();
919         }
920     }
921 
assertInstrumentationEqual(ParsedInstrumentation a, ParsedInstrumentation b)922     private static void assertInstrumentationEqual(ParsedInstrumentation a,
923             ParsedInstrumentation b) {
924         assertComponentsEqual(a, b);
925 
926         // Validity check for InstrumentationInfo.
927         assertEquals(a.getTargetPackage(), b.getTargetPackage());
928         assertEquals(a.getTargetProcesses(), b.getTargetProcesses());
929         assertEquals(a.isHandleProfiling(), b.isHandleProfiling());
930         assertEquals(a.isFunctionalTest(), b.isFunctionalTest());
931     }
932 
assertServicesEqual( AndroidPackage aPkg, ParsedService a, AndroidPackage bPkg, ParsedService b )933     private static void assertServicesEqual(
934             AndroidPackage aPkg,
935             ParsedService a,
936             AndroidPackage bPkg,
937             ParsedService b
938     ) {
939         assertComponentsEqual(a, b);
940 
941         // Validity check for ServiceInfo.
942         ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0,
943                 PackageUserStateInternal.DEFAULT, 0, mockPkgSetting(aPkg));
944         ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0,
945                 PackageUserStateInternal.DEFAULT, 0, mockPkgSetting(bPkg));
946         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
947         assertEquals(a.getName(), b.getName());
948     }
949 
assertProvidersEqual( AndroidPackage aPkg, ParsedProvider a, AndroidPackage bPkg, ParsedProvider b )950     private static void assertProvidersEqual(
951             AndroidPackage aPkg,
952             ParsedProvider a,
953             AndroidPackage bPkg,
954             ParsedProvider b
955     ) {
956         assertComponentsEqual(a, b);
957         assertEquals(a.getName(), b.getName());
958     }
959 
assertActivitiesEqual( AndroidPackage aPkg, ParsedActivity a, AndroidPackage bPkg, ParsedActivity b )960     private static void assertActivitiesEqual(
961             AndroidPackage aPkg,
962             ParsedActivity a,
963             AndroidPackage bPkg,
964             ParsedActivity b
965     ) {
966         assertComponentsEqual(a, b);
967 
968         // Validity check for ActivityInfo.
969         ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0,
970                 PackageUserStateInternal.DEFAULT, 0, mockPkgSetting(aPkg));
971         ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0,
972                 PackageUserStateInternal.DEFAULT, 0, mockPkgSetting(bPkg));
973         assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
974         assertEquals(a.getName(), b.getName());
975     }
976 
assertPermissionGroupsEqual(ParsedPermissionGroup a, ParsedPermissionGroup b)977     private static void assertPermissionGroupsEqual(ParsedPermissionGroup a,
978             ParsedPermissionGroup b) {
979         assertComponentsEqual(a, b);
980 
981         // Validity check for PermissionGroupInfo.
982         assertEquals(a.getName(), b.getName());
983         assertEquals(a.getDescriptionRes(), b.getDescriptionRes());
984     }
985 
assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that)986     private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) {
987         assertEquals(a.descriptionRes, that.descriptionRes);
988         assertEquals(a.theme, that.theme);
989         assertEquals(a.fullBackupContent, that.fullBackupContent);
990         assertEquals(a.uiOptions, that.uiOptions);
991         assertEquals(Integer.toBinaryString(a.flags), Integer.toBinaryString(that.flags));
992         assertEquals(a.privateFlags, that.privateFlags);
993         assertEquals(a.requiresSmallestWidthDp, that.requiresSmallestWidthDp);
994         assertEquals(a.compatibleWidthLimitDp, that.compatibleWidthLimitDp);
995         assertEquals(a.largestWidthLimitDp, that.largestWidthLimitDp);
996         assertEquals(a.nativeLibraryRootRequiresIsa, that.nativeLibraryRootRequiresIsa);
997         assertEquals(a.uid, that.uid);
998         assertEquals(a.minSdkVersion, that.minSdkVersion);
999         assertEquals(a.targetSdkVersion, that.targetSdkVersion);
1000         assertEquals(a.versionCode, that.versionCode);
1001         assertEquals(a.enabled, that.enabled);
1002         assertEquals(a.enabledSetting, that.enabledSetting);
1003         assertEquals(a.installLocation, that.installLocation);
1004         assertEquals(a.networkSecurityConfigRes, that.networkSecurityConfigRes);
1005         assertEquals(a.taskAffinity, that.taskAffinity);
1006         assertEquals(a.permission, that.permission);
1007         assertEquals(a.getKnownActivityEmbeddingCerts(), that.getKnownActivityEmbeddingCerts());
1008         assertEquals(a.processName, that.processName);
1009         assertEquals(a.className, that.className);
1010         assertEquals(a.manageSpaceActivityName, that.manageSpaceActivityName);
1011         assertEquals(a.backupAgentName, that.backupAgentName);
1012         assertEquals(a.volumeUuid, that.volumeUuid);
1013         assertEquals(a.scanSourceDir, that.scanSourceDir);
1014         assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir);
1015         assertEquals(a.sourceDir, that.sourceDir);
1016         assertEquals(a.publicSourceDir, that.publicSourceDir);
1017         assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs);
1018         assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs);
1019         assertArrayEquals(a.resourceDirs, that.resourceDirs);
1020         assertArrayEquals(a.overlayPaths, that.overlayPaths);
1021         assertEquals(a.seInfo, that.seInfo);
1022         assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles);
1023         assertEquals(a.dataDir, that.dataDir);
1024         assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
1025         assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
1026         assertEquals(a.nativeLibraryDir, that.nativeLibraryDir);
1027         assertEquals(a.secondaryNativeLibraryDir, that.secondaryNativeLibraryDir);
1028         assertEquals(a.nativeLibraryRootDir, that.nativeLibraryRootDir);
1029         assertEquals(a.primaryCpuAbi, that.primaryCpuAbi);
1030         assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi);
1031     }
1032 
setKnownFields(ParsingPackage pkg)1033     public static void setKnownFields(ParsingPackage pkg) {
1034         Bundle bundle = new Bundle();
1035         bundle.putString("key", "value");
1036 
1037         ParsedPermissionImpl permission = new ParsedPermissionImpl();
1038         permission.setParsedPermissionGroup(new ParsedPermissionGroupImpl());
1039 
1040         ((ParsedPackage) pkg.setBaseRevisionCode(100)
1041                 .setHardwareAccelerated(true)
1042                 .setSharedUserLabelResourceId(100)
1043                 .setInstallLocation(100)
1044                 .setRequiredForAllUsers(true)
1045                 .asSplit(
1046                         new String[]{"foo2"},
1047                         new String[]{"foo6"},
1048                         new int[]{100},
1049                         null
1050                 )
1051                 .set32BitAbiPreferred(true)
1052                 .setVolumeUuid("d52ef59a-7def-4541-bf21-4c28ed4b65a0")
1053                 .addPermission(permission)
1054                 .addPermissionGroup(new ParsedPermissionGroupImpl())
1055                 .addActivity(new ParsedActivityImpl())
1056                 .addReceiver(new ParsedActivityImpl())
1057                 .addProvider(new ParsedProviderImpl())
1058                 .addService(new ParsedServiceImpl())
1059                 .addInstrumentation(new ParsedInstrumentationImpl())
1060                 .addUsesPermission(new ParsedUsesPermissionImpl("foo7", 0))
1061                 .addImplicitPermission("foo25")
1062                 .addProtectedBroadcast("foo8")
1063                 .setSdkLibraryName("sdk12")
1064                 .setSdkLibVersionMajor(42)
1065                 .addUsesSdkLibrary("sdk23", 200, new String[]{"digest2"})
1066                 .setStaticSharedLibraryName("foo23")
1067                 .setStaticSharedLibraryVersion(100)
1068                 .addUsesStaticLibrary("foo23", 100, new String[]{"digest"})
1069                 .addLibraryName("foo10")
1070                 .addUsesLibrary("foo11")
1071                 .addUsesOptionalLibrary("foo12")
1072                 .addOriginalPackage("foo14")
1073                 .addAdoptPermission("foo16")
1074                 .setMetaData(bundle)
1075                 .setVersionName("foo17")
1076                 .setSharedUserId("foo18")
1077                 .setSigningDetails(
1078                         new SigningDetails(
1079                                 new Signature[]{new Signature(new byte[16])},
1080                                 SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
1081                                 new ArraySet<>(),
1082                                 null)
1083                 )
1084                 .setRestrictedAccountType("foo19")
1085                 .setRequiredAccountType("foo20")
1086                 .setOverlayTarget("foo21")
1087                 .setOverlayPriority(100)
1088                 .setUpgradeKeySets(new ArraySet<>())
1089                 .addPreferredActivityFilter("className", new ParsedIntentInfoImpl())
1090                 .addConfigPreference(new ConfigurationInfo())
1091                 .addReqFeature(new FeatureInfo())
1092                 .addFeatureGroup(new FeatureGroupInfo())
1093                 .setCompileSdkVersionCodeName("foo23")
1094                 .setCompileSdkVersion(100)
1095                 .setOverlayCategory("foo24")
1096                 .setOverlayIsStatic(true)
1097                 .setOverlayTargetOverlayableName("foo26")
1098                 .setVisibleToInstantApps(true)
1099                 .setSplitHasCode(0, true)
1100                 .hideAsParsed())
1101                 .setBaseApkPath("foo5")
1102                 .setPath("foo4")
1103                 .setVersionCode(100)
1104                 .setRestrictUpdateHash(new byte[16])
1105                 .setVersionCodeMajor(100)
1106                 .setCoreApp(true)
1107                 .hideAsFinal();
1108     }
1109 
assertAllFieldsExist(ParsedPackage pkg)1110     private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception {
1111         Field[] fields = ParsedPackage.class.getDeclaredFields();
1112 
1113         Set<String> nonSerializedFields = new HashSet<>();
1114         nonSerializedFields.add("mExtras");
1115         nonSerializedFields.add("packageUsageTimeMillis");
1116         nonSerializedFields.add("isStub");
1117 
1118         for (Field f : fields) {
1119             final Class<?> fieldType = f.getType();
1120 
1121             if (nonSerializedFields.contains(f.getName())) {
1122                 continue;
1123             }
1124 
1125             if (List.class.isAssignableFrom(fieldType)) {
1126                 // Validity check for list fields: Assume they're non-null and contain precisely
1127                 // one element.
1128                 List<?> list = (List<?>) f.get(pkg);
1129                 assertNotNull("List was null: " + f, list);
1130                 assertEquals(1, list.size());
1131             } else if (fieldType.getComponentType() != null) {
1132                 // Validity check for array fields: Assume they're non-null and contain precisely
1133                 // one element.
1134                 Object array = f.get(pkg);
1135                 assertNotNull(Array.get(array, 0));
1136             } else if (fieldType == String.class) {
1137                 // String fields: Check that they're set to "foo".
1138                 String value = (String) f.get(pkg);
1139 
1140                 assertTrue("Bad value for field: " + f, value != null && value.startsWith("foo"));
1141             } else if (fieldType == int.class) {
1142                 // int fields: Check that they're set to 100.
1143                 int value = (int) f.get(pkg);
1144                 assertEquals("Bad value for field: " + f, 100, value);
1145             } else if (fieldType == boolean.class) {
1146                 // boolean fields: Check that they're set to true.
1147                 boolean value = (boolean) f.get(pkg);
1148                 assertTrue("Bad value for field: " + f, value);
1149             } else {
1150                 // All other fields: Check that they're set.
1151                 Object o = f.get(pkg);
1152                 assertNotNull("Field was null: " + f, o);
1153             }
1154         }
1155     }
1156 }
1157 
1158