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.os.Build
20 import com.android.server.testutils.any
21 import com.android.server.testutils.spy
22 import com.android.server.testutils.whenever
23 import com.google.common.truth.Truth.assertThat
24 import org.junit.Before
25 import org.junit.Rule
26 import org.junit.Test
27 import org.junit.runner.RunWith
28 import org.junit.runners.JUnit4
29 import org.mockito.Mockito.eq
30 import org.mockito.Mockito.times
31 import org.mockito.Mockito.verify
32 import kotlin.test.assertFailsWith
33 
34 @RunWith(JUnit4::class)
35 class PackageFreezerTest {
36 
37     companion object {
38         const val TEST_PACKAGE = "com.android.test.package"
39         const val TEST_REASON = "test reason"
40         const val TEST_EXIT_REASON = 1
41         const val TEST_USER_ID = 0
42     }
43 
44     @Rule
45     @JvmField
46     val rule = MockSystemRule()
47 
48     lateinit var pms: PackageManagerService
49 
50     private fun createPackageManagerService(vararg stageExistingPackages: String):
51             PackageManagerService {
52         stageExistingPackages.forEach {
53             rule.system().stageScanExistingPackage(it, 1L,
54                 rule.system().dataAppDirectory)
55         }
56         var pms = PackageManagerService(rule.mocks().injector,
57             false /*factoryTest*/,
58             MockSystem.DEFAULT_VERSION_INFO.fingerprint,
59             false /*isEngBuild*/,
60             false /*isUserDebugBuild*/,
61             Build.VERSION_CODES.CUR_DEVELOPMENT,
62             Build.VERSION.INCREMENTAL)
63         rule.system().validateFinalState()
64         return pms
65     }
66 
67     private fun frozenMessage(packageName: String) = "Package $packageName is currently frozen!"
68 
69     private fun <T : Throwable> assertThrowContainsMessage(
70         exceptionClass: kotlin.reflect.KClass<T>,
71         message: String,
72         block: () -> Unit
73     ) {
74         assertThat(assertFailsWith(exceptionClass, block).message).contains(message)
75     }
76 
77     private fun checkPackageStartable() {
78         pms.checkPackageStartable(pms.snapshotComputer(), TEST_PACKAGE, TEST_USER_ID)
79     }
80 
81     @Before
82     @Throws(Exception::class)
83     fun setup() {
84         rule.system().stageNominalSystemState()
85         pms = spy(createPackageManagerService(TEST_PACKAGE))
86         whenever(pms.killApplication(any(), any(), any(), any(), any()))
87     }
88 
89     @Test
90     fun freezePackage() {
91         val freezer = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms, TEST_EXIT_REASON)
92         verify(pms, times(1))
93             .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON),
94                     eq(TEST_EXIT_REASON))
95 
96         assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
97             checkPackageStartable()
98         }
99 
100         freezer.close()
101         checkPackageStartable()
102     }
103 
104     @Test
105     fun freezePackage_twice() {
106         val freezer1 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
107                 TEST_EXIT_REASON)
108         val freezer2 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
109                 TEST_EXIT_REASON)
110         verify(pms, times(2))
111             .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON),
112                     eq(TEST_EXIT_REASON))
113 
114         assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
115             checkPackageStartable()
116         }
117 
118         freezer1.close()
119         assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
120             checkPackageStartable()
121         }
122 
123         freezer2.close()
124         checkPackageStartable()
125     }
126 
127     @Test
128     fun freezePackage_withoutClosing() {
129         var freezer: PackageFreezer? = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
130                 TEST_EXIT_REASON)
131         verify(pms, times(1))
132             .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON),
133                     eq(TEST_EXIT_REASON))
134 
135         assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
136             checkPackageStartable()
137         }
138 
139         freezer = null
140         System.gc()
141         System.runFinalization()
142 
143         checkPackageStartable()
144     }
145 }
146