1 /*
2  * Copyright (C) 2021 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 android.content.Intent
20 import android.content.pm.SuspendDialogInfo
21 import android.os.Binder
22 import android.os.PersistableBundle
23 import com.android.server.testutils.any
24 import com.android.server.testutils.eq
25 import com.android.server.testutils.nullable
26 import com.google.common.truth.Truth.assertThat
27 import org.junit.Test
28 import org.junit.runner.RunWith
29 import org.junit.runners.JUnit4
30 import org.mockito.ArgumentMatchers.anyInt
31 import org.mockito.Mockito.times
32 import org.mockito.Mockito.verify
33 
34 @RunWith(JUnit4::class)
35 class SuspendPackageHelperTest : PackageHelperTestBase() {
36 
37     @Test
38     fun setPackagesSuspended() {
39         val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
40         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
41                 targetPackages, true /* suspended */, null /* appExtras */,
42                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
43                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
44         testHandler.flush()
45 
46         verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
47         verify(broadcastHelper).sendPackageBroadcast(eq(Intent.ACTION_PACKAGES_SUSPENDED),
48             nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
49             nullable(), nullable(), nullable(), nullable())
50         verify(broadcastHelper).doSendBroadcast(eq(Intent.ACTION_MY_PACKAGE_SUSPENDED), nullable(),
51             nullable(), any(), eq(TEST_PACKAGE_1), nullable(), any(), any(), nullable(),
52             nullable(), nullable())
53         verify(broadcastHelper).doSendBroadcast(eq(Intent.ACTION_MY_PACKAGE_SUSPENDED), nullable(),
54             nullable(), any(), eq(TEST_PACKAGE_2), nullable(), any(), any(), nullable(),
55             nullable(), nullable())
56 
57         var modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
58         assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
59         assertThat(failedNames).isEmpty()
60     }
61 
62     @Test
63     fun setPackagesSuspended_emptyPackageName() {
64         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
65                 null /* packageNames */, true /* suspended */, null /* appExtras */,
66                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
67                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
68 
69         assertThat(failedNames).isNull()
70 
71         failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
72                 arrayOfNulls(0), true /* suspended */, null /* appExtras */,
73                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
74                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
75 
76         assertThat(failedNames).isEmpty()
77     }
78 
79     @Test
80     fun setPackagesSuspended_callerIsNotAllowed() {
81         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
82                 arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
83                 null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
84                 Binder.getCallingUid(), false /* forQuietMode */)
85 
86         assertThat(failedNames).asList().hasSize(1)
87         assertThat(failedNames).asList().contains(TEST_PACKAGE_2)
88     }
89 
90     @Test
91     fun setPackagesSuspended_callerSuspendItself() {
92         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
93                 arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
94                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
95                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
96 
97         assertThat(failedNames).asList().hasSize(1)
98         assertThat(failedNames).asList().contains(DEVICE_OWNER_PACKAGE)
99     }
100 
101     @Test
102     fun setPackagesSuspended_nonexistentPackage() {
103         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
104                 arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
105                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
106                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
107 
108         assertThat(failedNames).asList().hasSize(1)
109         assertThat(failedNames).asList().contains(NONEXISTENT_PACKAGE)
110     }
111 
112     @Test
113     fun setPackagesSuspended_knownPackages() {
114         val knownPackages = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
115             INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
116         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
117                 knownPackages, true /* suspended */, null /* appExtras */,
118                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
119                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)!!
120 
121         assertThat(failedNames.size).isEqualTo(knownPackages.size)
122         for (pkg in knownPackages) {
123             assertThat(failedNames).asList().contains(pkg)
124         }
125     }
126 
127     @Test
128     fun setPackagesSuspended_forQuietMode() {
129         val knownPackages = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
130                 INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE,
131                 PERMISSION_CONTROLLER_PACKAGE, MGMT_ROLE_HOLDER_PACKAGE)
132         val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
133                 knownPackages, true /* suspended */, null /* appExtras */,
134                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
135                 TEST_USER_ID, deviceOwnerUid, true /* forQuietMode */)!!
136 
137         assertThat(failedNames.size).isEqualTo(1)
138         assertThat(failedNames[0]).isEqualTo(MGMT_ROLE_HOLDER_PACKAGE)
139     }
140 
141     @Test
142     fun setPackagesUnsuspended() {
143         val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
144         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
145                 targetPackages, true /* suspended */, null /* appExtras */,
146                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
147                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
148         testHandler.flush()
149         assertThat(failedNames).isEmpty()
150         failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
151                 targetPackages, false /* suspended */, null /* appExtras */,
152                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
153                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
154         testHandler.flush()
155 
156         verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
157         verify(broadcastHelper).sendPackageBroadcast(eq(Intent.ACTION_PACKAGES_UNSUSPENDED),
158             nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
159             nullable(), nullable(), nullable(), nullable())
160         verify(broadcastHelper).doSendBroadcast(eq(Intent.ACTION_MY_PACKAGE_UNSUSPENDED),
161             nullable(), nullable(), any(), eq(TEST_PACKAGE_1), nullable(), any(), any(),
162             nullable(), nullable(), nullable())
163         verify(broadcastHelper).doSendBroadcast(eq(Intent.ACTION_MY_PACKAGE_UNSUSPENDED),
164             nullable(), nullable(), any(), eq(TEST_PACKAGE_2), nullable(), any(), any(),
165             nullable(), nullable(), nullable())
166 
167         var modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
168         assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
169         assertThat(failedNames).isEmpty()
170     }
171 
172     @Test
173     fun getUnsuspendablePackagesForUser() {
174         val suspendables = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
175         val unsuspendables = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
176             INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
177         val results = suspendPackageHelper.getUnsuspendablePackagesForUser(pms.snapshotComputer(),
178             suspendables + unsuspendables, TEST_USER_ID, deviceOwnerUid)
179 
180         assertThat(results.size).isEqualTo(unsuspendables.size)
181         for (pkg in unsuspendables) {
182             assertThat(results).asList().contains(pkg)
183         }
184     }
185 
186     @Test
187     fun getUnsuspendablePackagesForUser_callerIsNotAllowed() {
188         val suspendables = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
189         val results = suspendPackageHelper.getUnsuspendablePackagesForUser(pms.snapshotComputer(),
190             suspendables, TEST_USER_ID, Binder.getCallingUid())
191 
192         assertThat(results.size).isEqualTo(suspendables.size)
193         for (pkg in suspendables) {
194             assertThat(results).asList().contains(pkg)
195         }
196     }
197 
198     @Test
199     fun getSuspendedPackageAppExtras() {
200         val appExtras = PersistableBundle()
201         appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1)
202         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
203                 arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
204                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
205                 false /* forQuietMode */)
206         testHandler.flush()
207         assertThat(failedNames).isEmpty()
208 
209         val result = suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
210             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)!!
211 
212         assertThat(result.getString(TEST_PACKAGE_1)).isEqualTo(TEST_PACKAGE_1)
213     }
214 
215     @Test
216     fun removeSuspensionsBySuspendingPackage() {
217         val appExtras = PersistableBundle()
218         appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_2)
219         val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
220         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
221                 targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
222                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
223                 false /* forQuietMode */)
224         testHandler.flush()
225         assertThat(failedNames).isEmpty()
226         assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
227             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
228         assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
229             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
230         assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
231             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
232         assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
233             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
234 
235         suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
236             targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
237             TEST_USER_ID)
238 
239         testHandler.flush()
240         verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
241         verify(broadcastHelper).sendPackageBroadcast(eq(Intent.ACTION_PACKAGES_UNSUSPENDED),
242             nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
243             nullable(), nullable(), nullable(), nullable())
244         verify(broadcastHelper).doSendBroadcast(eq(Intent.ACTION_MY_PACKAGE_UNSUSPENDED),
245             nullable(), nullable(), any(), eq(TEST_PACKAGE_1), nullable(), any(), any(),
246             nullable(), nullable(), nullable())
247         verify(broadcastHelper).doSendBroadcast(eq(Intent.ACTION_MY_PACKAGE_UNSUSPENDED),
248             nullable(), nullable(), any(), eq(TEST_PACKAGE_2), nullable(), any(), any(),
249             nullable(), nullable(), nullable())
250 
251         assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
252             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
253         assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
254             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
255         assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
256             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
257         assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
258             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
259     }
260 
261     @Test
262     fun getSuspendedPackageLauncherExtras() {
263         val launcherExtras = PersistableBundle()
264         launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
265         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
266                 arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
267                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
268                 false /* forQuietMode */)
269         testHandler.flush()
270         assertThat(failedNames).isEmpty()
271 
272         val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(pms.snapshotComputer(),
273             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)!!
274 
275         assertThat(result.getString(TEST_PACKAGE_2)).isEqualTo(TEST_PACKAGE_2)
276     }
277 
278     @Test
279     fun isPackageSuspended() {
280         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
281                 arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
282                 null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
283                 TEST_USER_ID, deviceOwnerUid, false /* forQuietMode */)
284         testHandler.flush()
285         assertThat(failedNames).isEmpty()
286 
287         assertThat(suspendPackageHelper.isPackageSuspended(pms.snapshotComputer(),
288             TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isTrue()
289     }
290 
291     @Test
292     fun getSuspendingPackage() {
293         val launcherExtras = PersistableBundle()
294         launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
295         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
296                 arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
297                 null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
298                 false /* forQuietMode */)
299         testHandler.flush()
300         assertThat(failedNames).isEmpty()
301 
302         assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
303             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
304     }
305 
306     @Test
307     fun getSuspendedDialogInfo() {
308         val dialogInfo = SuspendDialogInfo.Builder()
309             .setTitle(TEST_PACKAGE_1).build()
310         var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
311                 arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
312                 null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
313                 deviceOwnerUid, false /* forQuietMode */)
314         testHandler.flush()
315         assertThat(failedNames).isEmpty()
316 
317         val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
318             TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
319 
320         assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
321     }
322 
323     @Test
324     @Throws(Exception::class)
325     fun sendPackagesSuspendedForUser() {
326         suspendPackageHelper.sendPackagesSuspendedForUser(
327             Intent.ACTION_PACKAGES_SUSPENDED, packagesToChange, uidsToChange, TEST_USER_ID)
328         testHandler.flush()
329         verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
330                 anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable(),
331                 nullable())
332 
333         var changedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
334         var changedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
335         assertThat(changedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
336         assertThat(changedUids).asList().containsExactly(
337                 packageSetting1.appId, packageSetting2.appId)
338     }
339 
340     @Test
341     @Throws(Exception::class)
342     fun sendPackagesSuspendModifiedForUser() {
343         suspendPackageHelper.sendPackagesSuspendedForUser(
344             Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToChange, uidsToChange, TEST_USER_ID)
345         testHandler.flush()
346         verify(broadcastHelper).sendPackageBroadcast(
347                 eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
348                 anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable(),
349                 nullable())
350 
351         var modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
352         var modifiedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
353         assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
354         assertThat(modifiedUids).asList().containsExactly(
355                 packageSetting1.appId, packageSetting2.appId)
356     }
357 }
358