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