1 /*
2  * Copyright (C) 2019 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;
18 
19 import static android.content.pm.SharedLibraryInfo.TYPE_DYNAMIC;
20 import static android.content.pm.SharedLibraryInfo.TYPE_SDK_PACKAGE;
21 import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
22 import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
23 
24 import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
25 import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
26 import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
27 import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
28 import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
29 
30 import static org.hamcrest.MatcherAssert.assertThat;
31 import static org.hamcrest.Matchers.empty;
32 import static org.hamcrest.Matchers.hasItems;
33 import static org.hamcrest.Matchers.nullValue;
34 import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
35 import static org.hamcrest.core.Is.is;
36 import static org.junit.Assert.assertNotSame;
37 import static org.mockito.ArgumentMatchers.any;
38 import static org.mockito.ArgumentMatchers.anyBoolean;
39 import static org.mockito.ArgumentMatchers.nullable;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.when;
42 
43 import android.Manifest;
44 import android.content.pm.ApplicationInfo;
45 import android.content.pm.PackageInfo;
46 import android.content.pm.SharedLibraryInfo;
47 import android.content.res.TypedArray;
48 import android.os.Environment;
49 import android.os.UserHandle;
50 import android.platform.test.annotations.Presubmit;
51 import android.util.Pair;
52 
53 import com.android.internal.pm.parsing.pkg.PackageImpl;
54 import com.android.internal.pm.parsing.pkg.ParsedPackage;
55 import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
56 import com.android.internal.pm.pkg.parsing.ParsingPackage;
57 import com.android.server.compat.PlatformCompat;
58 import com.android.server.pm.parsing.PackageInfoUtils;
59 import com.android.server.pm.pkg.AndroidPackage;
60 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
61 
62 import org.hamcrest.BaseMatcher;
63 import org.hamcrest.Description;
64 import org.hamcrest.Matcher;
65 import org.junit.Before;
66 import org.junit.Test;
67 import org.junit.runner.RunWith;
68 import org.mockito.Mock;
69 import org.mockito.junit.MockitoJUnitRunner;
70 
71 import java.io.File;
72 import java.util.UUID;
73 
74 @RunWith(MockitoJUnitRunner.class)
75 @Presubmit
76 // TODO: shared user tests
77 public class ScanTests {
78 
79     private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
80 
81     private static final UUID UUID_ONE = UUID.randomUUID();
82     private static final UUID UUID_TWO = UUID.randomUUID();
83 
84     @Mock
85     PackageAbiHelper mMockPackageAbiHelper;
86     @Mock
87     UserManagerInternal mMockUserManager;
88     @Mock
89     PlatformCompat mMockCompatibility;
90     @Mock
91     PackageManagerServiceInjector mMockInjector;
92     @Mock
93     PackageManagerService mMockPackageManager;
94     @Mock
95     Installer mMockInstaller;
96 
97     @Before
setupInjector()98     public void setupInjector() {
99         when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper);
100         when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager);
101         when(mMockInjector.getCompatibility()).thenReturn(mMockCompatibility);
102 
103         DomainVerificationManagerInternal domainVerificationManager =
104                 mock(DomainVerificationManagerInternal.class);
105         when(domainVerificationManager.generateNewId())
106                 .thenAnswer(invocation -> UUID.randomUUID());
107 
108         when(mMockInjector.getDomainVerificationManagerInternal())
109                 .thenReturn(domainVerificationManager);
110         when(mMockInjector.getInstaller()).thenReturn(mMockInstaller);
111     }
112 
113     @Before
setupDefaultUser()114     public void setupDefaultUser() {
115         when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
116     }
117 
118     @Before
setupDefaultAbiBehavior()119     public void setupDefaultAbiBehavior() throws Exception {
120         when(mMockPackageAbiHelper.derivePackageAbi(
121                 any(AndroidPackage.class), anyBoolean(), anyBoolean(), nullable(String.class),
122                 any(File.class)))
123                 .thenReturn(new Pair<>(
124                         new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
125                         new PackageAbiHelper.NativeLibraryPaths(
126                                 "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
127         when(mMockPackageAbiHelper.deriveNativeLibraryPaths(
128                 any(AndroidPackage.class), anyBoolean(), anyBoolean(), any(File.class)))
129                 .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
130                         "getRootDir", true, "getNativeDir", "getNativeDir2"
131                 ));
132         when(mMockPackageAbiHelper.getBundledAppAbis(
133                 any(AndroidPackage.class)))
134                 .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
135     }
136 
137     @Test
newInstallSimpleAllNominal()138     public void newInstallSimpleAllNominal() throws Exception {
139         final ScanRequest scanRequest =
140                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
141                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
142                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
143                         .build();
144 
145         final ScanResult scanResult = executeScan(scanRequest);
146 
147         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
148         assertThat(scanResult.mExistingSettingCopied, is(false));
149         assertPathsNotDerived(scanResult);
150     }
151 
152     @Test
newInstallForAllUsers()153     public void newInstallForAllUsers() throws Exception {
154         final int[] userIds = {0, 10, 11};
155         when(mMockUserManager.getUserIds()).thenReturn(userIds);
156 
157         final ScanRequest scanRequest =
158                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
159                         .setRealPkgName(null)
160                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
161                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
162                         .build();
163         final ScanResult scanResult = executeScan(scanRequest);
164 
165         for (int uid : userIds) {
166             assertThat(scanResult.mPkgSetting.readUserState(uid).isInstalled(), is(true));
167         }
168     }
169 
170     @Test
installRealPackageName()171     public void installRealPackageName() throws Exception {
172         final ScanRequest scanRequest =
173                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
174                         .setRealPkgName("com.package.real")
175                         .build();
176 
177         final ScanResult scanResult = executeScan(scanRequest);
178 
179         assertThat(scanResult.mPkgSetting.getRealName(), is("com.package.real"));
180 
181         final ScanRequest scanRequestNoRealPkg =
182                 createBasicScanRequestBuilder(
183                         createBasicPackage(DUMMY_PACKAGE_NAME)
184                                 .addOriginalPackage("com.package.real"))
185                         .build();
186 
187         final ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
188         assertThat(scanResultNoReal.mPkgSetting.getRealName(), nullValue());
189     }
190 
191     @Test
updateSimpleNominal()192     public void updateSimpleNominal() throws Exception {
193         when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
194 
195         final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
196                 .setPrimaryCpuAbiString("primaryCpuAbi")
197                 .setSecondaryCpuAbiString("secondaryCpuAbi")
198                 .build();
199         final ScanRequest scanRequest =
200                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
201                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
202                         .setPkgSetting(pkgSetting)
203                         .build();
204 
205 
206         final ScanResult scanResult = executeScan(scanRequest);
207 
208         assertThat(scanResult.mExistingSettingCopied, is(true));
209 
210         // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
211         assertNotSame(pkgSetting, scanResult.mPkgSetting);
212 
213         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
214 
215         assertThat(scanResult.mPkgSetting.getPrimaryCpuAbiLegacy(), is("primaryCpuAbi"));
216         assertThat(scanResult.mPkgSetting.getSecondaryCpuAbiLegacy(), is("secondaryCpuAbi"));
217         assertThat(scanResult.mPkgSetting.getCpuAbiOverride(), nullValue());
218 
219         assertPathsNotDerived(scanResult);
220     }
221 
222     @Test
updateInstantSimpleNominal()223     public void updateInstantSimpleNominal() throws Exception {
224         when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
225 
226         final PackageSetting existingPkgSetting =
227                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
228                         .setInstantAppUserState(0, true)
229                         .build();
230 
231         final ScanRequest scanRequest =
232                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
233                         .setPkgSetting(existingPkgSetting)
234                         .build();
235 
236 
237         final ScanResult scanResult = executeScan(scanRequest);
238 
239         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
240     }
241 
242     @Test
installSdkLibrary()243     public void installSdkLibrary() throws Exception {
244         final ParsedPackage pkg = ((ParsedPackage) createBasicPackage("ogl.sdk_123")
245                 .setSdkLibraryName("ogl.sdk")
246                 .setSdkLibVersionMajor(123)
247                 .hideAsParsed())
248                 .setPackageName("ogl.sdk_123")
249                 .setVersionCodeMajor(5)
250                 .setVersionCode(678)
251                 .setBaseApkPath("/some/path.apk")
252                 .setSplitCodePaths(new String[] {"/some/other/path.apk"});
253 
254         final ScanRequest scanRequest = new ScanRequestBuilder(pkg)
255                 .setUser(UserHandle.of(0)).build();
256 
257         final ScanResult scanResult = executeScan(scanRequest);
258 
259         assertThat(scanResult.mSdkSharedLibraryInfo.getPackageName(), is("ogl.sdk_123"));
260         assertThat(scanResult.mSdkSharedLibraryInfo.getName(), is("ogl.sdk"));
261         assertThat(scanResult.mSdkSharedLibraryInfo.getLongVersion(), is(123L));
262         assertThat(scanResult.mSdkSharedLibraryInfo.getType(), is(TYPE_SDK_PACKAGE));
263         assertThat(scanResult.mSdkSharedLibraryInfo.getDeclaringPackage().getPackageName(),
264                 is("ogl.sdk_123"));
265         assertThat(scanResult.mSdkSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
266                 is(pkg.getLongVersionCode()));
267         assertThat(scanResult.mSdkSharedLibraryInfo.getAllCodePaths(),
268                 hasItems("/some/path.apk", "/some/other/path.apk"));
269         assertThat(scanResult.mSdkSharedLibraryInfo.getDependencies(), nullValue());
270         assertThat(scanResult.mSdkSharedLibraryInfo.getDependentPackages(), empty());
271     }
272 
273     @Test
installStaticSharedLibrary()274     public void installStaticSharedLibrary() throws Exception {
275         final ParsedPackage pkg = ((ParsedPackage) createBasicPackage("static.lib.pkg")
276                 .setStaticSharedLibraryName("static.lib")
277                 .setStaticSharedLibraryVersion(123L)
278                 .hideAsParsed())
279                 .setPackageName("static.lib.pkg.123")
280                 .setVersionCodeMajor(1)
281                 .setVersionCode(234)
282                 .setBaseApkPath("/some/path.apk")
283                 .setSplitCodePaths(new String[] {"/some/other/path.apk"});
284 
285         final ScanRequest scanRequest = new ScanRequestBuilder(pkg)
286                 .setUser(UserHandle.of(0)).build();
287 
288 
289         final ScanResult scanResult = executeScan(scanRequest);
290 
291         assertThat(scanResult.mStaticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
292         assertThat(scanResult.mStaticSharedLibraryInfo.getName(), is("static.lib"));
293         assertThat(scanResult.mStaticSharedLibraryInfo.getLongVersion(), is(123L));
294         assertThat(scanResult.mStaticSharedLibraryInfo.getType(), is(TYPE_STATIC));
295         assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
296                 is("static.lib.pkg"));
297         assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
298                 is(pkg.getLongVersionCode()));
299         assertThat(scanResult.mStaticSharedLibraryInfo.getAllCodePaths(),
300                 hasItems("/some/path.apk", "/some/other/path.apk"));
301         assertThat(scanResult.mStaticSharedLibraryInfo.getDependencies(), nullValue());
302         assertThat(scanResult.mStaticSharedLibraryInfo.getDependentPackages(), empty());
303     }
304 
305     @Test
installDynamicLibraries()306     public void installDynamicLibraries() throws Exception {
307         final ParsedPackage pkg = ((ParsedPackage) createBasicPackage(
308                 "dynamic.lib.pkg")
309                 .addLibraryName("liba")
310                 .addLibraryName("libb")
311                 .hideAsParsed())
312                 .setVersionCodeMajor(1)
313                 .setVersionCode(234)
314                 .setBaseApkPath("/some/path.apk")
315                 .setSplitCodePaths(new String[] {"/some/other/path.apk"});
316 
317         final ScanRequest scanRequest =
318                 new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
319 
320 
321         final ScanResult scanResult = executeScan(scanRequest);
322 
323         final SharedLibraryInfo dynamicLib0 = scanResult.mDynamicSharedLibraryInfos.get(0);
324         assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
325         assertThat(dynamicLib0.getName(), is("liba"));
326         assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
327         assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
328         assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
329         assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
330                 is(pkg.getLongVersionCode()));
331         assertThat(dynamicLib0.getAllCodePaths(),
332                 hasItems("/some/path.apk", "/some/other/path.apk"));
333         assertThat(dynamicLib0.getDependencies(), nullValue());
334         assertThat(dynamicLib0.getDependentPackages(), empty());
335 
336         final SharedLibraryInfo dynamicLib1 = scanResult.mDynamicSharedLibraryInfos.get(1);
337         assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
338         assertThat(dynamicLib1.getName(), is("libb"));
339         assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
340         assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
341         assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
342         assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
343                 is(pkg.getLongVersionCode()));
344         assertThat(dynamicLib1.getAllCodePaths(),
345                 hasItems("/some/path.apk", "/some/other/path.apk"));
346         assertThat(dynamicLib1.getDependencies(), nullValue());
347         assertThat(dynamicLib1.getDependentPackages(), empty());
348     }
349 
350     @Test
volumeUuidChangesOnUpdate()351     public void volumeUuidChangesOnUpdate() throws Exception {
352         final PackageSetting pkgSetting =
353                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
354                         .setVolumeUuid("someUuid")
355                         .build();
356 
357         final ParsedPackage basicPackage = ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
358                 .setVolumeUuid(UUID_TWO.toString())
359                 .hideAsParsed());
360 
361 
362         final ScanResult scanResult = executeScan(
363                 new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
364 
365         assertThat(scanResult.mPkgSetting.getVolumeUuid(), is(UUID_TWO.toString()));
366     }
367 
368     @Test
scanFirstBoot_apexDontDeriveAbis()369     public void scanFirstBoot_apexDontDeriveAbis() throws Exception {
370         final PackageSetting pkgSetting =
371                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
372                         .setPkgFlags(ApplicationInfo.FLAG_SYSTEM).build();
373 
374         final String codePath = "/data/apex/" + DUMMY_PACKAGE_NAME + ".apex";
375 
376         // Create the ParsedPackage for the apex
377         final ParsedPackage basicPackage =
378                 ((ParsedPackage) new PackageImpl(DUMMY_PACKAGE_NAME, codePath, codePath,
379                         mock(TypedArray.class), false, null)
380                         .setVolumeUuid(UUID_ONE.toString())
381                         .hideAsParsed())
382                         .setVersionCodeMajor(1)
383                         .setVersionCode(2345)
384                         .setSystem(true);
385 
386         when(mMockInjector.getAbiHelper()).thenReturn(new PackageAbiHelperImpl());
387 
388         // prepare the scan request with the scanflag (SCAN_FIRST_BOOT_OR_UPGRADE | SCAN_AS_APEX)
389         final ScanResult scanResult = executeScan(new ScanRequestBuilder(basicPackage)
390                 .setPkgSetting(pkgSetting)
391                 .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE | SCAN_AS_APEX)
392                 .build());
393 
394         final PackageSetting resultSetting = scanResult.mPkgSetting;
395         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
396                 resultSetting.getPkg(), 0, pkgSetting.getUserStateOrDefault(0), 0, resultSetting);
397         assertThat(applicationInfo.primaryCpuAbi, nullValue());
398         assertThat(applicationInfo.primaryCpuAbi, nullValue());
399         assertThat(applicationInfo.secondaryCpuAbi, nullValue());
400 
401         assertThat(applicationInfo.nativeLibraryRootDir, nullValue());
402         assertThat(pkgSetting.getLegacyNativeLibraryPath(), nullValue());
403         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(false));
404         assertThat(applicationInfo.nativeLibraryDir, nullValue());
405         assertThat(applicationInfo.secondaryNativeLibraryDir, nullValue());
406     }
407 
408     @Test
scanFirstBoot_derivesAbis()409     public void scanFirstBoot_derivesAbis() throws Exception {
410         final PackageSetting pkgSetting =
411                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
412 
413         final ParsedPackage basicPackage =
414                 ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
415                         .hideAsParsed());
416 
417 
418         final ScanResult scanResult = executeScan(new ScanRequestBuilder(
419                 basicPackage)
420                 .setPkgSetting(pkgSetting)
421                 .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
422                 .build());
423 
424         assertAbiAndPathssDerived(scanResult);
425     }
426 
427     @Test
scanWithOriginalPkgSetting_packageNameChanges()428     public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
429         final PackageSetting originalPkgSetting =
430                 createBasicPackageSettingBuilder("original.package").build();
431 
432         final ParsedPackage basicPackage =
433                 (ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
434                         .hideAsParsed();
435 
436 
437         final ScanResult result =
438                 executeScan(new ScanRequestBuilder(basicPackage)
439                         .setOriginalPkgSetting(originalPkgSetting)
440                         .build());
441 
442         assertThat(result.mRequest.mParsedPackage.getPackageName(), is("original.package"));
443     }
444 
445     @Test
updateInstant_changeToFull()446     public void updateInstant_changeToFull() throws Exception {
447         when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
448 
449         final PackageSetting existingPkgSetting =
450                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
451                         .setInstantAppUserState(0, true)
452                         .build();
453 
454         final ScanRequest scanRequest =
455                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
456                         .setPkgSetting(existingPkgSetting)
457                         .addScanFlag(SCAN_AS_FULL_APP)
458                         .build();
459 
460 
461         final ScanResult scanResult = executeScan(scanRequest);
462 
463         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
464     }
465 
466     @Test
updateFull_changeToInstant()467     public void updateFull_changeToInstant() throws Exception {
468         when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
469 
470         final PackageSetting existingPkgSetting =
471                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
472                         .setInstantAppUserState(0, false)
473                         .build();
474 
475         final ScanRequest scanRequest =
476                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
477                         .setPkgSetting(existingPkgSetting)
478                         .addScanFlag(SCAN_AS_INSTANT_APP)
479                         .build();
480 
481 
482         final ScanResult scanResult = executeScan(scanRequest);
483 
484         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
485     }
486 
487     @Test
updateSystemApp_applicationInfoFlagSet()488     public void updateSystemApp_applicationInfoFlagSet() throws Exception {
489         final PackageSetting existingPkgSetting =
490                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
491                         .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
492                         .build();
493 
494         final ScanRequest scanRequest =
495                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
496                         .setPkgSetting(existingPkgSetting)
497                         .setDisabledPkgSetting(existingPkgSetting)
498                         .addScanFlag(SCAN_NEW_INSTALL)
499                         .build();
500 
501         final ScanResult scanResult = executeScan(scanRequest);
502 
503         int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
504                 scanResult.mPkgSetting);
505         assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
506     }
507 
508     @Test
factoryTestFlagSet()509     public void factoryTestFlagSet() throws Exception {
510         final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
511                 .addUsesPermission(
512                         new ParsedUsesPermissionImpl(Manifest.permission.FACTORY_TEST, 0));
513 
514         final ScanResult scanResult = ScanPackageUtils.scanPackageOnly(
515                 createBasicScanRequestBuilder(basicPackage).build(),
516                 mMockInjector,
517                 true /*isUnderFactoryTest*/,
518                 System.currentTimeMillis());
519 
520         int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
521                 scanResult.mRequest.mPkgSetting);
522         assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
523     }
524 
525     @Test
scanSystemApp_isOrphanedTrue()526     public void scanSystemApp_isOrphanedTrue() throws Exception {
527         final ParsedPackage pkg = ((ParsedPackage) createBasicPackage(DUMMY_PACKAGE_NAME)
528                 .hideAsParsed())
529                 .setSystem(true);
530 
531         final ScanRequest scanRequest =
532                 createBasicScanRequestBuilder(pkg)
533                         .build();
534 
535         final ScanResult scanResult = executeScan(scanRequest);
536 
537         assertThat(scanResult.mPkgSetting.getInstallSource().mIsOrphaned, is(true));
538     }
539 
hasFlag(final int flag)540     private static Matcher<Integer> hasFlag(final int flag) {
541         return new BaseMatcher<Integer>() {
542             @Override public void describeTo(Description description) {
543                 description.appendText("flags ");
544             }
545 
546             @Override public boolean matches(Object item) {
547                 return ((int) item & flag) != 0;
548             }
549 
550             @Override
551             public void describeMismatch(Object item, Description mismatchDescription) {
552                 mismatchDescription
553                         .appendValue(item)
554                         .appendText(" does not contain flag ")
555                         .appendValue(flag);
556             }
557         };
558     }
559 
560     private ScanResult executeScan(
561             ScanRequest scanRequest) throws PackageManagerException {
562         ScanResult result = ScanPackageUtils.scanPackageOnly(
563                 scanRequest,
564                 mMockInjector,
565                 false /*isUnderFactoryTest*/,
566                 System.currentTimeMillis());
567 
568         // Need to call hideAsFinal to cache derived fields. This is normally done in PMS, but not
569         // in this cut down flow used for the test.
570         ((ParsedPackage) result.mPkgSetting.getPkg()).hideAsFinal();
571         return result;
572     }
573 
574     private static String createCodePath(String packageName) {
575         return "/data/app/" + packageName + "-randompath";
576     }
577 
578     private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
579         return new PackageSettingBuilder()
580                 .setName(packageName)
581                 .setCodePath(createCodePath(packageName));
582     }
583 
584     private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
585         return new ScanRequestBuilder((ParsedPackage) pkg.hideAsParsed())
586                 .setUser(UserHandle.of(0));
587     }
588 
589     private static ScanRequestBuilder createBasicScanRequestBuilder(ParsedPackage pkg) {
590         return new ScanRequestBuilder(pkg)
591                 .setUser(UserHandle.of(0));
592     }
593 
594     private static ParsingPackage createBasicPackage(String packageName) {
595         // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
596         return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName,
597                 "/data/tmp/randompath/base.apk", createCodePath(packageName),
598                 mock(TypedArray.class), false, null)
599                 .setVolumeUuid(UUID_ONE.toString())
600                 .addUsesStaticLibrary("some.static.library", 234L, new String[]{"testCert1"})
601                 .addUsesStaticLibrary("some.other.static.library", 456L, new String[]{"testCert2"})
602                 .addUsesSdkLibrary("some.sdk.library", 123L, new String[]{"testCert3"}, false)
603                 .addUsesSdkLibrary("some.other.sdk.library", 789L, new String[]{"testCert4"}, true)
604                 .hideAsParsed())
605                 .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
606                 .setVersionCodeMajor(1)
607                 .setVersionCode(2345);
608     }
609 
610     private static void assertBasicPackageScanResult(
611             ScanResult scanResult, String packageName, boolean isInstant) {
612 
613         final PackageSetting pkgSetting = scanResult.mPkgSetting;
614         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
615 
616         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
617                 pkgSetting.getPkg(), 0, pkgSetting.getUserStateOrDefault(0), 0, pkgSetting);
618         assertBasicApplicationInfo(scanResult, applicationInfo);
619     }
620 
621     private static void assertBasicPackageSetting(ScanResult scanResult,
622             String packageName, boolean isInstant, PackageSetting pkgSetting) {
623         assertThat(pkgSetting.getPkg().getPackageName(), is(packageName));
624         assertThat(pkgSetting.getInstantApp(0), is(isInstant));
625         assertThat(pkgSetting.getUsesStaticLibraries(),
626                 arrayContaining("some.static.library", "some.other.static.library"));
627         assertThat(pkgSetting.getUsesStaticLibrariesVersions(), is(new long[]{234L, 456L}));
628         assertThat(pkgSetting.getUsesSdkLibraries(),
629                 arrayContaining("some.sdk.library", "some.other.sdk.library"));
630         assertThat(pkgSetting.getUsesSdkLibrariesVersionsMajor(), is(new long[]{123L, 789L}));
631         assertThat(pkgSetting.getUsesSdkLibrariesOptional(), is(new boolean[]{false, true}));
632         assertThat(pkgSetting.getPkg(), is(scanResult.mRequest.mParsedPackage));
633         assertThat(pkgSetting.getPath(), is(new File(createCodePath(packageName))));
634         assertThat(pkgSetting.getVersionCode(),
635                 is(PackageInfo.composeLongVersionCode(1, 2345)));
636     }
637 
638     private static void assertBasicApplicationInfo(ScanResult scanResult,
639             ApplicationInfo applicationInfo) {
640         assertThat(applicationInfo.processName,
641                 is(scanResult.mRequest.mParsedPackage.getPackageName()));
642 
643         final int uid = applicationInfo.uid;
644         assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
645 
646         final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
647                 applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
648                 scanResult.mRequest.mParsedPackage.getPackageName()).getAbsolutePath();
649         assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
650         assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
651     }
652 
653     private static void assertAbiAndPathssDerived(ScanResult scanResult) {
654         PackageSetting pkgSetting = scanResult.mPkgSetting;
655         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
656                 pkgSetting.getPkg(), 0, pkgSetting.getUserStateOrDefault(0), 0, pkgSetting);
657         assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
658         assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
659 
660         assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
661         assertThat(pkgSetting.getLegacyNativeLibraryPath(), is("derivedRootDir"));
662         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
663         assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
664         assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
665     }
666 
667     private static void assertPathsNotDerived(ScanResult scanResult) {
668         PackageSetting pkgSetting = scanResult.mPkgSetting;
669         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
670                 pkgSetting.getPkg(), 0, pkgSetting.getUserStateOrDefault(0), 0, pkgSetting);
671         assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
672         assertThat(pkgSetting.getLegacyNativeLibraryPath(), is("getRootDir"));
673         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
674         assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
675         assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
676     }
677 }
678