1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.pm.parsing;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.content.Context;
24 import android.content.IntentFilter;
25 import android.content.pm.PackageManager;
26 import android.content.pm.PermissionInfo;
27 import android.content.pm.parsing.FrameworkParsingPackageUtils;
28 import android.content.pm.parsing.result.ParseResult;
29 import android.content.pm.parsing.result.ParseTypeImpl;
30 import android.os.Build;
31 import android.os.Bundle;
32 import android.os.FileUtils;
33 import android.platform.test.annotations.Presubmit;
34 import android.util.Pair;
35 import android.util.SparseIntArray;
36 
37 import androidx.test.InstrumentationRegistry;
38 import androidx.test.filters.SmallTest;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.internal.pm.parsing.PackageParserException;
42 import com.android.internal.pm.parsing.pkg.ParsedPackage;
43 import com.android.internal.pm.pkg.component.ParsedActivityUtils;
44 import com.android.internal.pm.pkg.component.ParsedComponent;
45 import com.android.internal.pm.pkg.component.ParsedIntentInfo;
46 import com.android.internal.pm.pkg.component.ParsedPermission;
47 import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
48 import com.android.internal.util.ArrayUtils;
49 import com.android.server.pm.pkg.AndroidPackage;
50 import com.android.server.pm.test.service.server.R;
51 
52 import com.google.common.truth.Expect;
53 
54 import org.junit.Rule;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 
58 import java.io.File;
59 import java.io.InputStream;
60 import java.util.HashMap;
61 import java.util.List;
62 import java.util.Map;
63 import java.util.function.Function;
64 
65 /**
66  * {@link ParsedPackage} was moved to the server, so this test moved along with it.
67  *
68  * This should be eventually refactored to a comprehensive parsing test, combined with its
69  * server variant in the parent package.
70  *
71  * TODO(b/135203078): Remove this test and replicate the cases in the actual com.android.server
72  *  variant.
73  */
74 @Presubmit
75 @SmallTest
76 @RunWith(AndroidJUnit4.class)
77 public class PackageParserLegacyCoreTest {
78     private static final String RELEASED = null;
79     private static final String OLDER_PRE_RELEASE = "Q";
80     private static final String PRE_RELEASE = "R";
81     private static final String NEWER_PRE_RELEASE = "Z";
82 
83     // Codenames with a fingerprint attached to them. These may only be present in the apps
84     // declared min SDK and not as platform codenames.
85     private static final String OLDER_PRE_RELEASE_WITH_FINGERPRINT = "Q.fingerprint";
86     private static final String PRE_RELEASE_WITH_FINGERPRINT = "R.fingerprint";
87     private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "Z.fingerprint";
88 
89     private static final String[] CODENAMES_RELEASED = { /* empty */};
90     private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE};
91 
92     private static final int OLDER_VERSION = 10;
93     private static final int PLATFORM_VERSION = 20;
94     private static final int NEWER_VERSION = 30;
95 
96     private static final int DISALLOW_PRERELEASE = -1;
97     private static final int DISALLOW_RELEASED = -1;
98 
99     @Rule public final Expect expect = Expect.create();
100 
verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename, boolean isPlatformReleased, int expectedMinSdk)101     private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
102             boolean isPlatformReleased, int expectedMinSdk) {
103         final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat();
104         final ParseResult<Integer> result = FrameworkParsingPackageUtils.computeMinSdkVersion(
105                 minSdkVersion,
106                 minSdkCodename,
107                 PLATFORM_VERSION,
108                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
109                 input);
110 
111         if (expectedMinSdk == -1) {
112             assertTrue(result.isError());
113         } else {
114             assertTrue(result.isSuccess());
115             assertEquals(expectedMinSdk, (int) result.getResult());
116         }
117     }
118 
119     @Test
testComputeMinSdkVersion_preReleasePlatform()120     public void testComputeMinSdkVersion_preReleasePlatform() {
121         // Do allow older release minSdkVersion on pre-release platform.
122         // APP: Released API 10
123         // DEV: Pre-release API 20
124         verifyComputeMinSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION);
125 
126         // Do allow same release minSdkVersion on pre-release platform.
127         // APP: Released API 20
128         // DEV: Pre-release API 20
129         verifyComputeMinSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION);
130 
131         // Don't allow newer release minSdkVersion on pre-release platform.
132         // APP: Released API 30
133         // DEV: Pre-release API 20
134         verifyComputeMinSdkVersion(NEWER_VERSION, RELEASED, false, -1);
135 
136         // Don't allow older pre-release minSdkVersion on pre-release platform.
137         // APP: Pre-release API 10
138         // DEV: Pre-release API 20
139         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
140         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
141 
142         // Do allow same pre-release minSdkVersion on pre-release platform,
143         // but overwrite the specified version with CUR_DEVELOPMENT.
144         // APP: Pre-release API 20
145         // DEV: Pre-release API 20
146         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
147                 Build.VERSION_CODES.CUR_DEVELOPMENT);
148         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
149                 Build.VERSION_CODES.CUR_DEVELOPMENT);
150 
151 
152         // Don't allow newer pre-release minSdkVersion on pre-release platform.
153         // APP: Pre-release API 30
154         // DEV: Pre-release API 20
155         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
156                 DISALLOW_PRERELEASE);
157         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
158                 DISALLOW_PRERELEASE);
159     }
160 
161     @Test
testComputeMinSdkVersion_releasedPlatform()162     public void testComputeMinSdkVersion_releasedPlatform() {
163         // Do allow older release minSdkVersion on released platform.
164         // APP: Released API 10
165         // DEV: Released API 20
166         verifyComputeMinSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION);
167 
168         // Do allow same release minSdkVersion on released platform.
169         // APP: Released API 20
170         // DEV: Released API 20
171         verifyComputeMinSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION);
172 
173         // Don't allow newer release minSdkVersion on released platform.
174         // APP: Released API 30
175         // DEV: Released API 20
176         verifyComputeMinSdkVersion(NEWER_VERSION, RELEASED, true, -1);
177 
178         // Don't allow older pre-release minSdkVersion on released platform.
179         // APP: Pre-release API 10
180         // DEV: Released API 20
181         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true,
182                 DISALLOW_RELEASED);
183         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true,
184                 DISALLOW_RELEASED);
185 
186         // Don't allow same pre-release minSdkVersion on released platform.
187         // APP: Pre-release API 20
188         // DEV: Released API 20
189         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true,
190                 DISALLOW_RELEASED);
191         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true,
192                 DISALLOW_RELEASED);
193 
194 
195         // Don't allow newer pre-release minSdkVersion on released platform.
196         // APP: Pre-release API 30
197         // DEV: Released API 20
198         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true,
199                 DISALLOW_RELEASED);
200         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true,
201                 DISALLOW_RELEASED);
202     }
203 
verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename, boolean isPlatformReleased, boolean allowUnknownCodenames, int expectedTargetSdk)204     private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
205             boolean isPlatformReleased, boolean allowUnknownCodenames, int expectedTargetSdk) {
206         final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat();
207         final ParseResult<Integer> result = FrameworkParsingPackageUtils.computeTargetSdkVersion(
208                 targetSdkVersion,
209                 targetSdkCodename,
210                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
211                 input,
212                 allowUnknownCodenames);
213 
214         if (expectedTargetSdk == -1) {
215             assertTrue(result.isError());
216         } else {
217             assertTrue(result.isSuccess());
218             assertEquals(expectedTargetSdk, (int) result.getResult());
219         }
220     }
221 
222     @Test
testComputeTargetSdkVersion_preReleasePlatform()223     public void testComputeTargetSdkVersion_preReleasePlatform() {
224         // Do allow older release targetSdkVersion on pre-release platform.
225         // APP: Released API 10
226         // DEV: Pre-release API 20
227         verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, false, OLDER_VERSION);
228 
229         // Do allow same release targetSdkVersion on pre-release platform.
230         // APP: Released API 20
231         // DEV: Pre-release API 20
232         verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, false, PLATFORM_VERSION);
233 
234         // Do allow newer release targetSdkVersion on pre-release platform.
235         // APP: Released API 30
236         // DEV: Pre-release API 20
237         verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, false, NEWER_VERSION);
238 
239         // Don't allow older pre-release targetSdkVersion on pre-release platform.
240         // APP: Pre-release API 10
241         // DEV: Pre-release API 20
242         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, false, -1);
243         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false,
244                 false, -1
245         );
246 
247         // Don't allow older pre-release targetSdkVersion on pre-release platform when
248         // allowUnknownCodenames is true.
249         // APP: Pre-release API 10
250         // DEV: Pre-release API 20
251         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false,
252                 true, -1);
253         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false,
254                 true, -1);
255 
256         // Do allow same pre-release targetSdkVersion on pre-release platform,
257         // but overwrite the specified version with CUR_DEVELOPMENT.
258         // APP: Pre-release API 20
259         // DEV: Pre-release API 20
260         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
261                 false, Build.VERSION_CODES.CUR_DEVELOPMENT);
262         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
263                 false, Build.VERSION_CODES.CUR_DEVELOPMENT);
264 
265         // Don't allow newer pre-release targetSdkVersion on pre-release platform.
266         // APP: Pre-release API 30
267         // DEV: Pre-release API 20
268         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, false,
269                 DISALLOW_PRERELEASE);
270         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
271                 false, DISALLOW_PRERELEASE);
272 
273         // Do allow newer pre-release targetSdkVersion on pre-release platform when
274         // allowUnknownCodenames is true.
275         // APP: Pre-release API 30
276         // DEV: Pre-release API 20
277         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
278                 true, Build.VERSION_CODES.CUR_DEVELOPMENT);
279         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
280                 true, Build.VERSION_CODES.CUR_DEVELOPMENT);
281 
282     }
283 
284     @Test
testComputeTargetSdkVersion_releasedPlatform()285     public void testComputeTargetSdkVersion_releasedPlatform() {
286         // Do allow older release targetSdkVersion on released platform.
287         // APP: Released API 10
288         // DEV: Released API 20
289         verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, false, OLDER_VERSION);
290 
291         // Do allow same release targetSdkVersion on released platform.
292         // APP: Released API 20
293         // DEV: Released API 20
294         verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, false, PLATFORM_VERSION);
295 
296         // Do allow newer release targetSdkVersion on released platform.
297         // APP: Released API 30
298         // DEV: Released API 20
299         verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, false, NEWER_VERSION);
300 
301         // Don't allow older pre-release targetSdkVersion on released platform.
302         // APP: Pre-release API 10
303         // DEV: Released API 20
304         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, false,
305                 DISALLOW_RELEASED);
306         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true,
307                 false, DISALLOW_RELEASED);
308 
309         // Don't allow same pre-release targetSdkVersion on released platform.
310         // APP: Pre-release API 20
311         // DEV: Released API 20
312         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, false,
313                 DISALLOW_RELEASED);
314         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, false,
315                 DISALLOW_RELEASED);
316 
317         // Don't allow same pre-release targetSdkVersion on released platform when
318         // allowUnknownCodenames is true.
319         // APP: Pre-release API 20
320         // DEV: Released API 20
321         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, true,
322                 DISALLOW_RELEASED);
323         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, true,
324                 DISALLOW_RELEASED);
325 
326         // Don't allow newer pre-release targetSdkVersion on released platform.
327         // APP: Pre-release API 30
328         // DEV: Released API 20
329         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, false,
330                 DISALLOW_RELEASED);
331         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true,
332                 false, DISALLOW_RELEASED);
333         // Do allow newer pre-release targetSdkVersion on released platform when
334         // allowUnknownCodenames is true.
335         // APP: Pre-release API 30
336         // DEV: Released API 20
337         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, true,
338                 Build.VERSION_CODES.CUR_DEVELOPMENT);
339         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true,
340                 true, Build.VERSION_CODES.CUR_DEVELOPMENT);
341     }
342 
343     /**
344      * Unit test for PackageParser.getActivityConfigChanges().
345      * If the bit is 1 in the original configChanges, it is still 1 in the final configChanges.
346      * If the bit is 0 in the original configChanges and the bit is not set to 1 in
347      * recreateOnConfigChanges, the bit is changed to 1 in the final configChanges by default.
348      */
349     @Test
testGetActivityConfigChanges()350     public void testGetActivityConfigChanges() {
351         // Not set in either configChanges or recreateOnConfigChanges.
352         int configChanges = 0x0000; // 00000000.
353         int recreateOnConfigChanges = 0x0000; // 00000000.
354         int finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
355                 recreateOnConfigChanges);
356         assertEquals(0x0003, finalConfigChanges); // Should be 00000011.
357 
358         // Not set in configChanges, but set in recreateOnConfigChanges.
359         configChanges = 0x0000; // 00000000.
360         recreateOnConfigChanges = 0x0003; // 00000011.
361         finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
362                 recreateOnConfigChanges);
363         assertEquals(0x0000, finalConfigChanges); // Should be 00000000.
364 
365         // Set in configChanges.
366         configChanges = 0x0003; // 00000011.
367         recreateOnConfigChanges = 0X0000; // 00000000.
368         finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
369                 recreateOnConfigChanges);
370         assertEquals(0x0003, finalConfigChanges); // Should be 00000011.
371 
372         recreateOnConfigChanges = 0x0003; // 00000011.
373         finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
374                 recreateOnConfigChanges);
375         assertEquals(0x0003, finalConfigChanges); // Should still be 00000011.
376 
377         // Other bit set in configChanges.
378         configChanges = 0x0080; // 10000000, orientation.
379         recreateOnConfigChanges = 0x0000; // 00000000.
380         finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
381                 recreateOnConfigChanges);
382         assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
383     }
384 
385     /**
386      * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
387      * succeeded, or {@code null} otherwise.
388      */
copyRawResourceToFile(String baseName, int resourceId)389     File copyRawResourceToFile(String baseName, int resourceId) {
390         // Copy the resource to a file.
391         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
392         InputStream is = context.getResources().openRawResource(resourceId);
393         File outFile = null;
394         try {
395             outFile = new File(context.getFilesDir(), baseName);
396             assertTrue(FileUtils.copyToFile(is, outFile));
397             return outFile;
398         } catch (Exception e) {
399             if (outFile != null) {
400                 outFile.delete();
401             }
402 
403             return null;
404         }
405     }
406 
407     /**
408      * Attempts to parse a package.
409      *
410      * APKs are put into coretests/apks/packageparser_*.
411      *
412      * @param apkFileName   temporary file name to store apk extracted from resources
413      * @param apkResourceId identifier of the apk as a resource
414      */
parsePackage(String apkFileName, int apkResourceId, Function<ParsedPackage, ParsedPackage> converter)415     ParsedPackage parsePackage(String apkFileName, int apkResourceId,
416             Function<ParsedPackage, ParsedPackage> converter) throws Exception {
417         // Copy the resource to a file.
418         File outFile = null;
419         try {
420             outFile = copyRawResourceToFile(apkFileName, apkResourceId);
421             return converter.apply(new TestPackageParser2()
422                     .parsePackage(outFile, 0 /* flags */, false));
423         } finally {
424             if (outFile != null) {
425                 outFile.delete();
426             }
427         }
428     }
429 
430     /**
431      * Asserts basic properties about a component.
432      */
assertComponent(String className, int numIntents, ParsedComponent component)433     private void assertComponent(String className, int numIntents, ParsedComponent component) {
434         assertEquals(className, component.getName());
435         assertEquals(numIntents, component.getIntents().size());
436     }
437 
438     /**
439      * Asserts four regularly-named components of each type: one Activity, one Service, one
440      * Provider, and one Receiver.
441      *
442      * @param template templated string with %s subbed with Activity, Service, Provider, Receiver
443      */
assertOneComponentOfEachType(String template, AndroidPackage p)444     private void assertOneComponentOfEachType(String template, AndroidPackage p) {
445         assertEquals(1, p.getActivities().size());
446         assertComponent(String.format(template, "Activity"),
447                 0 /* intents */, p.getActivities().get(0));
448         assertEquals(1, p.getServices().size());
449         assertComponent(String.format(template, "Service"),
450                 0 /* intents */, p.getServices().get(0));
451         assertEquals(1, p.getProviders().size());
452         assertComponent(String.format(template, "Provider"),
453                 0 /* intents */, p.getProviders().get(0));
454         assertEquals(1, p.getReceivers().size());
455         assertComponent(String.format(template, "Receiver"),
456                 0 /* intents */, p.getReceivers().get(0));
457     }
458 
assertPermission(String name, int protectionLevel, ParsedPermission permission)459     private void assertPermission(String name, int protectionLevel, ParsedPermission permission) {
460         assertEquals(name, permission.getName());
461         assertEquals(protectionLevel, ParsedPermissionUtils.getProtection(permission));
462     }
463 
assertMetadata(Bundle b, String... keysAndValues)464     private void assertMetadata(Bundle b, String... keysAndValues) {
465         assertTrue("Odd number of elements in keysAndValues", (keysAndValues.length % 2) == 0);
466 
467         assertNotNull(b);
468         assertEquals(keysAndValues.length / 2, b.size());
469 
470         for (int i = 0; i < keysAndValues.length; i += 2) {
471             final String key = keysAndValues[i];
472             final String value = keysAndValues[i + 1];
473 
474             assertEquals(value, b.getString(key));
475         }
476     }
477 
478     // TODO Add a "_cached" test for testMultiPackageComponents() too, after fixing b/64295061.
479     // Package.writeToParcel can't handle circular package references.
480 
481     @Test
testPackageWithComponents_no_cache()482     public void testPackageWithComponents_no_cache() throws Exception {
483         checkPackageWithComponents(p -> p);
484     }
485 
486     @Test
testPackageWithComponents_cached()487     public void testPackageWithComponents_cached() throws Exception {
488         checkPackageWithComponents(p ->
489                 PackageCacher.fromCacheEntryStatic(PackageCacher.toCacheEntryStatic(p)));
490     }
491 
checkPackageWithComponents( Function<ParsedPackage, ParsedPackage> converter)492     private void checkPackageWithComponents(
493             Function<ParsedPackage, ParsedPackage> converter) throws Exception {
494         ParsedPackage p = parsePackage(
495                 "install_complete_package_info.apk", R.raw.install_complete_package_info,
496                 converter);
497         String packageName = "com.android.frameworks.coretests.install_complete_package_info";
498 
499         assertEquals(packageName, p.getPackageName());
500         assertEquals(1, p.getPermissions().size());
501         assertPermission(
502                 "com.android.frameworks.coretests.install_complete_package_info.test_permission",
503                 PermissionInfo.PROTECTION_NORMAL, p.getPermissions().get(0));
504 
505         findAndRemoveAppDetailsActivity(p);
506 
507         assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
508 
509         assertMetadata(p.getMetaData(),
510                 "key1", "value1",
511                 "key2", "this_is_app");
512         assertMetadata(p.getActivities().get(0).getMetaData(),
513                 "key1", "value1",
514                 "key2", "this_is_activity");
515         assertMetadata(p.getServices().get(0).getMetaData(),
516                 "key1", "value1",
517                 "key2", "this_is_service");
518         assertMetadata(p.getReceivers().get(0).getMetaData(),
519                 "key1", "value1",
520                 "key2", "this_is_receiver");
521         assertMetadata(p.getProviders().get(0).getMetaData(),
522                 "key1", "value1",
523                 "key2", "this_is_provider");
524 
525     }
526 
findAndRemoveAppDetailsActivity(ParsedPackage p)527     private void findAndRemoveAppDetailsActivity(ParsedPackage p) {
528         // Hidden "app details" activity is added to every package.
529         boolean foundAppDetailsActivity = false;
530         for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) {
531             if (p.getActivities().get(i).getClassName().equals(
532                     PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
533                 foundAppDetailsActivity = true;
534                 p.getActivities().remove(i);
535                 break;
536             }
537         }
538         assertTrue("Did not find app details activity", foundAppDetailsActivity);
539     }
540 
541     @Test
testPackageWithIntentFilters_no_cache()542     public void testPackageWithIntentFilters_no_cache() throws Exception {
543         checkPackageWithIntentFilters(p -> p);
544     }
545 
546     @Test
testPackageWithIntentFilters_cached()547     public void testPackageWithIntentFilters_cached() throws Exception {
548         checkPackageWithIntentFilters(p ->
549                 PackageCacher.fromCacheEntryStatic(PackageCacher.toCacheEntryStatic(p)));
550     }
551 
checkPackageWithIntentFilters( Function<ParsedPackage, ParsedPackage> converter)552     private void checkPackageWithIntentFilters(
553             Function<ParsedPackage, ParsedPackage> converter) throws Exception {
554         ParsedPackage p = parsePackage(
555                 "install_intent_filters.apk", R.raw.install_intent_filters,
556                 converter);
557         String packageName = "com.android.frameworks.servicestests.install_intent_filters";
558 
559         assertEquals(packageName, p.getPackageName());
560 
561         findAndRemoveAppDetailsActivity(p);
562 
563         assertEquals("Expected exactly one activity", 1, p.getActivities().size());
564         List<ParsedIntentInfo> intentInfos = p.getActivities().get(0).getIntents();
565         assertEquals("Expected exactly one intent filter", 1, intentInfos.size());
566         IntentFilter intentFilter = intentInfos.get(0).getIntentFilter();
567         assertEquals("Expected exactly one mime group in intent filter", 1,
568                 intentFilter.countMimeGroups());
569         assertTrue("Did not find expected mime group 'mime_group_1'",
570                 intentFilter.hasMimeGroup("mime_group_1"));
571     }
572 
573     @Test
testUsesSdk()574     public void testUsesSdk() throws Exception {
575         ParsedPackage pkg;
576         SparseIntArray minExtVers;
577         pkg = parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
578         minExtVers = pkg.getMinExtensionVersions();
579         assertEquals(1, minExtVers.size());
580         assertEquals(0, minExtVers.get(30, -1));
581 
582         pkg = parsePackage("install_uses_sdk.apk_r0_s0", R.raw.install_uses_sdk_r0_s0, x -> x);
583         minExtVers = pkg.getMinExtensionVersions();
584         assertEquals(2, minExtVers.size());
585         assertEquals(0, minExtVers.get(30, -1));
586         assertEquals(0, minExtVers.get(31, -1));
587 
588         Map<Pair<String, Integer>, Integer> appToError = new HashMap<>();
589         appToError.put(Pair.create("install_uses_sdk.apk_r10000", R.raw.install_uses_sdk_r10000),
590                        PackageManager.INSTALL_FAILED_OLDER_SDK);
591         appToError.put(
592                 Pair.create("install_uses_sdk.apk_r0_s10000", R.raw.install_uses_sdk_r0_s10000),
593                 PackageManager.INSTALL_FAILED_OLDER_SDK);
594 
595         appToError.put(Pair.create("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0),
596                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
597         appToError.put(Pair.create("install_uses_sdk.apk_q0_r0", R.raw.install_uses_sdk_q0_r0),
598                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
599         appToError.put(Pair.create("install_uses_sdk.apk_r_none", R.raw.install_uses_sdk_r_none),
600                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
601         appToError.put(Pair.create("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0),
602                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
603 
604         for (Map.Entry<Pair<String, Integer>, Integer> entry : appToError.entrySet()) {
605             String filename = entry.getKey().first;
606             int resId = entry.getKey().second;
607             int result = entry.getValue();
608             try {
609                 parsePackage(filename, resId, x -> x);
610                 expect.withMessage("Expected parsing error %s from %s", result, filename).fail();
611             } catch (PackageParserException expected) {
612                 expect.that(expected.error).isEqualTo(result);
613             }
614         }
615     }
616 }
617