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