xref: /aosp_15_r20/cts/hostsidetests/packagemanager/parsing/host/src/android/content/pm/parsing/cts/host/UsesSdkTest.kt (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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 android.content.pm.parsing.cts.host
18 
19 import android.content.pm.parsing.cts.generator.api.AndroidManifestXml
20 import android.content.pm.parsing.cts.generator.api.ApkGenerator
21 import android.platform.test.annotations.RequiresFlagsEnabled
22 import android.platform.test.flag.junit.CheckFlagsRule
23 import android.platform.test.flag.junit.host.HostFlagsValueProvider
24 import android.sdk.Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME
25 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
26 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
27 import com.google.common.truth.Truth.assertThat
28 import com.google.common.truth.Truth.assertWithMessage
29 import org.junit.After
30 import org.junit.Before
31 import org.junit.BeforeClass
32 import org.junit.ClassRule
33 import org.junit.Rule
34 import org.junit.Test
35 import org.junit.rules.TemporaryFolder
36 import org.junit.runner.RunWith
37 
38 @RunWith(DeviceJUnit4ClassRunner::class)
39 class UsesSdkTest : BaseHostJUnit4Test() {
40 
41     companion object {
42 
43         @JvmField
44         @ClassRule
45         val tempFolder = TemporaryFolder()
46 
47         @JvmStatic
48         @BeforeClass
preloadApksnull49         fun preloadApks() {
50             ApkGenerator.initialize(tempFolder)
51         }
52     }
53 
54     @Rule
55     @JvmField
56     val mCheckFlagsRule: CheckFlagsRule =
<lambda>null57         HostFlagsValueProvider.createCheckFlagsRule { this.device }
58 
59     @Before
60     @After
uninstallnull61     fun uninstall() {
62         ApkGenerator.uninstallAll(device, tempFolder)
63     }
64 
65     @Test
defaultsNoTagnull66     fun defaultsNoTag() {
67         // language=XML
68         @AndroidManifestXml
69         val xml = """
70             <manifest>
71                 <application/>
72             </manifest>
73         """
74         val result = ApkGenerator.install(device, xml, tempFolder)
75         assertThat(result.error).isEmpty()
76         assertSdks(result, min = 1, target = 0)
77     }
78 
79     @Test
defaultsWithTagnull80     fun defaultsWithTag() {
81         // language=XML
82         @AndroidManifestXml
83         val xml = """
84             <manifest>
85                 <uses-sdk/>
86                 <application/>
87             </manifest>
88         """
89         val result = ApkGenerator.install(device, xml, tempFolder)
90         assertThat(result.error).isEmpty()
91         assertSdks(result, min = 1, target = 1)
92     }
93 
94     @Test
missingMinDefaultsnull95     fun missingMinDefaults() {
96         // language=XML
97         @AndroidManifestXml
98         val xml = """
99             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
100                 <uses-sdk android:targetSdkVersion="29"/>
101                 <application/>
102             </manifest>
103         """
104         val result = ApkGenerator.install(device, xml, tempFolder)
105         assertThat(result.error).isEmpty()
106         assertSdks(result, min = 1, target = 29)
107     }
108 
109     @Test
missingTargetCoercedToMinnull110     fun missingTargetCoercedToMin() {
111         // language=XML
112         @AndroidManifestXml
113         val xml = """
114             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
115                 <uses-sdk android:minSdkVersion="29"/>
116                 <application/>
117             </manifest>
118         """
119         val result = ApkGenerator.install(device, xml, tempFolder)
120         assertThat(result.error).isEmpty()
121         assertSdks(result, min = 29, target = 29)
122     }
123 
124     @Test
takeAndroidTargetSdknull125     fun takeAndroidTargetSdk() {
126         // language=XML
127         @AndroidManifestXml
128         val xml = """
129             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
130                 <uses-sdk targetSdkVersion="27" android:targetSdkVersion="27">
131                     <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0"/>
132                 </uses-sdk>
133                 <uses-sdk android:targetSdkVersion="29" targetSdkVersion="27">
134                     <extension-sdk android:sdkVersion="31" android:minExtensionVersion="0"/>
135                 </uses-sdk>
136                 <application/>
137             </manifest>
138         """
139         val result = ApkGenerator.install(device, xml, tempFolder)
140         assertThat(result.error).isEmpty()
141         assertSdks(result, target = 29, extensions = mapOf(31 to 0))
142     }
143 
144     @Test
emptyUsesSdknull145     fun emptyUsesSdk() {
146         // language=XML
147         @AndroidManifestXml
148         val xml = """
149             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
150                 <uses-sdk android:targetSdkVersion="29">
151                     <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0"/>
152                 </uses-sdk>
153                 <uses-sdk targetSdkVersion="27"/>
154                 <application/>
155             </manifest>
156         """
157         val result = ApkGenerator.install(device, xml, tempFolder)
158         assertThat(result.error).isEmpty()
159         assertSdks(result, min = 1, target = 1, extensions = emptyMap())
160     }
161 
162     @Test
takeLastTargetSdknull163     fun takeLastTargetSdk() {
164         // language=XML
165         @AndroidManifestXml
166         val xml = """
167             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
168                 <uses-sdk android:targetSdkVersion="28"/>
169                 <uses-sdk android:targetSdkVersion="29"/>
170                 <application/>
171             </manifest>
172         """
173         val result = ApkGenerator.install(device, xml, tempFolder)
174         assertThat(result.error).isEmpty()
175         assertSdks(result, target = 29)
176     }
177 
178     @Test
takeLastMinSdknull179     fun takeLastMinSdk() {
180         // language=XML
181         @AndroidManifestXml
182         val xml = """
183             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
184                 <uses-sdk android:minSdkVersion="28"/>
185                 <uses-sdk android:minSdkVersion="29"/>
186                 <application/>
187             </manifest>
188         """
189         val result = ApkGenerator.install(device, xml, tempFolder)
190         assertThat(result.error).isEmpty()
191         // Target gets coerced to 29 since it's not possible to target below min
192         assertSdks(result, min = 29, target = 29)
193     }
194 
195     @Test
takeLastExtensionSdknull196     fun takeLastExtensionSdk() {
197         // language=XML
198         @AndroidManifestXml
199         val xml = """
200             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
201                 <uses-sdk>
202                     <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0"/>
203                 </uses-sdk>
204                 <uses-sdk>
205                     <extension-sdk android:sdkVersion="31" android:minExtensionVersion="0"/>
206                 </uses-sdk>
207                 <application/>
208             </manifest>
209         """
210         val result = ApkGenerator.install(device, xml, tempFolder)
211         assertThat(result.error).isEmpty()
212         assertSdks(result, min = 1, target = 1, extensions = mapOf(31 to 0))
213     }
214 
215     @Test
lastDeclarationOverridesAllPreviousnull216     fun lastDeclarationOverridesAllPrevious() {
217         // language=XML
218         @AndroidManifestXml
219         val xml = """
220             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
221                 <uses-sdk android:minSdkVersion="21">
222                     <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0"/>
223                 </uses-sdk>
224                 <uses-sdk android:targetSdkVersion="30"/>
225                 <application/>
226             </manifest>
227         """
228         val result = ApkGenerator.install(device, xml, tempFolder)
229         assertThat(result.error).isEmpty()
230         assertSdks(result, min = 1, target = 30, extensions = emptyMap())
231     }
232 
233     @Test
takeLastAfterAppTagnull234     fun takeLastAfterAppTag() {
235         // language=XML
236         @AndroidManifestXml
237         val xml = """
238             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
239                 <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29">
240                     <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0"/>
241                 </uses-sdk>
242                 <application/>
243                 <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30">
244                     <extension-sdk android:sdkVersion="31" android:minExtensionVersion="0"/>
245                 </uses-sdk>
246             </manifest>
247         """
248         val result = ApkGenerator.install(device, xml, tempFolder)
249         assertThat(result.error).isEmpty()
250         assertSdks(result, min = 30, target = 30, extensions = mapOf(31 to 0))
251     }
252 
253     @Test
254     @RequiresFlagsEnabled(FLAG_MAJOR_MINOR_VERSIONING_SCHEME)
minSdkVersionMinorVersionImplicitlySetTo0null255     fun minSdkVersionMinorVersionImplicitlySetTo0() {
256         // language=XML
257         @AndroidManifestXml
258         val xml = """
259             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
260                 <uses-sdk android:minSdkVersionFull="35"/>
261                 <application/>
262             </manifest>
263         """
264         val result = ApkGenerator.install(device, xml, tempFolder)
265         assertThat(result.error).isEmpty()
266     }
267 
268     @Test
269     @RequiresFlagsEnabled(FLAG_MAJOR_MINOR_VERSIONING_SCHEME)
minSdkVersionMinorVersionSetTo0null270     fun minSdkVersionMinorVersionSetTo0() {
271         // language=XML
272         @AndroidManifestXml
273         val xml = """
274             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
275                 <uses-sdk android:minSdkVersionFull="35.0"/>
276                 <application/>
277             </manifest>
278         """
279         val result = ApkGenerator.install(device, xml, tempFolder)
280         assertThat(result.error).isEmpty()
281     }
282 
283     @Test
284     @RequiresFlagsEnabled(FLAG_MAJOR_MINOR_VERSIONING_SCHEME)
minSdkVersionMinorVersionSetTo1null285     fun minSdkVersionMinorVersionSetTo1() {
286         // language=XML
287         @AndroidManifestXml
288         val xml = """
289             <manifest xmlns:android="http://schemas.android.com/apk/res/android">
290                 <uses-sdk android:minSdkVersionFull="35.1"/>
291                 <application/>
292             </manifest>
293         """
294         val result = ApkGenerator.install(device, xml, tempFolder)
295         assertThat(result.error)
296           .contains("Requires newer sdk version 35.1 (current version is 35.0)")
297     }
298 
assertSdksnull299     private fun assertSdks(
300         result: ApkGenerator.InstallResult,
301         min: Int = 1,
302         target: Int = 1,
303         extensions: Map<Int, Int> = emptyMap()
304     ) {
305         val output = device.executeShellCommand("dumpsys package ${result.packageName}")
306         assertThat(output).contains("minSdk=$min")
307         assertThat(output).contains("targetSdk=$target")
308 
309         val minExtensionVersions = output.lineSequence()
310             .dropWhile { !it.startsWith("Packages:") }
311             .map { it.trim() }
312             .first { it.startsWith("minExtensionVersions=") }
313             .removePrefix("minExtensionVersions=[")
314             .removeSuffix("]")
315             .trim()
316             .takeIf(String::isNotEmpty)
317             ?.split(",")
318             ?.associate {
319                 it.split("=")
320                     .map(String::trim)
321                     .map(String::toInt)
322                     .let { it.first() to it.last() }
323             }
324             ?: emptyMap()
325 
326         assertWithMessage(output).that(minExtensionVersions).containsExactlyEntriesIn(extensions)
327     }
328 }
329