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