1 /*
2  * Copyright (C) 2017 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 com.android.compatibility.common.util.ShellUtils.runShellCommand;
20 
21 import static com.google.common.truth.Truth.assertWithMessage;
22 
23 import static org.junit.Assert.assertThrows;
24 import static org.junit.Assert.fail;
25 
26 import static java.lang.reflect.Modifier.isFinal;
27 import static java.lang.reflect.Modifier.isPublic;
28 import static java.lang.reflect.Modifier.isStatic;
29 
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 import android.app.AppGlobals;
33 import android.content.IIntentReceiver;
34 import android.content.pm.IPackageManager;
35 import android.content.pm.PackageManager;
36 import android.os.Bundle;
37 import android.os.UserHandle;
38 import android.os.UserManager;
39 import android.platform.test.annotations.Postsubmit;
40 import android.util.SparseArray;
41 
42 import androidx.test.InstrumentationRegistry;
43 import androidx.test.runner.AndroidJUnit4;
44 
45 import com.android.internal.util.HexDump;
46 import com.android.server.pm.PerPackageReadTimeouts.Timeouts;
47 import com.android.server.pm.PerPackageReadTimeouts.VersionCodes;
48 
49 import com.google.android.collect.Lists;
50 
51 import org.junit.After;
52 import org.junit.Assert;
53 import org.junit.Assume;
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 
58 import java.io.File;
59 import java.lang.reflect.Field;
60 import java.lang.reflect.Method;
61 import java.lang.reflect.Type;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collections;
65 import java.util.List;
66 import java.util.regex.Pattern;
67 
68 // atest PackageManagerServiceTest
69 @Postsubmit
70 @RunWith(AndroidJUnit4.class)
71 public class PackageManagerServiceTest {
72 
73     private static final String PACKAGE_NAME = "com.android.server.pm.test.service.server";
74 
75     private static final String TEST_DATA_PATH = "/data/local/tmp/servicestests/";
76     private static final String TEST_APP_APK = "StubTestApp.apk";
77     private static final String TEST_PKG_NAME = "com.android.servicestests.apps.stubapp";
78 
79     private IPackageManager mIPackageManager;
80 
81     @Before
setUp()82     public void setUp() throws Exception {
83         mIPackageManager = AppGlobals.getPackageManager();
84     }
85 
86     @After
tearDown()87     public void tearDown() throws Exception {
88     }
89 
90     @Test
testPackageRemoval()91     public void testPackageRemoval() {
92         class PackageSenderImpl implements PackageSender {
93             public void sendPackageBroadcast(final String action, final String pkg,
94                     final Bundle extras, final int flags, final String targetPkg,
95                     final IIntentReceiver finishedReceiver, final int[] userIds,
96                     int[] instantUserIds, SparseArray<int[]> broadcastAllowList,
97                     @Nullable Bundle bOptions) {
98             }
99 
100             public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
101                     boolean sendBootComplete, boolean includeStopped, int appId,
102                     int[] userIds, int[] instantUserIds, int dataLoaderType) {
103             }
104 
105             @Override
106             public void notifyPackageAdded(String packageName, int uid) {
107             }
108 
109             @Override
110             public void notifyPackageChanged(String packageName, int uid) {
111 
112             }
113 
114             @Override
115             public void notifyPackageRemoved(String packageName, int uid) {
116             }
117         }
118 
119         PackageSenderImpl sender = new PackageSenderImpl();
120         PackageSetting setting = null;
121         PackageRemovedInfo pri = new PackageRemovedInfo(sender);
122 
123         // Initial conditions: nothing there
124         Assert.assertNull(pri.mRemovedUsers);
125         Assert.assertNull(pri.mBroadcastUsers);
126 
127         // populateUsers with nothing leaves nothing
128         pri.populateUsers(null, setting);
129         Assert.assertNull(pri.mBroadcastUsers);
130 
131         // Create a real (non-null) PackageSetting and confirm that the removed
132         // users are copied properly
133         setting = new PackageSettingBuilder()
134                 .setName("name")
135                 .setRealName("realName")
136                 .setCodePath("codePath")
137                 .setLegacyNativeLibraryPathString("legacyNativeLibraryPathString")
138                 .setPrimaryCpuAbiString("primaryCpuAbiString")
139                 .setSecondaryCpuAbiString("secondaryCpuAbiString")
140                 .setCpuAbiOverrideString("cpuAbiOverrideString")
141                 .build();
142         pri.populateUsers(new int[]{
143                 1, 2, 3, 4, 5
144         }, setting);
145         Assert.assertNotNull(pri.mBroadcastUsers);
146         Assert.assertEquals(5, pri.mBroadcastUsers.length);
147         Assert.assertNotNull(pri.mInstantUserIds);
148         Assert.assertEquals(0, pri.mInstantUserIds.length);
149 
150         // Exclude a user
151         pri.mBroadcastUsers = null;
152         final int EXCLUDED_USER_ID = 4;
153         setting.setInstantApp(true, EXCLUDED_USER_ID);
154         pri.populateUsers(new int[]{
155                 1, 2, 3, EXCLUDED_USER_ID, 5
156         }, setting);
157         Assert.assertNotNull(pri.mBroadcastUsers);
158         Assert.assertEquals(4, pri.mBroadcastUsers.length);
159         Assert.assertNotNull(pri.mInstantUserIds);
160         Assert.assertEquals(1, pri.mInstantUserIds.length);
161 
162         // TODO: test that sendApplicationHiddenForUser() actually fills in
163         // broadcastUsers
164     }
165 
166     @Test
testPartitions()167     public void testPartitions() {
168         String[] partitions = {"system", "vendor", "odm", "oem", "product", "system_ext"};
169         String[] appdir = {"app", "priv-app"};
170         for (int i = 0; i < partitions.length; i++) {
171             final ScanPartition scanPartition =
172                     PackageManagerService.SYSTEM_PARTITIONS.get(i);
173             for (int j = 0; j < appdir.length; j++) {
174                 File path = new File(String.format("%s/%s/A.apk", partitions[i], appdir[j]));
175                 Assert.assertEquals(j == 1 && i != 3, scanPartition.containsPrivApp(path));
176 
177                 final int scanFlag = scanPartition.scanFlag;
178                 Assert.assertEquals(i == 1, scanFlag == PackageManagerService.SCAN_AS_VENDOR);
179                 Assert.assertEquals(i == 2, scanFlag == PackageManagerService.SCAN_AS_ODM);
180                 Assert.assertEquals(i == 3, scanFlag == PackageManagerService.SCAN_AS_OEM);
181                 Assert.assertEquals(i == 4, scanFlag == PackageManagerService.SCAN_AS_PRODUCT);
182                 Assert.assertEquals(i == 5, scanFlag == PackageManagerService.SCAN_AS_SYSTEM_EXT);
183             }
184         }
185     }
186 
187     @Test
testKnownPackageToString_shouldNotGetUnknown()188     public void testKnownPackageToString_shouldNotGetUnknown() {
189         final List<String> packageNames = new ArrayList<>();
190         for (int i = 0; i <= KnownPackages.LAST_KNOWN_PACKAGE; i++) {
191             packageNames.add(KnownPackages.knownPackageToString(i));
192         }
193         assertWithMessage(
194                 "The Ids of KnownPackage should be continuous and the string representation "
195                         + "should not be unknown.").that(
196                 packageNames).containsNoneIn(Lists.newArrayList("Unknown"));
197     }
198 
199     @Test
testKnownPackage_lastKnownPackageIsTheLast()200     public void testKnownPackage_lastKnownPackageIsTheLast() throws Exception {
201         final List<Integer> knownPackageIds = getKnownPackageIdsList();
202         assertWithMessage(
203                 "The last KnownPackage Id should be assigned to PackageManagerInternal"
204                         + ".LAST_KNOWN_PACKAGE.").that(
205                 knownPackageIds.get(knownPackageIds.size() - 1)).isEqualTo(
206                 KnownPackages.LAST_KNOWN_PACKAGE);
207     }
208 
209     @Test
testKnownPackage_IdsShouldBeUniqueAndContinuous()210     public void testKnownPackage_IdsShouldBeUniqueAndContinuous() throws Exception {
211         final List<Integer> knownPackageIds = getKnownPackageIdsList();
212         for (int i = 0, size = knownPackageIds.size(); i < size - 1; i++) {
213             assertWithMessage(
214                     "The KnownPackage Ids should be unique and continuous. KnownPackageIds = "
215                             + Arrays.toString(knownPackageIds.toArray())).that(
216                     knownPackageIds.get(i) + 1).isEqualTo(knownPackageIds.get(i + 1));
217         }
218     }
219 
220     @Test
testTimeouts()221     public void testTimeouts() {
222         Timeouts defaults = Timeouts.parse("3600000001:3600000002:3600000003");
223         Assert.assertEquals(3600000001L, defaults.minTimeUs);
224         Assert.assertEquals(3600000002L, defaults.minPendingTimeUs);
225         Assert.assertEquals(3600000003L, defaults.maxPendingTimeUs);
226 
227         Timeouts empty = Timeouts.parse("");
228         Assert.assertEquals(3600000000L, empty.minTimeUs);
229         Assert.assertEquals(3600000000L, empty.minPendingTimeUs);
230         Assert.assertEquals(3600000000L, empty.maxPendingTimeUs);
231 
232         Timeouts partial0 = Timeouts.parse("10000::");
233         Assert.assertEquals(10000L, partial0.minTimeUs);
234         Assert.assertEquals(3600000000L, partial0.minPendingTimeUs);
235         Assert.assertEquals(3600000000L, partial0.maxPendingTimeUs);
236 
237         Timeouts partial1 = Timeouts.parse("10000:10001:");
238         Assert.assertEquals(10000L, partial1.minTimeUs);
239         Assert.assertEquals(10001L, partial1.minPendingTimeUs);
240         Assert.assertEquals(3600000000L, partial1.maxPendingTimeUs);
241 
242         Timeouts fullDefault = Timeouts.parse("3600000000:3600000000:3600000000");
243         Assert.assertEquals(3600000000L, fullDefault.minTimeUs);
244         Assert.assertEquals(3600000000L, fullDefault.minPendingTimeUs);
245         Assert.assertEquals(3600000000L, fullDefault.maxPendingTimeUs);
246 
247         Timeouts full = Timeouts.parse("10000:10001:10002");
248         Assert.assertEquals(10000L, full.minTimeUs);
249         Assert.assertEquals(10001L, full.minPendingTimeUs);
250         Assert.assertEquals(10002L, full.maxPendingTimeUs);
251 
252         Timeouts invalid0 = Timeouts.parse(":10000");
253         Assert.assertEquals(3600000000L, invalid0.minTimeUs);
254         Assert.assertEquals(3600000000L, invalid0.minPendingTimeUs);
255         Assert.assertEquals(3600000000L, invalid0.maxPendingTimeUs);
256 
257         Timeouts invalid1 = Timeouts.parse(":10000::");
258         Assert.assertEquals(3600000000L, invalid1.minTimeUs);
259         Assert.assertEquals(3600000000L, invalid1.minPendingTimeUs);
260         Assert.assertEquals(3600000000L, invalid1.maxPendingTimeUs);
261 
262         Timeouts invalid2 = Timeouts.parse("10000:10001:abcd");
263         Assert.assertEquals(10000L, invalid2.minTimeUs);
264         Assert.assertEquals(10001L, invalid2.minPendingTimeUs);
265         Assert.assertEquals(3600000000L, invalid2.maxPendingTimeUs);
266 
267         Timeouts invalid3 = Timeouts.parse(":10000:");
268         Assert.assertEquals(3600000000L, invalid3.minTimeUs);
269         Assert.assertEquals(3600000000L, invalid3.minPendingTimeUs);
270         Assert.assertEquals(3600000000L, invalid3.maxPendingTimeUs);
271 
272         Timeouts invalid4 = Timeouts.parse("abcd:10001:10002");
273         Assert.assertEquals(3600000000L, invalid4.minTimeUs);
274         Assert.assertEquals(3600000000L, invalid4.minPendingTimeUs);
275         Assert.assertEquals(3600000000L, invalid4.maxPendingTimeUs);
276 
277         Timeouts invalid5 = Timeouts.parse("::1000000000000000000000000");
278         Assert.assertEquals(3600000000L, invalid5.minTimeUs);
279         Assert.assertEquals(3600000000L, invalid5.minPendingTimeUs);
280         Assert.assertEquals(3600000000L, invalid5.maxPendingTimeUs);
281 
282         Timeouts invalid6 = Timeouts.parse("-10000:10001:10002");
283         Assert.assertEquals(3600000000L, invalid6.minTimeUs);
284         Assert.assertEquals(3600000000L, invalid6.minPendingTimeUs);
285         Assert.assertEquals(3600000000L, invalid6.maxPendingTimeUs);
286     }
287 
288     @Test
testVersionCodes()289     public void testVersionCodes() {
290         final VersionCodes defaults = VersionCodes.parse("");
291         Assert.assertEquals(Long.MIN_VALUE, defaults.minVersionCode);
292         Assert.assertEquals(Long.MAX_VALUE, defaults.maxVersionCode);
293 
294         VersionCodes single = VersionCodes.parse("191000070");
295         Assert.assertEquals(191000070, single.minVersionCode);
296         Assert.assertEquals(191000070, single.maxVersionCode);
297 
298         VersionCodes single2 = VersionCodes.parse("191000070-191000070");
299         Assert.assertEquals(191000070, single2.minVersionCode);
300         Assert.assertEquals(191000070, single2.maxVersionCode);
301 
302         VersionCodes upto = VersionCodes.parse("-191000070");
303         Assert.assertEquals(Long.MIN_VALUE, upto.minVersionCode);
304         Assert.assertEquals(191000070, upto.maxVersionCode);
305 
306         VersionCodes andabove = VersionCodes.parse("191000070-");
307         Assert.assertEquals(191000070, andabove.minVersionCode);
308         Assert.assertEquals(Long.MAX_VALUE, andabove.maxVersionCode);
309 
310         VersionCodes range = VersionCodes.parse("191000070-201000070");
311         Assert.assertEquals(191000070, range.minVersionCode);
312         Assert.assertEquals(201000070, range.maxVersionCode);
313 
314         VersionCodes invalid0 = VersionCodes.parse("201000070-191000070");
315         Assert.assertEquals(Long.MIN_VALUE, invalid0.minVersionCode);
316         Assert.assertEquals(Long.MAX_VALUE, invalid0.maxVersionCode);
317 
318         VersionCodes invalid1 = VersionCodes.parse("abcd-191000070");
319         Assert.assertEquals(Long.MIN_VALUE, invalid1.minVersionCode);
320         Assert.assertEquals(191000070, invalid1.maxVersionCode);
321 
322         VersionCodes invalid2 = VersionCodes.parse("abcd");
323         Assert.assertEquals(Long.MIN_VALUE, invalid2.minVersionCode);
324         Assert.assertEquals(Long.MAX_VALUE, invalid2.maxVersionCode);
325 
326         VersionCodes invalid3 = VersionCodes.parse("191000070-abcd");
327         Assert.assertEquals(191000070, invalid3.minVersionCode);
328         Assert.assertEquals(Long.MAX_VALUE, invalid3.maxVersionCode);
329     }
330 
331     @Test
testPerPackageReadTimeouts()332     public void testPerPackageReadTimeouts() {
333         final String sha256 = "336faefc91bb2dddf9b21829106fbc607b862132fecd273e1b6b3ea55f09d4e1";
334         final VersionCodes defVCs = VersionCodes.parse("");
335         final Timeouts defTs = Timeouts.parse("3600000001:3600000002:3600000003");
336 
337         PerPackageReadTimeouts empty = PerPackageReadTimeouts.parse("", defVCs, defTs);
338         Assert.assertNull(empty);
339 
340         PerPackageReadTimeouts packageOnly = PerPackageReadTimeouts.parse("package.com", defVCs,
341                 defTs);
342         Assert.assertEquals("package.com", packageOnly.packageName);
343         Assert.assertEquals(null, packageOnly.sha256certificate);
344         Assert.assertEquals(Long.MIN_VALUE, packageOnly.versionCodes.minVersionCode);
345         Assert.assertEquals(Long.MAX_VALUE, packageOnly.versionCodes.maxVersionCode);
346         Assert.assertEquals(3600000001L, packageOnly.timeouts.minTimeUs);
347         Assert.assertEquals(3600000002L, packageOnly.timeouts.minPendingTimeUs);
348         Assert.assertEquals(3600000003L, packageOnly.timeouts.maxPendingTimeUs);
349 
350         PerPackageReadTimeouts packageHash = PerPackageReadTimeouts.parse(
351                 "package.com:" + sha256, defVCs, defTs);
352         Assert.assertEquals("package.com", packageHash.packageName);
353         Assert.assertEquals(sha256, bytesToHexString(packageHash.sha256certificate));
354         Assert.assertEquals(Long.MIN_VALUE, packageHash.versionCodes.minVersionCode);
355         Assert.assertEquals(Long.MAX_VALUE, packageHash.versionCodes.maxVersionCode);
356         Assert.assertEquals(3600000001L, packageHash.timeouts.minTimeUs);
357         Assert.assertEquals(3600000002L, packageHash.timeouts.minPendingTimeUs);
358         Assert.assertEquals(3600000003L, packageHash.timeouts.maxPendingTimeUs);
359 
360         PerPackageReadTimeouts packageVersionCode = PerPackageReadTimeouts.parse(
361                 "package.com::191000070", defVCs, defTs);
362         Assert.assertEquals("package.com", packageVersionCode.packageName);
363         Assert.assertEquals(null, packageVersionCode.sha256certificate);
364         Assert.assertEquals(191000070, packageVersionCode.versionCodes.minVersionCode);
365         Assert.assertEquals(191000070, packageVersionCode.versionCodes.maxVersionCode);
366         Assert.assertEquals(3600000001L, packageVersionCode.timeouts.minTimeUs);
367         Assert.assertEquals(3600000002L, packageVersionCode.timeouts.minPendingTimeUs);
368         Assert.assertEquals(3600000003L, packageVersionCode.timeouts.maxPendingTimeUs);
369 
370         PerPackageReadTimeouts full = PerPackageReadTimeouts.parse(
371                 "package.com:" + sha256 + ":191000070-201000070:10001:10002:10003", defVCs, defTs);
372         Assert.assertEquals("package.com", full.packageName);
373         Assert.assertEquals(sha256, bytesToHexString(full.sha256certificate));
374         Assert.assertEquals(191000070, full.versionCodes.minVersionCode);
375         Assert.assertEquals(201000070, full.versionCodes.maxVersionCode);
376         Assert.assertEquals(10001L, full.timeouts.minTimeUs);
377         Assert.assertEquals(10002L, full.timeouts.minPendingTimeUs);
378         Assert.assertEquals(10003L, full.timeouts.maxPendingTimeUs);
379     }
380 
381     @Test
testGetPerPackageReadTimeouts()382     public void testGetPerPackageReadTimeouts() {
383         Assert.assertEquals(0, getPerPackageReadTimeouts(null).length);
384         Assert.assertEquals(0, getPerPackageReadTimeouts("").length);
385         Assert.assertEquals(0, getPerPackageReadTimeouts(",,,,").length);
386 
387         final String sha256 = "0fae93f1a7925b4c68bbea80ad3eaa41acfc9bc6f10bf1054f5d93a2bd556093";
388 
389         PerPackageReadTimeouts[] singlePackage = getPerPackageReadTimeouts(
390                 "package.com:" + sha256 + ":191000070-201000070:10001:10002:10003");
391         Assert.assertEquals(1, singlePackage.length);
392         Assert.assertEquals("package.com", singlePackage[0].packageName);
393         Assert.assertEquals(sha256, bytesToHexString(singlePackage[0].sha256certificate));
394         Assert.assertEquals(191000070, singlePackage[0].versionCodes.minVersionCode);
395         Assert.assertEquals(201000070, singlePackage[0].versionCodes.maxVersionCode);
396         Assert.assertEquals(10001L, singlePackage[0].timeouts.minTimeUs);
397         Assert.assertEquals(10002L, singlePackage[0].timeouts.minPendingTimeUs);
398         Assert.assertEquals(10003L, singlePackage[0].timeouts.maxPendingTimeUs);
399 
400         PerPackageReadTimeouts[] multiPackage = getPerPackageReadTimeouts("package.com:" + sha256
401                 + ":191000070-201000070:10001:10002:10003,package1.com::123456");
402         Assert.assertEquals(2, multiPackage.length);
403         Assert.assertEquals("package.com", multiPackage[0].packageName);
404         Assert.assertEquals(sha256, bytesToHexString(multiPackage[0].sha256certificate));
405         Assert.assertEquals(191000070, multiPackage[0].versionCodes.minVersionCode);
406         Assert.assertEquals(201000070, multiPackage[0].versionCodes.maxVersionCode);
407         Assert.assertEquals(10001L, multiPackage[0].timeouts.minTimeUs);
408         Assert.assertEquals(10002L, multiPackage[0].timeouts.minPendingTimeUs);
409         Assert.assertEquals(10003L, multiPackage[0].timeouts.maxPendingTimeUs);
410         Assert.assertEquals("package1.com", multiPackage[1].packageName);
411         Assert.assertEquals(null, multiPackage[1].sha256certificate);
412         Assert.assertEquals(123456, multiPackage[1].versionCodes.minVersionCode);
413         Assert.assertEquals(123456, multiPackage[1].versionCodes.maxVersionCode);
414         Assert.assertEquals(3600000001L, multiPackage[1].timeouts.minTimeUs);
415         Assert.assertEquals(3600000002L, multiPackage[1].timeouts.minPendingTimeUs);
416         Assert.assertEquals(3600000003L, multiPackage[1].timeouts.maxPendingTimeUs);
417     }
418 
419     // Report an error from the Computer structure validation test.
flag(String name, String msg)420     private void flag(String name, String msg) {
421         fail(name + " " + msg);
422     }
423 
424     // Return a string that identifies a Method.  This is not very efficient but it is not
425     // called very often.
displayName(Method m)426     private String displayName(Method m) {
427         String r = m.getName();
428         String p = Arrays.toString(m.getGenericParameterTypes())
429                 .replaceAll("([a-zA-Z0-9]+\\.)+", "")
430                 .replace("class ", "")
431                 .replaceAll("^\\[", "(")
432                 .replaceAll("\\]$", ")");
433         return r + p;
434     }
435 
436     // Match a method to an array of Methods.  Matching is on method signature: name and
437     // parameter types.  If a method in the declared array matches, return it.  Otherwise
438     // return null.
matchMethod(Method m, Method[] declared)439     private Method matchMethod(Method m, Method[] declared) {
440         String n = m.getName();
441         Type[] t = m.getGenericParameterTypes();
442         for (int i = 0; i < declared.length; i++) {
443             Method l = declared[i];
444             if (l != null && l.getName().equals(n)
445                     && Arrays.equals(l.getGenericParameterTypes(), t)) {
446                 Method result = l;
447                 // Set the method to null since it has been visited already.
448                 declared[i] = null;
449                 return result;
450             }
451         }
452         return null;
453     }
454 
getPerPackageReadTimeouts(String knownDigestersList)455     private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) {
456         final String defaultTimeouts = "3600000001:3600000002:3600000003";
457         List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(
458                 defaultTimeouts, knownDigestersList);
459         if (result == null) {
460             return null;
461         }
462         return result.toArray(new PerPackageReadTimeouts[result.size()]);
463     }
464 
bytesToHexString(byte[] bytes)465     private static String bytesToHexString(byte[] bytes) {
466         return HexDump.toHexString(bytes, 0, bytes.length, /*upperCase=*/ false);
467     }
468 
getKnownPackageIdsList()469     private List<Integer> getKnownPackageIdsList() throws IllegalAccessException {
470         final ArrayList<Integer> knownPackageIds = new ArrayList<>();
471         final Field[] allFields = KnownPackages.class.getDeclaredFields();
472         for (Field field : allFields) {
473             final int modifier = field.getModifiers();
474             if (isPublic(modifier) && isStatic(modifier) && isFinal(modifier)
475                     && Pattern.matches("PACKAGE(_[A-Z]+)+", field.getName())) {
476                 knownPackageIds.add(field.getInt(null));
477             }
478         }
479         Collections.sort(knownPackageIds);
480         return knownPackageIds;
481     }
482 
483     @Test
testInstallReason_afterUpdate_keepUnchanged()484     public void testInstallReason_afterUpdate_keepUnchanged() throws Exception {
485         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
486         try {
487             // Try to install test APK with reason INSTALL_REASON_DEVICE_SETUP
488             runShellCommand("pm install --install-reason 3 " + testApk);
489             assertWithMessage("The install reason of test APK is incorrect.").that(
490                     mIPackageManager.getInstallReason(TEST_PKG_NAME,
491                             UserHandle.myUserId())).isEqualTo(
492                     PackageManager.INSTALL_REASON_DEVICE_SETUP);
493 
494             // Try to update test APK with different reason INSTALL_REASON_USER
495             runShellCommand("pm install --install-reason 4 " + testApk);
496             assertWithMessage("The install reason should keep unchanged after update.").that(
497                     mIPackageManager.getInstallReason(TEST_PKG_NAME,
498                             UserHandle.myUserId())).isEqualTo(
499                     PackageManager.INSTALL_REASON_DEVICE_SETUP);
500         } finally {
501             runShellCommand("pm uninstall " + TEST_PKG_NAME);
502         }
503     }
504 
505     @Test
testInstallReason_userRemainsUninstalled_keepUnknown()506     public void testInstallReason_userRemainsUninstalled_keepUnknown() throws Exception {
507         Assume.assumeTrue(UserManager.supportsMultipleUsers());
508         final UserManager um = UserManager.get(
509                 InstrumentationRegistry.getInstrumentation().getContext());
510         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
511         int userId = UserHandle.USER_NULL;
512         try {
513             // Try to install test APK with reason INSTALL_REASON_DEVICE_SETUP
514             runShellCommand("pm install --install-reason 3 " + testApk);
515             assertWithMessage("The install reason of test APK is incorrect.").that(
516                     mIPackageManager.getInstallReason(TEST_PKG_NAME,
517                             UserHandle.myUserId())).isEqualTo(
518                     PackageManager.INSTALL_REASON_DEVICE_SETUP);
519 
520             // Create and start the 2nd user.
521             userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
522             runShellCommand("am start-user -w " + userId);
523             // Since the test APK isn't installed on the 2nd user, the reason should be unknown.
524             assertWithMessage("The test APK should not be installed in the 2nd user").that(
525                     mIPackageManager.getPackageInfo(TEST_PKG_NAME, 0 /* flags */, userId)).isNull();
526             assertWithMessage("The install reason in 2nd user should be unknown.").that(
527                     mIPackageManager.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
528                     PackageManager.INSTALL_REASON_UNKNOWN);
529         } finally {
530             runShellCommand("pm uninstall " + TEST_PKG_NAME);
531             if (userId != UserHandle.USER_NULL) {
532                 um.removeUser(userId);
533             }
534         }
535     }
536 
537     @Test
testInstallReason_installForAllUsers_sameReason()538     public void testInstallReason_installForAllUsers_sameReason() throws Exception {
539         Assume.assumeTrue(UserManager.supportsMultipleUsers());
540         final UserManager um = UserManager.get(
541                 InstrumentationRegistry.getInstrumentation().getContext());
542         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
543         int userId = UserHandle.USER_NULL;
544         try {
545             // Create and start the 2nd user.
546             userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
547             runShellCommand("am start-user -w " + userId);
548 
549             // Try to install test APK to all users with reason INSTALL_REASON_DEVICE_SETUP
550             runShellCommand("pm install --install-reason 3 " + testApk);
551             assertWithMessage("The install reason is inconsistent across users.").that(
552                     mIPackageManager.getInstallReason(TEST_PKG_NAME,
553                             UserHandle.myUserId())).isEqualTo(
554                     mIPackageManager.getInstallReason(TEST_PKG_NAME, userId));
555         } finally {
556             runShellCommand("pm uninstall " + TEST_PKG_NAME);
557             if (userId != UserHandle.USER_NULL) {
558                 um.removeUser(userId);
559             }
560         }
561     }
562 
563     @Test
testInstallReason_installSeparately_withSeparatedReason()564     public void testInstallReason_installSeparately_withSeparatedReason() throws Exception {
565         Assume.assumeTrue(UserManager.supportsMultipleUsers());
566         final UserManager um = UserManager.get(
567                 InstrumentationRegistry.getInstrumentation().getContext());
568         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
569         int userId = UserHandle.USER_NULL;
570         try {
571             // Create and start the 2nd user.
572             userId = um.createUser("Test User", 0 /* flags */).getUserHandle().getIdentifier();
573             runShellCommand("am start-user -w " + userId);
574 
575             // Try to install test APK on the current user with reason INSTALL_REASON_DEVICE_SETUP
576             runShellCommand("pm install --user cur --install-reason 3 " + testApk);
577             assertWithMessage("The install reason on the current user is incorrect.").that(
578                     mIPackageManager.getInstallReason(TEST_PKG_NAME,
579                             UserHandle.myUserId())).isEqualTo(
580                     PackageManager.INSTALL_REASON_DEVICE_SETUP);
581 
582             // Try to install test APK on the 2nd user with reason INSTALL_REASON_USER
583             runShellCommand("pm install --user " + userId + " --install-reason 4 " + testApk);
584             assertWithMessage("The install reason on the 2nd user is incorrect.").that(
585                     mIPackageManager.getInstallReason(TEST_PKG_NAME, userId)).isEqualTo(
586                     PackageManager.INSTALL_REASON_USER);
587         } finally {
588             runShellCommand("pm uninstall " + TEST_PKG_NAME);
589             if (userId != UserHandle.USER_NULL) {
590                 um.removeUser(userId);
591             }
592         }
593     }
594 
595     @Test
testSetSplashScreenTheme_samePackage_succeeds()596     public void testSetSplashScreenTheme_samePackage_succeeds() throws Exception {
597         mIPackageManager.setSplashScreenTheme(PACKAGE_NAME, null /* themeName */,
598                 UserHandle.myUserId());
599         // Invoking setSplashScreenTheme on the same package shouldn't get any exception.
600     }
601 
602     @Test
testSetSplashScreenTheme_differentPackage_fails()603     public void testSetSplashScreenTheme_differentPackage_fails() throws Exception {
604         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
605         try {
606             runShellCommand("pm install " + testApk);
607             mIPackageManager.setSplashScreenTheme(TEST_PKG_NAME, null /* themeName */,
608                     UserHandle.myUserId());
609             fail("setSplashScreenTheme did not throw SecurityException as expected");
610         } catch (SecurityException e) {
611             // expected
612         } finally {
613             runShellCommand("pm uninstall " + TEST_PKG_NAME);
614         }
615     }
616 
617     @Test
testSetUserMinAspectRatio_samePackage_succeeds()618     public void testSetUserMinAspectRatio_samePackage_succeeds() throws Exception {
619         mIPackageManager.setUserMinAspectRatio(PACKAGE_NAME, UserHandle.myUserId(),
620                 PackageManager.USER_MIN_ASPECT_RATIO_UNSET);
621         // Invoking setUserMinAspectRatio on the same package shouldn't get any exception.
622     }
623 
624     @Test
testSetUserMinAspectRatio_differentPackage_fails()625     public void testSetUserMinAspectRatio_differentPackage_fails() {
626         final File testApk = new File(TEST_DATA_PATH, TEST_APP_APK);
627         runShellCommand("pm install " + testApk);
628         assertThrows(SecurityException.class, () -> {
629             mIPackageManager.setUserMinAspectRatio(TEST_PKG_NAME, UserHandle.myUserId(),
630                     PackageManager.USER_MIN_ASPECT_RATIO_UNSET);
631         });
632         runShellCommand("pm uninstall " + TEST_PKG_NAME);
633     }
634 }
635